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.43.0"
version="1.43.1"
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.43.0"
version="1.43.1"
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.43.0"
version="1.43.1"
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.43.0"
version="1.43.1"
script="netfox.gd"
1 change: 1 addition & 0 deletions addons/netfox/rollback/network-rollback.gd
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ func _rollback() -> void:
on_record_tick.emit(tick + 1)
NetworkHistoryServer._record_rollback_state(tick + 1)
NetworkSynchronizationServer._synchronize_state(tick + 1)
NetworkHistoryServer.flush_ignores()

# Restore display state
_rollback_stage = _STAGE_AFTER
Expand Down
16 changes: 14 additions & 2 deletions addons/netfox/rollback/rollback-synchronizer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ class_name RollbackSynchronizer
## [br][br]
## Enabling this will run [code]_rollback_tick[/code] on nodes under
## [member root] even if there's no current input available for the tick.
@export var enable_prediction: bool = false
@export var enable_prediction: bool = false:
set(v):
if v != enable_prediction:
_set_prediction_enabled(v)
enable_prediction = v

@export_group("State")
## Properties that define the game state.
Expand Down Expand Up @@ -87,6 +91,7 @@ func process_settings() -> void:
for node in managed_nodes:
if NetworkRollback.is_rollback_aware(node):
RollbackSimulationServer.register(NetworkRollback._get_rollback_method(node))
RollbackSimulationServer.set_prediction_enabled_for(node, enable_prediction)
_sim_nodes.append(node)

if NetworkRollback.is_rollback_liveness_aware(node) and not RollbackLivenessServer.is_registered(node):
Expand Down Expand Up @@ -255,7 +260,10 @@ func ignore_prediction(node: Node) -> void:
# predictions.
#
# This method may see some use again, otherwise it will be deprecated.
pass

# NOTE: Turns out this is useful - even if mispredictions are not recorded,
# we might not want to display them
NetworkHistoryServer.ignore(node)

## Get the tick of the last known input.
## [br][br]
Expand Down Expand Up @@ -380,6 +388,10 @@ func _reprocess_settings() -> void:
_properties_dirty = false
process_settings()

func _set_prediction_enabled(enabled: bool) -> void:
for node in _sim_nodes:
RollbackSimulationServer.set_prediction_enabled_for(node, enabled)

# Find managed nodes recursively from given root, ignoring branches managed by
# a different RollbackSynchronizer
func _collect_managed_nodes(root: Node) -> Array[Node]:
Expand Down
21 changes: 21 additions & 0 deletions addons/netfox/servers/network-history-server.gd
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ var _sync_state_properties := _PropertyPool.new()
var _rb_history_size := NetworkRollback.history_limit
var _sync_history_size := ProjectSettings.get_setting("netfox/state_synchronizer/history_limit", 64) as int

var _ignored_subjects := _Set.new()

# Source of truth for history
var _rb_input_history := _PerObjectHistory.new(_rb_history_size)
var _rb_state_history := _PerObjectHistory.new(_rb_history_size)
Expand Down Expand Up @@ -74,6 +76,22 @@ func deregister(node: Node) -> void:
var snapshot := value as _Snapshot
snapshot.erase_subject(node)

## Do not record [param subject]
## [br][br]
## Can be used in [code]_rollback_tick()[/code] in case node prediction is
## enabled, but state can't be reasonably predicted.
## [br][br]
## Subjects stay ignored until [method flush_ignores] is called. This is done
## by default after every rollback tick.
func ignore(subject: Node) -> void:
_ignored_subjects.add(subject)

## Clear the list of ignored subjects
## [br][br]
## Calling this method undoes all previous [method ignore] calls.
func flush_ignores() -> void:
_ignored_subjects.clear()

## Return the latest tick where any of the [param subjects] had rollback
## state data available
func get_latest_state_tick_for(subjects: Array, tick: int) -> int:
Expand Down Expand Up @@ -161,6 +179,9 @@ func _record(tick: int, history: _PerObjectHistory, snapshots: _HistoryBuffer, p
for subject in property_pool.get_subjects():
assert(subject is Node, "Only nodes supported for now!")

if _ignored_subjects.has(subject):
continue

var is_auth := auth_filter.call(subject)

if only_auth and not is_auth:
Expand Down
25 changes: 23 additions & 2 deletions addons/netfox/servers/rollback-simulation-server.gd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var _liveness_server: _RollbackLivenessServer

var _callbacks := {} # node to callback
var _simulated_ticks := {} # node to array of ticks
var _prediction_enabled_nodes := _Set.new()

var _input_graph := _Graph.new() # Links inputs to objects controlled by them

Expand Down Expand Up @@ -63,6 +64,7 @@ func deregister_node(node: Node) -> void:
if _callbacks.has(node):
deregister(_callbacks[node])
_input_graph.erase(node)
_prediction_enabled_nodes.erase(node)

## Register [param input] as providing input for [param node]
func register_rollback_input_for(node: Node, input: Node) -> void:
Expand All @@ -72,6 +74,23 @@ func register_rollback_input_for(node: Node, input: Node) -> void:
func deregister_rollback_input(node: Node, input: Node) -> void:
_input_graph.unlink(input, node)

## Toggle the prediction enabled flag for [param node]
## [br][br]
## Prediction in this sense means that the node will be simulated even if there
## is no up to date input available.
func set_prediction_enabled_for(node: Node, enabled: bool) -> void:
if enabled:
_prediction_enabled_nodes.add(node)
else:
_prediction_enabled_nodes.erase(node)

## Return true if prediction is enabled for [param node]
## [br][br]
## Prediction in this sense means that the node will be simulated even if there
## is no up to date input available.
func is_prediction_enabled_for(node: Node) -> bool:
return _prediction_enabled_nodes.has(node)

## Return true if the currently simulated node is being predicted
func is_predicting_current() -> bool:
if not _current_object or not is_instance_valid(_current_object):
Expand Down Expand Up @@ -140,8 +159,10 @@ func _get_nodes_to_simulate(input_snapshot: _Snapshot) -> Array[Node]:
result.append(node)
continue

if not input_snapshot.has_subjects(inputs, true):
# We don't have input for node, don't simulate
if not input_snapshot.has_subjects(inputs, true) and \
not is_prediction_enabled_for(node):
# We don't have input for node, and input prediction is disabled
# Don't simulate
continue

result.append(node)
Expand Down
Loading