Skip to content

Commit ee2a985

Browse files
refactor: History encoder (#425)
Refs #358 --------- Co-authored-by: Dustie <77035922+DustieDog@users.noreply.github.com>
1 parent ff130ed commit ee2a985

19 files changed

Lines changed: 592 additions & 149 deletions

addons/netfox.extras/plugin.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
name="netfox.extras"
44
description="Game-specific utilities for Netfox"
55
author="Tamas Galffy and contributors"
6-
version="1.24.6"
6+
version="1.24.7"
77
script="netfox-extras.gd"

addons/netfox.internals/history-buffer.gd

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,24 @@ func set_snapshot(tick: int, data):
1616
func get_buffer() -> Dictionary:
1717
return _buffer
1818

19+
func get_earliest_tick() -> int:
20+
return _buffer.keys().min()
21+
22+
func get_latest_tick() -> int:
23+
return _buffer.keys().max()
24+
1925
func get_closest_tick(tick: int) -> int:
2026
if _buffer.has(tick):
2127
return tick
2228

2329
if _buffer.is_empty():
2430
return -1
2531

26-
var earliest_tick = _buffer.keys().min()
27-
32+
var earliest_tick = get_earliest_tick()
2833
if tick < earliest_tick:
2934
return earliest_tick
3035

31-
var latest_tick = _buffer.keys().max()
32-
36+
var latest_tick = get_latest_tick()
3337
if tick > latest_tick:
3438
return latest_tick
3539

addons/netfox.internals/plugin.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
name="netfox.internals"
44
description="Shared internals for netfox addons"
55
author="Tamas Galffy and contributors"
6-
version="1.24.6"
6+
version="1.24.7"
77
script="plugin.gd"

addons/netfox.noray/plugin.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
name="netfox.noray"
44
description="Bulletproof your connectivity with noray integration for netfox"
55
author="Tamas Galffy and contributors"
6-
version="1.24.6"
6+
version="1.24.7"
77
script="netfox-noray.gd"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
extends RefCounted
2+
class_name _DiffHistoryEncoder
3+
4+
var _history: _PropertyHistoryBuffer
5+
var _property_cache: PropertyCache
6+
7+
static var _logger := _NetfoxLogger.for_netfox("DiffHistoryEncoder")
8+
9+
func _init(p_history: _PropertyHistoryBuffer, p_property_cache: PropertyCache):
10+
_history = p_history
11+
_property_cache = p_property_cache
12+
13+
func encode(tick: int, reference_tick: int) -> Dictionary:
14+
var snapshot := _history.get_snapshot(tick)
15+
16+
var reference_snapshot := _history.get_history(reference_tick)
17+
var diff_snapshot := reference_snapshot.make_patch(snapshot)
18+
19+
return diff_snapshot.as_dictionary()
20+
21+
func decode(data: Dictionary) -> _PropertySnapshot:
22+
return _PropertySnapshot.from_dictionary(data)
23+
24+
func apply(tick: int, snapshot: _PropertySnapshot, reference_tick: int, sender: int = -1) -> bool:
25+
if tick < NetworkRollback.history_start:
26+
# State too old!
27+
_logger.error(
28+
"Received diff snapshot for @%d, rejecting because older than %s frames",
29+
[tick, NetworkRollback.history_limit]
30+
)
31+
return false
32+
33+
if snapshot.is_empty():
34+
return true
35+
36+
if sender > 0:
37+
snapshot.sanitize(sender, _property_cache)
38+
if snapshot.is_empty():
39+
_logger.warning("Received invalid diff from #%s for @%s", [sender, tick])
40+
return false
41+
42+
if not _history.has(reference_tick):
43+
# Reference tick missing, hope for the best
44+
_logger.warning("Reference tick %d missing for applying %d", [reference_tick, tick])
45+
46+
var reference_snapshot := _history.get_snapshot(reference_tick)
47+
_history.set_snapshot(tick, reference_snapshot.merge(snapshot))
48+
return true
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
extends RefCounted
2+
class_name _RedundantHistoryEncoder
3+
4+
var redundancy: int = 4:
5+
get = get_redundancy,
6+
set = set_redundancy
7+
8+
var _history: _PropertyHistoryBuffer
9+
var _property_cache: PropertyCache
10+
11+
var _logger := _NetfoxLogger.for_netfox("RedundantHistoryEncoder")
12+
13+
func get_redundancy() -> int:
14+
return redundancy
15+
16+
func set_redundancy(p_redundancy: int):
17+
if p_redundancy <= 0:
18+
_logger.warning(
19+
"Attempting to set redundancy to %d, which would send no data!", [p_redundancy]
20+
)
21+
return
22+
23+
redundancy = p_redundancy
24+
25+
func encode(tick: int) -> Array:
26+
if _history.is_empty():
27+
return []
28+
29+
var data : Array[Dictionary] = []
30+
data.resize(redundancy)
31+
32+
for i in range(mini(redundancy, _history.size())):
33+
var offset_tick := tick - i
34+
if offset_tick < _history.get_earliest_tick():
35+
data.resize(i)
36+
break
37+
38+
data[i] = _history.get_snapshot(offset_tick).as_dictionary()
39+
40+
return data
41+
42+
func decode(data: Array) -> Array[_PropertySnapshot]:
43+
var result: Array[_PropertySnapshot] = []
44+
result.resize(data.size())
45+
46+
for i in range(data.size()):
47+
result[i] = _PropertySnapshot.from_dictionary(data[i])
48+
49+
return result
50+
51+
# Returns earliest new tick as int, or -1 if no new ticks applied
52+
func apply(tick: int, snapshots: Array[_PropertySnapshot], sender: int = 0) -> int:
53+
var earliest_new_tick = -1
54+
55+
for i in range(snapshots.size()):
56+
var offset_tick := tick - i
57+
var snapshot := snapshots[i]
58+
59+
if offset_tick < NetworkRollback.history_start:
60+
# Data too old
61+
_logger.warning(
62+
"Received data for %s, rejecting because older than %s frames",
63+
[offset_tick, NetworkRollback.history_limit]
64+
)
65+
continue
66+
67+
if sender > 0:
68+
snapshot.sanitize(sender, _property_cache)
69+
if snapshot.is_empty():
70+
# No valid properties ( probably after sanitize )
71+
_logger.warning("Received invalid data from %d for tick %d", [sender, tick])
72+
continue
73+
74+
var known_snapshot := _history.get_snapshot(offset_tick)
75+
if not known_snapshot.equals(snapshot):
76+
# Received a new snapshot, store and emit signal
77+
_history.set_snapshot(offset_tick, snapshot)
78+
earliest_new_tick = offset_tick
79+
80+
return earliest_new_tick
81+
82+
83+
func _init(p_history: _PropertyHistoryBuffer, p_property_cache: PropertyCache):
84+
_history = p_history
85+
_property_cache = p_property_cache
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
extends RefCounted
2+
class_name _SnapshotHistoryEncoder
3+
4+
var _history: _PropertyHistoryBuffer
5+
var _property_cache: PropertyCache
6+
7+
static var _logger := _NetfoxLogger.for_netfox("_SnapshotHistoryEncoder")
8+
9+
func _init(p_history: _PropertyHistoryBuffer, p_property_cache: PropertyCache):
10+
_history = p_history
11+
_property_cache = p_property_cache
12+
13+
func encode(tick: int) -> Dictionary:
14+
return _history.get_snapshot(tick).as_dictionary()
15+
16+
func decode(data: Dictionary) -> _PropertySnapshot:
17+
return _PropertySnapshot.from_dictionary(data)
18+
19+
func apply(tick: int, snapshot: _PropertySnapshot, sender: int = -1) -> bool:
20+
if tick < NetworkRollback.history_start:
21+
# State too old!
22+
_logger.error("Received full snapshot for %s, rejecting because older than %s frames", [tick, NetworkRollback.history_limit])
23+
return false
24+
25+
if sender > 0:
26+
snapshot.sanitize(sender, _property_cache)
27+
if snapshot.is_empty(): return false
28+
29+
_history.set_snapshot(tick, snapshot)
30+
return true

addons/netfox/plugin.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
name="netfox"
44
description="Shared internals for netfox addons"
55
author="Tamas Galffy and contributors"
6-
version="1.24.6"
6+
version="1.24.7"
77
script="netfox.gd"

addons/netfox/properties/property-cache.gd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ func properties() -> Array:
2323
# See: https://github.com/godotengine/godot/issues/72627
2424
result.assign(_cache.values())
2525
return result
26+
27+
func clear():
28+
_cache.clear()

addons/netfox/properties/property-snapshot.gd

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ func equals(other: _PropertySnapshot):
3434
func is_empty() -> bool:
3535
return _snapshot.is_empty()
3636

37-
static func extract(properties: Array[PropertyEntry]) -> _PropertySnapshot:
38-
var result = {}
39-
for property in properties:
40-
result[property.to_string()] = property.get_value()
41-
return _PropertySnapshot.from_dictionary(result)
42-
4337
func apply(cache: PropertyCache):
4438
for property_path in _snapshot:
4539
var property_entry = cache.get_entry(property_path)
@@ -82,5 +76,14 @@ func sanitize(sender: int, property_cache: PropertyCache):
8276

8377
_snapshot = sanitized
8478

79+
static func extract(properties: Array[PropertyEntry]) -> _PropertySnapshot:
80+
var result = {}
81+
for property in properties:
82+
result[property.to_string()] = property.get_value()
83+
return _PropertySnapshot.from_dictionary(result)
84+
8585
func _init(p_snapshot: Dictionary = {}):
8686
_snapshot = p_snapshot
87+
88+
func _to_string():
89+
return str(_snapshot)

0 commit comments

Comments
 (0)