feat(multiplayer): preserve authoritative queue wait

This commit is contained in:
Josh Creek
2026-09-01 21:45:07 +01:00
parent 950e879861
commit 9240cd4b27
6 changed files with 37 additions and 2 deletions
+2
View File
@@ -275,6 +275,8 @@ static func is_retryable_mutation_response(response_code: int) -> bool:
static func normalize_ticket(payload: Dictionary) -> Dictionary:
var result := payload.duplicate(true)
if result.has("enqueued_at") and result["enqueued_at"] is String:
result["enqueued_at_unix"] = Time.get_unix_time_from_datetime_string(String(result["enqueued_at"]))
if result.has("expires_at") and result["expires_at"] is String:
result["expires_at_unix"] = Time.get_unix_time_from_datetime_string(String(result["expires_at"]))
return result
+4 -1
View File
@@ -175,7 +175,10 @@ func _render(snapshot: Dictionary) -> void:
if String(snapshot.get("message", "")) != "":
detail_label.text = String(snapshot["message"])
elif phase == MatchmakingState.QUEUED:
detail_label.text = "Elapsed %.0fs · revision %d" % [_elapsed_seconds, int(snapshot.get("revision", 0))]
var waited := _elapsed_seconds
if int(snapshot.get("enqueued_at_unix", 0)) > 0:
waited = float(ControlPlaneClient.state.waited_seconds(int(Time.get_unix_time_from_system())))
detail_label.text = "Waiting %.0fs · revision %d" % [waited, int(snapshot.get("revision", 0))]
elif phase == MatchmakingState.PROPOSED:
detail_label.text = "Review the proposal before the countdown expires"
elif phase == MatchmakingState.IDLE:
+14 -1
View File
@@ -24,6 +24,7 @@ var phase := IDLE
var ticket_id := ""
var playlist := ""
var revision := 0
var enqueued_at_unix := 0
var expires_at_unix := 0
var proposal_id := ""
var proposal_revision := 0
@@ -61,6 +62,8 @@ func apply_ticket_update(update: Dictionary) -> bool:
# queued ticket's expiry is ever set at all.
if update.has("expires_at_unix"):
expires_at_unix = int(update["expires_at_unix"])
if update.has("enqueued_at_unix"):
enqueued_at_unix = maxi(0, int(update["enqueued_at_unix"]))
return true
if incoming_revision > revision + 1:
return _request_resync(self.ticket_id)
@@ -73,6 +76,8 @@ func apply_ticket_update(update: Dictionary) -> bool:
playlist = String(update["playlist"])
if update.has("expires_at_unix"):
expires_at_unix = int(update["expires_at_unix"])
if update.has("enqueued_at_unix"):
enqueued_at_unix = maxi(0, int(update["enqueued_at_unix"]))
if update.has("message"):
message = String(update["message"])
else:
@@ -173,6 +178,7 @@ func restore_snapshot(saved: Dictionary) -> bool:
playlist = saved_playlist
phase = saved_phase
revision = maxi(0, int(saved.get("revision", 0)))
enqueued_at_unix = maxi(0, int(saved.get("enqueued_at_unix", 0)))
expires_at_unix = maxi(0, int(saved.get("expires_at_unix", 0)))
proposal_id = String(saved.get("proposal_id", ""))
proposal_revision = maxi(0, int(saved.get("proposal_revision", 0)))
@@ -187,8 +193,14 @@ func can_cancel() -> bool:
return phase == QUEUED or phase == PROPOSED or phase == ALLOCATING
func waited_seconds(now_unix: int) -> int:
if enqueued_at_unix <= 0:
return 0
return maxi(0, now_unix - enqueued_at_unix)
func snapshot() -> Dictionary:
return {"phase": phase, "ticket_id": ticket_id, "playlist": playlist, "revision": revision, "expires_at_unix": expires_at_unix, "proposal_id": proposal_id, "proposal_revision": proposal_revision, "proposal_state": proposal_state, "message": message, "needs_resync": needs_resync}
return {"phase": phase, "ticket_id": ticket_id, "playlist": playlist, "revision": revision, "enqueued_at_unix": enqueued_at_unix, "expires_at_unix": expires_at_unix, "proposal_id": proposal_id, "proposal_revision": proposal_revision, "proposal_state": proposal_state, "message": message, "needs_resync": needs_resync}
func _ticket_differs(update: Dictionary) -> bool:
@@ -219,6 +231,7 @@ func _reset() -> void:
phase = IDLE
playlist = ""
revision = 0
enqueued_at_unix = 0
expires_at_unix = 0
proposal_id = ""
proposal_revision = 0