island-battles-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,870 @@
1
+ # Generated by scripts/generate.py from backend/api/openapi.json. Do not edit;
2
+ # change the Go API types, export the document, and regenerate instead.
3
+
4
+ from collections.abc import Mapping, Sequence
5
+ from enum import StrEnum
6
+ from typing import Annotated, Any, Literal
7
+ from uuid import UUID
8
+
9
+ from island_battles_client._entities import (
10
+ BoardEntity,
11
+ GameModel,
12
+ GenerationBase,
13
+ SoldierGroupBase,
14
+ )
15
+ from pydantic import (
16
+ AnyUrl,
17
+ AwareDatetime,
18
+ ConfigDict,
19
+ Field,
20
+ RootModel,
21
+ StrictBool,
22
+ StrictFloat,
23
+ StrictInt,
24
+ StrictStr,
25
+ )
26
+
27
+
28
+ class BotChoice(GameModel):
29
+ model_config = ConfigDict(
30
+ extra="ignore",
31
+ )
32
+ kind: Literal["localhost", "default"]
33
+ """
34
+ localhost: the player's own bot, which island-battles-bot serve runs on their machine; their game client relays each turn to it and submits its answer. default: a default bot of GET /bots/defaults, which the backend plays itself, so the player's client submits nothing.
35
+ """
36
+ level: Annotated[StrictInt | None, Field(ge=1)] = None
37
+ """
38
+ For kind default, the level of the default bot, one that GET /bots/defaults lists. Absent for kind localhost.
39
+ """
40
+
41
+
42
+ class BotTurn(GameModel):
43
+ model_config = ConfigDict(
44
+ extra="ignore",
45
+ )
46
+ game_id: Annotated[StrictInt, Field(ge=1)]
47
+ generation: Generation
48
+ memory: Mapping[str, Any] | None
49
+ """
50
+ The memory the bot returned with its previous turn in this game, or null on its first turn and after a turn that returned null.
51
+ """
52
+ team_color: Annotated[StrictInt, Field(ge=1)]
53
+ turn_deadline_at: AwareDatetime | None
54
+ """
55
+ When the turn times out, GenerationState.turn_deadline_at, or null when turns have no time limit. A bot that hasn't answered by then makes its whole team lose.
56
+ """
57
+ upgrades: Sequence[Upgrade]
58
+ """
59
+ The upgrade cost table, the same list GET /game/upgrades returns as its upgrades. It is the same for the whole game, so a client reads it once and reuses it in every turn. Reaching a level costs its soldier_cost.
60
+ """
61
+
62
+
63
+ class BotTurnResult(GameModel):
64
+ model_config = ConfigDict(
65
+ extra="ignore",
66
+ )
67
+ commands: Annotated[Sequence[PublicGenerationCommand], Field(max_length=1000)]
68
+ logs: Annotated[Sequence[GenerationLogLine], Field(max_length=100)]
69
+ """
70
+ Game log lines for this turn, of at most 500 characters each.
71
+ """
72
+ memory: Mapping[str, Any] | None
73
+ """
74
+ Any JSON object of at most 64 KiB as compact JSON, given back as BotTurn.memory next turn, or null for none.
75
+ """
76
+
77
+
78
+ class Castle(BoardEntity):
79
+ model_config = ConfigDict(
80
+ extra="ignore",
81
+ )
82
+ id: Annotated[StrictInt, Field(ge=0)]
83
+ """
84
+ Castle ID, stable for the whole game.
85
+ """
86
+ soldiers: Annotated[StrictInt, Field(ge=0)]
87
+ team_color: Annotated[StrictInt, Field(ge=0)]
88
+ """
89
+ Owning team; 0 is neutral.
90
+ """
91
+ upgrades: Mapping[UpgradeType, StrictInt]
92
+ """
93
+ Every upgrade type's level. GET /game/upgrades lists the levels and what the next one costs.
94
+ """
95
+ x: StrictFloat
96
+ y: StrictFloat
97
+
98
+
99
+ class CastleTemplate(GameModel):
100
+ model_config = ConfigDict(
101
+ extra="ignore",
102
+ )
103
+ starting_soldier_amount: Annotated[StrictInt | None, Field(ge=0)] = None
104
+ """
105
+ Soldiers in the castle when a game starts. Defaults to neutral_starting_soldier_amount.
106
+ """
107
+ team_color: Annotated[StrictInt, Field(ge=0)]
108
+ """
109
+ Owning team colour, from 1 to player_amount; 0 is neutral.
110
+ """
111
+ upgrades: Mapping[UpgradeType, StrictInt] | None = None
112
+ """
113
+ Starting level of each upgrade type. Omitted types start at level 1.
114
+ """
115
+ x: StrictFloat
116
+ """
117
+ Distance from the centre of the plane, between -plane_size_x/2 and plane_size_x/2.
118
+ """
119
+ y: StrictFloat
120
+ """
121
+ Distance from the centre of the plane, between -plane_size_y/2 and plane_size_y/2.
122
+ """
123
+
124
+
125
+ class Clash(GameModel):
126
+ model_config = ConfigDict(
127
+ extra="ignore",
128
+ )
129
+ id: Annotated[StrictInt, Field(ge=1)]
130
+ """
131
+ Identifies the clash within its generation.
132
+ """
133
+ participants: Sequence[ClashParticipant]
134
+ time: Annotated[StrictFloat, Field(ge=0.0, le=1.0)]
135
+ """
136
+ Fraction of the turn at which contact happened.
137
+ """
138
+
139
+
140
+ class ClashParticipant(GameModel):
141
+ model_config = ConfigDict(
142
+ extra="ignore",
143
+ )
144
+ clash_radius: Annotated[StrictFloat, Field(gt=0.0)]
145
+ group_id: Annotated[StrictInt, Field(ge=0)]
146
+ """
147
+ Soldier group ID; the group may no longer exist.
148
+ """
149
+ soldiers_after: Annotated[StrictInt, Field(ge=0)]
150
+ """
151
+ Soldiers immediately after this contact; 0 means the group was defeated.
152
+ """
153
+ soldiers_before: Annotated[StrictInt, Field(ge=0)]
154
+ """
155
+ Soldiers immediately before this contact.
156
+ """
157
+ team_color: Annotated[StrictInt, Field(ge=0)]
158
+ x: StrictFloat
159
+ y: StrictFloat
160
+
161
+
162
+ class ConnectionToken(GameModel):
163
+ model_config = ConfigDict(
164
+ extra="ignore",
165
+ )
166
+ field_schema: Annotated[
167
+ AnyUrl | None,
168
+ Field(alias="$schema", examples=["https://example.com/ConnectionToken.json"]),
169
+ ] = None
170
+ """
171
+ A URL to the JSON Schema for this object.
172
+ """
173
+ expires_at: AwareDatetime
174
+ token: StrictStr
175
+ websocket_url: AnyUrl
176
+
177
+
178
+ class ConnectionTokenInputBody(GameModel):
179
+ model_config = ConfigDict(
180
+ extra="ignore",
181
+ )
182
+ field_schema: Annotated[
183
+ AnyUrl | None,
184
+ Field(
185
+ alias="$schema",
186
+ examples=["https://example.com/ConnectionTokenInputBody.json"],
187
+ ),
188
+ ] = None
189
+ """
190
+ A URL to the JSON Schema for this object.
191
+ """
192
+
193
+
194
+ class DefaultBot(GameModel):
195
+ model_config = ConfigDict(
196
+ extra="ignore",
197
+ )
198
+ description: StrictStr
199
+ """
200
+ How the bot plays, in a sentence or two.
201
+ """
202
+ level: Annotated[StrictInt, Field(ge=1)]
203
+ """
204
+ The bot's level. Higher levels play better.
205
+ """
206
+ name: StrictStr
207
+ """
208
+ A short name to show in a bot picker.
209
+ """
210
+
211
+
212
+ class Demo(GameModel):
213
+ model_config = ConfigDict(
214
+ extra="ignore",
215
+ )
216
+ format: Literal["island-battles-demo"]
217
+ """
218
+ Marks the file as an Island Battles demo.
219
+ """
220
+ frames: Annotated[Sequence[Generation], Field(min_length=1)]
221
+ """
222
+ Every generation played when the demo was saved, in order. Each is the board view that players received.
223
+ """
224
+ game_id: Annotated[StrictInt, Field(ge=1)]
225
+ logs: Sequence[GenerationLogs]
226
+ """
227
+ One entry per frame, in the same order, with the game log lines its saver could see when saving: while the game runs only the saver's team's, once it has ended every team's. hidden_team_colors names the teams left out.
228
+ """
229
+ outcome: GameOutcome | None
230
+ """
231
+ How the game ended, or null when the demo was saved while the game was still running.
232
+ """
233
+ saved_at: AwareDatetime
234
+ """
235
+ When the demo was saved.
236
+ """
237
+ schema_version: Literal[1]
238
+ """
239
+ The demo format's version. The demo viewer opens only the current version and rejects a demo saved by another version of the game.
240
+ """
241
+ teams: Sequence[GameTeam]
242
+ """
243
+ The teams that played, with their lobby names and the display names their players had at the start.
244
+ """
245
+
246
+
247
+ class ErrorDetail(GameModel):
248
+ model_config = ConfigDict(
249
+ extra="ignore",
250
+ )
251
+ location: StrictStr | None = None
252
+ """
253
+ Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'
254
+ """
255
+ message: StrictStr | None = None
256
+ """
257
+ Error message text
258
+ """
259
+ value: Any | None = None
260
+ """
261
+ The value at the given location
262
+ """
263
+
264
+
265
+ class ErrorModel(GameModel):
266
+ model_config = ConfigDict(
267
+ extra="ignore",
268
+ )
269
+ field_schema: Annotated[
270
+ AnyUrl | None,
271
+ Field(alias="$schema", examples=["https://example.com/ErrorModel.json"]),
272
+ ] = None
273
+ """
274
+ A URL to the JSON Schema for this object.
275
+ """
276
+ detail: Annotated[
277
+ StrictStr | None, Field(examples=["Property foo is required but is missing."])
278
+ ] = None
279
+ """
280
+ A human-readable explanation specific to this occurrence of the problem.
281
+ """
282
+ errors: Sequence[ErrorDetail] | None = None
283
+ """
284
+ Optional list of individual error details
285
+ """
286
+ instance: Annotated[
287
+ AnyUrl | None, Field(examples=["https://example.com/error-log/abc123"])
288
+ ] = None
289
+ """
290
+ A URI reference that identifies the specific occurrence of the problem.
291
+ """
292
+ status: Annotated[StrictInt | None, Field(examples=[400])] = None
293
+ """
294
+ HTTP status code
295
+ """
296
+ title: Annotated[StrictStr | None, Field(examples=["Bad Request"])] = None
297
+ """
298
+ A short, human-readable summary of the problem type. This value should not change between occurrences of the error.
299
+ """
300
+ type: Annotated[
301
+ AnyUrl | None, Field(examples=["https://example.com/errors/example"])
302
+ ] = "about:blank"
303
+ """
304
+ A URI reference to human-readable documentation for the error.
305
+ """
306
+
307
+
308
+ class GameEndedEvent(GameModel):
309
+ model_config = ConfigDict(
310
+ extra="ignore",
311
+ )
312
+ schema_version: Literal[1]
313
+ state: GenerationState
314
+ """
315
+ The final generation, with its outcome.
316
+ """
317
+ type: Literal["game.ended"]
318
+
319
+
320
+ class GameOutcome(GameModel):
321
+ model_config = ConfigDict(
322
+ extra="ignore",
323
+ )
324
+ reason: Literal[
325
+ "last_team_standing", "all_eliminated", "generation_cap", "turn_timeout"
326
+ ]
327
+ """
328
+ last_team_standing: one team was left after every other team lost all its castles and soldier groups. all_eliminated: the last teams were eliminated in the same turn, a draw. generation_cap: the game reached its last generation; the team with the most castles won, and equal counts are a draw. turn_timeout: a turn passed its deadline; every team with a player who hadn't completed it lost, and among the other teams still standing the team with the most castles won, while equal counts, or no team left, are a draw.
329
+ """
330
+ summary: StrictStr
331
+ """
332
+ The outcome in one sentence, naming the winning team, and for turn_timeout the teams that lost and their players who didn't answer.
333
+ """
334
+ winner_team_color: Annotated[StrictInt | None, Field(ge=1)]
335
+ """
336
+ The winning team, or null for a draw.
337
+ """
338
+
339
+
340
+ class GameTeam(GameModel):
341
+ model_config = ConfigDict(
342
+ extra="ignore",
343
+ )
344
+ color: Annotated[StrictInt, Field(ge=1)]
345
+ """
346
+ The team colour that castles and soldier groups carry as team_color.
347
+ """
348
+ name: StrictStr
349
+ players: Sequence[StrictStr]
350
+ """
351
+ The display names the team's players had at the start.
352
+ """
353
+
354
+
355
+ class Generation(GenerationBase):
356
+ model_config = ConfigDict(
357
+ extra="ignore",
358
+ )
359
+ castles: Sequence[Castle]
360
+ clashes: Sequence[Clash]
361
+ id: Annotated[StrictInt, Field(ge=1)]
362
+ """
363
+ Generation ID; increases with every turn.
364
+ """
365
+ soldier_groups: Sequence[SoldierGroup]
366
+
367
+
368
+ class GenerationEvent(GameModel):
369
+ model_config = ConfigDict(
370
+ extra="ignore",
371
+ )
372
+ schema_version: Literal[1]
373
+ state: GenerationState
374
+ type: Literal["game.next_generation"]
375
+
376
+
377
+ class GenerationLogLine(GameModel):
378
+ model_config = ConfigDict(
379
+ extra="ignore",
380
+ )
381
+ level: Literal["debug", "info", "warning", "error"]
382
+ logger: Annotated[StrictStr, Field(max_length=100)]
383
+ """
384
+ The name of the logger that wrote the line, such as island_battles.player.
385
+ """
386
+ message: Annotated[StrictStr, Field(max_length=500, min_length=1)]
387
+ """
388
+ The line, of 1 to 500 Unicode code points. A client cuts a longer line to fit and says so at its end.
389
+ """
390
+
391
+
392
+ class GenerationLogs(GameModel):
393
+ model_config = ConfigDict(
394
+ extra="ignore",
395
+ )
396
+ field_schema: Annotated[
397
+ AnyUrl | None,
398
+ Field(alias="$schema", examples=["https://example.com/GenerationLogs.json"]),
399
+ ] = None
400
+ """
401
+ A URL to the JSON Schema for this object.
402
+ """
403
+ generation_id: Annotated[StrictInt, Field(ge=1)]
404
+ hidden_team_colors: Sequence[HiddenTeamColor]
405
+ """
406
+ Teams whose logs you can't see yet. While the game runs you see only your own team's logs; once it has an outcome you see every team's.
407
+ """
408
+ players: Sequence[PlayerGenerationLogs]
409
+ """
410
+ Every player of the teams you can see, ordered by team colour and then display name, with their lines in the order they were written.
411
+ """
412
+
413
+
414
+ class GenerationState(GameModel):
415
+ model_config = ConfigDict(
416
+ extra="ignore",
417
+ )
418
+ field_schema: Annotated[
419
+ AnyUrl | None,
420
+ Field(alias="$schema", examples=["https://example.com/GenerationState.json"]),
421
+ ] = None
422
+ """
423
+ A URL to the JSON Schema for this object.
424
+ """
425
+ bot: BotChoice
426
+ """
427
+ Your bot in this game, the one you chose in the lobby, copied when the game started. For kind localhost your client relays each turn to your bot and submits its answer. For kind default the backend plays your turns itself as soon as each generation is created, so your client submits nothing.
428
+ """
429
+ channel: StrictStr
430
+ """
431
+ Your personal Centrifugo channel, which receives GenerationEvent after each turn and GameEndedEvent after the last one.
432
+ """
433
+ game_id: Annotated[StrictInt, Field(ge=1)]
434
+ generation: Generation
435
+ generation_id: Annotated[StrictInt, Field(ge=1)]
436
+ lobby_id: UUID
437
+ log_lines_stored: Annotated[StrictInt, Field(ge=0)]
438
+ """
439
+ How many game log lines you have stored for this generation, out of the 100 a player may store per generation. 0 when there are none. A client that restarts during a turn continues counting from it.
440
+ """
441
+ memory: Mapping[str, Any] | None
442
+ """
443
+ The memory sent with your latest completed turn of this game, for your bot's next BotTurn.memory. Null before your first completed turn, and after a completed turn without memory.
444
+ """
445
+ outcome: GameOutcome | None = None
446
+ """
447
+ How the game ended. Absent while the game runs. A finished game keeps its final generation and rejects every command.
448
+ """
449
+ player_id: UUID
450
+ submitted: StrictBool
451
+ """
452
+ Whether you completed this generation's turn.
453
+ """
454
+ team_color: Annotated[StrictInt, Field(ge=1)]
455
+ turn_deadline_at: AwareDatetime | None
456
+ """
457
+ When this generation's turn times out: the generation's creation time plus the lobby's turn_timeout_seconds. Null when turns have no time limit, and once the game has ended. If a player of a team hasn't completed the turn by then, the team loses and the game ends. A client waiting for other players calls POST /game/from-lobby/{lobby_id}/deadline about a second after it, because the server runs no timers.
458
+ """
459
+
460
+
461
+ class HiddenTeamColor(RootModel[StrictInt]):
462
+ root: Annotated[StrictInt, Field(ge=0)]
463
+
464
+
465
+ class ListDefaultBotsResponseBody(GameModel):
466
+ model_config = ConfigDict(
467
+ extra="ignore",
468
+ )
469
+ field_schema: Annotated[
470
+ AnyUrl | None,
471
+ Field(
472
+ alias="$schema",
473
+ examples=["https://example.com/ListDefaultBotsResponseBody.json"],
474
+ ),
475
+ ] = None
476
+ """
477
+ A URL to the JSON Schema for this object.
478
+ """
479
+ bots: Sequence[DefaultBot]
480
+
481
+
482
+ class ListMapTemplatesResponseBody(GameModel):
483
+ model_config = ConfigDict(
484
+ extra="ignore",
485
+ )
486
+ field_schema: Annotated[
487
+ AnyUrl | None,
488
+ Field(
489
+ alias="$schema",
490
+ examples=["https://example.com/ListMapTemplatesResponseBody.json"],
491
+ ),
492
+ ] = None
493
+ """
494
+ A URL to the JSON Schema for this object.
495
+ """
496
+ maps: Sequence[MapTemplateSummary]
497
+
498
+
499
+ class ListUpgradesResponseBody(GameModel):
500
+ model_config = ConfigDict(
501
+ extra="ignore",
502
+ )
503
+ field_schema: Annotated[
504
+ AnyUrl | None,
505
+ Field(
506
+ alias="$schema",
507
+ examples=["https://example.com/ListUpgradesResponseBody.json"],
508
+ ),
509
+ ] = None
510
+ """
511
+ A URL to the JSON Schema for this object.
512
+ """
513
+ upgrades: Sequence[Upgrade]
514
+
515
+
516
+ class LobbyBots(GameModel):
517
+ model_config = ConfigDict(
518
+ extra="ignore",
519
+ )
520
+ field_schema: Annotated[
521
+ AnyUrl | None,
522
+ Field(alias="$schema", examples=["https://example.com/LobbyBots.json"]),
523
+ ] = None
524
+ """
525
+ A URL to the JSON Schema for this object.
526
+ """
527
+ lobby_id: UUID
528
+ members: Sequence[LobbyMemberBot]
529
+ """
530
+ Every member of the lobby, in the lobby's member order, bot seats included.
531
+ """
532
+
533
+
534
+ class LobbyMemberBot(GameModel):
535
+ model_config = ConfigDict(
536
+ extra="ignore",
537
+ )
538
+ bot: BotChoice | None = None
539
+ """
540
+ The member's bot. Absent until they choose one, and a member can't get ready without one. A bot seat that the host added has the default bot of its level.
541
+ """
542
+ display_name: StrictStr
543
+ player_id: UUID
544
+
545
+
546
+ class LobbySettings(GameModel):
547
+ model_config = ConfigDict(
548
+ extra="ignore",
549
+ )
550
+ map: MapTemplate | None = None
551
+ """
552
+ Start on this map file. Cannot be combined with map_template_id.
553
+ """
554
+ map_template_id: Annotated[StrictInt | None, Field(ge=1)] = None
555
+ """
556
+ Start on this default map, a map_template_id from GET /map/templates. Cannot be combined with map.
557
+ """
558
+ turn_timeout_seconds: Annotated[StrictInt | None, Field(ge=5, le=600)] = 30
559
+ """
560
+ How long each turn lasts, in whole seconds from 5 to 600, counted from when its generation was created; 30 when left out. null means no limit, for example while debugging a bot. When a turn's deadline passes before every player has completed it, each team with a player who hadn't loses, and the game ends.
561
+ """
562
+
563
+
564
+ class MapTemplate(GameModel):
565
+ model_config = ConfigDict(
566
+ extra="ignore",
567
+ )
568
+ castles: Annotated[Sequence[CastleTemplate], Field(min_length=1)]
569
+ """
570
+ Each castle's position in the list is its castle ID in every game built from the map.
571
+ """
572
+ map_name: Annotated[StrictStr, Field(min_length=1)]
573
+ """
574
+ Name of the map, unique among default maps.
575
+ """
576
+ neutral_starting_soldier_amount: Annotated[StrictInt, Field(ge=0)]
577
+ """
578
+ Soldiers in every castle, owned or neutral, that sets no starting_soldier_amount.
579
+ """
580
+ plane_size_x: Annotated[StrictInt, Field(ge=1)]
581
+ """
582
+ Width of the plane, which is centred on the origin.
583
+ """
584
+ plane_size_y: Annotated[StrictInt, Field(ge=1)]
585
+ """
586
+ Height of the plane, which is centred on the origin.
587
+ """
588
+ player_amount: Annotated[StrictInt, Field(ge=1)]
589
+ """
590
+ Players the map is made for. Castle team colours run from 1 to player_amount.
591
+ """
592
+
593
+
594
+ class MapTemplateSummary(GameModel):
595
+ model_config = ConfigDict(
596
+ extra="ignore",
597
+ )
598
+ castle_count: StrictInt
599
+ """
600
+ Castles on the map, team and neutral.
601
+ """
602
+ map_name: StrictStr
603
+ map_template_id: Annotated[StrictInt, Field(ge=0)]
604
+ """
605
+ Choose the map by passing this ID as game_settings.map_template_id when creating a lobby.
606
+ """
607
+ plane_size_x: Annotated[StrictInt, Field(ge=0)]
608
+ plane_size_y: Annotated[StrictInt, Field(ge=0)]
609
+ team_count: StrictInt
610
+ """
611
+ Teams the map is made for, its player_amount. A lobby on this map has exactly this many teams, in team colour order.
612
+ """
613
+
614
+
615
+ class PlayerGenerationLogs(GameModel):
616
+ model_config = ConfigDict(
617
+ extra="ignore",
618
+ )
619
+ display_name: StrictStr
620
+ lines: Sequence[GenerationLogLine]
621
+ team_color: Annotated[StrictInt, Field(ge=1)]
622
+
623
+
624
+ class Problem(GameModel):
625
+ model_config = ConfigDict(
626
+ extra="ignore",
627
+ )
628
+ code: Literal[
629
+ "unauthenticated",
630
+ "not_found",
631
+ "not_host",
632
+ "lobby_full",
633
+ "team_full",
634
+ "phase_conflict",
635
+ "not_ready",
636
+ "empty_teams",
637
+ "stale_membership",
638
+ "idempotency_conflict",
639
+ "invalid_input",
640
+ "invalid_game_settings",
641
+ "invalid_seat_settings",
642
+ "game_requirement",
643
+ "watcher_kicked",
644
+ "watchers_full",
645
+ "unavailable",
646
+ "internal_error",
647
+ ]
648
+ detail: StrictStr
649
+ status: StrictInt
650
+ team_ids: Sequence[StrictStr] | None = None
651
+ """
652
+ The teams the error is about. For empty_teams, the teams that still need a player, in team order.
653
+ """
654
+ title: StrictStr
655
+ type: StrictStr | None = None
656
+ """
657
+ For game_requirement, the game's own problem type, a URI that the game documents, such as one meaning a player has yet to choose something in the game's API. Absent for every other code.
658
+ """
659
+
660
+
661
+ class RegisterGenerationCommands(GameModel):
662
+ model_config = ConfigDict(
663
+ extra="ignore",
664
+ )
665
+ field_schema: Annotated[
666
+ AnyUrl | None,
667
+ Field(
668
+ alias="$schema",
669
+ examples=["https://example.com/RegisterGenerationCommands.json"],
670
+ ),
671
+ ] = None
672
+ """
673
+ A URL to the JSON Schema for this object.
674
+ """
675
+ commands: Annotated[Sequence[PublicGenerationCommand], Field(max_length=1000)]
676
+ complete: StrictBool | None = None
677
+ """
678
+ Seals your turn after this batch. Defaults to true.
679
+ """
680
+ game_id: Annotated[StrictInt, Field(ge=1)]
681
+ generation_id: Annotated[StrictInt, Field(ge=1)]
682
+ logs: Annotated[Sequence[GenerationLogLine] | None, Field(max_length=100)] = None
683
+ """
684
+ Game log lines written since your previous batch for this generation, appended in order after the lines already stored. At most 100 lines per player per generation, each of at most 500 characters; a batch that would break either limit is rejected whole with 422 and problem type urn:island-battles:problem:game-log-limit.
685
+ """
686
+ memory: Mapping[str, Any] | None = None
687
+ """
688
+ Your bot's memory, the BotTurnResult.memory it returned: any JSON object of at most 64 KiB as compact JSON. Only the batch with complete true saves it, replacing your previous memory, and an absent or null memory clears it; other batches ignore it. GenerationState.memory returns it. Larger memory is rejected whole with 422 and problem type urn:island-battles:problem:bot-memory-too-large.
689
+ """
690
+ request_id: UUID
691
+ """
692
+ Identifies this batch. Retry a lost request with the same UUID and body; use a new UUID for every new batch.
693
+ """
694
+
695
+
696
+ class SendSoldierGroupCommand(GameModel):
697
+ model_config = ConfigDict(
698
+ extra="ignore",
699
+ )
700
+ command_type: Literal["send_soldier_group"]
701
+ parameters: SendSoldierGroupParameters
702
+
703
+
704
+ class SendSoldierGroupParameters(GameModel):
705
+ model_config = ConfigDict(
706
+ extra="ignore",
707
+ )
708
+ destination_castle_id: Annotated[StrictInt, Field(ge=0)]
709
+ """
710
+ Any other castle.
711
+ """
712
+ origin_castle_id: Annotated[StrictInt, Field(ge=0)]
713
+ """
714
+ Castle your team owns.
715
+ """
716
+ soldier_amount: Annotated[StrictInt, Field(ge=1)]
717
+ """
718
+ Soldiers to send; counts against soldiers already reserved by your team this turn.
719
+ """
720
+
721
+
722
+ class SoldierGroup(SoldierGroupBase):
723
+ model_config = ConfigDict(
724
+ extra="ignore",
725
+ )
726
+ clash_radius: Annotated[StrictFloat, Field(gt=0.0)]
727
+ """
728
+ Enemies clash when their centers are within the larger of their radii.
729
+ """
730
+ destination_castle_id: Annotated[StrictInt, Field(ge=0)]
731
+ id: Annotated[StrictInt, Field(ge=0)]
732
+ """
733
+ Soldier group ID, never reassigned within a game.
734
+ """
735
+ origin_castle_id: Annotated[StrictInt, Field(ge=0)]
736
+ soldiers: Annotated[StrictInt, Field(ge=0)]
737
+ team_color: Annotated[StrictInt, Field(ge=0)]
738
+ """
739
+ Owning team; 0 is neutral.
740
+ """
741
+ upgrades: Mapping[UpgradeType, StrictInt]
742
+ """
743
+ Every upgrade type's level, copied from the origin castle when the group left.
744
+ """
745
+ x: StrictFloat
746
+ y: StrictFloat
747
+
748
+
749
+ class Upgrade(GameModel):
750
+ model_config = ConfigDict(
751
+ extra="ignore",
752
+ )
753
+ description: StrictStr
754
+ """
755
+ What the levels' values measure.
756
+ """
757
+ levels: Sequence[UpgradeLevel]
758
+ """
759
+ Every level from 1 to max_level, in order.
760
+ """
761
+ max_level: Annotated[StrictInt, Field(ge=1)]
762
+ """
763
+ The highest level. Every castle starts at level 1.
764
+ """
765
+ type: UpgradeType
766
+
767
+
768
+ class UpgradeCastleCommand(GameModel):
769
+ model_config = ConfigDict(
770
+ extra="ignore",
771
+ )
772
+ command_type: Literal["upgrade_castle"]
773
+ parameters: UpgradeCastleParameters
774
+
775
+
776
+ class PublicGenerationCommand(
777
+ RootModel[SendSoldierGroupCommand | UpgradeCastleCommand]
778
+ ):
779
+ root: Annotated[
780
+ SendSoldierGroupCommand | UpgradeCastleCommand,
781
+ Field(discriminator="command_type"),
782
+ ]
783
+
784
+
785
+ class UpgradeCastleParameters(GameModel):
786
+ model_config = ConfigDict(
787
+ extra="ignore",
788
+ )
789
+ castle_id: Annotated[StrictInt, Field(ge=0)]
790
+ """
791
+ Castle your team owns. It pays the level's soldier_cost from GET /game/upgrades.
792
+ """
793
+ upgrade_type: UpgradeType
794
+ """
795
+ The type to raise by one level. Several upgrades of a castle in one turn each buy the next level.
796
+ """
797
+
798
+
799
+ class UpgradeLevel(GameModel):
800
+ model_config = ConfigDict(
801
+ extra="ignore",
802
+ )
803
+ level: Annotated[StrictInt, Field(ge=1)]
804
+ soldier_cost: Annotated[StrictInt, Field(ge=0)]
805
+ """
806
+ Soldiers the castle pays to reach this level from the level below. Level 1 is free.
807
+ """
808
+ value: StrictFloat
809
+ """
810
+ The level's effect, in the unit its type's description names.
811
+ """
812
+
813
+
814
+ class UpgradeType(StrEnum):
815
+ clash_stop_generations = "clash_stop_generations"
816
+ speed = "speed"
817
+
818
+
819
+ class WatchGameEndedEvent(GameModel):
820
+ model_config = ConfigDict(
821
+ extra="ignore",
822
+ )
823
+ schema_version: Literal[1]
824
+ state: WatchState
825
+ """
826
+ The final generation, with its outcome.
827
+ """
828
+ type: Literal["game.ended"]
829
+
830
+
831
+ class WatchGenerationEvent(GameModel):
832
+ model_config = ConfigDict(
833
+ extra="ignore",
834
+ )
835
+ schema_version: Literal[1]
836
+ state: WatchState
837
+ type: Literal["game.next_generation"]
838
+
839
+
840
+ class WatchState(GameModel):
841
+ model_config = ConfigDict(
842
+ extra="ignore",
843
+ )
844
+ field_schema: Annotated[
845
+ AnyUrl | None,
846
+ Field(alias="$schema", examples=["https://example.com/WatchState.json"]),
847
+ ] = None
848
+ """
849
+ A URL to the JSON Schema for this object.
850
+ """
851
+ channel: StrictStr
852
+ """
853
+ The lobby's watch channel, watch:island-battles:<lobby_id>, which receives WatchGenerationEvent after each turn and WatchGameEndedEvent after the last one.
854
+ """
855
+ game_id: Annotated[StrictInt, Field(ge=1)]
856
+ generation: Generation
857
+ generation_id: Annotated[StrictInt, Field(ge=1)]
858
+ lobby_id: UUID
859
+ outcome: GameOutcome | None = None
860
+ """
861
+ How the game ended. Absent while the game runs.
862
+ """
863
+ teams: Sequence[GameTeam]
864
+ """
865
+ The teams that play, with their lobby names and the display names their players had at the start.
866
+ """
867
+ turn_deadline_at: AwareDatetime | None
868
+ """
869
+ When this generation's turn times out, as in GenerationState. Null when turns have no time limit, and once the game has ended. Watchers never apply a deadline themselves.
870
+ """