mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
fix(multiplayer): bound workload credential lifetime
This commit is contained in:
@@ -451,10 +451,10 @@ func configure_result_submission(callback: Callable) -> void:
|
||||
_result_submit = callback
|
||||
|
||||
|
||||
func submit_authoritative_result(score: Dictionary) -> bool:
|
||||
func submit_authoritative_result(score: Dictionary, integrity_state := "CERTIFIED") -> bool:
|
||||
if not _result_submit.is_valid() or not score.has(0) or not score.has(1):
|
||||
return false
|
||||
_result_submit.call(int(score[0]), int(score[1]))
|
||||
_result_submit.call(int(score[0]), int(score[1]), integrity_state)
|
||||
return true
|
||||
|
||||
|
||||
|
||||
@@ -320,6 +320,8 @@ static var server_bot_fill_override := false
|
||||
var _max_spectators := -1
|
||||
var _last_emitted_countdown := -1
|
||||
var _in_overtime := false
|
||||
var _max_overtime_seconds := 900.0
|
||||
var _overtime_deadline_tick := -1
|
||||
var _match_over := false
|
||||
var _planned_server_shutdown := false
|
||||
var _awaiting_result_submission := false
|
||||
@@ -349,6 +351,7 @@ func _ready() -> void:
|
||||
# FULL_TIME/OVERTIME/RESULTS, so allow an override. Server-side only —
|
||||
# a client cannot shorten anyone's match.
|
||||
match_length_seconds = maxf(1.0, float(config.get_value("match-length")))
|
||||
_max_overtime_seconds = maxf(1.0, float(config.get_value("max-overtime-seconds")))
|
||||
var smoke_after := float(config.get_value("smoke-force-goal-after"))
|
||||
if smoke_after >= 0.0:
|
||||
_smoke_force_goal_tick = -2 # arm when PLAYING begins; -1 remains disabled
|
||||
@@ -685,6 +688,8 @@ func _apply_match_state(new_state: int, at_tick: int) -> void:
|
||||
# Kickoff is over: bodies move again, and the clock resumes.
|
||||
_pending_freeze_tick = -1
|
||||
_set_bodies_frozen(false)
|
||||
if new_state == MatchState.State.OVERTIME:
|
||||
_overtime_deadline_tick = at_tick + int(_max_overtime_seconds * SimConstants.TICK_HZ)
|
||||
# The clock only advances during live play (§6.2 step 9). Derived here
|
||||
# rather than tracked separately so it cannot disagree with the state.
|
||||
var was_running := _clock_running
|
||||
@@ -1055,12 +1060,12 @@ func _update_clock() -> void:
|
||||
|
||||
# --- §6.2 step 10: full time, overtime, results (task 5.5) -----------------
|
||||
|
||||
func _enter_results(winning_team: int) -> void:
|
||||
func _enter_results(winning_team: int, integrity_state := "CERTIFIED") -> void:
|
||||
_match_over = true
|
||||
_clock_running = false
|
||||
_set_bodies_frozen(true)
|
||||
match_ended.emit(winning_team, score.duplicate())
|
||||
if multiplayer.is_server() and MatchNet.submit_authoritative_result(score):
|
||||
if multiplayer.is_server() and MatchNet.submit_authoritative_result(score, integrity_state):
|
||||
_awaiting_result_submission = true
|
||||
ServerLog.info("match_ended", {"score_0": score.get(0, 0), "score_1": score.get(1, 0), "overtime": _in_overtime})
|
||||
_set_match_state(MatchState.State.RESULTS)
|
||||
@@ -1103,6 +1108,12 @@ func _update_match_state() -> void:
|
||||
else:
|
||||
_enter_results(_winning_team())
|
||||
return
|
||||
if match_state == MatchState.State.OVERTIME and _overtime_deadline_tick >= 0 and now >= _overtime_deadline_tick:
|
||||
# Golden goal remains clockless to players, but an operational bound is
|
||||
# necessary: a stalled draw must finish while its allocated credential is
|
||||
# valid. REVIEW completes lifecycle delivery without rating either side.
|
||||
_enter_results(-1, "REVIEW")
|
||||
return
|
||||
if _state_deadline_tick < 0 or now < _state_deadline_tick:
|
||||
return
|
||||
match match_state:
|
||||
|
||||
@@ -56,6 +56,7 @@ static func specs() -> Array[Spec]:
|
||||
out.append(Spec.new("log-level", Kind.STRING, "info", "logging", "One of debug, info, warn, error"))
|
||||
out.append(Spec.new("replay-log", Kind.STRING, "", "logging", "Path to record a binary replay log to; empty disables (see tools/replay_dump.gd)"))
|
||||
out.append(Spec.new("match-length", Kind.FLOAT, 150.0, "match", "Regulation length in seconds"))
|
||||
out.append(Spec.new("max-overtime-seconds", Kind.FLOAT, 900.0, "match", "Safety cap for sudden death; expiry records a REVIEW result without rating changes"))
|
||||
out.append(Spec.new("max-matches", Kind.INT, 0, "match", "Exit cleanly after this many completed matches; 0 runs forever"))
|
||||
out.append(Spec.new("min-players", Kind.INT, 1, "match", "Players required before a match starts"))
|
||||
out.append(Spec.new("start-countdown", Kind.FLOAT, 5.0, "match", "Seconds to wait after min-players is met before starting"))
|
||||
@@ -255,6 +256,8 @@ func _validate() -> void:
|
||||
errors.append("--max-clients must be at least 1, got %d" % int(values["max-clients"]))
|
||||
if float(values["match-length"]) <= 0.0:
|
||||
errors.append("--match-length must be positive, got %s" % str(values["match-length"]))
|
||||
if float(values["max-overtime-seconds"]) <= 0.0:
|
||||
errors.append("--max-overtime-seconds must be positive, got %s" % str(values["max-overtime-seconds"]))
|
||||
if int(values["max-matches"]) < 0:
|
||||
errors.append("--max-matches must be 0 or more, got %d" % int(values["max-matches"]))
|
||||
if int(values["min-players"]) < 1:
|
||||
|
||||
@@ -30,7 +30,7 @@ func configure(base_url: String, workload_token: String, match_id: String, serve
|
||||
|
||||
|
||||
func submit(team_0: int, team_1: int, integrity_state := "CERTIFIED") -> void:
|
||||
if _submitting or team_0 < 0 or team_1 < 0 or integrity_state != "CERTIFIED":
|
||||
if _submitting or team_0 < 0 or team_1 < 0 or not integrity_state in ["CERTIFIED", "REVIEW"]:
|
||||
return
|
||||
_submitting = true
|
||||
var nonce := result_nonce(_match_id, _server_id, team_0, team_1, integrity_state)
|
||||
|
||||
Reference in New Issue
Block a user