Skip to content

Add console_command action: run dev-console commands over the HTTP API - #119

Open
SamPease wants to merge 1 commit into
Gennadiyev:mainfrom
SamPease:add-console-command
Open

Add console_command action: run dev-console commands over the HTTP API#119
SamPease wants to merge 1 commit into
Gennadiyev:mainfrom
SamPease:add-console-command

Conversation

@SamPease

Copy link
Copy Markdown

What

Adds a console_command action that constructs a MegaCrit.Sts2.Core.DevConsole.DevConsole
directly and calls ProcessCommand(string) on it, bypassing the console's UI panel
entirely. This exposes the game's full first-party dev-console command set (heal,
damage, block, energy, card, draw, applypower, fight <encounter_id>,
unlock, achievement, ...) over the existing localhost API.

POST /api/v1/singleplayer {"action": "console_command", "command": "heal 999"}

(Requires a run in progress, same as every other action.)

Motivation: I'm using this mod as a ground-truth oracle for a personal project that
differential-tests a from-scratch combat simulator. Legal play alone can't reach a lot
of the precise/edge-case states I need to test against (exact HP thresholds, specific
status stacks, specific encounters without map RNG) — the dev console can construct
these directly. Seemed generically useful beyond my own use case, so opening this
rather than keeping it as a private patch.

A real bug found and fixed along the way

Task-returning commands (e.g. fight) need to be fired via TaskHelper.RunSafely,
matching the game's own console (DevConsoleUI's ProcessCommand call site) — not
awaited synchronously. I initially awaited the task directly
(result.task.GetAwaiter().GetResult()), which deadlocked the entire mod: this handler
already runs on the main thread via RunOnMainThread, and fight's task itself needs
the main thread to keep pumping to complete. Confirmed live — calling fight while
another combat was already in progress hung the whole HTTP server, not just that
request, until switching to fire-and-forget.

Verification note

main currently doesn't compile against the latest installed STS2 (v0.109.0) due to
the pre-existing IsPlayPhase/Inventory API breakage tracked in #114/#116/#117, so I
couldn't build-verify this diff directly against unpatched main. I did build and
extensively live-verify this exact change (including finding and fixing the deadlock
above) on top of #117's branch, which does compile and run against v0.108.0 and
v0.109.0. This diff doesn't touch any of the lines #117 changes — it's a new method
plus one new switch case — so it should apply and build cleanly on main once #117 (or
an equivalent fix) lands. Happy to rebase/re-verify against main directly once that's
in, or against whatever base you'd prefer.

Constructs a MegaCrit.Sts2.Core.DevConsole.DevConsole directly and calls
ProcessCommand(string) on it, bypassing the console's UI panel entirely.
Exposes the game's full first-party dev-console command set (heal, damage,
block, energy, card, draw, applypower, fight <encounter_id>, unlock,
achievement, ...) over the existing localhost API - useful for reaching
precise states (exact HP/block/hand/statuses, or jumping straight into a
named encounter) beyond what's reachable through legal play alone.

Usage: POST /api/v1/singleplayer {"action": "console_command", "command": "heal 999"}
(requires a run in progress, same as every other action.)

Task-returning commands (e.g. fight) are fired via TaskHelper.RunSafely,
matching the game's own console (DevConsoleUI's ProcessCommand call site) -
not awaited synchronously. That matters: awaiting synchronously deadlocked
the whole mod when a task-returning command needed the main thread to keep
pumping to complete, since this handler already runs on the main thread via
RunOnMainThread. Confirmed live by calling `fight` while another combat was
already in progress before landing on the fire-and-forget fix.
Copilot AI review requested due to automatic review settings July 18, 2026 22:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new singleplayer HTTP action that lets clients execute first-party STS2 dev-console commands directly against the live run state, enabling precise scenario setup via the existing localhost API.

Changes:

  • Add a new "console_command" action dispatch in the singleplayer action switch.
  • Implement ExecuteConsoleCommand to call DevConsole.ProcessCommand(string) and fire-and-forget any returned task via TaskHelper.RunSafely.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread McpMod.Actions.cs
Comment on lines +164 to +166
var devConsole = new MegaCrit.Sts2.Core.DevConsole.DevConsole(shouldAllowDebugCommands: true);
var result = devConsole.ProcessCommand(command);

Comment thread McpMod.Actions.cs
Comment on lines 88 to 91
"crystal_sphere_click_cell" => ExecuteCrystalSphereClickCell(data),
"crystal_sphere_proceed" => ExecuteCrystalSphereProceed(),
"console_command" => ExecuteConsoleCommand(data),
_ => Error($"Unknown action: {action}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants