Do I need this page?
- Yes if your node reads world data (weather, time, light, entities, blocks, biomes)
- Yes if your node triggers effects (sounds, particles, chat messages, displays)
- Use as a lookup table โ you don't need to memorize all 37 methods, just find the one you need
- Skip for now if your node only does math/logic on its input signals (you won't call any context methods)
Prerequisite: Core Concepts
๐ฏ Quick Navigation โ Most addons only need 3โ4 methods
Sensors: readDigitalInput(),
readAnalogInput()
Outputs: applyDigitalOutputs(),
applyAnalogOutputs()
World data: isRaining(),
getLightLevel(),
worldTimeTicks()
Display: publishDisplayMessage()
Use Ctrl+F to search โ treat this page as a lookup table, not a read-through.
What is the Execution Context?
ISpcExecutionContext is created fresh each server tick and passed to every
compiled node's execute(context, state) method. It provides read-only
world access (sensors, inputs) and write-only world actions
(outputs, effects, display messages).
All methods have safe defaults โ if the physical multiblock doesn't
support a feature (e.g., no FE modules), the method silently returns a neutral value
or does nothing. Your node code never needs null-checks.
When is it available?
| Phase | Context State | What your node should do |
INPUT_READ | Fresh, inputs sampled | Read physical/virtual inputs, write to signal bus |
LOGIC_EVALUATION | Same context | Read upstream signals from bus, compute logic, write results to bus |
STATE_UPDATE | Same context | Update timers, counters, latches; read from bus and context |
OUTPUT_APPLY | Same context | Read bus, push values to physical outputs via context |
โน๏ธ Context vs. State
ISpcExecutionContext = world interaction (Minecraft blocks, sensors, effects).
ISpcRuntimeState = signal bus + persistent data (signals between nodes, counters, latches).
Both are passed to
execute(). Use context for the world, state for the program.
Digital I/O (2 methods)
| Method | Returns | Parameters | Default | Description |
readDigitalInput(int channel) |
boolean |
channel โ 1-based input channel number |
โ |
Read the on/off state of a physical digital input block at the given channel |
applyDigitalOutputs(Map<Integer,Boolean>) |
void |
outputStates โ map of channel โ boolean |
โ |
Write on/off values to physical digital output blocks |
โ ๏ธ No defaults
These two methods are
not default methods โ they are always implemented
by the SPC runtime. They are the core I/O methods of any LOGO machine.
Analog I/O (2 methods)
| Method | Returns | Parameters | Default | Description |
readAnalogInput(int channel) |
int |
channel โ 1-based input channel |
0 |
Read the integer signal level from an analog input block (e.g., comparator reading) |
applyAnalogOutputs(Map<Integer,Integer>) |
void |
outputStates โ map of channel โ integer value |
no-op |
Write integer values to analog output blocks |
FE (Forge Energy) I/O (2 methods)
| Method | Returns | Parameters | Default | Description |
readFeInput(int channel) |
int |
channel โ 1-based FE input channel |
0 |
Read stored FE amount from FE I/O block at this channel |
applyFeOutputs(Map<Integer,Integer>) |
void |
feOutputs โ map of channel โ FE amount to transfer |
no-op |
Transfer FE to adjacent machines via FE output blocks |
Virtual Signals (6 methods)
Virtual signals are named global variables shared across all nodes in a program.
They're useful for cross-node communication without wires.
| Method | Returns | Parameters | Default | Description |
readVirtualDigital(String sourceKey) |
boolean |
sourceKey โ named signal key |
false |
Read a boolean virtual signal |
readVirtualInteger(String sourceKey) |
int |
sourceKey โ named signal key |
0 |
Read an integer virtual signal |
readVirtualDecimal(String sourceKey) |
double |
sourceKey โ named signal key |
0.0 |
Read a decimal virtual signal |
writeVirtualDigital(String sourceKey, boolean value) |
void |
sourceKey, value |
no-op |
Write a boolean virtual signal |
writeVirtualInteger(String sourceKey, int value) |
void |
sourceKey, value |
no-op |
Write an integer virtual signal |
writeVirtualDecimal(String sourceKey, double value) |
void |
sourceKey, value |
no-op |
Write a decimal virtual signal |
// Write a virtual signal from one node:
context.writeVirtualInteger("mymod:temperature", 350);
// Read it from another node (same tick, later phase):
int temp = context.readVirtualInteger("mymod:temperature");
Time (2 methods)
| Method | Returns | Parameters | Default | Description |
worldTimeTicks() |
long |
โ |
0L |
Current world time in ticks (absolute, not day-of-cycle) |
isDaytime() |
boolean |
โ |
Computed |
true when worldTimeTicks() % 24000 < 12000 |
Display (2 methods)
| Method | Returns | Parameters | Default | Description |
publishDisplayMessage(UUID nodeId, String message, boolean active) |
void |
nodeId โ the publishing node; message โ text; active โ highlight state |
no-op |
Send a text message to the LOGO display unit attached to this machine |
publishExternalDisplayMessage(String targetIp, UUID nodeId, String message, boolean active) |
void |
targetIp โ network display IP; nodeId; message; active |
no-op |
Send text to an external display unit on the network |
World Sensors (9 methods)
| Method | Returns | Parameters | Default | Description |
isRaining() |
boolean |
โ |
false |
Whether it's currently raining at the machine's position |
isThundering() |
boolean |
โ |
false |
Whether there's currently a thunderstorm |
getLightLevel(int offsetX, int offsetY, int offsetZ) |
int |
Block offset from machine anchor |
0 |
Light level (0โ15) at the offset position |
getPlayerDistance() |
int |
โ |
Integer.MAX_VALUE |
Distance in blocks to the nearest player |
countEntitiesInRadius(int radius, String entityType) |
int |
radius โ block radius; entityType โ registry ID (e.g., "minecraft:zombie") |
0 |
Count entities of a specific type within the radius |
isBlockAt(int offsetX, int offsetY, int offsetZ, String blockId) |
boolean |
Block offset + block registry ID |
false |
Check if a specific block type exists at the offset position |
getContainerFillLevel(int offsetX, int offsetY, int offsetZ) |
int |
Block offset |
0 |
Container fill level (0โ15, like comparator) at offset |
getBiomeId() |
String |
โ |
"" |
The biome registry ID at the machine's position (e.g., "minecraft:plains") |
getMoonPhase() |
int |
โ |
0 |
Current moon phase (0โ7). 0 = full moon. |
// Example: Read nearby entities
int zombieCount = context.countEntitiesInRadius(32, "minecraft:zombie");
// Example: Check what block is nearby
boolean hasFurnace = context.isBlockAt(0, -1, 0, "minecraft:furnace");
Effects (4 methods)
| Method | Returns | Parameters | Default | Description |
playNote(int instrument, int pitch) |
void |
instrument โ note block instrument ID; pitch โ note (0โ24) |
no-op |
Play a note block sound at the machine position |
emitParticles(String particleType, int count) |
void |
particleType โ particle registry ID; count โ number of particles |
no-op |
Spawn particles at the machine position |
launchSignalFlare(int color) |
void |
color โ dye color ordinal |
no-op |
Launch a visual flare above the machine (alarm/notification) |
sendChatMessage(UUID nodeId, String sender, String message) |
void |
nodeId โ source node; sender โ display name; message โ text |
no-op |
Broadcast a chat message to nearby players |
Items (4 methods)
| Method | Returns | Parameters | Default | Description |
readItemInputId(int channel, int slot) |
String |
channel โ I/O channel; slot โ inventory slot index |
"" |
Read the item registry ID from an input inventory slot |
readItemInputCount(int channel, int slot) |
int |
channel; slot |
0 |
Read the stack size from an input inventory slot |
readInventoryFingerprint(int channel) |
long |
channel โ I/O channel |
0L |
Hash of entire inventory contents โ changes when any slot changes |
applyItemOutputs(Map<Integer,String> itemIds, Map<Integer,Integer> itemCounts) |
void |
itemIds โ channel โ item ID; itemCounts โ channel โ count |
no-op |
Request item transfers to output inventory slots |
Data Logging (1 method)
| Method | Returns | Parameters | Default | Description |
recordDataLog(UUID nodeId, Map<String,SpcSignalValue> values) |
void |
nodeId โ source node; values โ named signal snapshots |
no-op |
Record signal values for data logging/trending displays |
Custom Module I/O (2 methods)
These methods bridge addon-registered multiblock modules (see Multiblock Modules)
to the execution context. When a node needs to read from a custom input module or write
to a custom output module, it uses these methods.
| Method | Returns | Parameters | Default | Description |
readCustomInput(String moduleTypeId, int channel) |
SpcSignalValue |
moduleTypeId โ registered type (e.g., "mymod:rotational_input"); channel โ 1-based |
INTEGER_ZERO |
Read a value from a custom input module's channel |
applyCustomOutputs(String moduleTypeId, Map<Integer,SpcSignalValue> values) |
void |
moduleTypeId; values โ channel โ signal value |
no-op |
Write values to custom output module channels |
// Read from a custom rotational input module:
SpcSignalValue rpm = context.readCustomInput("mymod:rotational_input", 1);
int speed = rpm.asInteger();
// Write to a custom output module:
context.applyCustomOutputs("mymod:rotational_output",
Map.of(1, SpcSignalValue.integer(targetSpeed)));
Extension Mechanism (1 method)
For complex world interactions that go beyond the built-in methods, addons register
custom ISpcExecutionContextExtension implementations. See the
Context Extensions guide for full details.
| Method | Returns | Parameters | Default | Description |
getExtension(Class<T> extensionType) |
Optional<T> |
extensionType โ the extension interface class |
Optional.empty() |
Retrieve a registered addon extension for custom world interactions |
// In your compiled node:
Optional<ICreateRotationalContext> ext = context.getExtension(ICreateRotationalContext.class);
ext.ifPresent(rotCtx -> {
int speed = rotCtx.getRotationalSpeed(blockPos);
state.setSignal(outputAddr, SpcSignalValue.integer(speed));
});
Method Count Summary
| Category | Methods | Has Default? | Typical Node Phase |
| Digital I/O | 2 | No | INPUT_READ / OUTPUT_APPLY |
| Analog I/O | 2 | Yes | INPUT_READ / OUTPUT_APPLY |
| FE I/O | 2 | Yes | INPUT_READ / OUTPUT_APPLY |
| Virtual Signals | 6 | Yes | Any |
| Time | 2 | Yes | INPUT_READ |
| Display | 2 | Yes | OUTPUT_APPLY |
| World Sensors | 9 | Yes | INPUT_READ |
| Effects | 4 | Yes | OUTPUT_APPLY |
| Items | 4 | Yes | INPUT_READ / OUTPUT_APPLY |
| Data Logging | 1 | Yes | OUTPUT_APPLY |
| Custom Module I/O | 2 | Yes | INPUT_READ / OUTPUT_APPLY |
| Extensions | 1 | Yes | Any |
| Total | 37 | | |