Adv 2.0 L5a: skills migration off AdvCharacter to player_meta

Eight player_meta columns (combat_level, combat_xp, mining_skill,
mining_xp, foraging_skill, foraging_xp, fishing_skill, fishing_xp).
SkillState struct with HasSkills() marker mirrors PetState/HouseState
shape. loadSkillState / upsertPlayerMetaSkillState /
backfillPlayerMetaSkillState / skillStateFromAdvChar helpers.

Dual-writes wired at every mutation site: consumables craft XP (both
success and failure branches), events.go XP grant across all skills,
arena death + session-complete combat XP. Backfill is idempotent (only
fills rows where every skill column is still zero AND the legacy row
has any non-zero value).

CombatLevel/CombatXP are transitional — dropped at L5g after the DnD
mass-backfill retires the legacy CombatLevel-derived fallback.

Tests: TestPlayerMetaSkillStateBackfill_Idempotent,
TestLoadSkillState_FallsBackToAdvCharacter,
TestUpsertPlayerMetaSkillState_RoundTrip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-09 11:16:07 -07:00
parent cf072f8a8f
commit 79e5d19d23
8 changed files with 317 additions and 1 deletions

View File

@@ -472,6 +472,9 @@ func (p *AdventurePlugin) resolveArenaDeath(ctx MessageContext, run *ArenaRun, c
if err := upsertPlayerMetaArena(ctx.Sender, char.ArenaWins, char.ArenaLosses, char.InvasionScore); err != nil {
slog.Error("player_meta: arena loss dual-write failed", "user", ctx.Sender, "err", err)
}
if err := upsertPlayerMetaSkillState(ctx.Sender, skillStateFromAdvChar(char)); err != nil {
slog.Error("player_meta: arena loss skill dual-write failed", "user", ctx.Sender, "err", err)
}
now := time.Now().UTC()
run.Status = "dead"
@@ -551,6 +554,9 @@ func (p *AdventurePlugin) arenaCompleteSession(userID id.UserID, run *ArenaRun,
if err := upsertPlayerMetaArena(userID, char.ArenaWins, char.ArenaLosses, char.InvasionScore); err != nil {
slog.Error("player_meta: arena win dual-write failed", "user", userID, "err", err)
}
if err := upsertPlayerMetaSkillState(userID, skillStateFromAdvChar(char)); err != nil {
slog.Error("player_meta: arena win skill dual-write failed", "user", userID, "err", err)
}
// End run if not already ended
if run.Status != "completed" && run.Status != "cashed_out" {