mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
84 lines
2.8 KiB
Go
84 lines
2.8 KiB
Go
package domain
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"fmt"
|
|
)
|
|
|
|
type RankedParticipant struct {
|
|
PlayerID string
|
|
SteamID string
|
|
PartyID string
|
|
IsBot bool
|
|
IsBackfill bool
|
|
}
|
|
|
|
type RankedArena struct {
|
|
ID string
|
|
Path string
|
|
}
|
|
|
|
// rankedArenas is the server-owned eligibility registry for launch ranked
|
|
// matches. It mirrors the floor-goal ArenaRegistry entries in the Godot
|
|
// project, but deliberately excludes every elevated-goal variant until a
|
|
// policy trained for that geometry is promoted.
|
|
var rankedArenas = map[string]RankedArena{
|
|
"arena_01": {ID: "arena_01", Path: "res://scenes/arena_01.tscn"},
|
|
"arena_02": {ID: "arena_02", Path: "res://scenes/arena_02.tscn"},
|
|
"arena_03": {ID: "arena_03", Path: "res://scenes/arena_03.tscn"},
|
|
}
|
|
|
|
var rankedArenaOrder = []string{"arena_01", "arena_02", "arena_03"}
|
|
|
|
// DefaultRankedArena supplies a safe server-owned eligibility decision while
|
|
// the allocator-to-Godot match configuration channel is being completed. A
|
|
// ranked proposal is never admitted based on a mutable command-line boolean.
|
|
func DefaultRankedArena() RankedArena {
|
|
return rankedArenas["arena_01"]
|
|
}
|
|
|
|
// RankedArenaForProposal chooses a floor-goal arena deterministically from the
|
|
// proposal identity. The same durable proposal retry therefore cannot change
|
|
// arena, while independent proposals rotate across the registry without
|
|
// mutable worker-local counters.
|
|
func RankedArenaForProposal(proposalID string) RankedArena {
|
|
if proposalID == "" {
|
|
return DefaultRankedArena()
|
|
}
|
|
digest := sha256.Sum256([]byte(proposalID))
|
|
return rankedArenas[rankedArenaOrder[int(digest[0])%len(rankedArenaOrder)]]
|
|
}
|
|
|
|
// IsRankedArenaPath is the durable-store boundary for arena paths. Proposal
|
|
// and allocation records must not accept a merely non-empty caller supplied
|
|
// scene path, even when the caller bypasses matcher formation.
|
|
func IsRankedArenaPath(path string) bool {
|
|
for _, arena := range rankedArenas {
|
|
if arena.Path == path {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func ValidateRankedAdmission(participants []RankedParticipant, arena RankedArena) error {
|
|
if len(participants) != 6 || !validRankedArena(arena) {
|
|
return fmt.Errorf("ranked admission requirements not met")
|
|
}
|
|
seenPlayers := make(map[string]bool, len(participants))
|
|
seenSteam := make(map[string]bool, len(participants))
|
|
for _, participant := range participants {
|
|
if participant.PlayerID == "" || participant.SteamID == "" || participant.PartyID != "" || participant.IsBot || participant.IsBackfill || seenPlayers[participant.PlayerID] || seenSteam[participant.SteamID] {
|
|
return fmt.Errorf("ranked requires six unique verified solo humans")
|
|
}
|
|
seenPlayers[participant.PlayerID] = true
|
|
seenSteam[participant.SteamID] = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validRankedArena(arena RankedArena) bool {
|
|
registered, ok := rankedArenas[arena.ID]
|
|
return ok && registered == arena
|
|
}
|