-
-
Notifications
You must be signed in to change notification settings - Fork 14
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
When a player sends a state RPC, the state is serialized, and on receiving the RPC it is deserialized. #254
Changes from 1 commit
2e38768
4fde8ab
705cca6
e3e240b
3809b30
33fe080
9205e78
7a9a1b9
ed3b284
a45c405
723faf8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,9 +21,10 @@ var _auth_state_props: Array[PropertyEntry] = [] | |
var _auth_input_props: Array[PropertyEntry] = [] | ||
var _nodes: Array[Node] = [] | ||
|
||
var _states: Dictionary = {} | ||
var _inputs: Dictionary = {} | ||
var _states: Dictionary = {} #<tick, Dictionary<String, Variant>> | ||
var _inputs: Dictionary = {} #<tick, Dictionary<String, Variant>> | ||
var _serialized_inputs: Dictionary = {} #<tick, PackedByteArray> | ||
var _serialized_states: Dictionary = {} #<tick, PackedByteArray> | ||
var serialized_inputs_to_send: Array[PackedByteArray] = [] | ||
var _latest_state: int = -1 | ||
var _earliest_input: int | ||
|
@@ -51,7 +52,7 @@ func process_settings(): | |
|
||
# Gather state props - all state props are recorded | ||
for property in state_properties: | ||
var pe = _property_cache.get_entry(property) | ||
var pe: PropertyEntry = _property_cache.get_entry(property) | ||
_record_state_props.push_back(pe) | ||
|
||
process_authority() | ||
|
@@ -83,10 +84,9 @@ func process_authority(): | |
# Only record input that is our own | ||
for property in input_properties: | ||
var pe = _property_cache.get_entry(property) | ||
_record_input_props.push_back(pe) | ||
if pe.node.is_multiplayer_authority(): | ||
_auth_input_props.push_back(pe) | ||
else: | ||
_record_input_props.push_back(pe) | ||
|
||
func _ready(): | ||
process_settings() | ||
|
@@ -150,21 +150,35 @@ func _process_tick(tick: int): | |
NetworkRollback.process_rollback(node, NetworkTime.ticktime, tick, is_fresh) | ||
_freshness_store.notify_processed(node, tick) | ||
|
||
|
||
|
||
func _record_tick(tick: int): | ||
# Broadcast state we own | ||
if not _auth_state_props.is_empty(): | ||
var broadcast = {} | ||
|
||
var state_to_broadcast = {} | ||
|
||
#if (multiplayer.get_unique_id() > 1): | ||
#print("Record tick state sending, peer id is: %s" % multiplayer.get_unique_id()) | ||
for property in _auth_state_props: | ||
if _can_simulate(property.node, tick - 1): | ||
# Only broadcast if we've simulated the node | ||
broadcast[property.to_string()] = property.get_value() | ||
state_to_broadcast[property.to_string()] = property.get_value() | ||
|
||
if broadcast.size() > 0: | ||
# Broadcast as new state | ||
if state_to_broadcast.size() > 0: | ||
_latest_state = max(_latest_state, tick) | ||
_states[tick] = PropertySnapshot.merge(_states.get(tick, {}), broadcast) | ||
_submit_state.rpc(broadcast, tick) | ||
_states[tick] = PropertySnapshot.merge(_states.get(tick, {}), state_to_broadcast) | ||
|
||
if (NetworkRollback.enable_state_serialization): | ||
var serialized_current_state: PackedByteArray = PropertiesSerializer.serialize_multiple_properties(_auth_state_props, tick) | ||
_serialized_states[tick] = serialized_current_state | ||
|
||
# Broadcast as new state | ||
for picked_peer_id in multiplayer.get_peers(): | ||
_submit_serialized_state.rpc_id(picked_peer_id, serialized_current_state) | ||
else: | ||
# Broadcast as new state | ||
for picked_peer_id in multiplayer.get_peers(): | ||
_submit_state.rpc_id(picked_peer_id, state_to_broadcast, tick) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thing as inputs. Locally, not a single RPC should be sent/received. Because we already have the state locally. So we must simply RPC to other peers, because for this tick we are RPCing, we already have set locally the variables There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rpc's |
||
|
||
# Record state for specified tick ( current + 1 ) | ||
if not _record_state_props.is_empty() and tick > _latest_state: | ||
|
@@ -222,8 +236,16 @@ func history_cleanup() -> void: | |
_inputs.erase(_inputs.keys().min()) | ||
|
||
if (NetworkRollback.enable_input_serialization): | ||
while _serialized_inputs.size() > NetworkRollback.history_limit: | ||
_serialized_inputs.erase(_serialized_inputs.keys().min()) | ||
if (NetworkRollback.serialized_inputs_history_limit > 0): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0 or -1 value is for saving all states/inputs (PackedByteArray format is optimal) |
||
while _serialized_inputs.size() > NetworkRollback.serialized_inputs_history_limit: | ||
#Would be faster if we cached the earliest key in an integer instead of searching min() each tick! | ||
_serialized_inputs.erase(_serialized_inputs.keys().min()) | ||
|
||
if (NetworkRollback.enable_state_serialization): | ||
if (NetworkRollback.serialized_states_history_limit > 0): | ||
while _serialized_states.size() > NetworkRollback.serialized_states_history_limit: | ||
#Would be faster if we cached the earliest key in an integer instead of searching min() each tick! | ||
_serialized_states.erase(_serialized_states.keys().min()) | ||
|
||
_freshness_store.trim() | ||
|
||
|
@@ -334,6 +356,18 @@ func _submit_raw_input(input: Dictionary, tick: int): | |
else: | ||
_logger.warning("Received invalid input from %s for tick %s for %s" % [sender, tick, root.name]) | ||
|
||
@rpc("any_peer", "unreliable_ordered", "call_remote") | ||
func _submit_serialized_state(serialized_state: PackedByteArray): | ||
var received_tick: int = serialized_state.decode_u32(0) | ||
var state_values_size: int = serialized_state.decode_u8(4) | ||
var serialized_state_values: PackedByteArray = serialized_state.slice(5, 5 + state_values_size) | ||
var byte_index: int = 5 | ||
var deserialized_state_of_this_tick: Dictionary | ||
|
||
deserialized_state_of_this_tick = PropertiesSerializer.deserialize_multiple_properties(serialized_state_values, _record_state_props) | ||
|
||
_submit_state(deserialized_state_of_this_tick, received_tick) | ||
|
||
@rpc("any_peer", "unreliable_ordered", "call_remote") | ||
func _submit_state(state: Dictionary, tick: int): | ||
if tick > NetworkTime.tick: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not critical enough to backport it to #251
From what I understood,
_record_state_props
records the properties of a node, regardless of authority._record_input_props
was unused (yet I needed it for that exact purpose, to learn the properties of a node I don't have authority on, as the receiver), so I replicated the same as_record_state_props
But this opens a new issue. Why do
_auth_input_props
and_auth_state_props
even exist?!They are currently used exclusively as booleans, to get if we have authority or not.
And it's not like properties are added realtime - if they are, they could as well be added onto
_record_state_props
and_record_input_props
without problems.My suggestion is to straight up remove the variables
_auth_input_props
and_auth_state_props
and replace them with booleans (e.g.node.get_multiplayer_authority()
) unless I am missing something