@@ -171,9 +171,11 @@ func _record_tick(tick: int):
171171 _latest_state = max (_latest_state , tick )
172172 _states [tick ] = PropertySnapshot .merge (_states .get (tick , {}), full_state_to_broadcast )
173173
174- var properties_to_include : Array [String ] = []
175- var diff_state_to_broadcast = {}
174+
176175 if (NetworkRollback .enable_state_diffs ):
176+ var properties_to_include : Array [String ] = []
177+ var diff_state_to_broadcast = {}
178+
177179 if (_states .has (tick - 1 )):
178180 for picked_property_path in full_state_to_broadcast :
179181 if (_states [tick - 1 ].has (picked_property_path ) == false ):
@@ -187,7 +189,9 @@ func _record_tick(tick: int):
187189 for picked_property in properties_to_include :
188190 diff_state_to_broadcast [picked_property ] = full_state_to_broadcast [picked_property ]
189191
190- _attempt_submit_serialized_states (tick , full_state_to_broadcast , diff_state_to_broadcast , properties_to_include )
192+ _attempt_submit_diff_states (tick , full_state_to_broadcast , diff_state_to_broadcast , properties_to_include )
193+ else :
194+ _attempt_submit_full_states (tick , full_state_to_broadcast )
191195
192196 # Record state for specified tick ( current + 1 )
193197 if not _record_state_props .is_empty () and tick > _latest_state :
@@ -276,32 +280,38 @@ func _attempt_submit_serialized_inputs(serialized_inputs: PackedByteArray):
276280 elif not multiplayer .is_server ():
277281 _submit_serialized_inputs .rpc_id (1 , serialized_inputs )
278282
279- func _attempt_submit_serialized_states (tick : int , full_state_to_broadcast : Dictionary , diff_state_to_broadcast : Dictionary , properties_to_include : Array [String ]):
283+ func _attempt_submit_diff_states (tick : int , full_state_to_broadcast : Dictionary , diff_state_to_broadcast : Dictionary , properties_to_include : Array [String ]):
280284 if (NetworkRollback .enable_state_serialization ):
281285 var serialized_current_state : PackedByteArray = PropertiesSerializer .serialize_state_properties (tick , diff_state_to_broadcast , properties_to_include , _auth_state_props )
282286 _serialized_states [tick ] = serialized_current_state
283287
284288 # Broadcast as new state
285289 for picked_peer_id in multiplayer .get_peers ():
286- if (_sent_full_state_to_peer_ids .has (picked_peer_id ) && diff_state_to_broadcast . is_empty () == false ):
290+ if (_sent_full_state_to_peer_ids .has (picked_peer_id )):
287291 _submit_serialized_state .rpc_id (picked_peer_id , serialized_current_state )
288292 else : # First state must be the full state
289- var all_properties : Array [String ] = []
290- for picked_property_path in full_state_to_broadcast :
291- all_properties .append (picked_property_path )
292-
293- var serialized_full_state : PackedByteArray = PropertiesSerializer .serialize_state_properties (tick , full_state_to_broadcast , all_properties , _auth_state_props )
294- _submit_serialized_state .rpc_id (picked_peer_id , serialized_full_state )
293+ var serialized_full_state : PackedByteArray = PropertiesSerializer .serialize_state_properties (tick , full_state_to_broadcast , state_properties , _auth_state_props )
294+ _submit_serialized_reliable_state .rpc_id (picked_peer_id , serialized_full_state )
295295 _sent_full_state_to_peer_ids .append (picked_peer_id )
296296 else :
297+ # print("At tick %s properties to include for %s are %s" % [tick, root.name ,properties_to_include])
297298 # Broadcast as new state
298299 for picked_peer_id in multiplayer .get_peers ():
299- if (_sent_full_state_to_peer_ids .has (picked_peer_id ) && diff_state_to_broadcast . is_empty () == false ):
300- _submit_state .rpc_id (picked_peer_id , diff_state_to_broadcast , tick )
301- else : # First state must be full
302- _submit_state .rpc_id (picked_peer_id , full_state_to_broadcast , tick )
300+ if (_sent_full_state_to_peer_ids .has (picked_peer_id )):
301+ _submit_raw_state .rpc_id (picked_peer_id , diff_state_to_broadcast , tick )
302+ else :# Send the very first state
303+ _submit_reliable_state .rpc_id (picked_peer_id , full_state_to_broadcast , tick )
303304 _sent_full_state_to_peer_ids .append (picked_peer_id )
304305
306+ func _attempt_submit_full_states (tick : int , full_state_to_broadcast : Dictionary ):
307+ if (NetworkRollback .enable_state_serialization ):
308+ var serialized_full_state : PackedByteArray = PropertiesSerializer .serialize_state_properties (tick , full_state_to_broadcast , state_properties , _auth_state_props )
309+ for picked_peer_id in multiplayer .get_peers ():
310+ _submit_serialized_state .rpc_id (picked_peer_id , serialized_full_state )
311+ else :
312+ for picked_peer_id in multiplayer .get_peers ():
313+ _submit_raw_state .rpc_id (picked_peer_id , full_state_to_broadcast , tick )
314+
305315func _get_history (buffer : Dictionary , tick : int ) -> Dictionary :
306316 if buffer .has (tick ):
307317 return buffer [tick ]
@@ -391,36 +401,48 @@ func _submit_raw_input(input: Dictionary, tick: int):
391401 else :
392402 _logger .warning ("Received invalid input from %s for tick %s for %s " % [sender , tick , root .name ])
393403
404+ @rpc ("any_peer" , "reliable" , "call_remote" )
405+ func _submit_serialized_reliable_state (serialized_state : PackedByteArray ):
406+ _submit_serialized_state (serialized_state )
407+ apply_cached_states ()
408+
394409@rpc ("any_peer" , "unreliable_ordered" , "call_remote" )
395410func _submit_serialized_state (serialized_state : PackedByteArray ):
396411 var received_tick : int = serialized_state .decode_u32 (0 )
397412 var state_values_size : int = serialized_state .decode_u16 (4 )
398413 var header_property_indexes_contained : int = serialized_state .decode_u16 (6 )
399414 var serialized_state_values : PackedByteArray = serialized_state .slice (10 , 10 + state_values_size )
400- var deserialized_state_of_this_tick : Dictionary
415+ var deserialized_state_of_this_tick : Dictionary = PropertiesSerializer .deserialize_state_properties (\
416+ serialized_state_values , _record_state_props , header_property_indexes_contained )
401417
402- deserialized_state_of_this_tick = PropertiesSerializer .deserialize_state_properties (serialized_state_values , _record_state_props , header_property_indexes_contained )
403-
404- _submit_state (deserialized_state_of_this_tick , received_tick )
418+ _submit_state (deserialized_state_of_this_tick , received_tick , multiplayer .get_remote_sender_id ())
419+
420+ var initial_state : Dictionary = {}
421+ var cached_diff_states : Dictionary = {}
422+
423+ @rpc ("any_peer" , "reliable" , "call_remote" )
424+ func _submit_reliable_state (received_state : Dictionary , tick : int ):
425+ _submit_state (received_state , tick , multiplayer .get_remote_sender_id ())
426+ apply_cached_states ()
405427
406428@rpc ("any_peer" , "unreliable_ordered" , "call_remote" )
407- func _submit_state (received_state : Dictionary , tick : int ):
408- if tick > NetworkTime .tick :
409- # This used to be weird, but is now expected due to estimating remote time
410- # push_warning("Received state from the future %s / %s - adding nonetheless" % [tick, NetworkTime.tick])
411- pass
412-
429+ func _submit_raw_state (received_state : Dictionary , tick : int ):
430+ _submit_state (received_state , tick , multiplayer .get_remote_sender_id ())
431+
432+ @rpc ("any_peer" , "unreliable_ordered" , "call_remote" )
433+ func _submit_state (received_state : Dictionary , tick : int , sender : int ):
413434 if tick < NetworkTime .tick - NetworkRollback .history_limit and _latest_state >= 0 :
414435 # State too old!
415436 _logger .error ("Received state for %s , rejecting because older than %s frames" % [tick , NetworkRollback .history_limit ])
416437 return
417438
418- var sender : int = multiplayer .get_remote_sender_id ()
419439 var sanitized = {}
440+ var properties_included : int = 0
420441 for property in received_state :
421442 var pe : PropertyEntry = _property_cache .get_entry (property )
422443 var value = received_state [property ]
423444 var state_owner : int = pe .node .get_multiplayer_authority ()
445+ properties_included += 1
424446
425447 if state_owner != sender :
426448 _logger .warning ("Received state for node owned by %s from %s , sender has no authority!" \
@@ -429,20 +451,51 @@ func _submit_state(received_state: Dictionary, tick: int):
429451
430452 sanitized [property ] = value
431453
432- # Missing properties means they didn't change from previous tick
433- # so, set it as the previous one (extrapolation)
434- for picked_property_path in state_properties :
435- if (sanitized .has (picked_property_path ) == false ):
436- if (_states .has (tick - 1 )):
437- if (_states [tick - 1 ].has (picked_property_path )):
438- sanitized [picked_property_path ] = _states [tick - 1 ][picked_property_path ]
454+ if (NetworkRollback .enable_state_diffs ):
455+ var full_properties_count : int = state_properties .size ()
456+ # print("At tick %s for %s properties included are: %s and total size is %s" % [tick, root.name, properties_included, full_properties_count])
457+ if (initial_state .is_empty ()):
458+ if (properties_included < full_properties_count ):
459+ if (sanitized .is_empty () == false ):
460+ cached_diff_states [tick ] = sanitized
461+ _logger .warning ("Cached at tick %s " % tick )
462+ return
439463 else :
440- _logger .error ("Diff states error, _states of previous tick %s , doesn't have property %s " % [tick - 1 , picked_property_path ])
464+ _logger .error ("When initial state doesn't exist, received invalid state from %s for tick %s " % [sender , tick ])
441465 else :
442- _logger .error ("Diff states error, current tick is %s and _states doesn't have previous tick %s " % [tick , tick - 1 ])
443-
466+ initial_state = sanitized
467+
468+ if (properties_included < full_properties_count ):
469+ sanitized = reconstruct_state_from_missing_state (sanitized , tick )
470+
471+ # if (root.name != "Brawler #1"):
472+ # print("[%s]At tick %s for %s properties are: %s" % [multiplayer.get_unique_id(), tick, root.name, sanitized])
444473 if sanitized .size () > 0 :
445474 _states [tick ] = PropertySnapshot .merge (_states .get (tick , {}), sanitized )
446475 _latest_state = tick
447- else :
476+ elif ( not NetworkRollback . enable_state_diffs ) :
448477 _logger .warning ("Received invalid state from %s for tick %s " % [sender , tick ])
478+
479+ ## In the case we have received diff states, but not the full state (yet), this function applies the diff states atop the full state
480+ func apply_cached_states ():
481+ var picked_full_state : Dictionary
482+ for picked_tick in cached_diff_states :
483+ picked_full_state = reconstruct_state_from_missing_state (cached_diff_states [picked_tick ], picked_tick )
484+
485+ _states [picked_tick ] = PropertySnapshot .merge (_states .get (picked_tick , {}), picked_full_state )
486+ _latest_state = max (picked_tick , _latest_state )
487+
488+ func reconstruct_state_from_missing_state (diff_state : Dictionary , diff_state_tick : int ) -> Dictionary :
489+ # Missing properties means they didn't change from previous tick
490+ # so, set it as the previous one (accurate extrapolation)
491+ for picked_property_path in state_properties :
492+ if (diff_state .has (picked_property_path ) == false ):
493+ if (_states .has (diff_state_tick - 1 )):
494+ if (_states [diff_state_tick - 1 ].has (picked_property_path )):
495+ diff_state [picked_property_path ] = _states [diff_state_tick - 1 ][picked_property_path ]
496+ else :
497+ _logger .error ("Diff states error, _states of previous tick %s , doesn't have property %s " % [diff_state_tick - 1 , picked_property_path ])
498+ else :
499+ _logger .error ("Diff states error, current tick is %s and _states doesn't have previous tick %s " % [diff_state_tick , diff_state_tick - 1 ])
500+
501+ return diff_state
0 commit comments