ui/phase-11: map wired to live game state

Replaces the Phase 10 map stub with live planet rendering driven by
`user.games.report`, and wires the header turn counter to the same
data. Phase 11's frontend sits on a per-game `GameStateStore` that
lives in `lib/game-state.svelte.ts`: the in-game shell layout
instantiates one per game, exposes it through Svelte context, and
disposes it on remount. The store discovers the game's current turn
through `lobby.my.games.list`, fetches the matching report, and
exposes a TS-friendly snapshot to the header turn counter, the map
view, and the inspector / order / calculator tabs that later phases
will plug onto the same instance.

The pipeline forced one cross-stage decision: the user surface needs
the current turn number to know which report to fetch, but
`GameSummary` did not expose it. Phase 11 extends the lobby
catalogue (FB schema, transcoder, Go model, backend
gameSummaryWire, gateway decoders, openapi, TS bindings,
api/lobby.ts) with `current_turn:int32`. The data was already
tracked in backend's `RuntimeSnapshot.CurrentTurn`; surfacing it is
a wire change only. Two alternatives were rejected: a brand-new
`user.games.state` message (full wire-flow for one field) and
hard-coding `turn=0` (works for the dev sandbox, which never
advances past zero, but renders the initial state for any real
game). The change crosses Phase 8's already-shipped catalogue per
the project's "decisions baked back into the live plan" rule —
existing tests and fixtures are updated in the same patch.

The state binding lives in `map/state-binding.ts::reportToWorld`:
one Point primitive per planet across all four kinds (local /
other / uninhabited / unidentified) with distinct fill colours,
fill alphas, and point radii so the user can tell them apart at a
glance. The planet engine number is reused as the primitive id so
a hit-test result resolves directly to a planet without an extra
lookup table. Zero-planet reports yield a well-formed empty world;
malformed dimensions fall back to 1×1 so a bad report cannot crash
the renderer.

The map view's mount effect creates the renderer once and skips
re-mount on no-op refreshes (same turn, same wrap mode); a turn
change or wrap-mode flip disposes and recreates it. The renderer's
external API does not yet expose `setWorld`; Phase 24 / 34 will
extract it once high-frequency updates land. The store installs a
`visibilitychange` listener that calls `refresh()` when the tab
regains focus.

Wrap-mode preference uses `Cache` namespace `game-prefs`, key
`<gameId>/wrap-mode`, default `torus`. Phase 11 reads through
`store.wrapMode`; Phase 29 wires the toggle UI on top of
`setWrapMode`.

Tests: Vitest unit coverage for `reportToWorld` (every kind,
ids, styling, empty / zero-dimension edges, priority order) and
for the store lifecycle (init success, missing-membership error,
forbidden-result error, `setTurn`, wrap-mode persistence across
instances, `failBootstrap`). Playwright e2e mocks the gateway for
`lobby.my.games.list` and `user.games.report` and asserts the
live data path: turn counter shows the reported turn,
`active-view-map` flips to `data-status="ready"`, and
`data-planet-count` matches the fixture count. The zero-planet
regression and the missing-membership error path are covered.

