Add transactional RV decor synchronization

This commit is contained in:
Alexander Sellite 2026-08-31 05:48:36 -04:00
parent ee992d9f0c
commit 6578d3e870
7 changed files with 663 additions and 48 deletions

View file

@ -28,6 +28,7 @@ const MAX_PENDING_MOVEMENT_INPUTS: int = 96
const ANIMATION_REFRESH_INTERVAL: float = 1.0
const MAX_MOVEMENT_INPUT_SEQUENCE: int = 2147483647
const MAX_MOVEMENT_ONE_WAY_TRANSIT_SECONDS: float = 0.25
const SPACE_TRANSITION_SNAPSHOT_GUARD_DISTANCE: float = 12.0
const MOVEMENT_FLAG_JUMP: int = 1 << 0
const MOVEMENT_FLAG_SPRINT: int = 1 << 1
@ -124,6 +125,9 @@ var _pending_movement_inputs: Array[Dictionary] = []
var _snapshot_accumulator: float = 0.0
var _movement_snapshot_tick: int = 0
var _last_local_snapshot_received_msec: int = 0
var _local_space_transition_guard_active: bool = false
var _local_space_transition_guard_position: Vector3 = Vector3.ZERO
var _local_space_transition_minimum_ack: int = 0
var _animation_refresh_accumulator: float = 0.0
var _last_animation_state_by_peer: Dictionary[int, Dictionary] = {}
var _pending_animation_state_by_peer: Dictionary[int, Dictionary] = {}
@ -703,6 +707,40 @@ func peers_share_space(first_peer_id: int, second_peer_id: int) -> bool:
return get_peer_space(first_peer_id) == get_peer_space(second_peer_id)
func apply_authoritative_space_transition(
peer_id: int,
target_transform: Transform3D,
acknowledged_input: int,
) -> bool:
if not target_transform.origin.is_finite():
return false
var local_peer_id: int = get_local_peer_id()
var local_transition: bool = peer_id == local_peer_id
var avatar: Player = _spawn_service.get_avatar(peer_id)
# Remote home transitions can arrive before their player-spawn message. Keep
# the new space assignment so the later spawn inherits correct visibility;
# only a missing local avatar is a transition failure.
if avatar == null:
return not local_transition
avatar.apply_network_space_transition(target_transform, local_transition)
if (
local_transition
and state == State.JOINED_CLIENT
):
# Movement snapshots use another ENet channel and a pre-transition audit
# can therefore arrive after the reliable home transition. Clear local
# prediction and reject those old-world snapshots until the host publishes
# its first audit from the new space.
_pending_movement_inputs.clear()
_last_local_snapshot_received_msec = 0
_last_input_state_hash = 0
_idle_input_accumulator = IDLE_INPUT_INTERVAL
_local_space_transition_guard_active = true
_local_space_transition_guard_position = target_transform.origin
_local_space_transition_minimum_ack = maxi(acknowledged_input, 0)
return true
func get_peer_rtt_ms(peer_id: int) -> int:
if peer_id == 1:
return 0
@ -2569,6 +2607,8 @@ func receive_movement_snapshots(encoded_snapshots: Array) -> void:
if avatar == null:
continue
if peer_id == local_peer_id:
if _reject_stale_space_transition_snapshot(snapshot):
continue
_discard_acknowledged_movement_inputs(
int(snapshot.get("acknowledged_input", 0))
)
@ -2586,6 +2626,33 @@ func receive_movement_snapshots(encoded_snapshots: Array) -> void:
)
func _reject_stale_space_transition_snapshot(snapshot: Dictionary) -> bool:
if not _local_space_transition_guard_active:
return false
var position_values: Array = snapshot.get("position", [])
if position_values.size() != 3:
return true
var position := Vector3(
float(position_values[0]),
float(position_values[1]),
float(position_values[2]),
)
var acknowledged_input: int = int(
snapshot.get("acknowledged_input", 0)
)
if acknowledged_input < _local_space_transition_minimum_ack:
return true
if acknowledged_input > _local_space_transition_minimum_ack:
_local_space_transition_guard_active = false
return false
if position.distance_to(_local_space_transition_guard_position) > (
SPACE_TRANSITION_SNAPSHOT_GUARD_DISTANCE
):
return true
_local_space_transition_guard_active = false
return false
func _discard_acknowledged_movement_inputs(acknowledged_sequence: int) -> void:
while (
not _pending_movement_inputs.is_empty()
@ -2914,6 +2981,9 @@ func _teardown_peer() -> void:
_snapshot_accumulator = 0.0
_movement_snapshot_tick = 0
_last_local_snapshot_received_msec = 0
_local_space_transition_guard_active = false
_local_space_transition_guard_position = Vector3.ZERO
_local_space_transition_minimum_ack = 0
_animation_refresh_accumulator = 0.0
_last_animation_state_by_peer.clear()
_pending_animation_state_by_peer.clear()