Files
SirRoboGarage/libs/tankroyale_botapi/tankroyale_botapi/schemas.nim
T
SirStone 64697f917e fix(botapi): static event queue storage + end-of-battle train wait
The event queue's heap seq was the last GC'd block surviving across
rounds: each round runs on a freshly spawned bot thread, so the N+1
thread realloc'd a block grown by dead thread N's allocator mid-round
(at the next capacity doubling, ~turn 104) -> rawDealloc SIGSEGV in
addEvent (7 gdb-confirmed coredumps). Replace with a static
array[MAX_QUEUE_SIZE, BotEvent] + eventsLen: no heap block crosses
threads, realloc can never happen.

Also fix the harness aborting the final round mid-train: PPO_Bot's
onRoundEnded trains synchronously after the runner's RoundEndedEvent,
so the counter read right after awaitResults() is the stale pre-train
value and System.exit killed the bot inside ppoUpdate. Poll up to 60s
for the counter to catch up before declaring the battle incomplete.

Verified: 72 consecutive rounds vs Fire, 100% wins, all rounds trained
(counter advanced 1:1), zero coredumps since the fix.
2026-08-19 03:12:22 +02:00

276 lines
7.0 KiB
Nim

## Schema types for Robocode Tank Royale protocol messages.
## These mirror the YAML schemas in schema/schemas/.
import ./color
type
# ---- Shared / embedded types -----------------------------------------------
InitialPosition* = object
x*: float
y*: float
direction*: float
GameSetup* = object
gameType*: string
arenaWidth*: int
isArenaWidthLocked*: bool
arenaHeight*: int
isArenaHeightLocked*: bool
minNumberOfParticipants*: int
isMinNumberOfParticipantsLocked*: bool
maxNumberOfParticipants*: int
isMaxNumberOfParticipantsLocked*: bool
numberOfRounds*: int
isNumberOfRoundsLocked*: bool
gunCoolingRate*: float
isGunCoolingRateLocked*: bool
maxInactivityTurns*: int
isMaxInactivityTurnsLocked*: bool
turnTimeout*: int # microseconds
isTurnTimeoutLocked*: bool
readyTimeout*: int # microseconds
isReadyTimeoutLocked*: bool
defaultTurnsPerSecond*: int
BotState* = object
isDroid*: bool
energy*: float
x*: float
y*: float
direction*: float
gunDirection*: float
radarDirection*: float
radarSweep*: float
speed*: float
turnRate*: float
gunTurnRate*: float
radarTurnRate*: float
gunHeat*: float
enemyCount*: int
bodyColor*: Color
turretColor*: Color
radarColor*: Color
bulletColor*: Color
scanColor*: Color
tracksColor*: Color
gunColor*: Color
BulletState* = object
bulletId*: int
ownerId*: int
power*: float
x*: float
y*: float
direction*: float
color*: Color
ResultsForBot* = object
rank*: int
survival*: int
lastSurvivorBonus*: int
bulletDamage*: int
bulletKillBonus*: int
ramDamage*: int
ramKillBonus*: int
totalScore*: int
firstPlaces*: int
secondPlaces*: int
thirdPlaces*: int
TeamMessage* = object
message*: string
messageType*: string
receiverId*: int
# ---- Connection event types ------------------------------------------------
ConnectedEvent* = object
serverUrl*: string
DisconnectedEvent* = object
serverUrl*: string
remote*: bool
statusCode*: int ## 0 when not provided
reason*: string
ConnectionErrorEvent* = object
serverUrl*: string
error*: string
# ---- Server → Bot messages -------------------------------------------------
ServerHandshake* = object
`type`*: string
sessionId*: string
name*: string
variant*: string
version*: string
gameTypes*: seq[string]
GameStartedEventForBot* = object
`type`*: string
myId*: int
startX*: float
startY*: float
startDirection*: float
teammateIds*: seq[int]
gameSetup*: GameSetup
RoundStartedEvent* = object
`type`*: string
roundNumber*: int
RoundEndedEventForBot* = object
`type`*: string
turnNumber*: int
roundNumber*: int
results*: ResultsForBot
GameEndedEventForBot* = object
`type`*: string
numberOfRounds*: int
results*: ResultsForBot
GameAbortedEvent* = object
`type`*: string
SkippedTurnEvent* = object
`type`*: string
turnNumber*: int
# Events inside TickEventForBot.events
BotDeathEvent* = object
`type`*: string
turnNumber*: int
victimId*: int
BotHitBotEvent* = object
`type`*: string
turnNumber*: int
victimId*: int
botId*: int
energy*: float
x*: float
y*: float
rammed*: bool
BotHitWallEvent* = object
`type`*: string
turnNumber*: int
victimId*: int
BulletFiredEvent* = object
`type`*: string
turnNumber*: int
bullet*: BulletState
BulletHitBotEvent* = object
`type`*: string
turnNumber*: int
victimId*: int
bullet*: BulletState
damage*: float
energy*: float
BulletHitBulletEvent* = object
`type`*: string
turnNumber*: int
bullet*: BulletState
hitBullet*: BulletState
BulletHitWallEvent* = object
`type`*: string
turnNumber*: int
bullet*: BulletState
HitByBulletEvent* = object
`type`*: string
turnNumber*: int
bullet*: BulletState
damage*: float
energy*: float
ScannedBotEvent* = object
`type`*: string
turnNumber*: int
scannedByBotId*: int
scannedBotId*: int
energy*: float
x*: float
y*: float
direction*: float
speed*: float
WonRoundEvent* = object
`type`*: string
turnNumber*: int
TeamMessageEvent* = object
`type`*: string
turnNumber*: int
message*: string
messageType*: string
senderId*: int
TickEventForBot* = object
`type`*: string
turnNumber*: int
roundNumber*: int
botState*: BotState
bulletStates*: seq[BulletState]
events*: seq[RawEvent] # heterogeneous; decoded by type field
# A raw event with just a type field, for first-pass dispatch
RawEvent* = object
`type`*: string
turnNumber*: int
# ---- Bot → Server messages -------------------------------------------------
BotHandshake* = object
`type`*: string
sessionId*: string
name*: string
version*: string
authors*: seq[string]
description*: string
homepage*: string
countryCodes*: seq[string]
gameTypes*: seq[string]
platform*: string
programmingLang*: string
initialPosition*: InitialPosition
teamId*: int
teamName*: string
teamVersion*: string
isDroid*: bool
secret*: string
BotReady* = object
`type`*: string
BotIntent* = object
`type`*: string
turnRate*: float
gunTurnRate*: float
radarTurnRate*: float
targetSpeed*: float
firepower*: float
adjustGunForBodyTurn*: bool
adjustRadarForBodyTurn*: bool
adjustRadarForGunTurn*: bool
rescan*: bool
fireAssist*: bool
bodyColor*: Color
turretColor*: Color
radarColor*: Color
bulletColor*: Color
scanColor*: Color
tracksColor*: Color
gunColor*: Color
stdOut*: string
stdErr*: string
teamMessages*: seq[TeamMessage]
debugGraphics*: string