Dev
Testing
How to check a change: unit tests, play tests in the editor, and two-player co-op runs. Most of this is about driving Unity from a Claude session through the Unity MCP, where the editor runs in the background.
Before any play test: back up the save
The user plays between sessions and has real progress. The save lives in
~/Library/Application Support/lobodart/Game Mower/save.json.
- Copy it next to itself as
save.before-<what>.json(for examplesave.before-step3.json) before entering play mode or running anything that resets progress. - Restore it when you're done, and say which backup you made.
The -profile <name> command-line argument switches to save-<name>.json. The co-op guest uses
-profile guest (save-guest.json, a copy with another player name), so it never touches the host's save.
Unit tests
- EditMode tests live in
Assets/_Game/Tests/EditMode, assemblyGameMower.Sim.Tests. One file per area (SimTests,StoreTests,WireTests,BedtimeTests...). - They cover the
Simassembly: game state and rules, no scene. Every new company command gets a test. - Run them through the Unity MCP
run_testswith a narrow filter: it returns every result, so the full suite floods the reply.
Driving the editor from a session
The editor is usually unfocused while a session drives it. That changes how it behaves:
-
No auto-refresh. After editing files, run
AssetDatabase.Refresh()throughevalbefore testing. -
EditorApplication.delayCallnever runs. CallGameMowerSetup.RebuildAll()directly ineval(timeout 300000; it takes about a minute). -
Play mode runs at about 10 fps (
runInBackgroundis on). Wait on game state withwait_for, not on wall time. Never use a synchronouswait_forlonger than ~50 s: it blocks the MCP queue and every later call times out. -
The MCP drops on every domain reload (recompile, entering play). Wait for it to come back, then reload the tools:
until nc -z 127.0.0.1 7800; do sleep 1; done -
Start play with
editor_play. SettingEditorApplication.isPlaying = truefromevaldoesn't start it. -
Compile errors can land after the reload marker. Once the MCP is back, grep the log for
error CS, or play mode silently refuses to start:grep "error CS" ~/Library/Logs/Unity/Editor.log | tail -
Logs: play-mode logs don't reach the MCP console, and its buffer saturates at 2000 entries (old errors hide new ones). Read
~/Library/Logs/Unity/Editor.log, or hookApplication.logMessageReceivedfromeval.
Input in play tests
The game ignores the live keyboard and mouse while its window is unfocused. Two ways around it:
- Scripted hooks:
GameMower.Autopilot.Attach(sprint)mows in rows, unclogs and empties the bag.PlayerController.scripted*,PlayerInteraction.scriptedHold,HandToolController.scriptedUse,ToolBelt.Select(i),Lawn.DebugCutFraction(f, edges),HedgeGrid.DebugTrimFraction(f),AmbianceDirector.Instance.Time01 / Weather. - Simulated keys:
simulate_keydown, wait 2 s, then up. A plain press is missed byWasPressedThisFramein an unfocused editor that runs few frames, so game code reads held-state edges.
Shortcuts
- Skip the title screen: menu Game Mower › Skip Title In Editor, or the
-notitleargument in builds. To drive the title instead, callHubUI.StartNew(online)/Continue(...)by reflection, only onceHubUI.ShowingTitleis true. - A season or a later day: set
company.State.day, thenSceneManager.LoadScene("Garden"). - A quick visual check without play mode: a new scene,
Town.Build(parent, Resources.Load<GameDatabase>("GameDatabase").props, site), a camera, thencapture_game_view(camera: ...). Delete the default Main Camera or tag the shot camera:YardGrassculls againstCamera.main. - Screenshots:
capture_game_viewsaves underAssets/. Move the file out afterwards.
Two-player co-op runs
The editor is the host and a development build is the guest, on the same machine.
-
Build
Builds/Mac/GameMower.appwith Game Mower › Build Dev Player (Mac) (Development, and the only build that carries the Sandbox scene). Fromeval, callGameMowerSetup.BuildDevPlayer()with a long timeout (about 5 minutes). -
In the editor: open the scene,
editor_play, theneval NetSession.Ensure().Host()(addAutopilot.Attach()to mow). In the sandbox,SandboxSession.Load(new SandboxSpec { mission = "m09_jungle", seed = 999, ... })builds a given garden for both. -
Start the guest with its own save and log:
open -n Builds/Mac/GameMower.app --args -netjoin 127.0.0.1 -netauto -profile guest -screen-fullscreen 0 -logFile /tmp/guest.log -
Read the guest log: it prints
[Net] statsevery 5 s, andmismatches=must stay at 0.
What the arguments do: -nethost / -netjoin <ip> connect at startup, -netauto makes the guest act on its own
(mows and does a bit of every job in a garden, walks and scrubs in the house, follows the host to bed),
-profile guest keeps its save apart. The guest never saves.
After a build, git checkout the UnityConnectSettings file: builds keep switching m_Enabled on.
To click in the guest window for real, computer use needs full-screen control: Unity ignores clicks on a window in the background.