Download Game! Currently 73 players and visitors. Last logged in:DealRauskisPereKlarence

Blitzer's Blog >> 72033

Back to blogs index
Posted: 05 Sep 2026 10:41 [ permalink ]
Combining publishing and listening into a single EFUN is the absolute right
instinct. By unifying them, you essentially transform your standard LPC
objects into distributed, eventually-consistent entities that automatically
repair themselves across the network.
We can introduce a single, self-documenting EFUN like mesh_sync_object(ob,
topic). Once an object is bound to a topic, it inherently publishes its own
mutations and simultaneously listens for external state changes.
Here is how we can architect this on the sub-LPC level to guarantee
persistence and solve the chicken-and-egg synchronization problems.
Resolving the Chicken-and-Egg via Event Sourcing
To make node restarts completely idempotent, the transport layer shouldn't
just broadcast the current static values of the object; it should broadcast
the intent.
By relying on an event sourcing model, the in-memory mailboxes can elegantly
handle host failures:
 * Initialization: When Host B spins up and calls mesh_sync_object(ob,
"score_daemon"), it doesn't blindly overwrite the network. It broadcasts a
"sync_request" to the mesh.
 * Reconciliation: Host A (or a decentralized database) receives the request
and replies with the object's chronological event history. Host B rapidly
replays these events in memory to rebuild the current state.
 * Conflict-Free Execution: Treating these shared daemons structurally as
Conflict-free Replicated Data Types (CRDTs) ensures that if Host B and C
mutate the object simultaneously, the underlying logical operations merge into
the exact same state without race conditions.
The Sub-LPC Mailbox Implementation
Under the hood, we can implement this dynamically so the LPC developer never
has to write a manual network loop again:
 * The Registry: Calling mesh_sync_object(ob, topic) adds the object's ID to a
native rt.__MESH_REGISTRY.
 * The AST Interceptor: Inside codegen.js, we wrap variable assignment
operators (=, +=) for synced objects. Whenever a variable inside ob mutates,
the AST silently generates an intent log and pushes it directly into
rt.__OUTBOX for the host to route.
 * The VM Updater: When the host pushes an external state change into
rt.__INBOX, the VMs tick processor intercepts it, safely modifies the local
object's variables, and triggers an optional mesh_update() callback inside the
LPC object so it can react to the new data.
This gives you a completely decentralized architecture where your LPC daemons
survive node crashes automatically.
To implement the AST interceptor efficiently, should we automatically
intercept and sync all variables inside a meshed object, or should we
introduce a special variable modifier (like sync int score;) to keep network
traffic strictly limited to marked variables?