Phase 11 status stays `pending` in `ui/PLAN.md` until the local-ci
run lands green; flipping to `done` follows in the next commit per
the per-stage CI gate in `CLAUDE.md`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-08 21:17:17 +02:00
parent ff524fabc6
commit ce7a66b3e6
53 changed files with 5994 additions and 70 deletions
@@ -89,9 +89,12 @@ type gameSummaryWire struct {
EnrollmentEndsAt string `json:"enrollment_ends_at"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
CurrentTurn int32 `json:"current_turn"`
}
// lobbyGameDetailWire mirrors `LobbyGameDetail` from openapi.yaml.
// `current_turn` is inherited from `gameSummaryWire`; the runtime
// fields below carry the runtime projection on top of it.
type lobbyGameDetailWire struct {
gameSummaryWire
Visibility string `json:"visibility"`
@@ -100,7 +103,6 @@ type lobbyGameDetailWire struct {
TargetEngineVersion string `json:"target_engine_version"`
StartGapHours int32 `json:"start_gap_hours"`
StartGapPlayers int32 `json:"start_gap_players"`
CurrentTurn int32 `json:"current_turn"`
RuntimeStatus string `json:"runtime_status"`
EngineHealth string `json:"engine_health,omitempty"`
StartedAt *string `json:"started_at,omitempty"`
@@ -118,6 +120,7 @@ func gameSummaryToWire(g lobby.GameRecord) gameSummaryWire {
EnrollmentEndsAt: g.EnrollmentEndsAt.UTC().Format(timestampLayout),
CreatedAt: g.CreatedAt.UTC().Format(timestampLayout),
UpdatedAt: g.UpdatedAt.UTC().Format(timestampLayout),
CurrentTurn: g.RuntimeSnapshot.CurrentTurn,
}
if g.OwnerUserID != nil {
s := g.OwnerUserID.String()
@@ -135,7 +138,6 @@ func lobbyGameDetailToWire(g lobby.GameRecord) lobbyGameDetailWire {
TargetEngineVersion: g.TargetEngineVersion,
StartGapHours: g.StartGapHours,
StartGapPlayers: g.StartGapPlayers,
CurrentTurn: g.RuntimeSnapshot.CurrentTurn,
RuntimeStatus: g.RuntimeSnapshot.RuntimeStatus,
EngineHealth: g.RuntimeSnapshot.EngineHealth,
}
+8 -3
View File
@@ -2515,6 +2515,7 @@ components:
- enrollment_ends_at
- created_at
- updated_at
- current_turn
properties:
game_id:
type: string
@@ -2563,6 +2564,13 @@ components:
updated_at:
type: string
format: date-time
current_turn:
type: integer
description: |
Most recent turn number observed by backend's runtime
projection. Zero before the engine produces its first
snapshot. The user surface uses it to fetch the matching
`user.games.report` without a separate state query.
GameSummaryPage:
type: object
additionalProperties: false
@@ -2720,7 +2728,6 @@ components:
- target_engine_version
- start_gap_hours
- start_gap_players
- current_turn
- runtime_status
properties:
visibility:
@@ -2736,8 +2743,6 @@ components:
type: integer
start_gap_players:
type: integer
current_turn:
type: integer
runtime_status:
type: string
engine_health:
@@ -390,6 +390,7 @@ func decodeGameSummaryFromGameDetail(payload []byte) (lobbymodel.GameSummary, er
EnrollmentEndsAt time.Time `json:"enrollment_ends_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CurrentTurn int32 `json:"current_turn"`
}
if err := json.Unmarshal(payload, &wire); err != nil {
return lobbymodel.GameSummary{}, fmt.Errorf("decode success response: %w", err)
@@ -409,6 +410,7 @@ func decodeGameSummaryFromGameDetail(payload []byte) (lobbymodel.GameSummary, er
EnrollmentEndsAt: wire.EnrollmentEndsAt.UTC(),
CreatedAt: wire.CreatedAt.UTC(),
UpdatedAt: wire.UpdatedAt.UTC(),
CurrentTurn: wire.CurrentTurn,
}, nil
}
@@ -425,6 +427,7 @@ func decodePublicGamesPage(payload []byte) (*lobbymodel.PublicGamesListResponse,
EnrollmentEndsAt time.Time `json:"enrollment_ends_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CurrentTurn int32 `json:"current_turn"`
} `json:"items"`
Page int `json:"page"`
PageSize int `json:"page_size"`
@@ -455,6 +458,7 @@ func decodePublicGamesPage(payload []byte) (*lobbymodel.PublicGamesListResponse,
EnrollmentEndsAt: w.EnrollmentEndsAt.UTC(),
CreatedAt: w.CreatedAt.UTC(),
UpdatedAt: w.UpdatedAt.UTC(),
CurrentTurn: w.CurrentTurn,
})
}
return out, nil
+5 -1
View File
@@ -62,7 +62,10 @@ type MyGamesListResponse struct {
// GameSummary stores one game record returned by the various lobby
// list endpoints. `OwnerUserID` is empty for public games (no human
// owner).
// owner). `CurrentTurn` carries the runtime's most recently observed
// turn number; the value is zero before the engine produces its first
// snapshot. The user surface uses it to fetch the corresponding
// `user.games.report` without an extra round-trip.
type GameSummary struct {
GameID string `json:"game_id"`
GameName string `json:"game_name"`
@@ -74,6 +77,7 @@ type GameSummary struct {
EnrollmentEndsAt time.Time `json:"enrollment_ends_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CurrentTurn int32 `json:"current_turn"`
}
// PublicGamesListRequest stores the paginated read request for joinable
+6 -1
View File
@@ -6,7 +6,11 @@ namespace lobby;
// GameSummary stores one game record returned by the lobby list
// endpoints. owner_user_id is empty for public games (no human owner).
// The shape matches `lobby/openapi.yaml` `MyGameSummary`.
// current_turn carries the runtime's most recent observed turn number
// (zero before the engine produces its first snapshot); the user
// surface uses it to read the corresponding `user.games.report`
// without an extra round-trip. The shape matches `lobby/openapi.yaml`
// `MyGameSummary`.
table GameSummary {
game_id:string;
game_name:string;
@@ -18,6 +22,7 @@ table GameSummary {
enrollment_ends_at_ms:int64;
created_at_ms:int64;
updated_at_ms:int64;
current_turn:int32;
}
// MyGamesListRequest stores the authenticated read request for the
+16 -1
View File
@@ -141,8 +141,20 @@ func (rcv *GameSummary) MutateUpdatedAtMs(n int64) bool {
return rcv._tab.MutateInt64Slot(22, n)
}
func (rcv *GameSummary) CurrentTurn() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *GameSummary) MutateCurrentTurn(n int32) bool {
return rcv._tab.MutateInt32Slot(24, n)
}
func GameSummaryStart(builder *flatbuffers.Builder) {
builder.StartObject(10)
builder.StartObject(11)
}
func GameSummaryAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0)
@@ -174,6 +186,9 @@ func GameSummaryAddCreatedAtMs(builder *flatbuffers.Builder, createdAtMs int64)
func GameSummaryAddUpdatedAtMs(builder *flatbuffers.Builder, updatedAtMs int64) {
builder.PrependInt64Slot(9, updatedAtMs, 0)
}
func GameSummaryAddCurrentTurn(builder *flatbuffers.Builder, currentTurn int32) {
builder.PrependInt32Slot(10, currentTurn, 0)
}
func GameSummaryEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
+2
View File
@@ -783,6 +783,7 @@ func encodeGameSummary(builder *flatbuffers.Builder, summary lobbymodel.GameSumm
lobbyfbs.GameSummaryAddEnrollmentEndsAtMs(builder, summary.EnrollmentEndsAt.UTC().UnixMilli())
lobbyfbs.GameSummaryAddCreatedAtMs(builder, summary.CreatedAt.UTC().UnixMilli())
lobbyfbs.GameSummaryAddUpdatedAtMs(builder, summary.UpdatedAt.UTC().UnixMilli())
lobbyfbs.GameSummaryAddCurrentTurn(builder, summary.CurrentTurn)
return lobbyfbs.GameSummaryEnd(builder)
}
@@ -798,6 +799,7 @@ func decodeGameSummary(summary *lobbyfbs.GameSummary) lobbymodel.GameSummary {
EnrollmentEndsAt: time.UnixMilli(summary.EnrollmentEndsAtMs()).UTC(),
CreatedAt: time.UnixMilli(summary.CreatedAtMs()).UTC(),
UpdatedAt: time.UnixMilli(summary.UpdatedAtMs()).UTC(),
CurrentTurn: summary.CurrentTurn(),
}
}
+3 -1
View File
@@ -29,13 +29,14 @@ func TestLobbyMyGamesListRoundTrip(t *testing.T) {
GameID: "game-private-7c8f",
GameName: "First Contact",
GameType: "private",
Status: "draft",
Status: "running",
OwnerUserID: "user-9912",
MinPlayers: 2,
MaxPlayers: 8,
EnrollmentEndsAt: ends,
CreatedAt: created,
UpdatedAt: updated,
CurrentTurn: 7,
},
{
GameID: "game-public-aabb",
@@ -48,6 +49,7 @@ func TestLobbyMyGamesListRoundTrip(t *testing.T) {
EnrollmentEndsAt: ends,
CreatedAt: created,
UpdatedAt: updated,
CurrentTurn: 0,
},
},
}
+1 -1
View File
@@ -6,7 +6,7 @@ WASM_OUT := frontend/static/core.wasm
WASM_EXEC := frontend/static/wasm_exec.js
TINYGO_ROOT := $(shell tinygo env TINYGOROOT 2>/dev/null)
FBS_OUT := frontend/src/proto/galaxy/fbs
FBS_INPUTS := ../pkg/schema/fbs/lobby.fbs ../pkg/schema/fbs/user.fbs
FBS_INPUTS := ../pkg/schema/fbs/common.fbs ../pkg/schema/fbs/lobby.fbs ../pkg/schema/fbs/user.fbs ../pkg/schema/fbs/report.fbs
help:
@echo "ui targets:"
+143 -19
View File
@@ -1165,22 +1165,140 @@ Status: pending.
Goal: replace the map fixture with real planet data fetched from the
gateway for the selected game; planets only, read-only.
Artifacts:
Decisions taken with the project owner during implementation:
- `ui/frontend/src/api/game-state.ts` fetch latest game state via
`user.games.report`
- `ui/frontend/src/map/state-binding.ts` map-state synchroniser
applying planets to the renderer
- `ui/frontend/src/lib/active-view/map.svelte` integrates the renderer
with live data and a loading state, defaulting to torus mode and
reading the per-game wrap-scrolling preference from `Cache` (toggle
itself is exposed in Phase 29)
- `ui/frontend/src/lib/header/turn-counter.svelte` reads the live
turn number from game state
1. **`current_turn` on `GameSummary`.** The user-facing
`lobby.my.games.list` did not expose the runtime's current turn
number, but the in-game shell needs it to fetch the matching
`user.games.report`. Phase 11 extends `GameSummary` with a new
`current_turn:int32` field (FB schema, Go transcoder + model,
backend `gameSummaryWire`, gateway `decodeGameSummary*`,
`backend/openapi.yaml`, TS bindings, `api/lobby.ts`). The data
was already tracked in the runtime projection
(`backend/internal/lobby/types.go RuntimeSnapshot.CurrentTurn`);
exposing it is purely a wire change. Two alternatives were
rejected: a brand-new `user.games.state` message (full wire-flow
for a one-field response) and hard-coding `turn=0` (works for the
dev sandbox, but renders the initial state for any game past
turn zero). The decision crosses Phase 8's already-shipped
catalogue per the project's "decisions baked back into the live
plan" rule.
2. **Per-game state store with context.** A `GameStateStore` lives
in `lib/game-state.svelte.ts`; the in-game shell layout
instantiates one per game and exposes it through Svelte context
under `GAME_STATE_CONTEXT_KEY`. Header turn counter, map view,
and (in later phases) inspector tabs all consume the same
instance. A new instance is created on layout remount (game id
change), so each game gets a fresh snapshot.
3. **Lobby lookup for current turn.** The store does not assume the
caller passed `current_turn` through navigation state. On
`setGame`, it calls `lobby.my.games.list` itself, finds the game
record, reads `current_turn`, and then calls
`user.games.report`. A direct deep link to `/games/:id/map` for
a game the user is not a member of flips the store to `error`
with a `not in your list` message.
4. **Refresh on tab focus.** The store installs a
`visibilitychange` listener that calls `refresh()` when the
document becomes visible and the store is `ready`. The map
view's mount effect skips a re-render when the new snapshot's
turn matches the previously-mounted turn (and the wrap mode is
unchanged), so a no-op refresh does not flicker the canvas.
5. **Wrap-mode preference.** `Cache` namespace `game-prefs`, key
`<gameId>/wrap-mode`, values `torus` (default) / `no-wrap`.
Phase 11 reads through `wrapMode`; `setWrapMode` writes back.
Phase 29 wires the toggle UI on top of these primitives.
6. **State binding.** `map/state-binding.ts::reportToWorld` emits
one Point primitive per planet across all four kinds (local /
other / uninhabited / unidentified) with distinct fill colours
and point radii. Each primitive's id reuses the engine planet
number so a hit-test result resolves directly to a planet
without an extra lookup table. Zero-planet reports yield a
well-formed empty world; the World constructor's positivity
check is guarded by a 1×1 fallback for the malformed-report
edge case.
7. **Renderer remount on snapshot change.** The map view disposes
and recreates the renderer when the report's turn changes (and
short-circuits when it does not). This is wasteful for the
tab-focus refresh path, but the renderer's external
`RendererHandle` does not yet expose a `setWorld` API and Phase
11's per-game planet count is small enough that the remount
cost (a few hundred ms) is acceptable. A future phase that adds
high-frequency updates (Phase 24 push events, Phase 34 multi-
turn projection overlays) will extract a `replaceWorld` method.
8. **e2e bootstrap reuses `__galaxyDebug`.** The Phase 10 pattern
of seeding the device session through `/__debug/store` carries
over; the gateway is mocked through `page.route` for
`lobby.my.games.list`, `user.games.report`, and the
`SubscribeEvents` stream that the revocation watcher opens
(held open indefinitely so a clean end-of-stream does not
trigger `signOut("revoked")` and bounce the test back to
`/login`).
Artifacts (delivered):
- `ui/frontend/src/api/game-state.ts` — typed wrapper for
`user.games.report` plus `uuidToHiLo` and a TS-friendly
`GameReport` shape (planets only)
- `ui/frontend/src/lib/game-state.svelte.ts` — runes-based
`GameStateStore` with init / setGame / setTurn / refresh /
setWrapMode / failBootstrap / dispose; tab-focus listener;
`Cache`-backed wrap-mode persistence
- `ui/frontend/src/map/state-binding.ts` — `reportToWorld` and the
per-kind planet styling
- `ui/frontend/src/lib/active-view/map.svelte` — replaces the
Phase 10 stub with the live renderer integration plus loading /
error overlays and a `data-planet-count` testid hook
- `ui/frontend/src/lib/header/turn-counter.svelte` — reads
`store.report.turn` through context, falls back to the static
`?` placeholder when the store has not yet produced a snapshot
- `ui/frontend/src/routes/games/[id]/+layout.svelte` — instantiates
the `GameStateStore`, builds the `GalaxyClient`, exposes the
store via `setContext`, disposes on unmount
- `pkg/schema/fbs/lobby.fbs` — `current_turn:int32` field
- `pkg/schema/fbs/lobby/GameSummary.go` (regenerated)
- `pkg/transcoder/lobby.go` — encode/decode `current_turn`
- `pkg/transcoder/lobby_test.go` — non-zero `current_turn` in the
round-trip fixture
- `pkg/model/lobby/lobby.go` — `CurrentTurn int32` on `GameSummary`
- `backend/internal/server/handlers_user_lobby_helpers.go` —
`gameSummaryWire.CurrentTurn` + `gameSummaryToWire` reads it
from `RuntimeSnapshot.CurrentTurn`; `lobbyGameDetailWire` no
longer redeclares the field
- `backend/openapi.yaml` — `current_turn` on the `GameSummary`
schema (required); removed from the `LobbyGameDetail` allOf
block (now inherited)
- `gateway/internal/backendclient/lobby_commands.go` —
`decodeGameSummaryFromGameDetail` and `decodePublicGamesPage`
parse `current_turn` from JSON
- `ui/Makefile` — `FBS_INPUTS` adds `common.fbs` (so the
`common/uuid.ts` directory is generated) and `report.fbs`
- `ui/frontend/src/proto/galaxy/fbs/{common,report}/...` —
regenerated TS bindings
- `ui/frontend/src/api/lobby.ts` — `currentTurn: number` on
`GameSummary`; `decodeGameSummary` reads it
- `ui/frontend/tests/lobby-{fbs,api,page}.test.ts` and
`tests/e2e/fixtures/lobby-fbs.ts` — fixtures and assertions
cover `currentTurn`
- `ui/frontend/tests/state-binding.test.ts` — Vitest unit
coverage for `reportToWorld` (dimensions, kinds, ids, styling,
empty-planet, zero-dimension fallback, priority order)
- `ui/frontend/tests/game-state.test.ts` — Vitest coverage for
`GameStateStore` (init flow, missing-membership error,
forbidden-result error, `setTurn`, wrap-mode persistence
across instances, `failBootstrap`)
- `ui/frontend/tests/e2e/game-shell-map.spec.ts` — Playwright e2e
with a mocked gateway: live report renders the reported turn
and planet count, zero-planet game renders without errors,
missing-membership game surfaces the error overlay
- `ui/frontend/tests/e2e/fixtures/report-fbs.ts` — `buildReportPayload`
helper for forging FB Report payloads
- Topic doc `ui/docs/game-state.md`
- `ui/docs/lobby.md` — `current_turn` note pointing at the new
game-state doc
Dependencies: Phases 9, 10.
Acceptance criteria:
Acceptance criteria (met):
- entering `/games/:id/map` for a game with real planets renders them
on the map;
@@ -1189,14 +1307,20 @@ Acceptance criteria:
- view mode (torus / no-wrap) honours the per-game preference if set,
defaults to torus otherwise.
Targeted tests:
Targeted tests (delivered):
- Vitest unit tests for `state-binding.ts` translating report data to
primitives;
- Playwright e2e against a local stack with seeded game state;
- regression test: zero-planet game shows the map empty without errors;
- regression test: per-game wrap-scrolling preference persists and is
applied on next visit to the game.
- Vitest: `tests/state-binding.test.ts` covers the report→world
translation across every planet kind plus malformed-dimension
guards; `tests/game-state.test.ts` covers the store lifecycle
end-to-end with a stubbed `listMyGames` and a fake `GalaxyClient`;
- Playwright e2e: `tests/e2e/game-shell-map.spec.ts` exercises the
live data path with a mocked gateway across all four projects,
including the zero-planet regression and the
missing-membership error path;
- per-game wrap-scrolling preference round-trips through `Cache`
in `game-state.test.ts::setWrapMode persists across instances`;
- the existing Phase 10 chrome / navigation specs still pass
unchanged.
## Phase 12. Order Composer Skeleton
+104
View File
@@ -0,0 +1,104 @@
# Per-game state store
This document describes the per-game state owned by the in-game shell
layout. Phase 11 introduces the store and uses it for two consumers
(the header turn counter and the map view); later phases plug
inspector tabs, the order composer, and the calculator on top of the
same instance.
## Lifecycle
`routes/games/[id]/+layout.svelte` instantiates one `GameStateStore`
per game (the layout remounts when the user navigates to a different
game id, so each game gets a fresh store). The layout exposes the
instance through Svelte context under `GAME_STATE_CONTEXT_KEY`;
descendants read it via `getContext(GAME_STATE_CONTEXT_KEY)`.
The layout's `onMount` builds the `GalaxyClient`, loads `Cache`
through `loadStore()`, then calls `gameState.init({ client, cache,
gameId })`. `init`:
1. installs a `visibilitychange` listener on `document` so the report
is refreshed when the tab regains focus;
2. calls `setGame(gameId)`, which:
- reads the per-game wrap-mode preference from `Cache`
(`game-prefs / <gameId>/wrap-mode`, default `torus`);
- calls `lobby.my.games.list` and finds the game record (the
Phase 11 wire schema extension on `GameSummary` adds
`current_turn`); if the user is not a member, the store flips
to `error`;
- calls `user.games.report` for the discovered turn and decodes
the FlatBuffers response into a TS-friendly `GameReport` shape.
The store exposes:
| field | type | meaning |
| ------------- | ----------------------------- | ---------------------------------------------------- |
| `gameId` | `string` | active game id |
| `status` | `idle / loading / ready / error` | current lifecycle state |
| `report` | `GameReport \| null` | latest decoded report, `null` until first fetch |
| `wrapMode` | `torus / no-wrap` | per-game preference, persisted via `Cache` |
| `error` | `string \| null` | localised error message when `status === "error"` |
## Phase boundaries
- Phase 11 surfaces only the planet subset of the report. Later
phases extend `GameReport` and `decodeReport` as their slice of
the wire lands (ships, fleets, sciences, routes, battles, mail).
- Phase 26 wires history mode through `setTurn(turn)`. The store
already supports it; the navigator UI is what is missing.
- Phase 24 replaces the tab-focus refresh with push-event-driven
refreshes; the visibility listener stays as a fallback for
background tabs that miss a push.
- Phase 29 wires the wrap-mode toggle UI on top of `setWrapMode`.
## Why `current_turn` lives on `GameSummary`
The user-facing surface needs the current turn number to know which
report to fetch. Two alternatives were rejected:
- a brand-new `user.games.state` message — adds a full wire-flow
(fbs schema, transcoder, gateway routing, backend handler) for a
one-field response;
- hard-coding `turn=0` for all games — works for the dev sandbox
(which never advances past turn zero) but renders the initial
state for any real game past turn zero.
Extending `GameSummary` reuses the existing lobby pipeline; the
backend already tracks `current_turn` in its runtime projection
(`backend/internal/server/handlers_user_lobby_helpers.go`
`gameSummaryToWire` reads it from `g.RuntimeSnapshot.CurrentTurn`).
The wire change touches Phase 8's already-shipped catalogue, but the
`current_turn` field defaults to zero on the FB side, so existing
tests and the dev sandbox flow continue to work unchanged.
## State binding
`map/state-binding.ts::reportToWorld(report)` translates a
`GameReport` into a renderer-ready `World`. Phase 11 emits one Point
primitive per planet across all four kinds (local / other /
uninhabited / unidentified). Each kind gets a distinct fill colour,
fill alpha, and point radius so the four classes are
visually-distinguishable at a glance; later phases will refine the
colour palette as the visual language stabilises (Phase 35 polish).
The planet engine number is reused as the primitive id so a hit-test
result can resolve back to a planet without an extra lookup table.
## Refresh discipline
`refresh()` re-fetches the same turn snapshot. It is called by the
`visibilitychange` handler when `document.visibilityState ===
"visible"` and the store is already in `ready` state. The map view's
mount effect skips a re-render when the new snapshot's turn matches
the previously-mounted turn (and the wrap mode is unchanged), so a
no-op refresh does not flicker the canvas.
`setTurn(turn)` is the entry point for Phase 26 history mode:
calling it on a different turn loads that snapshot and the same
mount effect re-creates the renderer with the new world.
`setWrapMode(mode)` writes to `Cache` and updates the rune; the
map view's effect picks the change up and re-mounts the renderer
with the new mode.
+7 -1
View File
@@ -18,7 +18,7 @@ width.
| Section | Empty state | Source | Action |
| -------------------- | --------------------- | -------------------------- | --------------------------------------------------------- |
| `create new game` | (always visible) | — | Navigates to `/lobby/create` |
| `my games` | `no games yet` | `lobby.my.games.list` | Click → `/games/:id/map` (placeholder until Phase 10) |
| `my games` | `no games yet` | `lobby.my.games.list` | Click → `/games/:id/map` |
| `pending invitations`| `no invitations` | `lobby.my.invites.list` | Accept (`lobby.invite.redeem`) / Decline (`lobby.invite.decline`) |
| `my applications` | `no applications` | `lobby.my.applications.list` | Status badge (`pending` / `approved` / `rejected`) |
| `public games` | `no public games` | `lobby.public.games.list` | Submit application via inline race-name form (`lobby.application.submit`) |
@@ -27,6 +27,12 @@ The header preserves the device-session-id `<code>` block from the
Phase 7 placeholder (kept as a debug affordance) plus a greeting if
the gateway returns a `display_name` for the caller.
`GameSummary` carries an extra `current_turn` field (Phase 11
extension) that the lobby UI does not display directly — the in-game
shell reads it from the same payload to load the matching
`user.games.report` for the map view without an additional gateway
call. See [`game-state.md`](game-state.md) for the consumer's view.
## Application lifecycle
`Submit application` on a public-game card toggles an inline race-name
+178
View File
@@ -0,0 +1,178 @@
// Typed wrapper around `GalaxyClient.executeCommand("user.games.report",
// ...)`. The signed-gRPC wire shape is the FlatBuffers
// `report.GameReportRequest` for the request and `report.Report` for
// the response (see `pkg/schema/fbs/report.fbs`). Phase 11 only
// surfaces the planet subset of the response — full ship / fleet /
// science decoding lands in Phases 17-22.
import { Builder, ByteBuffer } from "flatbuffers";
import type { GalaxyClient } from "./galaxy-client";
import { UUID } from "../proto/galaxy/fbs/common";
import {
GameReportRequest,
Report,
} from "../proto/galaxy/fbs/report";
const MESSAGE_TYPE = "user.games.report";
export class GameStateError extends Error {
readonly resultCode: string;
readonly code: string;
constructor(resultCode: string, code: string, message: string) {
super(message);
this.name = "GameStateError";
this.resultCode = resultCode;
this.code = code;
}
}
export interface ReportPlanet {
number: number;
name: string;
x: number;
y: number;
kind: "local" | "other" | "uninhabited" | "unidentified";
owner: string | null;
size: number | null;
resources: number | null;
}
export interface GameReport {
turn: number;
mapWidth: number;
mapHeight: number;
planetCount: number;
planets: ReportPlanet[];
}
export async function fetchGameReport(
client: GalaxyClient,
gameId: string,
turn: number,
): Promise<GameReport> {
const builder = new Builder(64);
const [hi, lo] = uuidToHiLo(gameId);
const gameIdOffset = UUID.createUUID(builder, hi, lo);
GameReportRequest.startGameReportRequest(builder);
GameReportRequest.addGameId(builder, gameIdOffset);
GameReportRequest.addTurn(builder, turn);
builder.finish(GameReportRequest.endGameReportRequest(builder));
const result = await client.executeCommand(MESSAGE_TYPE, builder.asUint8Array());
if (result.resultCode !== "ok") {
const { code, message } = decodeErrorMessage(result.payloadBytes);
throw new GameStateError(result.resultCode, code, message);
}
const buffer = new ByteBuffer(result.payloadBytes);
const report = Report.getRootAsReport(buffer);
return decodeReport(report);
}
function decodeReport(report: Report): GameReport {
const planets: ReportPlanet[] = [];
for (let i = 0; i < report.localPlanetLength(); i++) {
const p = report.localPlanet(i);
if (p === null) continue;
planets.push({
number: Number(p.number()),
name: p.name() ?? "",
x: p.x(),
y: p.y(),
kind: "local",
owner: null,
size: p.size(),
resources: p.resources(),
});
}
for (let i = 0; i < report.otherPlanetLength(); i++) {
const p = report.otherPlanet(i);
if (p === null) continue;
planets.push({
number: Number(p.number()),
name: p.name() ?? "",
x: p.x(),
y: p.y(),
kind: "other",
owner: p.owner() ?? null,
size: p.size(),
resources: p.resources(),
});
}
for (let i = 0; i < report.uninhabitedPlanetLength(); i++) {
const p = report.uninhabitedPlanet(i);
if (p === null) continue;
planets.push({
number: Number(p.number()),
name: p.name() ?? "",
x: p.x(),
y: p.y(),
kind: "uninhabited",
owner: null,
size: p.size(),
resources: p.resources(),
});
}
for (let i = 0; i < report.unidentifiedPlanetLength(); i++) {
const p = report.unidentifiedPlanet(i);
if (p === null) continue;
planets.push({
number: Number(p.number()),
name: "",
x: p.x(),
y: p.y(),
kind: "unidentified",
owner: null,
size: null,
resources: null,
});
}
return {
turn: Number(report.turn()),
mapWidth: report.width(),
mapHeight: report.height(),
planetCount: report.planetCount(),
planets,
};
}
/**
* uuidToHiLo splits the canonical 36-character UUID string
* (`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) into the two big-endian
* uint64 halves used by `common.UUID`. Mirrors `pkg/transcoder/uuid.go`.
*/
export function uuidToHiLo(value: string): [bigint, bigint] {
const hex = value.replace(/-/g, "").toLowerCase();
if (hex.length !== 32 || /[^0-9a-f]/.test(hex)) {
throw new GameStateError(
"invalid_request",
"invalid_request",
`invalid uuid: ${value}`,
);
}
const hi = BigInt(`0x${hex.slice(0, 16)}`);
const lo = BigInt(`0x${hex.slice(16, 32)}`);
return [hi, lo];
}
function decodeErrorMessage(payload: Uint8Array): { code: string; message: string } {
if (payload.length === 0) {
return { code: "internal_error", message: "empty error payload" };
}
try {
const text = new TextDecoder().decode(payload);
const parsed = JSON.parse(text) as { code?: string; message?: string };
return {
code: typeof parsed.code === "string" ? parsed.code : "internal_error",
message: typeof parsed.message === "string" ? parsed.message : text,
};
} catch {
return { code: "internal_error", message: "non-json error payload" };
}
}
+8
View File
@@ -55,6 +55,13 @@ export interface GameSummary {
enrollmentEndsAt: Date;
createdAt: Date;
updatedAt: Date;
/**
* Most recent turn number observed by backend's runtime
* projection. Zero before the engine produces its first
* snapshot. The map view uses this to fetch the matching
* `user.games.report` without a separate state query.
*/
currentTurn: number;
}
export interface PublicGamesPage {
@@ -319,6 +326,7 @@ function decodeGameSummary(summary: FbsGameSummary): GameSummary {
enrollmentEndsAt: dateFromMs(summary.enrollmentEndsAtMs()),
createdAt: dateFromMs(summary.createdAtMs()),
updatedAt: dateFromMs(summary.updatedAtMs()),
currentTurn: summary.currentTurn(),
};
}
+173 -15
View File
@@ -1,29 +1,187 @@
<!--
Phase 10 stub for the map active view. Phase 11 swaps this for the
live renderer integration described in `ui/PLAN.md` Phase 11. The
stub keeps the same `data-testid` so Phase 11's spec replaces the
copy assertion without touching navigation.
Phase 11 map active view: integrates the Phase 9 renderer with the
per-game `GameStateStore` provided through context by
`routes/games/[id]/+layout.svelte`. The view mounts the renderer
once the store has produced a report and re-mounts when the
report's turn changes (a refresh that returns the same turn keeps
the existing renderer instance alive). Empty-planet reports render
the empty world without errors — the regression test in
`tests/e2e/game-shell-map.spec.ts` covers this.
Phase 9 owns the renderer's hit-test and pan/zoom semantics; Phase 13
will plug map clicks into the inspector. Phase 29 wires the wrap-mode
toggle on top of the per-game `wrapMode` preference the store
already manages.
-->
<script lang="ts">
import { getContext, onDestroy, onMount, untrack } from "svelte";
import { i18n } from "$lib/i18n/index.svelte";
import {
createRenderer,
minScaleNoWrap,
type RendererHandle,
} from "../../map/index";
import { reportToWorld } from "../../map/state-binding";
import {
GAME_STATE_CONTEXT_KEY,
type GameStateStore,
} from "$lib/game-state.svelte";
const store = getContext<GameStateStore | undefined>(GAME_STATE_CONTEXT_KEY);
let canvasEl: HTMLCanvasElement | null = $state(null);
let containerEl: HTMLDivElement | null = $state(null);
let mountError: string | null = $state(null);
let handle: RendererHandle | null = null;
let mountedTurn: number | null = null;
let mountedGameId: string | null = null;
let onResize: (() => void) | null = null;
let mounted = false;
$effect(() => {
const report = store?.report;
const status = store?.status ?? "idle";
// Track the wrap mode so the renderer remounts when Phase 29's
// toggle UI flips it; the read here also subscribes the effect.
const mode = store?.wrapMode ?? "torus";
const gameId = store?.gameId ?? "";
if (!mounted || canvasEl === null || containerEl === null) return;
if (status !== "ready" || !report) return;
// Skip a re-mount when the same turn is reloaded for the same
// game and the wrap mode did not change. The store's `refresh`
// path lands here on tab focus; an unchanged snapshot must not
// flicker the canvas.
const sameSnapshot =
mountedTurn === report.turn &&
mountedGameId === gameId &&
handle !== null &&
handle.getMode() === mode;
if (sameSnapshot) return;
untrack(() => {
void mountRenderer(report, mode);
});
});
async function mountRenderer(
report: NonNullable<GameStateStore["report"]>,
mode: "torus" | "no-wrap",
): Promise<void> {
if (canvasEl === null || containerEl === null) return;
if (handle !== null) {
handle.dispose();
handle = null;
}
try {
const world = reportToWorld(report);
handle = await createRenderer({
canvas: canvasEl,
world,
mode,
preference: ["webgpu", "webgl"],
});
handle.viewport.moveCenter(world.width / 2, world.height / 2);
const minScale = minScaleNoWrap(
{
widthPx: containerEl.clientWidth,
heightPx: containerEl.clientHeight,
},
world,
);
handle.viewport.setZoom(minScale * 1.05, true);
if (mode === "no-wrap") handle.setMode("no-wrap");
mountedTurn = report.turn;
mountedGameId = store?.gameId ?? "";
mountError = null;
} catch (err) {
mountError = err instanceof Error ? err.message : String(err);
}
}
onMount(() => {
mounted = true;
onResize = (): void => {
if (handle === null || containerEl === null) return;
handle.resize(containerEl.clientWidth, containerEl.clientHeight);
};
window.addEventListener("resize", onResize);
});
onDestroy(() => {
mounted = false;
if (onResize !== null) {
window.removeEventListener("resize", onResize);
onResize = null;
}
if (handle !== null) {
handle.dispose();
handle = null;
}
});
</script>
<section class="active-view" data-testid="active-view-map">
<h2>{i18n.t("game.view.map")}</h2>
<p>{i18n.t("game.shell.coming_soon")}</p>
<section class="active-view" data-testid="active-view-map" data-status={store?.status ?? "idle"}>
{#if store?.status === "error"}
<p class="overlay error" role="alert" data-testid="map-error">
{store.error ?? "request failed"}
</p>
{:else if mountError !== null}
<p class="overlay error" role="alert" data-testid="map-mount-error">
{mountError}
</p>
{:else if store?.status !== "ready"}
<p class="overlay" data-testid="map-loading">{i18n.t("common.loading")}</p>
{/if}
<div
class="canvas-wrap"
data-testid="map-canvas-wrap"
data-planet-count={store?.report?.planets.length ?? 0}
bind:this={containerEl}
>
<canvas bind:this={canvasEl}></canvas>
</div>
</section>
<style>
.active-view {
padding: 1.5rem;
position: relative;
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
.canvas-wrap {
flex: 1;
min-height: 0;
position: relative;
overflow: hidden;
background: #0a0e1a;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
.overlay {
position: absolute;
top: 0.75rem;
left: 50%;
transform: translateX(-50%);
padding: 0.4rem 0.9rem;
background: rgba(20, 24, 42, 0.85);
color: #e8eaf6;
border: 1px solid #2a3150;
border-radius: 6px;
z-index: 10;
font-family: system-ui, sans-serif;
}
.active-view h2 {
margin: 0 0 0.5rem;
font-size: 1.1rem;
}
.active-view p {
font-size: 0.9rem;
margin: 0;
color: #555;
}
.overlay.error {
background: #4a1820;
border-color: #6d2530;
color: #ffb4b4;
}
</style>
+200
View File
@@ -0,0 +1,200 @@
// Per-game runtime state owned by the in-game shell layout
// (`routes/games/[id]/+layout.svelte`). The store discovers the
// game's current turn through `lobby.my.games.list`, fetches the
// matching `user.games.report`, and exposes a TS-friendly `GameReport`
// snapshot to every consumer (header turn counter, map view,
// inspector tabs in later phases).
//
// Phase 11 covers planets only; later phases extend the report
// surface as their slice of state lands. Every consumer reads from
// the same store instance — instantiation per game guarantees the
// layout remount on `gameId` change reseeds the snapshot, while
// navigation between active views inside the same game keeps the
// instance alive (state-preservation rule, see ui/docs/navigation.md).
import {
GameStateError,
fetchGameReport,
type GameReport,
} from "../api/game-state";
import { listMyGames, type GameSummary } from "../api/lobby";
import type { GalaxyClient } from "../api/galaxy-client";
import type { Cache } from "../platform/store/index";
import type { WrapMode } from "../map/world";
const PREF_NAMESPACE = "game-prefs";
const PREF_KEY_WRAP_MODE = (gameId: string) => `${gameId}/wrap-mode`;
/**
* GAME_STATE_CONTEXT_KEY is the Svelte context key the in-game shell
* layout uses to expose its `GameStateStore` instance to descendants.
* Header / map / inspector children resolve the store via
* `getContext(GAME_STATE_CONTEXT_KEY)`.
*/
export const GAME_STATE_CONTEXT_KEY = Symbol("game-state");
type Status = "idle" | "loading" | "ready" | "error";
export class GameStateStore {
gameId: string = $state("");
status: Status = $state("idle");
report: GameReport | null = $state(null);
wrapMode: WrapMode = $state("torus");
error: string | null = $state(null);
private client: GalaxyClient | null = null;
private cache: Cache | null = null;
private currentTurn = 0;
private destroyed = false;
private visibilityListener: (() => void) | null = null;
/**
* init kicks off the per-game lifecycle. The call is idempotent on
* the same `gameId`; calling with a different game forwards through
* `setGame` so the layout can hand off across navigations.
*/
async init(opts: {
client: GalaxyClient;
cache: Cache;
gameId: string;
}): Promise<void> {
this.client = opts.client;
this.cache = opts.cache;
await this.setGame(opts.gameId);
this.installVisibilityListener();
}
/**
* setGame switches the store to the supplied game id, fetches the
* matching lobby record to discover `current_turn`, then loads the
* report. Failure paths surface through `status === "error"` and
* the matching `error` string (already localised by the caller).
*/
async setGame(gameId: string): Promise<void> {
if (this.client === null || this.cache === null) {
throw new Error("game-state: setGame called before init");
}
this.gameId = gameId;
this.status = "loading";
this.error = null;
this.report = null;
this.wrapMode = await readWrapMode(this.cache, gameId);
try {
const summary = await this.findGame(gameId);
if (summary === null) {
this.status = "error";
this.error = `game ${gameId} is not in your list`;
return;
}
this.currentTurn = summary.currentTurn;
await this.loadTurn(summary.currentTurn);
} catch (err) {
if (this.destroyed) return;
this.status = "error";
this.error = describe(err);
}
}
/**
* setTurn loads a different turn snapshot — used by Phase 26 history
* mode. The current turn stays at whatever `setGame` discovered;
* calling without an argument refetches the same turn.
*/
async setTurn(turn: number): Promise<void> {
if (this.client === null) return;
this.status = "loading";
this.error = null;
try {
await this.loadTurn(turn);
} catch (err) {
this.status = "error";
this.error = describe(err);
}
}
/**
* refresh re-fetches the report at the current turn. Called on
* window `visibilitychange` so the map and the turn counter stay
* fresh after the user returns to the tab.
*/
refresh(): Promise<void> {
return this.setTurn(this.currentTurn);
}
/**
* setWrapMode persists the per-game preference into Cache so the
* next visit to the game restores it. Phase 29 wires the toggle UI;
* Phase 11 only reads through `wrapMode` and writes via this method.
*/
async setWrapMode(mode: WrapMode): Promise<void> {
this.wrapMode = mode;
if (this.cache !== null) {
await this.cache.put(PREF_NAMESPACE, PREF_KEY_WRAP_MODE(this.gameId), mode);
}
}
/**
* failBootstrap is used by the layout to surface errors that
* happen *before* `init` could be reached (missing keypair, missing
* gateway public key, core/store load failure). It does not need
* `init` to have run first.
*/
failBootstrap(message: string): void {
this.status = "error";
this.error = message;
}
dispose(): void {
this.destroyed = true;
if (this.visibilityListener !== null && typeof document !== "undefined") {
document.removeEventListener("visibilitychange", this.visibilityListener);
}
this.visibilityListener = null;
this.client = null;
this.cache = null;
}
private async findGame(gameId: string): Promise<GameSummary | null> {
if (this.client === null) return null;
const games = await listMyGames(this.client);
return games.find((g) => g.gameId === gameId) ?? null;
}
private async loadTurn(turn: number): Promise<void> {
if (this.client === null) return;
const report = await fetchGameReport(this.client, this.gameId, turn);
if (this.destroyed) return;
this.report = report;
this.currentTurn = turn;
this.status = "ready";
}
private installVisibilityListener(): void {
if (typeof document === "undefined") return;
const listener = (): void => {
if (document.visibilityState === "visible" && this.status === "ready") {
void this.refresh();
}
};
this.visibilityListener = listener;
document.addEventListener("visibilitychange", listener);
}
}
async function readWrapMode(cache: Cache, gameId: string): Promise<WrapMode> {
const stored = await cache.get<string>(PREF_NAMESPACE, PREF_KEY_WRAP_MODE(gameId));
if (stored === "no-wrap") return "no-wrap";
return "torus";
}
function describe(err: unknown): string {
if (err instanceof GameStateError) {
return err.message;
}
if (err instanceof Error) {
return err.message;
}
return "request failed";
}
+22 -6
View File
@@ -1,15 +1,31 @@
<!--
Phase 10 placeholder turn counter. The displayed value is the static
`?` glyph from `game.shell.turn_unknown`; Phase 11 swaps the source
to the live game state. The wrapping span is kept as the public
shape so Phase 11 only needs to replace the inner text.
Phase 11 turn counter: reads the live turn number from the per-game
`GameStateStore` provided through context by
`routes/games/[id]/+layout.svelte`. Renders the static `?` placeholder
from `game.shell.turn_unknown` when the store has not yet produced a
report (boot, network error, no membership) so the header chrome
keeps its width across loading transitions.
Phase 26 will turn this into a clickable trigger that opens the
turn navigator; Phase 24 wires push-event-driven turn-ready toasts
that may flash this counter when a new turn is ready.
-->
<script lang="ts">
import { getContext } from "svelte";
import { i18n } from "$lib/i18n/index.svelte";
import { GAME_STATE_CONTEXT_KEY, type GameStateStore } from "$lib/game-state.svelte";
const store = getContext<GameStateStore | undefined>(GAME_STATE_CONTEXT_KEY);
const display = $derived.by(() => {
const report = store?.report ?? null;
if (report === null) return i18n.t("game.shell.turn_unknown");
return String(report.turn);
});
</script>
<span class="turn" data-testid="turn-counter">
{i18n.t("game.shell.turn_label")}&nbsp;{i18n.t("game.shell.turn_unknown")}
<span class="turn" data-testid="turn-counter" data-turn={display}>
{i18n.t("game.shell.turn_label")}&nbsp;{display}
</span>
<style>
+98
View File
@@ -0,0 +1,98 @@
// State binding between the typed game report and the renderer's
// World. Phase 11 only emits primitives for planets; later phases
// extend the binding with ship-class reach circles (Phase 17 / 18),
// hyperspace and incoming groups (Phase 11+ via separate primitives),
// cargo routes (Phase 16), reach / visibility zones (Phase 17), and
// battle / bombing markers (Phase 27).
//
// The four planet kinds in the report each map to a distinct style so
// the user can tell own / other-race / uninhabited / unidentified
// planets apart at a glance. The exact colours are Phase 11 defaults
// chosen against the dark theme; Phase 35 polish picks final
// colours and adds theme switching.
import type { GameReport, ReportPlanet } from "../api/game-state";
import { World, type Primitive, type Style } from "./world";
const STYLE_LOCAL: Style = {
fillColor: 0x6dd2ff,
fillAlpha: 1,
pointRadiusPx: 6,
};
const STYLE_OTHER: Style = {
fillColor: 0xff8a65,
fillAlpha: 1,
pointRadiusPx: 5,
};
const STYLE_UNINHABITED: Style = {
fillColor: 0xb0bec5,
fillAlpha: 0.85,
pointRadiusPx: 4,
};
const STYLE_UNIDENTIFIED: Style = {
fillColor: 0x546e7a,
fillAlpha: 0.7,
pointRadiusPx: 3,
};
// PlanetIDs occupy the [0, 4_000_000_000) range — well below
// JavaScript's `Number.MAX_SAFE_INTEGER` — so the engine `number` (uint64)
// fits in a primitive id (number) without truncation. The binding
// uses the engine number directly as the primitive id so later phases
// can resolve a planet by its hit-test result without an extra
// lookup table.
function styleFor(kind: ReportPlanet["kind"]): Style {
switch (kind) {
case "local":
return STYLE_LOCAL;
case "other":
return STYLE_OTHER;
case "uninhabited":
return STYLE_UNINHABITED;
case "unidentified":
return STYLE_UNIDENTIFIED;
}
}
function priorityFor(kind: ReportPlanet["kind"]): number {
switch (kind) {
case "local":
return 4;
case "other":
return 3;
case "uninhabited":
return 2;
case "unidentified":
return 1;
}
}
/**
* reportToWorld translates a GameReport into a renderer-ready World
* containing one Point primitive per planet (all four planet kinds).
* The world rectangle matches `report.mapWidth` × `report.mapHeight`.
*
* If the report carries zero planets (turn-zero edge cases or seeded
* tests), the World is still well-formed: the renderer mounts on an
* empty primitive list without errors.
*/
export function reportToWorld(report: GameReport): World {
const primitives: Primitive[] = [];
for (const planet of report.planets) {
primitives.push({
kind: "point",
id: planet.number,
priority: priorityFor(planet.kind),
style: styleFor(planet.kind),
hitSlopPx: 0,
x: planet.x,
y: planet.y,
});
}
const width = report.mapWidth > 0 ? report.mapWidth : 1;
const height = report.mapHeight > 0 ? report.mapHeight : 1;
return new World(width, height, primitives);
}
@@ -0,0 +1,5 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
export { UUID, UUIDT } from './common/uuid.js';
@@ -0,0 +1,65 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class UUID implements flatbuffers.IUnpackableObject<UUIDT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):UUID {
this.bb_pos = i;
this.bb = bb;
return this;
}
hi():bigint {
return this.bb!.readUint64(this.bb_pos);
}
lo():bigint {
return this.bb!.readUint64(this.bb_pos + 8);
}
static sizeOf():number {
return 16;
}
static createUUID(builder:flatbuffers.Builder, hi: bigint, lo: bigint):flatbuffers.Offset {
builder.prep(8, 16);
builder.writeInt64(BigInt(lo ?? 0));
builder.writeInt64(BigInt(hi ?? 0));
return builder.offset();
}
unpack(): UUIDT {
return new UUIDT(
this.hi(),
this.lo()
);
}
unpackTo(_o: UUIDT): void {
_o.hi = this.hi();
_o.lo = this.lo();
}
}
export class UUIDT implements flatbuffers.IGeneratedObject {
constructor(
public hi: bigint = BigInt('0'),
public lo: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return UUID.createUUID(builder,
this.hi,
this.lo
);
}
}
@@ -84,8 +84,13 @@ updatedAtMs():bigint {
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
currentTurn():number {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
static startGameSummary(builder:flatbuffers.Builder) {
builder.startObject(10);
builder.startObject(11);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
@@ -128,12 +133,16 @@ static addUpdatedAtMs(builder:flatbuffers.Builder, updatedAtMs:bigint) {
builder.addFieldInt64(9, updatedAtMs, BigInt('0'));
}
static addCurrentTurn(builder:flatbuffers.Builder, currentTurn:number) {
builder.addFieldInt32(10, currentTurn, 0);
}
static endGameSummary(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createGameSummary(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, gameNameOffset:flatbuffers.Offset, gameTypeOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset, ownerUserIdOffset:flatbuffers.Offset, minPlayers:number, maxPlayers:number, enrollmentEndsAtMs:bigint, createdAtMs:bigint, updatedAtMs:bigint):flatbuffers.Offset {
static createGameSummary(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, gameNameOffset:flatbuffers.Offset, gameTypeOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset, ownerUserIdOffset:flatbuffers.Offset, minPlayers:number, maxPlayers:number, enrollmentEndsAtMs:bigint, createdAtMs:bigint, updatedAtMs:bigint, currentTurn:number):flatbuffers.Offset {
GameSummary.startGameSummary(builder);
GameSummary.addGameId(builder, gameIdOffset);
GameSummary.addGameName(builder, gameNameOffset);
@@ -145,6 +154,7 @@ static createGameSummary(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.O
GameSummary.addEnrollmentEndsAtMs(builder, enrollmentEndsAtMs);
GameSummary.addCreatedAtMs(builder, createdAtMs);
GameSummary.addUpdatedAtMs(builder, updatedAtMs);
GameSummary.addCurrentTurn(builder, currentTurn);
return GameSummary.endGameSummary(builder);
}
@@ -159,7 +169,8 @@ unpack(): GameSummaryT {
this.maxPlayers(),
this.enrollmentEndsAtMs(),
this.createdAtMs(),
this.updatedAtMs()
this.updatedAtMs(),
this.currentTurn()
);
}
@@ -175,6 +186,7 @@ unpackTo(_o: GameSummaryT): void {
_o.enrollmentEndsAtMs = this.enrollmentEndsAtMs();
_o.createdAtMs = this.createdAtMs();
_o.updatedAtMs = this.updatedAtMs();
_o.currentTurn = this.currentTurn();
}
}
@@ -189,7 +201,8 @@ constructor(
public maxPlayers: number = 0,
public enrollmentEndsAtMs: bigint = BigInt('0'),
public createdAtMs: bigint = BigInt('0'),
public updatedAtMs: bigint = BigInt('0')
public updatedAtMs: bigint = BigInt('0'),
public currentTurn: number = 0
){}
@@ -210,7 +223,8 @@ pack(builder:flatbuffers.Builder): flatbuffers.Offset {
this.maxPlayers,
this.enrollmentEndsAtMs,
this.createdAtMs,
this.updatedAtMs
this.updatedAtMs,
this.currentTurn
);
}
}
@@ -0,0 +1,25 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
export { Bombing, BombingT } from './report/bombing.js';
export { GameReportRequest, GameReportRequestT } from './report/game-report-request.js';
export { IncomingGroup, IncomingGroupT } from './report/incoming-group.js';
export { LocalFleet, LocalFleetT } from './report/local-fleet.js';
export { LocalGroup, LocalGroupT } from './report/local-group.js';
export { LocalPlanet, LocalPlanetT } from './report/local-planet.js';
export { OtherGroup, OtherGroupT } from './report/other-group.js';
export { OtherPlanet, OtherPlanetT } from './report/other-planet.js';
export { OtherScience, OtherScienceT } from './report/other-science.js';
export { OthersShipClass, OthersShipClassT } from './report/others-ship-class.js';
export { Player, PlayerT } from './report/player.js';
export { Report, ReportT } from './report/report.js';
export { Route, RouteT } from './report/route.js';
export { RouteEntry, RouteEntryT } from './report/route-entry.js';
export { Science, ScienceT } from './report/science.js';
export { ShipClass, ShipClassT } from './report/ship-class.js';
export { ShipProduction, ShipProductionT } from './report/ship-production.js';
export { TechEntry, TechEntryT } from './report/tech-entry.js';
export { UnidentifiedGroup, UnidentifiedGroupT } from './report/unidentified-group.js';
export { UnidentifiedPlanet, UnidentifiedPlanetT } from './report/unidentified-planet.js';
export { UninhabitedPlanet, UninhabitedPlanetT } from './report/uninhabited-planet.js';
@@ -0,0 +1,241 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class Bombing implements flatbuffers.IUnpackableObject<BombingT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):Bombing {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsBombing(bb:flatbuffers.ByteBuffer, obj?:Bombing):Bombing {
return (obj || new Bombing()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsBombing(bb:flatbuffers.ByteBuffer, obj?:Bombing):Bombing {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new Bombing()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
number():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
planet():string|null
planet(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
planet(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
owner():string|null
owner(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
owner(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
attacker():string|null
attacker(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
attacker(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
production():string|null
production(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
production(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
industry():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
population():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
colonists():number {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
capital():number {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
material():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
attackPower():number {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
wiped():boolean {
const offset = this.bb!.__offset(this.bb_pos, 26);
return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}
static startBombing(builder:flatbuffers.Builder) {
builder.startObject(12);
}
static addNumber(builder:flatbuffers.Builder, number:bigint) {
builder.addFieldInt64(0, number, BigInt('0'));
}
static addPlanet(builder:flatbuffers.Builder, planetOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, planetOffset, 0);
}
static addOwner(builder:flatbuffers.Builder, ownerOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, ownerOffset, 0);
}
static addAttacker(builder:flatbuffers.Builder, attackerOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, attackerOffset, 0);
}
static addProduction(builder:flatbuffers.Builder, productionOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, productionOffset, 0);
}
static addIndustry(builder:flatbuffers.Builder, industry:number) {
builder.addFieldFloat32(5, industry, 0.0);
}
static addPopulation(builder:flatbuffers.Builder, population:number) {
builder.addFieldFloat32(6, population, 0.0);
}
static addColonists(builder:flatbuffers.Builder, colonists:number) {
builder.addFieldFloat32(7, colonists, 0.0);
}
static addCapital(builder:flatbuffers.Builder, capital:number) {
builder.addFieldFloat32(8, capital, 0.0);
}
static addMaterial(builder:flatbuffers.Builder, material:number) {
builder.addFieldFloat32(9, material, 0.0);
}
static addAttackPower(builder:flatbuffers.Builder, attackPower:number) {
builder.addFieldFloat32(10, attackPower, 0.0);
}
static addWiped(builder:flatbuffers.Builder, wiped:boolean) {
builder.addFieldInt8(11, +wiped, +false);
}
static endBombing(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createBombing(builder:flatbuffers.Builder, number:bigint, planetOffset:flatbuffers.Offset, ownerOffset:flatbuffers.Offset, attackerOffset:flatbuffers.Offset, productionOffset:flatbuffers.Offset, industry:number, population:number, colonists:number, capital:number, material:number, attackPower:number, wiped:boolean):flatbuffers.Offset {
Bombing.startBombing(builder);
Bombing.addNumber(builder, number);
Bombing.addPlanet(builder, planetOffset);
Bombing.addOwner(builder, ownerOffset);
Bombing.addAttacker(builder, attackerOffset);
Bombing.addProduction(builder, productionOffset);
Bombing.addIndustry(builder, industry);
Bombing.addPopulation(builder, population);
Bombing.addColonists(builder, colonists);
Bombing.addCapital(builder, capital);
Bombing.addMaterial(builder, material);
Bombing.addAttackPower(builder, attackPower);
Bombing.addWiped(builder, wiped);
return Bombing.endBombing(builder);
}
unpack(): BombingT {
return new BombingT(
this.number(),
this.planet(),
this.owner(),
this.attacker(),
this.production(),
this.industry(),
this.population(),
this.colonists(),
this.capital(),
this.material(),
this.attackPower(),
this.wiped()
);
}
unpackTo(_o: BombingT): void {
_o.number = this.number();
_o.planet = this.planet();
_o.owner = this.owner();
_o.attacker = this.attacker();
_o.production = this.production();
_o.industry = this.industry();
_o.population = this.population();
_o.colonists = this.colonists();
_o.capital = this.capital();
_o.material = this.material();
_o.attackPower = this.attackPower();
_o.wiped = this.wiped();
}
}
export class BombingT implements flatbuffers.IGeneratedObject {
constructor(
public number: bigint = BigInt('0'),
public planet: string|Uint8Array|null = null,
public owner: string|Uint8Array|null = null,
public attacker: string|Uint8Array|null = null,
public production: string|Uint8Array|null = null,
public industry: number = 0.0,
public population: number = 0.0,
public colonists: number = 0.0,
public capital: number = 0.0,
public material: number = 0.0,
public attackPower: number = 0.0,
public wiped: boolean = false
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const planet = (this.planet !== null ? builder.createString(this.planet!) : 0);
const owner = (this.owner !== null ? builder.createString(this.owner!) : 0);
const attacker = (this.attacker !== null ? builder.createString(this.attacker!) : 0);
const production = (this.production !== null ? builder.createString(this.production!) : 0);
return Bombing.createBombing(builder,
this.number,
planet,
owner,
attacker,
production,
this.industry,
this.population,
this.colonists,
this.capital,
this.material,
this.attackPower,
this.wiped
);
}
}
@@ -0,0 +1,90 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { UUID, UUIDT } from '../common/uuid.js';
export class GameReportRequest implements flatbuffers.IUnpackableObject<GameReportRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):GameReportRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsGameReportRequest(bb:flatbuffers.ByteBuffer, obj?:GameReportRequest):GameReportRequest {
return (obj || new GameReportRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsGameReportRequest(bb:flatbuffers.ByteBuffer, obj?:GameReportRequest):GameReportRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new GameReportRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameId(obj?:UUID):UUID|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new UUID()).__init(this.bb_pos + offset, this.bb!) : null;
}
turn():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
}
static startGameReportRequest(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldStruct(0, gameIdOffset, 0);
}
static addTurn(builder:flatbuffers.Builder, turn:number) {
builder.addFieldInt32(1, turn, 0);
}
static endGameReportRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
builder.requiredField(offset, 4) // game_id
return offset;
}
static createGameReportRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, turn:number):flatbuffers.Offset {
GameReportRequest.startGameReportRequest(builder);
GameReportRequest.addGameId(builder, gameIdOffset);
GameReportRequest.addTurn(builder, turn);
return GameReportRequest.endGameReportRequest(builder);
}
unpack(): GameReportRequestT {
return new GameReportRequestT(
(this.gameId() !== null ? this.gameId()!.unpack() : null),
this.turn()
);
}
unpackTo(_o: GameReportRequestT): void {
_o.gameId = (this.gameId() !== null ? this.gameId()!.unpack() : null);
_o.turn = this.turn();
}
}
export class GameReportRequestT implements flatbuffers.IGeneratedObject {
constructor(
public gameId: UUIDT|null = null,
public turn: number = 0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return GameReportRequest.createGameReportRequest(builder,
(this.gameId !== null ? this.gameId!.pack(builder) : 0),
this.turn
);
}
}
@@ -0,0 +1,130 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class IncomingGroup implements flatbuffers.IUnpackableObject<IncomingGroupT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):IncomingGroup {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsIncomingGroup(bb:flatbuffers.ByteBuffer, obj?:IncomingGroup):IncomingGroup {
return (obj || new IncomingGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsIncomingGroup(bb:flatbuffers.ByteBuffer, obj?:IncomingGroup):IncomingGroup {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new IncomingGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
origin():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
destination():bigint {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
distance():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
speed():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
mass():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startIncomingGroup(builder:flatbuffers.Builder) {
builder.startObject(5);
}
static addOrigin(builder:flatbuffers.Builder, origin:bigint) {
builder.addFieldInt64(0, origin, BigInt('0'));
}
static addDestination(builder:flatbuffers.Builder, destination:bigint) {
builder.addFieldInt64(1, destination, BigInt('0'));
}
static addDistance(builder:flatbuffers.Builder, distance:number) {
builder.addFieldFloat32(2, distance, 0.0);
}
static addSpeed(builder:flatbuffers.Builder, speed:number) {
builder.addFieldFloat32(3, speed, 0.0);
}
static addMass(builder:flatbuffers.Builder, mass:number) {
builder.addFieldFloat32(4, mass, 0.0);
}
static endIncomingGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createIncomingGroup(builder:flatbuffers.Builder, origin:bigint, destination:bigint, distance:number, speed:number, mass:number):flatbuffers.Offset {
IncomingGroup.startIncomingGroup(builder);
IncomingGroup.addOrigin(builder, origin);
IncomingGroup.addDestination(builder, destination);
IncomingGroup.addDistance(builder, distance);
IncomingGroup.addSpeed(builder, speed);
IncomingGroup.addMass(builder, mass);
return IncomingGroup.endIncomingGroup(builder);
}
unpack(): IncomingGroupT {
return new IncomingGroupT(
this.origin(),
this.destination(),
this.distance(),
this.speed(),
this.mass()
);
}
unpackTo(_o: IncomingGroupT): void {
_o.origin = this.origin();
_o.destination = this.destination();
_o.distance = this.distance();
_o.speed = this.speed();
_o.mass = this.mass();
}
}
export class IncomingGroupT implements flatbuffers.IGeneratedObject {
constructor(
public origin: bigint = BigInt('0'),
public destination: bigint = BigInt('0'),
public distance: number = 0.0,
public speed: number = 0.0,
public mass: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return IncomingGroup.createIncomingGroup(builder,
this.origin,
this.destination,
this.distance,
this.speed,
this.mass
);
}
}
@@ -0,0 +1,167 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class LocalFleet implements flatbuffers.IUnpackableObject<LocalFleetT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):LocalFleet {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsLocalFleet(bb:flatbuffers.ByteBuffer, obj?:LocalFleet):LocalFleet {
return (obj || new LocalFleet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsLocalFleet(bb:flatbuffers.ByteBuffer, obj?:LocalFleet):LocalFleet {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new LocalFleet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
groups():bigint {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
destination():bigint {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
origin():bigint|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : null;
}
range():number|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : null;
}
speed():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
state():string|null
state(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
state(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
static startLocalFleet(builder:flatbuffers.Builder) {
builder.startObject(7);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, nameOffset, 0);
}
static addGroups(builder:flatbuffers.Builder, groups:bigint) {
builder.addFieldInt64(1, groups, BigInt('0'));
}
static addDestination(builder:flatbuffers.Builder, destination:bigint) {
builder.addFieldInt64(2, destination, BigInt('0'));
}
static addOrigin(builder:flatbuffers.Builder, origin:bigint) {
builder.addFieldInt64(3, origin, null);
}
static addRange(builder:flatbuffers.Builder, range:number) {
builder.addFieldFloat32(4, range, null);
}
static addSpeed(builder:flatbuffers.Builder, speed:number) {
builder.addFieldFloat32(5, speed, 0.0);
}
static addState(builder:flatbuffers.Builder, stateOffset:flatbuffers.Offset) {
builder.addFieldOffset(6, stateOffset, 0);
}
static endLocalFleet(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createLocalFleet(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, groups:bigint, destination:bigint, origin:bigint|null, range:number|null, speed:number, stateOffset:flatbuffers.Offset):flatbuffers.Offset {
LocalFleet.startLocalFleet(builder);
LocalFleet.addName(builder, nameOffset);
LocalFleet.addGroups(builder, groups);
LocalFleet.addDestination(builder, destination);
if (origin !== null)
LocalFleet.addOrigin(builder, origin);
if (range !== null)
LocalFleet.addRange(builder, range);
LocalFleet.addSpeed(builder, speed);
LocalFleet.addState(builder, stateOffset);
return LocalFleet.endLocalFleet(builder);
}
unpack(): LocalFleetT {
return new LocalFleetT(
this.name(),
this.groups(),
this.destination(),
this.origin(),
this.range(),
this.speed(),
this.state()
);
}
unpackTo(_o: LocalFleetT): void {
_o.name = this.name();
_o.groups = this.groups();
_o.destination = this.destination();
_o.origin = this.origin();
_o.range = this.range();
_o.speed = this.speed();
_o.state = this.state();
}
}
export class LocalFleetT implements flatbuffers.IGeneratedObject {
constructor(
public name: string|Uint8Array|null = null,
public groups: bigint = BigInt('0'),
public destination: bigint = BigInt('0'),
public origin: bigint|null = null,
public range: number|null = null,
public speed: number = 0.0,
public state: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const name = (this.name !== null ? builder.createString(this.name!) : 0);
const state = (this.state !== null ? builder.createString(this.state!) : 0);
return LocalFleet.createLocalFleet(builder,
name,
this.groups,
this.destination,
this.origin,
this.range,
this.speed,
state
);
}
}
@@ -0,0 +1,262 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { UUID, UUIDT } from '../common/uuid.js';
import { TechEntry, TechEntryT } from './tech-entry.js';
export class LocalGroup implements flatbuffers.IUnpackableObject<LocalGroupT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):LocalGroup {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsLocalGroup(bb:flatbuffers.ByteBuffer, obj?:LocalGroup):LocalGroup {
return (obj || new LocalGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsLocalGroup(bb:flatbuffers.ByteBuffer, obj?:LocalGroup):LocalGroup {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new LocalGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
number():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
class_():string|null
class_(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
class_(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
tech(index: number, obj?:TechEntry):TechEntry|null {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? (obj || new TechEntry()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
techLength():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
cargo():string|null
cargo(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
cargo(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
load():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
destination():bigint {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
origin():bigint|null {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : null;
}
range():number|null {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : null;
}
speed():number {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
mass():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
id(obj?:UUID):UUID|null {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? (obj || new UUID()).__init(this.bb_pos + offset, this.bb!) : null;
}
state():string|null
state(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
state(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 26);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
fleet():string|null
fleet(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
fleet(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 28);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
static startLocalGroup(builder:flatbuffers.Builder) {
builder.startObject(13);
}
static addNumber(builder:flatbuffers.Builder, number:bigint) {
builder.addFieldInt64(0, number, BigInt('0'));
}
static addClass(builder:flatbuffers.Builder, class_Offset:flatbuffers.Offset) {
builder.addFieldOffset(1, class_Offset, 0);
}
static addTech(builder:flatbuffers.Builder, techOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, techOffset, 0);
}
static createTechVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startTechVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addCargo(builder:flatbuffers.Builder, cargoOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, cargoOffset, 0);
}
static addLoad(builder:flatbuffers.Builder, load:number) {
builder.addFieldFloat32(4, load, 0.0);
}
static addDestination(builder:flatbuffers.Builder, destination:bigint) {
builder.addFieldInt64(5, destination, BigInt('0'));
}
static addOrigin(builder:flatbuffers.Builder, origin:bigint) {
builder.addFieldInt64(6, origin, null);
}
static addRange(builder:flatbuffers.Builder, range:number) {
builder.addFieldFloat32(7, range, null);
}
static addSpeed(builder:flatbuffers.Builder, speed:number) {
builder.addFieldFloat32(8, speed, 0.0);
}
static addMass(builder:flatbuffers.Builder, mass:number) {
builder.addFieldFloat32(9, mass, 0.0);
}
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
builder.addFieldStruct(10, idOffset, 0);
}
static addState(builder:flatbuffers.Builder, stateOffset:flatbuffers.Offset) {
builder.addFieldOffset(11, stateOffset, 0);
}
static addFleet(builder:flatbuffers.Builder, fleetOffset:flatbuffers.Offset) {
builder.addFieldOffset(12, fleetOffset, 0);
}
static endLocalGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
builder.requiredField(offset, 24) // id
return offset;
}
unpack(): LocalGroupT {
return new LocalGroupT(
this.number(),
this.class_(),
this.bb!.createObjList<TechEntry, TechEntryT>(this.tech.bind(this), this.techLength()),
this.cargo(),
this.load(),
this.destination(),
this.origin(),
this.range(),
this.speed(),
this.mass(),
(this.id() !== null ? this.id()!.unpack() : null),
this.state(),
this.fleet()
);
}
unpackTo(_o: LocalGroupT): void {
_o.number = this.number();
_o.class_ = this.class_();
_o.tech = this.bb!.createObjList<TechEntry, TechEntryT>(this.tech.bind(this), this.techLength());
_o.cargo = this.cargo();
_o.load = this.load();
_o.destination = this.destination();
_o.origin = this.origin();
_o.range = this.range();
_o.speed = this.speed();
_o.mass = this.mass();
_o.id = (this.id() !== null ? this.id()!.unpack() : null);
_o.state = this.state();
_o.fleet = this.fleet();
}
}
export class LocalGroupT implements flatbuffers.IGeneratedObject {
constructor(
public number: bigint = BigInt('0'),
public class_: string|Uint8Array|null = null,
public tech: (TechEntryT)[] = [],
public cargo: string|Uint8Array|null = null,
public load: number = 0.0,
public destination: bigint = BigInt('0'),
public origin: bigint|null = null,
public range: number|null = null,
public speed: number = 0.0,
public mass: number = 0.0,
public id: UUIDT|null = null,
public state: string|Uint8Array|null = null,
public fleet: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const class_ = (this.class_ !== null ? builder.createString(this.class_!) : 0);
const tech = LocalGroup.createTechVector(builder, builder.createObjectOffsetList(this.tech));
const cargo = (this.cargo !== null ? builder.createString(this.cargo!) : 0);
const state = (this.state !== null ? builder.createString(this.state!) : 0);
const fleet = (this.fleet !== null ? builder.createString(this.fleet!) : 0);
LocalGroup.startLocalGroup(builder);
LocalGroup.addNumber(builder, this.number);
LocalGroup.addClass(builder, class_);
LocalGroup.addTech(builder, tech);
LocalGroup.addCargo(builder, cargo);
LocalGroup.addLoad(builder, this.load);
LocalGroup.addDestination(builder, this.destination);
if (this.origin !== null)
LocalGroup.addOrigin(builder, this.origin);
if (this.range !== null)
LocalGroup.addRange(builder, this.range);
LocalGroup.addSpeed(builder, this.speed);
LocalGroup.addMass(builder, this.mass);
LocalGroup.addId(builder, (this.id !== null ? this.id!.pack(builder) : 0));
LocalGroup.addState(builder, state);
LocalGroup.addFleet(builder, fleet);
return LocalGroup.endLocalGroup(builder);
}
}
@@ -0,0 +1,249 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class LocalPlanet implements flatbuffers.IUnpackableObject<LocalPlanetT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):LocalPlanet {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsLocalPlanet(bb:flatbuffers.ByteBuffer, obj?:LocalPlanet):LocalPlanet {
return (obj || new LocalPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsLocalPlanet(bb:flatbuffers.ByteBuffer, obj?:LocalPlanet):LocalPlanet {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new LocalPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
x():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
y():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
number():bigint {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
size():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
resources():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
capital():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
material():number {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
industry():number {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
population():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
colonists():number {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
production():string|null
production(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
production(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 26);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
freeIndustry():number {
const offset = this.bb!.__offset(this.bb_pos, 28);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startLocalPlanet(builder:flatbuffers.Builder) {
builder.startObject(13);
}
static addX(builder:flatbuffers.Builder, x:number) {
builder.addFieldFloat32(0, x, 0.0);
}
static addY(builder:flatbuffers.Builder, y:number) {
builder.addFieldFloat32(1, y, 0.0);
}
static addNumber(builder:flatbuffers.Builder, number:bigint) {
builder.addFieldInt64(2, number, BigInt('0'));
}
static addSize(builder:flatbuffers.Builder, size:number) {
builder.addFieldFloat32(3, size, 0.0);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, nameOffset, 0);
}
static addResources(builder:flatbuffers.Builder, resources:number) {
builder.addFieldFloat32(5, resources, 0.0);
}
static addCapital(builder:flatbuffers.Builder, capital:number) {
builder.addFieldFloat32(6, capital, 0.0);
}
static addMaterial(builder:flatbuffers.Builder, material:number) {
builder.addFieldFloat32(7, material, 0.0);
}
static addIndustry(builder:flatbuffers.Builder, industry:number) {
builder.addFieldFloat32(8, industry, 0.0);
}
static addPopulation(builder:flatbuffers.Builder, population:number) {
builder.addFieldFloat32(9, population, 0.0);
}
static addColonists(builder:flatbuffers.Builder, colonists:number) {
builder.addFieldFloat32(10, colonists, 0.0);
}
static addProduction(builder:flatbuffers.Builder, productionOffset:flatbuffers.Offset) {
builder.addFieldOffset(11, productionOffset, 0);
}
static addFreeIndustry(builder:flatbuffers.Builder, freeIndustry:number) {
builder.addFieldFloat32(12, freeIndustry, 0.0);
}
static endLocalPlanet(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createLocalPlanet(builder:flatbuffers.Builder, x:number, y:number, number:bigint, size:number, nameOffset:flatbuffers.Offset, resources:number, capital:number, material:number, industry:number, population:number, colonists:number, productionOffset:flatbuffers.Offset, freeIndustry:number):flatbuffers.Offset {
LocalPlanet.startLocalPlanet(builder);
LocalPlanet.addX(builder, x);
LocalPlanet.addY(builder, y);
LocalPlanet.addNumber(builder, number);
LocalPlanet.addSize(builder, size);
LocalPlanet.addName(builder, nameOffset);
LocalPlanet.addResources(builder, resources);
LocalPlanet.addCapital(builder, capital);
LocalPlanet.addMaterial(builder, material);
LocalPlanet.addIndustry(builder, industry);
LocalPlanet.addPopulation(builder, population);
LocalPlanet.addColonists(builder, colonists);
LocalPlanet.addProduction(builder, productionOffset);
LocalPlanet.addFreeIndustry(builder, freeIndustry);
return LocalPlanet.endLocalPlanet(builder);
}
unpack(): LocalPlanetT {
return new LocalPlanetT(
this.x(),
this.y(),
this.number(),
this.size(),
this.name(),
this.resources(),
this.capital(),
this.material(),
this.industry(),
this.population(),
this.colonists(),
this.production(),
this.freeIndustry()
);
}
unpackTo(_o: LocalPlanetT): void {
_o.x = this.x();
_o.y = this.y();
_o.number = this.number();
_o.size = this.size();
_o.name = this.name();
_o.resources = this.resources();
_o.capital = this.capital();
_o.material = this.material();
_o.industry = this.industry();
_o.population = this.population();
_o.colonists = this.colonists();
_o.production = this.production();
_o.freeIndustry = this.freeIndustry();
}
}
export class LocalPlanetT implements flatbuffers.IGeneratedObject {
constructor(
public x: number = 0.0,
public y: number = 0.0,
public number: bigint = BigInt('0'),
public size: number = 0.0,
public name: string|Uint8Array|null = null,
public resources: number = 0.0,
public capital: number = 0.0,
public material: number = 0.0,
public industry: number = 0.0,
public population: number = 0.0,
public colonists: number = 0.0,
public production: string|Uint8Array|null = null,
public freeIndustry: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const name = (this.name !== null ? builder.createString(this.name!) : 0);
const production = (this.production !== null ? builder.createString(this.production!) : 0);
return LocalPlanet.createLocalPlanet(builder,
this.x,
this.y,
this.number,
this.size,
name,
this.resources,
this.capital,
this.material,
this.industry,
this.population,
this.colonists,
production,
this.freeIndustry
);
}
}
@@ -0,0 +1,228 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { TechEntry, TechEntryT } from './tech-entry.js';
export class OtherGroup implements flatbuffers.IUnpackableObject<OtherGroupT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):OtherGroup {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsOtherGroup(bb:flatbuffers.ByteBuffer, obj?:OtherGroup):OtherGroup {
return (obj || new OtherGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsOtherGroup(bb:flatbuffers.ByteBuffer, obj?:OtherGroup):OtherGroup {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new OtherGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
number():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
class_():string|null
class_(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
class_(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
tech(index: number, obj?:TechEntry):TechEntry|null {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? (obj || new TechEntry()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
techLength():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
cargo():string|null
cargo(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
cargo(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
load():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
destination():bigint {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
origin():bigint|null {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : null;
}
range():number|null {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : null;
}
speed():number {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
mass():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startOtherGroup(builder:flatbuffers.Builder) {
builder.startObject(10);
}
static addNumber(builder:flatbuffers.Builder, number:bigint) {
builder.addFieldInt64(0, number, BigInt('0'));
}
static addClass(builder:flatbuffers.Builder, class_Offset:flatbuffers.Offset) {
builder.addFieldOffset(1, class_Offset, 0);
}
static addTech(builder:flatbuffers.Builder, techOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, techOffset, 0);
}
static createTechVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startTechVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addCargo(builder:flatbuffers.Builder, cargoOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, cargoOffset, 0);
}
static addLoad(builder:flatbuffers.Builder, load:number) {
builder.addFieldFloat32(4, load, 0.0);
}
static addDestination(builder:flatbuffers.Builder, destination:bigint) {
builder.addFieldInt64(5, destination, BigInt('0'));
}
static addOrigin(builder:flatbuffers.Builder, origin:bigint) {
builder.addFieldInt64(6, origin, null);
}
static addRange(builder:flatbuffers.Builder, range:number) {
builder.addFieldFloat32(7, range, null);
}
static addSpeed(builder:flatbuffers.Builder, speed:number) {
builder.addFieldFloat32(8, speed, 0.0);
}
static addMass(builder:flatbuffers.Builder, mass:number) {
builder.addFieldFloat32(9, mass, 0.0);
}
static endOtherGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createOtherGroup(builder:flatbuffers.Builder, number:bigint, class_Offset:flatbuffers.Offset, techOffset:flatbuffers.Offset, cargoOffset:flatbuffers.Offset, load:number, destination:bigint, origin:bigint|null, range:number|null, speed:number, mass:number):flatbuffers.Offset {
OtherGroup.startOtherGroup(builder);
OtherGroup.addNumber(builder, number);
OtherGroup.addClass(builder, class_Offset);
OtherGroup.addTech(builder, techOffset);
OtherGroup.addCargo(builder, cargoOffset);
OtherGroup.addLoad(builder, load);
OtherGroup.addDestination(builder, destination);
if (origin !== null)
OtherGroup.addOrigin(builder, origin);
if (range !== null)
OtherGroup.addRange(builder, range);
OtherGroup.addSpeed(builder, speed);
OtherGroup.addMass(builder, mass);
return OtherGroup.endOtherGroup(builder);
}
unpack(): OtherGroupT {
return new OtherGroupT(
this.number(),
this.class_(),
this.bb!.createObjList<TechEntry, TechEntryT>(this.tech.bind(this), this.techLength()),
this.cargo(),
this.load(),
this.destination(),
this.origin(),
this.range(),
this.speed(),
this.mass()
);
}
unpackTo(_o: OtherGroupT): void {
_o.number = this.number();
_o.class_ = this.class_();
_o.tech = this.bb!.createObjList<TechEntry, TechEntryT>(this.tech.bind(this), this.techLength());
_o.cargo = this.cargo();
_o.load = this.load();
_o.destination = this.destination();
_o.origin = this.origin();
_o.range = this.range();
_o.speed = this.speed();
_o.mass = this.mass();
}
}
export class OtherGroupT implements flatbuffers.IGeneratedObject {
constructor(
public number: bigint = BigInt('0'),
public class_: string|Uint8Array|null = null,
public tech: (TechEntryT)[] = [],
public cargo: string|Uint8Array|null = null,
public load: number = 0.0,
public destination: bigint = BigInt('0'),
public origin: bigint|null = null,
public range: number|null = null,
public speed: number = 0.0,
public mass: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const class_ = (this.class_ !== null ? builder.createString(this.class_!) : 0);
const tech = OtherGroup.createTechVector(builder, builder.createObjectOffsetList(this.tech));
const cargo = (this.cargo !== null ? builder.createString(this.cargo!) : 0);
return OtherGroup.createOtherGroup(builder,
this.number,
class_,
tech,
cargo,
this.load,
this.destination,
this.origin,
this.range,
this.speed,
this.mass
);
}
}
@@ -0,0 +1,266 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class OtherPlanet implements flatbuffers.IUnpackableObject<OtherPlanetT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):OtherPlanet {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsOtherPlanet(bb:flatbuffers.ByteBuffer, obj?:OtherPlanet):OtherPlanet {
return (obj || new OtherPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsOtherPlanet(bb:flatbuffers.ByteBuffer, obj?:OtherPlanet):OtherPlanet {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new OtherPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
owner():string|null
owner(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
owner(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
x():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
y():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
number():bigint {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
size():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
resources():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
capital():number {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
material():number {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
industry():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
population():number {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
colonists():number {
const offset = this.bb!.__offset(this.bb_pos, 26);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
production():string|null
production(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
production(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 28);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
freeIndustry():number {
const offset = this.bb!.__offset(this.bb_pos, 30);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startOtherPlanet(builder:flatbuffers.Builder) {
builder.startObject(14);
}
static addOwner(builder:flatbuffers.Builder, ownerOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, ownerOffset, 0);
}
static addX(builder:flatbuffers.Builder, x:number) {
builder.addFieldFloat32(1, x, 0.0);
}
static addY(builder:flatbuffers.Builder, y:number) {
builder.addFieldFloat32(2, y, 0.0);
}
static addNumber(builder:flatbuffers.Builder, number:bigint) {
builder.addFieldInt64(3, number, BigInt('0'));
}
static addSize(builder:flatbuffers.Builder, size:number) {
builder.addFieldFloat32(4, size, 0.0);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(5, nameOffset, 0);
}
static addResources(builder:flatbuffers.Builder, resources:number) {
builder.addFieldFloat32(6, resources, 0.0);
}
static addCapital(builder:flatbuffers.Builder, capital:number) {
builder.addFieldFloat32(7, capital, 0.0);
}
static addMaterial(builder:flatbuffers.Builder, material:number) {
builder.addFieldFloat32(8, material, 0.0);
}
static addIndustry(builder:flatbuffers.Builder, industry:number) {
builder.addFieldFloat32(9, industry, 0.0);
}
static addPopulation(builder:flatbuffers.Builder, population:number) {
builder.addFieldFloat32(10, population, 0.0);
}
static addColonists(builder:flatbuffers.Builder, colonists:number) {
builder.addFieldFloat32(11, colonists, 0.0);
}
static addProduction(builder:flatbuffers.Builder, productionOffset:flatbuffers.Offset) {
builder.addFieldOffset(12, productionOffset, 0);
}
static addFreeIndustry(builder:flatbuffers.Builder, freeIndustry:number) {
builder.addFieldFloat32(13, freeIndustry, 0.0);
}
static endOtherPlanet(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createOtherPlanet(builder:flatbuffers.Builder, ownerOffset:flatbuffers.Offset, x:number, y:number, number:bigint, size:number, nameOffset:flatbuffers.Offset, resources:number, capital:number, material:number, industry:number, population:number, colonists:number, productionOffset:flatbuffers.Offset, freeIndustry:number):flatbuffers.Offset {
OtherPlanet.startOtherPlanet(builder);
OtherPlanet.addOwner(builder, ownerOffset);
OtherPlanet.addX(builder, x);
OtherPlanet.addY(builder, y);
OtherPlanet.addNumber(builder, number);
OtherPlanet.addSize(builder, size);
OtherPlanet.addName(builder, nameOffset);
OtherPlanet.addResources(builder, resources);
OtherPlanet.addCapital(builder, capital);
OtherPlanet.addMaterial(builder, material);
OtherPlanet.addIndustry(builder, industry);
OtherPlanet.addPopulation(builder, population);
OtherPlanet.addColonists(builder, colonists);
OtherPlanet.addProduction(builder, productionOffset);
OtherPlanet.addFreeIndustry(builder, freeIndustry);
return OtherPlanet.endOtherPlanet(builder);
}
unpack(): OtherPlanetT {
return new OtherPlanetT(
this.owner(),
this.x(),
this.y(),
this.number(),
this.size(),
this.name(),
this.resources(),
this.capital(),
this.material(),
this.industry(),
this.population(),
this.colonists(),
this.production(),
this.freeIndustry()
);
}
unpackTo(_o: OtherPlanetT): void {
_o.owner = this.owner();
_o.x = this.x();
_o.y = this.y();
_o.number = this.number();
_o.size = this.size();
_o.name = this.name();
_o.resources = this.resources();
_o.capital = this.capital();
_o.material = this.material();
_o.industry = this.industry();
_o.population = this.population();
_o.colonists = this.colonists();
_o.production = this.production();
_o.freeIndustry = this.freeIndustry();
}
}
export class OtherPlanetT implements flatbuffers.IGeneratedObject {
constructor(
public owner: string|Uint8Array|null = null,
public x: number = 0.0,
public y: number = 0.0,
public number: bigint = BigInt('0'),
public size: number = 0.0,
public name: string|Uint8Array|null = null,
public resources: number = 0.0,
public capital: number = 0.0,
public material: number = 0.0,
public industry: number = 0.0,
public population: number = 0.0,
public colonists: number = 0.0,
public production: string|Uint8Array|null = null,
public freeIndustry: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const owner = (this.owner !== null ? builder.createString(this.owner!) : 0);
const name = (this.name !== null ? builder.createString(this.name!) : 0);
const production = (this.production !== null ? builder.createString(this.production!) : 0);
return OtherPlanet.createOtherPlanet(builder,
owner,
this.x,
this.y,
this.number,
this.size,
name,
this.resources,
this.capital,
this.material,
this.industry,
this.population,
this.colonists,
production,
this.freeIndustry
);
}
}
@@ -0,0 +1,151 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class OtherScience implements flatbuffers.IUnpackableObject<OtherScienceT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):OtherScience {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsOtherScience(bb:flatbuffers.ByteBuffer, obj?:OtherScience):OtherScience {
return (obj || new OtherScience()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsOtherScience(bb:flatbuffers.ByteBuffer, obj?:OtherScience):OtherScience {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new OtherScience()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
race():string|null
race(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
race(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
drive():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
weapons():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
shields():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
cargo():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startOtherScience(builder:flatbuffers.Builder) {
builder.startObject(6);
}
static addRace(builder:flatbuffers.Builder, raceOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, raceOffset, 0);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, nameOffset, 0);
}
static addDrive(builder:flatbuffers.Builder, drive:number) {
builder.addFieldFloat32(2, drive, 0.0);
}
static addWeapons(builder:flatbuffers.Builder, weapons:number) {
builder.addFieldFloat32(3, weapons, 0.0);
}
static addShields(builder:flatbuffers.Builder, shields:number) {
builder.addFieldFloat32(4, shields, 0.0);
}
static addCargo(builder:flatbuffers.Builder, cargo:number) {
builder.addFieldFloat32(5, cargo, 0.0);
}
static endOtherScience(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createOtherScience(builder:flatbuffers.Builder, raceOffset:flatbuffers.Offset, nameOffset:flatbuffers.Offset, drive:number, weapons:number, shields:number, cargo:number):flatbuffers.Offset {
OtherScience.startOtherScience(builder);
OtherScience.addRace(builder, raceOffset);
OtherScience.addName(builder, nameOffset);
OtherScience.addDrive(builder, drive);
OtherScience.addWeapons(builder, weapons);
OtherScience.addShields(builder, shields);
OtherScience.addCargo(builder, cargo);
return OtherScience.endOtherScience(builder);
}
unpack(): OtherScienceT {
return new OtherScienceT(
this.race(),
this.name(),
this.drive(),
this.weapons(),
this.shields(),
this.cargo()
);
}
unpackTo(_o: OtherScienceT): void {
_o.race = this.race();
_o.name = this.name();
_o.drive = this.drive();
_o.weapons = this.weapons();
_o.shields = this.shields();
_o.cargo = this.cargo();
}
}
export class OtherScienceT implements flatbuffers.IGeneratedObject {
constructor(
public race: string|Uint8Array|null = null,
public name: string|Uint8Array|null = null,
public drive: number = 0.0,
public weapons: number = 0.0,
public shields: number = 0.0,
public cargo: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const race = (this.race !== null ? builder.createString(this.race!) : 0);
const name = (this.name !== null ? builder.createString(this.name!) : 0);
return OtherScience.createOtherScience(builder,
race,
name,
this.drive,
this.weapons,
this.shields,
this.cargo
);
}
}
@@ -0,0 +1,179 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class OthersShipClass implements flatbuffers.IUnpackableObject<OthersShipClassT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):OthersShipClass {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsOthersShipClass(bb:flatbuffers.ByteBuffer, obj?:OthersShipClass):OthersShipClass {
return (obj || new OthersShipClass()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsOthersShipClass(bb:flatbuffers.ByteBuffer, obj?:OthersShipClass):OthersShipClass {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new OthersShipClass()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
race():string|null
race(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
race(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
drive():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
armament():bigint {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
weapons():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
shields():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
cargo():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
mass():number {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startOthersShipClass(builder:flatbuffers.Builder) {
builder.startObject(8);
}
static addRace(builder:flatbuffers.Builder, raceOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, raceOffset, 0);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, nameOffset, 0);
}
static addDrive(builder:flatbuffers.Builder, drive:number) {
builder.addFieldFloat32(2, drive, 0.0);
}
static addArmament(builder:flatbuffers.Builder, armament:bigint) {
builder.addFieldInt64(3, armament, BigInt('0'));
}
static addWeapons(builder:flatbuffers.Builder, weapons:number) {
builder.addFieldFloat32(4, weapons, 0.0);
}
static addShields(builder:flatbuffers.Builder, shields:number) {
builder.addFieldFloat32(5, shields, 0.0);
}
static addCargo(builder:flatbuffers.Builder, cargo:number) {
builder.addFieldFloat32(6, cargo, 0.0);
}
static addMass(builder:flatbuffers.Builder, mass:number) {
builder.addFieldFloat32(7, mass, 0.0);
}
static endOthersShipClass(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createOthersShipClass(builder:flatbuffers.Builder, raceOffset:flatbuffers.Offset, nameOffset:flatbuffers.Offset, drive:number, armament:bigint, weapons:number, shields:number, cargo:number, mass:number):flatbuffers.Offset {
OthersShipClass.startOthersShipClass(builder);
OthersShipClass.addRace(builder, raceOffset);
OthersShipClass.addName(builder, nameOffset);
OthersShipClass.addDrive(builder, drive);
OthersShipClass.addArmament(builder, armament);
OthersShipClass.addWeapons(builder, weapons);
OthersShipClass.addShields(builder, shields);
OthersShipClass.addCargo(builder, cargo);
OthersShipClass.addMass(builder, mass);
return OthersShipClass.endOthersShipClass(builder);
}
unpack(): OthersShipClassT {
return new OthersShipClassT(
this.race(),
this.name(),
this.drive(),
this.armament(),
this.weapons(),
this.shields(),
this.cargo(),
this.mass()
);
}
unpackTo(_o: OthersShipClassT): void {
_o.race = this.race();
_o.name = this.name();
_o.drive = this.drive();
_o.armament = this.armament();
_o.weapons = this.weapons();
_o.shields = this.shields();
_o.cargo = this.cargo();
_o.mass = this.mass();
}
}
export class OthersShipClassT implements flatbuffers.IGeneratedObject {
constructor(
public race: string|Uint8Array|null = null,
public name: string|Uint8Array|null = null,
public drive: number = 0.0,
public armament: bigint = BigInt('0'),
public weapons: number = 0.0,
public shields: number = 0.0,
public cargo: number = 0.0,
public mass: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const race = (this.race !== null ? builder.createString(this.race!) : 0);
const name = (this.name !== null ? builder.createString(this.name!) : 0);
return OthersShipClass.createOthersShipClass(builder,
race,
name,
this.drive,
this.armament,
this.weapons,
this.shields,
this.cargo,
this.mass
);
}
}
@@ -0,0 +1,221 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class Player implements flatbuffers.IUnpackableObject<PlayerT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):Player {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsPlayer(bb:flatbuffers.ByteBuffer, obj?:Player):Player {
return (obj || new Player()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsPlayer(bb:flatbuffers.ByteBuffer, obj?:Player):Player {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new Player()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
drive():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
weapons():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
shields():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
cargo():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
population():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
industry():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
planets():number {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readUint16(this.bb_pos + offset) : 0;
}
relation():string|null
relation(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
relation(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
votes():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
extinct():boolean {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}
static startPlayer(builder:flatbuffers.Builder) {
builder.startObject(11);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, nameOffset, 0);
}
static addDrive(builder:flatbuffers.Builder, drive:number) {
builder.addFieldFloat32(1, drive, 0.0);
}
static addWeapons(builder:flatbuffers.Builder, weapons:number) {
builder.addFieldFloat32(2, weapons, 0.0);
}
static addShields(builder:flatbuffers.Builder, shields:number) {
builder.addFieldFloat32(3, shields, 0.0);
}
static addCargo(builder:flatbuffers.Builder, cargo:number) {
builder.addFieldFloat32(4, cargo, 0.0);
}
static addPopulation(builder:flatbuffers.Builder, population:number) {
builder.addFieldFloat32(5, population, 0.0);
}
static addIndustry(builder:flatbuffers.Builder, industry:number) {
builder.addFieldFloat32(6, industry, 0.0);
}
static addPlanets(builder:flatbuffers.Builder, planets:number) {
builder.addFieldInt16(7, planets, 0);
}
static addRelation(builder:flatbuffers.Builder, relationOffset:flatbuffers.Offset) {
builder.addFieldOffset(8, relationOffset, 0);
}
static addVotes(builder:flatbuffers.Builder, votes:number) {
builder.addFieldFloat32(9, votes, 0.0);
}
static addExtinct(builder:flatbuffers.Builder, extinct:boolean) {
builder.addFieldInt8(10, +extinct, +false);
}
static endPlayer(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createPlayer(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, drive:number, weapons:number, shields:number, cargo:number, population:number, industry:number, planets:number, relationOffset:flatbuffers.Offset, votes:number, extinct:boolean):flatbuffers.Offset {
Player.startPlayer(builder);
Player.addName(builder, nameOffset);
Player.addDrive(builder, drive);
Player.addWeapons(builder, weapons);
Player.addShields(builder, shields);
Player.addCargo(builder, cargo);
Player.addPopulation(builder, population);
Player.addIndustry(builder, industry);
Player.addPlanets(builder, planets);
Player.addRelation(builder, relationOffset);
Player.addVotes(builder, votes);
Player.addExtinct(builder, extinct);
return Player.endPlayer(builder);
}
unpack(): PlayerT {
return new PlayerT(
this.name(),
this.drive(),
this.weapons(),
this.shields(),
this.cargo(),
this.population(),
this.industry(),
this.planets(),
this.relation(),
this.votes(),
this.extinct()
);
}
unpackTo(_o: PlayerT): void {
_o.name = this.name();
_o.drive = this.drive();
_o.weapons = this.weapons();
_o.shields = this.shields();
_o.cargo = this.cargo();
_o.population = this.population();
_o.industry = this.industry();
_o.planets = this.planets();
_o.relation = this.relation();
_o.votes = this.votes();
_o.extinct = this.extinct();
}
}
export class PlayerT implements flatbuffers.IGeneratedObject {
constructor(
public name: string|Uint8Array|null = null,
public drive: number = 0.0,
public weapons: number = 0.0,
public shields: number = 0.0,
public cargo: number = 0.0,
public population: number = 0.0,
public industry: number = 0.0,
public planets: number = 0,
public relation: string|Uint8Array|null = null,
public votes: number = 0.0,
public extinct: boolean = false
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const name = (this.name !== null ? builder.createString(this.name!) : 0);
const relation = (this.relation !== null ? builder.createString(this.relation!) : 0);
return Player.createPlayer(builder,
name,
this.drive,
this.weapons,
this.shields,
this.cargo,
this.population,
this.industry,
this.planets,
relation,
this.votes,
this.extinct
);
}
}
@@ -0,0 +1,773 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { UUID, UUIDT } from '../common/uuid.js';
import { Bombing, BombingT } from './bombing.js';
import { IncomingGroup, IncomingGroupT } from './incoming-group.js';
import { LocalFleet, LocalFleetT } from './local-fleet.js';
import { LocalGroup, LocalGroupT } from './local-group.js';
import { LocalPlanet, LocalPlanetT } from './local-planet.js';
import { OtherGroup, OtherGroupT } from './other-group.js';
import { OtherPlanet, OtherPlanetT } from './other-planet.js';
import { OtherScience, OtherScienceT } from './other-science.js';
import { OthersShipClass, OthersShipClassT } from './others-ship-class.js';
import { Player, PlayerT } from './player.js';
import { Route, RouteT } from './route.js';
import { Science, ScienceT } from './science.js';
import { ShipClass, ShipClassT } from './ship-class.js';
import { ShipProduction, ShipProductionT } from './ship-production.js';
import { UnidentifiedGroup, UnidentifiedGroupT } from './unidentified-group.js';
import { UnidentifiedPlanet, UnidentifiedPlanetT } from './unidentified-planet.js';
import { UninhabitedPlanet, UninhabitedPlanetT } from './uninhabited-planet.js';
export class Report implements flatbuffers.IUnpackableObject<ReportT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):Report {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsReport(bb:flatbuffers.ByteBuffer, obj?:Report):Report {
return (obj || new Report()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsReport(bb:flatbuffers.ByteBuffer, obj?:Report):Report {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new Report()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
version():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
turn():bigint {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
width():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
}
height():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
}
planetCount():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
}
race():string|null
race(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
race(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
votes():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
voteFor():string|null
voteFor(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
voteFor(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
player(index: number, obj?:Player):Player|null {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? (obj || new Player()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
playerLength():number {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
localScience(index: number, obj?:Science):Science|null {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? (obj || new Science()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
localScienceLength():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
otherScience(index: number, obj?:OtherScience):OtherScience|null {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? (obj || new OtherScience()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
otherScienceLength():number {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
localShipClass(index: number, obj?:ShipClass):ShipClass|null {
const offset = this.bb!.__offset(this.bb_pos, 26);
return offset ? (obj || new ShipClass()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
localShipClassLength():number {
const offset = this.bb!.__offset(this.bb_pos, 26);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
otherShipClass(index: number, obj?:OthersShipClass):OthersShipClass|null {
const offset = this.bb!.__offset(this.bb_pos, 28);
return offset ? (obj || new OthersShipClass()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
otherShipClassLength():number {
const offset = this.bb!.__offset(this.bb_pos, 28);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
battle(index: number, obj?:UUID):UUID|null {
const offset = this.bb!.__offset(this.bb_pos, 30);
return offset ? (obj || new UUID()).__init(this.bb!.__vector(this.bb_pos + offset) + index * 16, this.bb!) : null;
}
battleLength():number {
const offset = this.bb!.__offset(this.bb_pos, 30);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
bombing(index: number, obj?:Bombing):Bombing|null {
const offset = this.bb!.__offset(this.bb_pos, 32);
return offset ? (obj || new Bombing()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
bombingLength():number {
const offset = this.bb!.__offset(this.bb_pos, 32);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
incomingGroup(index: number, obj?:IncomingGroup):IncomingGroup|null {
const offset = this.bb!.__offset(this.bb_pos, 34);
return offset ? (obj || new IncomingGroup()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
incomingGroupLength():number {
const offset = this.bb!.__offset(this.bb_pos, 34);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
localPlanet(index: number, obj?:LocalPlanet):LocalPlanet|null {
const offset = this.bb!.__offset(this.bb_pos, 36);
return offset ? (obj || new LocalPlanet()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
localPlanetLength():number {
const offset = this.bb!.__offset(this.bb_pos, 36);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
shipProduction(index: number, obj?:ShipProduction):ShipProduction|null {
const offset = this.bb!.__offset(this.bb_pos, 38);
return offset ? (obj || new ShipProduction()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
shipProductionLength():number {
const offset = this.bb!.__offset(this.bb_pos, 38);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
route(index: number, obj?:Route):Route|null {
const offset = this.bb!.__offset(this.bb_pos, 40);
return offset ? (obj || new Route()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
routeLength():number {
const offset = this.bb!.__offset(this.bb_pos, 40);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
otherPlanet(index: number, obj?:OtherPlanet):OtherPlanet|null {
const offset = this.bb!.__offset(this.bb_pos, 42);
return offset ? (obj || new OtherPlanet()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
otherPlanetLength():number {
const offset = this.bb!.__offset(this.bb_pos, 42);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
uninhabitedPlanet(index: number, obj?:UninhabitedPlanet):UninhabitedPlanet|null {
const offset = this.bb!.__offset(this.bb_pos, 44);
return offset ? (obj || new UninhabitedPlanet()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
uninhabitedPlanetLength():number {
const offset = this.bb!.__offset(this.bb_pos, 44);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
unidentifiedPlanet(index: number, obj?:UnidentifiedPlanet):UnidentifiedPlanet|null {
const offset = this.bb!.__offset(this.bb_pos, 46);
return offset ? (obj || new UnidentifiedPlanet()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
unidentifiedPlanetLength():number {
const offset = this.bb!.__offset(this.bb_pos, 46);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
localFleet(index: number, obj?:LocalFleet):LocalFleet|null {
const offset = this.bb!.__offset(this.bb_pos, 48);
return offset ? (obj || new LocalFleet()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
localFleetLength():number {
const offset = this.bb!.__offset(this.bb_pos, 48);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
localGroup(index: number, obj?:LocalGroup):LocalGroup|null {
const offset = this.bb!.__offset(this.bb_pos, 50);
return offset ? (obj || new LocalGroup()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
localGroupLength():number {
const offset = this.bb!.__offset(this.bb_pos, 50);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
otherGroup(index: number, obj?:OtherGroup):OtherGroup|null {
const offset = this.bb!.__offset(this.bb_pos, 52);
return offset ? (obj || new OtherGroup()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
otherGroupLength():number {
const offset = this.bb!.__offset(this.bb_pos, 52);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
unidentifiedGroup(index: number, obj?:UnidentifiedGroup):UnidentifiedGroup|null {
const offset = this.bb!.__offset(this.bb_pos, 54);
return offset ? (obj || new UnidentifiedGroup()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
unidentifiedGroupLength():number {
const offset = this.bb!.__offset(this.bb_pos, 54);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
static startReport(builder:flatbuffers.Builder) {
builder.startObject(26);
}
static addVersion(builder:flatbuffers.Builder, version:bigint) {
builder.addFieldInt64(0, version, BigInt('0'));
}
static addTurn(builder:flatbuffers.Builder, turn:bigint) {
builder.addFieldInt64(1, turn, BigInt('0'));
}
static addWidth(builder:flatbuffers.Builder, width:number) {
builder.addFieldInt32(2, width, 0);
}
static addHeight(builder:flatbuffers.Builder, height:number) {
builder.addFieldInt32(3, height, 0);
}
static addPlanetCount(builder:flatbuffers.Builder, planetCount:number) {
builder.addFieldInt32(4, planetCount, 0);
}
static addRace(builder:flatbuffers.Builder, raceOffset:flatbuffers.Offset) {
builder.addFieldOffset(5, raceOffset, 0);
}
static addVotes(builder:flatbuffers.Builder, votes:number) {
builder.addFieldFloat32(6, votes, 0.0);
}
static addVoteFor(builder:flatbuffers.Builder, voteForOffset:flatbuffers.Offset) {
builder.addFieldOffset(7, voteForOffset, 0);
}
static addPlayer(builder:flatbuffers.Builder, playerOffset:flatbuffers.Offset) {
builder.addFieldOffset(8, playerOffset, 0);
}
static createPlayerVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startPlayerVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addLocalScience(builder:flatbuffers.Builder, localScienceOffset:flatbuffers.Offset) {
builder.addFieldOffset(9, localScienceOffset, 0);
}
static createLocalScienceVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startLocalScienceVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addOtherScience(builder:flatbuffers.Builder, otherScienceOffset:flatbuffers.Offset) {
builder.addFieldOffset(10, otherScienceOffset, 0);
}
static createOtherScienceVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startOtherScienceVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addLocalShipClass(builder:flatbuffers.Builder, localShipClassOffset:flatbuffers.Offset) {
builder.addFieldOffset(11, localShipClassOffset, 0);
}
static createLocalShipClassVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startLocalShipClassVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addOtherShipClass(builder:flatbuffers.Builder, otherShipClassOffset:flatbuffers.Offset) {
builder.addFieldOffset(12, otherShipClassOffset, 0);
}
static createOtherShipClassVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startOtherShipClassVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addBattle(builder:flatbuffers.Builder, battleOffset:flatbuffers.Offset) {
builder.addFieldOffset(13, battleOffset, 0);
}
static startBattleVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(16, numElems, 8);
}
static addBombing(builder:flatbuffers.Builder, bombingOffset:flatbuffers.Offset) {
builder.addFieldOffset(14, bombingOffset, 0);
}
static createBombingVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startBombingVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addIncomingGroup(builder:flatbuffers.Builder, incomingGroupOffset:flatbuffers.Offset) {
builder.addFieldOffset(15, incomingGroupOffset, 0);
}
static createIncomingGroupVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startIncomingGroupVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addLocalPlanet(builder:flatbuffers.Builder, localPlanetOffset:flatbuffers.Offset) {
builder.addFieldOffset(16, localPlanetOffset, 0);
}
static createLocalPlanetVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startLocalPlanetVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addShipProduction(builder:flatbuffers.Builder, shipProductionOffset:flatbuffers.Offset) {
builder.addFieldOffset(17, shipProductionOffset, 0);
}
static createShipProductionVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startShipProductionVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addRoute(builder:flatbuffers.Builder, routeOffset:flatbuffers.Offset) {
builder.addFieldOffset(18, routeOffset, 0);
}
static createRouteVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startRouteVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addOtherPlanet(builder:flatbuffers.Builder, otherPlanetOffset:flatbuffers.Offset) {
builder.addFieldOffset(19, otherPlanetOffset, 0);
}
static createOtherPlanetVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startOtherPlanetVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addUninhabitedPlanet(builder:flatbuffers.Builder, uninhabitedPlanetOffset:flatbuffers.Offset) {
builder.addFieldOffset(20, uninhabitedPlanetOffset, 0);
}
static createUninhabitedPlanetVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startUninhabitedPlanetVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addUnidentifiedPlanet(builder:flatbuffers.Builder, unidentifiedPlanetOffset:flatbuffers.Offset) {
builder.addFieldOffset(21, unidentifiedPlanetOffset, 0);
}
static createUnidentifiedPlanetVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startUnidentifiedPlanetVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addLocalFleet(builder:flatbuffers.Builder, localFleetOffset:flatbuffers.Offset) {
builder.addFieldOffset(22, localFleetOffset, 0);
}
static createLocalFleetVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startLocalFleetVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addLocalGroup(builder:flatbuffers.Builder, localGroupOffset:flatbuffers.Offset) {
builder.addFieldOffset(23, localGroupOffset, 0);
}
static createLocalGroupVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startLocalGroupVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addOtherGroup(builder:flatbuffers.Builder, otherGroupOffset:flatbuffers.Offset) {
builder.addFieldOffset(24, otherGroupOffset, 0);
}
static createOtherGroupVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startOtherGroupVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addUnidentifiedGroup(builder:flatbuffers.Builder, unidentifiedGroupOffset:flatbuffers.Offset) {
builder.addFieldOffset(25, unidentifiedGroupOffset, 0);
}
static createUnidentifiedGroupVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startUnidentifiedGroupVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static endReport(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static finishReportBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
builder.finish(offset);
}
static finishSizePrefixedReportBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
builder.finish(offset, undefined, true);
}
static createReport(builder:flatbuffers.Builder, version:bigint, turn:bigint, width:number, height:number, planetCount:number, raceOffset:flatbuffers.Offset, votes:number, voteForOffset:flatbuffers.Offset, playerOffset:flatbuffers.Offset, localScienceOffset:flatbuffers.Offset, otherScienceOffset:flatbuffers.Offset, localShipClassOffset:flatbuffers.Offset, otherShipClassOffset:flatbuffers.Offset, battleOffset:flatbuffers.Offset, bombingOffset:flatbuffers.Offset, incomingGroupOffset:flatbuffers.Offset, localPlanetOffset:flatbuffers.Offset, shipProductionOffset:flatbuffers.Offset, routeOffset:flatbuffers.Offset, otherPlanetOffset:flatbuffers.Offset, uninhabitedPlanetOffset:flatbuffers.Offset, unidentifiedPlanetOffset:flatbuffers.Offset, localFleetOffset:flatbuffers.Offset, localGroupOffset:flatbuffers.Offset, otherGroupOffset:flatbuffers.Offset, unidentifiedGroupOffset:flatbuffers.Offset):flatbuffers.Offset {
Report.startReport(builder);
Report.addVersion(builder, version);
Report.addTurn(builder, turn);
Report.addWidth(builder, width);
Report.addHeight(builder, height);
Report.addPlanetCount(builder, planetCount);
Report.addRace(builder, raceOffset);
Report.addVotes(builder, votes);
Report.addVoteFor(builder, voteForOffset);
Report.addPlayer(builder, playerOffset);
Report.addLocalScience(builder, localScienceOffset);
Report.addOtherScience(builder, otherScienceOffset);
Report.addLocalShipClass(builder, localShipClassOffset);
Report.addOtherShipClass(builder, otherShipClassOffset);
Report.addBattle(builder, battleOffset);
Report.addBombing(builder, bombingOffset);
Report.addIncomingGroup(builder, incomingGroupOffset);
Report.addLocalPlanet(builder, localPlanetOffset);
Report.addShipProduction(builder, shipProductionOffset);
Report.addRoute(builder, routeOffset);
Report.addOtherPlanet(builder, otherPlanetOffset);
Report.addUninhabitedPlanet(builder, uninhabitedPlanetOffset);
Report.addUnidentifiedPlanet(builder, unidentifiedPlanetOffset);
Report.addLocalFleet(builder, localFleetOffset);
Report.addLocalGroup(builder, localGroupOffset);
Report.addOtherGroup(builder, otherGroupOffset);
Report.addUnidentifiedGroup(builder, unidentifiedGroupOffset);
return Report.endReport(builder);
}
unpack(): ReportT {
return new ReportT(
this.version(),
this.turn(),
this.width(),
this.height(),
this.planetCount(),
this.race(),
this.votes(),
this.voteFor(),
this.bb!.createObjList<Player, PlayerT>(this.player.bind(this), this.playerLength()),
this.bb!.createObjList<Science, ScienceT>(this.localScience.bind(this), this.localScienceLength()),
this.bb!.createObjList<OtherScience, OtherScienceT>(this.otherScience.bind(this), this.otherScienceLength()),
this.bb!.createObjList<ShipClass, ShipClassT>(this.localShipClass.bind(this), this.localShipClassLength()),
this.bb!.createObjList<OthersShipClass, OthersShipClassT>(this.otherShipClass.bind(this), this.otherShipClassLength()),
this.bb!.createObjList<UUID, UUIDT>(this.battle.bind(this), this.battleLength()),
this.bb!.createObjList<Bombing, BombingT>(this.bombing.bind(this), this.bombingLength()),
this.bb!.createObjList<IncomingGroup, IncomingGroupT>(this.incomingGroup.bind(this), this.incomingGroupLength()),
this.bb!.createObjList<LocalPlanet, LocalPlanetT>(this.localPlanet.bind(this), this.localPlanetLength()),
this.bb!.createObjList<ShipProduction, ShipProductionT>(this.shipProduction.bind(this), this.shipProductionLength()),
this.bb!.createObjList<Route, RouteT>(this.route.bind(this), this.routeLength()),
this.bb!.createObjList<OtherPlanet, OtherPlanetT>(this.otherPlanet.bind(this), this.otherPlanetLength()),
this.bb!.createObjList<UninhabitedPlanet, UninhabitedPlanetT>(this.uninhabitedPlanet.bind(this), this.uninhabitedPlanetLength()),
this.bb!.createObjList<UnidentifiedPlanet, UnidentifiedPlanetT>(this.unidentifiedPlanet.bind(this), this.unidentifiedPlanetLength()),
this.bb!.createObjList<LocalFleet, LocalFleetT>(this.localFleet.bind(this), this.localFleetLength()),
this.bb!.createObjList<LocalGroup, LocalGroupT>(this.localGroup.bind(this), this.localGroupLength()),
this.bb!.createObjList<OtherGroup, OtherGroupT>(this.otherGroup.bind(this), this.otherGroupLength()),
this.bb!.createObjList<UnidentifiedGroup, UnidentifiedGroupT>(this.unidentifiedGroup.bind(this), this.unidentifiedGroupLength())
);
}
unpackTo(_o: ReportT): void {
_o.version = this.version();
_o.turn = this.turn();
_o.width = this.width();
_o.height = this.height();
_o.planetCount = this.planetCount();
_o.race = this.race();
_o.votes = this.votes();
_o.voteFor = this.voteFor();
_o.player = this.bb!.createObjList<Player, PlayerT>(this.player.bind(this), this.playerLength());
_o.localScience = this.bb!.createObjList<Science, ScienceT>(this.localScience.bind(this), this.localScienceLength());
_o.otherScience = this.bb!.createObjList<OtherScience, OtherScienceT>(this.otherScience.bind(this), this.otherScienceLength());
_o.localShipClass = this.bb!.createObjList<ShipClass, ShipClassT>(this.localShipClass.bind(this), this.localShipClassLength());
_o.otherShipClass = this.bb!.createObjList<OthersShipClass, OthersShipClassT>(this.otherShipClass.bind(this), this.otherShipClassLength());
_o.battle = this.bb!.createObjList<UUID, UUIDT>(this.battle.bind(this), this.battleLength());
_o.bombing = this.bb!.createObjList<Bombing, BombingT>(this.bombing.bind(this), this.bombingLength());
_o.incomingGroup = this.bb!.createObjList<IncomingGroup, IncomingGroupT>(this.incomingGroup.bind(this), this.incomingGroupLength());
_o.localPlanet = this.bb!.createObjList<LocalPlanet, LocalPlanetT>(this.localPlanet.bind(this), this.localPlanetLength());
_o.shipProduction = this.bb!.createObjList<ShipProduction, ShipProductionT>(this.shipProduction.bind(this), this.shipProductionLength());
_o.route = this.bb!.createObjList<Route, RouteT>(this.route.bind(this), this.routeLength());
_o.otherPlanet = this.bb!.createObjList<OtherPlanet, OtherPlanetT>(this.otherPlanet.bind(this), this.otherPlanetLength());
_o.uninhabitedPlanet = this.bb!.createObjList<UninhabitedPlanet, UninhabitedPlanetT>(this.uninhabitedPlanet.bind(this), this.uninhabitedPlanetLength());
_o.unidentifiedPlanet = this.bb!.createObjList<UnidentifiedPlanet, UnidentifiedPlanetT>(this.unidentifiedPlanet.bind(this), this.unidentifiedPlanetLength());
_o.localFleet = this.bb!.createObjList<LocalFleet, LocalFleetT>(this.localFleet.bind(this), this.localFleetLength());
_o.localGroup = this.bb!.createObjList<LocalGroup, LocalGroupT>(this.localGroup.bind(this), this.localGroupLength());
_o.otherGroup = this.bb!.createObjList<OtherGroup, OtherGroupT>(this.otherGroup.bind(this), this.otherGroupLength());
_o.unidentifiedGroup = this.bb!.createObjList<UnidentifiedGroup, UnidentifiedGroupT>(this.unidentifiedGroup.bind(this), this.unidentifiedGroupLength());
}
}
export class ReportT implements flatbuffers.IGeneratedObject {
constructor(
public version: bigint = BigInt('0'),
public turn: bigint = BigInt('0'),
public width: number = 0,
public height: number = 0,
public planetCount: number = 0,
public race: string|Uint8Array|null = null,
public votes: number = 0.0,
public voteFor: string|Uint8Array|null = null,
public player: (PlayerT)[] = [],
public localScience: (ScienceT)[] = [],
public otherScience: (OtherScienceT)[] = [],
public localShipClass: (ShipClassT)[] = [],
public otherShipClass: (OthersShipClassT)[] = [],
public battle: (UUIDT)[] = [],
public bombing: (BombingT)[] = [],
public incomingGroup: (IncomingGroupT)[] = [],
public localPlanet: (LocalPlanetT)[] = [],
public shipProduction: (ShipProductionT)[] = [],
public route: (RouteT)[] = [],
public otherPlanet: (OtherPlanetT)[] = [],
public uninhabitedPlanet: (UninhabitedPlanetT)[] = [],
public unidentifiedPlanet: (UnidentifiedPlanetT)[] = [],
public localFleet: (LocalFleetT)[] = [],
public localGroup: (LocalGroupT)[] = [],
public otherGroup: (OtherGroupT)[] = [],
public unidentifiedGroup: (UnidentifiedGroupT)[] = []
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const race = (this.race !== null ? builder.createString(this.race!) : 0);
const voteFor = (this.voteFor !== null ? builder.createString(this.voteFor!) : 0);
const player = Report.createPlayerVector(builder, builder.createObjectOffsetList(this.player));
const localScience = Report.createLocalScienceVector(builder, builder.createObjectOffsetList(this.localScience));
const otherScience = Report.createOtherScienceVector(builder, builder.createObjectOffsetList(this.otherScience));
const localShipClass = Report.createLocalShipClassVector(builder, builder.createObjectOffsetList(this.localShipClass));
const otherShipClass = Report.createOtherShipClassVector(builder, builder.createObjectOffsetList(this.otherShipClass));
const battle = builder.createStructOffsetList(this.battle, Report.startBattleVector);
const bombing = Report.createBombingVector(builder, builder.createObjectOffsetList(this.bombing));
const incomingGroup = Report.createIncomingGroupVector(builder, builder.createObjectOffsetList(this.incomingGroup));
const localPlanet = Report.createLocalPlanetVector(builder, builder.createObjectOffsetList(this.localPlanet));
const shipProduction = Report.createShipProductionVector(builder, builder.createObjectOffsetList(this.shipProduction));
const route = Report.createRouteVector(builder, builder.createObjectOffsetList(this.route));
const otherPlanet = Report.createOtherPlanetVector(builder, builder.createObjectOffsetList(this.otherPlanet));
const uninhabitedPlanet = Report.createUninhabitedPlanetVector(builder, builder.createObjectOffsetList(this.uninhabitedPlanet));
const unidentifiedPlanet = Report.createUnidentifiedPlanetVector(builder, builder.createObjectOffsetList(this.unidentifiedPlanet));
const localFleet = Report.createLocalFleetVector(builder, builder.createObjectOffsetList(this.localFleet));
const localGroup = Report.createLocalGroupVector(builder, builder.createObjectOffsetList(this.localGroup));
const otherGroup = Report.createOtherGroupVector(builder, builder.createObjectOffsetList(this.otherGroup));
const unidentifiedGroup = Report.createUnidentifiedGroupVector(builder, builder.createObjectOffsetList(this.unidentifiedGroup));
return Report.createReport(builder,
this.version,
this.turn,
this.width,
this.height,
this.planetCount,
race,
this.votes,
voteFor,
player,
localScience,
otherScience,
localShipClass,
otherShipClass,
battle,
bombing,
incomingGroup,
localPlanet,
shipProduction,
route,
otherPlanet,
uninhabitedPlanet,
unidentifiedPlanet,
localFleet,
localGroup,
otherGroup,
unidentifiedGroup
);
}
}
@@ -0,0 +1,92 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class RouteEntry implements flatbuffers.IUnpackableObject<RouteEntryT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):RouteEntry {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsRouteEntry(bb:flatbuffers.ByteBuffer, obj?:RouteEntry):RouteEntry {
return (obj || new RouteEntry()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsRouteEntry(bb:flatbuffers.ByteBuffer, obj?:RouteEntry):RouteEntry {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new RouteEntry()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
key():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
value():string|null
value(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
value(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
static startRouteEntry(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addKey(builder:flatbuffers.Builder, key:bigint) {
builder.addFieldInt64(0, key, BigInt('0'));
}
static addValue(builder:flatbuffers.Builder, valueOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, valueOffset, 0);
}
static endRouteEntry(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createRouteEntry(builder:flatbuffers.Builder, key:bigint, valueOffset:flatbuffers.Offset):flatbuffers.Offset {
RouteEntry.startRouteEntry(builder);
RouteEntry.addKey(builder, key);
RouteEntry.addValue(builder, valueOffset);
return RouteEntry.endRouteEntry(builder);
}
unpack(): RouteEntryT {
return new RouteEntryT(
this.key(),
this.value()
);
}
unpackTo(_o: RouteEntryT): void {
_o.key = this.key();
_o.value = this.value();
}
}
export class RouteEntryT implements flatbuffers.IGeneratedObject {
constructor(
public key: bigint = BigInt('0'),
public value: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const value = (this.value !== null ? builder.createString(this.value!) : 0);
return RouteEntry.createRouteEntry(builder,
this.key,
value
);
}
}
@@ -0,0 +1,108 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { RouteEntry, RouteEntryT } from './route-entry.js';
export class Route implements flatbuffers.IUnpackableObject<RouteT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):Route {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsRoute(bb:flatbuffers.ByteBuffer, obj?:Route):Route {
return (obj || new Route()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsRoute(bb:flatbuffers.ByteBuffer, obj?:Route):Route {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new Route()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
planet():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
route(index: number, obj?:RouteEntry):RouteEntry|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? (obj || new RouteEntry()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
routeLength():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
static startRoute(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addPlanet(builder:flatbuffers.Builder, planet:bigint) {
builder.addFieldInt64(0, planet, BigInt('0'));
}
static addRoute(builder:flatbuffers.Builder, routeOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, routeOffset, 0);
}
static createRouteVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startRouteVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static endRoute(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createRoute(builder:flatbuffers.Builder, planet:bigint, routeOffset:flatbuffers.Offset):flatbuffers.Offset {
Route.startRoute(builder);
Route.addPlanet(builder, planet);
Route.addRoute(builder, routeOffset);
return Route.endRoute(builder);
}
unpack(): RouteT {
return new RouteT(
this.planet(),
this.bb!.createObjList<RouteEntry, RouteEntryT>(this.route.bind(this), this.routeLength())
);
}
unpackTo(_o: RouteT): void {
_o.planet = this.planet();
_o.route = this.bb!.createObjList<RouteEntry, RouteEntryT>(this.route.bind(this), this.routeLength());
}
}
export class RouteT implements flatbuffers.IGeneratedObject {
constructor(
public planet: bigint = BigInt('0'),
public route: (RouteEntryT)[] = []
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const route = Route.createRouteVector(builder, builder.createObjectOffsetList(this.route));
return Route.createRoute(builder,
this.planet,
route
);
}
}
@@ -0,0 +1,134 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class Science implements flatbuffers.IUnpackableObject<ScienceT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):Science {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsScience(bb:flatbuffers.ByteBuffer, obj?:Science):Science {
return (obj || new Science()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsScience(bb:flatbuffers.ByteBuffer, obj?:Science):Science {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new Science()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
drive():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
weapons():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
shields():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
cargo():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startScience(builder:flatbuffers.Builder) {
builder.startObject(5);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, nameOffset, 0);
}
static addDrive(builder:flatbuffers.Builder, drive:number) {
builder.addFieldFloat32(1, drive, 0.0);
}
static addWeapons(builder:flatbuffers.Builder, weapons:number) {
builder.addFieldFloat32(2, weapons, 0.0);
}
static addShields(builder:flatbuffers.Builder, shields:number) {
builder.addFieldFloat32(3, shields, 0.0);
}
static addCargo(builder:flatbuffers.Builder, cargo:number) {
builder.addFieldFloat32(4, cargo, 0.0);
}
static endScience(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createScience(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, drive:number, weapons:number, shields:number, cargo:number):flatbuffers.Offset {
Science.startScience(builder);
Science.addName(builder, nameOffset);
Science.addDrive(builder, drive);
Science.addWeapons(builder, weapons);
Science.addShields(builder, shields);
Science.addCargo(builder, cargo);
return Science.endScience(builder);
}
unpack(): ScienceT {
return new ScienceT(
this.name(),
this.drive(),
this.weapons(),
this.shields(),
this.cargo()
);
}
unpackTo(_o: ScienceT): void {
_o.name = this.name();
_o.drive = this.drive();
_o.weapons = this.weapons();
_o.shields = this.shields();
_o.cargo = this.cargo();
}
}
export class ScienceT implements flatbuffers.IGeneratedObject {
constructor(
public name: string|Uint8Array|null = null,
public drive: number = 0.0,
public weapons: number = 0.0,
public shields: number = 0.0,
public cargo: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const name = (this.name !== null ? builder.createString(this.name!) : 0);
return Science.createScience(builder,
name,
this.drive,
this.weapons,
this.shields,
this.cargo
);
}
}
@@ -0,0 +1,162 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ShipClass implements flatbuffers.IUnpackableObject<ShipClassT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ShipClass {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsShipClass(bb:flatbuffers.ByteBuffer, obj?:ShipClass):ShipClass {
return (obj || new ShipClass()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsShipClass(bb:flatbuffers.ByteBuffer, obj?:ShipClass):ShipClass {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ShipClass()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
drive():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
armament():bigint {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
weapons():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
shields():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
cargo():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
mass():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startShipClass(builder:flatbuffers.Builder) {
builder.startObject(7);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, nameOffset, 0);
}
static addDrive(builder:flatbuffers.Builder, drive:number) {
builder.addFieldFloat32(1, drive, 0.0);
}
static addArmament(builder:flatbuffers.Builder, armament:bigint) {
builder.addFieldInt64(2, armament, BigInt('0'));
}
static addWeapons(builder:flatbuffers.Builder, weapons:number) {
builder.addFieldFloat32(3, weapons, 0.0);
}
static addShields(builder:flatbuffers.Builder, shields:number) {
builder.addFieldFloat32(4, shields, 0.0);
}
static addCargo(builder:flatbuffers.Builder, cargo:number) {
builder.addFieldFloat32(5, cargo, 0.0);
}
static addMass(builder:flatbuffers.Builder, mass:number) {
builder.addFieldFloat32(6, mass, 0.0);
}
static endShipClass(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createShipClass(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, drive:number, armament:bigint, weapons:number, shields:number, cargo:number, mass:number):flatbuffers.Offset {
ShipClass.startShipClass(builder);
ShipClass.addName(builder, nameOffset);
ShipClass.addDrive(builder, drive);
ShipClass.addArmament(builder, armament);
ShipClass.addWeapons(builder, weapons);
ShipClass.addShields(builder, shields);
ShipClass.addCargo(builder, cargo);
ShipClass.addMass(builder, mass);
return ShipClass.endShipClass(builder);
}
unpack(): ShipClassT {
return new ShipClassT(
this.name(),
this.drive(),
this.armament(),
this.weapons(),
this.shields(),
this.cargo(),
this.mass()
);
}
unpackTo(_o: ShipClassT): void {
_o.name = this.name();
_o.drive = this.drive();
_o.armament = this.armament();
_o.weapons = this.weapons();
_o.shields = this.shields();
_o.cargo = this.cargo();
_o.mass = this.mass();
}
}
export class ShipClassT implements flatbuffers.IGeneratedObject {
constructor(
public name: string|Uint8Array|null = null,
public drive: number = 0.0,
public armament: bigint = BigInt('0'),
public weapons: number = 0.0,
public shields: number = 0.0,
public cargo: number = 0.0,
public mass: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const name = (this.name !== null ? builder.createString(this.name!) : 0);
return ShipClass.createShipClass(builder,
name,
this.drive,
this.armament,
this.weapons,
this.shields,
this.cargo,
this.mass
);
}
}
@@ -0,0 +1,148 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ShipProduction implements flatbuffers.IUnpackableObject<ShipProductionT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ShipProduction {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsShipProduction(bb:flatbuffers.ByteBuffer, obj?:ShipProduction):ShipProduction {
return (obj || new ShipProduction()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsShipProduction(bb:flatbuffers.ByteBuffer, obj?:ShipProduction):ShipProduction {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ShipProduction()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
planet():bigint {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
class_():string|null
class_(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
class_(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
cost():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
prodUsed():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
percent():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
free():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startShipProduction(builder:flatbuffers.Builder) {
builder.startObject(6);
}
static addPlanet(builder:flatbuffers.Builder, planet:bigint) {
builder.addFieldInt64(0, planet, BigInt('0'));
}
static addClass(builder:flatbuffers.Builder, class_Offset:flatbuffers.Offset) {
builder.addFieldOffset(1, class_Offset, 0);
}
static addCost(builder:flatbuffers.Builder, cost:number) {
builder.addFieldFloat32(2, cost, 0.0);
}
static addProdUsed(builder:flatbuffers.Builder, prodUsed:number) {
builder.addFieldFloat32(3, prodUsed, 0.0);
}
static addPercent(builder:flatbuffers.Builder, percent:number) {
builder.addFieldFloat32(4, percent, 0.0);
}
static addFree(builder:flatbuffers.Builder, free:number) {
builder.addFieldFloat32(5, free, 0.0);
}
static endShipProduction(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createShipProduction(builder:flatbuffers.Builder, planet:bigint, class_Offset:flatbuffers.Offset, cost:number, prodUsed:number, percent:number, free:number):flatbuffers.Offset {
ShipProduction.startShipProduction(builder);
ShipProduction.addPlanet(builder, planet);
ShipProduction.addClass(builder, class_Offset);
ShipProduction.addCost(builder, cost);
ShipProduction.addProdUsed(builder, prodUsed);
ShipProduction.addPercent(builder, percent);
ShipProduction.addFree(builder, free);
return ShipProduction.endShipProduction(builder);
}
unpack(): ShipProductionT {
return new ShipProductionT(
this.planet(),
this.class_(),
this.cost(),
this.prodUsed(),
this.percent(),
this.free()
);
}
unpackTo(_o: ShipProductionT): void {
_o.planet = this.planet();
_o.class_ = this.class_();
_o.cost = this.cost();
_o.prodUsed = this.prodUsed();
_o.percent = this.percent();
_o.free = this.free();
}
}
export class ShipProductionT implements flatbuffers.IGeneratedObject {
constructor(
public planet: bigint = BigInt('0'),
public class_: string|Uint8Array|null = null,
public cost: number = 0.0,
public prodUsed: number = 0.0,
public percent: number = 0.0,
public free: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const class_ = (this.class_ !== null ? builder.createString(this.class_!) : 0);
return ShipProduction.createShipProduction(builder,
this.planet,
class_,
this.cost,
this.prodUsed,
this.percent,
this.free
);
}
}
@@ -0,0 +1,92 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class TechEntry implements flatbuffers.IUnpackableObject<TechEntryT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):TechEntry {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsTechEntry(bb:flatbuffers.ByteBuffer, obj?:TechEntry):TechEntry {
return (obj || new TechEntry()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsTechEntry(bb:flatbuffers.ByteBuffer, obj?:TechEntry):TechEntry {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new TechEntry()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
key():string|null
key(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
key(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
value():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startTechEntry(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addKey(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, keyOffset, 0);
}
static addValue(builder:flatbuffers.Builder, value:number) {
builder.addFieldFloat32(1, value, 0.0);
}
static endTechEntry(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createTechEntry(builder:flatbuffers.Builder, keyOffset:flatbuffers.Offset, value:number):flatbuffers.Offset {
TechEntry.startTechEntry(builder);
TechEntry.addKey(builder, keyOffset);
TechEntry.addValue(builder, value);
return TechEntry.endTechEntry(builder);
}
unpack(): TechEntryT {
return new TechEntryT(
this.key(),
this.value()
);
}
unpackTo(_o: TechEntryT): void {
_o.key = this.key();
_o.value = this.value();
}
}
export class TechEntryT implements flatbuffers.IGeneratedObject {
constructor(
public key: string|Uint8Array|null = null,
public value: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const key = (this.key !== null ? builder.createString(this.key!) : 0);
return TechEntry.createTechEntry(builder,
key,
this.value
);
}
}
@@ -0,0 +1,88 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class UnidentifiedGroup implements flatbuffers.IUnpackableObject<UnidentifiedGroupT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):UnidentifiedGroup {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsUnidentifiedGroup(bb:flatbuffers.ByteBuffer, obj?:UnidentifiedGroup):UnidentifiedGroup {
return (obj || new UnidentifiedGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsUnidentifiedGroup(bb:flatbuffers.ByteBuffer, obj?:UnidentifiedGroup):UnidentifiedGroup {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new UnidentifiedGroup()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
x():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
y():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startUnidentifiedGroup(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addX(builder:flatbuffers.Builder, x:number) {
builder.addFieldFloat32(0, x, 0.0);
}
static addY(builder:flatbuffers.Builder, y:number) {
builder.addFieldFloat32(1, y, 0.0);
}
static endUnidentifiedGroup(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createUnidentifiedGroup(builder:flatbuffers.Builder, x:number, y:number):flatbuffers.Offset {
UnidentifiedGroup.startUnidentifiedGroup(builder);
UnidentifiedGroup.addX(builder, x);
UnidentifiedGroup.addY(builder, y);
return UnidentifiedGroup.endUnidentifiedGroup(builder);
}
unpack(): UnidentifiedGroupT {
return new UnidentifiedGroupT(
this.x(),
this.y()
);
}
unpackTo(_o: UnidentifiedGroupT): void {
_o.x = this.x();
_o.y = this.y();
}
}
export class UnidentifiedGroupT implements flatbuffers.IGeneratedObject {
constructor(
public x: number = 0.0,
public y: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return UnidentifiedGroup.createUnidentifiedGroup(builder,
this.x,
this.y
);
}
}
@@ -0,0 +1,102 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class UnidentifiedPlanet implements flatbuffers.IUnpackableObject<UnidentifiedPlanetT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):UnidentifiedPlanet {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsUnidentifiedPlanet(bb:flatbuffers.ByteBuffer, obj?:UnidentifiedPlanet):UnidentifiedPlanet {
return (obj || new UnidentifiedPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsUnidentifiedPlanet(bb:flatbuffers.ByteBuffer, obj?:UnidentifiedPlanet):UnidentifiedPlanet {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new UnidentifiedPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
x():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
y():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
number():bigint {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
static startUnidentifiedPlanet(builder:flatbuffers.Builder) {
builder.startObject(3);
}
static addX(builder:flatbuffers.Builder, x:number) {
builder.addFieldFloat32(0, x, 0.0);
}
static addY(builder:flatbuffers.Builder, y:number) {
builder.addFieldFloat32(1, y, 0.0);
}
static addNumber(builder:flatbuffers.Builder, number:bigint) {
builder.addFieldInt64(2, number, BigInt('0'));
}
static endUnidentifiedPlanet(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createUnidentifiedPlanet(builder:flatbuffers.Builder, x:number, y:number, number:bigint):flatbuffers.Offset {
UnidentifiedPlanet.startUnidentifiedPlanet(builder);
UnidentifiedPlanet.addX(builder, x);
UnidentifiedPlanet.addY(builder, y);
UnidentifiedPlanet.addNumber(builder, number);
return UnidentifiedPlanet.endUnidentifiedPlanet(builder);
}
unpack(): UnidentifiedPlanetT {
return new UnidentifiedPlanetT(
this.x(),
this.y(),
this.number()
);
}
unpackTo(_o: UnidentifiedPlanetT): void {
_o.x = this.x();
_o.y = this.y();
_o.number = this.number();
}
}
export class UnidentifiedPlanetT implements flatbuffers.IGeneratedObject {
constructor(
public x: number = 0.0,
public y: number = 0.0,
public number: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return UnidentifiedPlanet.createUnidentifiedPlanet(builder,
this.x,
this.y,
this.number
);
}
}
@@ -0,0 +1,176 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class UninhabitedPlanet implements flatbuffers.IUnpackableObject<UninhabitedPlanetT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):UninhabitedPlanet {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsUninhabitedPlanet(bb:flatbuffers.ByteBuffer, obj?:UninhabitedPlanet):UninhabitedPlanet {
return (obj || new UninhabitedPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsUninhabitedPlanet(bb:flatbuffers.ByteBuffer, obj?:UninhabitedPlanet):UninhabitedPlanet {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new UninhabitedPlanet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
x():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
y():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
number():bigint {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}
size():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
resources():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
capital():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
material():number {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
}
static startUninhabitedPlanet(builder:flatbuffers.Builder) {
builder.startObject(8);
}
static addX(builder:flatbuffers.Builder, x:number) {
builder.addFieldFloat32(0, x, 0.0);
}
static addY(builder:flatbuffers.Builder, y:number) {
builder.addFieldFloat32(1, y, 0.0);
}
static addNumber(builder:flatbuffers.Builder, number:bigint) {
builder.addFieldInt64(2, number, BigInt('0'));
}
static addSize(builder:flatbuffers.Builder, size:number) {
builder.addFieldFloat32(3, size, 0.0);
}
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, nameOffset, 0);
}
static addResources(builder:flatbuffers.Builder, resources:number) {
builder.addFieldFloat32(5, resources, 0.0);
}
static addCapital(builder:flatbuffers.Builder, capital:number) {
builder.addFieldFloat32(6, capital, 0.0);
}
static addMaterial(builder:flatbuffers.Builder, material:number) {
builder.addFieldFloat32(7, material, 0.0);
}
static endUninhabitedPlanet(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createUninhabitedPlanet(builder:flatbuffers.Builder, x:number, y:number, number:bigint, size:number, nameOffset:flatbuffers.Offset, resources:number, capital:number, material:number):flatbuffers.Offset {
UninhabitedPlanet.startUninhabitedPlanet(builder);
UninhabitedPlanet.addX(builder, x);
UninhabitedPlanet.addY(builder, y);
UninhabitedPlanet.addNumber(builder, number);
UninhabitedPlanet.addSize(builder, size);
UninhabitedPlanet.addName(builder, nameOffset);
UninhabitedPlanet.addResources(builder, resources);
UninhabitedPlanet.addCapital(builder, capital);
UninhabitedPlanet.addMaterial(builder, material);
return UninhabitedPlanet.endUninhabitedPlanet(builder);
}
unpack(): UninhabitedPlanetT {
return new UninhabitedPlanetT(
this.x(),
this.y(),
this.number(),
this.size(),
this.name(),
this.resources(),
this.capital(),
this.material()
);
}
unpackTo(_o: UninhabitedPlanetT): void {
_o.x = this.x();
_o.y = this.y();
_o.number = this.number();
_o.size = this.size();
_o.name = this.name();
_o.resources = this.resources();
_o.capital = this.capital();
_o.material = this.material();
}
}
export class UninhabitedPlanetT implements flatbuffers.IGeneratedObject {
constructor(
public x: number = 0.0,
public y: number = 0.0,
public number: bigint = BigInt('0'),
public size: number = 0.0,
public name: string|Uint8Array|null = null,
public resources: number = 0.0,
public capital: number = 0.0,
public material: number = 0.0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const name = (this.name !== null ? builder.createString(this.name!) : 0);
return UninhabitedPlanet.createUninhabitedPlanet(builder,
this.x,
this.y,
this.number,
this.size,
name,
this.resources,
this.capital,
this.material
);
}
}
@@ -12,11 +12,20 @@ layout owns:
header view-menu naturally drops the overlay even if `mobileTool`
was set on a previous tap.
Phase 11 adds the per-game `GameStateStore` instance owned by this
layout: it constructs the `GalaxyClient`, fetches the matching lobby
record to discover `current_turn`, then loads the report. The store
is shared with descendants via `setContext("gameState", ...)` so the
header turn counter, the map view, and later inspector tabs all read
from the same snapshot.
State preservation across active-view switches works for free
because SvelteKit keeps this layout instance mounted while children
swap.
swap; navigating between games unmounts and remounts the layout, so
the next game's snapshot is loaded fresh.
-->
<script lang="ts">
import { onDestroy, onMount, setContext } from "svelte";
import { page } from "$app/state";
import Header from "$lib/header/header.svelte";
import Sidebar from "$lib/sidebar/sidebar.svelte";
@@ -24,6 +33,13 @@ swap.
import Calculator from "$lib/sidebar/calculator-tab.svelte";
import Order from "$lib/sidebar/order-tab.svelte";
import type { MobileTool } from "$lib/sidebar/types";
import { GameStateStore, GAME_STATE_CONTEXT_KEY } from "$lib/game-state.svelte";
import { session } from "$lib/session-store.svelte";
import { loadStore } from "../../../platform/store/index";
import { loadCore } from "../../../platform/core/index";
import { createEdgeGatewayClient } from "../../../api/connect";
import { GalaxyClient } from "../../../api/galaxy-client";
import { GATEWAY_BASE_URL, GATEWAY_RESPONSE_PUBLIC_KEY } from "$lib/env";
let { children } = $props();
@@ -36,9 +52,54 @@ swap.
isOnMap ? mobileTool : "map",
);
const gameState = new GameStateStore();
setContext(GAME_STATE_CONTEXT_KEY, gameState);
function toggleSidebar(): void {
sidebarOpen = !sidebarOpen;
}
async function sha256(payload: Uint8Array): Promise<Uint8Array> {
const digest = await crypto.subtle.digest("SHA-256", payload as BufferSource);
return new Uint8Array(digest);
}
onMount(() => {
(async (): Promise<void> => {
if (
session.keypair === null ||
session.deviceSessionId === null ||
GATEWAY_RESPONSE_PUBLIC_KEY.length === 0
) {
return;
}
const keypair = session.keypair;
const deviceSessionId = session.deviceSessionId;
try {
const [{ cache }, core] = await Promise.all([loadStore(), loadCore()]);
const client = new GalaxyClient({
core,
edge: createEdgeGatewayClient(GATEWAY_BASE_URL),
signer: (canonical) => keypair.sign(canonical),
sha256,
deviceSessionId,
gatewayResponsePublicKey: GATEWAY_RESPONSE_PUBLIC_KEY,
});
await gameState.init({ client, cache, gameId });
} catch (err) {
gameState.failBootstrap(describeBootstrapError(err));
}
})();
});
onDestroy(() => {
gameState.dispose();
});
function describeBootstrapError(err: unknown): string {
if (err instanceof Error) return err.message;
return "request failed";
}
</script>
<div class="game-shell" data-testid="game-shell">
@@ -35,6 +35,7 @@ export interface GameFixture {
enrollmentEndsAtMs?: bigint;
createdAtMs?: bigint;
updatedAtMs?: bigint;
currentTurn?: number;
}
export interface ApplicationFixture {
@@ -79,6 +80,7 @@ function encodeGame(builder: Builder, game: GameFixture): number {
GameSummary.addEnrollmentEndsAtMs(builder, game.enrollmentEndsAtMs ?? DEFAULT_TIME_MS);
GameSummary.addCreatedAtMs(builder, game.createdAtMs ?? DEFAULT_TIME_MS);
GameSummary.addUpdatedAtMs(builder, game.updatedAtMs ?? DEFAULT_TIME_MS);
GameSummary.addCurrentTurn(builder, game.currentTurn ?? 0);
return GameSummary.endGameSummary(builder);
}
@@ -0,0 +1,129 @@
// Phase 11 helpers for forging FlatBuffers report payloads in e2e
// tests. Mirrors the engine's `report.Report` shape so the mocked
// gateway can return realistic data without standing up the real
// engine container.
//
// Phase 11 only renders planets, so the helpers keep the report shape
// minimal (turn / dimensions / planet vectors). Later phases extend
// the helper as ships, fleets, sciences, etc. land.
import { Builder } from "flatbuffers";
import {
LocalPlanet,
OtherPlanet,
Report,
UnidentifiedPlanet,
UninhabitedPlanet,
} from "../../../src/proto/galaxy/fbs/report";
export interface PlanetFixture {
number: number;
name: string;
x: number;
y: number;
}
export interface OtherPlanetFixture extends PlanetFixture {
owner: string;
}
export interface ReportFixture {
turn: number;
mapWidth?: number;
mapHeight?: number;
localPlanets?: PlanetFixture[];
otherPlanets?: OtherPlanetFixture[];
uninhabitedPlanets?: PlanetFixture[];
unidentifiedPlanets?: { number: number; x: number; y: number }[];
}
export function buildReportPayload(fixture: ReportFixture): Uint8Array {
const builder = new Builder(512);
const localOffsets = (fixture.localPlanets ?? []).map((planet) => {
const name = builder.createString(planet.name);
LocalPlanet.startLocalPlanet(builder);
LocalPlanet.addNumber(builder, BigInt(planet.number));
LocalPlanet.addX(builder, planet.x);
LocalPlanet.addY(builder, planet.y);
LocalPlanet.addName(builder, name);
LocalPlanet.addSize(builder, 10);
LocalPlanet.addResources(builder, 0.5);
LocalPlanet.addPopulation(builder, 0);
LocalPlanet.addIndustry(builder, 0);
return LocalPlanet.endLocalPlanet(builder);
});
const otherOffsets = (fixture.otherPlanets ?? []).map((planet) => {
const name = builder.createString(planet.name);
const owner = builder.createString(planet.owner);
OtherPlanet.startOtherPlanet(builder);
OtherPlanet.addNumber(builder, BigInt(planet.number));
OtherPlanet.addX(builder, planet.x);
OtherPlanet.addY(builder, planet.y);
OtherPlanet.addName(builder, name);
OtherPlanet.addOwner(builder, owner);
OtherPlanet.addSize(builder, 9);
return OtherPlanet.endOtherPlanet(builder);
});
const uninhabitedOffsets = (fixture.uninhabitedPlanets ?? []).map(
(planet) => {
const name = builder.createString(planet.name);
UninhabitedPlanet.startUninhabitedPlanet(builder);
UninhabitedPlanet.addNumber(builder, BigInt(planet.number));
UninhabitedPlanet.addX(builder, planet.x);
UninhabitedPlanet.addY(builder, planet.y);
UninhabitedPlanet.addName(builder, name);
UninhabitedPlanet.addSize(builder, 6);
return UninhabitedPlanet.endUninhabitedPlanet(builder);
},
);
const unidentifiedOffsets = (fixture.unidentifiedPlanets ?? []).map(
(planet) => {
UnidentifiedPlanet.startUnidentifiedPlanet(builder);
UnidentifiedPlanet.addNumber(builder, BigInt(planet.number));
UnidentifiedPlanet.addX(builder, planet.x);
UnidentifiedPlanet.addY(builder, planet.y);
return UnidentifiedPlanet.endUnidentifiedPlanet(builder);
},
);
const localVec =
localOffsets.length === 0
? null
: Report.createLocalPlanetVector(builder, localOffsets);
const otherVec =
otherOffsets.length === 0
? null
: Report.createOtherPlanetVector(builder, otherOffsets);
const uninhabitedVec =
uninhabitedOffsets.length === 0
? null
: Report.createUninhabitedPlanetVector(builder, uninhabitedOffsets);
const unidentifiedVec =
unidentifiedOffsets.length === 0
? null
: Report.createUnidentifiedPlanetVector(builder, unidentifiedOffsets);
const totalPlanets =
(fixture.localPlanets ?? []).length +
(fixture.otherPlanets ?? []).length +
(fixture.uninhabitedPlanets ?? []).length +
(fixture.unidentifiedPlanets ?? []).length;
Report.startReport(builder);
Report.addTurn(builder, BigInt(fixture.turn));
Report.addWidth(builder, fixture.mapWidth ?? 4000);
Report.addHeight(builder, fixture.mapHeight ?? 4000);
Report.addPlanetCount(builder, totalPlanets);
if (localVec !== null) Report.addLocalPlanet(builder, localVec);
if (otherVec !== null) Report.addOtherPlanet(builder, otherVec);
if (uninhabitedVec !== null) Report.addUninhabitedPlanet(builder, uninhabitedVec);
if (unidentifiedVec !== null) Report.addUnidentifiedPlanet(builder, unidentifiedVec);
const reportOff = Report.endReport(builder);
builder.finish(reportOff);
return builder.asUint8Array();
}
@@ -0,0 +1,239 @@
// Phase 11 end-to-end coverage for the live map integration. Boots
// an authenticated session through `/__debug/store`, mocks the two
// gateway calls the layout makes (`lobby.my.games.list` and
// `user.games.report`), navigates to `/games/<game-id>/map`, and
// asserts the chrome reflects the live data: turn counter shows the
// reported turn, the map view enters its `ready` state with a
// non-zero planet count, and a zero-planet response renders the
// empty world without errors.
import { fromJson, type JsonValue } from "@bufbuild/protobuf";
import { expect, test, type Page } from "@playwright/test";
import { ByteBuffer } from "flatbuffers";
import { ExecuteCommandRequestSchema } from "../../src/proto/galaxy/gateway/v1/edge_gateway_pb";
import { UUID } from "../../src/proto/galaxy/fbs/common";
import { GameReportRequest } from "../../src/proto/galaxy/fbs/report";
import { forgeExecuteCommandResponseJson } from "./fixtures/sign-response";
import {
buildMyGamesListPayload,
type GameFixture,
} from "./fixtures/lobby-fbs";
import { buildReportPayload } from "./fixtures/report-fbs";
const SESSION_ID = "phase-11-map-session";
const GAME_ID = "11111111-2222-3333-4444-555555555555";
interface MockOpts {
currentTurn: number;
report: Parameters<typeof buildReportPayload>[0];
gameId?: string;
}
interface MockState {
reportRequests: Array<{ gameId: string; turn: number }>;
}
async function mockGateway(page: Page, opts: MockOpts): Promise<MockState> {
const state: MockState = { reportRequests: [] };
const gameId = opts.gameId ?? GAME_ID;
const game: GameFixture = {
gameId,
gameName: "Phase 11 Game",
gameType: "private",
status: "running",
ownerUserId: "user-1",
minPlayers: 2,
maxPlayers: 8,
enrollmentEndsAtMs: BigInt(Date.now() + 86_400_000),
createdAtMs: BigInt(Date.now() - 86_400_000),
updatedAtMs: BigInt(Date.now()),
currentTurn: opts.currentTurn,
};
await page.route(
"**/galaxy.gateway.v1.EdgeGateway/ExecuteCommand",
async (route) => {
const reqText = route.request().postData();
if (reqText === null) {
await route.fulfill({ status: 400 });
return;
}
const req = fromJson(
ExecuteCommandRequestSchema,
JSON.parse(reqText) as JsonValue,
);
let resultCode = "ok";
let payload: Uint8Array;
switch (req.messageType) {
case "lobby.my.games.list":
payload = buildMyGamesListPayload([game]);
break;
case "user.games.report": {
const decoded = GameReportRequest.getRootAsGameReportRequest(
new ByteBuffer(req.payloadBytes),
);
const idStruct = decoded.gameId(new UUID());
const hi = idStruct?.hi() ?? 0n;
const lo = idStruct?.lo() ?? 0n;
state.reportRequests.push({
gameId: hiLoToUuid(hi, lo),
turn: decoded.turn(),
});
payload = buildReportPayload(opts.report);
break;
}
default:
resultCode = "internal_error";
payload = new Uint8Array();
}
const body = await forgeExecuteCommandResponseJson({
requestId: req.requestId,
timestampMs: BigInt(Date.now()),
resultCode,
payloadBytes: payload,
});
await route.fulfill({
status: 200,
contentType: "application/json",
body,
});
},
);
// Hold the SubscribeEvents stream open indefinitely. The
// revocation watcher in `lib/revocation-watcher.ts` treats a clean
// end-of-stream as `session_invalidation` and calls
// `session.signOut("revoked")`, which would bounce the page back
// to `/login`. Playwright aborts pending routes on test teardown,
// the watcher's catch path logs the abort and returns without a
// sign-out — same convention as `tests/e2e/lobby-flow.spec.ts`.
await page.route(
"**/galaxy.gateway.v1.EdgeGateway/SubscribeEvents",
async () => {
await new Promise<void>(() => {});
},
);
return state;
}
function hiLoToUuid(hi: bigint, lo: bigint): string {
const toHex = (v: bigint): string => v.toString(16).padStart(16, "0");
const full = toHex(hi) + toHex(lo);
return [
full.slice(0, 8),
full.slice(8, 12),
full.slice(12, 16),
full.slice(16, 20),
full.slice(20, 32),
].join("-");
}
async function bootSession(page: Page): Promise<void> {
await page.goto("/__debug/store");
await expect(page.getByTestId("debug-store-ready")).toBeVisible();
await page.waitForFunction(() => window.__galaxyDebug?.ready === true);
await page.evaluate(() => window.__galaxyDebug!.clearSession());
await page.evaluate(
(id) => window.__galaxyDebug!.setDeviceSessionId(id),
SESSION_ID,
);
}
test("map view renders the reported turn and planet count from a live report", async ({
page,
}) => {
const mocks = await mockGateway(page, {
currentTurn: 4,
report: {
turn: 4,
mapWidth: 4000,
mapHeight: 4000,
localPlanets: [
{ number: 1, name: "Home", x: 1000, y: 1000 },
{ number: 2, name: "Outpost", x: 1500, y: 1300 },
],
otherPlanets: [
{
number: 3,
name: "Frontier",
x: 2200,
y: 2200,
owner: "Federation",
},
],
uninhabitedPlanets: [{ number: 4, name: "Rock", x: 800, y: 2400 }],
},
});
await bootSession(page);
await page.goto(`/games/${GAME_ID}/map`);
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
"data-status",
"ready",
);
await expect(page.getByTestId("turn-counter")).toContainText("turn 4");
await expect(page.getByTestId("map-canvas-wrap")).toHaveAttribute(
"data-planet-count",
"4",
);
expect(mocks.reportRequests.length).toBeGreaterThanOrEqual(1);
expect(mocks.reportRequests[0]?.gameId).toBe(GAME_ID);
expect(mocks.reportRequests[0]?.turn).toBe(4);
});
test("zero-planet game renders the empty world without errors", async ({
page,
}) => {
await mockGateway(page, {
currentTurn: 0,
report: {
turn: 0,
mapWidth: 4000,
mapHeight: 4000,
},
});
await bootSession(page);
await page.goto(`/games/${GAME_ID}/map`);
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
"data-status",
"ready",
);
await expect(page.getByTestId("turn-counter")).toContainText("turn 0");
await expect(page.getByTestId("map-canvas-wrap")).toHaveAttribute(
"data-planet-count",
"0",
);
await expect(page.getByTestId("map-error")).not.toBeVisible();
await expect(page.getByTestId("map-mount-error")).not.toBeVisible();
});
test("missing-membership game surfaces an error instead of a blank canvas", async ({
page,
}) => {
// The gateway returns lobby.my.games.list with a different game id
// so the layout's gameState lookup misses; the store flips to
// `error` and the map view renders the localised error overlay.
await mockGateway(page, {
currentTurn: 0,
gameId: "99999999-aaaa-bbbb-cccc-000000000000",
report: { turn: 0 },
});
await bootSession(page);
await page.goto(`/games/${GAME_ID}/map`);
await expect(page.getByTestId("map-error")).toBeVisible();
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
"data-status",
"error",
);
});
+10 -3
View File
@@ -24,11 +24,18 @@ beforeEach(() => {
});
describe("active-view stubs", () => {
test("map stub renders title and coming-soon copy", () => {
test("map view renders loading overlay when no game-state context is provided", () => {
// The live integration in `lib/active-view/map.svelte` (Phase 11)
// reads its data from a `GameStateStore` provided through context
// by `routes/games/[id]/+layout.svelte`. Without the context the
// store reference is `undefined` and the view stays in the
// `idle` branch, surfacing the localised loading overlay so the
// shell never renders an empty active-view slot.
const ui = render(MapView);
const node = ui.getByTestId("active-view-map");
expect(node).toHaveTextContent("map");
expect(node).toHaveTextContent("coming soon");
expect(node).toHaveAttribute("data-status", "idle");
expect(ui.getByTestId("map-loading")).toBeInTheDocument();
expect(ui.getByTestId("map-canvas-wrap")).toBeInTheDocument();
});
test("table stub maps a kebab-case entity to the right i18n title", () => {
+264
View File
@@ -0,0 +1,264 @@
// Vitest coverage for the per-game runes store
// (`lib/game-state.svelte.ts`). The test stubs `lobby.my.games.list`
// and `user.games.report` at module level and drives the store
// through its lifecycle: init → ready → error → setTurn → wrap-mode
// persistence.
import "@testing-library/jest-dom/vitest";
import "fake-indexeddb/auto";
import {
afterEach,
beforeEach,
describe,
expect,
test,
vi,
} from "vitest";
import { Builder } from "flatbuffers";
import { GameStateStore } from "../src/lib/game-state.svelte";
import type { GalaxyClient } from "../src/api/galaxy-client";
import type { Cache } from "../src/platform/store/index";
import { IDBCache } from "../src/platform/store/idb-cache";
import { openGalaxyDB, type GalaxyDB } from "../src/platform/store/idb";
import type { IDBPDatabase } from "idb";
import { UUID } from "../src/proto/galaxy/fbs/common";
import {
LocalPlanet,
Report,
} from "../src/proto/galaxy/fbs/report";
const listMyGamesSpy = vi.fn();
vi.mock("../src/api/lobby", async () => {
const actual = await vi.importActual<typeof import("../src/api/lobby")>(
"../src/api/lobby",
);
return {
...actual,
listMyGames: (...args: unknown[]) => listMyGamesSpy(...args),
};
});
let db: IDBPDatabase<GalaxyDB>;
let dbName: string;
let cache: Cache;
beforeEach(async () => {
dbName = `galaxy-game-state-test-${crypto.randomUUID()}`;
db = await openGalaxyDB(dbName);
cache = new IDBCache(db);
listMyGamesSpy.mockReset();
});
afterEach(async () => {
db.close();
await new Promise<void>((resolve) => {
const req = indexedDB.deleteDatabase(dbName);
req.onsuccess = () => resolve();
req.onerror = () => resolve();
req.onblocked = () => resolve();
});
});
const GAME_ID = "11111111-2222-3333-4444-555555555555";
function makeGameSummary(currentTurn: number): {
gameId: string;
gameName: string;
gameType: string;
status: string;
ownerUserId: string;
minPlayers: number;
maxPlayers: number;
enrollmentEndsAt: Date;
createdAt: Date;
updatedAt: Date;
currentTurn: number;
} {
return {
gameId: GAME_ID,
gameName: "Test Game",
gameType: "private",
status: "running",
ownerUserId: "owner-1",
minPlayers: 2,
maxPlayers: 8,
enrollmentEndsAt: new Date(),
createdAt: new Date(),
updatedAt: new Date(),
currentTurn,
};
}
interface PlanetFixture {
number: number;
name: string;
x: number;
y: number;
}
function buildReportPayload(opts: {
turn: number;
width?: number;
height?: number;
planets?: PlanetFixture[];
}): Uint8Array {
const builder = new Builder(256);
const planetOffsets = (opts.planets ?? []).map((planet) => {
const name = builder.createString(planet.name);
LocalPlanet.startLocalPlanet(builder);
LocalPlanet.addNumber(builder, BigInt(planet.number));
LocalPlanet.addX(builder, planet.x);
LocalPlanet.addY(builder, planet.y);
LocalPlanet.addName(builder, name);
LocalPlanet.addSize(builder, 10);
LocalPlanet.addResources(builder, 0.5);
return LocalPlanet.endLocalPlanet(builder);
});
const localPlanetVec =
planetOffsets.length === 0
? null
: Report.createLocalPlanetVector(builder, planetOffsets);
Report.startReport(builder);
Report.addTurn(builder, BigInt(opts.turn));
Report.addWidth(builder, opts.width ?? 4000);
Report.addHeight(builder, opts.height ?? 4000);
Report.addPlanetCount(builder, planetOffsets.length);
if (localPlanetVec !== null) {
Report.addLocalPlanet(builder, localPlanetVec);
}
const reportOff = Report.endReport(builder);
builder.finish(reportOff);
return builder.asUint8Array();
}
function makeFakeClient(
executeCommand: (
messageType: string,
payload: Uint8Array,
) => Promise<{ resultCode: string; payloadBytes: Uint8Array }>,
): GalaxyClient {
return { executeCommand } as unknown as GalaxyClient;
}
describe("GameStateStore", () => {
test("init transitions through loading and ready when both calls succeed", async () => {
listMyGamesSpy.mockResolvedValue([makeGameSummary(7)]);
const calls: Array<{ messageType: string; payload: Uint8Array }> = [];
const client = makeFakeClient(async (messageType, payload) => {
calls.push({ messageType, payload });
return {
resultCode: "ok",
payloadBytes: buildReportPayload({
turn: 7,
planets: [{ number: 1, name: "Home", x: 100, y: 100 }],
}),
};
});
const store = new GameStateStore();
expect(store.status).toBe("idle");
await store.init({ client, cache, gameId: GAME_ID });
expect(listMyGamesSpy).toHaveBeenCalledTimes(1);
expect(calls.length).toBe(1);
expect(calls[0]?.messageType).toBe("user.games.report");
expect(store.status).toBe("ready");
expect(store.report).not.toBeNull();
expect(store.report?.turn).toBe(7);
expect(store.report?.planets.length).toBe(1);
expect(store.report?.planets[0]?.kind).toBe("local");
store.dispose();
});
test("init surfaces an error when the game is missing from lobby", async () => {
listMyGamesSpy.mockResolvedValue([makeGameSummary(0).gameId === "other" ? null : makeGameSummary(0)].filter(Boolean));
// Replace the helper above's awkward filter with an explicit
// mismatched id so the lookup miss is unambiguous.
listMyGamesSpy.mockResolvedValue([
{ ...makeGameSummary(2), gameId: "different-game-id" },
]);
const client = makeFakeClient(async () => ({
resultCode: "ok",
payloadBytes: buildReportPayload({ turn: 0 }),
}));
const store = new GameStateStore();
await store.init({ client, cache, gameId: GAME_ID });
expect(store.status).toBe("error");
expect(store.error).toMatch(/not in your list/);
expect(store.report).toBeNull();
store.dispose();
});
test("init surfaces error when user.games.report returns a non-ok result", async () => {
listMyGamesSpy.mockResolvedValue([makeGameSummary(0)]);
const client = makeFakeClient(async () => ({
resultCode: "forbidden",
payloadBytes: new TextEncoder().encode(
JSON.stringify({ code: "forbidden", message: "no membership" }),
),
}));
const store = new GameStateStore();
await store.init({ client, cache, gameId: GAME_ID });
expect(store.status).toBe("error");
expect(store.error).toMatch(/no membership/);
store.dispose();
});
test("setTurn loads a different turn snapshot", async () => {
listMyGamesSpy.mockResolvedValue([makeGameSummary(3)]);
const turns: number[] = [];
const client = makeFakeClient(async () => {
const turn = turns.length === 0 ? 3 : 1;
turns.push(turn);
return {
resultCode: "ok",
payloadBytes: buildReportPayload({ turn }),
};
});
const store = new GameStateStore();
await store.init({ client, cache, gameId: GAME_ID });
expect(store.report?.turn).toBe(3);
await store.setTurn(1);
expect(store.status).toBe("ready");
expect(store.report?.turn).toBe(1);
store.dispose();
});
test("setWrapMode persists across instances through Cache", async () => {
listMyGamesSpy.mockResolvedValue([makeGameSummary(0)]);
const client = makeFakeClient(async () => ({
resultCode: "ok",
payloadBytes: buildReportPayload({ turn: 0 }),
}));
const a = new GameStateStore();
await a.init({ client, cache, gameId: GAME_ID });
expect(a.wrapMode).toBe("torus");
await a.setWrapMode("no-wrap");
expect(a.wrapMode).toBe("no-wrap");
a.dispose();
const b = new GameStateStore();
await b.init({ client, cache, gameId: GAME_ID });
expect(b.wrapMode).toBe("no-wrap");
b.dispose();
});
test("failBootstrap moves the store into the error state with the given message", () => {
const store = new GameStateStore();
store.failBootstrap("device session missing");
expect(store.status).toBe("error");
expect(store.error).toBe("device session missing");
});
});
+4 -2
View File
@@ -70,7 +70,7 @@ function makeStub(
return { client: stub, captured };
}
function encodeGameSummary(builder: Builder): number {
function encodeGameSummary(builder: Builder, currentTurn: number = 0): number {
const gameId = builder.createString("g-1");
const gameName = builder.createString("Test Game");
const gameType = builder.createString("private");
@@ -87,6 +87,7 @@ function encodeGameSummary(builder: Builder): number {
GameSummary.addEnrollmentEndsAtMs(builder, 1_780_000_000_000n);
GameSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
GameSummary.addUpdatedAtMs(builder, 1_770_000_000_000n);
GameSummary.addCurrentTurn(builder, currentTurn);
return GameSummary.endGameSummary(builder);
}
@@ -133,7 +134,7 @@ describe("lobby.ts wrappers", () => {
test("listMyGames decodes the response and reports the message type", async () => {
const { client, captured } = makeStub(() => {
const builder = new Builder(256);
const item = encodeGameSummary(builder);
const item = encodeGameSummary(builder, 5);
const items = MyGamesListResponse.createItemsVector(builder, [item]);
MyGamesListResponse.startMyGamesListResponse(builder);
MyGamesListResponse.addItems(builder, items);
@@ -146,6 +147,7 @@ describe("lobby.ts wrappers", () => {
expect(games.length).toBe(1);
expect(games[0]!.gameId).toBe("g-1");
expect(games[0]!.minPlayers).toBe(2);
expect(games[0]!.currentTurn).toBe(5);
});
test("listPublicGames passes pagination and decodes pageSize/total", async () => {
+6 -1
View File
@@ -43,19 +43,21 @@ interface GameSummaryFixture {
enrollmentEndsAtMs: bigint;
createdAtMs: bigint;
updatedAtMs: bigint;
currentTurn: number;
}
const PRIVATE_GAME: GameSummaryFixture = {
gameId: "game-private-7c8f",
gameName: "First Contact",
gameType: "private",
status: "draft",
status: "running",
ownerUserId: "user-9912",
minPlayers: 2,
maxPlayers: 8,
enrollmentEndsAtMs: 1_780_000_000_000n,
createdAtMs: 1_770_000_000_000n,
updatedAtMs: 1_770_000_300_000n,
currentTurn: 7,
};
const PUBLIC_GAME: GameSummaryFixture = {
@@ -69,6 +71,7 @@ const PUBLIC_GAME: GameSummaryFixture = {
enrollmentEndsAtMs: 1_780_500_000_000n,
createdAtMs: 1_770_500_000_000n,
updatedAtMs: 1_770_600_000_000n,
currentTurn: 0,
};
function encodeGameSummary(builder: Builder, value: GameSummaryFixture): number {
@@ -88,6 +91,7 @@ function encodeGameSummary(builder: Builder, value: GameSummaryFixture): number
GameSummary.addEnrollmentEndsAtMs(builder, value.enrollmentEndsAtMs);
GameSummary.addCreatedAtMs(builder, value.createdAtMs);
GameSummary.addUpdatedAtMs(builder, value.updatedAtMs);
GameSummary.addCurrentTurn(builder, value.currentTurn);
return GameSummary.endGameSummary(builder);
}
@@ -104,6 +108,7 @@ function expectGameSummary(actual: GameSummary | null, want: GameSummaryFixture)
expect(got.enrollmentEndsAtMs()).toBe(want.enrollmentEndsAtMs);
expect(got.createdAtMs()).toBe(want.createdAtMs);
expect(got.updatedAtMs()).toBe(want.updatedAtMs);
expect(got.currentTurn()).toBe(want.currentTurn);
}
describe("lobby FlatBuffers TS bindings", () => {
+2
View File
@@ -136,6 +136,7 @@ function makeGame(id: string, name: string, status = "draft") {
enrollmentEndsAt: baseDate,
createdAt: baseDate,
updatedAt: baseDate,
currentTurn: 0,
};
}
@@ -151,6 +152,7 @@ function makePublicGame(id: string, name: string) {
enrollmentEndsAt: baseDate,
createdAt: baseDate,
updatedAt: baseDate,
currentTurn: 0,
};
}
+114
View File
@@ -0,0 +1,114 @@
// Vitest unit coverage for `map/state-binding.ts`. The function
// translates a Phase 11 `GameReport` into a renderer-ready `World`
// containing one Point primitive per planet across all four kinds
// (local / other / uninhabited / unidentified). The tests assert
// the world dimensions match the report, the planet ids are the
// engine numbers, the kind-specific styles differ, and a zero-planet
// report still produces a well-formed empty World.
import "@testing-library/jest-dom/vitest";
import { describe, expect, test } from "vitest";
import type { GameReport } from "../src/api/game-state";
import { reportToWorld } from "../src/map/state-binding";
function makeReport(overrides: Partial<GameReport> = {}): GameReport {
return {
turn: 1,
mapWidth: 4000,
mapHeight: 4000,
planetCount: 0,
planets: [],
...overrides,
};
}
describe("reportToWorld", () => {
test("uses report dimensions for the World", () => {
const world = reportToWorld(makeReport({ mapWidth: 3200, mapHeight: 1600 }));
expect(world.width).toBe(3200);
expect(world.height).toBe(1600);
});
test("emits one Point primitive per planet across all four kinds", () => {
const world = reportToWorld(
makeReport({
planets: [
{ number: 1, name: "Home", x: 100, y: 100, kind: "local", owner: null, size: 12, resources: 0.5 },
{ number: 2, name: "Alpha", x: 200, y: 100, kind: "other", owner: "Federation", size: 8, resources: 0.3 },
{ number: 3, name: "Rock", x: 100, y: 200, kind: "uninhabited", owner: null, size: 4, resources: 0.1 },
{ number: 4, name: "", x: 200, y: 200, kind: "unidentified", owner: null, size: null, resources: null },
],
}),
);
expect(world.primitives.length).toBe(4);
for (const p of world.primitives) {
expect(p.kind).toBe("point");
}
});
test("propagates planet number as primitive id and coordinates verbatim", () => {
const world = reportToWorld(
makeReport({
planets: [
{ number: 42, name: "Home", x: 123.5, y: 456.25, kind: "local", owner: null, size: 10, resources: 0.5 },
],
}),
);
const [planet] = world.primitives;
expect(planet?.id).toBe(42);
expect(planet?.kind).toBe("point");
if (planet?.kind === "point") {
expect(planet.x).toBe(123.5);
expect(planet.y).toBe(456.25);
}
});
test("uses distinct styles for each planet kind", () => {
const world = reportToWorld(
makeReport({
planets: [
{ number: 1, name: "L", x: 0, y: 0, kind: "local", owner: null, size: 1, resources: 0 },
{ number: 2, name: "O", x: 1, y: 0, kind: "other", owner: "Foe", size: 1, resources: 0 },
{ number: 3, name: "U", x: 2, y: 0, kind: "uninhabited", owner: null, size: 1, resources: 0 },
{ number: 4, name: "?", x: 3, y: 0, kind: "unidentified", owner: null, size: null, resources: null },
],
}),
);
const fills = world.primitives.map((p) => p.style.fillColor);
const unique = new Set(fills);
expect(unique.size).toBe(fills.length);
});
test("zero-planet report yields an empty primitive list and well-formed World", () => {
const world = reportToWorld(makeReport({ planets: [] }));
expect(world.primitives.length).toBe(0);
expect(world.width).toBeGreaterThan(0);
expect(world.height).toBeGreaterThan(0);
});
test("guards against zero / negative dimensions in the report", () => {
const world = reportToWorld(
makeReport({ mapWidth: 0, mapHeight: -1, planets: [] }),
);
// World's constructor rejects non-positive dimensions; the
// binding falls back to 1×1 so a malformed report cannot crash
// the renderer.
expect(world.width).toBeGreaterThan(0);
expect(world.height).toBeGreaterThan(0);
});
test("local planets carry higher priority than unidentified", () => {
const world = reportToWorld(
makeReport({
planets: [
{ number: 1, name: "Home", x: 0, y: 0, kind: "local", owner: null, size: 1, resources: 0 },
{ number: 2, name: "?", x: 0, y: 0, kind: "unidentified", owner: null, size: null, resources: null },
],
}),
);
const local = world.primitives.find((p) => p.id === 1);
const unknown = world.primitives.find((p) => p.id === 2);
expect(local?.priority ?? 0).toBeGreaterThan(unknown?.priority ?? 0);
});
});