PyTrapIC is a Python tool to convert Python code into Stationeers IC10. See below for features and limitations.
More examples are below
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
panels = SolarPanels # port facing north
sensor = DaylightSensor(d0) # port facing east
while True:
panels.Horizontal = sensor.Horizontal
panels.Vertical = 90 - sensor.Vertical |
| IC10 |
l r0 d0 Horizontal # Generated by PyTrapIC v0.2.3
sb HASH("StructureSolarPanel") Horizontal r0
l r0 d0 Vertical
sub r1 90 r0
sb HASH("StructureSolarPanel") Vertical r1
j 0 |
-
Command line tool
pip install git+https://github.com/aproposmath/stationeers-pytrapic.git
python -m stationeers-pytrapic some_simple_code.py
Python Features
- Common Python features:
+,-,*,/,%,+=,-=,*=,/=,and,or,notif,else,while,for,break,continuelist(only compile-time constant lists)- functions
global
- Type-safe access to structures (
WallHeater(d0).Activate = True) - Batch operations (use plural name) (
AutoLathes.Activate = True) - Named batch operations with
[]operator (my_value = WallLights["Some Name"].On.Maximum) - Slot access, either by name (
furnace.Export.Occupied) or by index (furnace.slot0.Occupied) - Enums for all IC10 types like
LogicType.On,DisplayMode.Celsius,SortingClass, etc. - Auto-completion for logic types / slot types etc.
- Intrinsics - all IC10 instructions can be called as functions, e.g.
a = pop()orx = lb(HASH("StructureWallHeater", "On", "Maximum")) (example below) - Optimizations (evaluate constant expressions, function inlining, remove unused code)
@constexprfunction decorator to force evaluation at compile time (example below)- Compile flags (example below)
Planned Features
- Access slot by variable index (
furnace.slots[i].Occupied) - better register allocation (check scope in ic10 code instead of python code for more granularity)
- pass function arguments/return values in registers (currently only via stack)
- allow structures as function arguments/return values (currently only simple values like
floatare allowed) - you tell me!
NOT planned
- lambda functions
- anything that is not supported by IC10 (e.g. classes, exceptions, etc.)
- anything provided by the Python standard library (e.g.
math,random, etc.) - list, dict, set, tuple, comprehensions (maybe later, but only for constant expressions)
Logic Types
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
# Simple access to logic types
# access devices by their symbolic names (d0-d5, db)
db.Setting = d0.RatioCarbonDioxide
# simple calculations will get optimized away
d1.Setting = 273.15 + 22
# use structure names to get proper autocompletion
sensor = DaylightSensor(d5)
db.Setting = sensor.Horizontal |
| IC10 |
l r0 d0 RatioCarbonDioxide # Generated by PyTrapIC v0.2.3
s db Setting r0
s d1 Setting 295.15
l r0 d5 Horizontal
s db Setting r0 |
Batch Operations
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
# Batch operations
# Use the plural name (append "s") to do batch operations
GrowLights.On = True
# Use bracket operator for named batch instructions
GrowLights["Potatos"].On = True
# Access batch properties, either first by batch mode, or by property name
charge0 = Batteries.Average.Charge
charge1 = Batteries.Charge.Average
# having batch mode first is useful if you access the same type multiple times
batteries_bank1 = Batteries["Bank1"].Average
if batteries_bank1.Charge < 0.2:
SolidFuelGenerators.On = True
# wait until charge is above 30%
while batteries_bank1.Charge < 0.3:
pass
SolidFuelGenerators.On = False |
| IC10 |
sb HASH("StructureGrowLight") On 1 # Generated by PyTrapIC v0.2.3
sbn HASH("StructureGrowLight") HASH("Potatos") On 1
lb r0 HASH("StructureBattery") Charge Average
lb r1 HASH("StructureBattery") Charge Average
lbn r2 HASH("StructureBattery") HASH("Bank1") Charge Average
bge r2 0.2 11
sb HASH("StructureSolidFuelGenerator") On 1
lbn r2 HASH("StructureBattery") HASH("Bank1") Charge Average
bge r2 0.3 10
j 7
sb HASH("StructureSolidFuelGenerator") On 0 |
Loops
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
def while_condition():
# blocking wait until pressure is 0
while GasSensors["Airlock"].Average.Pressure > 0:
pass
def for_range():
sum = 0
for i in range(10):
sum += stack[i]
return sum
def for_list():
for name_hash in [HASH("O2"), HASH("N2"), HASH("VOL"), HASH("CO2")]:
pressure = PipeAnalysizers[name_hash].Average.Pressure
ConsoleLED1x2s[name_hash].Setting = pressure
# typical endless loop as main entry point
while True:
while_condition()
db.Setting = for_range()
for_list()
for_range() |
| IC10 |
lbn r1 HASH("StructureGasSensor") HASH("Airlock") Pressure Average
ble r1 0 3 # Generated by PyTrapIC v0.2.3
j 0
jal 22
get r0 db 511
s db Setting r0
move r1 7
move r1 HASH("O2")
jal 16
move r1 HASH("N2")
jal 16
move r1 HASH("VOL")
jal 16
move r1 HASH("CO2")
jal 16
j 19
lbn r2 HASH("StructurePipeAnalysizer") r1 Pressure Average
sbn HASH("StructureConsoleLED1x2") r1 Setting r2
j ra
jal 22
get r0 db 511
j 0
move r1 0
move r2 0
bge r2 10 29
get r3 db r2
add r1 r1 r3
add r2 r2 1
j 24
put db 511 r1
j ra |
Misc
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
# assign boolean value directly from comparison
GrowLights.On = DaylightSensor(d0).Vertical > 90
# if-else expression will use "select" IC10 instruction
db.Setting = STR("Day") if DaylightSensor(d0).Vertical < 90 else STR("Night") |
| IC10 |
l r1 d0 Vertical # Generated by PyTrapIC v0.2.3
sgt r0 r1 90
sb HASH("StructureGrowLight") On r0
l r0 d0 Vertical
slt r1 r0 90
select r2 r1 STR("Day") STR("Night")
s db Setting r2 |
Stack
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
# "stack" variable gives access to the IC10 stack directly
stack[0] = 123
db.Settings = stack[2] + stack[3]
# create stack variables for other devices (dX or by RefId)
stack_d3 = Stack(d3)
stack_d3[0] = 456
stack_dev = Stack(ref_id=0x2355)
stack_dev[0] = 789 |
| IC10 |
poke 0 123 # Generated by PyTrapIC v0.2.3
get r0 db 2
get r1 db 3
add r2 r0 r1
s db Settings r2
put d3 0 456
putd 9045 0 789 |
Constexpr
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
@constexpr
def filter_by_sorting_class(cls, negate=False):
condop = ConditionOperation.Equals
if negate:
condop = ConditionOperation.NotEquals
condop = condop << 8
cls = cls << 16
return cls + condop + SorterInstruction.FilterSortingClassCompare
@constexpr
def filter_by_name(name, negate=False):
hash = HASH(name) << 8
instruction = SorterInstruction.FilterPrefabHashEquals
if negate:
instruction = SorterInstruction.FilterPrefabHashNotEquals
return hash + instruction
# access the stack of a sorter
ores_sorter_stack = Stack(d0)
ores_sorter_stack[0] = filter_by_sorting_class(SortingClass.Ores)
no_ices_sorter_stack = Stack(d1)
no_ices_sorter_stack[0] = filter_by_sorting_class(SortingClass.Ices, negate=True)
# you can also get the stack by the reference id
only_steel = Stack(ref_id=0x3455)
only_steel[0] = filter_by_name("ItemSteelIngot") |
| IC10 |
put d0 0 $90003 # Generated by PyTrapIC v0.2.3
put d1 0 $A0303
putd $3455 0 -167626437375 |
Intrinsics
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
# Builtin functions STR and HASH
# Depending on compiler settings, they will be evaluated at compile time
db.Setting = STR("Hello")
db.Setting = HASH("StructureAutholathe")
# all ic10 instructions are available as python functions
push(HASH("Some name"))
# instructions with an output argument will return a value and have one operand less
db.Setting = pop()
# any string argument of an intrinsic will be emited as-is
# but variables (bat_name) are also supported
but_name = HASH("Main Battery")
charge = lbn("HASH('StructureBattery')", bat_name, "Average", LogicType.Ratio)
Diodes["Low Power"].On = charge < 0.1 |
| IC10 |
s db Setting STR("Hello") # Generated by PyTrapIC v0.2.3
s db Setting HASH("StructureAutholathe")
push HASH("Some name")
pop r1
s db Setting r1
lbn r0 HASH('StructureBattery') Average Ratio
slt r1 r0 0.1
sbn HASH("StructureDiode") HASH("Low Power") On r1 |
Compiler Options
| Python Open in online editor |
|---|
from stationeers_pytrapic.symbols import *
# Available compiler options
# name Default Description
# compact False evaluates HASH/STR (if shorter), use numbers instead of enums
# inline-functions True Inline function calls if possible
# remove-labels False removes jump labels
# append-version True add comment with PyTrapIC version
# Usage is demonstated below. Prepend "no-" for negating options.
# The options can appear anywhere in the code and will be applied globally.
# pytrapic: compact
# pytrapic: no-append-version
# pytrapic: inline-functions
# pytrapic: remove-labels
def some_function():
display = ConsoleLED1x2(d0)
display.Mode = DisplayMode.String
display.Setting = STR("Hi")
while True:
some_function() |
| IC10 |
s d0 3 10
s d0 12 26952
j 0 |
The transpiler itself is written in Python and uses astroid to parse python code.
The web application uses Pyodide to run the transpiler in the browser. The editor is based on monaco and uses monaco-pyright-lsp for code completion. No data is sent to the server, everything is running in the browser.
The project requires Python 3.10+. A .venv is the recommended way to work locally.
Create and activate the venv (first time only):
python3 -m venv .venv
source .venv/bin/activateInstall the package in editable mode with its dependencies:
pip install -e .For building wheels, generating type stubs, and running the webapp data pipeline, also install:
pip install build wheel pyright setuptools setuptools_scmmacOS note: The system Python (e.g. Homebrew Python 3.14) is PEP 668 "externally managed" and will refuse
pip installwithout--break-system-packages. Always use the project.venv.
pip install pytest
pytestTests live in test/ and compare transpiler output against .ref reference files.
src/stationeers_pytrapic/ # transpiler core (Python)
test/ # pytest test cases and reference outputs
mod/ # in-game C# mod (PyTrapIC.cs)
webapp/ # browser IDE (TypeScript + Vite)
scripts/ # code generation and build helpers
pyproject.toml # package metadata and build config
Version is managed by setuptools_scm from git tags, written to src/stationeers_pytrapic/_version.py at build time.
The browser IDE has its own setup steps (Node.js, data file generation). See webapp/README.md.
The in-game BepInEx mod has its own setup steps (.NET SDK, game DLLs, mod dependencies). See the Developer Setup section in mod/README.md.