This example showcases the usage of SyncSys add-on to simplify networking of scene spawns/despawns over network.
Even though the example showcases it in 2D this system is general enough and can be used for 3D or even UI too.
Verified to work with Godot 3.1.
Godot's main unit of abstraction is node/scene and high level networking provides great tools for networking some aspects of that abstraction. However in my opinion that's not enough. What's the main pain-point and missing feature I have in high level networking is inability to easily network node spawns/despawns. That's why I created the SyncSys addon as a workaround. Also later an optional replication feature was added.
System consists of the 2 new nodes: SyncRoot
and SyncNode
.
When a SyncNode
is added under a SyncRoot
in hierarchy then (if the SyncRoot
node is a network master) the SyncNode
's direct parent addition/removal will be networked if enabled
is set to true, and replicated if replicated
is set to true.
SyncNode
's parent name
and network master id
is carried over the network properly when spawned.
Clients listen to server or masters. Server automatically relays events from masters to puppets.
System was designed with dedicated servers in mind. Currently server-as-player may not work properly, to be improved in the future.
There can be as many SyncRoot
nodes in a hierarchy as one wishes. It's up to the server/master to manage them. They will co-exist simultaneously just fine. This could be used to achieve streaming different parts of open-world map to different clients without much effort.
- Copy the
addons/sync_sys
folder into theaddons
folder of your project. - Activate
SyncSys
plugin underProject -> Project Settings -> Plugins
. - Add
SyncRoot
node, somewhere appropriate in your SceneTree. Usually an AutoLoad works great. Make sure to callsync_client(id)
when new client connects to the server, to update that client with the current state of the world. - Navigate to a scene whose instantiation you would want to be networked.
- Add
SyncNode
(or any of it's subclasses) as the direct child of the given scene's root. Tweak the settings to your liking, see API reference for more info. - Instantiate the given scene and add that instance as a child anywhere under the
SyncRoot
's node in hierarchy. NOTE: Due to engine's RPC limitations, if you're instantiating the same scene multiple times make sure to explicitly name the instances differently. Or add children withadd_child(your_instance_here, true)
, the second argument must be set totrue
. - It should work automagically.
sync_client(id)
-- used to sync whole sync root tree state to the clientsync_spawn(node)
-- synchronizes spawn of the given node over network, usually doesn't need to be called directly because SyncNode will do it for us automaticallysync_spawn(node)
-- synchronizes despawn of the given node over network, usually doesn't need to be called directly because SyncNode will do it for us automaticallyclear(free=true)
-- removes and frees all children, if argument free is set the children will also be queued for free upon being removed
signal spawned(data)
-- this signal is called when the initial spawn data is sent, it will awlays get called once on node spawn if node enabled even if replication itself is disabledsignal replicated(data)
-- this signal is called when the new replication data arrives, it's not getting called if the replication for this node is disabledvar enabled : bool
-- if this node is enabled it's spawning and despawning will be synchronized over networkvar replicated : bool
-- whether or not automatic replication is enabledvar force_reliable : bool
-- by default replication (except for spawn/despawn messages) is sent as unreliable, turn this on if you wish for it to be always sent as reliablevar interval : float
-- interval at which replication happens if enabledfuncref validate(old_data, new_data)
-- a FuncRef to custom validation function. It will be called before received replication data is applied to the SyncNode (and later sent out to other nodes, if server). To prevent malicious (hacking/cheating) clients you can correct the values by modifiying values stored inside thenew_data
dictionary.var data : Dictionary
-- this dictionary gets sent from master to puppets if replicated is set to truereplicate(reliable=true)
-- this function can be called to replicate the data dictionary over to puppets, will only work on masters. Doesn't usually need to be called directly, it's called automatically under the hood. Although you can call it directly if you've disabled automatic replication and want to control exactly when the replication data is sent out.
This node simplifies synchronization of Node2D
nodes over network. It will automatically replicate and apply parent's transform.
It writes/reads it's state to data.transform
be careful not to manipulate it unless you know what you're doing.
- subclasses SyncNode, hence all SyncNode properties apply
var interpolate : bool
-- whether or not received transform should be interpolated (smoothed motion)var lerp_speed : bool
-- how much of interpolation to apply ifinterpolate
is enabled
Pretty much the same as SyncTransform2D but works on Spatial
nodes.
This node simplifies synchronization of RigidBody2D
nodes. It will automatically replicate rigidbody state and apply it. This node attempts to extrapolate/dead reckon on missing packets, also allows sleeping puppet bodies to sleep until they recieve a packet with actual movement from the master.
It writes/reads it's state to data.transform
, data.linear_velocity
, data.angular_velocity
be careful not to manipulate it unless you know what you're doing.
- subclasses SyncNode, hence all SyncNode properties apply
var interpolate : bool
-- whether or not received transform should be interpolated (smoothed motion)var lerp_speed : bool
-- how much of interpolation to apply ifinterpolate
is enabledvar epsilon : bool
-- position/force difference threshold above which body will forcefully woken up (if sleeping) and made to reconcileintegrate_forces(state)
-- due to godot limitations you should call this function in your parent's node_integrate_forces(state)
function, see example here.
Pretty much the same as SyncRigidBody2D but works on RigidBody
nodes.
Initial release
Ability for host play added. Server now can spawn objects for himself and sync node emulates replication to itself, so the code stays the same as for remote clients.
Introduction of specific SyncNode subclasses to simplify common replication usecases:
Examples moved to the examples
directory instead of being placed in the project root.
Implemented ability to supply validate
callback to SyncNode. This makes it possible to cope with malicious clients.
Clients now replicate strictly to server. Server replicates to everyone.
Spawning and despawning is now server authoritative, SyncRoot masters no longer honored, only servers.