mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 00:14:00 +00:00
feat(multiplayer): task 2.8 net_sim.gd, close out Phase 2
New NetSim autoload: seeded, CLI-driven (--net-sim-latency/-jitter/-loss/-dup) latency/jitter/loss/duplicate decorator, a true no-op passthrough unless a flag is set. Wraps MatchSim.send_input/send_snapshot per the design doc's scope, plus NetworkManager's ping/pong so the already-tested RTT/clock measurement becomes the acceptance signal for "raises observed RTT" without waiting on Phase 3's per-peer snapshot echo. Two real bugs found while building and verifying this against Phase 2's own milestone gate (a real match under --net-sim-latency 80 --net-sim-jitter 20, not just LAN): a timestamp captured inside a delayed RPC closure silently ate that side's own added delay out of the round-trip measurement instead of adding to it; and a delayed send whose target disconnected (or whose own process had already shut down) during the hold threw RPC errors, since the existing get_peers() filtering only checked validity at schedule time. Fixed by capturing timestamps before handing off to NetSim, and by having NetSim re-validate the target at fire time. Phase 2's milestone gate now passes for real: a full 1v1 under simulated 80ms latency / 20ms jitter still shows clean server-authoritative movement and zero RPC errors. Full Phase 1 + Phase 2 regression suite re-verified clean with NetSim present but inactive.
This commit is contained in:
@@ -93,7 +93,10 @@ func _process(delta: float) -> void:
|
||||
_ping_accum_sec += delta
|
||||
if _ping_accum_sec >= PING_INTERVAL_SEC:
|
||||
_ping_accum_sec = 0.0
|
||||
_ping.rpc_id(1, Time.get_ticks_msec())
|
||||
# Capture the timestamp now, before NetSim (task 2.8) can add any
|
||||
# simulated delay — see net_sim.gd's header comment for why.
|
||||
var send_ms := Time.get_ticks_msec()
|
||||
NetSim.send(func() -> void: _ping.rpc_id(1, send_ms), 1)
|
||||
|
||||
|
||||
# Estimate of what the server's Time.get_ticks_msec() reads right now.
|
||||
@@ -165,7 +168,13 @@ func shutdown() -> void:
|
||||
func _ping(client_send_ms: int) -> void:
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
_pong.rpc_id(multiplayer.get_remote_sender_id(), client_send_ms, Time.get_ticks_msec())
|
||||
# Same rule as the client's send above: read the server's clock now, at
|
||||
# true receipt time, before NetSim can delay the reply — otherwise the
|
||||
# server's own outbound leg would be silently absorbed out of both the
|
||||
# RTT sample and the offset estimate instead of adding to them.
|
||||
var server_now := Time.get_ticks_msec()
|
||||
var sender_id := multiplayer.get_remote_sender_id()
|
||||
NetSim.send(func() -> void: _pong.rpc_id(sender_id, client_send_ms, server_now), sender_id)
|
||||
|
||||
|
||||
@rpc("authority", "call_remote", "reliable")
|
||||
|
||||
Reference in New Issue
Block a user