weekly challenges: admin-configurable slate + working skin rewards

Port the admin-editable weekly-challenge feature to the 2020.03 branch
and fix the skin-reward bug it had on December: rewards now actually
land in the player's inventory instead of only granting XP + tokens.

Server config: add WeeklyChallenges* columns to ServerSettings (Postgres
post-EnsureCreated patches + SQLite column patches), and port the
ServerSettingsService weekly methods/records. The reward record carries
the store item Slug — the reliable handle December lacked — so the grant
can resolve the real item.

ProgressionController: CurrentChallenge + updateProgress now read the
configured slate and reward instead of a hardcoded one, keeping the
2020.03 ChallengeMap/ChallengeGift wire shapes (verified against the
march dump: ChallengeGift TypeDefIndex 11455). The Gift now sends
AvatarItemType (Outfit when an AvatarItemDesc is set) so the watch's
gift-card render binds the avatar preview. On completing the week's
challenges the configured skin/consumable is granted via the new
StoreService.GrantItemFreeBySlugAsync (same inventory path as a purchase,
no charge), gated behind the once-only reward sentinel.

Admin: GET/POST settings/weekly-challenges + reward-options (avatar +
consumable only — 2020.03 StoreService has no equipment payload helper),
and the admin-ui Server settings page to edit the slate + reward. The
reward picker keys on item slug rather than December's fragile
descriptor-string match.

Docs: README no longer lists weekly challenges as December-only;
url-coverage notes the config-driven challenge endpoints + skin grant.
This commit is contained in:
Alexa
2026-05-31 14:47:12 +03:00
parent 1eba8d9345
commit f6a4fdc5fb
9 changed files with 858 additions and 58 deletions
+21
View File
@@ -703,6 +703,20 @@ using (var scope = app.Services.CreateScope())
""UpdatedAt"" timestamp with time zone NOT NULL DEFAULT now()
);");
// 2026-05-31 — Weekly-challenge config columns on ServerSettings.
// Back the admin SPA's editable weekly slate + gift (XP/tokens +
// an optional store skin granted on completion). EnsureCreated-
// skipped on existing DBs, so add idempotently.
await RunPatchAsync("ServerSettings.WeeklyChallengesCompletedRequired column",
@"ALTER TABLE ""ServerSettings""
ADD COLUMN IF NOT EXISTS ""WeeklyChallengesCompletedRequired"" boolean NOT NULL DEFAULT true;");
await RunPatchAsync("ServerSettings.WeeklyChallengesJson column",
@"ALTER TABLE ""ServerSettings""
ADD COLUMN IF NOT EXISTS ""WeeklyChallengesJson"" text NOT NULL DEFAULT '';");
await RunPatchAsync("ServerSettings.WeeklyChallengeRewardJson column",
@"ALTER TABLE ""ServerSettings""
ADD COLUMN IF NOT EXISTS ""WeeklyChallengeRewardJson"" text NOT NULL DEFAULT '';");
// 2026-05-19 — Players.IsCommunityTeam column. Backs the
// overhead-badge admin toggle alongside IsDeveloper; the
// RoleController ORs the two so either one unlocks the watch's
@@ -1238,6 +1252,13 @@ static void ApplySqliteCompatibilityPatches(DorkNetDbContext db)
if (!db.Database.IsSqlite()) return;
AddSqliteColumnIfMissing(db, "Rooms", "HiddenFromBrowse",
@"""HiddenFromBrowse"" INTEGER NOT NULL DEFAULT 0");
// 2026-05-31 — weekly-challenge config columns (see ServerSettingsEntity).
AddSqliteColumnIfMissing(db, "ServerSettings", "WeeklyChallengesCompletedRequired",
@"""WeeklyChallengesCompletedRequired"" INTEGER NOT NULL DEFAULT 1");
AddSqliteColumnIfMissing(db, "ServerSettings", "WeeklyChallengesJson",
@"""WeeklyChallengesJson"" TEXT NOT NULL DEFAULT ''");
AddSqliteColumnIfMissing(db, "ServerSettings", "WeeklyChallengeRewardJson",
@"""WeeklyChallengeRewardJson"" TEXT NOT NULL DEFAULT ''");
}
static void AddSqliteColumnIfMissing(DorkNetDbContext db, string table, string column, string definition)