fix(multiplayer): recover assignment handoff

This commit is contained in:
Josh Creek
2026-09-02 18:47:00 +01:00
parent 84d27d82da
commit 91658fbc13
12 changed files with 147 additions and 15 deletions
+24 -3
View File
@@ -48,7 +48,7 @@ func begin_queue(new_ticket_id: String, new_playlist: String) -> bool:
return true
func apply_ticket_update(update: Dictionary) -> bool:
func apply_ticket_update(update: Dictionary, authoritative_snapshot: bool = false) -> bool:
if not _has_string(update, "ticket_id") or not update.has("revision") or not _valid_revision(update["revision"]) or not update.has("state"):
return _request_resync(self.ticket_id)
if update.has("playlist") and not _valid_playlist(String(update["playlist"])):
@@ -75,12 +75,15 @@ func apply_ticket_update(update: Dictionary) -> bool:
if update.has("enqueued_at_unix"):
enqueued_at_unix = maxi(0, int(update["enqueued_at_unix"]))
return true
if incoming_revision > revision + 1:
if incoming_revision > revision + 1 and not authoritative_snapshot:
return _request_resync(self.ticket_id)
var incoming_state := String(update["state"])
if not _is_ticket_state(incoming_state):
return _request_resync(self.ticket_id)
if not _is_legal_ticket_transition(phase, incoming_state):
if authoritative_snapshot:
if not _can_reach_ticket_state(phase, incoming_state):
return _request_resync(self.ticket_id)
elif not _is_legal_ticket_transition(phase, incoming_state):
return _request_resync(self.ticket_id)
revision = incoming_revision
phase = incoming_state
@@ -319,6 +322,24 @@ func _is_legal_ticket_transition(from: String, to: String) -> bool:
return transitions.has(from) and to in transitions[from]
func _can_reach_ticket_state(from: String, to: String) -> bool:
if from == to:
return true
var pending: Array[String] = [from]
var visited := {}
visited[from] = true
while not pending.is_empty():
var current: String = pending.pop_front()
for candidate in [QUEUED, PROPOSED, ACCEPTED, ALLOCATING, PROCESS_READY, ASSIGNMENT_READY, ASSIGNED, CONNECTING, LIVE, RESULT_PENDING, COMPLETED, CANCELLED, EXPIRED, FAILED]:
if visited.has(candidate) or not _is_legal_ticket_transition(current, candidate):
continue
if candidate == to:
return true
visited[candidate] = true
pending.append(candidate)
return false
func _is_legal_proposal_transition(from: String, to: String) -> bool:
if from.is_empty():
return to == "OPEN"