Patrick Parodex is a small local toolkit for agents that want to attempt the Patrick's Parabox demo on macOS. It provides three practical layers:
- a reversible patch that makes the Unity game write live grid coordinates to
Player.log - read-only helpers for inspecting current state and level data
- basic input helpers for sending game keys
The public toolkit is intentionally limited: it should help an agent see the board and operate the game, but it should not hand over routes or puzzle solutions. The project is intended for local automation and research. It does not require network access.
- macOS
- Patrick's Parabox Demo installed locally, usually through Steam
- Python 3.11 or newer
- Xcode Command Line Tools, for compiling the CoreGraphics key-event helper when needed
- macOS Accessibility and Automation permissions for the terminal or agent process that sends keys
The default workflow uses the log patch instead of screenshots.
This toolkit modifies the local Patrick's Parabox Demo assembly
(Assembly-CSharp.dll) to add log-based state observation. The installer creates
a backup next to the original DLL and provides a restore command, but this is
still a game-file patch. Quit the game before installing or restoring the patch,
and restart the game afterward so Unity loads the intended DLL.
Steam updates or game file verification may overwrite the patched assembly. If the game behaves unexpectedly, restore the original DLL:
python3 scripts/install_patrick_patch.py --restoremacOS may also require local permissions for input automation. Grant these only to the terminal or agent process you trust.
-
Clone or copy this repository.
-
Create local configuration if needed:
cp patrick_config.example.json patrick_config.json
patrick_config.jsonis ignored by git. The default config is usually enough:{ "app_name": "Patrick's Parabox", "input_delay": 0.07 } -
Quit Patrick's Parabox before patching the game assembly.
-
Install the live-state logger patch:
python3 scripts/install_patrick_patch.py --install --live-blocks
If Steam installed the game somewhere unusual, pass the assembly path explicitly:
python3 scripts/install_patrick_patch.py --install --live-blocks --assembly "/path/to/Assembly-CSharp.dll" -
Check patch status:
python3 scripts/install_patrick_patch.py --status
-
Start the game. If it opens on the menu after launch or restart, press Enter once to enter the game:
python3 scripts/patrick_send_keys.py enter
-
Verify that state logging works:
python3 scripts/read_patrick_state_log.py python3 scripts/read_patrick_live_blocks.py
A healthy output looks like:
level=hub area=Area_Enter state= coords=screen x=... y=... raw_x=... raw_y=...
The installer creates a backup next to the patched assembly:
Assembly-CSharp.dll.patrick_state_logger.bak
To restore the original DLL:
python3 scripts/install_patrick_patch.py --restoreRestart the game after restoring.
Read the current logged state:
python3 scripts/read_patrick_state_log.pyRead the current player cell plus every live non-player block cell in the same outer board:
python3 scripts/read_patrick_live_blocks.pyIf this prints blocks=0 in a puzzle that visibly has non-player blocks, restart
the game after installing --live-blocks; a running game keeps the old DLL in
memory until restart.
The live block id is a runtime DebugID; match it to asset block information
by cell and interaction type, not by assuming it equals the asset block_id.
Static walls are not included in the live block log. Use
read_patrick_levels.py --level LEVEL_NAME for walls, buttons, portals, and
other initial terrain.
Render a level from game assets:
python3 scripts/read_patrick_levels.py --level first_puzzleThese tools default to screen coordinates: up is y - 1, down is y + 1,
left is x - 1, and right is x + 1. Pass --coords raw only when debugging
Unity asset coordinates.
Patrick's Parabox supports chain pushing: pushing can propagate through a straight line of pushable blocks when every block in the chain has room to move into the next cell. This is a general movement rule, not a level-specific solution hint.
List hub portals and their current status:
python3 scripts/read_patrick_hub.pyStatuses are enterable, completed, or locked. The game normally creates
save_demoN.txt only after at least one level has been completed, so
save=not-found on a fresh run usually means there is no completion data yet.
List which blocks in a level can be entered versus only pushed:
python3 scripts/read_patrick_blocks.py --level enterUse the interaction, enterable, and pushable fields rather than color.
Yellow-looking blocks can be push-only, and the current player may appear as
another color.
Block positions from this command are initial asset positions; use
read_patrick_state_log.py for the current player position and
read_patrick_live_blocks.py for current non-player block positions after
pushes.
Each block occupies one cell in its parent board. inner_size describes the
inside of a block, not a 5-by-5 outer footprint.
Send one key after manually confirming the current state:
python3 scripts/patrick_send_keys.py downpatrick_send_keys.py sends physical key names. Read the log first, then send
the intended key. In this desktop setup, d is the most reliable right-move key.
Preview key parsing without sending input:
python3 scripts/patrick_send_keys.py "down,right" --dry-runIf the agent gets stuck inside a puzzle, use the in-game pause/menu path to return to the previous map layer. Use a longer delay so the menu has time to open before the selection moves:
python3 scripts/patrick_send_keys.py "escape,down,enter" --delay 0.35After returning, read the log again before sending any movement key.
scripts/install_patrick_patch.py: install, inspect, or restore the game DLL logger patch.scripts/patch_patrick_state_logger.py: low-level patch implementation.scripts/inspect_dotnet_metadata.py: .NET metadata and IL inspection.scripts/read_patrick_state_log.py: parse the newest patched state line from Unity's log.scripts/read_patrick_live_blocks.py: parse the newest live non-player block cells from Unity's log.scripts/read_patrick_levels.py: parse and render level layouts fromresources.assets.scripts/read_patrick_hub.py: list hub portals as enterable, completed, or locked.scripts/read_patrick_blocks.py: list level blocks as enterable, push-only, or controlled-player.scripts/patrick_send_keys.py: activate the game and send key events.scripts/patrick_cgevent_keys.c: native CoreGraphics key-event helper source.
Solver, route-finder, replay, and screenshot fallback scripts live under
local_challenge_artifacts/. That directory is ignored by .gitignore and is
not part of the public toolkit.
The toolkit needs local permissions only. It does not need network access for normal use.
- Read/write access to the game's
Assembly-CSharp.dllwhile installing or restoring the patch. - Read access to Unity's
Player.logfor live player and block coordinates. - Read access to Patrick's Parabox save files when checking hub progress.
- macOS Accessibility permission for automated key input.
- macOS Automation permission if prompted to let the terminal or agent control
System Eventsor Patrick's Parabox. - Xcode Command Line Tools permission/toolchain access if the CoreGraphics key helper needs to be compiled.
- Added
scripts/install_patrick_patch.pyas the public patch install/status/restore entry point. - Added
scripts/read_patrick_hub.pyandscripts/read_patrick_blocks.pyas observation-only tools for hub status and block interaction. - Added a release-style
README.mdwith installation, restore, workflow, permissions, and tool overview. - Added
AGENTS.MDwith challenge goals and agent operating instructions. - Split reusable tooling from puzzle-specific scratch artifacts in
.gitignore. - Kept
solve_correct_outer.pyignored because it encodes a one-off strategy for a specific puzzle. - Moved solver, route-finder, and replay scripts out of the public tool set so fresh agents must reason through the game themselves.
- Moved non-delivered challenge scripts into
local_challenge_artifacts/. - Moved screenshot-based position detection into
local_challenge_artifacts/; the public workflow depends on the log patch instead. - Switched public state reading and level rendering to screen coordinates by default so up/down match physical movement.
- Added live non-player block position logging and
scripts/read_patrick_live_blocks.pyfor current pushed-block cells.