LuaComb++


A programmable, quality-aware circuit combinator with a guided Lua editor for Factorio ispired by Moon Logic

Content
14 hours ago
2.0
6
Circuit network
Owner:
ZeroAinz
Source:
N/A
Homepage:
N/A
License:
CC BY-SA 4.0
Created:
15 hours ago
Latest Version:
2026.09.07 (14 hours ago)
Factorio version:
2.0
Downloaded by:
6 users

LuaComb++

Overview

LuaComb++ executes restricted Lua scripts inside a circuit combinator. A script can read the green and red input wires, combine their signals, retain controlled data between executions, and produce independent persistent outputs.

The project began as a fork of Moon Logic 2 by Chilla55 and has since been extensively reworked around a guided editing workflow, Factorio 2.0 signal qualities, deterministic execution, and multiplayer safety.


Main features

Circuit interface

  • Read the green wire with g, the red wire with r, or their combined total with get.
  • Address signals by name, type, and quality.
  • Aggregate all qualities or select one exact numeric quality level.
  • Write independently to the green or red output wire.
  • Keep outputs active until they are changed, removed with count 0, or cleared explicitly.

State and scheduling

  • Store private per-combinator data in self.
  • Share data-only global variables between LuaComb++ combinators belonging to the same force.
  • Choose an execution interval from the editor: every tick, every 6 ticks, or once per second.
  • Preserve the last valid outputs if execution fails.

Guided editor

  • Live input and output signal panels.
  • Contextual suggestions for Lua, signals, properties, and LuaComb++ functions.
  • Factorio signal picker for exact signal descriptors.
  • Script formatting and translated Help.
  • Recovery of the last successfully compiled script.
  • Personal library for up to ten named scripts.
  • Settings copy and blueprint support.

Runtime protection

  • Restricted, deterministic Lua environment.
  • Limits for instructions, source size, strings, tables, nesting, persistent data, and signals.
  • Isolated failure handling for each combinator.
  • Force-scoped alerts for connected players when a script is disabled.

Design lineage and focus

Moon Logic 2 and LuaComb++ share the same central idea: express circuit-network logic with Lua. Their interfaces emphasize different styles of use.

Area Moon Logic 2 approach LuaComb++ approach
Editing workflow Compact code window designed for short scripts and pasted logic Guided editor with live panels, completion, formatting, Help, and recovery tools
Circuit access red, green, and out tables Quality-aware g, r, and get records with explicit output functions
Signal identity Direct name-based wire access Explicit type + name + quality identity with convenient aggregate access
Persistent state Per-combinator var data Per-combinator self data plus force-wide shared globals
Scheduling Script-controlled delay and irq values Per-combinator execution profile selected from the editor
Output style Assignment through the persistent out table Persistent set, g.set, r.set, and clear operations
Runtime goal Lightweight programmable circuit transformations Bounded execution, deterministic shared state, and controlled multiplayer behavior
Mods data Great feuture wich provide data from prototypes and other mods stuff Not implemented

LuaComb++ keeps the programmable-combinator concept while offering a workflow aimed at players who want to build and debug scripts directly inside the game.


Quick start

  1. Place a LuaComb++ combinator.
  2. Connect its input and output circuit wires.
  3. Open the editor and choose an execution interval.
  4. Write the script.
  5. Press Compile, validate and save.

Editor changes remain drafts until validation succeeds.

local plates = get["iron-plate"].count

if plates < 100 then
    g.set("signal-A", 1)
else
    r.set("signal-A", 1)
end

Script reference

Reading signals

Every signal record exposes:

Property Meaning
.count Signed signal quantity
.quality Numeric quality level
.quality_level Alias of .quality
.type Signal prototype type
g["iron-plate"].count       -- all qualities on green
r["iron-plate"][2].count    -- exact quality level 2 on red
get["iron-plate"].count     -- all qualities on both wires
get["iron-plate"][0].count  -- base quality on both wires

Unqualified access aggregates every quality. Its .quality is the highest quality whose count is not zero, including negative signals. A valid signal that is absent returns count and quality level 0.

Use a complete descriptor when the signal type must be explicit:

get[{name = "iron-plate", quality = 2, type = "item"}].count

Writing signals

set(signal, count [, quality [, type]])
g.set(signal, count [, quality [, type]])
r.set(signal, count [, quality [, type]])
  • set writes to both output wires.
  • g.set writes only to green.
  • r.set writes only to red.
  • Count 0 removes the exact signal identity.
  • clear() removes every stored output.

Outputs persist across execution cycles, recompilation, saving, and loading until a script changes them explicitly.

Persistent data

Use self for data owned by one combinator:

self.counter = (self.counter or 0) + 1

Use a normal global variable for data shared by every LuaComb++ combinator in the same force:

production_target = (production_target or 0) + 100

Only data can persist. Functions should normally be declared local. A successful recompilation resets self; destroying the combinator removes its local state.

Complete example: seven-segment counter

This example cycles a display through digits 0 to 9.

