Skip to content

Sync and Events

Ahmad Saleem edited this page Sep 4, 2026 · 6 revisions

Sync and events

A server doesn't have the network data the moment it starts. It has to connect to the proxy and receive everything first. That gap is short, but scripts that ignore it break in ways that are hard to find later.

The startup problem

When a server starts, its copy of the network variables is empty.

Empty isn't the same as "the network has nothing". During that gap this says yes even for players who already have data:

if {?coins::%uuid of player%} is not set:
	set {?coins::%uuid of player%} to 500   # about to wipe a real balance

So skNetwork refuses every write until the first sync finishes. Refused writes are counted and logged:

refused a write to {?coins::abc}: not synced with the proxy (SYNCING).
3 write(s) dropped so far. Guard writes with 'network is synced'

Reads still work. They just answer from an empty copy.

Sequence diagram: lobby sends HELLO, the proxy replies WELCOME, SNAPSHOT chunks, then SYNCED. Only after SYNCED are writes accepted and on network sync fires.

network is synced

if network is synced:
	# safe to read and write
if network is not synced:
	# still starting up

Guard anything that runs early:

on join:
	if network is not synced:
		kick player due to "The network is still starting. Try again in a moment."
		stop
	atomically set {?coins::%uuid of player%} to 500 if it is not set

It also tells you whether the proxy is reachable right now:

command /netstatus:
	trigger:
		if network is synced:
			send "Network is up."
		else:
			send "Network is down. Balances are read only."

on network sync

Fires once the copy is filled in and writes are accepted.

on network sync:
	send "Network ready on %network server name%" to console

It fires again after every reconnect, not only at startup. That makes it the right place to rebuild anything this server owns.

The usual case is a cross-server player list. A server that crashes never runs on quit, so its players would stay in the list forever. Clearing and rebuilding on every sync fixes that:

on network sync:
	delete {?online::%network server name%::*}
	loop all players:
		add loop-player's name to {?online::%network server name%::*}

A crash now only leaves stale names until that server comes back.

on network disconnect

Fires when the server loses the proxy.

on network disconnect:
	broadcast "&cLost the network. Money is read only for now."

Reads keep working from the copy the server already holds. Writes are refused until it reconnects.

Reconnecting is automatic. The wait starts at 1 second and doubles up to 30 seconds.

Both events were checked by running /sknet reconnect on a live server:

EVENT: network disconnect fired on lobby
EVENT: network sync fired on lobby

They arrived one second apart.

network server name

The name of the server the script is running on. It comes from server-name in that server's plugins/skNetwork/config.yml.

send "This server is %network server name%"

name of this network server means the same thing.

This is what lets one script go to every server and still behave differently on each:

on join:
	add player's name to {?online::%network server name%::*}
	set {?stats::server::%uuid of player%} to network server name

on quit:
	remove player's name from {?online::%network server name%::*}

Every server runs the same file and writes to its own list. Read the lists back for a network wide view:

command /netonline:
	trigger:
		send "lobby:    %size of {?online::lobby::*}%"
		send "lobby2:   %size of {?online::lobby2::*}%"
		send "survival: %size of {?online::survival::*}%"

If server-name is blank, the name becomes server- plus the port, like server-25567. Set it properly. Two servers sharing a name causes real problems, see Limitations.

Putting it together

A starting balance given once for the whole network, on whichever server sees the player first:

on join:
	if network is not synced:
		stop
	atomically set {?eco::bal::%uuid of player%} to 500 if it is not set
	atomically add 1 to {?eco::joins::%uuid of player%}
	set {?stats::server::%uuid of player%} to network server name

The if it is not set form means it doesn't matter that this runs on three servers. Only the first one wins.

See also

Clone this wiki locally