adventure: validate race/class + clamp level in admin char-migrate

Code-review fixes on the stuck-adventurer minting path:
- AdminBuildConfirmedCharacter now runs race/class through parseRace/
  parseClass (same as !setup), so a typo or non-playable class errors
  instead of silently minting a 1-HP/AC-10/no-spell sheet; inputs are
  normalized too.
- Clamp level to dndMaxLevel to match the L20 cap enforced elsewhere.
- CLI parses/validates every spec before db.Init, so a malformed spec
  mid-batch no longer leaves earlier specs already committed.
This commit is contained in:
prosolis
2026-07-16 06:42:54 -07:00
parent d08a20a114
commit 85e5ba5fce
2 changed files with 35 additions and 4 deletions

View File

@@ -40,16 +40,31 @@ func main() {
os.Exit(2)
}
if err := db.Init(*dataDir); err != nil {
log.Fatalf("db init: %v", err)
// Parse every spec before touching the DB, so a malformed spec in the
// middle of the batch fails fast instead of leaving the earlier specs
// already committed to gogobee.db.
type charSpec struct {
uid id.UserID
race plugin.DnDRace
class plugin.DnDClass
level int
}
specs := make([]charSpec, 0, flag.NArg())
for _, spec := range flag.Args() {
uid, race, class, level, err := parseSpec(spec)
if err != nil {
log.Fatalf("bad spec %q: %v", spec, err)
}
c, err := plugin.AdminBuildConfirmedCharacter(uid, race, class, level)
specs = append(specs, charSpec{uid, race, class, level})
}
if err := db.Init(*dataDir); err != nil {
log.Fatalf("db init: %v", err)
}
for _, s := range specs {
uid := s.uid
c, err := plugin.AdminBuildConfirmedCharacter(s.uid, s.race, s.class, s.level)
if err != nil {
log.Fatalf("build %s: %v", uid, err)
}