Skip to content

BaseComponentLogic

public abstract class BaseComponentLogic

The base of every part’s component logic, the side of a part that touches the visible and physical world. Override Initialize and Update, and PhysicsUpdate for logic that must keep step with physics. The generated members Rendering, Connections and Interactivity reach the part’s nodes, Properties its own properties, CircuitProperties its circuit logic’s properties, and Circuit its circuit logic.

public Simulation.BaseCircuitLogic Circuit { get; set; }

This part’s circuit logic, the electrical side: read its state (e.g. Circuit.UserData) and hand electrical values back to it. Null when the part has no circuit logic, and still null while Initialize first runs; it is linked just before OnCircuitPropertyUpdated is called with a null name. The host sets it; part logic does not assign it.

virtual

public virtual void Initialize();

Called when the part’s logic is created (when the part is loaded or added, and on Reset State), after Rendering, Connections, Interactivity and the saved property values are in place: set starting visuals and subscribe to interactivity events here. Circuit is still null on this first call, so read circuit values in OnCircuitPropertyUpdated, which follows with a null name once the circuit is linked. It can run again on the same instance (when Play re-analyses an edited circuit, or when the part is moved or removed), so make it safe to repeat. Main thread.

virtual

public virtual void Update(double delta);

Called once per rendered frame on the main thread, for visual work: move meshes, set material values, write decal text. It runs while the part is visible, before Play and during Play, but not while the simulation is paused. For logic that must keep step with physics use PhysicsUpdate.

Parameters

  • delta: Seconds since the last frame. During Play it is the SIMULATED time, so a visual that integrates a rate keeps pace with a slowed simulation; before Play it is the real frame time.

virtual

public virtual void PhysicsUpdate(double delta);

Called on every PHYSICS tick while the simulation is playing (the physics rate, 1 kHz or more), not on the render frame, for logic that must stay tightly coupled to the physics solver. Update runs at the render rate (about 60 Hz), too slow to close a stiff electrical-mechanical loop: a low-inertia rotor spins up in under one render frame, so a back-EMF read there lags and the motor overshoots into a current runaway. Put such coupling here: read a body’s velocity (for example Rendering.Shaft.Rigidbody.SpinRate), feed it back electrically (through Circuit.UserData) and apply the reacting force or torque, so it runs in lock-step with the bodies. Any device whose force depends on live body state (a motor, a governor, an active damper, force feedback) belongs here. It can run on the physics thread and runs many times per frame, so keep it lean and leave visual work to Update.

Parameters

  • delta: The physics step in seconds.

virtual

public virtual void OnPropertyUpdated(string propertyName);

Called when one of THIS component’s exposed properties changes, without polling in Update. Fired once after Initialize on load (with a null propertyName), and again each time a component property is edited in the designer (with the changed property’s name).

virtual

public virtual void OnCircuitPropertyUpdated(string propertyName);

Called when a CIRCUIT-logic property changes, separate from OnPropertyUpdated so the origin is unambiguous. Fired once with a null propertyName after the circuit is linked on load, and again with the property’s name each time a circuit property is edited. Read the value via the generated CircuitProperties view (e.g. CircuitProperties.Resistance).

public void RequireRender();

Asks the 3D view to redraw for the next few frames. The view is drawn only when something asks, so call this after changing how the part looks (a material value, a glow) to make sure the change is drawn. Call it when something actually changed, not every frame: asking every frame keeps the GPU busy on a still scene. Main thread (Update, Initialize or an interactivity handler).

public void SaveState(string name, int value);

Persist a component property’s value so it survives a save and load, for LATCHING state such as a slide or DIP switch position (unlike a momentary press, which is re-driven each frame). Update the property in your own code first (e.g. Properties.Position = 1;), then call SaveState("Position", Properties.Position). This is lightweight: it does NOT pause or re-analyze the simulation (unlike a designer inspector edit), so it is safe to call from a pointer event while the circuit runs. The name must match an exposed component property; on load that property is restored from the save before Initialize. It also calls MarkDesignDirty for you, since persisting a value changes what would be written on save. Main thread (an interactivity handler or Update).

Parameters

  • name: The property’s name as it appears after Properties.
  • value: The value to save, the one the property now holds.
public void SaveState(string name, bool value);

Persist a true or false component property (a switch that is on or off) so it survives a save and load. Set the property first, then call this with its name, as with the whole-number overload: it does not pause the simulation, the property is restored before Initialize on load, and the workspace is marked as having unsaved changes. Main thread.

Parameters

  • name: The property’s name as it appears after Properties.
  • value: The value to save, the one the property now holds.
public void SaveState(string name, double value);

Persist a decimal component property (a knob’s setting, say) so it survives a save and load. Set the property first, then call this with its name, as with the whole-number overload: it does not pause the simulation, the property is restored before Initialize on load, and the workspace is marked as having unsaved changes. Main thread.

Parameters

  • name: The property’s name as it appears after Properties.
  • value: The value to save, the one the property now holds.
public void MarkDesignDirty();

Flag the active workspace as having unsaved changes: adds the “(*)” marker to its tab and makes the close and new-scene guards prompt to save. Call this when a runtime interaction changes state that ought to be saved, e.g. a user flipping a latching switch. SaveState and its overloads already call this, so you only need it directly for a design change that does NOT persist a property. Does nothing when there is no active workspace (e.g. headless). Main thread only: fire it from an interactivity event or Update.

Generated from the CRUMB source, commit fcec660d, 2026-10-29.