Setup

  1. Import the blueprint provided below or build a seven-segment display.
  2. Connect virtual signals signal-A through signal-G to their corresponding segments.
  3. Connect the LuaComb++ green output wire to the display.
  4. Select 1 execution per second in the editor.
  5. Compile and save the following script.

Script



self.segments = {
    'ABCEFG', 'CF', 'ACDEG', 'ACDFG', 'BCDF',
    'ABDFG', 'ABDEFG', 'ACF', 'ABCDEFG', 'ABCDFG'
}

self.tickCount = self.tickCount or 1
local pattern = self.segments[self.tickCount]

clear()

for i = 1, string.len(pattern) do
    local letter = tostring(string.sub(pattern, i, i))
    g.set(concat({'signal-', letter}), 1)
end

self.tickCount = self.tickCount + 1

if self.tickCount >= 11 then
    self.tickCount = 1
end

Execution sequence

  1. self.segments contains exactly ten patterns. Table indices 1 through 10 represent digits 0 through 9.
  2. self.tickCount starts at 1 and survives between successful executions.
  3. The current counter value selects the pattern for the digit.
  4. clear() removes the preceding digit because output signals are persistent.
  5. The loop extracts one letter at a time with string.sub.
  6. concat builds signal names such as signal-A.
  7. g.set activates every required segment on the green output.
  8. After index 10 displays digit 9, the counter returns to 1.

At one execution per second, each digit remains visible for one second. Recompiling the script resets self, so the sequence restarts from digit 0.

Blueprint

Copy the complete string and import it through Factorio's Import string command:

0eNrVWO1u2jAUfZXIf4DNIBJI+JBWaYW2D1EQMsGANceJbIetQnn3XdsESos2wh8ahMjJ9bkfx7l2QvZoyXOaSSY0
Gu8Ri1Oh0Ph1jxTbCMKNTZCEojFSCeG8zUmSoQIjJlb0Dxr7Bb5A5TmJ02SZZW1zYILoVL5zCoo5RlRophl1yezJ20LkyZJKiIr/
GQmjLFXgnAqT01TRCTF6s9WgFZM0dmNDjECOlilfLOmW7Bj4ggORTG8Tqlm8gOGVDaTMgKLm3BiVJmY
+uhilGZXEhUPfUAEJNNlY9rE047Bmm7zkQaB4SxNidcTpyk4e5euOopsElCrvh7dv/HycPD2
/NPAJTJ7N2WT69OKO1vgIR0uaHsjTg5djw/AximEUM2FTgbhfkzQXGnJ9MHip9PyZ4GlMuJcRrakUJaus8PXcZ
z4TMadENlszsQZ3Bnwfe0pD22w6nIrmIU7LW6Uz4cHHhefUmIGtU0duHnxUvix9sMfg22o5Pxiiugkz
GhPd3Ddca7Ub2EUqWtgHIhWr/+v8blTOBFt/HHiA4n1Pb6nwIOenML6Nj0y3Qsadaeyoa/qVLDldobGWOS0K0/cfujbAF5bKp15tdw/
N2uuExeUGjZmMc6YXZynx0XxsWsNdM6n04rQC9VtmKtgxqXOwnEpyE/mIXM5Tg0MPZ0TadTVGD+iist5VyspVGNxD2M
+bhPWvEtatn7DwKmG9e7bi5CZh0VXCgvpdsUG13aNfn91jWGn3CO8hbHqTsFGl3aNGwvxupVVWJ2V+pY2xX5+N0a/4+
DG4h7Sn26T1qkmLaiStX6kf73LRnm9TVu0RJKqRsqjSDW14D2UvtykbVLqjfVFlGOWKQg6eSlX+XbugdVjpHv
dlr+Ico99M2vcorz7u4x4O5vg1wAHgEg0s6h1tBkUWhWcI7o4GAh2PLBqeIXgsMHBkoEtjLKWXw6HDwTuOxa4
E2O5OHIuHDkfvOFFpB2lM0wSUnt5RYbSjUtnpDKNg1B+NwmE/GsBPUfwFSkhVkw==

Safety and multiplayer

LuaComb++ scripts run inside a bounded sandbox. Factorio objects, metatables, coroutines, dynamic code loading, and unrestricted libraries are unavailable.

If compilation, input handling, or runtime execution fails:

  1. Only the affected combinator is disabled.
  2. Its last valid outputs remain active.
  3. Connected players belonging to the same force receive an alert.
  4. The last valid script and state remain available for recovery.

Scripts imported from untrusted blueprints should always be reviewed before being enabled.


Credits

LuaComb++ is derived from:

  • Moon Logic 2 by Chilla55 and contributors
  • Moon Logic by mk-fg
  • Sandboxed LuaCombinator by IWTDU
  • LuaCombinator 2 by OwnlyMe

Original and upstream contributors include OwnlyMe, IWTDU, mk-fg, smartguy1196, and Chilla55.

I work on it when i have time...sorry :(