Fix SQL errors for D&D-only players: seed player_meta on setup confirm

!setup confirm wrote only dnd_character, never the canonical player_meta
seed row. A player who built a character via !setup and played purely in
the D&D/expedition system (which writes inventory directly, bypassing
ensureCharacter) ended up with no player_meta — so every legacy-layer
command's loadAdvCharacter returned 'sql: no rows in result set'.

dndSetupConfirm now routes through ensureCharacter (which seeds
player_meta + tier-0 equipment on first contact) instead of a bare
loadAdvCharacter.

Also fix !wotd force: it was deleting from a non-existent
job_completed/job_key table (silent no-op that left forced re-posts
blocked by the stale dedup row). Now clears the real daily_prefetch
rows and checks the error.
This commit is contained in:
prosolis
2026-06-03 17:23:53 -07:00
parent 1b8d13e0dd
commit 667f87f9d0
2 changed files with 18 additions and 3 deletions

View File

@@ -258,7 +258,13 @@ func (p *AdventurePlugin) dndSetupConfirm(ctx MessageContext) error {
// Initial D&D level seeded from existing combat_level (v1.1 §4.1). // Initial D&D level seeded from existing combat_level (v1.1 §4.1).
// combat_level "freezes" thereafter — dnd_level is canonical. // combat_level "freezes" thereafter — dnd_level is canonical.
advChar, _ := loadAdvCharacter(ctx.Sender) //
// ensureCharacter (not a bare loadAdvCharacter) so the canonical
// player_meta seed row + tier-0 equipment exist for D&D-only players
// who reach !setup confirm without ever touching the legacy adventure
// path. Without this seed, loadAdvCharacter returns "sql: no rows in
// result set" on every legacy-layer command (arena, npcs, events, …).
advChar, _, _ := p.ensureCharacter(ctx.Sender)
startLevel := 1 startLevel := 1
if advChar != nil { if advChar != nil {
startLevel = dndLevelFromCombatLevel(advChar.CombatLevel) startLevel = dndLevelFromCombatLevel(advChar.CombatLevel)

View File

@@ -247,8 +247,17 @@ func (p *WOTDPlugin) prefetchWord(force bool) error {
if _, delErr := d.Exec(`DELETE FROM wotd_log WHERE date = ?`, today); delErr != nil { if _, delErr := d.Exec(`DELETE FROM wotd_log WHERE date = ?`, today); delErr != nil {
slog.Error("wotd: force delete failed", "err", delErr) slog.Error("wotd: force delete failed", "err", delErr)
} }
// Also clear job-completed flags so PostWOTD will re-post // Also clear job-completed flags so PostWOTD will re-post. The
d.Exec(`DELETE FROM job_completed WHERE job_name = 'wotd' AND job_key LIKE ?`, today+"%") // per-room dedup keys are "<date>:<roomID>" in daily_prefetch, so
// match every room's flag for today. (Was targeting a non-existent
// job_completed/job_key table — a silent no-op that left forced
// re-posts blocked by the stale dedup row.)
if _, delErr := d.Exec(
`DELETE FROM daily_prefetch WHERE job_name = 'wotd' AND date LIKE ?`,
today+"%",
); delErr != nil {
slog.Error("wotd: force clear dedup flags failed", "err", delErr)
}
} }
_, err := d.Exec( _, err := d.Exec(