From c91ef067a09c24a5b11bd7e9d94bc2209115bd78 Mon Sep 17 00:00:00 2001 From: gk98s Date: Wed, 24 Jun 2026 17:16:14 +0000 Subject: [PATCH 1/2] fixes --- addons/netfox/servers/data/per-object-history.gd | 3 +++ addons/netfox/servers/data/property-pool.gd | 3 +++ addons/netfox/servers/rollback-simulation-server.gd | 3 +++ 3 files changed, 9 insertions(+) diff --git a/addons/netfox/servers/data/per-object-history.gd b/addons/netfox/servers/data/per-object-history.gd index 450a4ae96..538bb816e 100644 --- a/addons/netfox/servers/data/per-object-history.gd +++ b/addons/netfox/servers/data/per-object-history.gd @@ -11,6 +11,9 @@ func _init(p_history_size: int): _history_size = p_history_size func subjects() -> Array[Object]: + for key in _data.keys(): + if not is_instance_valid(key): + _data.erase(key) var result := [] as Array[Object] result.assign(_data.keys()) return result diff --git a/addons/netfox/servers/data/property-pool.gd b/addons/netfox/servers/data/property-pool.gd index 63db467ff..b8b1d0959 100644 --- a/addons/netfox/servers/data/property-pool.gd +++ b/addons/netfox/servers/data/property-pool.gd @@ -49,6 +49,9 @@ func get_properties_of(subject: Object) -> Array[NodePath]: return properties func get_subjects() -> Array[Object]: + for key in _properties_by_subject.keys(): + if not is_instance_valid(key): + _properties_by_subject.erase(key) var subjects := [] as Array[Object] subjects.assign(_properties_by_subject.keys()) return subjects diff --git a/addons/netfox/servers/rollback-simulation-server.gd b/addons/netfox/servers/rollback-simulation-server.gd index 40e74adb9..eb8a36e7d 100644 --- a/addons/netfox/servers/rollback-simulation-server.gd +++ b/addons/netfox/servers/rollback-simulation-server.gd @@ -116,6 +116,9 @@ func simulate(delta: float, tick: int) -> void: # Determine predicted nodes for node in _callbacks.keys(): + if not is_instance_valid(node): + _callbacks.erase(node) + continue if _is_predicting(input_snapshot, node): _predicted_nodes.add(node) From 53188c8ac1923a22ded34fa88969760427ac7ceb Mon Sep 17 00:00:00 2001 From: gk98s Date: Tue, 7 Jul 2026 23:46:27 +0000 Subject: [PATCH 2/2] new fix --- .../netfox/rollback/rollback-synchronizer.gd | 30 ++++++++++++------- .../netfox/servers/data/per-object-history.gd | 3 -- addons/netfox/servers/data/property-pool.gd | 3 -- .../netfox/servers/network-history-server.gd | 3 ++ .../servers/rollback-simulation-server.gd | 4 +++ 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/addons/netfox/rollback/rollback-synchronizer.gd b/addons/netfox/rollback/rollback-synchronizer.gd index bcff31762..ed8162ec8 100644 --- a/addons/netfox/rollback/rollback-synchronizer.gd +++ b/addons/netfox/rollback/rollback-synchronizer.gd @@ -328,7 +328,9 @@ func _ready() -> void: multiplayer.connected_to_server.connect(process_settings) func _notification(what: int) -> void: - if what == NOTIFICATION_EDITOR_PRE_SAVE: + if what == NOTIFICATION_PREDELETE: + _cleanup() + elif what == NOTIFICATION_EDITOR_PRE_SAVE: update_configuration_warnings() func _get_configuration_warnings() -> PackedStringArray: @@ -373,15 +375,23 @@ func _exit_tree() -> void: _managed_roots.erase(root) if root.is_queued_for_deletion(): - # RBS and its nodes are being freed, time to deregister everything - for node in _sim_nodes + _state_properties.get_subjects() + _input_properties.get_subjects(): - RollbackSimulationServer.deregister_node(node) - NetworkSynchronizationServer.deregister(node) - NetworkIdentityServer.deregister_node(node) - NetworkHistoryServer.deregister(node) - - for node in _liveness_nodes: - RollbackLivenessServer.deregister(node) + _cleanup() + +func _cleanup() -> void: + if _sim_nodes.is_empty(): + return + + for node in _sim_nodes + _state_properties.get_subjects() + _input_properties.get_subjects(): + RollbackSimulationServer.deregister_node(node) + NetworkSynchronizationServer.deregister(node) + NetworkIdentityServer.deregister_node(node) + NetworkHistoryServer.deregister(node) + + for node in _liveness_nodes: + RollbackLivenessServer.deregister(node) + + _sim_nodes.clear() + _liveness_nodes.clear() func _reprocess_settings() -> void: if not _properties_dirty or Engine.is_editor_hint(): diff --git a/addons/netfox/servers/data/per-object-history.gd b/addons/netfox/servers/data/per-object-history.gd index 538bb816e..450a4ae96 100644 --- a/addons/netfox/servers/data/per-object-history.gd +++ b/addons/netfox/servers/data/per-object-history.gd @@ -11,9 +11,6 @@ func _init(p_history_size: int): _history_size = p_history_size func subjects() -> Array[Object]: - for key in _data.keys(): - if not is_instance_valid(key): - _data.erase(key) var result := [] as Array[Object] result.assign(_data.keys()) return result diff --git a/addons/netfox/servers/data/property-pool.gd b/addons/netfox/servers/data/property-pool.gd index b8b1d0959..63db467ff 100644 --- a/addons/netfox/servers/data/property-pool.gd +++ b/addons/netfox/servers/data/property-pool.gd @@ -49,9 +49,6 @@ func get_properties_of(subject: Object) -> Array[NodePath]: return properties func get_subjects() -> Array[Object]: - for key in _properties_by_subject.keys(): - if not is_instance_valid(key): - _properties_by_subject.erase(key) var subjects := [] as Array[Object] subjects.assign(_properties_by_subject.keys()) return subjects diff --git a/addons/netfox/servers/network-history-server.gd b/addons/netfox/servers/network-history-server.gd index cce5325f6..f1369b16c 100644 --- a/addons/netfox/servers/network-history-server.gd +++ b/addons/netfox/servers/network-history-server.gd @@ -181,6 +181,9 @@ func _record(tick: int, history: _PerObjectHistory, snapshots: _HistoryBuffer, p if _ignored_subjects.has(subject): continue + + if not subject.is_inside_tree(): + continue var is_auth := auth_filter.call(subject) diff --git a/addons/netfox/servers/rollback-simulation-server.gd b/addons/netfox/servers/rollback-simulation-server.gd index eb8a36e7d..85c0d3c09 100644 --- a/addons/netfox/servers/rollback-simulation-server.gd +++ b/addons/netfox/servers/rollback-simulation-server.gd @@ -119,6 +119,10 @@ func simulate(delta: float, tick: int) -> void: if not is_instance_valid(node): _callbacks.erase(node) continue + + if not node.is_inside_tree(): + continue + if _is_predicting(input_snapshot, node): _predicted_nodes.add(node)