mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
feat(multiplayer): harden ranked arena admission
This commit is contained in:
@@ -53,16 +53,16 @@ func TestPrepareProposalRejectsInvalidRankedMetadataAndAcceptsVerifiedSix(t *tes
|
||||
for i, player := range formation.Selection.Players {
|
||||
participants[i] = RankedParticipant{PlayerID: player.PlayerID, SteamID: "steam-" + player.PlayerID}
|
||||
}
|
||||
if _, err := PrepareProposal("proposal-ranked-123456", Ranked, formation, participants, RankedArena{RandomEnabled: true}, time.Unix(1000, 0)); err != nil {
|
||||
if _, err := PrepareProposal("proposal-ranked-123456", Ranked, formation, participants, DefaultRankedArena(), time.Unix(1000, 0)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
participants[0].IsBot = true
|
||||
if _, err := PrepareProposal("proposal-ranked-654321", Ranked, formation, participants, RankedArena{RandomEnabled: true}, time.Unix(1000, 0)); err == nil {
|
||||
if _, err := PrepareProposal("proposal-ranked-654321", Ranked, formation, participants, DefaultRankedArena(), time.Unix(1000, 0)); err == nil {
|
||||
t.Fatal("ranked bot metadata accepted")
|
||||
}
|
||||
participants[0].IsBot = false
|
||||
participants[0].PlayerID = "unknown"
|
||||
if _, err := PrepareProposal("proposal-ranked-000000", Ranked, formation, participants, RankedArena{RandomEnabled: true}, time.Unix(1000, 0)); err == nil {
|
||||
if _, err := PrepareProposal("proposal-ranked-000000", Ranked, formation, participants, DefaultRankedArena(), time.Unix(1000, 0)); err == nil {
|
||||
t.Fatal("ranked unknown player metadata accepted")
|
||||
}
|
||||
}
|
||||
|
||||
+24
-3
@@ -11,12 +11,28 @@ type RankedParticipant struct {
|
||||
}
|
||||
|
||||
type RankedArena struct {
|
||||
RandomEnabled bool
|
||||
ElevatedGoals bool
|
||||
ID 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"},
|
||||
"arena_02": {ID: "arena_02"},
|
||||
"arena_03": {ID: "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"]
|
||||
}
|
||||
|
||||
func ValidateRankedAdmission(participants []RankedParticipant, arena RankedArena) error {
|
||||
if len(participants) != 6 || !arena.RandomEnabled || arena.ElevatedGoals {
|
||||
if len(participants) != 6 || !validRankedArena(arena) {
|
||||
return fmt.Errorf("ranked admission requirements not met")
|
||||
}
|
||||
seenPlayers := make(map[string]bool, len(participants))
|
||||
@@ -30,3 +46,8 @@ func ValidateRankedAdmission(participants []RankedParticipant, arena RankedArena
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validRankedArena(arena RankedArena) bool {
|
||||
registered, ok := rankedArenas[arena.ID]
|
||||
return ok && registered == arena
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ func rankedParticipants() []RankedParticipant {
|
||||
}
|
||||
|
||||
func TestRankedAdmissionRequiresSixUniqueVerifiedSoloHumansAndEligibleArena(t *testing.T) {
|
||||
if err := ValidateRankedAdmission(rankedParticipants(), RankedArena{RandomEnabled: true}); err != nil {
|
||||
if err := ValidateRankedAdmission(rankedParticipants(), DefaultRankedArena()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cases := []struct {
|
||||
@@ -23,13 +23,12 @@ func TestRankedAdmissionRequiresSixUniqueVerifiedSoloHumansAndEligibleArena(t *t
|
||||
{"bot", func(p []RankedParticipant, _ *RankedArena) { p[0].IsBot = true }},
|
||||
{"backfill", func(p []RankedParticipant, _ *RankedArena) { p[0].IsBackfill = true }},
|
||||
{"duplicate identity", func(p []RankedParticipant, _ *RankedArena) { p[1].SteamID = p[0].SteamID }},
|
||||
{"random disabled", func(_ []RankedParticipant, a *RankedArena) { a.RandomEnabled = false }},
|
||||
{"elevated arena", func(_ []RankedParticipant, a *RankedArena) { a.ElevatedGoals = true }},
|
||||
{"unknown arena", func(_ []RankedParticipant, a *RankedArena) { a.ID = "arena_unknown" }},
|
||||
}
|
||||
for _, test := range cases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
participants := rankedParticipants()
|
||||
arena := RankedArena{RandomEnabled: true}
|
||||
arena := DefaultRankedArena()
|
||||
test.edit(participants, &arena)
|
||||
if err := ValidateRankedAdmission(participants, arena); err == nil {
|
||||
t.Fatal("invalid ranked admission accepted")
|
||||
@@ -37,3 +36,11 @@ func TestRankedAdmissionRequiresSixUniqueVerifiedSoloHumansAndEligibleArena(t *t
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankedArenaRegistryExcludesElevatedVariants(t *testing.T) {
|
||||
for _, id := range []string{"arena_01_elevated", "arena_02_elevated", "arena_03_elevated"} {
|
||||
if err := ValidateRankedAdmission(rankedParticipants(), RankedArena{ID: id}); err == nil {
|
||||
t.Fatalf("elevated arena %q accepted for ranked", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user