Game Mower wiki

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.

  1. Copy it next to itself as save.before-<what>.json (for example save.before-step3.json) before entering play mode or running anything that resets progress.
  2. 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, assembly GameMower.Sim.Tests. One file per area (SimTests, StoreTests, WireTests, BedtimeTests...).
  • They cover the Sim assembly: game state and rules, no scene. Every new company command gets a test.
  • Run them through the Unity MCP run_tests with 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() through eval before testing.

  • EditorApplication.delayCall never runs. Call GameMowerSetup.RebuildAll() directly in eval (timeout 300000; it takes about a minute).

  • Play mode runs at about 10 fps (runInBackground is on). Wait on game state with wait_for, not on wall time. Never use a synchronous wait_for longer 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. Setting EditorApplication.isPlaying = true from eval doesn'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 hook Application.logMessageReceived from eval.

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_key down, wait 2 s, then up. A plain press is missed by WasPressedThisFrame in 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 -notitle argument in builds. To drive the title instead, call HubUI.StartNew(online) / Continue(...) by reflection, only once HubUI.ShowingTitle is true.
  • A season or a later day: set company.State.day, then SceneManager.LoadScene("Garden").
  • A quick visual check without play mode: a new scene, Town.Build(parent, Resources.Load<GameDatabase>("GameDatabase").props, site), a camera, then capture_game_view(camera: ...). Delete the default Main Camera or tag the shot camera: YardGrass culls against Camera.main.
  • Screenshots: capture_game_view saves under Assets/. 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.

  1. Build Builds/Mac/GameMower.app with Game Mower › Build Dev Player (Mac) (Development, and the only build that carries the Sandbox scene). From eval, call GameMowerSetup.BuildDevPlayer() with a long timeout (about 5 minutes).

  2. In the editor: open the scene, editor_play, then eval NetSession.Ensure().Host() (add Autopilot.Attach() to mow). In the sandbox, SandboxSession.Load(new SandboxSpec { mission = "m09_jungle", seed = 999, ... }) builds a given garden for both.

  3. 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
  4. Read the guest log: it prints [Net] stats every 5 s, and mismatches= 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.

Source docs/dev/testing.mdEdited 2026-10-02