Configurator: factory circuit settings
Connect computer NETWORK to configurator NETWORK; connect factory devices to its
separate TARGETS port. peripheral.find("configurator", "red") selects discovery
red; cfg.getDevices("green") independently selects TARGETS green. These roles
never bridge. Vanilla poles relay same-color TARGETS wires, but isolated native
combinator input/output connectors do not bridge. Ghosts, foreign force/surface
and wireless transport do not grant authority.
Complete methods
All use dots, strict arity, opaque string IDs and explicit target Wire. Every addressed operation rechecks live identity/path. Replacement at identical coordinates gets a different ID. Readback is copied Data, not Factorio objects.
| Signature | Exact returns |
|---|---|
cfg.getDevices(target_wire) |
Complete ID-sorted unique DeviceInfo array, never a partial prefix |
cfg.getDevice(id, target_wire) |
DeviceInfo or one nil for absent/disconnected/replaced identity |
cfg.getCapabilities(id, target_wire) |
CapabilitySet of current typed settings/observations/sections |
cfg.getConfiguration(id, target_wire) |
ConfigurationSnapshot |
cfg.setConfiguration(id, patch, target_wire) |
Normalized native ConfigurationSnapshot after verified update |
cfg.getSections(id, target_wire) |
Native-index-ordered SectionInfo array |
cfg.addSection(id, definition, target_wire) |
Actual new native integer index |
cfg.setSection(id, index, patch, target_wire) |
Selected SectionInfo after update |
cfg.removeSection(id, index, target_wire) |
Boolean; false if absent, true after verified removal |
cfg.getLimits() |
Defensive common + configurator capacities |
Device and schema records
DeviceInfo: id, prototype, type, position={x,y} actual world coordinates,
surface={index,name}, direction native enum name (not necessarily cardinal),
quality, target_wire, sorted connected_connector_ids native enum-name array,
configurable:boolean, configuration={behavior?, readable:string[],
writable:string[], sections:boolean, reason?}. Helpers are hidden; public mod
bodies are protected/nonconfigurable. Devices without supported behavior remain
in inventory with a reason. Inspection never creates native control behavior.
CapabilitySet: api_version=1, behavior?, settings field-name map,
observations field-name map, sections={supported, fields, limits}, reason?.
Each FieldSchema describes kind, readable, writable, clearable, optional
min/max/max_bytes/max_items, enum values, nested fields/required,
additional_fields=false, array items, union alternatives,
prototype_registry, constraints, unavailable_reason. Selector objects also
expose operation variants={operation={fields,required}}. Respect current flags
and reasons rather than inferring writability from a name.
The complete readable settings catalogue and nested schemas list every pinned root field, enum and parameter type. No need to open development JSON to find supported settings. Native mode restrictions remain dynamic:
- include_fuel needs a fuel inventory; electric machines cannot enable it.
- blue_signal needs a chain signal; normal rail signal marks it unreadable/unwritable.
- logistic-container exclusive mode needs requester/buffer mode.
- landing-pad set_requests requires the engine's space-travel feature; base exposes none/send_contents only.
- electric turrets cannot read ammunition; asteroid collectors' inherited connect_to_logistic_network setting is natively ineffective and unavailable.
- speaker zero-based instrument/note IDs must exist on the actual target. Headless verification does not establish audible playback.
Behavior class selects the adapter, not a prototype-name allowlist; expansion prototypes must actually be installed. This is circuit configuration only, not arbitrary entity properties, inventory mutation, creation, teleport or remote calls.
Read and patch
ConfigurationSnapshot is {values={...}, unset={string,...}, observations={...}}.
False is a real value; nil/unset is different. disabled and evaluated
circuit_condition_fulfilled/logistic_condition_fulfilled are observations, not
writable settings or nested fulfilled inputs.
Patch: {set={field=value,...}?, clear={field_name,...}?}. An empty patch is a
validated read/no-op. Each set root replaces a complete value; nested maps are
not recursively merged. Omitted roots remain. Explicit clear requires clearable
metadata, cannot repeat or overlap set. Unknown/read-only fields, malformed Data,
invalid prototype/quality/enum or broken variants fail before mutation.
Signal type/name are explicit; quality defaults normal and readback includes it.
Configurator SignalID additionally supports installed entity, recipe, space-location,
asteroid-chunk and quality signal types where the native schema permits them;
logic-handler ordinary SignalId remains item/fluid/virtual only.
Quality/location object unions become registered name strings, never native
objects. Conditions are flat {first_signal=..., comparator=..., constant=...}
or second_signal instead of constant; no legacy condition={...} wrapper.
Comparators =, >, <, ≥/>=, ≤/<=, ≠/!= normalize aliases. Default comparator <,
constant 0. Clearing conditions can return native defaults, not nil. Ordinary
first condition operands permit anything/everything; second operands do not.
Arithmetic each output requires each input; decider each output requires an each
condition. See nested schemas for full combinator/selector forms.
Setters apply deterministically (signals/modes, conditions, activation switches; alphabetical inside ranks) with no simulation advance during the operation. Preflight reserves setter/readback/restoration work. Unexpected engine failure restores prior supported target settings and verifies them. Failed restoration retains explicit recovery and faults further writes through that configurator. A newly created behavior can be reset to defaults, not deleted; shared-group creation and third-party notifications are not global rollback.
Last successful write wins, not a lock or compare-and-set. Stop, cable loss or configurator removal does not undo applied native settings. Player edits remain until a new explicit write. Reading/reconnecting does not periodically enforce an old desired configuration.
Constant-combinator sections
Only compatible targets support section methods; others raise E_UNSUPPORTED.
SectionInfo has index, enum-name type, is_manual, active, group,
multiplier, indexed filters, filters_count, dynamic capabilities.
Indexes are native 1-based and shift after removal: always re-enumerate.
Definition fields/defaults: active=true, group="", multiplier=1, filters={}. SetSection uses the same patch form for these four fields, none clearable; use filters={} to empty. Joining an existing nonempty group reads its effective filters instead of replacing them with defaults. Nonmanual sections are read-only, including removal. Removing missing index returns false, not an invented section.
Filters are LogisticFilter records, not logic Signal arrays: explicit index
1–128, optional value signal/quality/comparator, signed min, optional unsigned
max/minimum_delivery_count and registered import_from location. Sparse slots are
represented by a dense list of explicit indexes. Duplicate indexes/identities
refuse. Nonzero min needs an exact quality filter. Readback normalizes item import
default to registered nauvis; multiplier preserves native float32 precision.
Shared filter writes always raise E_SHARED_SCOPE. Explicit group="" detaches
only the selected section, preserves effective filters, then permits optional local
replacement. Never silently detach. Nonempty final group cannot combine group
assignment with filters. Active/multiplier/reference changes stay target-local.
Section failure recovery does not overwrite a protected nonmanual suffix.
Bounds, programs and troubleshooting
Initial limits: target_nodes=256 connector vertices, target_edges=512, configuration_bytes=16384, configuration_nodes=4096, patch_fields=32, sections=32, section_filters=128. Common return/callback/allocation bounds also apply; maxima cannot necessarily be combined in one callback. Pending/limit errors are not an empty target inventory. Active service needs configurator power; getLimits still works if reachable and unpowered.
Run configurator-program with one inserter on green TARGETS to set its condition, or configurator-sections with a constant combinator on green. The factory tutorial supplies actual output. No inserter movement from configuration alone is expected: it still needs power, items and a circuit signal. If a setting refuses, inspect current writable/reason metadata, exact enum/prototypes and selected connector. For shared filters explicitly detach or edit the native group manually; never retry unsafe writes in a loop.