RimPLC

Colony logic as a PLC ladder: live sensors, editable rules and an in-game ladder window.

The command file for an external assistant, and the same commands as RimBridgeServer tools.

Commands and the AI API

Everything the window can do, an external program can do too -- the same Api answers both. There are two routes; the commands and their results are identical on each.

The command file

With no bridge installed, RimPLC reads commands from a file in the game's configuration folder and answers in a file beside it:

<RimWorld config folder>/RimPLC/inbox.jsonl    one JSON object per line, written by the client
<RimWorld config folder>/RimPLC/outbox.jsonl   {"id":..,"cmd":..,"result":{..}} per line, appended

The inbox is claimed by an atomic rename, a bounded number of lines run per pass and the rest stay queued. It runs once a real second, so it works while the game is paused.

{"id":"1","cmd":"read_ladder","top":4}
{"id":"2","cmd":"set_mark","name":"combat_paused","value":true}
{"id":"3","cmd":"set_tag","name":"STEEL_RESERVE","value":600}
{"id":"4","cmd":"upsert_rung","rung":{"id":"check-beer","priority":30,"when":{"colonists":">3"},"then":["brew beer"]}}
{"id":"5","cmd":"enable_rung","id":"unity-check-beer","enabled":false}
{"id":"6","cmd":"upsert_rung","rung":{"id":"cold-hold","priority":12,"when":{"cold":{"ton":{"outdoor_temp":"<-10"},"hours":2}},"then":["build a heater in the barracks"]}}
{"id":"7","cmd":"export","name":"my-ladder"}
{"id":"8","cmd":"import","json":{"version":2,"gates":[],"tags":{"constants":{},"variables":{}}},"dry_run":true}

The commands

CommandArgsResult
read_laddertop (default 4), allthe live rungs with the measured values that made them fire, plus tags, marks, player rungs, unknown keys, unresolved conditions, disabled rungs, not-applicable rungs, the scan tick
read_statekeys (optional filter)the sensor values measured this scan; absent keys are unmeasured
set_tagname, value (empty clears), owneroverride a variable within its bounds; a constant needs the owner flag
set_markname, valueset a boolean or numeric mark
set_hosta dictionary of readingspush host inputs (readings measured outside the game) before a scan; merged first, a game reading of the same name wins, dropped after 120 s
upsert_rungrungadd or replace a player rung; validated like the editor
remove_rungidremove a player rung, or drop the player copy of a preset rung
enable_rungid, enabled, ownerswitch a rung on or off; switching a preset rung off needs the owner flag
letters_seen--mark every letter on the stack as read
exportnamewrite the ladder to RimPLC/exports/<name>.json
importjson, dry_runmerge a ladder; dry_run returns the diff without applying it

A refusal is a result with ok: false and a reason in plain words. The shapes of every command, rung, sensor, tag and mark are frozen in the repository's docs/schema/ JSON schemas.

The owner flag

"owner": true unlocks the owner-only changes -- a constant, a preset rung switched off. It is meant to be set only by the owner's own client, never by anything that relays chat or another user's input; the flag is the whole guard, so the client that sets it is the one being trusted.

The RimBridgeServer tools

With RimBridgeServer installed, the companion BridgeTools/RimPLC.BridgeTools.dll exposes the same commands as bridge tools:

rimplc/read_ladder   rimplc/read_state    rimplc/set_tag       rimplc/set_mark
rimplc/upsert_rung   rimplc/remove_rung   rimplc/enable_rung   rimplc/letters_seen
rimplc/export        rimplc/import

Each call hops to the game's main thread and runs the shared Api, so a tool and its file command return the same text. Install exactly one copy of the companion -- the one inside the mod folder -- as Install explains.

Host inputs

set_host lets a program outside the game contribute readings the game cannot know: whether a person is at the keyboard, how long since the last spoken line, whether a chat question is waiting. They appear in the Sensors tab under Stream, are merged before the game's own readings (a game reading of the same name wins), and are dropped after 120 seconds so a client that stops pushing does not leave stale truth in the ladder.