Admin rules: starting balance, guild claim/member limits, market listing limit; panel UI
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DjMbLQujBHunCCu5GpsHaT
This commit is contained in:
8 files changed
+166
-12
No files matched your search
@@ -48,6 +48,32 @@ pub struct Progression {
|
||||
pub global_xp_multiplier: f64,
|
||||
pub server_xp_multiplier: f64,
|
||||
pub xp_rates: XpRates,
|
||||
/// Economy and guild rules that apply on every server.
|
||||
pub rules: Rules,
|
||||
}
|
||||
|
||||
/// Network-wide limits an admin can change without touching a server. 0 means "no limit" where it says so.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(default)]
|
||||
pub struct Rules {
|
||||
/// Balance a player starts with on each server economy.
|
||||
pub starting_balance: f64,
|
||||
/// Chunks a new guild may claim.
|
||||
pub guild_base_claims: i64,
|
||||
/// Extra claimable chunks for every member beyond the leader.
|
||||
pub guild_claims_per_member: i64,
|
||||
/// Extra claimable chunks for every guild level above 1.
|
||||
pub guild_claims_per_level: i64,
|
||||
/// Most members a guild may have (0 = no limit).
|
||||
pub guild_max_members: i64,
|
||||
/// Most listings one player may have on a server's market (0 = no limit).
|
||||
pub market_max_listings: i64,
|
||||
}
|
||||
|
||||
impl Default for Rules {
|
||||
fn default() -> Self {
|
||||
Self { starting_balance: 1000.0, guild_base_claims: 16, guild_claims_per_member: 0, guild_claims_per_level: 0, guild_max_members: 0, market_max_listings: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Progression {
|
||||
@@ -62,6 +88,7 @@ impl Default for Progression {
|
||||
global_xp_multiplier: 1.0,
|
||||
server_xp_multiplier: 1.0,
|
||||
xp_rates: XpRates::default(),
|
||||
rules: Rules::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +116,21 @@ impl Progression {
|
||||
return Err(AppError::bad_request(format!("{name} must be between 0 and 100.")));
|
||||
}
|
||||
}
|
||||
let rules = &self.rules;
|
||||
if !rules.starting_balance.is_finite() || !(0.0..=1e9).contains(&rules.starting_balance) {
|
||||
return bad("Starting balance must be between 0 and 1,000,000,000.");
|
||||
}
|
||||
for (name, v, max) in [
|
||||
("Guild base claims", rules.guild_base_claims, 100_000),
|
||||
("Claims per member", rules.guild_claims_per_member, 10_000),
|
||||
("Claims per guild level", rules.guild_claims_per_level, 10_000),
|
||||
("Guild member limit", rules.guild_max_members, 10_000),
|
||||
("Market listing limit", rules.market_max_listings, 10_000),
|
||||
] {
|
||||
if !(0..=max).contains(&v) {
|
||||
return Err(AppError::bad_request(format!("{name} must be between 0 and {max}.")));
|
||||
}
|
||||
}
|
||||
let r = &self.xp_rates;
|
||||
for (name, v) in [
|
||||
("Playtime XP", r.playtime_per_hour),
|
||||
@@ -196,6 +238,14 @@ pub async fn save(pool: &sqlx::SqlitePool, p: &Progression) -> AppResult<()> {
|
||||
.bind(serde_json::to_string(p)?)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
// The same rules as plain rows, so SQL can use them (guild claim limits are worked out in queries).
|
||||
for (key, value) in [
|
||||
("rule_claims_per_member", p.rules.guild_claims_per_member),
|
||||
("rule_claims_per_level", p.rules.guild_claims_per_level),
|
||||
("rule_guild_max_members", p.rules.guild_max_members),
|
||||
] {
|
||||
sqlx::query("INSERT INTO kv (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").bind(key).bind(value.to_string()).execute(pool).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user