Skip to content

Cybersyn2 Constant Combinator

Cybersyn 2 Constant Combinator is a dedicated constant combinator mod for Project Cybersyn 2 in Factorio 2.0. It provides a reactive user interface powered by fcore and TypeScript JSX for managing station priorities, 32-bit network bitmasks, item/stack quantity calculations, and section group requests directly on native Factorio 2.0 control behavior sections.

Cybersyn 2 Constant Combinator GUI

Features

Combinator Control Panel

Status toggle (Output: On / Output: Off), 40-slot output signal grid, and instant tabbed navigation (Combinator and Settings tabs).

Priorities Summary Pane

Displays an integrated telemetry pane showing all unique items/fluids at the station with their Min/Max Request and Supply priorities across matching networks.

32-Bit Bitmask Encoder

Interactive 32-channel visual bitmask editor dialog with live network scanner across all active surfaces.

Item and Stack Calculations

Dual input fields for Stacks and Count with automatic focus based on signal type (items vs fluids) and automatic negative conversion for Cybersyn requests.

Player Settings and Admin Operations

Embedded in-game settings tab with draft state management and optional admin batch updates across all world combinators.

Reconciliation and Lifecycle Architecture

Built on fcore Virtual DOM diffing, bucketed polling schedulers, and native C++ UI elements.


Logistic Sections Structure

The combinator organizes native Factorio 2.0 constant combinator sections into dedicated functional roles:

  1. Section 1 (Station Priority): Manages the cybersyn2-priority virtual signal.
  2. Section 2 (Network Mask): Manages network mask bit flags on signal-A (or a customized network signal).
  3. Sections 3+ (Custom Section Groups): User-defined item and fluid request groups.
  4. Automated Save Migrations: Includes a migration script that reorganizes legacy constant combinators from older saves automatically.

Station Priority and Network Telemetry

Station Priority Adjustment

Adjust the station priority directly via synchronized Slider and Numeric input fields. Default values for newly built combinators are configurable per player.

Signal Priorities Summary (Telemetry)

The built-in Priorities Summary table queries Cybersyn 2 in the background and aggregates logistics data:

  • Inspects all item and fluid orders at the station.
  • Scans all matching network providers and requesters across the world.
  • Displays live Min/Max Request Priorities (Blue) and Min/Max Supply Priorities (Red) per signal directly in the combinator window.

Network Masks and Bitmask Encoder

Factorio train networks in Cybersyn 2 utilize 32-bit channel bitmasks.

Interactive Bitmask Grid

Click individual bits (1–32) to toggle channels on or off:

Bitmask Encoder Dialog

Global Active Networks

Discovers all active network masks in use across factory surfaces and allows one-click adoption:

Active Global Networks Dialog

Signal Input and Stack Calculation Rules

The behavior of the Stacks and Count input fields dynamically adapts based on the selected Signal Type:

Signal TypeStacks InputCount InputDefault FocusOutput Quantity Formula
Item (Stackable)EnabledEnabledPreferred Mode (Counts / Stacks)stacks × stack_size (or exact count)
Fluid / Virtual (Non-stackable)DisabledEnabledCountExact count
None (Empty Slot)EnabledEnabledPreferred ModeDefault setting value (or 1 / 1 stack)

Slot Controls:

  • Left-Click empty slot: Opens the signal picker dialog.
  • Left-Click filled slot: Selects the slot and focuses the preferred input field.
  • Right-Click filled slot: Clears the signal filter from the slot.

Default Fallback: If neither input field contains a value when selecting a signal, it uses the configured Default Output Stacks or Default Output Count setting (or 1 stack / 1 item if default settings are 0).

Negative Values: If Automatically make output signals negative is enabled (default), calculated values are output as negative integers for Cybersyn 2 logistics requests.


Player Settings

Preferences are configured directly inside the combinator’s Settings tab:

Player Preferences

Player Settings Tab

