feat: GM/admin commands (spawn, tp, kill, resurrect) #31
No reviewers
Labels
No labels
alpha:wave-0
alpha:wave-1
alpha:wave-2
alpha:wave-3
area:assets
area:combat
area:ecology
area:infra
area:render
area:scripting
area:ui
area:world
enhancement
epic
migration
post-alpha
roadmap
tech-debt
type:bug
type:chore
type:design
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
marco/IsoMmo!31
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/gm-commands"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Game-master commands, run from the chat box with a
/prefix (e.g./spawn rat). Server-authoritative and gated on a signed JWTadminclaim — a client can't self-grant.AppUser.IsAdminDB column (dual-provider migration) is the source of truth; Auth stamps anadminclaim into the token at login. Bootstrap the first admin withAdmin:Usernamesin Auth config (persisted to the DB on next login). Dev config seedstest.BaseCommand→GmCommand(implementsCanExecute= admin check) →SpawnCommand/TeleportCommand/KillCommand/ResurrectCommand, dispatched byCommandRegistry. Authorization lives in the command (CanExecute), not scattered in the dispatcher./spawn <rat>,/tp <x> <y>,/kill(nearest creature → corpse + respawn),/resurrect(/res).CombatSystem(extractedSlay/ScheduleRespawn/ForceResurrect), reused by both combat and the GM paths; World only orchestrates. Effects surface through the normal tick/AoI reconcile; feedback returns as aSystemMessage.HS256(rejectsalg:none/confusion) on top of the existing signature + issuer + audience + lifetime checks./-prefixed chat →GmCommandRequest;SystemMessageshown over the player + logged.Docs
docs/gm-commands.mdis the canonical command list; a new CLAUDE.md rule requires updating it in the same change that adds/changes a command.Tampering — why it's safe
The
adminclaim is inside an HMAC-SHA256-signed token; the GameServer validates the signature against the shared secret. Editing the payload breaks the signature → rejected. The residual risk is key secrecy —Jwt:Keymust be a strong secret in prod (dev key is a placeholder).How it was tested
adminclaim iffIsAdmin(unit).spawnadds a creature;tpmoves the player;killslays the nearest creature leaving a corpse; unknown command reported (unit, viaCommandRegistry+World).GmCommandRequest/SystemMessage.Needs your eyes (GUI)
As the
testuser (auto-admin in dev): open chat,/spawn rat,/kill,/tp 60 60, and (after dying)/res— feedback shows over your character. A non-admin gets "You are not allowed to do that."Checklist
just lintclean · [x]just testgreen (196) · [x] whole solution builds, 0 warnings · [x] multi-platform preserved · [x] tests added · [x] EF migrations for both providersGMs run chat-prefixed commands ("/spawn rat") authorized server-side by a signed JWT admin claim — never a client-sent flag. Admin identity is AppUser.IsAdmin (new Auth DB column, dual-provider migration), stamped into the token at login and bootstrapped from an Admin:Usernames config list. Commands are objects: BaseCommand -> GmCommand (CanExecute = admin check) -> SpawnCommand/TeleportCommand/KillCommand/ResurrectCommand, dispatched by CommandRegistry. Authorization lives in CanExecute; every effect goes through the World facade (World stays a thin facade — the death/corpse/resurrect logic lives in CombatSystem, reused by the GM slay/resurrect paths) and surfaces via the normal tick/AoI reconcile; feedback returns as a SystemMessage. Client sends "/" lines as GmCommandRequest and shows SystemMessage feedback. Hardened token validation to pin HS256. Canonical command list in docs/gm-commands.md (kept in sync per a new CLAUDE.md rule).