A programmable circuit combinator controlled via a RISC-V inspired assembly language. Supports reading red and green input signals and writing up to four output signals per tick.
Mods introducing new content into the game.
Version: 0.8.30
Date: 08. 04. 2026
Features:
- Added ANDI rd, rs, imm — bitwise AND with immediate (rd = rs & imm)
- Added ORI rd, rs, imm — bitwise OR with immediate (rd = rs | imm)
- Added XORI rd, rs, imm — bitwise XOR with immediate (rd = rs ^ imm)
All three accept decimal, hex (0x prefix), and negative immediates.
Useful for masking, setting, and toggling specific bits without needing
a register to hold the mask constant.
Changes:
- 7 new tests. 174 tests total.
Version: 0.8.29
Date: 08. 04. 2026
Features:
- validate_program() now detects duplicate labels at compile time.
Error format: [label:N] Duplicate label 'name' (first defined on line M)
The check runs before the instruction scan so all duplicate labels in a
program are reported in a single save, alongside any other errors.
- 2 new tests: duplicate label detection, and confirmation that distinct
labels do not produce false positives. 167 tests total.
Version: 0.8.28
Date: 08. 04. 2026
Bugfixes:
- Fixed 'Cannot serialise lua functions' on save. self.tick_fn stored a function
reference on the cpu object in storage, which Factorio cannot serialise.
- Fixed boot/step state being shared across all combinator instances. The previous
attempt used a module-level tick_fn_ndx variable, so any combinator's boot()
call would switch every other combinator to step() before it had compiled.
Changes:
- self.tick_ndx replaces self.tick_fn. It is an integer (0 or 1) stored on each
cpu object — fully serialisable. 0 = call boot, 1 = call step.
- TICK_FN = {boot, step} is a module-level table (not in storage).
cpu:tick() calls TICK_FN[(self.tick_ndx or 0) + 1](self). The 'or 0' handles
old saves where tick_ndx was not yet present (nil).
- boot() sets cpu.tick_ndx = 1 after compiling. All subsequent ticks call step().
- control.lua reattach_metatables() only calls setmetatable() — no other writes
to storage, fully compliant with on_load constraints.
- reset_tick_fn() removed; no longer needed.
- cpu:tick_step() retained for direct step() access in tests.
Version: 0.8.26
Date: 08. 04. 2026
Bugfixes:
- Fixed crash on load when analytical combinators were saved with versions
prior to 0.8.20. Those saves have no compiled program array. All previous
fix attempts (0.8.21-0.8.25) tried to compile during on_load, which
Factorio forbids as a storage write — causing a CRC error instead.
Changes:
- Replaced cpu:step() with a two-function tick state machine:
boot(cpu) — runs on the first tick per session per combinator
step(cpu) — runs on every subsequent tick
cpu:tick() dispatches through self.tick_fn which starts as boot and
switches to a direct reference to step after the first tick. After
initialisation the hot path is: one field read, one function call.
- boot() compiles self.memory if self.compiled is absent or empty,
handling all pre-compilation save versions with no on_load storage write.
After compiling, boot sets tick_fn = step and calls step on the same tick.
- self.tick_fn is a function reference (not serialisable). control.lua calls
cpu:reset_tick_fn() in reattach_metatables() after every load to restore it.
reset_tick_fn() writes only to the Lua state, not to storage.
- WAIT fast path from 0.8.24 retained in step().
- events.lua: data.cpu:step() -> data.cpu:tick().
- test.lua: myCpu:step() -> myCpu:tick() throughout (158 call sites).
Version: 0.8.25
Date: 07. 04. 2026
Bugfixes:
- Fixed cross-combinator interference caused by tostring(self) as the compiled
cache key. tostring() returns a table's memory address, which changes every
time storage is deserialised. This caused stale cache entries, missing cache
entries, and multiple combinators accidentally sharing entries — producing the
symptoms of other combinators halting when a new one is placed, or programs
stopping when an unrelated combinator's code is saved.
- Replaced tostring(self) with self.unit_number as the stable cache key.
unit_number is the entity's permanent Factorio identifier, written onto the
cpu object at placement time (a normal runtime write, not an on_load write)
and persisted in storage. on_load reads it to rebuild the cache with zero
storage writes, satisfying Factorio's on_load CRC constraint.
- Added cpu:set_unit_number(n) called by register_entity() in events.lua.
New cpus start with unit_number = 0; set_unit_number() moves the cache entry
to the real key immediately after placement.
Version: 0.8.24
Date: 07. 04. 2026
Optimizations:
- Added a WAIT fast path at the very top of step(). When wait_cycles is non-nil,
step() decrements the counter and returns immediately — before any cache lookup,
dispatch table access, or function call. For programs that spend most of their
time in WAIT (e.g. polling loops with WAIT 60), this eliminates nearly all
per-tick overhead for the waiting period.
- Simplified the DISPATCH["WAIT"] handler now that the decrement loop has moved
to the fast path. The handler's only job is to set wait_cycles on first encounter
and keep IP on the WAIT instruction.
- Added test: 'WAIT N occupies exactly N ticks before executing the next instruction'
to permanently lock in the correct tick-counting semantics. 165 tests total.
Version: 0.8.23
Date: 07. 04. 2026
Bugfixes:
- Fixed remaining CRC error on load. The 0.8.22 fix moved the compiled array out
of storage, but still wrote _cache_key onto the cpu object (which lives in
storage) during on_load(), triggering the same CRC violation.
- Root cause: any field assignment to a table that is reachable from storage
counts as a storage write, even if the field is newly added and not the
serialised data itself.
- Fix: replaced _cache_key with tostring(self) as the _compiled_cache lookup key.
tostring() on a Lua table returns its memory address as a string, which is
unique per object within a session. No field is written to the cpu object
(storage) at any point during on_load. The cache is purely a Lua-state
construct, rebuilt from self.memory on every load with zero storage writes.
- Removed set_cache_key(), _cache_key, and _next_test_key as they are no
longer needed.
Version: 0.8.22
Date: 07. 04. 2026
Bugfixes:
- Fixed CRC error on load caused by 0.8.21 attempting to write the compiled program
array into storage during on_load(). Factorio explicitly forbids storage writes
in on_load() as they cause desyncs in multiplayer.
- Root cause: the compiled array is ephemeral derived data that must never be
stored in storage. It belongs in a module-level Lua cache that is rebuilt on
every load from the persisted self.memory source of truth.
Changes:
- Introduced _compiled_cache: a module-level table in cpu.lua (outside storage)
keyed by unit_number. step() looks up the compiled program here instead of on
the cpu object. The cache is rebuilt in on_load() via rebuild_compiled() which
only reads self.memory from storage — no writes, no CRC violation.
- Added cpu:set_cache_key(unit_number) called by register_entity() in events.lua
to associate a newly-placed cpu with its entity's stable unit_number as the key.
New cpu objects created before placement use a temporary negative key.
- Added cpu:rebuild_compiled() for use in on_load and on_configuration_changed.
- Removed dead code: the input_signals nil-check backfill in reattach_metatables()
could never fire since input_signals has been present since the first version.
Version: 0.8.21
Date: 07. 04. 2026
Bugfixes:
- Fixed crash on load when a save contains combinators created before 0.8.20.
The compiled program array introduced in 0.8.20 is not present in older saves,
so step() crashed with 'attempt to index field compiled (a nil value)'.
- Added module:ensure_compiled() which re-compiles the program from self.memory
if the compiled field is absent or empty. Called from reattach_metatables() in
control.lua immediately after metatable re-attachment, covering both on_load
(normal resume) and on_configuration_changed (mod update). The compilation
cost is paid once at load time per affected combinator, not per tick.
Version: 0.8.20
Date: 02. 04. 2026
Optimizations:
- Replaced the if-elseif instruction dispatcher in step() with a dispatch table
(Lua table keyed by mnemonic string, values are handler functions). The hot path
is now: one array index, one table lookup, one function call. Previously it was
up to 40 string comparisons in the worst case.
- Added a compile() pass that runs once after successful validation. Each source
line is pre-parsed into a record { op, a1, a2, a3 } with immediate values
converted to numbers, label references resolved to line numbers, and mnemonics
upper-cased. step() now performs zero string operations in the hot path.
- Removed advance_ip() as a separate method; IP advancement is now handled
inline in step() based on the handler's return value.
- The advance_ip test was rewritten to use step() directly.
Version: 0.8.19
Date: 02. 04. 2026
Features:
- Added WSIGI od, signal, imm — write signal immediate. Outputs the named signal
with a constant integer count without needing a register to hold the value.
Accepts decimal, hex (0x prefix), and negative immediates. The signal name and
output register are validated at load time along with all other arguments.
Example: WSIGI o0, signal-red, 255
- 7 new tests covering WSIGI basic use, hex/negative immediates, load-time
error detection for bad output register, unknown signal, and non-numeric
immediate, and multi-output independence. 164 tests total.
Info:
- README: corrected signal validation note from 'runtime error' to 'when the
program is saved', reflecting the load-time validation introduced in 0.8.18.
- README: WSIGI added to circuit network output table.
Version: 0.8.18
Date: 02. 04. 2026
Optimizations:
- Complete refactor of load-time validation. validate_program() now checks every
instruction in the program once when code is loaded or saved, covering: unknown
mnemonics, wrong argument counts, invalid registers (x0-x31 and o0-o3), invalid
immediate values, unknown signal names, and undefined branch/JAL labels.
- step() now contains zero validation logic (except divide-by-zero which is only
knowable at runtime). Every instruction handler is pure computation.
- All instructions are described in a declarative INSTR table with argument type
descriptors (rd, rs, rt, od, imm, sig, lbl, reg_or_imm). Adding a new instruction
only requires adding a table entry and a handler in step().
- Refactored tokenize() into a shared local function used by both validate_program()
and step(), eliminating the duplicated strip-and-split logic.
- cpu.lua reduced from 1261 lines to 593 lines. Error-setting sites in step()
reduced from 116 to 7 (divide-by-zero x4, JR range check, nil IP guard,
unknown instruction fallback).
- 13 new tests covering load-time detection of unknown instructions, wrong arg
counts, bad registers, bad immediates, undefined labels, bad WSIG output
register, bad WAIT argument, multiple errors in one program. 157 tests total.
Version: 0.8.17
Date: 01. 04. 2026
Bugfixes:
- Added regression test for the 0.8.16 off-by-one fix. The test loads a program
containing RSIGR, RSIGG, RSIG, and WSIG with valid signal names and asserts
that no error is set at load time. This would have caught the 0.8.15 bug
(tokens[2] = register name being validated as signal name) immediately.
145 tests total.
Version: 0.8.16
Date: 01. 04. 2026
Bugfixes:
- Fixed validate_signals() indexing the signal-name token at position 2 instead of 3.
The mnemonic is still present at tokens[1] in the validator, so the signal name is
at tokens[3] (e.g. RSIG x6, signal-name -> tokens = {RSIG, x6, signal-name}).
In step() the mnemonic is removed via table.remove() before indexing, so args[2]
correctly refers to the signal. The mismatch caused the register name (e.g. x6)
to be validated as a signal name, always failing for any RSIG/RSIGR/RSIGG/WSIG
instruction. Signal instructions in the position table corrected from 2 to 3.
Version: 0.8.15
Date: 01. 04. 2026
Optimizations:
- Moved signal name validation from per-tick (inside step()) to load time
(inside new() and update_code()). Previously valid_signal_name() was called
into Factorio's prototype tables on every tick for every RSIG, RSIGR, RSIGG,
and WSIG instruction. It now runs once via validate_signals() when the program
is loaded or saved, with zero overhead during normal execution.
- validate_signals() scans the program's token stream, identifies signal-name
arguments in the four affected instructions, and pre-populates self.errors
with descriptive messages for any unknown names. The CPU starts in error state
immediately rather than discovering the problem mid-execution.
- Updated tests: validation tests no longer call step() before checking errors.
Added test confirming update_code() re-validates signal names.
144 tests total.
Version: 0.8.14
Date: 01. 04. 2026
Features:
- Added RSIG rd, signal — reads the named signal from BOTH the red and green input
wires and stores the sum in rd. Equivalent to RSIGR/RSIGG followed by ADD, but in
a single instruction. A signal absent on one or both wires contributes 0 to the sum.
RSIGR and RSIGG are retained for cases where per-wire distinction matters.
- Signal name validation: RSIG, RSIGR, RSIGG, and WSIG now validate the signal name
against Factorio's prototype tables (virtual_signal, item, fluid) at runtime.
An unrecognised name produces a descriptive error rather than silently reading 0
or emitting a signal that Factorio would reject. A valid signal name that is simply
absent on the wire at that moment still correctly returns 0 without error.
- Added prototypes mock to test.lua so signal-name validation tests run under Busted
without a live Factorio instance. Known signal names used in tests are registered
in the mock; unknown names correctly trigger error paths.
- 11 new tests (143 total).
Version: 0.8.12
Date: 01. 04. 2026
Bugfixes:
- Fixed changelog.txt format so the in-game mod changelog GUI displays correctly.
Problems were: double separator lines between every version section; two early
version entries missing Version: lines (assigned 0.7.1 and 0.7.2); non-standard
category name 'Documentation:' replaced with 'Info:'; trailing whitespace stripped.
Version: 0.8.11
Date: 01. 04. 2026
Features:
- Added LI rd, imm — load immediate. Sets rd = imm directly. Syntactic sugar for
ADDI rd, x0, imm; cleaner when the intent is loading a constant rather than adding.
Accepts decimal, hex (0x prefix), and negative values. All standard error checks apply.
- Instructions are now case-insensitive. Mnemonics may be written in upper, lower, or
mixed case (ADDI, addi, Addi). The mnemonic is uppercased once during parsing via
instruction:upper() before any comparison. Register names (x0-x31, o0-o3) and signal
names remain case-sensitive as Factorio requires.
Info:
- Updated README.md and LICENSE.md to user-supplied versions. LICENSE now retains
Joakim Lönnegren's original MIT copyright alongside the Analytical Combinator
contributors' copyright. README includes Credits section acknowledging the original
mod and Claude's role in development.
- README: LI added to arithmetic table; new "Instruction case" section documents
case-insensitive parsing.
- 12 new tests (132 total): LI basic use, hex/negative immediates, x0 suppression,
overwrite, error cases; case-insensitive mnemonic tests including a lower-case
loop with BNEI; signal/register case-sensitivity confirmation.
Version: 0.8.10
Date: 29. 03. 2026
Bugfixes:
- Fixed BEQ and BNE: missing register nil-checks meant that a literal (e.g. BEQ x3, 0,
label) or invalid register (e.g. BEQ x3, x99, label) was silently miscompared rather
than raising an error. nil==nil is true in Lua, so BEQ x3, x99 would always branch
regardless of x3; BEQ x3, 0 would never branch. Both now validate both operands first.
- Fixed WSIG: the count source register (third argument) had no nil check. An invalid
register name would silently emit a signal with count nil (treated as 0).
- Fixed JAL: the destination register for the saved return address had no nil check.
Writing to an invalid key (e.g. x99) would silently create a junk table entry.
- Fixed SLT: added nil check on the destination register (first argument).
Features:
- Added BEQI rs, imm, label — branch if rs == immediate value
- Added BNEI rs, imm, label — branch if rs != immediate value
- Added BLTI rs, imm, label — branch if rs < immediate value
- Added BLEI rs, imm, label — branch if rs <= immediate value
- Added BGTI rs, imm, label — branch if rs > immediate value
- Added BGEI rs, imm, label — branch if rs >= immediate value
- All immediate branches accept hex literals (0x prefix) and validate both the
register and immediate operands, erroring cleanly on invalid input.
- 20 new tests including regression tests for the nil-check bugs. 120 tests total.
Version: 0.8.9
Date: 29. 03. 2026
Features:
- Added MULI rd, rs, imm — multiply register by immediate (rd = rs * imm)
- Added DIV rd, rs, rt — integer division, floor toward -inf (rd = floor(rs/rt))
- Added DIVI rd, rs, imm — divide by immediate
- Added REM rd, rs, rt — remainder, sign follows dividend C-style (math.fmod)
- Added REMI rd, rs, imm — remainder by immediate
- DIV, DIVI, REM, REMI all produce a descriptive runtime error on divide-by-zero
rather than crashing. Lua's math.floor and math.fmod are used to give consistent
signed behaviour across all values.
- Note: MUL was already present since 0.8.4; MULI is the new immediate variant.
- 18 new tests covering basic operation, negative values, divide-by-zero errors,
hex immediates, and a practical modulo wrap-around example. 100 tests total.
Version: 0.8.8
Date: 29. 03. 2026
Changes:
- Fixed JAL to save IP+1 (address of the next instruction) rather than the line number
of the JAL itself. This matches standard RISC-V convention and makes JR work cleanly
without a compensating +1. Existing programs using JAL x0 (discard return address)
are unaffected. Programs relying on the specific numeric value saved by JAL will need
to add 1 to their expected values.
- Fixed JR to jump directly to the value in rs (no +1 adjustment needed now that JAL
saves the correct return address).
- JR x0 is now a defined special case: jumps to line 1 (program restart). Since x0 is
always 0 and 0 is not a valid line number, this provides a convenient restart without
requiring a label on line 1.
- Updated all tests: JAL return-address assertions updated (x1=3→4 etc.),
JR test comments corrected, new JR x0 restart test added. 82 tests total.
- README: JAL/JR table entries updated; subroutine example rewritten — the old version
needed an awkward BGT workaround because JAL saved the wrong value; the new example
is clean and straightforward.
Version: 0.8.7
Date: 29. 03. 2026
Features:
- Added BLT rd, rt, label — branch if rs < rt
- Added BLE rd, rt, label — branch if rs <= rt
- Added BGT rd, rt, label — branch if rs > rt
- Added BGE rd, rt, label — branch if rs >= rt
- Added JR rs — jump to instruction at rs+1, enabling subroutine returns.
JAL saves the line number of the JAL instruction itself, so JR adds 1 to
land on the instruction after the call site.
- 16 new tests (81 total): branch taken/not-taken cases for all four new
instructions, JR call/return, nested calls with distinct return registers,
and error cases.
- README: control flow table updated; new subroutine call/return example.
Version: 0.8.6
Date: 29. 03. 2026
Features:
- Added SRL rd, rs, rt — shift right logical by register (zero-fill)
- Added SRLI rd, rs, imm — shift right logical by immediate (zero-fill)
- Hex immediates: all immediate arguments now accept 0x prefix (e.g. ADDI x10, x0, 0xFF).
tonumber() auto-detects base, so decimal and hex both work everywhere.
Changes:
- Renamed shift instructions to match RISC-V convention:
SHL → SLL (shift left logical, register)
SHLI → SLLI (shift left logical, immediate)
SHR → SRA (shift right arithmetic, register)
SHRI → SRAI (shift right arithmetic, immediate)
- Moved bitlib setup (bit32/bit) to module level rather than inside step() to
avoid re-evaluating it on every tick.
- Fixed indentation bug: the else clause of the instruction dispatcher was
accidentally indented inside the CNTSG block.
Info:
- README Shifts table expanded to all six variants with logical/arithmetic distinction noted.
- README new section "Immediate value formats" documents decimal, hex, and negative literals.
- Test suite: shift tests renamed; 4 new tests contrasting SRL/SRLI (zero-fill) against
SRA/SRAI (sign-extend) on negative values. 65 tests total.
Version: 0.8.5
Date: 29. 03. 2026
Bugfixes:
- Fixed bitwise instruction implementation to use bit32 or bit library functions rather
than typical operators.
Version: 0.8.4
Date: 29. 03. 2026
Features:
- Added MUL rd, rs, rt — multiply two registers (rd = rs * rt)
- Added AND rd, rs, rt — bitwise AND
- Added OR rd, rs, rt — bitwise OR
- Added XOR rd, rs, rt — bitwise XOR
- Added NOT rd, rs — bitwise NOT, unary (rd = ~rs)
- Added SHL rd, rs, rt — shift left by register
- Added SHLI rd, rs, imm — shift left by immediate
- Added SHR rd, rs, rt — logical shift right by register
- Added SHRI rd, rs, imm — logical shift right by immediate
- Added CNTSR rd — count of distinct signals on the red input wire
- Added CNTSG rd — count of distinct signals on the green input wire
- All new instructions respect the x0 write-suppression rule and produce
descriptive errors for wrong argument counts or invalid register names
- 25 new tests (61 total)
- README: Bitwise and Shifts instruction tables added; CNTSR/CNTSG added to
circuit input table; two new examples (bit masking, signal presence detection)
Version: 0.8.3
Date: 29. 03. 2026
Bugfixes:
- Fixed README: the "Red/green mixer" example was using SUB (red minus green) despite
claiming to output a sum. Replaced with two correct ADD-based examples:
"Red/green signal sum" (continuous summing loop) and "Red/green sum with threshold gate"
(fires signal-A once combined total exceeds 500).
Version: 0.8.2
Date: 29. 03. 2026
Features:
- Added ADD instruction: ADD rd, rs, rt sets rd = rs + rt (register + register addition).
This is the missing complement to SUB and ADDI. Useful for combining values from two
sources, e.g. summing red and green wire readings of the same signal.
Example: RSIGR x10, iron-plate / RSIGG x11, iron-plate / ADD x12, x10, x11
- Added 6 tests for ADD covering basic addition, accumulation in place, x0 write
suppression, negative values, invalid register, and wrong argument count.
- README: ADD added to instruction table; new example showing red+green signal sum
with threshold gate.
Version: 0.8.1
Date: 29. 03. 2026
Features:
- Assembly code editor now uses a monospace font (NotoMono via the built-in "default-mono"
descriptor). A FontPrototype "ac-mono-14" is declared in prototypes/fonts.lua and applied
to the text-box at GUI creation time via textbox.style.font. No external TTF file is
required as NotoMono-Regular.ttf ships with Factorio core.
Version: 0.8.0
Date: 29. 03. 2026
Changes:
- New technology tree icon (256x256): dark PCB circle with circuit traces, central IC chip,
amber LED, and assembly code line art — no longer uses the vanilla circuit-network graphic
- New mod portal thumbnail (144x144): shows the combinator body with screen chip, green
input wire, red output wire, and a floating assembly code snippet
- Rewrote all locale descriptions in locale/en/base.cfg to specifically describe the
assembly-language programming model rather than generic combinator marketing copy
Version: 0.7.9
Date: 29. 03. 2026
Changes:
- Mod renamed from "Assembly Combinator" to "Analytical Combinator" to distinguish it
from the original constant-combinator-based mod by joalon. All internal entity names,
storage keys, GUI names, prototype IDs, and locale strings updated accordingly.
- License changed to Zero-Clause BSD (0BSD) — no attribution required.
- Updated mod description to better reflect RISC-V inspired assembly language and
dual-wire input capability.
Version: 0.7.8
Date: 28. 03. 2026
Bugfixes:
- Fixed crash when WSIG is used with virtual or fluid signals (e.g. signal-red, crude-oil).
Output signals were always emitted with type="item", causing Factorio to reject any name
that isn't a valid item. write_outputs now resolves each signal name against
prototypes.virtual_signal, prototypes.item, and prototypes.fluid in that order to
determine the correct type. Invalid signal names are silently skipped rather than crashing.
Version: 0.7.7
Date: 28. 03. 2026
Info:
- Fixed incorrect README description for the Threshold Gate example which claimed the
output signal appeared "on the red wire". WSIG writes to an output register with no
wire-colour specificity; the signal appears on whichever wire(s) are physically connected
to the output side of the combinator.
Version: 0.7.6
Date: 28. 03. 2026
Bugfixes:
- Fixed "everything" signal appearing on output wire in alt-mode and leaking onto the circuit
network. The always-true condition used signal-everything as its first_signal, which is a
special aggregate virtual signal that Factorio propagates to the output. Replaced with a
pure constant condition (first_constant=0, comparator="=", second_constant=0) which
references no signals at all and has no side effects on the network.
Version: 0.7.5
Date: 28. 03. 2026
Bugfixes:
- Fixed crash on load: defines.circuit_connector_id was removed in Factorio 2.0 and replaced
by defines.wire_connector_id with per-colour IDs. get_circuit_network() now takes a single
wire_connector_id (e.g. combinator_input_red / combinator_input_green) rather than a
wire_type + circuit_connector_id pair. Fixed in both events.lua and gui.lua.
Version: 0.7.4
Date: 28. 03. 2026
Bugfixes:
- Fixed RSIGR and RSIGG always reading zero: get_circuit_network() requires an explicit
circuit_connector_id for entities with separate input and output connectors. Without it
the call returns nil on a decider combinator. Both events.lua and gui.lua now pass
defines.circuit_connector_id.combinator_input when reading the input-side network.
Version: 0.7.3
Date: 28. 03. 2026
Bugfixes:
- Fixed crash when loading a saved game containing analytical combinators: Factorio does not
persist Lua metatables across saves, so stored cpu objects lost all their methods on load.
control.lua now re-attaches the cpu module metatable in both on_load (normal resume) and
on_configuration_changed (mod update). Also backfills the input_signals field for saves
predating 0.7.0 that were created without it.
Version: 0.7.2
Date: 28. 03. 2026
Bugfixes:
- Fixed crash on placement: LuaDeciderCombinatorControlBehavior does not expose
sections_count / add_section / get_section (those belong to the constant combinator).
Output writing now uses behavior.parameters with a conditions+outputs table, which is
the correct 2.0 API for decider combinators. Clearing outputs uses behavior.parameters=nil.
Version: 0.7.1
Date: 28. 03. 2026
Graphics:
- Added custom microchip display sprite (30x22) replacing the decider combinator's
comparison operator symbols (=, >, <, ≠, ≥, ≤) so the entity is visually distinct
in-world regardless of which operator mode Factorio internally selects
- Added custom 64x64 inventory/crafting icon showing the combinator body with the chip
symbol on screen, a green status LED, and an 'AC' label
Version: 0.7.0
Date: 28. 03. 2026
Major Features:
- Fork of Assembly combinator version 0.6.2 from joalon
- Analytical combinator is now based on a Decider Combinator, providing both input and output
circuit network connections (red and green wires)
- Added RSIGR instruction: read a named signal from the red input wire into a register
- Added RSIGG instruction: read a named signal from the green input wire into a register
- Red and green channels are read independently each tick, enabling programs to respond
to live circuit network state
Changes:
- Recipe now requires a Decider Combinator instead of a Constant Combinator