Fix achievement icons in launcher, allow opening OAuth URLs, live map docs
- Shared achievement icon catalogue; launcher resolves icon/background/border ids - Tauri opener capability now allows http(s) URLs (fixes Discord sign-in) - Rewrite live map docs, admin guide progression section Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DjMbLQujBHunCCu5GpsHaT
This commit is contained in:
17 files changed
+511
-151
No files matched your search
@@ -202,7 +202,8 @@ pub async fn save(pool: &sqlx::SqlitePool, p: &Progression) -> AppResult<()> {
|
||||
/// Recompute every stored level from its XP after the curve changed.
|
||||
pub async fn recalculate_levels(pool: &sqlx::SqlitePool) -> AppResult<usize> {
|
||||
let mut tx = pool.begin().await?;
|
||||
let globals: Vec<(String, i64, i64)> = sqlx::query_as("SELECT uuid, global_xp, global_level FROM user_levels").fetch_all(&mut *tx).await?;
|
||||
let globals: Vec<(String, i64, i64)> =
|
||||
sqlx::query_as("SELECT uuid, global_xp, global_level FROM user_levels").fetch_all(&mut *tx).await?;
|
||||
let mut changed = 0;
|
||||
for (uuid, xp, level) in globals {
|
||||
let new = level_from_xp(xp).0;
|
||||
@@ -211,11 +212,17 @@ pub async fn recalculate_levels(pool: &sqlx::SqlitePool) -> AppResult<usize> {
|
||||
changed += 1;
|
||||
}
|
||||
}
|
||||
let servers: Vec<(i64, String, i64, i64)> = sqlx::query_as("SELECT server_id, uuid, server_xp, server_level FROM server_levels").fetch_all(&mut *tx).await?;
|
||||
let servers: Vec<(i64, String, i64, i64)> =
|
||||
sqlx::query_as("SELECT server_id, uuid, server_xp, server_level FROM server_levels").fetch_all(&mut *tx).await?;
|
||||
for (server_id, uuid, xp, level) in servers {
|
||||
let new = level_from_xp(xp).0;
|
||||
if new != level {
|
||||
sqlx::query("UPDATE server_levels SET server_level = ? WHERE server_id = ? AND uuid = ?").bind(new).bind(server_id).bind(&uuid).execute(&mut *tx).await?;
|
||||
sqlx::query("UPDATE server_levels SET server_level = ? WHERE server_id = ? AND uuid = ?")
|
||||
.bind(new)
|
||||
.bind(server_id)
|
||||
.bind(&uuid)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
changed += 1;
|
||||
}
|
||||
}
|
||||
@@ -234,7 +241,13 @@ pub async fn recalculate_levels(pool: &sqlx::SqlitePool) -> AppResult<usize> {
|
||||
/// stays put for the whole period, even if admins add or edit quests; it is
|
||||
/// only topped up (raised limit, a disabled quest) or truncated (lowered
|
||||
/// limit). Pinned quests are always chosen first.
|
||||
pub async fn assigned_quest_ids(conn: &mut SqliteConnection, cfg: &Progression, uuid: &str, period: &str, key: &str) -> AppResult<Vec<String>> {
|
||||
pub async fn assigned_quest_ids(
|
||||
conn: &mut SqliteConnection,
|
||||
cfg: &Progression,
|
||||
uuid: &str,
|
||||
period: &str,
|
||||
key: &str,
|
||||
) -> AppResult<Vec<String>> {
|
||||
let limit = if period == "weekly" { cfg.weekly_quest_limit } else { cfg.daily_quest_limit } as usize;
|
||||
let eligible: Vec<(String, bool)> = sqlx::query_as("SELECT id, pinned FROM quests WHERE enabled = 1 AND period = ? ORDER BY id")
|
||||
.bind(period)
|
||||
@@ -262,20 +275,23 @@ pub async fn assigned_quest_ids(conn: &mut SqliteConnection, cfg: &Progression,
|
||||
.map(|(id, pinned)| (!pinned, hex::encode(Sha256::digest(format!("{seed}|{id}").as_bytes())), id))
|
||||
.collect();
|
||||
ranked.sort();
|
||||
let mut position: i64 = sqlx::query_scalar("SELECT COALESCE(MAX(position), -1) + 1 FROM quest_assignments WHERE user_uuid = ? AND period_key = ?")
|
||||
.bind(uuid)
|
||||
.bind(key)
|
||||
.fetch_one(&mut *conn)
|
||||
.await?;
|
||||
for (_, _, id) in ranked.into_iter().take(limit - current.len()) {
|
||||
sqlx::query("INSERT OR REPLACE INTO quest_assignments (user_uuid, period, period_key, quest_id, position) VALUES (?, ?, ?, ?, ?)")
|
||||
let mut position: i64 =
|
||||
sqlx::query_scalar("SELECT COALESCE(MAX(position), -1) + 1 FROM quest_assignments WHERE user_uuid = ? AND period_key = ?")
|
||||
.bind(uuid)
|
||||
.bind(period)
|
||||
.bind(key)
|
||||
.bind(&id)
|
||||
.bind(position)
|
||||
.execute(&mut *conn)
|
||||
.fetch_one(&mut *conn)
|
||||
.await?;
|
||||
for (_, _, id) in ranked.into_iter().take(limit - current.len()) {
|
||||
sqlx::query(
|
||||
"INSERT OR REPLACE INTO quest_assignments (user_uuid, period, period_key, quest_id, position) VALUES (?, ?, ?, ?, ?)",
|
||||
)
|
||||
.bind(uuid)
|
||||
.bind(period)
|
||||
.bind(key)
|
||||
.bind(&id)
|
||||
.bind(position)
|
||||
.execute(&mut *conn)
|
||||
.await?;
|
||||
position += 1;
|
||||
current.push(id);
|
||||
}
|
||||
@@ -284,7 +300,14 @@ pub async fn assigned_quest_ids(conn: &mut SqliteConnection, cfg: &Progression,
|
||||
Ok(current)
|
||||
}
|
||||
|
||||
pub async fn is_assigned(conn: &mut SqliteConnection, cfg: &Progression, uuid: &str, period: &str, key: &str, quest_id: &str) -> AppResult<bool> {
|
||||
pub async fn is_assigned(
|
||||
conn: &mut SqliteConnection,
|
||||
cfg: &Progression,
|
||||
uuid: &str,
|
||||
period: &str,
|
||||
key: &str,
|
||||
quest_id: &str,
|
||||
) -> AppResult<bool> {
|
||||
Ok(assigned_quest_ids(conn, cfg, uuid, period, key).await?.iter().any(|id| id == quest_id))
|
||||
}
|
||||
|
||||
@@ -329,7 +352,8 @@ pub fn target_xp(mode: Mode, current: i64, amount: i64) -> AppResult<i64> {
|
||||
}
|
||||
|
||||
pub async fn adjust_global(conn: &mut SqliteConnection, uuid: &str, mode: Mode, amount: i64, now: &str) -> AppResult<XpChange> {
|
||||
let old_xp: i64 = sqlx::query_scalar("SELECT global_xp FROM user_levels WHERE uuid = ?").bind(uuid).fetch_optional(&mut *conn).await?.unwrap_or(0);
|
||||
let old_xp: i64 =
|
||||
sqlx::query_scalar("SELECT global_xp FROM user_levels WHERE uuid = ?").bind(uuid).fetch_optional(&mut *conn).await?.unwrap_or(0);
|
||||
let new_xp = target_xp(mode, old_xp, amount)?;
|
||||
let (old_level, new_level) = (level_from_xp(old_xp).0, level_from_xp(new_xp).0);
|
||||
sqlx::query(
|
||||
@@ -345,7 +369,14 @@ pub async fn adjust_global(conn: &mut SqliteConnection, uuid: &str, mode: Mode,
|
||||
Ok(XpChange { old_xp, new_xp, old_level, new_level })
|
||||
}
|
||||
|
||||
pub async fn adjust_server(conn: &mut SqliteConnection, server_id: i64, uuid: &str, mode: Mode, amount: i64, now: &str) -> AppResult<XpChange> {
|
||||
pub async fn adjust_server(
|
||||
conn: &mut SqliteConnection,
|
||||
server_id: i64,
|
||||
uuid: &str,
|
||||
mode: Mode,
|
||||
amount: i64,
|
||||
now: &str,
|
||||
) -> AppResult<XpChange> {
|
||||
let old_xp: i64 = sqlx::query_scalar("SELECT server_xp FROM server_levels WHERE server_id = ? AND uuid = ?")
|
||||
.bind(server_id)
|
||||
.bind(uuid)
|
||||
|
||||
Reference in new issue
Block a user