island-battles-python 0.1.0__tar.gz → 0.2.0__tar.gz

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.
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: island-battles-python
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Async player client for Island Battles generation turns
5
+ License-Expression: MIT
5
6
  Requires-Dist: centrifuge-python==0.6.0
6
7
  Requires-Dist: httpx>=0.27,<1
7
8
  Requires-Dist: pydantic>=2.12,<3
@@ -434,6 +434,10 @@ class GenerationState(GameModel):
434
434
  generation: Generation
435
435
  generation_id: Annotated[StrictInt, Field(ge=1)]
436
436
  lobby_id: UUID
437
+ lobby_round: Annotated[StrictInt, Field(ge=1)]
438
+ """
439
+ The lobby round that the game plays. A lobby plays one game per round, and the /game/from-lobby/{lobby_id} routes serve its newest game: compare this with the lobby snapshot's lobby.round to tell whether the game is the one the lobby started last.
440
+ """
437
441
  log_lines_stored: Annotated[StrictInt, Field(ge=0)]
438
442
  """
439
443
  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.
@@ -585,9 +589,9 @@ class MapTemplate(GameModel):
585
589
  """
586
590
  Height of the plane, which is centred on the origin.
587
591
  """
588
- player_amount: Annotated[StrictInt, Field(ge=1)]
592
+ player_amount: Annotated[StrictInt, Field(ge=2, le=16)]
589
593
  """
590
- Players the map is made for. Castle team colours run from 1 to player_amount.
594
+ Teams the map is made for, from 2 to 16, one player each. Castle team colours run from 1 to player_amount, and every one of them owns at least one castle.
591
595
  """
592
596
 
593
597
 
@@ -640,6 +644,7 @@ class Problem(GameModel):
640
644
  "invalid_game_settings",
641
645
  "invalid_seat_settings",
642
646
  "game_requirement",
647
+ "game_running",
643
648
  "watcher_kicked",
644
649
  "watchers_full",
645
650
  "unavailable",
@@ -856,6 +861,10 @@ class WatchState(GameModel):
856
861
  generation: Generation
857
862
  generation_id: Annotated[StrictInt, Field(ge=1)]
858
863
  lobby_id: UUID
864
+ lobby_round: Annotated[StrictInt, Field(ge=1)]
865
+ """
866
+ The lobby round that the game plays. A lobby plays one game per round, and the /game/from-lobby/{lobby_id} routes serve its newest game: compare this with the lobby snapshot's lobby.round to tell whether the game is the one the lobby started last.
867
+ """
859
868
  outcome: GameOutcome | None = None
860
869
  """
861
870
  How the game ended. Absent while the game runs.
@@ -28,7 +28,7 @@ from typing import Any
28
28
  from pydantic import ValidationError
29
29
 
30
30
  from ._generated import BotTurn, GameOutcome, Generation
31
- from .bot import MEMORY_LIMIT_BYTES, Play, call_play, run_turn
31
+ from .bot import MEMORY_LIMIT_BYTES, Play, run_turn
32
32
  from .client import IslandBattlesClient
33
33
  from .errors import BotMemoryTooLargeError, GameError, InvalidBotResultError
34
34
  from .fixture import fixture_turn, fixture_turn_data
@@ -48,7 +48,9 @@ DEFAULT_ORIGINS = (
48
48
  "http://tauri.localhost",
49
49
  )
50
50
  CHECK_SECONDS = 2.0
51
- # The lobby's shortest turn timeout is 10 s; answer before the game moves on.
51
+ # The lobby's default turn timeout is 30 s and its shortest is 5 s. Answer before
52
+ # the lobby's timeout: 8 s suits the default, and a shorter one needs a smaller
53
+ # --turn-timeout.
52
54
  DEFAULT_TURN_TIMEOUT = 8.0
53
55
  # A BotTurn of a busy 6-team generation with 64 KiB of memory is a few hundred
54
56
  # KiB; 2 MiB leaves headroom.
@@ -416,9 +418,15 @@ def check(args: argparse.Namespace) -> int:
416
418
  play = load_play(args.bot)
417
419
  except Exception: # noqa: BLE001
418
420
  return fail(f"could not load {args.bot}:\n{traceback.format_exc()}")
421
+ # The same log scope that serve gives a turn, so the lines counted are the
422
+ # ones the game log would store: logged lines and the result's logs.
423
+ client_logging = ClientLogging(object(), logging.INFO, False, None)
424
+ client_logging.attach()
419
425
  started = time.monotonic()
420
426
  try:
421
- result = run_with_timeout(lambda: call_play(play, turn), CHECK_SECONDS)
427
+ result = run_with_timeout(
428
+ lambda: run_turn(play, turn, client_logging), CHECK_SECONDS
429
+ )
422
430
  except TimeoutError:
423
431
  # The bot's thread can't be stopped, and a daemon thread would still
424
432
  # be joined by a normal exit path in some cases; leave at once.
@@ -433,6 +441,8 @@ def check(args: argparse.Namespace) -> int:
433
441
  return fail(f"the bot returned an invalid result: {error.detail}")
434
442
  except Exception: # noqa: BLE001
435
443
  return fail(f"the bot raised an exception:\n{traceback.format_exc()}")
444
+ finally:
445
+ client_logging.detach()
436
446
  elapsed = time.monotonic() - started
437
447
  memory_size = len(
438
448
  json.dumps(result.memory, separators=(",", ":"), ensure_ascii=False).encode(
@@ -502,7 +512,9 @@ def build_parser() -> argparse.ArgumentParser:
502
512
  default=DEFAULT_TURN_TIMEOUT,
503
513
  metavar="SECONDS",
504
514
  help="answer 504 when a turn takes longer than this (default "
505
- f"{DEFAULT_TURN_TIMEOUT:g}, under the lobby's shortest turn timeout of 10)",
515
+ f"{DEFAULT_TURN_TIMEOUT:g}). A lobby's turn timeout is 30 s by default, "
516
+ "and its host can set it from 5 to 600 s or to none; this must be below "
517
+ "the lobby's, so for a lobby with a shorter timeout pass a smaller value",
506
518
  )
507
519
  serving.set_defaults(handler=serve)
508
520
 
@@ -1,7 +1,8 @@
1
1
  [project]
2
2
  name = "island-battles-python"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "Async player client for Island Battles generation turns"
5
+ license = "MIT"
5
6
  requires-python = ">=3.14"
6
7
  dependencies = [
7
8
  "centrifuge-python==0.6.0",
@@ -1,7 +1,8 @@
1
1
  [project]
2
2
  name = "island-battles-python"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "Async player client for Island Battles generation turns"
5
+ license = "MIT"
5
6
  requires-python = ">=3.14"
6
7
  dependencies = [
7
8
  "centrifuge-python==0.6.0",