Admin Batch Updates

Admin Batch Updates
SettingDefaultDescription
Automatically make output signals negativetrueOutputs item and fluid requests as negative values for Cybersyn 2.
Default Station Priority10Default priority assigned to newly placed combinators.
Default Network Signalsignal-ADefault network mask signal prototype (e.g. signal-A, signal-B).
Default Network Mask1Default network bitmask flag for new stations.
Default Output Stacks0Default stack input value pre-filled in GUI (0 for 1 stack fallback).
Default Output Count0Default count input value pre-filled in GUI (0 for 1 item fallback).
Default Item Input Mode"count"Preferred default focused input field for items ("count" or "stacks").

Admin Batch Update Options:

  • Apply priority to all combinators (Admin only): Updates all existing combinators in the world matching the previous default priority on Save.
  • Apply network to all combinators (Admin only): Updates all existing combinators in the world matching the previous default network signal and mask on Save.

Component Implementation

1. Root Window Registration (main.tsx)

import { createElement, useState, useMemo, useEntityLifecycle, registerComponent } from "fcore/react";
import type { LuaEntity, PlayerIndex } from "factorio:runtime";
import { WindowFrame, TabbedPane, Tab } from "fcore/react-components";
import { CombinatorTab } from "./combinator_tab";
import { PrioritiesSummary } from "./priorities_summary";
import { SettingsTab } from "./settings_tab";
import { Combinator } from "../../models/combinator";
import { CAPTIONS, GUI } from "../../constants";
export function MainWindow({ playerIndex, entity: initialEntity }: { playerIndex: PlayerIndex; entity: LuaEntity }) {
const [entity, setEntity] = useState<LuaEntity | undefined>(() => initialEntity);
useEntityLifecycle(entity, {
onDestroyed: () => setEntity(undefined),
onRevived: (newEntity) => setEntity(newEntity),
});
const comb = useMemo(
() => (entity && entity.valid ? new Combinator(entity) : undefined),
[entity],
);
if (!entity || !entity.valid || !comb) return undefined;
return (
<WindowFrame
name={GUI.MAIN_ELEMENT_NAME}
caption={CAPTIONS.TITLE}
playerIndex={playerIndex}
pinnable={true}
styles={{ maximal_width: 470, minimal_width: 455 }}
>
<TabbedPane default_tab_index={1}>
<Tab caption={CAPTIONS.TAB_COMBINATOR}>
<CombinatorTab playerIndex={playerIndex} combinator={comb} />
</Tab>
<Tab caption={CAPTIONS.TAB_SETTINGS}>
<SettingsTab playerIndex={playerIndex} combinator={comb} />
</Tab>
</TabbedPane>
</WindowFrame>
);
}
registerComponent(GUI.MAIN_ELEMENT_NAME, MainWindow);

2. Zero-Allocation Polling with useInterval (priorities_summary.tsx)

import { createElement, useState, useInterval } from "fcore/react";
import { SlotButton, SlotButtonTable, ScrollPane } from "fcore/react-components";
import { querySignalPriorities, findStationForCombinator } from "../priorities";
export function PrioritiesSummary({ playerIndex, combinator }: PrioritiesSummaryProps) {
const entity = combinator.getEntity();
if (!entity || !entity.valid) return undefined;
const [prioritiesCache, setPrioritiesCache] = useState(() =>
querySignalPriorities(entity)
);
// Polls network status every 120 game ticks (2 seconds) via fcore bucket scheduler
useInterval(() => {
if (!entity.valid) return;
const newPrio = querySignalPriorities(entity);
setPrioritiesCache(newPrio);
}, 120);
if (!prioritiesCache || prioritiesCache.length === 0) return undefined;
return (
<ScrollPane style="scroll_pane" maximal_height={160}>
<SlotButtonTable column_count={5}>
{/* Render live priority badges */}
</SlotButtonTable>
</ScrollPane>
);
}