Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: StateSynchronizer #202

Merged
merged 3 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion addons/netfox.extras/plugin.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
name="netfox.extras"
description="Game-specific utilities for Netfox"
author="Tamas Galffy"
version="1.2.0"
version="1.3.0"
script="netfox-extras.gd"
2 changes: 1 addition & 1 deletion addons/netfox.internals/plugin.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
name="netfox.internals"
description="Shared internals for netfox addons"
author="Tamas Galffy"
version="1.2.0"
version="1.3.0"
script="plugin.gd"
2 changes: 1 addition & 1 deletion addons/netfox.noray/plugin.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
name="netfox.noray"
description="Bulletproof your connectivity with noray integration for netfox"
author="Tamas Galffy"
version="1.2.0"
version="1.3.0"
script="netfox-noray.gd"
61 changes: 61 additions & 0 deletions addons/netfox/icons/state-synchronizer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions addons/netfox/icons/state-synchronizer.svg.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://ogbi1hffcoyh"
path="res://.godot/imported/state-synchronizer.svg-9cb9447ba79f114a58e468a24d17b860.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/netfox/icons/state-synchronizer.svg"
dest_files=["res://.godot/imported/state-synchronizer.svg-9cb9447ba79f114a58e468a24d17b860.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
6 changes: 6 additions & 0 deletions addons/netfox/netfox.gd
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ const TYPES = [
"script": ROOT + "/rollback/rollback-synchronizer.gd",
"icon": ROOT + "/icons/rollback-synchronizer.svg"
},
{
"name": "StateSynchronizer",
"base": "Node",
"script": ROOT + "/state-synchronizer.gd",
"icon": ROOT + "/icons/state-synchronizer.svg"
},
{
"name": "TickInterpolator",
"base": "Node",
Expand Down
2 changes: 1 addition & 1 deletion addons/netfox/plugin.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
name="netfox"
description="Shared internals for netfox addons"
author="Tamas Galffy"
version="1.2.0"
version="1.3.0"
script="netfox.gd"
45 changes: 45 additions & 0 deletions addons/netfox/state-synchronizer.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
extends Node
class_name StateSynchronizer

## Synchronizes state from authority.

@export var root: Node
@export var properties: Array[String]

var _property_cache: PropertyCache
var _props: Array[PropertyEntry]

var _last_received_tick: int = -1
var _last_received_state: Dictionary = {}

## Process settings.
##
## Call this after any change to configuration.
func process_settings():
_property_cache = PropertyCache.new(root)
_props = []

for property in properties:
var pe = _property_cache.get_entry(property)
_props.push_back(pe)

func _ready():
process_settings()
NetworkTime.after_tick.connect(_after_tick)

func _after_tick(_dt, tick):
if is_multiplayer_authority():
# Submit snapshot
var state = PropertySnapshot.extract(_props)
rpc("_submit_state", state, tick)
else:
# Apply last received state
PropertySnapshot.apply(_last_received_state, _property_cache)

@rpc("authority", "unreliable", "call_remote")
func _submit_state(state: Dictionary, tick: int):
if tick <= _last_received_tick:
return

_last_received_state = state
_last_received_tick = tick
Binary file added docs/netfox/assets/state-synchronizer-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions docs/netfox/nodes/state-synchronizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# StateSynchronizer

Synchronizes state from the node's authority to other peers.

Similar to Godot's [MultiplayerSynchronizer], but is tied to the [network tick
loop]. Works well with [TickInterpolator].

One way to use this node is to synchronize logic that runs only on the server,
for example NPC's in your games. The NPC's are controlled fully by the server,
and their state is synchronized to the clients by the *StateSynchronizer*
nodes.

## Configuring state

To use *StateSynchronizer*, add it as a child to the target node, specify the
root node, and configure which properties to synchronize:

![StateSynchronizer configuration](../assets/state-synchronizer-config.png)

*Root* specifies the root node for resolving properties. Best practice dictates
to add *StateSynchronizer* under its target, so *Root* will most often be the
*StateSynchronizer*'s parent node.

*Properties* are recorded for each tick on the node's authority ( usually the
server ), and broadcast to other peers. These are analogous to
[RollbackSynchronizer]'s *state properties*.

See [Property paths] on how to specify properties.

## Changing configuration

*StateSynchronizer* has to do some setup work whenever the state or the
input properties change.

By default, this work is done upon instantiation. If you need to change
properties during runtime, make sure to call `process_settings()`, otherwise
*StateSynchronizer* won't apply the changes.

You can change the node's authority without calling `process_settings()` again.
Make sure that the authority is changed the same way on all peers, to avoid
discrepancies.

## When to use StateSynchronizer and MultiplayerSynchronizer

Part of the design philosophy of netfox is to build *on top of* Godot's
networking tools, instead of *replacing* them.

Both [MultiplayerSynchronizer] and StateSynchronizer can be used to synchronize
state from authority to the rest of the peers.

[MultiplayerSynchronizer] uses its own timer, and is independent of netfox's
[network tick loop]. It can also do delta updates, and manage visibility per
peer. Since it is not tied to netfox's tick loop, it does not work with
[TickInterpolator].

StateSynchronizer records all the properties specified and broadcasts them
as-is to all peers. This does not include visiblity or delta updates. The
broadcast happens on every network tick. This node is explicitly designed to
work with [TickInterpolator].

---

You can use StateSynchronizer for properties that you want to be interpolated,
like position, rotation, or any other visual properties.

You can use [MultiplayerSynchronizer] for properties that either don't need
interpolation ( e.g. a unit's HP ), or specifically need one of
[MultiplayerSynchronizer]'s features.

[MultiplayerSynchronizer]: https://docs.godotengine.org/en/stable/classes/class_multiplayersynchronizer.html
[network tick loop]: ../guides/network-time.md
[TickInterpolator]: ./tick-interpolator.md
[RollbackSynchronizer]: ./rollback-synchronizer.md
[Property paths]: ../guides/property-paths.md
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ nav:
- Nodes:
- 'netfox/nodes/tick-interpolator.md'
- 'netfox/nodes/rollback-synchronizer.md'
- 'netfox/nodes/state-synchronizer.md'
- netfox.noray:
- Guides:
- 'netfox.noray/guides/noray.md'
Expand Down