Repository navigation
MP-12: DevBridge and dev tools in multiplayer - #17
Open
aurablacklight wants to merge 13 commits into
Open
aurablacklight wants to merge 13 commits into
aurablacklight wants to merge 13 commits into
Conversation
The packet worker could not run the live checks in its sandbox. Add what the coordinator observed when running them outside it, including what failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTWx6KTPBs4koTLg8uZMHX
…r review - A client whose DevBridge cannot bind its port is detected from its log, and relaunched once after the TIME_WAIT window, bounded by --timeout. - Server and client telemetry is read from logs/debug.log, so debug-level agentcraft.mp events are visible to harness tests. - Gradle preparation is bounded by --timeout, the launch export ensures client assets, and the process identity no longer depends on the caller's time zone or locale. - Fall back to the checkout's .gradle-home and check for Java 25, like the other launchers. Document and pin the --json summary shape. - Windows: portable test fixture paths, -ExecutionPolicy Bypass, and the wrapper started through Start-Bg. None of this was run on Windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnFLfHG1rVtWmS9c6mAQP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnFLfHG1rVtWmS9c6mAQP
main gained the CI workflow (.github/workflows/ci.yml). Nothing else changes on this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnFLfHG1rVtWmS9c6mAQP
Local integration branch for Wave 1 (not pushed, not for main). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnFLfHG1rVtWmS9c6mAQP
Local integration branch for Wave 1 (not pushed, not for main). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnFLfHG1rVtWmS9c6mAQP
Local integration branch for Wave 1 (not pushed, not for main). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnFLfHG1rVtWmS9c6mAQP
Local integration branch for Wave 1 (not pushed, not for main). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnFLfHG1rVtWmS9c6mAQP
On a remote server the DevBridge commands that needed the integrated server
now ask the real one as the player would: dev.command, dev.time and
dev.weather send one validated chat command (one optional leading slash, at
most 256 characters, chat characters only), and dev.camera sends /gamemode and
/tp with plain-decimal numbers. They need op, which the harness gives its
players. dev.quit leaves the server before stopping.
dev.state reports the mode, the registered studios and the player's own plot.
dev.anchors, dev.hq.check, dev.camera {anchor} and the camera paths take an
optional studio (a UUID or "own"). dev.mp.send puts one C2S payload on the
real network through the same codec the game uses and refuses in singleplayer;
dev.mp.relay shows the studios and the last 32 events the client received.
Singleplayer keeps its paths: the integrated-server branches are the old code.
dev.hq.check now refuses a minLight outside 0..15.
Reviewed twice by a second model, with one fix round between; the coordinator
made the second review's small corrections. 55 JUnit tests and both game tests
pass. The harness checks, the singleplayer refusal check and the QA compare
are still owed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NLkzPTC3pm16WCmLm9dqyp
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Connection-scoped relay events can leak across sessions, and the harness cannot recover an unrecorded Gradle process after a launcher crash.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Adds multiplayer-aware DevBridge controls and diagnostics while retaining integrated-server behavior. The stacked diff also includes the Wave 0 multiplayer foundation, harness, game-test infrastructure, and Node.js baseline.
Changes:
- Supports remote commands, cameras, studio-aware anchors/HQ checks, payload injection, and relay inspection.
- Adds multiplayer contracts, codecs, client registries, telemetry, and tests.
- Adds the two-client harness, Fabric game tests, and Node.js 22.18 minimum.
| File | Description |
|---|---|
mod/src/client/java/dev/agentcraft/client/dev/DevCommands.java |
Adds remote-server DevBridge fallbacks. |
mod/src/client/java/dev/agentcraft/client/dev/play/CameraPath.java |
Resolves camera anchors by studio. |
mod/src/client/java/dev/agentcraft/client/hq/HqCheck.java |
Adds studio-aware HQ checks. |
mod/src/client/java/dev/agentcraft/client/world/AnchorsDev.java |
Adds studio selection to anchor queries. |
mod/src/client/java/dev/agentcraft/client/mp/dev/MpDevCommands.java |
Adds multiplayer send, relay, and state commands. |
mod/src/test/java/dev/agentcraft/mp/dev/DevMpCommandsTest.java |
Tests multiplayer DevBridge parsing and relay state. |
mod/src/test/java/dev/agentcraft/client/dev/DevAnchorStudioTest.java |
Tests studio-aware anchor resolution. |
mod/src/test/java/dev/agentcraft/client/dev/DevRemoteCommandTest.java |
Tests remote command validation and teleport formatting. |
docs/multiplayer/worknotes/MP-12.md |
Records MP-12 implementation and verification. |
tools/mp.mjs |
Adds the multiplayer harness CLI. |
tools/lib/mp/config.mjs |
Defines harness options, ports, and plans. |
tools/lib/mp/harness.mjs |
Orchestrates harness startup and shutdown. |
tools/lib/mp/index.mjs |
Exposes harness commands, readiness, and telemetry. |
tools/lib/mp/launch.mjs |
Builds isolated Java launch configurations. |
tools/lib/mp/processes.mjs |
Tracks and controls owned processes. |
tools/lib/mp/export-launch.gradle |
Exports Loom launch metadata. |
tools/test/mp-config.test.mjs |
Tests harness configuration and launch arguments. |
tools/test/mp-library.test.mjs |
Tests readiness, telemetry, and directory seeding. |
tools/test/mp-processes.test.mjs |
Tests process identity and recovery. |
tools/test/mp-shutdown.test.mjs |
Tests safe, retryable harness cleanup. |
tools/README.md |
Documents the multiplayer harness. |
tools/package.json |
Requires Node.js 22.18+. |
tools/mac.mjs |
Enforces the Node.js baseline on macOS. |
tools/launch.ps1 |
Enforces the Node.js baseline on Windows. |
README.md |
Updates prerequisites. |
foreman/package.json |
Requires Node.js 22.18+. |
foreman/src/repos.ts |
Parses Node.js spec-reporter output. |
foreman/test/repos.test.ts |
Tests TAP and spec-reporter parsing. |
mod/build.gradle |
Adds JUnit and Fabric game-test infrastructure. |
mod/src/gametest/resources/fabric.mod.json |
Declares the game-test mod. |
mod/src/gametest/java/dev/agentcraft/gametest/HqSmokeGameTest.java |
Adds an HQ build smoke test. |
mod/src/main/java/dev/agentcraft/AgentCraft.java |
Wires multiplayer server features. |
mod/src/client/java/dev/agentcraft/client/ClientFeatures.java |
Wires multiplayer client features. |
mod/src/main/java/dev/agentcraft/hq/HqBuilder.java |
Adds plot origin and studio build options. |
mod/src/main/java/dev/agentcraft/layout/Anchors.java |
Stores per-studio anchor layouts. |
mod/src/main/java/dev/agentcraft/mp/StudioId.java |
Defines studio identity. |
mod/src/main/java/dev/agentcraft/mp/Plot.java |
Defines plot bounds and ownership. |
mod/src/main/java/dev/agentcraft/mp/PlotDirectory.java |
Defines plot lookup operations. |
mod/src/main/java/dev/agentcraft/mp/PlotGrid.java |
Maps plot indices to spiral positions. |
mod/src/main/java/dev/agentcraft/mp/Plots.java |
Provides the active plot directory. |
mod/src/main/java/dev/agentcraft/mp/RateBucket.java |
Adds rate limiting. |
mod/src/main/java/dev/agentcraft/mp/MpServerConfig.java |
Loads multiplayer server configuration. |
mod/src/main/java/dev/agentcraft/mp/MpEvents.java |
Defines multiplayer telemetry events. |
mod/src/main/java/dev/agentcraft/mp/MpLog.java |
Emits sanitized multiplayer telemetry. |
mod/src/main/java/dev/agentcraft/mp/MpReasons.java |
Defines rejection reason codes. |
mod/src/main/java/dev/agentcraft/mp/server/StudioRange.java |
Tracks studio visibility. |
mod/src/main/java/dev/agentcraft/mp/server/world/ServerWorldFeature.java |
Adds the server-world feature seam. |
mod/src/main/java/dev/agentcraft/mp/server/plot/PlotFeature.java |
Adds the plot feature seam. |
mod/src/main/java/dev/agentcraft/mp/server/layout/LayoutSyncFeature.java |
Adds the layout-sync seam. |
mod/src/main/java/dev/agentcraft/mp/server/relay/RelayFeature.java |
Adds the relay seam. |
mod/src/main/java/dev/agentcraft/mp/server/intent/WorldIntentFeature.java |
Adds the world-intent seam. |
mod/src/main/java/dev/agentcraft/mp/server/protect/PlotProtectionFeature.java |
Adds the plot-protection seam. |
mod/src/main/java/dev/agentcraft/mp/net/MpProtocol.java |
Defines the protocol version. |
mod/src/main/java/dev/agentcraft/mp/net/MpPayloads.java |
Registers multiplayer payloads and handshake. |
mod/src/main/java/dev/agentcraft/mp/net/MpCodecs.java |
Implements bounded payload codecs. |
mod/src/main/java/dev/agentcraft/mp/net/HelloC2S.java |
Defines the client handshake reply. |
mod/src/main/java/dev/agentcraft/mp/net/HelloS2C.java |
Defines the server handshake. |
mod/src/main/java/dev/agentcraft/mp/net/ServerInfo.java |
Carries server multiplayer limits. |
mod/src/main/java/dev/agentcraft/mp/net/LayoutS2C.java |
Carries studio layouts. |
mod/src/main/java/dev/agentcraft/mp/net/LayoutRemoveS2C.java |
Removes remote layouts. |
mod/src/main/java/dev/agentcraft/mp/net/PresenceS2C.java |
Carries studio presence. |
mod/src/main/java/dev/agentcraft/mp/net/PublicStateC2S.java |
Publishes public studio state. |
mod/src/main/java/dev/agentcraft/mp/net/StudioStateS2C.java |
Relays studio state. |
mod/src/main/java/dev/agentcraft/mp/net/StudioEventC2S.java |
Publishes studio events. |
mod/src/main/java/dev/agentcraft/mp/net/StudioEventS2C.java |
Relays studio events. |
mod/src/main/java/dev/agentcraft/mp/net/WorldIntentC2S.java |
Publishes world intents. |
mod/src/main/java/dev/agentcraft/mp/state/AgentStateWire.java |
Defines public agent states. |
mod/src/main/java/dev/agentcraft/mp/state/CiSlot.java |
Defines public CI slots. |
mod/src/main/java/dev/agentcraft/mp/state/CiStatusWire.java |
Defines public CI states. |
mod/src/main/java/dev/agentcraft/mp/state/Counts.java |
Defines public task counts. |
mod/src/main/java/dev/agentcraft/mp/state/GoalStatusWire.java |
Defines public goal states. |
mod/src/main/java/dev/agentcraft/mp/state/GoalSummary.java |
Defines public goal summaries. |
mod/src/main/java/dev/agentcraft/mp/state/LampStatusWire.java |
Defines lamp states. |
mod/src/main/java/dev/agentcraft/mp/state/MpText.java |
Sanitizes public text. |
mod/src/main/java/dev/agentcraft/mp/state/PublicAgent.java |
Defines public agent data. |
mod/src/main/java/dev/agentcraft/mp/state/PublicEvent.java |
Defines public studio events. |
mod/src/main/java/dev/agentcraft/mp/state/PublicJson.java |
Implements strict public JSON parsing. |
mod/src/main/java/dev/agentcraft/mp/state/PublicPolicy.java |
Defines public text-sharing policy. |
mod/src/main/java/dev/agentcraft/mp/state/PublicStudioState.java |
Defines the public-state allowlist. |
mod/src/main/java/dev/agentcraft/mp/state/PublicTask.java |
Defines public task data. |
mod/src/main/java/dev/agentcraft/mp/state/StationWire.java |
Defines public station values. |
mod/src/main/java/dev/agentcraft/mp/state/TaskStatusWire.java |
Defines public task states. |
mod/src/main/java/dev/agentcraft/mp/state/WorldIntent.java |
Defines validated world intents. |
mod/src/client/java/dev/agentcraft/client/mp/MpMode.java |
Tracks client multiplayer mode. |
mod/src/client/java/dev/agentcraft/client/mp/Studios.java |
Maintains client studio state. |
mod/src/client/java/dev/agentcraft/client/mp/StudioView.java |
Defines immutable studio views. |
mod/src/client/java/dev/agentcraft/client/mp/RemoteAgentClicks.java |
Adds the remote-agent click seam. |
mod/src/client/java/dev/agentcraft/client/mp/dev/MpDevFake.java |
Adds local multiplayer fixtures. |
mod/src/client/java/dev/agentcraft/client/mp/layout/LayoutSyncClient.java |
Adds the client layout-sync seam. |
mod/src/client/java/dev/agentcraft/client/mp/publish/PublishFeature.java |
Adds the publisher seam. |
mod/src/client/java/dev/agentcraft/client/mp/remote/RemoteStudiosFeature.java |
Adds the remote-studio seam. |
mod/src/client/java/dev/agentcraft/client/mp/visitor/VisitorFeature.java |
Adds the visitor seam. |
mod/src/test/java/dev/agentcraft/mp/AnchorsTest.java |
Tests per-studio anchors. |
mod/src/test/java/dev/agentcraft/mp/CodecTest.java |
Tests multiplayer codecs and limits. |
mod/src/test/java/dev/agentcraft/mp/DevFakeTest.java |
Tests fake studio injection. |
mod/src/test/java/dev/agentcraft/mp/FoundationTest.java |
Tests foundation contracts and telemetry. |
mod/src/test/java/dev/agentcraft/mp/RateBucketTest.java |
Tests rate limiting. |
mod/src/test/java/dev/agentcraft/mp/RemoteAgentClicksTest.java |
Tests remote click dispatch. |
mod/src/test/java/dev/agentcraft/mp/StudioRangeTest.java |
Tests studio visibility. |
mod/src/test/java/dev/agentcraft/mp/StudiosTest.java |
Tests client studio lifecycle. |
mod/src/test/java/dev/agentcraft/mp/WiringTest.java |
Verifies feature wiring. |
mod/src/test/java/dev/agentcraft/client/foreman/ForemanStates.java |
Adds Foreman state fixtures. |
mod/src/test/java/dev/agentcraft/client/foreman/ForemanStatesTest.java |
Tests Foreman fixtures. |
docs/multiplayer/README.md |
Updates campaign status. |
docs/multiplayer/handoffs/session-resume.md |
Updates coordinator handoff guidance. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+60
to
+63
| // Leaving a server drops the mode to SINGLEPLAYER: those events belong to the server we left. | ||
| MpMode.addListener(mode -> { | ||
| if (mode == MpMode.SINGLEPLAYER) { | ||
| synchronized (EVENTS) { |
Comment on lines
+112
to
+114
| const entry = { kind: 'build', marker: `ac-mp-${randomUUID()}`, log: path.join(plan.dir, 'build.log') }; | ||
| state.processes.push(entry); | ||
| saveJson(plan.file, state); |
The ring of received studio events was cleared from a mode listener, which does not fire when the mode is already singleplayer, so events injected in singleplayer survived into the next server's dev.mp.relay. It is now cleared from the client's play-connection join and disconnect events. Found by the pull-request review. 56 JUnit tests and both game tests pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NLkzPTC3pm16WCmLm9dqyp
The DevBridge is on by default in the jar a player installs, and this packet made dev.command, dev.time, dev.weather, dev.camera and dev.release send real commands to a remote server, and dev.mp.send send multiplayer payloads. Any program on the player's machine could therefore act on a shared server with the player's rights. Those paths now work only when the game was started with AGENTCRAFT_DEV_REMOTE=1 (the exact value; environment only). Without it they are refused before any side effect. The harness sets it for its own clients; a player never should. Read-only commands, local input and dev.quit are unchanged, and singleplayer needs no opt-in. sendCommand stays (behind the opt-in): sendUnattendedCommand opens a confirmation screen for every command these tools need. Found by the pull-request review (blocking). 60 JUnit tests and both game tests pass. Still open, as before: typing a command into chat through the bridge; only AGENTCRAFT_DEV=0 closes that. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NLkzPTC3pm16WCmLm9dqyp
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NLkzPTC3pm16WCmLm9dqyp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

The DevBridge commands that needed the integrated server now work on a remote server, and the dev tools can see and drive the multiplayer state. Singleplayer keeps its paths: the integrated-server branches are the old code.
Stacked on Wave 0. This branch starts from the four open Wave 0 pull requests (#1, #2, #4, #5) merged together, so until they are on
mainthis diff also shows their changes. The packet's own change is 1 commit: compare from the Wave 0 base.What is in it
dev.command,dev.timeanddev.weathersend one validated chat command (one optional leading slash, at most 256 characters, chat characters only), anddev.camerasends/gamemodeand/tpwith plain-decimal numbers. They need op, which the harness gives its players.dev.statereports the mode, the registered studios and the player's own plot.dev.anchors,dev.hq.check,dev.camera {anchor}and the camera paths take an optional studio.dev.mp.sendputs one C2S payload on the real network through the same codec the game uses and refuses in singleplayer;dev.mp.relayshows the studios and the last 32 events the client received.dev.hq.checknow refuses aminLightoutside 0..15.Review history
Reviewed twice by a second model, with one fix round between (7, then 6 findings; the last small ones corrected by the coordinator). The worknote (
docs/multiplayer/worknotes/MP-12.mdon this branch) has the details.Verification
gradlew test --rerun --no-build-cacheandgradlew build: 55 JUnit tests and 2 game tests, all passing.mp/integration): 238 JUnit tests and 102 game tests pass, and the singleplayer QA compare (ten shots against a reference on the same display) moved no shot; the singleplayer client logged noagentcraft.mpline.dev.mp.sendrefuses with a message naming singleplayer,dev.statereports the mode, the own studio and no plot, anddev.anchorsanddev.hq.checkanswer with the studio field. The singleplayer QA compare moved no shot.Still owed, and not run by anyone:
dev.mp.sendon a real server.Merge order and notes
mod/DEV.mdis not in this packet's row; the worknote lists the rows MP-Z should add to it.🤖 Generated with Claude Code
https://claude.ai/code/session_01NLkzPTC3pm16WCmLm9dqyp