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

Added Input delay (no custom serialization, no static typing) #276

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
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.8.3"
version="1.8.4"
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.8.3"
version="1.8.4"
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.8.3"
version="1.8.4"
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"
version="1.8.3"
version="1.8.4"
script="netfox.gd"
28 changes: 20 additions & 8 deletions addons/netfox/rollback/rollback-synchronizer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ class_name RollbackSynchronizer
## Turning this off is recommended to save bandwith and reduce cheating risks.
@export var enable_input_broadcast: bool = true

## This is measured in ticks. So if your game's tickrate (project settings > Time) is 60 ticks, 4 ticks are 68 ms (bad but acceptable)
## If your game's tickrate is 30 ticks, 4 ticks are 134 ms (laggy)
## The lesser the value, the tighter the controls feel locally, but the less time for other players to catch up to this node's input
@export var input_delay: int = 0

var _record_state_props: Array[PropertyEntry] = []
var _record_input_props: Array[PropertyEntry] = []
var _auth_state_props: Array[PropertyEntry] = []
Expand Down Expand Up @@ -92,6 +97,12 @@ func _ready():
await NetworkTime.after_sync
_latest_state = NetworkTime.tick - 1

# Dummy states to parse for first inputs before our first real input
# The code: PropertySnapshot.apply(input, _property_cache) -> does literally nothing if input == {}
# So the default input stays in its default values for the first input delay ticks.
for i in input_delay:
_inputs[NetworkTime.tick + i] = {}

NetworkTime.before_tick.connect(_before_tick)
NetworkTime.after_tick.connect(_after_tick)
NetworkRollback.before_loop.connect(_before_loop)
Expand Down Expand Up @@ -178,21 +189,22 @@ func _before_tick(_delta, tick):
var state = _get_history(_states, tick)
PropertySnapshot.apply(state, _property_cache)

func _after_tick(_delta, _tick):
func _after_tick(_delta: float, _tick: int):
if not _auth_input_props.is_empty():
var input = PropertySnapshot.extract(_auth_input_props)
_inputs[NetworkTime.tick] = input
var local_input: Dictionary = PropertySnapshot.extract(_auth_input_props)
var delayed_input_tick: int = _tick + input_delay
_inputs[delayed_input_tick] = local_input

#Send the last n inputs for each property
var inputs = {}
for i in range(0, NetworkRollback.input_redundancy):
var tick_input = _inputs.get(NetworkTime.tick - i, {})
var tick_input: Dictionary = _inputs.get(delayed_input_tick - i, {})
for property in tick_input:
if not inputs.has(property):
inputs[property] = []
inputs[property].push_back(tick_input[property])

_attempt_submit_input(inputs)
_attempt_submit_input(inputs, delayed_input_tick)

while _states.size() > NetworkRollback.history_limit:
_states.erase(_states.keys().min())
Expand All @@ -202,12 +214,12 @@ func _after_tick(_delta, _tick):

_freshness_store.trim()

func _attempt_submit_input(input: Dictionary):
func _attempt_submit_input(input: Dictionary, delayed_input_tick: int):
# TODO: Default to input broadcast in mesh network setups
if enable_input_broadcast:
_submit_input.rpc(input, NetworkTime.tick)
_submit_input.rpc(input, delayed_input_tick)
elif not multiplayer.is_server():
_submit_input.rpc_id(1, input, NetworkTime.tick)
_submit_input.rpc_id(1, input, delayed_input_tick)

func _get_history(buffer: Dictionary, tick: int) -> Dictionary:
if buffer.has(tick):
Expand Down