mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 18:03:43 +00:00
feat: persist matchmaking recovery state
This commit is contained in:
@@ -8,6 +8,7 @@ signal request_succeeded(operation: String, payload: Dictionary)
|
||||
signal request_failed(operation: String, http_code: int, detail: String)
|
||||
|
||||
const DEFAULT_BASE_URL := "http://127.0.0.1:8080"
|
||||
const PERSIST_PATH := "user://matchmaking_state.cfg"
|
||||
|
||||
var base_url := DEFAULT_BASE_URL
|
||||
var access_token := ""
|
||||
@@ -19,6 +20,8 @@ var _operation := ""
|
||||
|
||||
func _ready() -> void:
|
||||
state = MatchmakingState.new()
|
||||
_load_persisted_state()
|
||||
state.changed.connect(_persist_state)
|
||||
_request = HTTPRequest.new()
|
||||
_request.timeout = 10.0
|
||||
add_child(_request)
|
||||
@@ -145,3 +148,21 @@ func _on_request_completed(result: HTTPRequest.Result, response_code: int, _head
|
||||
|
||||
func _idempotency_key(prefix: String) -> String:
|
||||
return "%s-%s-%s" % [prefix, str(Time.get_ticks_usec()), str(randi())]
|
||||
|
||||
|
||||
func _persist_state(snapshot: Dictionary) -> void:
|
||||
var config := ConfigFile.new()
|
||||
config.set_value("matchmaking", "snapshot", JSON.stringify(snapshot))
|
||||
config.save(PERSIST_PATH)
|
||||
|
||||
|
||||
func _load_persisted_state() -> void:
|
||||
var config := ConfigFile.new()
|
||||
if config.load(PERSIST_PATH) != OK:
|
||||
return
|
||||
var raw = config.get_value("matchmaking", "snapshot", "")
|
||||
if not raw is String or String(raw).is_empty():
|
||||
return
|
||||
var parsed = JSON.parse_string(String(raw))
|
||||
if parsed is Dictionary and not state.restore_snapshot(parsed):
|
||||
state.fail("Saved matchmaking state is invalid")
|
||||
|
||||
@@ -70,6 +70,7 @@ func apply_ticket_update(update: Dictionary) -> bool:
|
||||
message = String(update["message"])
|
||||
else:
|
||||
message = ""
|
||||
needs_resync = false
|
||||
_emit_changed()
|
||||
return true
|
||||
|
||||
@@ -106,6 +107,7 @@ func apply_proposal_update(update: Dictionary) -> bool:
|
||||
return _request_resync(proposal_id)
|
||||
proposal_revision = incoming_revision
|
||||
proposal_state = incoming_proposal_state
|
||||
needs_resync = false
|
||||
if incoming_proposal_state == "OPEN" or incoming_proposal_state == "ACCEPTED":
|
||||
message = ""
|
||||
if update.has("expires_at_unix"):
|
||||
@@ -143,6 +145,31 @@ func set_notice(notice: String) -> void:
|
||||
_emit_changed()
|
||||
|
||||
|
||||
func restore_snapshot(saved: Dictionary) -> bool:
|
||||
_reset()
|
||||
if saved.is_empty():
|
||||
return true
|
||||
var saved_phase := String(saved.get("phase", IDLE))
|
||||
var saved_ticket_id := String(saved.get("ticket_id", ""))
|
||||
if saved_ticket_id.is_empty() or not _is_ticket_state(saved_phase):
|
||||
return false
|
||||
var saved_playlist := String(saved.get("playlist", ""))
|
||||
if saved_playlist != "casual" and saved_playlist != "ranked":
|
||||
return false
|
||||
ticket_id = saved_ticket_id
|
||||
playlist = saved_playlist
|
||||
phase = saved_phase
|
||||
revision = maxi(0, int(saved.get("revision", 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)))
|
||||
proposal_state = String(saved.get("proposal_state", ""))
|
||||
message = "Recovering authoritative matchmaking state"
|
||||
needs_resync = phase != CANCELLED and phase != EXPIRED and phase != FAILED
|
||||
_emit_changed()
|
||||
return true
|
||||
|
||||
|
||||
func can_cancel() -> bool:
|
||||
return phase == QUEUED or phase == PROPOSED or phase == ALLOCATING
|
||||
|
||||
|
||||
Reference in New Issue
Block a user