Skip to content
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 and contributors"
version="1.42.5"
version="1.43.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 and contributors"
version="1.42.5"
version="1.43.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 and contributors"
version="1.42.5"
version="1.43.0"
script="netfox-noray.gd"
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 and contributors"
version="1.42.5"
version="1.43.0"
script="netfox.gd"
33 changes: 32 additions & 1 deletion addons/netfox/rollback/predictive-synchronizer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ var _liveness_nodes: Array[Node] = []

var _properties_dirty: bool = false

static var _managed_roots := {} # root node to PredictiveSynchronizer

## Process settings.
## [br][br]
## Call this after any change to configuration.
Expand All @@ -42,7 +44,7 @@ func process_settings() -> void:
_sim_nodes.clear()

# Gather all prediction-aware nodes to call during prediction ticks
var managed_nodes := [root] + root.find_children("*")
var managed_nodes := [root] + _collect_managed_nodes(root)
for node in managed_nodes:
if NetworkRollback.is_rollback_aware(node):
_sim_nodes.append(node)
Expand Down Expand Up @@ -108,11 +110,16 @@ func _enter_tree() -> void:
if Engine.is_editor_hint():
return

_managed_roots[root] = self

if not NetworkTime.is_initial_sync_done():
# Wait for time sync to complete
await NetworkTime.after_sync
process_settings.call_deferred()

func _exit_tree() -> void:
_managed_roots.erase(root)

func _reprocess_settings() -> void:
if not _properties_dirty or Engine.is_editor_hint():
return
Expand Down Expand Up @@ -160,3 +167,27 @@ func _get_configuration_warnings() -> PackedStringArray:
))

return result

# Find managed nodes recursively from given root, ignoring branches managed by
# a different RollbackSynchronizer
func _collect_managed_nodes(root: Node) -> Array[Node]:
var result: Array[Node] = []
for child in root.get_children():
if _is_foreign_rollback_root(child):
continue
result.append(child)
result.append_array(_collect_managed_nodes(child))
return result

# Returns true if the node is the root of a different RollbackSynchronizer
func _is_foreign_rollback_root(node: Node) -> bool:
if not _managed_roots.has(node):
# No RBS treats node as root
return false

if _managed_roots[node] == self:
# Node is our own root
return false

# Node is foreign root
return true
36 changes: 34 additions & 2 deletions addons/netfox/rollback/rollback-synchronizer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ var _schema_nodes := _Set.new()

var _properties_dirty: bool = false

static var _logger: NetfoxLogger = NetfoxLogger._for_netfox("RollbackSynchronizer")
static var _managed_roots := {} # root node to RollbackSynchronizer

@onready var _logger: NetfoxLogger = NetfoxLogger._for_netfox("RollbackSynchronizer:" + root.name)

## Process settings.
## [br][br]
Expand All @@ -80,7 +82,8 @@ func process_settings() -> void:
process_authority()

# Register nodes for simulation and liveness
var managed_nodes := [root] + root.find_children("*")
var managed_nodes := [root] + _collect_managed_nodes(root)
_logger.debug("Filtering managed nodes: %s", [managed_nodes])
for node in managed_nodes:
if NetworkRollback.is_rollback_aware(node):
RollbackSimulationServer.register(NetworkRollback._get_rollback_method(node))
Expand Down Expand Up @@ -354,6 +357,8 @@ func _enter_tree() -> void:
if Engine.is_editor_hint():
return

_managed_roots[root] = self

if not visibility_filter:
visibility_filter = PeerVisibilityFilter.new()

Expand All @@ -365,9 +370,36 @@ func _enter_tree() -> void:
await NetworkTime.after_sync
process_settings.call_deferred()

func _exit_tree() -> void:
_managed_roots.erase(root)

func _reprocess_settings() -> void:
if not _properties_dirty or Engine.is_editor_hint():
return

_properties_dirty = false
process_settings()

# Find managed nodes recursively from given root, ignoring branches managed by
# a different RollbackSynchronizer
func _collect_managed_nodes(root: Node) -> Array[Node]:
var result: Array[Node] = []
for child in root.get_children():
if _is_foreign_rollback_root(child):
continue
result.append(child)
result.append_array(_collect_managed_nodes(child))
return result

# Returns true if the node is the root of a different RollbackSynchronizer
func _is_foreign_rollback_root(node: Node) -> bool:
if not _managed_roots.has(node):
# No RBS treats node as root
return false

if _managed_roots[node] == self:
# Node is our own root
return false

# Node is foreign root
return true
1 change: 1 addition & 0 deletions addons/netfox/servers/rollback-simulation-server.gd
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func register(callback: Callable) -> void:
return

assert(callback.get_object() is Node, "Only nodes supported for now!")
assert(not _callbacks.has(callback.get_object()), "Double register() of node %s!" % [callback.get_object()])

_callbacks[callback.get_object()] = callback

Expand Down
53 changes: 53 additions & 0 deletions test/netfox/rollback-synchronizer.test.gd
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,49 @@ func get_suite_name() -> String:
return "RollbackSynchronizer"

func suite():
test("Nested RollbackSynchronizer support", func():
# Setup node layout:
# primary_root/
# ├── primary_rbs
# └── secondary_root/
# └── secondary_rbs

var primary_root := RollbackAware.new(); primary_root.name = "Primary Root"
var primary_rbs := RollbackSynchronizer.new(); primary_rbs.name = "Primary RBS"
var secondary_root := RollbackAware.new(); secondary_root.name = "Secondary Root"
var secondary_rbs := RollbackSynchronizer.new(); secondary_rbs.name = "Secondary RBS"

primary_rbs.owner = primary_root
secondary_root.owner = primary_root
secondary_rbs.owner = primary_root

primary_root.add_child(primary_rbs)
primary_root.add_child(secondary_root)
secondary_root.add_child(secondary_rbs)

primary_rbs.root = primary_root
secondary_rbs.root = secondary_root

Vest.get_tree().root.add_child.call_deferred(primary_root)
await primary_root.ready

# Pick up managed nodes
primary_rbs.process_settings()
secondary_rbs.process_settings()

# Check managed nodes
expect_equal(primary_rbs._sim_nodes, [primary_root])
expect_equal(secondary_rbs._sim_nodes, [secondary_root])

print("Node tree:")
primary_root.print_tree_pretty()
print("Primary managed: %s" % [primary_rbs._sim_nodes])
print("Secondary managed: %s" % [secondary_rbs._sim_nodes])

# Cleanup
primary_root.queue_free()
)

# Messy to set up, keeping cases for later
define("Input age and predicting", func():
test("should return -1 on no input", func(): todo())
Expand All @@ -20,3 +63,13 @@ func suite():
test("should return -1 for no state", func(): todo())
test("should return latest", func(): todo())
)

class RollbackAware extends Node:
func _rollback_tick(_dt: float, _t: int, _if: int) -> void:
pass

func _to_vest():
return _to_string()

func _to_string() -> String:
return "RollbackAware:" + name
Loading