fix: synchronize late-joining players

This commit is contained in:
Alexander Sellite 2026-08-23 01:23:00 -04:00
parent 5c3eba1ad2
commit 2aeaf1d44d
6 changed files with 371 additions and 49 deletions

View file

@ -5,6 +5,7 @@ const BURST_COUNT: int = 3
const WINDOW_COUNT: int = 5
const WINDOW_SECONDS: float = 10.0
const CALL_COOLDOWN_MILLISECONDS: int = 90
const MAX_PENDING_MESSAGES_PER_PEER: int = 8
const DEDICATED_CHAT_WARNING: String = (
"Privacy notice: This dedicated server records and retains chat messages."
)
@ -40,6 +41,7 @@ var _last_call_msec: Dictionary[int, int] = {}
var _call_variant_indices: Dictionary[int, int] = {}
var _sequence: int = 0
var _peer_names: Dictionary[int, String] = {}
var _pending_peer_messages: Dictionary[int, Array] = {}
var _relationships: PlayerRelationshipStore
var _dedicated_history_enabled: bool = false
var _chat_log_path: String = ""
@ -418,9 +420,11 @@ func _apply_message(
else:
var sender_id := int(data["sender_peer_id"])
var record := _session.get_peer_record(sender_id)
if record == null:
_queue_pending_peer_message(sender_id, data, emit_live_signals)
return
valid_signature = (
record != null
and record.identity_fingerprint == str(data["sender_fingerprint"])
record.identity_fingerprint == str(data["sender_fingerprint"])
and _session.verify_peer_action(
sender_id,
"chat_send",
@ -466,7 +470,47 @@ func receive_chat_rejection(message: String) -> void:
send_rejected.emit(message.left(80))
func _queue_pending_peer_message(
peer_id: int,
message: Dictionary,
emit_live_signals: bool,
) -> void:
if peer_id <= 0:
return
var pending: Array = _pending_peer_messages.get(peer_id, [])
var message_id := str(message.get("message_id", ""))
for value: Variant in pending:
if (
typeof(value) == TYPE_DICTIONARY
and str(value.get("message", {}).get("message_id", "")) == message_id
):
return
pending.append({
"message": message.duplicate(true),
"emit_live_signals": emit_live_signals,
})
while pending.size() > MAX_PENDING_MESSAGES_PER_PEER:
pending.pop_front()
_pending_peer_messages[peer_id] = pending
func _flush_pending_peer_messages(peer_id: int) -> void:
var pending: Array = _pending_peer_messages.get(peer_id, [])
_pending_peer_messages.erase(peer_id)
for value: Variant in pending:
if typeof(value) != TYPE_DICTIONARY:
continue
var queued: Dictionary = value
if typeof(queued.get("message")) != TYPE_DICTIONARY:
continue
_apply_message(
queued["message"],
bool(queued.get("emit_live_signals", true)),
)
func _on_peer_authenticated(peer_id: int, display_name: String) -> void:
_flush_pending_peer_messages(peer_id)
if not _session.is_host():
return
_peer_names[peer_id] = display_name
@ -500,6 +544,7 @@ func _on_peer_removed(peer_id: int) -> void:
_rate_times.erase(peer_id)
_last_call_msec.erase(peer_id)
_call_variant_indices.erase(peer_id)
_pending_peer_messages.erase(peer_id)
if not _session.is_host():
return
var display_name: String = _peer_names.get(peer_id, "Player")
@ -601,6 +646,7 @@ func _on_session_state_changed(state: NetworkSession.State) -> void:
_last_call_msec.clear()
_call_variant_indices.clear()
_peer_names.clear()
_pending_peer_messages.clear()
_sequence = 0
history_replaced.emit([])