ui/phase-14: rename planet end-to-end + order read-back
Wires the first end-to-end command through the full pipeline:
inspector rename action → local order draft → user.games.order
submit → optimistic overlay on map / inspector → server hydration
on cache miss via the new user.games.order.get message type.
Backend: GET /api/v1/user/games/{id}/orders forwards to engine
GET /api/v1/order. Gateway parses the engine PUT response into the
extended UserGamesOrderResponse FBS envelope and adds
executeUserGamesOrderGet for the read-back path. Frontend ports
ValidateTypeName to TS, lands the inline rename editor + Submit
button, and exposes a renderedReport context so consumers see the
overlay-applied snapshot.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,11 @@
|
||||
// sets for `LocalPlanet`, `OtherPlanet`, `UninhabitedPlanet`, and
|
||||
// `UnidentifiedPlanet`, and the wrapper preserves that nullability
|
||||
// instead of inventing zero values.
|
||||
//
|
||||
// Phase 14 adds `applyOrderOverlay`: every applied / submitting
|
||||
// rename in the local draft swaps the planet name on the rendered
|
||||
// report so the player sees their intent reflected immediately,
|
||||
// without waiting for the next turn cutoff.
|
||||
|
||||
import { Builder, ByteBuffer } from "flatbuffers";
|
||||
|
||||
@@ -19,6 +24,7 @@ import {
|
||||
GameReportRequest,
|
||||
Report,
|
||||
} from "../proto/galaxy/fbs/report";
|
||||
import type { CommandStatus, OrderCommand } from "../sync/order-types";
|
||||
|
||||
const MESSAGE_TYPE = "user.games.report";
|
||||
|
||||
@@ -205,6 +211,42 @@ export function uuidToHiLo(value: string): [bigint, bigint] {
|
||||
return [hi, lo];
|
||||
}
|
||||
|
||||
/**
|
||||
* applyOrderOverlay returns a copy of `report` with every applied or
|
||||
* still-in-flight (`submitting`) command from `commands` projected on
|
||||
* top. Phase 14 understands `planetRename` only — every other variant
|
||||
* passes through. The function is pure: callers re-derive the
|
||||
* overlay whenever the draft or the report change.
|
||||
*
|
||||
* `statuses` maps command id → status. Entries with `applied` or
|
||||
* `submitting` participate in the overlay; everything else (`draft`,
|
||||
* `valid`, `invalid`, `rejected`) is treated as "not yet committed
|
||||
* by the player" and skipped. This matches the order-composer model:
|
||||
* the player sees their own committed intent, not their unfinished
|
||||
* edits.
|
||||
*/
|
||||
export function applyOrderOverlay(
|
||||
report: GameReport,
|
||||
commands: OrderCommand[],
|
||||
statuses: Record<string, CommandStatus>,
|
||||
): GameReport {
|
||||
if (commands.length === 0) return report;
|
||||
let mutatedPlanets: ReportPlanet[] | null = null;
|
||||
for (const cmd of commands) {
|
||||
const status = statuses[cmd.id];
|
||||
if (status !== "applied" && status !== "submitting") continue;
|
||||
if (cmd.kind !== "planetRename") continue;
|
||||
const idx = report.planets.findIndex((p) => p.number === cmd.planetNumber);
|
||||
if (idx < 0) continue;
|
||||
if (mutatedPlanets === null) {
|
||||
mutatedPlanets = [...report.planets];
|
||||
}
|
||||
mutatedPlanets[idx] = { ...mutatedPlanets[idx]!, name: cmd.name };
|
||||
}
|
||||
if (mutatedPlanets === null) return report;
|
||||
return { ...report, planets: mutatedPlanets };
|
||||
}
|
||||
|
||||
function decodeErrorMessage(payload: Uint8Array): { code: string; message: string } {
|
||||
if (payload.length === 0) {
|
||||
return { code: "internal_error", message: "empty error payload" };
|
||||
|
||||
@@ -36,8 +36,15 @@ preference the store already manages.
|
||||
SELECTION_CONTEXT_KEY,
|
||||
type SelectionStore,
|
||||
} from "$lib/selection.svelte";
|
||||
import {
|
||||
RENDERED_REPORT_CONTEXT_KEY,
|
||||
type RenderedReportSource,
|
||||
} from "$lib/rendered-report.svelte";
|
||||
|
||||
const store = getContext<GameStateStore | undefined>(GAME_STATE_CONTEXT_KEY);
|
||||
const renderedReport = getContext<RenderedReportSource | undefined>(
|
||||
RENDERED_REPORT_CONTEXT_KEY,
|
||||
);
|
||||
const selection = getContext<SelectionStore | undefined>(SELECTION_CONTEXT_KEY);
|
||||
|
||||
let canvasEl: HTMLCanvasElement | null = $state(null);
|
||||
@@ -52,7 +59,11 @@ preference the store already manages.
|
||||
let mounted = false;
|
||||
|
||||
$effect(() => {
|
||||
const report = store?.report;
|
||||
// Read the overlay-applied report so the map labels reflect
|
||||
// pending renames immediately. Falls back to raw report when
|
||||
// the rendered source is missing (e.g. component used outside
|
||||
// the in-game shell layout).
|
||||
const report = renderedReport?.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.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Exposes the per-game `GalaxyClient` instance through a Svelte
|
||||
// context so command-driven UI (the order-tab submit button,
|
||||
// later phases' inspector actions) can issue gateway calls without
|
||||
// re-instantiating the client. The handle is intentionally a thin
|
||||
// reactive wrapper: the layout populates `client` after the boot
|
||||
// `Promise.all` resolves, and consumers read the latest value
|
||||
// through the getter — `null` while the boot is in flight, set to
|
||||
// the live client once the keypair / gateway public key are loaded.
|
||||
|
||||
import type { GalaxyClient } from "../api/galaxy-client";
|
||||
|
||||
/**
|
||||
* GALAXY_CLIENT_CONTEXT_KEY is the Svelte context key the in-game
|
||||
* shell layout uses to expose its bound `GalaxyClient` to
|
||||
* descendants. The order-tab submit button reads this to call
|
||||
* `submitOrder`.
|
||||
*/
|
||||
export const GALAXY_CLIENT_CONTEXT_KEY = Symbol("galaxy-client");
|
||||
|
||||
export interface GalaxyClientHandle {
|
||||
readonly client: GalaxyClient | null;
|
||||
}
|
||||
|
||||
export class GalaxyClientHolder implements GalaxyClientHandle {
|
||||
#client: GalaxyClient | null = $state(null);
|
||||
|
||||
get client(): GalaxyClient | null {
|
||||
return this.#client;
|
||||
}
|
||||
|
||||
set(client: GalaxyClient | null): void {
|
||||
this.#client = client;
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,17 @@ export class GameStateStore {
|
||||
report: GameReport | null = $state(null);
|
||||
wrapMode: WrapMode = $state("torus");
|
||||
error: string | null = $state(null);
|
||||
/**
|
||||
* currentTurn mirrors the engine's turn number for the running
|
||||
* game (lifted from the lobby record on `setGame`). Phase 14
|
||||
* exposes it so the layout can pass it to
|
||||
* `OrderDraftStore.hydrateFromServer` after both stores boot;
|
||||
* later phases (history mode, calc) will read it directly.
|
||||
*/
|
||||
currentTurn = $state(0);
|
||||
|
||||
private client: GalaxyClient | null = null;
|
||||
private cache: Cache | null = null;
|
||||
private currentTurn = 0;
|
||||
private destroyed = false;
|
||||
private visibilityListener: (() => void) | null = null;
|
||||
|
||||
|
||||
@@ -120,6 +120,17 @@ const en = {
|
||||
"game.sidebar.empty.inspector": "select an object on the map",
|
||||
"game.sidebar.empty.order": "order is empty",
|
||||
"game.sidebar.order.command_delete": "delete",
|
||||
"game.sidebar.order.submit": "submit",
|
||||
"game.sidebar.order.submit_in_flight": "submitting…",
|
||||
"game.sidebar.order.status.draft": "draft",
|
||||
"game.sidebar.order.status.valid": "valid",
|
||||
"game.sidebar.order.status.invalid": "invalid",
|
||||
"game.sidebar.order.status.submitting": "submitting",
|
||||
"game.sidebar.order.status.applied": "applied",
|
||||
"game.sidebar.order.status.rejected": "rejected",
|
||||
"game.sidebar.order.label.placeholder": "{label}",
|
||||
"game.sidebar.order.label.planet_rename": "rename planet {planet} → {name}",
|
||||
"game.sidebar.order.error.batch_failed": "submit failed: {message}",
|
||||
"game.bottom_tabs.map": "map",
|
||||
"game.bottom_tabs.calc": "calc",
|
||||
"game.bottom_tabs.order": "order",
|
||||
@@ -144,6 +155,17 @@ const en = {
|
||||
"game.inspector.planet.production_none": "none",
|
||||
"game.inspector.planet.unidentified_no_data": "no data — only the location is known",
|
||||
"game.inspector.sheet_close": "close",
|
||||
"game.inspector.planet.action.rename": "rename",
|
||||
"game.inspector.planet.rename.title": "rename planet",
|
||||
"game.inspector.planet.rename.confirm": "save",
|
||||
"game.inspector.planet.rename.cancel": "cancel",
|
||||
"game.inspector.planet.rename.invalid.empty": "name cannot be empty",
|
||||
"game.inspector.planet.rename.invalid.too_long": "name is too long (30 characters max)",
|
||||
"game.inspector.planet.rename.invalid.starts_with_special": "name cannot start with a special character",
|
||||
"game.inspector.planet.rename.invalid.ends_with_special": "name cannot end with a special character",
|
||||
"game.inspector.planet.rename.invalid.consecutive_specials": "too many special characters in a row",
|
||||
"game.inspector.planet.rename.invalid.whitespace": "name cannot contain spaces",
|
||||
"game.inspector.planet.rename.invalid.disallowed_character": "name contains disallowed characters",
|
||||
} as const;
|
||||
|
||||
export default en;
|
||||
|
||||
@@ -121,6 +121,17 @@ const ru: Record<keyof typeof en, string> = {
|
||||
"game.sidebar.empty.inspector": "выберите объект на карте",
|
||||
"game.sidebar.empty.order": "приказ пуст",
|
||||
"game.sidebar.order.command_delete": "удалить",
|
||||
"game.sidebar.order.submit": "отправить",
|
||||
"game.sidebar.order.submit_in_flight": "отправка…",
|
||||
"game.sidebar.order.status.draft": "черновик",
|
||||
"game.sidebar.order.status.valid": "готова",
|
||||
"game.sidebar.order.status.invalid": "ошибка",
|
||||
"game.sidebar.order.status.submitting": "отправка",
|
||||
"game.sidebar.order.status.applied": "принята",
|
||||
"game.sidebar.order.status.rejected": "отклонена",
|
||||
"game.sidebar.order.label.placeholder": "{label}",
|
||||
"game.sidebar.order.label.planet_rename": "переименовать планету {planet} → {name}",
|
||||
"game.sidebar.order.error.batch_failed": "ошибка отправки: {message}",
|
||||
"game.bottom_tabs.map": "карта",
|
||||
"game.bottom_tabs.calc": "калк",
|
||||
"game.bottom_tabs.order": "приказ",
|
||||
@@ -145,6 +156,17 @@ const ru: Record<keyof typeof en, string> = {
|
||||
"game.inspector.planet.production_none": "не задано",
|
||||
"game.inspector.planet.unidentified_no_data": "нет данных — известно только местоположение",
|
||||
"game.inspector.sheet_close": "закрыть",
|
||||
"game.inspector.planet.action.rename": "переименовать",
|
||||
"game.inspector.planet.rename.title": "переименование планеты",
|
||||
"game.inspector.planet.rename.confirm": "сохранить",
|
||||
"game.inspector.planet.rename.cancel": "отмена",
|
||||
"game.inspector.planet.rename.invalid.empty": "имя не может быть пустым",
|
||||
"game.inspector.planet.rename.invalid.too_long": "имя слишком длинное (максимум 30 символов)",
|
||||
"game.inspector.planet.rename.invalid.starts_with_special": "имя не может начинаться со спецсимвола",
|
||||
"game.inspector.planet.rename.invalid.ends_with_special": "имя не может заканчиваться спецсимволом",
|
||||
"game.inspector.planet.rename.invalid.consecutive_specials": "слишком много спецсимволов подряд",
|
||||
"game.inspector.planet.rename.invalid.whitespace": "имя не может содержать пробелы",
|
||||
"game.inspector.planet.rename.invalid.disallowed_character": "имя содержит недопустимые символы",
|
||||
};
|
||||
|
||||
export default ru;
|
||||
|
||||
@@ -1,23 +1,29 @@
|
||||
<!--
|
||||
Phase 13 read-only planet inspector. Renders the documented field
|
||||
set for the planet kind in question:
|
||||
Planet inspector. Renders the documented field set for each planet
|
||||
kind (local / other / uninhabited / unidentified) and exposes a
|
||||
Rename action on owned (`local`) planets that opens an inline
|
||||
editor. The editor runs the same `validateEntityName` rules as the
|
||||
server-side validator (parity with `pkg/util/string.go`) and, on
|
||||
confirm, appends a `planetRename` command to the local order draft
|
||||
through the `OrderDraftStore` provided via context.
|
||||
|
||||
- `local` / `other` carry the full economy: name, owner (other only),
|
||||
coordinates, size, population, colonists, industry, both stockpiles,
|
||||
natural resources, current production, free production potential.
|
||||
- `uninhabited` keeps name, coordinates, size, both stockpiles, and
|
||||
natural resources — the engine does not project industry or
|
||||
population for unowned planets.
|
||||
- `unidentified` is reduced to coordinates plus a no-data hint.
|
||||
|
||||
The component is purely presentational: the parent supplies a
|
||||
`ReportPlanet` snapshot resolved from `GameStateStore`, no store
|
||||
lookups happen here. Phase 14 will extend the same component with a
|
||||
`Rename` action; the read-only layout stays the structural baseline.
|
||||
The read-only path stays unchanged for non-`local` planets. The
|
||||
inline editor lives directly inside this component per PLAN.md
|
||||
Phase 14 — a separate file would be over-abstraction for one input
|
||||
field with five buttons.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getContext, tick } from "svelte";
|
||||
import type { ReportPlanet } from "../../api/game-state";
|
||||
import { i18n, type TranslationKey } from "$lib/i18n/index.svelte";
|
||||
import {
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
OrderDraftStore,
|
||||
} from "../../sync/order-draft.svelte";
|
||||
import {
|
||||
validateEntityName,
|
||||
type EntityNameInvalidReason,
|
||||
} from "$lib/util/entity-name";
|
||||
|
||||
type Props = {
|
||||
planet: ReportPlanet;
|
||||
@@ -31,6 +37,34 @@ lookups happen here. Phase 14 will extend the same component with a
|
||||
unidentified: "game.inspector.planet.kind.unidentified",
|
||||
};
|
||||
|
||||
const invalidReasonKeyMap: Record<EntityNameInvalidReason, TranslationKey> = {
|
||||
empty: "game.inspector.planet.rename.invalid.empty",
|
||||
too_long: "game.inspector.planet.rename.invalid.too_long",
|
||||
starts_with_special:
|
||||
"game.inspector.planet.rename.invalid.starts_with_special",
|
||||
ends_with_special: "game.inspector.planet.rename.invalid.ends_with_special",
|
||||
consecutive_specials:
|
||||
"game.inspector.planet.rename.invalid.consecutive_specials",
|
||||
whitespace: "game.inspector.planet.rename.invalid.whitespace",
|
||||
disallowed_character:
|
||||
"game.inspector.planet.rename.invalid.disallowed_character",
|
||||
};
|
||||
|
||||
const draft = getContext<OrderDraftStore | undefined>(
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
);
|
||||
|
||||
let renameOpen = $state(false);
|
||||
let renameInput = $state("");
|
||||
let inputEl: HTMLInputElement | null = $state(null);
|
||||
|
||||
const renameValidation = $derived(validateEntityName(renameInput));
|
||||
const renameInvalidMessage = $derived(
|
||||
renameValidation.ok
|
||||
? ""
|
||||
: i18n.t(invalidReasonKeyMap[renameValidation.reason]),
|
||||
);
|
||||
|
||||
const kindLabel = $derived(i18n.t(kindKeyMap[planet.kind]));
|
||||
const coordinates = $derived(
|
||||
`(${formatNumber(planet.x)}, ${formatNumber(planet.y)})`,
|
||||
@@ -47,6 +81,44 @@ lookups happen here. Phase 14 will extend the same component with a
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async function openRename(): Promise<void> {
|
||||
renameInput = planet.name;
|
||||
renameOpen = true;
|
||||
await tick();
|
||||
inputEl?.focus();
|
||||
inputEl?.select();
|
||||
}
|
||||
|
||||
function cancelRename(): void {
|
||||
renameOpen = false;
|
||||
renameInput = "";
|
||||
}
|
||||
|
||||
async function confirmRename(): Promise<void> {
|
||||
const result = validateEntityName(renameInput);
|
||||
if (!result.ok || draft === undefined) return;
|
||||
await draft.add({
|
||||
kind: "planetRename",
|
||||
id: crypto.randomUUID(),
|
||||
planetNumber: planet.number,
|
||||
name: result.value,
|
||||
});
|
||||
renameOpen = false;
|
||||
renameInput = "";
|
||||
}
|
||||
|
||||
function onKeyDown(event: KeyboardEvent): void {
|
||||
if (event.key === "Escape") {
|
||||
event.preventDefault();
|
||||
cancelRename();
|
||||
return;
|
||||
}
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
void confirmRename();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section
|
||||
@@ -60,8 +132,65 @@ lookups happen here. Phase 14 will extend the same component with a
|
||||
{#if planet.kind !== "unidentified"}
|
||||
<h3 class="name" data-testid="inspector-planet-name">{planet.name}</h3>
|
||||
{/if}
|
||||
{#if planet.kind === "local" && !renameOpen}
|
||||
<button
|
||||
type="button"
|
||||
class="action"
|
||||
data-testid="inspector-planet-rename-action"
|
||||
onclick={openRename}
|
||||
>
|
||||
{i18n.t("game.inspector.planet.action.rename")}
|
||||
</button>
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
{#if planet.kind === "local" && renameOpen}
|
||||
<div class="rename" data-testid="inspector-planet-rename">
|
||||
<label class="rename-label" for="planet-rename-input">
|
||||
{i18n.t("game.inspector.planet.rename.title")}
|
||||
</label>
|
||||
<input
|
||||
id="planet-rename-input"
|
||||
type="text"
|
||||
class="rename-input"
|
||||
data-testid="inspector-planet-rename-input"
|
||||
bind:value={renameInput}
|
||||
bind:this={inputEl}
|
||||
onkeydown={onKeyDown}
|
||||
aria-invalid={renameValidation.ok ? "false" : "true"}
|
||||
aria-describedby={renameValidation.ok ? undefined : "planet-rename-error"}
|
||||
/>
|
||||
{#if !renameValidation.ok}
|
||||
<p
|
||||
id="planet-rename-error"
|
||||
class="rename-error"
|
||||
data-testid="inspector-planet-rename-error"
|
||||
>
|
||||
{renameInvalidMessage}
|
||||
</p>
|
||||
{/if}
|
||||
<div class="rename-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="rename-cancel"
|
||||
data-testid="inspector-planet-rename-cancel"
|
||||
onclick={cancelRename}
|
||||
>
|
||||
{i18n.t("game.inspector.planet.rename.cancel")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="rename-confirm"
|
||||
data-testid="inspector-planet-rename-confirm"
|
||||
disabled={!renameValidation.ok || draft === undefined}
|
||||
onclick={() => void confirmRename()}
|
||||
>
|
||||
{i18n.t("game.inspector.planet.rename.confirm")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<dl class="fields">
|
||||
{#if planet.kind === "other" && planet.owner !== null}
|
||||
<div class="field" data-testid="inspector-planet-field-owner">
|
||||
@@ -194,4 +323,69 @@ lookups happen here. Phase 14 will extend the same component with a
|
||||
color: #888;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.action {
|
||||
align-self: flex-start;
|
||||
margin-top: 0.25rem;
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
padding: 0.2rem 0.55rem;
|
||||
background: transparent;
|
||||
color: #aab;
|
||||
border: 1px solid #2a3150;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.action:hover {
|
||||
color: #e8eaf6;
|
||||
border-color: #6d8cff;
|
||||
}
|
||||
.rename {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.rename-label {
|
||||
font-size: 0.85rem;
|
||||
color: #aab;
|
||||
}
|
||||
.rename-input {
|
||||
font: inherit;
|
||||
padding: 0.3rem 0.5rem;
|
||||
background: #0a0e1a;
|
||||
color: #e8eaf6;
|
||||
border: 1px solid #2a3150;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.rename-input[aria-invalid="true"] {
|
||||
border-color: #d97a7a;
|
||||
}
|
||||
.rename-error {
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
color: #d97a7a;
|
||||
}
|
||||
.rename-actions {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.rename-cancel,
|
||||
.rename-confirm {
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25rem 0.65rem;
|
||||
background: transparent;
|
||||
color: #aab;
|
||||
border: 1px solid #2a3150;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.rename-confirm:not(:disabled):hover,
|
||||
.rename-cancel:hover {
|
||||
color: #e8eaf6;
|
||||
border-color: #6d8cff;
|
||||
}
|
||||
.rename-confirm:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Provides a derived view of the server `GameReport` overlaid with
|
||||
// the player's local order draft. Every consumer that needs to
|
||||
// render the player's current intent (inspector, map, mobile sheet)
|
||||
// subscribes through this context instead of reading `gameState.report`
|
||||
// directly.
|
||||
//
|
||||
// Lifetime matches the in-game shell layout: one source per game,
|
||||
// rebuilt on layout remount. The source itself is a thin reactive
|
||||
// wrapper — the actual overlay computation lives in
|
||||
// `applyOrderOverlay` (api/game-state.ts) and runs lazily on every
|
||||
// access through the `report` getter.
|
||||
|
||||
import {
|
||||
applyOrderOverlay,
|
||||
type GameReport,
|
||||
} from "../api/game-state";
|
||||
import type { GameStateStore } from "./game-state.svelte";
|
||||
import type { OrderDraftStore } from "../sync/order-draft.svelte";
|
||||
|
||||
/**
|
||||
* RENDERED_REPORT_CONTEXT_KEY is the Svelte context key the in-game
|
||||
* shell layout uses to expose a `RenderedReportSource` instance to
|
||||
* descendants. Consumers read the latest overlay through `source.report`
|
||||
* (a reactive getter) and re-render when the underlying stores
|
||||
* change.
|
||||
*/
|
||||
export const RENDERED_REPORT_CONTEXT_KEY = Symbol("rendered-report");
|
||||
|
||||
export interface RenderedReportSource {
|
||||
readonly report: GameReport | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* createRenderedReportSource binds the live `GameStateStore` and
|
||||
* `OrderDraftStore` to a getter that returns the overlay-applied
|
||||
* report on every read. The getter is reactive: Svelte tracks the
|
||||
* underlying `$state` accesses inside `applyOrderOverlay`, so any
|
||||
* change to the report or the draft re-runs every dependent
|
||||
* `$derived` block.
|
||||
*/
|
||||
export function createRenderedReportSource(
|
||||
gameState: GameStateStore,
|
||||
orderDraft: OrderDraftStore,
|
||||
): RenderedReportSource {
|
||||
return {
|
||||
get report(): GameReport | null {
|
||||
const raw = gameState.report;
|
||||
if (raw === null) return null;
|
||||
return applyOrderOverlay(raw, orderDraft.commands, orderDraft.statuses);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -14,18 +14,18 @@ from the Phase 10 stub.
|
||||
<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";
|
||||
import {
|
||||
SELECTION_CONTEXT_KEY,
|
||||
type SelectionStore,
|
||||
} from "$lib/selection.svelte";
|
||||
import {
|
||||
RENDERED_REPORT_CONTEXT_KEY,
|
||||
type RenderedReportSource,
|
||||
} from "$lib/rendered-report.svelte";
|
||||
import Planet from "$lib/inspectors/planet.svelte";
|
||||
|
||||
const gameState = getContext<GameStateStore | undefined>(
|
||||
GAME_STATE_CONTEXT_KEY,
|
||||
const renderedReport = getContext<RenderedReportSource | undefined>(
|
||||
RENDERED_REPORT_CONTEXT_KEY,
|
||||
);
|
||||
const selection = getContext<SelectionStore | undefined>(
|
||||
SELECTION_CONTEXT_KEY,
|
||||
@@ -34,7 +34,7 @@ from the Phase 10 stub.
|
||||
const selectedPlanet = $derived.by(() => {
|
||||
const sel = selection?.selected;
|
||||
if (sel === undefined || sel === null || sel.kind !== "planet") return null;
|
||||
const report = gameState?.report;
|
||||
const report = renderedReport?.report;
|
||||
if (report === undefined || report === null) return null;
|
||||
return report.planets.find((p) => p.number === sel.id) ?? null;
|
||||
});
|
||||
|
||||
@@ -1,31 +1,143 @@
|
||||
<!--
|
||||
Order composer tool. Resolves the per-game `OrderDraftStore` from
|
||||
context (set by `routes/games/[id]/+layout.svelte`) and renders the
|
||||
draft as a vertical, top-to-bottom command list. Empty state shows
|
||||
the i18n empty-state copy; non-empty state shows an ordered list of
|
||||
rows, each with a stable `data-testid` plus a per-row delete button.
|
||||
Order composer tool. Resolves the per-game `OrderDraftStore`,
|
||||
`GameStateStore`, and `GalaxyClient` from context (all set by
|
||||
`routes/games/[id]/+layout.svelte`) and renders the local draft as
|
||||
a vertical list with per-row status, a delete button, and a Submit
|
||||
button at the bottom.
|
||||
|
||||
Phase 12 has no UI for adding commands — Phase 14 lands the first
|
||||
end-to-end command (`planetRename`) and the inspector affordance
|
||||
that pushes it into the draft. Tests exercise the skeleton through
|
||||
`__galaxyDebug.seedOrderDraft` (Playwright) and via direct store
|
||||
construction (Vitest).
|
||||
Phase 14 wires the first end-to-end command: clicking Submit calls
|
||||
`submitOrder` for every entry in `valid` status, flips the in-flight
|
||||
rows to `submitting`, then merges the per-command verdict back into
|
||||
the draft once the gateway responds. The optimistic overlay in
|
||||
`renderedReport` continues to show the player's intent while the
|
||||
order is in flight, so the inspector and the map reflect the new
|
||||
name even before the server applies it at turn cutoff.
|
||||
|
||||
Tests exercise the skeleton through `__galaxyDebug.seedOrderDraft`
|
||||
(Playwright) and via direct store / mocked-client construction
|
||||
(Vitest).
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getContext } from "svelte";
|
||||
import { i18n } from "$lib/i18n/index.svelte";
|
||||
import { i18n, type TranslationKey } from "$lib/i18n/index.svelte";
|
||||
import {
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
OrderDraftStore,
|
||||
} from "../../sync/order-draft.svelte";
|
||||
import {
|
||||
GAME_STATE_CONTEXT_KEY,
|
||||
type GameStateStore,
|
||||
} from "$lib/game-state.svelte";
|
||||
import {
|
||||
GALAXY_CLIENT_CONTEXT_KEY,
|
||||
type GalaxyClientHandle,
|
||||
} from "$lib/galaxy-client-context.svelte";
|
||||
import type { CommandStatus, OrderCommand } from "../../sync/order-types";
|
||||
import { submitOrder } from "../../sync/submit";
|
||||
|
||||
const draft = getContext<OrderDraftStore | undefined>(
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
);
|
||||
const gameState = getContext<GameStateStore | undefined>(
|
||||
GAME_STATE_CONTEXT_KEY,
|
||||
);
|
||||
const galaxyClient = getContext<GalaxyClientHandle | undefined>(
|
||||
GALAXY_CLIENT_CONTEXT_KEY,
|
||||
);
|
||||
|
||||
function describe(cmd: { kind: string; label?: string }): string {
|
||||
if (cmd.kind === "placeholder") return cmd.label ?? cmd.kind;
|
||||
return cmd.kind;
|
||||
const statusKeyMap: Record<CommandStatus, TranslationKey> = {
|
||||
draft: "game.sidebar.order.status.draft",
|
||||
valid: "game.sidebar.order.status.valid",
|
||||
invalid: "game.sidebar.order.status.invalid",
|
||||
submitting: "game.sidebar.order.status.submitting",
|
||||
applied: "game.sidebar.order.status.applied",
|
||||
rejected: "game.sidebar.order.status.rejected",
|
||||
};
|
||||
|
||||
let submitInFlight = $state(false);
|
||||
let submitError = $state<string | null>(null);
|
||||
|
||||
const submittable = $derived.by(() => {
|
||||
if (draft === undefined) return [] as OrderCommand[];
|
||||
return draft.commands.filter(
|
||||
(cmd) => draft.statuses[cmd.id] === "valid",
|
||||
);
|
||||
});
|
||||
|
||||
const hasInvalid = $derived.by(() => {
|
||||
if (draft === undefined) return false;
|
||||
return draft.commands.some((cmd) => draft.statuses[cmd.id] === "invalid");
|
||||
});
|
||||
|
||||
const submitDisabled = $derived(
|
||||
draft === undefined ||
|
||||
galaxyClient === undefined ||
|
||||
galaxyClient.client === null ||
|
||||
submitInFlight ||
|
||||
submittable.length === 0 ||
|
||||
hasInvalid,
|
||||
);
|
||||
|
||||
function describe(cmd: OrderCommand): string {
|
||||
switch (cmd.kind) {
|
||||
case "placeholder":
|
||||
return i18n.t("game.sidebar.order.label.placeholder", {
|
||||
label: cmd.label,
|
||||
});
|
||||
case "planetRename":
|
||||
return i18n.t("game.sidebar.order.label.planet_rename", {
|
||||
planet: String(cmd.planetNumber),
|
||||
name: cmd.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function statusOf(cmd: OrderCommand): CommandStatus {
|
||||
return draft?.statuses[cmd.id] ?? "draft";
|
||||
}
|
||||
|
||||
async function submit(): Promise<void> {
|
||||
if (
|
||||
draft === undefined ||
|
||||
galaxyClient === undefined ||
|
||||
galaxyClient.client === null ||
|
||||
gameState === undefined
|
||||
)
|
||||
return;
|
||||
if (submittable.length === 0 || hasInvalid) return;
|
||||
const ids = submittable.map((cmd) => cmd.id);
|
||||
const snapshot = submittable.slice();
|
||||
submitInFlight = true;
|
||||
submitError = null;
|
||||
draft.markSubmitting(ids);
|
||||
try {
|
||||
const result = await submitOrder(
|
||||
galaxyClient.client,
|
||||
gameState.gameId,
|
||||
snapshot,
|
||||
{ updatedAt: draft.updatedAt },
|
||||
);
|
||||
if (result.ok) {
|
||||
draft.applyResults({
|
||||
results: result.results,
|
||||
updatedAt: result.updatedAt,
|
||||
});
|
||||
if (gameState !== undefined) {
|
||||
await gameState.refresh();
|
||||
}
|
||||
} else {
|
||||
draft.markRejected(ids);
|
||||
submitError = i18n.t("game.sidebar.order.error.batch_failed", {
|
||||
message: result.message,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
draft.revertSubmittingToValid();
|
||||
submitError =
|
||||
err instanceof Error ? err.message : "submit failed";
|
||||
} finally {
|
||||
submitInFlight = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -38,11 +150,22 @@ construction (Vitest).
|
||||
{:else}
|
||||
<ol class="commands" data-testid="order-list">
|
||||
{#each draft.commands as cmd, index (cmd.id)}
|
||||
<li class="command" data-testid="order-command-{index}">
|
||||
{@const status = statusOf(cmd)}
|
||||
<li
|
||||
class="command"
|
||||
data-testid="order-command-{index}"
|
||||
data-command-status={status}
|
||||
>
|
||||
<span class="index" aria-hidden="true">{index + 1}.</span>
|
||||
<span class="label" data-testid="order-command-label-{index}">
|
||||
{describe(cmd)}
|
||||
</span>
|
||||
<span
|
||||
class="status status-{status}"
|
||||
data-testid="order-command-status-{index}"
|
||||
>
|
||||
{i18n.t(statusKeyMap[status])}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="delete"
|
||||
@@ -54,6 +177,20 @@ construction (Vitest).
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
<button
|
||||
type="button"
|
||||
class="submit"
|
||||
data-testid="order-submit"
|
||||
disabled={submitDisabled}
|
||||
onclick={() => void submit()}
|
||||
>
|
||||
{submitInFlight
|
||||
? i18n.t("game.sidebar.order.submit_in_flight")
|
||||
: i18n.t("game.sidebar.order.submit")}
|
||||
</button>
|
||||
{#if submitError !== null}
|
||||
<p class="error" data-testid="order-submit-error">{submitError}</p>
|
||||
{/if}
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -72,14 +209,15 @@ construction (Vitest).
|
||||
}
|
||||
.commands {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
margin: 0 0 0.75rem;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
.command {
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto auto;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.4rem 0.5rem;
|
||||
@@ -88,17 +226,40 @@ construction (Vitest).
|
||||
border-radius: 4px;
|
||||
}
|
||||
.index {
|
||||
min-width: 1.5rem;
|
||||
color: #aab;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.status {
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #2a3150;
|
||||
color: #aab;
|
||||
}
|
||||
.status-applied {
|
||||
color: #8be9a3;
|
||||
border-color: #2f6d3f;
|
||||
}
|
||||
.status-rejected {
|
||||
color: #d97a7a;
|
||||
border-color: #6d2f2f;
|
||||
}
|
||||
.status-invalid {
|
||||
color: #d6b86c;
|
||||
border-color: #6d562f;
|
||||
}
|
||||
.status-submitting {
|
||||
color: #6d8cff;
|
||||
border-color: #2f3f6d;
|
||||
}
|
||||
.delete {
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
@@ -113,4 +274,26 @@ construction (Vitest).
|
||||
color: #e8eaf6;
|
||||
border-color: #6d8cff;
|
||||
}
|
||||
.submit {
|
||||
font: inherit;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.4rem 1rem;
|
||||
background: #1d2440;
|
||||
color: #e8eaf6;
|
||||
border: 1px solid #2a3150;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.submit:not(:disabled):hover {
|
||||
border-color: #6d8cff;
|
||||
}
|
||||
.submit:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.error {
|
||||
margin: 0.5rem 0 0;
|
||||
color: #d97a7a;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// TS port of `pkg/util/string.go.ValidateTypeName` — every entity
|
||||
// name (planet, ship class, science, …) the player edits goes
|
||||
// through this validator before reaching the order draft, so the
|
||||
// client-side check is identical to the server-side one. A
|
||||
// locally-valid name is always accepted at the wire level; an
|
||||
// invalid name never produces a network round-trip.
|
||||
|
||||
const MAX_LENGTH = 30;
|
||||
|
||||
const ALLOWED_SPECIALS = new Set<string>("!@#$%^*-_=+~()[]{}");
|
||||
|
||||
const SPECIAL_RUN_LIMIT = 2;
|
||||
|
||||
/**
|
||||
* EntityNameInvalidReason is the closed enumeration of reasons a
|
||||
* name can fail validation. The values are stable identifiers so
|
||||
* the inspector tooltip and the order-tab status row can map them
|
||||
* to localised copy via `i18n.t("game.order.invalid." + reason)`.
|
||||
*/
|
||||
export type EntityNameInvalidReason =
|
||||
| "empty"
|
||||
| "too_long"
|
||||
| "starts_with_special"
|
||||
| "ends_with_special"
|
||||
| "consecutive_specials"
|
||||
| "whitespace"
|
||||
| "disallowed_character";
|
||||
|
||||
export type EntityNameValidation =
|
||||
| { ok: true; value: string }
|
||||
| { ok: false; reason: EntityNameInvalidReason };
|
||||
|
||||
/**
|
||||
* validateEntityName mirrors `ValidateTypeName` exactly: the input
|
||||
* is trimmed, must be non-empty, must fit in 30 runes, must not
|
||||
* start or end with a special character, and must contain only
|
||||
* letters, digits, combining marks, or the allowed specials with at
|
||||
* most two in a row. Returns the trimmed value on success or a
|
||||
* structured reason on failure.
|
||||
*/
|
||||
export function validateEntityName(input: string): EntityNameValidation {
|
||||
const trimmed = input.trim();
|
||||
if (trimmed.length === 0) {
|
||||
return { ok: false, reason: "empty" };
|
||||
}
|
||||
|
||||
const runes = Array.from(trimmed);
|
||||
if (runes.length > MAX_LENGTH) {
|
||||
return { ok: false, reason: "too_long" };
|
||||
}
|
||||
|
||||
const first = runes[0]!;
|
||||
const last = runes[runes.length - 1]!;
|
||||
if (ALLOWED_SPECIALS.has(first)) {
|
||||
return { ok: false, reason: "starts_with_special" };
|
||||
}
|
||||
if (ALLOWED_SPECIALS.has(last)) {
|
||||
return { ok: false, reason: "ends_with_special" };
|
||||
}
|
||||
|
||||
let specialRun = 0;
|
||||
for (const rune of runes) {
|
||||
if (isWhitespace(rune)) {
|
||||
return { ok: false, reason: "whitespace" };
|
||||
}
|
||||
if (isLetter(rune) || isDigit(rune) || isCombiningMark(rune)) {
|
||||
specialRun = 0;
|
||||
continue;
|
||||
}
|
||||
if (ALLOWED_SPECIALS.has(rune)) {
|
||||
specialRun += 1;
|
||||
if (specialRun > SPECIAL_RUN_LIMIT) {
|
||||
return { ok: false, reason: "consecutive_specials" };
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return { ok: false, reason: "disallowed_character" };
|
||||
}
|
||||
|
||||
return { ok: true, value: trimmed };
|
||||
}
|
||||
|
||||
function isWhitespace(rune: string): boolean {
|
||||
// Matches Go's `unicode.IsSpace`.
|
||||
return /\s/u.test(rune);
|
||||
}
|
||||
|
||||
function isLetter(rune: string): boolean {
|
||||
return /\p{L}/u.test(rune);
|
||||
}
|
||||
|
||||
function isDigit(rune: string): boolean {
|
||||
return /\p{N}/u.test(rune);
|
||||
}
|
||||
|
||||
function isCombiningMark(rune: string): boolean {
|
||||
return /\p{M}/u.test(rune);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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 { CommandFleetMerge, CommandFleetMergeT } from './order/command-fleet-merge.js';
|
||||
export { CommandFleetSend, CommandFleetSendT } from './order/command-fleet-send.js';
|
||||
export { CommandItem, CommandItemT } from './order/command-item.js';
|
||||
export { CommandPayload } from './order/command-payload.js';
|
||||
export { CommandPlanetProduce, CommandPlanetProduceT } from './order/command-planet-produce.js';
|
||||
export { CommandPlanetRename, CommandPlanetRenameT } from './order/command-planet-rename.js';
|
||||
export { CommandPlanetRouteRemove, CommandPlanetRouteRemoveT } from './order/command-planet-route-remove.js';
|
||||
export { CommandPlanetRouteSet, CommandPlanetRouteSetT } from './order/command-planet-route-set.js';
|
||||
export { CommandRaceQuit, CommandRaceQuitT } from './order/command-race-quit.js';
|
||||
export { CommandRaceRelation, CommandRaceRelationT } from './order/command-race-relation.js';
|
||||
export { CommandRaceVote, CommandRaceVoteT } from './order/command-race-vote.js';
|
||||
export { CommandScienceCreate, CommandScienceCreateT } from './order/command-science-create.js';
|
||||
export { CommandScienceRemove, CommandScienceRemoveT } from './order/command-science-remove.js';
|
||||
export { CommandShipClassCreate, CommandShipClassCreateT } from './order/command-ship-class-create.js';
|
||||
export { CommandShipClassMerge, CommandShipClassMergeT } from './order/command-ship-class-merge.js';
|
||||
export { CommandShipClassRemove, CommandShipClassRemoveT } from './order/command-ship-class-remove.js';
|
||||
export { CommandShipGroupBreak, CommandShipGroupBreakT } from './order/command-ship-group-break.js';
|
||||
export { CommandShipGroupDismantle, CommandShipGroupDismantleT } from './order/command-ship-group-dismantle.js';
|
||||
export { CommandShipGroupJoinFleet, CommandShipGroupJoinFleetT } from './order/command-ship-group-join-fleet.js';
|
||||
export { CommandShipGroupLoad, CommandShipGroupLoadT } from './order/command-ship-group-load.js';
|
||||
export { CommandShipGroupMerge, CommandShipGroupMergeT } from './order/command-ship-group-merge.js';
|
||||
export { CommandShipGroupSend, CommandShipGroupSendT } from './order/command-ship-group-send.js';
|
||||
export { CommandShipGroupTransfer, CommandShipGroupTransferT } from './order/command-ship-group-transfer.js';
|
||||
export { CommandShipGroupUnload, CommandShipGroupUnloadT } from './order/command-ship-group-unload.js';
|
||||
export { CommandShipGroupUpgrade, CommandShipGroupUpgradeT } from './order/command-ship-group-upgrade.js';
|
||||
export { PlanetProduction } from './order/planet-production.js';
|
||||
export { PlanetRouteLoadType } from './order/planet-route-load-type.js';
|
||||
export { Relation } from './order/relation.js';
|
||||
export { ShipGroupCargo } from './order/ship-group-cargo.js';
|
||||
export { ShipGroupUpgradeTech } from './order/ship-group-upgrade-tech.js';
|
||||
export { UserGamesCommand, UserGamesCommandT } from './order/user-games-command.js';
|
||||
export { UserGamesCommandResponse, UserGamesCommandResponseT } from './order/user-games-command-response.js';
|
||||
export { UserGamesOrder, UserGamesOrderT } from './order/user-games-order.js';
|
||||
export { UserGamesOrderGet, UserGamesOrderGetT } from './order/user-games-order-get.js';
|
||||
export { UserGamesOrderGetResponse, UserGamesOrderGetResponseT } from './order/user-games-order-get-response.js';
|
||||
export { UserGamesOrderResponse, UserGamesOrderResponseT } from './order/user-games-order-response.js';
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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 CommandFleetMerge implements flatbuffers.IUnpackableObject<CommandFleetMergeT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandFleetMerge {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandFleetMerge(bb:flatbuffers.ByteBuffer, obj?:CommandFleetMerge):CommandFleetMerge {
|
||||
return (obj || new CommandFleetMerge()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandFleetMerge(bb:flatbuffers.ByteBuffer, obj?:CommandFleetMerge):CommandFleetMerge {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandFleetMerge()).__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;
|
||||
}
|
||||
|
||||
target():string|null
|
||||
target(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
target(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 startCommandFleetMerge(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, nameOffset, 0);
|
||||
}
|
||||
|
||||
static addTarget(builder:flatbuffers.Builder, targetOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, targetOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandFleetMerge(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandFleetMerge(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandFleetMerge.startCommandFleetMerge(builder);
|
||||
CommandFleetMerge.addName(builder, nameOffset);
|
||||
CommandFleetMerge.addTarget(builder, targetOffset);
|
||||
return CommandFleetMerge.endCommandFleetMerge(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandFleetMergeT {
|
||||
return new CommandFleetMergeT(
|
||||
this.name(),
|
||||
this.target()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandFleetMergeT): void {
|
||||
_o.name = this.name();
|
||||
_o.target = this.target();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandFleetMergeT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public name: string|Uint8Array|null = null,
|
||||
public target: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
const target = (this.target !== null ? builder.createString(this.target!) : 0);
|
||||
|
||||
return CommandFleetMerge.createCommandFleetMerge(builder,
|
||||
name,
|
||||
target
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 CommandFleetSend implements flatbuffers.IUnpackableObject<CommandFleetSendT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandFleetSend {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandFleetSend(bb:flatbuffers.ByteBuffer, obj?:CommandFleetSend):CommandFleetSend {
|
||||
return (obj || new CommandFleetSend()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandFleetSend(bb:flatbuffers.ByteBuffer, obj?:CommandFleetSend):CommandFleetSend {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandFleetSend()).__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;
|
||||
}
|
||||
|
||||
destination():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
static startCommandFleetSend(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, nameOffset, 0);
|
||||
}
|
||||
|
||||
static addDestination(builder:flatbuffers.Builder, destination:bigint) {
|
||||
builder.addFieldInt64(1, destination, BigInt('0'));
|
||||
}
|
||||
|
||||
static endCommandFleetSend(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandFleetSend(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, destination:bigint):flatbuffers.Offset {
|
||||
CommandFleetSend.startCommandFleetSend(builder);
|
||||
CommandFleetSend.addName(builder, nameOffset);
|
||||
CommandFleetSend.addDestination(builder, destination);
|
||||
return CommandFleetSend.endCommandFleetSend(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandFleetSendT {
|
||||
return new CommandFleetSendT(
|
||||
this.name(),
|
||||
this.destination()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandFleetSendT): void {
|
||||
_o.name = this.name();
|
||||
_o.destination = this.destination();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandFleetSendT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public name: string|Uint8Array|null = null,
|
||||
public destination: bigint = BigInt('0')
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
|
||||
return CommandFleetSend.createCommandFleetSend(builder,
|
||||
name,
|
||||
this.destination
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
// 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 { CommandFleetMerge, CommandFleetMergeT } from './command-fleet-merge.js';
|
||||
import { CommandFleetSend, CommandFleetSendT } from './command-fleet-send.js';
|
||||
import { CommandPayload, unionToCommandPayload, unionListToCommandPayload } from './command-payload.js';
|
||||
import { CommandPlanetProduce, CommandPlanetProduceT } from './command-planet-produce.js';
|
||||
import { CommandPlanetRename, CommandPlanetRenameT } from './command-planet-rename.js';
|
||||
import { CommandPlanetRouteRemove, CommandPlanetRouteRemoveT } from './command-planet-route-remove.js';
|
||||
import { CommandPlanetRouteSet, CommandPlanetRouteSetT } from './command-planet-route-set.js';
|
||||
import { CommandRaceQuit, CommandRaceQuitT } from './command-race-quit.js';
|
||||
import { CommandRaceRelation, CommandRaceRelationT } from './command-race-relation.js';
|
||||
import { CommandRaceVote, CommandRaceVoteT } from './command-race-vote.js';
|
||||
import { CommandScienceCreate, CommandScienceCreateT } from './command-science-create.js';
|
||||
import { CommandScienceRemove, CommandScienceRemoveT } from './command-science-remove.js';
|
||||
import { CommandShipClassCreate, CommandShipClassCreateT } from './command-ship-class-create.js';
|
||||
import { CommandShipClassMerge, CommandShipClassMergeT } from './command-ship-class-merge.js';
|
||||
import { CommandShipClassRemove, CommandShipClassRemoveT } from './command-ship-class-remove.js';
|
||||
import { CommandShipGroupBreak, CommandShipGroupBreakT } from './command-ship-group-break.js';
|
||||
import { CommandShipGroupDismantle, CommandShipGroupDismantleT } from './command-ship-group-dismantle.js';
|
||||
import { CommandShipGroupJoinFleet, CommandShipGroupJoinFleetT } from './command-ship-group-join-fleet.js';
|
||||
import { CommandShipGroupLoad, CommandShipGroupLoadT } from './command-ship-group-load.js';
|
||||
import { CommandShipGroupMerge, CommandShipGroupMergeT } from './command-ship-group-merge.js';
|
||||
import { CommandShipGroupSend, CommandShipGroupSendT } from './command-ship-group-send.js';
|
||||
import { CommandShipGroupTransfer, CommandShipGroupTransferT } from './command-ship-group-transfer.js';
|
||||
import { CommandShipGroupUnload, CommandShipGroupUnloadT } from './command-ship-group-unload.js';
|
||||
import { CommandShipGroupUpgrade, CommandShipGroupUpgradeT } from './command-ship-group-upgrade.js';
|
||||
|
||||
|
||||
export class CommandItem implements flatbuffers.IUnpackableObject<CommandItemT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandItem {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandItem(bb:flatbuffers.ByteBuffer, obj?:CommandItem):CommandItem {
|
||||
return (obj || new CommandItem()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandItem(bb:flatbuffers.ByteBuffer, obj?:CommandItem):CommandItem {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandItem()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
cmdId():string|null
|
||||
cmdId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
cmdId(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;
|
||||
}
|
||||
|
||||
cmdApplied():boolean|null {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : null;
|
||||
}
|
||||
|
||||
cmdErrorCode():bigint|null {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : null;
|
||||
}
|
||||
|
||||
payloadType():CommandPayload {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 10);
|
||||
return offset ? this.bb!.readUint8(this.bb_pos + offset) : CommandPayload.NONE;
|
||||
}
|
||||
|
||||
payload<T extends flatbuffers.Table>(obj:any):any|null {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 12);
|
||||
return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null;
|
||||
}
|
||||
|
||||
static startCommandItem(builder:flatbuffers.Builder) {
|
||||
builder.startObject(5);
|
||||
}
|
||||
|
||||
static addCmdId(builder:flatbuffers.Builder, cmdIdOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, cmdIdOffset, 0);
|
||||
}
|
||||
|
||||
static addCmdApplied(builder:flatbuffers.Builder, cmdApplied:boolean) {
|
||||
builder.addFieldInt8(1, +cmdApplied, null);
|
||||
}
|
||||
|
||||
static addCmdErrorCode(builder:flatbuffers.Builder, cmdErrorCode:bigint) {
|
||||
builder.addFieldInt64(2, cmdErrorCode, null);
|
||||
}
|
||||
|
||||
static addPayloadType(builder:flatbuffers.Builder, payloadType:CommandPayload) {
|
||||
builder.addFieldInt8(3, payloadType, CommandPayload.NONE);
|
||||
}
|
||||
|
||||
static addPayload(builder:flatbuffers.Builder, payloadOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(4, payloadOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandItem(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
builder.requiredField(offset, 12) // payload
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandItem(builder:flatbuffers.Builder, cmdIdOffset:flatbuffers.Offset, cmdApplied:boolean|null, cmdErrorCode:bigint|null, payloadType:CommandPayload, payloadOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandItem.startCommandItem(builder);
|
||||
CommandItem.addCmdId(builder, cmdIdOffset);
|
||||
if (cmdApplied !== null)
|
||||
CommandItem.addCmdApplied(builder, cmdApplied);
|
||||
if (cmdErrorCode !== null)
|
||||
CommandItem.addCmdErrorCode(builder, cmdErrorCode);
|
||||
CommandItem.addPayloadType(builder, payloadType);
|
||||
CommandItem.addPayload(builder, payloadOffset);
|
||||
return CommandItem.endCommandItem(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandItemT {
|
||||
return new CommandItemT(
|
||||
this.cmdId(),
|
||||
this.cmdApplied(),
|
||||
this.cmdErrorCode(),
|
||||
this.payloadType(),
|
||||
(() => {
|
||||
const temp = unionToCommandPayload(this.payloadType(), this.payload.bind(this));
|
||||
if(temp === null) { return null; }
|
||||
return temp.unpack()
|
||||
})()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandItemT): void {
|
||||
_o.cmdId = this.cmdId();
|
||||
_o.cmdApplied = this.cmdApplied();
|
||||
_o.cmdErrorCode = this.cmdErrorCode();
|
||||
_o.payloadType = this.payloadType();
|
||||
_o.payload = (() => {
|
||||
const temp = unionToCommandPayload(this.payloadType(), this.payload.bind(this));
|
||||
if(temp === null) { return null; }
|
||||
return temp.unpack()
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandItemT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public cmdId: string|Uint8Array|null = null,
|
||||
public cmdApplied: boolean|null = null,
|
||||
public cmdErrorCode: bigint|null = null,
|
||||
public payloadType: CommandPayload = CommandPayload.NONE,
|
||||
public payload: CommandFleetMergeT|CommandFleetSendT|CommandPlanetProduceT|CommandPlanetRenameT|CommandPlanetRouteRemoveT|CommandPlanetRouteSetT|CommandRaceQuitT|CommandRaceRelationT|CommandRaceVoteT|CommandScienceCreateT|CommandScienceRemoveT|CommandShipClassCreateT|CommandShipClassMergeT|CommandShipClassRemoveT|CommandShipGroupBreakT|CommandShipGroupDismantleT|CommandShipGroupJoinFleetT|CommandShipGroupLoadT|CommandShipGroupMergeT|CommandShipGroupSendT|CommandShipGroupTransferT|CommandShipGroupUnloadT|CommandShipGroupUpgradeT|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const cmdId = (this.cmdId !== null ? builder.createString(this.cmdId!) : 0);
|
||||
const payload = builder.createObjectOffset(this.payload);
|
||||
|
||||
return CommandItem.createCommandItem(builder,
|
||||
cmdId,
|
||||
this.cmdApplied,
|
||||
this.cmdErrorCode,
|
||||
this.payloadType,
|
||||
payload
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// 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 { CommandFleetMerge, CommandFleetMergeT } from './command-fleet-merge.js';
|
||||
import { CommandFleetSend, CommandFleetSendT } from './command-fleet-send.js';
|
||||
import { CommandPlanetProduce, CommandPlanetProduceT } from './command-planet-produce.js';
|
||||
import { CommandPlanetRename, CommandPlanetRenameT } from './command-planet-rename.js';
|
||||
import { CommandPlanetRouteRemove, CommandPlanetRouteRemoveT } from './command-planet-route-remove.js';
|
||||
import { CommandPlanetRouteSet, CommandPlanetRouteSetT } from './command-planet-route-set.js';
|
||||
import { CommandRaceQuit, CommandRaceQuitT } from './command-race-quit.js';
|
||||
import { CommandRaceRelation, CommandRaceRelationT } from './command-race-relation.js';
|
||||
import { CommandRaceVote, CommandRaceVoteT } from './command-race-vote.js';
|
||||
import { CommandScienceCreate, CommandScienceCreateT } from './command-science-create.js';
|
||||
import { CommandScienceRemove, CommandScienceRemoveT } from './command-science-remove.js';
|
||||
import { CommandShipClassCreate, CommandShipClassCreateT } from './command-ship-class-create.js';
|
||||
import { CommandShipClassMerge, CommandShipClassMergeT } from './command-ship-class-merge.js';
|
||||
import { CommandShipClassRemove, CommandShipClassRemoveT } from './command-ship-class-remove.js';
|
||||
import { CommandShipGroupBreak, CommandShipGroupBreakT } from './command-ship-group-break.js';
|
||||
import { CommandShipGroupDismantle, CommandShipGroupDismantleT } from './command-ship-group-dismantle.js';
|
||||
import { CommandShipGroupJoinFleet, CommandShipGroupJoinFleetT } from './command-ship-group-join-fleet.js';
|
||||
import { CommandShipGroupLoad, CommandShipGroupLoadT } from './command-ship-group-load.js';
|
||||
import { CommandShipGroupMerge, CommandShipGroupMergeT } from './command-ship-group-merge.js';
|
||||
import { CommandShipGroupSend, CommandShipGroupSendT } from './command-ship-group-send.js';
|
||||
import { CommandShipGroupTransfer, CommandShipGroupTransferT } from './command-ship-group-transfer.js';
|
||||
import { CommandShipGroupUnload, CommandShipGroupUnloadT } from './command-ship-group-unload.js';
|
||||
import { CommandShipGroupUpgrade, CommandShipGroupUpgradeT } from './command-ship-group-upgrade.js';
|
||||
|
||||
|
||||
export enum CommandPayload {
|
||||
NONE = 0,
|
||||
CommandRaceQuit = 1,
|
||||
CommandRaceVote = 2,
|
||||
CommandRaceRelation = 3,
|
||||
CommandShipClassCreate = 4,
|
||||
CommandShipClassMerge = 5,
|
||||
CommandShipClassRemove = 6,
|
||||
CommandShipGroupBreak = 7,
|
||||
CommandShipGroupLoad = 8,
|
||||
CommandShipGroupUnload = 9,
|
||||
CommandShipGroupSend = 10,
|
||||
CommandShipGroupUpgrade = 11,
|
||||
CommandShipGroupMerge = 12,
|
||||
CommandShipGroupDismantle = 13,
|
||||
CommandShipGroupTransfer = 14,
|
||||
CommandShipGroupJoinFleet = 15,
|
||||
CommandFleetMerge = 16,
|
||||
CommandFleetSend = 17,
|
||||
CommandScienceCreate = 18,
|
||||
CommandScienceRemove = 19,
|
||||
CommandPlanetRename = 20,
|
||||
CommandPlanetProduce = 21,
|
||||
CommandPlanetRouteSet = 22,
|
||||
CommandPlanetRouteRemove = 23
|
||||
}
|
||||
|
||||
export function unionToCommandPayload(
|
||||
type: CommandPayload,
|
||||
accessor: (obj:CommandFleetMerge|CommandFleetSend|CommandPlanetProduce|CommandPlanetRename|CommandPlanetRouteRemove|CommandPlanetRouteSet|CommandRaceQuit|CommandRaceRelation|CommandRaceVote|CommandScienceCreate|CommandScienceRemove|CommandShipClassCreate|CommandShipClassMerge|CommandShipClassRemove|CommandShipGroupBreak|CommandShipGroupDismantle|CommandShipGroupJoinFleet|CommandShipGroupLoad|CommandShipGroupMerge|CommandShipGroupSend|CommandShipGroupTransfer|CommandShipGroupUnload|CommandShipGroupUpgrade) => CommandFleetMerge|CommandFleetSend|CommandPlanetProduce|CommandPlanetRename|CommandPlanetRouteRemove|CommandPlanetRouteSet|CommandRaceQuit|CommandRaceRelation|CommandRaceVote|CommandScienceCreate|CommandScienceRemove|CommandShipClassCreate|CommandShipClassMerge|CommandShipClassRemove|CommandShipGroupBreak|CommandShipGroupDismantle|CommandShipGroupJoinFleet|CommandShipGroupLoad|CommandShipGroupMerge|CommandShipGroupSend|CommandShipGroupTransfer|CommandShipGroupUnload|CommandShipGroupUpgrade|null
|
||||
): CommandFleetMerge|CommandFleetSend|CommandPlanetProduce|CommandPlanetRename|CommandPlanetRouteRemove|CommandPlanetRouteSet|CommandRaceQuit|CommandRaceRelation|CommandRaceVote|CommandScienceCreate|CommandScienceRemove|CommandShipClassCreate|CommandShipClassMerge|CommandShipClassRemove|CommandShipGroupBreak|CommandShipGroupDismantle|CommandShipGroupJoinFleet|CommandShipGroupLoad|CommandShipGroupMerge|CommandShipGroupSend|CommandShipGroupTransfer|CommandShipGroupUnload|CommandShipGroupUpgrade|null {
|
||||
switch(CommandPayload[type]) {
|
||||
case 'NONE': return null;
|
||||
case 'CommandRaceQuit': return accessor(new CommandRaceQuit())! as CommandRaceQuit;
|
||||
case 'CommandRaceVote': return accessor(new CommandRaceVote())! as CommandRaceVote;
|
||||
case 'CommandRaceRelation': return accessor(new CommandRaceRelation())! as CommandRaceRelation;
|
||||
case 'CommandShipClassCreate': return accessor(new CommandShipClassCreate())! as CommandShipClassCreate;
|
||||
case 'CommandShipClassMerge': return accessor(new CommandShipClassMerge())! as CommandShipClassMerge;
|
||||
case 'CommandShipClassRemove': return accessor(new CommandShipClassRemove())! as CommandShipClassRemove;
|
||||
case 'CommandShipGroupBreak': return accessor(new CommandShipGroupBreak())! as CommandShipGroupBreak;
|
||||
case 'CommandShipGroupLoad': return accessor(new CommandShipGroupLoad())! as CommandShipGroupLoad;
|
||||
case 'CommandShipGroupUnload': return accessor(new CommandShipGroupUnload())! as CommandShipGroupUnload;
|
||||
case 'CommandShipGroupSend': return accessor(new CommandShipGroupSend())! as CommandShipGroupSend;
|
||||
case 'CommandShipGroupUpgrade': return accessor(new CommandShipGroupUpgrade())! as CommandShipGroupUpgrade;
|
||||
case 'CommandShipGroupMerge': return accessor(new CommandShipGroupMerge())! as CommandShipGroupMerge;
|
||||
case 'CommandShipGroupDismantle': return accessor(new CommandShipGroupDismantle())! as CommandShipGroupDismantle;
|
||||
case 'CommandShipGroupTransfer': return accessor(new CommandShipGroupTransfer())! as CommandShipGroupTransfer;
|
||||
case 'CommandShipGroupJoinFleet': return accessor(new CommandShipGroupJoinFleet())! as CommandShipGroupJoinFleet;
|
||||
case 'CommandFleetMerge': return accessor(new CommandFleetMerge())! as CommandFleetMerge;
|
||||
case 'CommandFleetSend': return accessor(new CommandFleetSend())! as CommandFleetSend;
|
||||
case 'CommandScienceCreate': return accessor(new CommandScienceCreate())! as CommandScienceCreate;
|
||||
case 'CommandScienceRemove': return accessor(new CommandScienceRemove())! as CommandScienceRemove;
|
||||
case 'CommandPlanetRename': return accessor(new CommandPlanetRename())! as CommandPlanetRename;
|
||||
case 'CommandPlanetProduce': return accessor(new CommandPlanetProduce())! as CommandPlanetProduce;
|
||||
case 'CommandPlanetRouteSet': return accessor(new CommandPlanetRouteSet())! as CommandPlanetRouteSet;
|
||||
case 'CommandPlanetRouteRemove': return accessor(new CommandPlanetRouteRemove())! as CommandPlanetRouteRemove;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function unionListToCommandPayload(
|
||||
type: CommandPayload,
|
||||
accessor: (index: number, obj:CommandFleetMerge|CommandFleetSend|CommandPlanetProduce|CommandPlanetRename|CommandPlanetRouteRemove|CommandPlanetRouteSet|CommandRaceQuit|CommandRaceRelation|CommandRaceVote|CommandScienceCreate|CommandScienceRemove|CommandShipClassCreate|CommandShipClassMerge|CommandShipClassRemove|CommandShipGroupBreak|CommandShipGroupDismantle|CommandShipGroupJoinFleet|CommandShipGroupLoad|CommandShipGroupMerge|CommandShipGroupSend|CommandShipGroupTransfer|CommandShipGroupUnload|CommandShipGroupUpgrade) => CommandFleetMerge|CommandFleetSend|CommandPlanetProduce|CommandPlanetRename|CommandPlanetRouteRemove|CommandPlanetRouteSet|CommandRaceQuit|CommandRaceRelation|CommandRaceVote|CommandScienceCreate|CommandScienceRemove|CommandShipClassCreate|CommandShipClassMerge|CommandShipClassRemove|CommandShipGroupBreak|CommandShipGroupDismantle|CommandShipGroupJoinFleet|CommandShipGroupLoad|CommandShipGroupMerge|CommandShipGroupSend|CommandShipGroupTransfer|CommandShipGroupUnload|CommandShipGroupUpgrade|null,
|
||||
index: number
|
||||
): CommandFleetMerge|CommandFleetSend|CommandPlanetProduce|CommandPlanetRename|CommandPlanetRouteRemove|CommandPlanetRouteSet|CommandRaceQuit|CommandRaceRelation|CommandRaceVote|CommandScienceCreate|CommandScienceRemove|CommandShipClassCreate|CommandShipClassMerge|CommandShipClassRemove|CommandShipGroupBreak|CommandShipGroupDismantle|CommandShipGroupJoinFleet|CommandShipGroupLoad|CommandShipGroupMerge|CommandShipGroupSend|CommandShipGroupTransfer|CommandShipGroupUnload|CommandShipGroupUpgrade|null {
|
||||
switch(CommandPayload[type]) {
|
||||
case 'NONE': return null;
|
||||
case 'CommandRaceQuit': return accessor(index, new CommandRaceQuit())! as CommandRaceQuit;
|
||||
case 'CommandRaceVote': return accessor(index, new CommandRaceVote())! as CommandRaceVote;
|
||||
case 'CommandRaceRelation': return accessor(index, new CommandRaceRelation())! as CommandRaceRelation;
|
||||
case 'CommandShipClassCreate': return accessor(index, new CommandShipClassCreate())! as CommandShipClassCreate;
|
||||
case 'CommandShipClassMerge': return accessor(index, new CommandShipClassMerge())! as CommandShipClassMerge;
|
||||
case 'CommandShipClassRemove': return accessor(index, new CommandShipClassRemove())! as CommandShipClassRemove;
|
||||
case 'CommandShipGroupBreak': return accessor(index, new CommandShipGroupBreak())! as CommandShipGroupBreak;
|
||||
case 'CommandShipGroupLoad': return accessor(index, new CommandShipGroupLoad())! as CommandShipGroupLoad;
|
||||
case 'CommandShipGroupUnload': return accessor(index, new CommandShipGroupUnload())! as CommandShipGroupUnload;
|
||||
case 'CommandShipGroupSend': return accessor(index, new CommandShipGroupSend())! as CommandShipGroupSend;
|
||||
case 'CommandShipGroupUpgrade': return accessor(index, new CommandShipGroupUpgrade())! as CommandShipGroupUpgrade;
|
||||
case 'CommandShipGroupMerge': return accessor(index, new CommandShipGroupMerge())! as CommandShipGroupMerge;
|
||||
case 'CommandShipGroupDismantle': return accessor(index, new CommandShipGroupDismantle())! as CommandShipGroupDismantle;
|
||||
case 'CommandShipGroupTransfer': return accessor(index, new CommandShipGroupTransfer())! as CommandShipGroupTransfer;
|
||||
case 'CommandShipGroupJoinFleet': return accessor(index, new CommandShipGroupJoinFleet())! as CommandShipGroupJoinFleet;
|
||||
case 'CommandFleetMerge': return accessor(index, new CommandFleetMerge())! as CommandFleetMerge;
|
||||
case 'CommandFleetSend': return accessor(index, new CommandFleetSend())! as CommandFleetSend;
|
||||
case 'CommandScienceCreate': return accessor(index, new CommandScienceCreate())! as CommandScienceCreate;
|
||||
case 'CommandScienceRemove': return accessor(index, new CommandScienceRemove())! as CommandScienceRemove;
|
||||
case 'CommandPlanetRename': return accessor(index, new CommandPlanetRename())! as CommandPlanetRename;
|
||||
case 'CommandPlanetProduce': return accessor(index, new CommandPlanetProduce())! as CommandPlanetProduce;
|
||||
case 'CommandPlanetRouteSet': return accessor(index, new CommandPlanetRouteSet())! as CommandPlanetRouteSet;
|
||||
case 'CommandPlanetRouteRemove': return accessor(index, new CommandPlanetRouteRemove())! as CommandPlanetRouteRemove;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// 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 { PlanetProduction } from './planet-production.js';
|
||||
|
||||
|
||||
export class CommandPlanetProduce implements flatbuffers.IUnpackableObject<CommandPlanetProduceT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandPlanetProduce {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandPlanetProduce(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetProduce):CommandPlanetProduce {
|
||||
return (obj || new CommandPlanetProduce()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandPlanetProduce(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetProduce):CommandPlanetProduce {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandPlanetProduce()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
number():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 4);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
production():PlanetProduction {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt8(this.bb_pos + offset) : PlanetProduction.UNKNOWN;
|
||||
}
|
||||
|
||||
subject():string|null
|
||||
subject(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
subject(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;
|
||||
}
|
||||
|
||||
static startCommandPlanetProduce(builder:flatbuffers.Builder) {
|
||||
builder.startObject(3);
|
||||
}
|
||||
|
||||
static addNumber(builder:flatbuffers.Builder, number:bigint) {
|
||||
builder.addFieldInt64(0, number, BigInt('0'));
|
||||
}
|
||||
|
||||
static addProduction(builder:flatbuffers.Builder, production:PlanetProduction) {
|
||||
builder.addFieldInt8(1, production, PlanetProduction.UNKNOWN);
|
||||
}
|
||||
|
||||
static addSubject(builder:flatbuffers.Builder, subjectOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(2, subjectOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandPlanetProduce(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandPlanetProduce(builder:flatbuffers.Builder, number:bigint, production:PlanetProduction, subjectOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandPlanetProduce.startCommandPlanetProduce(builder);
|
||||
CommandPlanetProduce.addNumber(builder, number);
|
||||
CommandPlanetProduce.addProduction(builder, production);
|
||||
CommandPlanetProduce.addSubject(builder, subjectOffset);
|
||||
return CommandPlanetProduce.endCommandPlanetProduce(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandPlanetProduceT {
|
||||
return new CommandPlanetProduceT(
|
||||
this.number(),
|
||||
this.production(),
|
||||
this.subject()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandPlanetProduceT): void {
|
||||
_o.number = this.number();
|
||||
_o.production = this.production();
|
||||
_o.subject = this.subject();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandPlanetProduceT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public number: bigint = BigInt('0'),
|
||||
public production: PlanetProduction = PlanetProduction.UNKNOWN,
|
||||
public subject: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const subject = (this.subject !== null ? builder.createString(this.subject!) : 0);
|
||||
|
||||
return CommandPlanetProduce.createCommandPlanetProduce(builder,
|
||||
this.number,
|
||||
this.production,
|
||||
subject
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 CommandPlanetRename implements flatbuffers.IUnpackableObject<CommandPlanetRenameT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandPlanetRename {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandPlanetRename(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetRename):CommandPlanetRename {
|
||||
return (obj || new CommandPlanetRename()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandPlanetRename(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetRename):CommandPlanetRename {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandPlanetRename()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
number():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 4);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('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, 6);
|
||||
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
|
||||
}
|
||||
|
||||
static startCommandPlanetRename(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addNumber(builder:flatbuffers.Builder, number:bigint) {
|
||||
builder.addFieldInt64(0, number, BigInt('0'));
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, nameOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandPlanetRename(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandPlanetRename(builder:flatbuffers.Builder, number:bigint, nameOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandPlanetRename.startCommandPlanetRename(builder);
|
||||
CommandPlanetRename.addNumber(builder, number);
|
||||
CommandPlanetRename.addName(builder, nameOffset);
|
||||
return CommandPlanetRename.endCommandPlanetRename(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandPlanetRenameT {
|
||||
return new CommandPlanetRenameT(
|
||||
this.number(),
|
||||
this.name()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandPlanetRenameT): void {
|
||||
_o.number = this.number();
|
||||
_o.name = this.name();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandPlanetRenameT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public number: bigint = BigInt('0'),
|
||||
public name: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
|
||||
return CommandPlanetRename.createCommandPlanetRename(builder,
|
||||
this.number,
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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 { PlanetRouteLoadType } from './planet-route-load-type.js';
|
||||
|
||||
|
||||
export class CommandPlanetRouteRemove implements flatbuffers.IUnpackableObject<CommandPlanetRouteRemoveT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandPlanetRouteRemove {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandPlanetRouteRemove(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetRouteRemove):CommandPlanetRouteRemove {
|
||||
return (obj || new CommandPlanetRouteRemove()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandPlanetRouteRemove(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetRouteRemove):CommandPlanetRouteRemove {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandPlanetRouteRemove()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
origin():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 4);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
loadType():PlanetRouteLoadType {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt8(this.bb_pos + offset) : PlanetRouteLoadType.UNKNOWN;
|
||||
}
|
||||
|
||||
static startCommandPlanetRouteRemove(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addOrigin(builder:flatbuffers.Builder, origin:bigint) {
|
||||
builder.addFieldInt64(0, origin, BigInt('0'));
|
||||
}
|
||||
|
||||
static addLoadType(builder:flatbuffers.Builder, loadType:PlanetRouteLoadType) {
|
||||
builder.addFieldInt8(1, loadType, PlanetRouteLoadType.UNKNOWN);
|
||||
}
|
||||
|
||||
static endCommandPlanetRouteRemove(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandPlanetRouteRemove(builder:flatbuffers.Builder, origin:bigint, loadType:PlanetRouteLoadType):flatbuffers.Offset {
|
||||
CommandPlanetRouteRemove.startCommandPlanetRouteRemove(builder);
|
||||
CommandPlanetRouteRemove.addOrigin(builder, origin);
|
||||
CommandPlanetRouteRemove.addLoadType(builder, loadType);
|
||||
return CommandPlanetRouteRemove.endCommandPlanetRouteRemove(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandPlanetRouteRemoveT {
|
||||
return new CommandPlanetRouteRemoveT(
|
||||
this.origin(),
|
||||
this.loadType()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandPlanetRouteRemoveT): void {
|
||||
_o.origin = this.origin();
|
||||
_o.loadType = this.loadType();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandPlanetRouteRemoveT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public origin: bigint = BigInt('0'),
|
||||
public loadType: PlanetRouteLoadType = PlanetRouteLoadType.UNKNOWN
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
return CommandPlanetRouteRemove.createCommandPlanetRouteRemove(builder,
|
||||
this.origin,
|
||||
this.loadType
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// 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 { PlanetRouteLoadType } from './planet-route-load-type.js';
|
||||
|
||||
|
||||
export class CommandPlanetRouteSet implements flatbuffers.IUnpackableObject<CommandPlanetRouteSetT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandPlanetRouteSet {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandPlanetRouteSet(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetRouteSet):CommandPlanetRouteSet {
|
||||
return (obj || new CommandPlanetRouteSet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandPlanetRouteSet(bb:flatbuffers.ByteBuffer, obj?:CommandPlanetRouteSet):CommandPlanetRouteSet {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandPlanetRouteSet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
origin():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 4);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
destination():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
loadType():PlanetRouteLoadType {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.readInt8(this.bb_pos + offset) : PlanetRouteLoadType.UNKNOWN;
|
||||
}
|
||||
|
||||
static startCommandPlanetRouteSet(builder:flatbuffers.Builder) {
|
||||
builder.startObject(3);
|
||||
}
|
||||
|
||||
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 addLoadType(builder:flatbuffers.Builder, loadType:PlanetRouteLoadType) {
|
||||
builder.addFieldInt8(2, loadType, PlanetRouteLoadType.UNKNOWN);
|
||||
}
|
||||
|
||||
static endCommandPlanetRouteSet(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandPlanetRouteSet(builder:flatbuffers.Builder, origin:bigint, destination:bigint, loadType:PlanetRouteLoadType):flatbuffers.Offset {
|
||||
CommandPlanetRouteSet.startCommandPlanetRouteSet(builder);
|
||||
CommandPlanetRouteSet.addOrigin(builder, origin);
|
||||
CommandPlanetRouteSet.addDestination(builder, destination);
|
||||
CommandPlanetRouteSet.addLoadType(builder, loadType);
|
||||
return CommandPlanetRouteSet.endCommandPlanetRouteSet(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandPlanetRouteSetT {
|
||||
return new CommandPlanetRouteSetT(
|
||||
this.origin(),
|
||||
this.destination(),
|
||||
this.loadType()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandPlanetRouteSetT): void {
|
||||
_o.origin = this.origin();
|
||||
_o.destination = this.destination();
|
||||
_o.loadType = this.loadType();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandPlanetRouteSetT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public origin: bigint = BigInt('0'),
|
||||
public destination: bigint = BigInt('0'),
|
||||
public loadType: PlanetRouteLoadType = PlanetRouteLoadType.UNKNOWN
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
return CommandPlanetRouteSet.createCommandPlanetRouteSet(builder,
|
||||
this.origin,
|
||||
this.destination,
|
||||
this.loadType
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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 CommandRaceQuit implements flatbuffers.IUnpackableObject<CommandRaceQuitT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandRaceQuit {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandRaceQuit(bb:flatbuffers.ByteBuffer, obj?:CommandRaceQuit):CommandRaceQuit {
|
||||
return (obj || new CommandRaceQuit()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandRaceQuit(bb:flatbuffers.ByteBuffer, obj?:CommandRaceQuit):CommandRaceQuit {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandRaceQuit()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static startCommandRaceQuit(builder:flatbuffers.Builder) {
|
||||
builder.startObject(0);
|
||||
}
|
||||
|
||||
static endCommandRaceQuit(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandRaceQuit(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
CommandRaceQuit.startCommandRaceQuit(builder);
|
||||
return CommandRaceQuit.endCommandRaceQuit(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandRaceQuitT {
|
||||
return new CommandRaceQuitT();
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandRaceQuitT): void {}
|
||||
}
|
||||
|
||||
export class CommandRaceQuitT implements flatbuffers.IGeneratedObject {
|
||||
constructor(){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
return CommandRaceQuit.createCommandRaceQuit(builder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// 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 { Relation } from './relation.js';
|
||||
|
||||
|
||||
export class CommandRaceRelation implements flatbuffers.IUnpackableObject<CommandRaceRelationT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandRaceRelation {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandRaceRelation(bb:flatbuffers.ByteBuffer, obj?:CommandRaceRelation):CommandRaceRelation {
|
||||
return (obj || new CommandRaceRelation()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandRaceRelation(bb:flatbuffers.ByteBuffer, obj?:CommandRaceRelation):CommandRaceRelation {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandRaceRelation()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
acceptor():string|null
|
||||
acceptor(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
acceptor(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;
|
||||
}
|
||||
|
||||
relation():Relation {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt8(this.bb_pos + offset) : Relation.UNKNOWN;
|
||||
}
|
||||
|
||||
static startCommandRaceRelation(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addAcceptor(builder:flatbuffers.Builder, acceptorOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, acceptorOffset, 0);
|
||||
}
|
||||
|
||||
static addRelation(builder:flatbuffers.Builder, relation:Relation) {
|
||||
builder.addFieldInt8(1, relation, Relation.UNKNOWN);
|
||||
}
|
||||
|
||||
static endCommandRaceRelation(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandRaceRelation(builder:flatbuffers.Builder, acceptorOffset:flatbuffers.Offset, relation:Relation):flatbuffers.Offset {
|
||||
CommandRaceRelation.startCommandRaceRelation(builder);
|
||||
CommandRaceRelation.addAcceptor(builder, acceptorOffset);
|
||||
CommandRaceRelation.addRelation(builder, relation);
|
||||
return CommandRaceRelation.endCommandRaceRelation(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandRaceRelationT {
|
||||
return new CommandRaceRelationT(
|
||||
this.acceptor(),
|
||||
this.relation()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandRaceRelationT): void {
|
||||
_o.acceptor = this.acceptor();
|
||||
_o.relation = this.relation();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandRaceRelationT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public acceptor: string|Uint8Array|null = null,
|
||||
public relation: Relation = Relation.UNKNOWN
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const acceptor = (this.acceptor !== null ? builder.createString(this.acceptor!) : 0);
|
||||
|
||||
return CommandRaceRelation.createCommandRaceRelation(builder,
|
||||
acceptor,
|
||||
this.relation
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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 CommandRaceVote implements flatbuffers.IUnpackableObject<CommandRaceVoteT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandRaceVote {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandRaceVote(bb:flatbuffers.ByteBuffer, obj?:CommandRaceVote):CommandRaceVote {
|
||||
return (obj || new CommandRaceVote()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandRaceVote(bb:flatbuffers.ByteBuffer, obj?:CommandRaceVote):CommandRaceVote {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandRaceVote()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
acceptor():string|null
|
||||
acceptor(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
acceptor(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;
|
||||
}
|
||||
|
||||
static startCommandRaceVote(builder:flatbuffers.Builder) {
|
||||
builder.startObject(1);
|
||||
}
|
||||
|
||||
static addAcceptor(builder:flatbuffers.Builder, acceptorOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, acceptorOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandRaceVote(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandRaceVote(builder:flatbuffers.Builder, acceptorOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandRaceVote.startCommandRaceVote(builder);
|
||||
CommandRaceVote.addAcceptor(builder, acceptorOffset);
|
||||
return CommandRaceVote.endCommandRaceVote(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandRaceVoteT {
|
||||
return new CommandRaceVoteT(
|
||||
this.acceptor()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandRaceVoteT): void {
|
||||
_o.acceptor = this.acceptor();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandRaceVoteT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public acceptor: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const acceptor = (this.acceptor !== null ? builder.createString(this.acceptor!) : 0);
|
||||
|
||||
return CommandRaceVote.createCommandRaceVote(builder,
|
||||
acceptor
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 CommandScienceCreate implements flatbuffers.IUnpackableObject<CommandScienceCreateT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandScienceCreate {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandScienceCreate(bb:flatbuffers.ByteBuffer, obj?:CommandScienceCreate):CommandScienceCreate {
|
||||
return (obj || new CommandScienceCreate()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandScienceCreate(bb:flatbuffers.ByteBuffer, obj?:CommandScienceCreate):CommandScienceCreate {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandScienceCreate()).__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!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
weapons():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
shields():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 10);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
cargo():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 12);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
static startCommandScienceCreate(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.addFieldFloat64(1, drive, 0.0);
|
||||
}
|
||||
|
||||
static addWeapons(builder:flatbuffers.Builder, weapons:number) {
|
||||
builder.addFieldFloat64(2, weapons, 0.0);
|
||||
}
|
||||
|
||||
static addShields(builder:flatbuffers.Builder, shields:number) {
|
||||
builder.addFieldFloat64(3, shields, 0.0);
|
||||
}
|
||||
|
||||
static addCargo(builder:flatbuffers.Builder, cargo:number) {
|
||||
builder.addFieldFloat64(4, cargo, 0.0);
|
||||
}
|
||||
|
||||
static endCommandScienceCreate(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandScienceCreate(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, drive:number, weapons:number, shields:number, cargo:number):flatbuffers.Offset {
|
||||
CommandScienceCreate.startCommandScienceCreate(builder);
|
||||
CommandScienceCreate.addName(builder, nameOffset);
|
||||
CommandScienceCreate.addDrive(builder, drive);
|
||||
CommandScienceCreate.addWeapons(builder, weapons);
|
||||
CommandScienceCreate.addShields(builder, shields);
|
||||
CommandScienceCreate.addCargo(builder, cargo);
|
||||
return CommandScienceCreate.endCommandScienceCreate(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandScienceCreateT {
|
||||
return new CommandScienceCreateT(
|
||||
this.name(),
|
||||
this.drive(),
|
||||
this.weapons(),
|
||||
this.shields(),
|
||||
this.cargo()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandScienceCreateT): void {
|
||||
_o.name = this.name();
|
||||
_o.drive = this.drive();
|
||||
_o.weapons = this.weapons();
|
||||
_o.shields = this.shields();
|
||||
_o.cargo = this.cargo();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandScienceCreateT 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 CommandScienceCreate.createCommandScienceCreate(builder,
|
||||
name,
|
||||
this.drive,
|
||||
this.weapons,
|
||||
this.shields,
|
||||
this.cargo
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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 CommandScienceRemove implements flatbuffers.IUnpackableObject<CommandScienceRemoveT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandScienceRemove {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandScienceRemove(bb:flatbuffers.ByteBuffer, obj?:CommandScienceRemove):CommandScienceRemove {
|
||||
return (obj || new CommandScienceRemove()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandScienceRemove(bb:flatbuffers.ByteBuffer, obj?:CommandScienceRemove):CommandScienceRemove {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandScienceRemove()).__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;
|
||||
}
|
||||
|
||||
static startCommandScienceRemove(builder:flatbuffers.Builder) {
|
||||
builder.startObject(1);
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, nameOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandScienceRemove(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandScienceRemove(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandScienceRemove.startCommandScienceRemove(builder);
|
||||
CommandScienceRemove.addName(builder, nameOffset);
|
||||
return CommandScienceRemove.endCommandScienceRemove(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandScienceRemoveT {
|
||||
return new CommandScienceRemoveT(
|
||||
this.name()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandScienceRemoveT): void {
|
||||
_o.name = this.name();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandScienceRemoveT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public name: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
|
||||
return CommandScienceRemove.createCommandScienceRemove(builder,
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 CommandShipClassCreate implements flatbuffers.IUnpackableObject<CommandShipClassCreateT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipClassCreate {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipClassCreate(bb:flatbuffers.ByteBuffer, obj?:CommandShipClassCreate):CommandShipClassCreate {
|
||||
return (obj || new CommandShipClassCreate()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipClassCreate(bb:flatbuffers.ByteBuffer, obj?:CommandShipClassCreate):CommandShipClassCreate {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipClassCreate()).__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!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
armament():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
weapons():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 10);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
shields():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 12);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
cargo():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 14);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
static startCommandShipClassCreate(builder:flatbuffers.Builder) {
|
||||
builder.startObject(6);
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, nameOffset, 0);
|
||||
}
|
||||
|
||||
static addDrive(builder:flatbuffers.Builder, drive:number) {
|
||||
builder.addFieldFloat64(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.addFieldFloat64(3, weapons, 0.0);
|
||||
}
|
||||
|
||||
static addShields(builder:flatbuffers.Builder, shields:number) {
|
||||
builder.addFieldFloat64(4, shields, 0.0);
|
||||
}
|
||||
|
||||
static addCargo(builder:flatbuffers.Builder, cargo:number) {
|
||||
builder.addFieldFloat64(5, cargo, 0.0);
|
||||
}
|
||||
|
||||
static endCommandShipClassCreate(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipClassCreate(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, drive:number, armament:bigint, weapons:number, shields:number, cargo:number):flatbuffers.Offset {
|
||||
CommandShipClassCreate.startCommandShipClassCreate(builder);
|
||||
CommandShipClassCreate.addName(builder, nameOffset);
|
||||
CommandShipClassCreate.addDrive(builder, drive);
|
||||
CommandShipClassCreate.addArmament(builder, armament);
|
||||
CommandShipClassCreate.addWeapons(builder, weapons);
|
||||
CommandShipClassCreate.addShields(builder, shields);
|
||||
CommandShipClassCreate.addCargo(builder, cargo);
|
||||
return CommandShipClassCreate.endCommandShipClassCreate(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipClassCreateT {
|
||||
return new CommandShipClassCreateT(
|
||||
this.name(),
|
||||
this.drive(),
|
||||
this.armament(),
|
||||
this.weapons(),
|
||||
this.shields(),
|
||||
this.cargo()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipClassCreateT): 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();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipClassCreateT 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
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
|
||||
return CommandShipClassCreate.createCommandShipClassCreate(builder,
|
||||
name,
|
||||
this.drive,
|
||||
this.armament,
|
||||
this.weapons,
|
||||
this.shields,
|
||||
this.cargo
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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 CommandShipClassMerge implements flatbuffers.IUnpackableObject<CommandShipClassMergeT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipClassMerge {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipClassMerge(bb:flatbuffers.ByteBuffer, obj?:CommandShipClassMerge):CommandShipClassMerge {
|
||||
return (obj || new CommandShipClassMerge()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipClassMerge(bb:flatbuffers.ByteBuffer, obj?:CommandShipClassMerge):CommandShipClassMerge {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipClassMerge()).__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;
|
||||
}
|
||||
|
||||
target():string|null
|
||||
target(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
target(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 startCommandShipClassMerge(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, nameOffset, 0);
|
||||
}
|
||||
|
||||
static addTarget(builder:flatbuffers.Builder, targetOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, targetOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandShipClassMerge(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipClassMerge(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, targetOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandShipClassMerge.startCommandShipClassMerge(builder);
|
||||
CommandShipClassMerge.addName(builder, nameOffset);
|
||||
CommandShipClassMerge.addTarget(builder, targetOffset);
|
||||
return CommandShipClassMerge.endCommandShipClassMerge(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipClassMergeT {
|
||||
return new CommandShipClassMergeT(
|
||||
this.name(),
|
||||
this.target()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipClassMergeT): void {
|
||||
_o.name = this.name();
|
||||
_o.target = this.target();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipClassMergeT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public name: string|Uint8Array|null = null,
|
||||
public target: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
const target = (this.target !== null ? builder.createString(this.target!) : 0);
|
||||
|
||||
return CommandShipClassMerge.createCommandShipClassMerge(builder,
|
||||
name,
|
||||
target
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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 CommandShipClassRemove implements flatbuffers.IUnpackableObject<CommandShipClassRemoveT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipClassRemove {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipClassRemove(bb:flatbuffers.ByteBuffer, obj?:CommandShipClassRemove):CommandShipClassRemove {
|
||||
return (obj || new CommandShipClassRemove()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipClassRemove(bb:flatbuffers.ByteBuffer, obj?:CommandShipClassRemove):CommandShipClassRemove {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipClassRemove()).__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;
|
||||
}
|
||||
|
||||
static startCommandShipClassRemove(builder:flatbuffers.Builder) {
|
||||
builder.startObject(1);
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, nameOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandShipClassRemove(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipClassRemove(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandShipClassRemove.startCommandShipClassRemove(builder);
|
||||
CommandShipClassRemove.addName(builder, nameOffset);
|
||||
return CommandShipClassRemove.endCommandShipClassRemove(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipClassRemoveT {
|
||||
return new CommandShipClassRemoveT(
|
||||
this.name()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipClassRemoveT): void {
|
||||
_o.name = this.name();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipClassRemoveT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public name: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
|
||||
return CommandShipClassRemove.createCommandShipClassRemove(builder,
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// 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 CommandShipGroupBreak implements flatbuffers.IUnpackableObject<CommandShipGroupBreakT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupBreak {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupBreak(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupBreak):CommandShipGroupBreak {
|
||||
return (obj || new CommandShipGroupBreak()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupBreak(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupBreak):CommandShipGroupBreak {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupBreak()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
newId():string|null
|
||||
newId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
newId(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;
|
||||
}
|
||||
|
||||
quantity():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
static startCommandShipGroupBreak(builder:flatbuffers.Builder) {
|
||||
builder.startObject(3);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static addNewId(builder:flatbuffers.Builder, newIdOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, newIdOffset, 0);
|
||||
}
|
||||
|
||||
static addQuantity(builder:flatbuffers.Builder, quantity:bigint) {
|
||||
builder.addFieldInt64(2, quantity, BigInt('0'));
|
||||
}
|
||||
|
||||
static endCommandShipGroupBreak(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupBreak(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, newIdOffset:flatbuffers.Offset, quantity:bigint):flatbuffers.Offset {
|
||||
CommandShipGroupBreak.startCommandShipGroupBreak(builder);
|
||||
CommandShipGroupBreak.addId(builder, idOffset);
|
||||
CommandShipGroupBreak.addNewId(builder, newIdOffset);
|
||||
CommandShipGroupBreak.addQuantity(builder, quantity);
|
||||
return CommandShipGroupBreak.endCommandShipGroupBreak(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupBreakT {
|
||||
return new CommandShipGroupBreakT(
|
||||
this.id(),
|
||||
this.newId(),
|
||||
this.quantity()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupBreakT): void {
|
||||
_o.id = this.id();
|
||||
_o.newId = this.newId();
|
||||
_o.quantity = this.quantity();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupBreakT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null,
|
||||
public newId: string|Uint8Array|null = null,
|
||||
public quantity: bigint = BigInt('0')
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
const newId = (this.newId !== null ? builder.createString(this.newId!) : 0);
|
||||
|
||||
return CommandShipGroupBreak.createCommandShipGroupBreak(builder,
|
||||
id,
|
||||
newId,
|
||||
this.quantity
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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 CommandShipGroupDismantle implements flatbuffers.IUnpackableObject<CommandShipGroupDismantleT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupDismantle {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupDismantle(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupDismantle):CommandShipGroupDismantle {
|
||||
return (obj || new CommandShipGroupDismantle()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupDismantle(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupDismantle):CommandShipGroupDismantle {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupDismantle()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
static startCommandShipGroupDismantle(builder:flatbuffers.Builder) {
|
||||
builder.startObject(1);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandShipGroupDismantle(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupDismantle(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandShipGroupDismantle.startCommandShipGroupDismantle(builder);
|
||||
CommandShipGroupDismantle.addId(builder, idOffset);
|
||||
return CommandShipGroupDismantle.endCommandShipGroupDismantle(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupDismantleT {
|
||||
return new CommandShipGroupDismantleT(
|
||||
this.id()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupDismantleT): void {
|
||||
_o.id = this.id();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupDismantleT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
|
||||
return CommandShipGroupDismantle.createCommandShipGroupDismantle(builder,
|
||||
id
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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 CommandShipGroupJoinFleet implements flatbuffers.IUnpackableObject<CommandShipGroupJoinFleetT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupJoinFleet {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupJoinFleet(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupJoinFleet):CommandShipGroupJoinFleet {
|
||||
return (obj || new CommandShipGroupJoinFleet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupJoinFleet(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupJoinFleet):CommandShipGroupJoinFleet {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupJoinFleet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
static startCommandShipGroupJoinFleet(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, nameOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandShipGroupJoinFleet(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupJoinFleet(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, nameOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandShipGroupJoinFleet.startCommandShipGroupJoinFleet(builder);
|
||||
CommandShipGroupJoinFleet.addId(builder, idOffset);
|
||||
CommandShipGroupJoinFleet.addName(builder, nameOffset);
|
||||
return CommandShipGroupJoinFleet.endCommandShipGroupJoinFleet(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupJoinFleetT {
|
||||
return new CommandShipGroupJoinFleetT(
|
||||
this.id(),
|
||||
this.name()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupJoinFleetT): void {
|
||||
_o.id = this.id();
|
||||
_o.name = this.name();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupJoinFleetT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null,
|
||||
public name: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
const name = (this.name !== null ? builder.createString(this.name!) : 0);
|
||||
|
||||
return CommandShipGroupJoinFleet.createCommandShipGroupJoinFleet(builder,
|
||||
id,
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// 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 { ShipGroupCargo } from './ship-group-cargo.js';
|
||||
|
||||
|
||||
export class CommandShipGroupLoad implements flatbuffers.IUnpackableObject<CommandShipGroupLoadT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupLoad {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupLoad(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupLoad):CommandShipGroupLoad {
|
||||
return (obj || new CommandShipGroupLoad()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupLoad(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupLoad):CommandShipGroupLoad {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupLoad()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
cargo():ShipGroupCargo {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt8(this.bb_pos + offset) : ShipGroupCargo.UNKNOWN;
|
||||
}
|
||||
|
||||
quantity():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
static startCommandShipGroupLoad(builder:flatbuffers.Builder) {
|
||||
builder.startObject(3);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static addCargo(builder:flatbuffers.Builder, cargo:ShipGroupCargo) {
|
||||
builder.addFieldInt8(1, cargo, ShipGroupCargo.UNKNOWN);
|
||||
}
|
||||
|
||||
static addQuantity(builder:flatbuffers.Builder, quantity:number) {
|
||||
builder.addFieldFloat64(2, quantity, 0.0);
|
||||
}
|
||||
|
||||
static endCommandShipGroupLoad(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupLoad(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, cargo:ShipGroupCargo, quantity:number):flatbuffers.Offset {
|
||||
CommandShipGroupLoad.startCommandShipGroupLoad(builder);
|
||||
CommandShipGroupLoad.addId(builder, idOffset);
|
||||
CommandShipGroupLoad.addCargo(builder, cargo);
|
||||
CommandShipGroupLoad.addQuantity(builder, quantity);
|
||||
return CommandShipGroupLoad.endCommandShipGroupLoad(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupLoadT {
|
||||
return new CommandShipGroupLoadT(
|
||||
this.id(),
|
||||
this.cargo(),
|
||||
this.quantity()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupLoadT): void {
|
||||
_o.id = this.id();
|
||||
_o.cargo = this.cargo();
|
||||
_o.quantity = this.quantity();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupLoadT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null,
|
||||
public cargo: ShipGroupCargo = ShipGroupCargo.UNKNOWN,
|
||||
public quantity: number = 0.0
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
|
||||
return CommandShipGroupLoad.createCommandShipGroupLoad(builder,
|
||||
id,
|
||||
this.cargo,
|
||||
this.quantity
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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 CommandShipGroupMerge implements flatbuffers.IUnpackableObject<CommandShipGroupMergeT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupMerge {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupMerge(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupMerge):CommandShipGroupMerge {
|
||||
return (obj || new CommandShipGroupMerge()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupMerge(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupMerge):CommandShipGroupMerge {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupMerge()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static startCommandShipGroupMerge(builder:flatbuffers.Builder) {
|
||||
builder.startObject(0);
|
||||
}
|
||||
|
||||
static endCommandShipGroupMerge(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupMerge(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
CommandShipGroupMerge.startCommandShipGroupMerge(builder);
|
||||
return CommandShipGroupMerge.endCommandShipGroupMerge(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupMergeT {
|
||||
return new CommandShipGroupMergeT();
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupMergeT): void {}
|
||||
}
|
||||
|
||||
export class CommandShipGroupMergeT implements flatbuffers.IGeneratedObject {
|
||||
constructor(){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
return CommandShipGroupMerge.createCommandShipGroupMerge(builder);
|
||||
}
|
||||
}
|
||||
@@ -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 CommandShipGroupSend implements flatbuffers.IUnpackableObject<CommandShipGroupSendT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupSend {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupSend(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupSend):CommandShipGroupSend {
|
||||
return (obj || new CommandShipGroupSend()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupSend(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupSend):CommandShipGroupSend {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupSend()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
destination():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
static startCommandShipGroupSend(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static addDestination(builder:flatbuffers.Builder, destination:bigint) {
|
||||
builder.addFieldInt64(1, destination, BigInt('0'));
|
||||
}
|
||||
|
||||
static endCommandShipGroupSend(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupSend(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, destination:bigint):flatbuffers.Offset {
|
||||
CommandShipGroupSend.startCommandShipGroupSend(builder);
|
||||
CommandShipGroupSend.addId(builder, idOffset);
|
||||
CommandShipGroupSend.addDestination(builder, destination);
|
||||
return CommandShipGroupSend.endCommandShipGroupSend(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupSendT {
|
||||
return new CommandShipGroupSendT(
|
||||
this.id(),
|
||||
this.destination()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupSendT): void {
|
||||
_o.id = this.id();
|
||||
_o.destination = this.destination();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupSendT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null,
|
||||
public destination: bigint = BigInt('0')
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
|
||||
return CommandShipGroupSend.createCommandShipGroupSend(builder,
|
||||
id,
|
||||
this.destination
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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 CommandShipGroupTransfer implements flatbuffers.IUnpackableObject<CommandShipGroupTransferT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupTransfer {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupTransfer(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupTransfer):CommandShipGroupTransfer {
|
||||
return (obj || new CommandShipGroupTransfer()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupTransfer(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupTransfer):CommandShipGroupTransfer {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupTransfer()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
acceptor():string|null
|
||||
acceptor(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
acceptor(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 startCommandShipGroupTransfer(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static addAcceptor(builder:flatbuffers.Builder, acceptorOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, acceptorOffset, 0);
|
||||
}
|
||||
|
||||
static endCommandShipGroupTransfer(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupTransfer(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, acceptorOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
CommandShipGroupTransfer.startCommandShipGroupTransfer(builder);
|
||||
CommandShipGroupTransfer.addId(builder, idOffset);
|
||||
CommandShipGroupTransfer.addAcceptor(builder, acceptorOffset);
|
||||
return CommandShipGroupTransfer.endCommandShipGroupTransfer(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupTransferT {
|
||||
return new CommandShipGroupTransferT(
|
||||
this.id(),
|
||||
this.acceptor()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupTransferT): void {
|
||||
_o.id = this.id();
|
||||
_o.acceptor = this.acceptor();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupTransferT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null,
|
||||
public acceptor: string|Uint8Array|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
const acceptor = (this.acceptor !== null ? builder.createString(this.acceptor!) : 0);
|
||||
|
||||
return CommandShipGroupTransfer.createCommandShipGroupTransfer(builder,
|
||||
id,
|
||||
acceptor
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 CommandShipGroupUnload implements flatbuffers.IUnpackableObject<CommandShipGroupUnloadT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupUnload {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupUnload(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupUnload):CommandShipGroupUnload {
|
||||
return (obj || new CommandShipGroupUnload()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupUnload(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupUnload):CommandShipGroupUnload {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupUnload()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
quantity():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
static startCommandShipGroupUnload(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static addQuantity(builder:flatbuffers.Builder, quantity:number) {
|
||||
builder.addFieldFloat64(1, quantity, 0.0);
|
||||
}
|
||||
|
||||
static endCommandShipGroupUnload(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupUnload(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, quantity:number):flatbuffers.Offset {
|
||||
CommandShipGroupUnload.startCommandShipGroupUnload(builder);
|
||||
CommandShipGroupUnload.addId(builder, idOffset);
|
||||
CommandShipGroupUnload.addQuantity(builder, quantity);
|
||||
return CommandShipGroupUnload.endCommandShipGroupUnload(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupUnloadT {
|
||||
return new CommandShipGroupUnloadT(
|
||||
this.id(),
|
||||
this.quantity()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupUnloadT): void {
|
||||
_o.id = this.id();
|
||||
_o.quantity = this.quantity();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupUnloadT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null,
|
||||
public quantity: number = 0.0
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
|
||||
return CommandShipGroupUnload.createCommandShipGroupUnload(builder,
|
||||
id,
|
||||
this.quantity
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// 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 { ShipGroupUpgradeTech } from './ship-group-upgrade-tech.js';
|
||||
|
||||
|
||||
export class CommandShipGroupUpgrade implements flatbuffers.IUnpackableObject<CommandShipGroupUpgradeT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):CommandShipGroupUpgrade {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsCommandShipGroupUpgrade(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupUpgrade):CommandShipGroupUpgrade {
|
||||
return (obj || new CommandShipGroupUpgrade()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsCommandShipGroupUpgrade(bb:flatbuffers.ByteBuffer, obj?:CommandShipGroupUpgrade):CommandShipGroupUpgrade {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new CommandShipGroupUpgrade()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
id():string|null
|
||||
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
|
||||
id(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;
|
||||
}
|
||||
|
||||
tech():ShipGroupUpgradeTech {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt8(this.bb_pos + offset) : ShipGroupUpgradeTech.UNKNOWN;
|
||||
}
|
||||
|
||||
level():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
|
||||
}
|
||||
|
||||
static startCommandShipGroupUpgrade(builder:flatbuffers.Builder) {
|
||||
builder.startObject(3);
|
||||
}
|
||||
|
||||
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(0, idOffset, 0);
|
||||
}
|
||||
|
||||
static addTech(builder:flatbuffers.Builder, tech:ShipGroupUpgradeTech) {
|
||||
builder.addFieldInt8(1, tech, ShipGroupUpgradeTech.UNKNOWN);
|
||||
}
|
||||
|
||||
static addLevel(builder:flatbuffers.Builder, level:number) {
|
||||
builder.addFieldFloat64(2, level, 0.0);
|
||||
}
|
||||
|
||||
static endCommandShipGroupUpgrade(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createCommandShipGroupUpgrade(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, tech:ShipGroupUpgradeTech, level:number):flatbuffers.Offset {
|
||||
CommandShipGroupUpgrade.startCommandShipGroupUpgrade(builder);
|
||||
CommandShipGroupUpgrade.addId(builder, idOffset);
|
||||
CommandShipGroupUpgrade.addTech(builder, tech);
|
||||
CommandShipGroupUpgrade.addLevel(builder, level);
|
||||
return CommandShipGroupUpgrade.endCommandShipGroupUpgrade(builder);
|
||||
}
|
||||
|
||||
unpack(): CommandShipGroupUpgradeT {
|
||||
return new CommandShipGroupUpgradeT(
|
||||
this.id(),
|
||||
this.tech(),
|
||||
this.level()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: CommandShipGroupUpgradeT): void {
|
||||
_o.id = this.id();
|
||||
_o.tech = this.tech();
|
||||
_o.level = this.level();
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandShipGroupUpgradeT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public id: string|Uint8Array|null = null,
|
||||
public tech: ShipGroupUpgradeTech = ShipGroupUpgradeTech.UNKNOWN,
|
||||
public level: number = 0.0
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const id = (this.id !== null ? builder.createString(this.id!) : 0);
|
||||
|
||||
return CommandShipGroupUpgrade.createCommandShipGroupUpgrade(builder,
|
||||
id,
|
||||
this.tech,
|
||||
this.level
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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 enum PlanetProduction {
|
||||
UNKNOWN = 0,
|
||||
MAT = 1,
|
||||
CAP = 2,
|
||||
DRIVE = 3,
|
||||
WEAPONS = 4,
|
||||
SHIELDS = 5,
|
||||
CARGO = 6,
|
||||
SCIENCE = 7,
|
||||
SHIP = 8
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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 enum PlanetRouteLoadType {
|
||||
UNKNOWN = 0,
|
||||
MAT = 1,
|
||||
CAP = 2,
|
||||
COL = 3,
|
||||
EMP = 4
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// 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 enum Relation {
|
||||
UNKNOWN = 0,
|
||||
WAR = 1,
|
||||
PEACE = 2
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// 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 enum ShipGroupCargo {
|
||||
UNKNOWN = 0,
|
||||
COL = 1,
|
||||
MAT = 2,
|
||||
CAP = 3
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 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 enum ShipGroupUpgradeTech {
|
||||
UNKNOWN = 0,
|
||||
ALL = 1,
|
||||
DRIVE = 2,
|
||||
WEAPONS = 3,
|
||||
SHIELDS = 4,
|
||||
CARGO = 5
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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 UserGamesCommandResponse implements flatbuffers.IUnpackableObject<UserGamesCommandResponseT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):UserGamesCommandResponse {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsUserGamesCommandResponse(bb:flatbuffers.ByteBuffer, obj?:UserGamesCommandResponse):UserGamesCommandResponse {
|
||||
return (obj || new UserGamesCommandResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsUserGamesCommandResponse(bb:flatbuffers.ByteBuffer, obj?:UserGamesCommandResponse):UserGamesCommandResponse {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new UserGamesCommandResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static startUserGamesCommandResponse(builder:flatbuffers.Builder) {
|
||||
builder.startObject(0);
|
||||
}
|
||||
|
||||
static endUserGamesCommandResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createUserGamesCommandResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
UserGamesCommandResponse.startUserGamesCommandResponse(builder);
|
||||
return UserGamesCommandResponse.endUserGamesCommandResponse(builder);
|
||||
}
|
||||
|
||||
unpack(): UserGamesCommandResponseT {
|
||||
return new UserGamesCommandResponseT();
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: UserGamesCommandResponseT): void {}
|
||||
}
|
||||
|
||||
export class UserGamesCommandResponseT implements flatbuffers.IGeneratedObject {
|
||||
constructor(){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
return UserGamesCommandResponse.createUserGamesCommandResponse(builder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
// 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 { CommandItem, CommandItemT } from './command-item.js';
|
||||
|
||||
|
||||
export class UserGamesCommand implements flatbuffers.IUnpackableObject<UserGamesCommandT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):UserGamesCommand {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsUserGamesCommand(bb:flatbuffers.ByteBuffer, obj?:UserGamesCommand):UserGamesCommand {
|
||||
return (obj || new UserGamesCommand()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsUserGamesCommand(bb:flatbuffers.ByteBuffer, obj?:UserGamesCommand):UserGamesCommand {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new UserGamesCommand()).__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;
|
||||
}
|
||||
|
||||
commands(index: number, obj?:CommandItem):CommandItem|null {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? (obj || new CommandItem()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
|
||||
}
|
||||
|
||||
commandsLength():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
|
||||
}
|
||||
|
||||
static startUserGamesCommand(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
|
||||
builder.addFieldStruct(0, gameIdOffset, 0);
|
||||
}
|
||||
|
||||
static addCommands(builder:flatbuffers.Builder, commandsOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, commandsOffset, 0);
|
||||
}
|
||||
|
||||
static createCommandsVector(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 startCommandsVector(builder:flatbuffers.Builder, numElems:number) {
|
||||
builder.startVector(4, numElems, 4);
|
||||
}
|
||||
|
||||
static endUserGamesCommand(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
builder.requiredField(offset, 4) // game_id
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createUserGamesCommand(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, commandsOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
UserGamesCommand.startUserGamesCommand(builder);
|
||||
UserGamesCommand.addGameId(builder, gameIdOffset);
|
||||
UserGamesCommand.addCommands(builder, commandsOffset);
|
||||
return UserGamesCommand.endUserGamesCommand(builder);
|
||||
}
|
||||
|
||||
unpack(): UserGamesCommandT {
|
||||
return new UserGamesCommandT(
|
||||
(this.gameId() !== null ? this.gameId()!.unpack() : null),
|
||||
this.bb!.createObjList<CommandItem, CommandItemT>(this.commands.bind(this), this.commandsLength())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: UserGamesCommandT): void {
|
||||
_o.gameId = (this.gameId() !== null ? this.gameId()!.unpack() : null);
|
||||
_o.commands = this.bb!.createObjList<CommandItem, CommandItemT>(this.commands.bind(this), this.commandsLength());
|
||||
}
|
||||
}
|
||||
|
||||
export class UserGamesCommandT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public gameId: UUIDT|null = null,
|
||||
public commands: (CommandItemT)[] = []
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const commands = UserGamesCommand.createCommandsVector(builder, builder.createObjectOffsetList(this.commands));
|
||||
|
||||
return UserGamesCommand.createUserGamesCommand(builder,
|
||||
(this.gameId !== null ? this.gameId!.pack(builder) : 0),
|
||||
commands
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 { UserGamesOrder, UserGamesOrderT } from './user-games-order.js';
|
||||
|
||||
|
||||
export class UserGamesOrderGetResponse implements flatbuffers.IUnpackableObject<UserGamesOrderGetResponseT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):UserGamesOrderGetResponse {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsUserGamesOrderGetResponse(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrderGetResponse):UserGamesOrderGetResponse {
|
||||
return (obj || new UserGamesOrderGetResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsUserGamesOrderGetResponse(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrderGetResponse):UserGamesOrderGetResponse {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new UserGamesOrderGetResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
found():boolean {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 4);
|
||||
return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
|
||||
}
|
||||
|
||||
order(obj?:UserGamesOrder):UserGamesOrder|null {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? (obj || new UserGamesOrder()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
|
||||
}
|
||||
|
||||
static startUserGamesOrderGetResponse(builder:flatbuffers.Builder) {
|
||||
builder.startObject(2);
|
||||
}
|
||||
|
||||
static addFound(builder:flatbuffers.Builder, found:boolean) {
|
||||
builder.addFieldInt8(0, +found, +false);
|
||||
}
|
||||
|
||||
static addOrder(builder:flatbuffers.Builder, orderOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(1, orderOffset, 0);
|
||||
}
|
||||
|
||||
static endUserGamesOrderGetResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
unpack(): UserGamesOrderGetResponseT {
|
||||
return new UserGamesOrderGetResponseT(
|
||||
this.found(),
|
||||
(this.order() !== null ? this.order()!.unpack() : null)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: UserGamesOrderGetResponseT): void {
|
||||
_o.found = this.found();
|
||||
_o.order = (this.order() !== null ? this.order()!.unpack() : null);
|
||||
}
|
||||
}
|
||||
|
||||
export class UserGamesOrderGetResponseT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public found: boolean = false,
|
||||
public order: UserGamesOrderT|null = null
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const order = (this.order !== null ? this.order!.pack(builder) : 0);
|
||||
|
||||
UserGamesOrderGetResponse.startUserGamesOrderGetResponse(builder);
|
||||
UserGamesOrderGetResponse.addFound(builder, this.found);
|
||||
UserGamesOrderGetResponse.addOrder(builder, order);
|
||||
|
||||
return UserGamesOrderGetResponse.endUserGamesOrderGetResponse(builder);
|
||||
}
|
||||
}
|
||||
@@ -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 UserGamesOrderGet implements flatbuffers.IUnpackableObject<UserGamesOrderGetT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):UserGamesOrderGet {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsUserGamesOrderGet(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrderGet):UserGamesOrderGet {
|
||||
return (obj || new UserGamesOrderGet()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsUserGamesOrderGet(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrderGet):UserGamesOrderGet {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new UserGamesOrderGet()).__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():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
static startUserGamesOrderGet(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:bigint) {
|
||||
builder.addFieldInt64(1, turn, BigInt('0'));
|
||||
}
|
||||
|
||||
static endUserGamesOrderGet(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
builder.requiredField(offset, 4) // game_id
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createUserGamesOrderGet(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, turn:bigint):flatbuffers.Offset {
|
||||
UserGamesOrderGet.startUserGamesOrderGet(builder);
|
||||
UserGamesOrderGet.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrderGet.addTurn(builder, turn);
|
||||
return UserGamesOrderGet.endUserGamesOrderGet(builder);
|
||||
}
|
||||
|
||||
unpack(): UserGamesOrderGetT {
|
||||
return new UserGamesOrderGetT(
|
||||
(this.gameId() !== null ? this.gameId()!.unpack() : null),
|
||||
this.turn()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: UserGamesOrderGetT): void {
|
||||
_o.gameId = (this.gameId() !== null ? this.gameId()!.unpack() : null);
|
||||
_o.turn = this.turn();
|
||||
}
|
||||
}
|
||||
|
||||
export class UserGamesOrderGetT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public gameId: UUIDT|null = null,
|
||||
public turn: bigint = BigInt('0')
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
return UserGamesOrderGet.createUserGamesOrderGet(builder,
|
||||
(this.gameId !== null ? this.gameId!.pack(builder) : 0),
|
||||
this.turn
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// 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 { CommandItem, CommandItemT } from './command-item.js';
|
||||
|
||||
|
||||
export class UserGamesOrderResponse implements flatbuffers.IUnpackableObject<UserGamesOrderResponseT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):UserGamesOrderResponse {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsUserGamesOrderResponse(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrderResponse):UserGamesOrderResponse {
|
||||
return (obj || new UserGamesOrderResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsUserGamesOrderResponse(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrderResponse):UserGamesOrderResponse {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new UserGamesOrderResponse()).__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;
|
||||
}
|
||||
|
||||
updatedAt():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
commands(index: number, obj?:CommandItem):CommandItem|null {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? (obj || new CommandItem()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
|
||||
}
|
||||
|
||||
commandsLength():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
|
||||
}
|
||||
|
||||
static startUserGamesOrderResponse(builder:flatbuffers.Builder) {
|
||||
builder.startObject(3);
|
||||
}
|
||||
|
||||
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
|
||||
builder.addFieldStruct(0, gameIdOffset, 0);
|
||||
}
|
||||
|
||||
static addUpdatedAt(builder:flatbuffers.Builder, updatedAt:bigint) {
|
||||
builder.addFieldInt64(1, updatedAt, BigInt('0'));
|
||||
}
|
||||
|
||||
static addCommands(builder:flatbuffers.Builder, commandsOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(2, commandsOffset, 0);
|
||||
}
|
||||
|
||||
static createCommandsVector(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 startCommandsVector(builder:flatbuffers.Builder, numElems:number) {
|
||||
builder.startVector(4, numElems, 4);
|
||||
}
|
||||
|
||||
static endUserGamesOrderResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createUserGamesOrderResponse(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, updatedAt:bigint, commandsOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
UserGamesOrderResponse.startUserGamesOrderResponse(builder);
|
||||
UserGamesOrderResponse.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrderResponse.addUpdatedAt(builder, updatedAt);
|
||||
UserGamesOrderResponse.addCommands(builder, commandsOffset);
|
||||
return UserGamesOrderResponse.endUserGamesOrderResponse(builder);
|
||||
}
|
||||
|
||||
unpack(): UserGamesOrderResponseT {
|
||||
return new UserGamesOrderResponseT(
|
||||
(this.gameId() !== null ? this.gameId()!.unpack() : null),
|
||||
this.updatedAt(),
|
||||
this.bb!.createObjList<CommandItem, CommandItemT>(this.commands.bind(this), this.commandsLength())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: UserGamesOrderResponseT): void {
|
||||
_o.gameId = (this.gameId() !== null ? this.gameId()!.unpack() : null);
|
||||
_o.updatedAt = this.updatedAt();
|
||||
_o.commands = this.bb!.createObjList<CommandItem, CommandItemT>(this.commands.bind(this), this.commandsLength());
|
||||
}
|
||||
}
|
||||
|
||||
export class UserGamesOrderResponseT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public gameId: UUIDT|null = null,
|
||||
public updatedAt: bigint = BigInt('0'),
|
||||
public commands: (CommandItemT)[] = []
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const commands = UserGamesOrderResponse.createCommandsVector(builder, builder.createObjectOffsetList(this.commands));
|
||||
|
||||
return UserGamesOrderResponse.createUserGamesOrderResponse(builder,
|
||||
(this.gameId !== null ? this.gameId!.pack(builder) : 0),
|
||||
this.updatedAt,
|
||||
commands
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
// 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 { CommandItem, CommandItemT } from './command-item.js';
|
||||
|
||||
|
||||
export class UserGamesOrder implements flatbuffers.IUnpackableObject<UserGamesOrderT> {
|
||||
bb: flatbuffers.ByteBuffer|null = null;
|
||||
bb_pos = 0;
|
||||
__init(i:number, bb:flatbuffers.ByteBuffer):UserGamesOrder {
|
||||
this.bb_pos = i;
|
||||
this.bb = bb;
|
||||
return this;
|
||||
}
|
||||
|
||||
static getRootAsUserGamesOrder(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrder):UserGamesOrder {
|
||||
return (obj || new UserGamesOrder()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
|
||||
}
|
||||
|
||||
static getSizePrefixedRootAsUserGamesOrder(bb:flatbuffers.ByteBuffer, obj?:UserGamesOrder):UserGamesOrder {
|
||||
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
|
||||
return (obj || new UserGamesOrder()).__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;
|
||||
}
|
||||
|
||||
updatedAt():bigint {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 6);
|
||||
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
|
||||
}
|
||||
|
||||
commands(index: number, obj?:CommandItem):CommandItem|null {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? (obj || new CommandItem()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
|
||||
}
|
||||
|
||||
commandsLength():number {
|
||||
const offset = this.bb!.__offset(this.bb_pos, 8);
|
||||
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
|
||||
}
|
||||
|
||||
static startUserGamesOrder(builder:flatbuffers.Builder) {
|
||||
builder.startObject(3);
|
||||
}
|
||||
|
||||
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
|
||||
builder.addFieldStruct(0, gameIdOffset, 0);
|
||||
}
|
||||
|
||||
static addUpdatedAt(builder:flatbuffers.Builder, updatedAt:bigint) {
|
||||
builder.addFieldInt64(1, updatedAt, BigInt('0'));
|
||||
}
|
||||
|
||||
static addCommands(builder:flatbuffers.Builder, commandsOffset:flatbuffers.Offset) {
|
||||
builder.addFieldOffset(2, commandsOffset, 0);
|
||||
}
|
||||
|
||||
static createCommandsVector(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 startCommandsVector(builder:flatbuffers.Builder, numElems:number) {
|
||||
builder.startVector(4, numElems, 4);
|
||||
}
|
||||
|
||||
static endUserGamesOrder(builder:flatbuffers.Builder):flatbuffers.Offset {
|
||||
const offset = builder.endObject();
|
||||
builder.requiredField(offset, 4) // game_id
|
||||
return offset;
|
||||
}
|
||||
|
||||
static createUserGamesOrder(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, updatedAt:bigint, commandsOffset:flatbuffers.Offset):flatbuffers.Offset {
|
||||
UserGamesOrder.startUserGamesOrder(builder);
|
||||
UserGamesOrder.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrder.addUpdatedAt(builder, updatedAt);
|
||||
UserGamesOrder.addCommands(builder, commandsOffset);
|
||||
return UserGamesOrder.endUserGamesOrder(builder);
|
||||
}
|
||||
|
||||
unpack(): UserGamesOrderT {
|
||||
return new UserGamesOrderT(
|
||||
(this.gameId() !== null ? this.gameId()!.unpack() : null),
|
||||
this.updatedAt(),
|
||||
this.bb!.createObjList<CommandItem, CommandItemT>(this.commands.bind(this), this.commandsLength())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
unpackTo(_o: UserGamesOrderT): void {
|
||||
_o.gameId = (this.gameId() !== null ? this.gameId()!.unpack() : null);
|
||||
_o.updatedAt = this.updatedAt();
|
||||
_o.commands = this.bb!.createObjList<CommandItem, CommandItemT>(this.commands.bind(this), this.commandsLength());
|
||||
}
|
||||
}
|
||||
|
||||
export class UserGamesOrderT implements flatbuffers.IGeneratedObject {
|
||||
constructor(
|
||||
public gameId: UUIDT|null = null,
|
||||
public updatedAt: bigint = BigInt('0'),
|
||||
public commands: (CommandItemT)[] = []
|
||||
){}
|
||||
|
||||
|
||||
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
|
||||
const commands = UserGamesOrder.createCommandsVector(builder, builder.createObjectOffsetList(this.commands));
|
||||
|
||||
return UserGamesOrder.createUserGamesOrder(builder,
|
||||
(this.gameId !== null ? this.gameId!.pack(builder) : 0),
|
||||
this.updatedAt,
|
||||
commands
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -57,10 +57,18 @@ fresh.
|
||||
SelectionStore,
|
||||
SELECTION_CONTEXT_KEY,
|
||||
} from "$lib/selection.svelte";
|
||||
import {
|
||||
createRenderedReportSource,
|
||||
RENDERED_REPORT_CONTEXT_KEY,
|
||||
} from "$lib/rendered-report.svelte";
|
||||
import {
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
OrderDraftStore,
|
||||
} from "../../../sync/order-draft.svelte";
|
||||
import {
|
||||
GALAXY_CLIENT_CONTEXT_KEY,
|
||||
GalaxyClientHolder,
|
||||
} from "$lib/galaxy-client-context.svelte";
|
||||
import { session } from "$lib/session-store.svelte";
|
||||
import { loadStore } from "../../../platform/store/index";
|
||||
import { loadCore } from "../../../platform/core/index";
|
||||
@@ -89,17 +97,23 @@ fresh.
|
||||
setContext(ORDER_DRAFT_CONTEXT_KEY, orderDraft);
|
||||
const selection = new SelectionStore();
|
||||
setContext(SELECTION_CONTEXT_KEY, selection);
|
||||
const renderedReport = createRenderedReportSource(gameState, orderDraft);
|
||||
setContext(RENDERED_REPORT_CONTEXT_KEY, renderedReport);
|
||||
const galaxyClient = new GalaxyClientHolder();
|
||||
setContext(GALAXY_CLIENT_CONTEXT_KEY, galaxyClient);
|
||||
|
||||
// selectedPlanet resolves the current selection against the live
|
||||
// report so both the desktop sidebar and the mobile sheet display
|
||||
// the same snapshot. A selection that points at a planet missing
|
||||
// from the current report (e.g. visibility lost between turns)
|
||||
// reads as `null` here, which collapses the inspector and the
|
||||
// sheet without surfacing a stale row.
|
||||
// sheet without surfacing a stale row. The rendered report layers
|
||||
// the local order draft on top so the player sees their pending
|
||||
// renames immediately.
|
||||
const selectedPlanet = $derived.by(() => {
|
||||
const sel = selection.selected;
|
||||
if (sel === null || sel.kind !== "planet") return null;
|
||||
const report = gameState.report;
|
||||
const report = renderedReport.report;
|
||||
if (report === null) return null;
|
||||
return report.planets.find((p) => p.number === sel.id) ?? null;
|
||||
});
|
||||
@@ -149,6 +163,13 @@ fresh.
|
||||
gameState.init({ client, cache, gameId }),
|
||||
orderDraft.init({ cache, gameId }),
|
||||
]);
|
||||
galaxyClient.set(client);
|
||||
if (orderDraft.needsServerHydration) {
|
||||
await orderDraft.hydrateFromServer({
|
||||
client,
|
||||
turn: gameState.currentTurn,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
gameState.failBootstrap(describeBootstrapError(err));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
// any UI.
|
||||
|
||||
import type { Cache } from "../platform/store/index";
|
||||
import type { OrderCommand } from "./order-types";
|
||||
import type { GalaxyClient } from "../api/galaxy-client";
|
||||
import { fetchOrder } from "./order-load";
|
||||
import type { CommandStatus, OrderCommand } from "./order-types";
|
||||
import { validateEntityName } from "$lib/util/entity-name";
|
||||
|
||||
const NAMESPACE = "order-drafts";
|
||||
const draftKey = (gameId: string): string => `${gameId}/draft`;
|
||||
@@ -34,9 +37,21 @@ type Status = "idle" | "ready" | "error";
|
||||
|
||||
export class OrderDraftStore {
|
||||
commands: OrderCommand[] = $state([]);
|
||||
statuses: Record<string, CommandStatus> = $state({});
|
||||
updatedAt = $state(0);
|
||||
status: Status = $state("idle");
|
||||
error: string | null = $state(null);
|
||||
|
||||
/**
|
||||
* needsServerHydration is `true` when the cache row for this game
|
||||
* was absent at `init` time. The layout reads it after both
|
||||
* `gameState.init` and `orderDraft.init` resolve and, if `true`,
|
||||
* calls `hydrateFromServer` once the current turn is known.
|
||||
* An explicitly empty cache row sets it to `false` (the user has
|
||||
* an empty draft, not a missing one).
|
||||
*/
|
||||
needsServerHydration = $state(false);
|
||||
|
||||
private cache: Cache | null = null;
|
||||
private gameId = "";
|
||||
private destroyed = false;
|
||||
@@ -47,6 +62,12 @@ export class OrderDraftStore {
|
||||
* idempotent on the same store instance — the layout always
|
||||
* constructs a fresh store per game, so there is no need to support
|
||||
* mid-life game switching here.
|
||||
*
|
||||
* When the cache row is absent, `needsServerHydration` is set to
|
||||
* `true`; the layout fans out a `hydrateFromServer` call once the
|
||||
* current turn is known. An explicitly empty cache row is treated
|
||||
* as "user has an empty draft" and skipped — local intent always
|
||||
* wins over server snapshot.
|
||||
*/
|
||||
async init(opts: { cache: Cache; gameId: string }): Promise<void> {
|
||||
this.cache = opts.cache;
|
||||
@@ -57,7 +78,14 @@ export class OrderDraftStore {
|
||||
draftKey(opts.gameId),
|
||||
);
|
||||
if (this.destroyed) return;
|
||||
this.commands = Array.isArray(stored) ? [...stored] : [];
|
||||
if (stored === undefined) {
|
||||
this.commands = [];
|
||||
this.needsServerHydration = true;
|
||||
} else {
|
||||
this.commands = Array.isArray(stored) ? [...stored] : [];
|
||||
this.needsServerHydration = false;
|
||||
}
|
||||
this.recomputeStatuses();
|
||||
this.status = "ready";
|
||||
} catch (err) {
|
||||
if (this.destroyed) return;
|
||||
@@ -67,13 +95,44 @@ export class OrderDraftStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* add appends a command to the end of the draft and persists the
|
||||
* updated list. Mutations made before `init` resolves are ignored —
|
||||
* the layout always awaits `init` before exposing the store.
|
||||
* hydrateFromServer fetches the player's stored order from the
|
||||
* gateway when the cache row was absent at boot. The result is
|
||||
* merged into `commands` and persisted so subsequent reloads
|
||||
* prefer the cached version. Failures are non-fatal — the draft
|
||||
* stays empty and the user can keep composing.
|
||||
*/
|
||||
async hydrateFromServer(opts: {
|
||||
client: GalaxyClient;
|
||||
turn: number;
|
||||
}): Promise<void> {
|
||||
if (this.status !== "ready" || !this.needsServerHydration) return;
|
||||
this.needsServerHydration = false;
|
||||
try {
|
||||
const fetched = await fetchOrder(opts.client, this.gameId, opts.turn);
|
||||
if (this.destroyed) return;
|
||||
this.commands = fetched.commands;
|
||||
this.updatedAt = fetched.updatedAt;
|
||||
this.recomputeStatuses();
|
||||
await this.persist();
|
||||
} catch (err) {
|
||||
if (this.destroyed) return;
|
||||
console.warn(
|
||||
"order-draft: server hydration failed; staying on empty draft",
|
||||
err,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* add appends a command to the end of the draft, runs local
|
||||
* validation for the new entry, and persists the updated list.
|
||||
* Mutations made before `init` resolves are ignored — the layout
|
||||
* always awaits `init` before exposing the store.
|
||||
*/
|
||||
async add(command: OrderCommand): Promise<void> {
|
||||
if (this.status !== "ready") return;
|
||||
this.commands = [...this.commands, command];
|
||||
this.statuses = { ...this.statuses, [command.id]: validateCommand(command) };
|
||||
await this.persist();
|
||||
}
|
||||
|
||||
@@ -86,6 +145,9 @@ export class OrderDraftStore {
|
||||
const next = this.commands.filter((cmd) => cmd.id !== id);
|
||||
if (next.length === this.commands.length) return;
|
||||
this.commands = next;
|
||||
const nextStatuses = { ...this.statuses };
|
||||
delete nextStatuses[id];
|
||||
this.statuses = nextStatuses;
|
||||
await this.persist();
|
||||
}
|
||||
|
||||
@@ -109,11 +171,83 @@ export class OrderDraftStore {
|
||||
await this.persist();
|
||||
}
|
||||
|
||||
/**
|
||||
* markSubmitting flips the status of every entry in `ids` to
|
||||
* `submitting` so the order tab can disable per-row controls and
|
||||
* show a spinner. The state machine runs `valid → submitting →
|
||||
* applied | rejected` (see ui/docs/order-composer.md).
|
||||
*/
|
||||
markSubmitting(ids: string[]): void {
|
||||
const next = { ...this.statuses };
|
||||
for (const id of ids) {
|
||||
next[id] = "submitting";
|
||||
}
|
||||
this.statuses = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* applyResults merges the verdict map returned by `submitOrder`
|
||||
* into the per-command status map. Entries not present in the
|
||||
* map keep their current status — useful when only a subset of
|
||||
* commands round-tripped to the server. The engine-assigned
|
||||
* `updatedAt` is also stashed for the next submit's stale-order
|
||||
* detection (kept as plumbing only in Phase 14).
|
||||
*/
|
||||
applyResults(opts: {
|
||||
results: Map<string, CommandStatus>;
|
||||
updatedAt: number;
|
||||
}): void {
|
||||
const next = { ...this.statuses };
|
||||
for (const [id, status] of opts.results.entries()) {
|
||||
next[id] = status;
|
||||
}
|
||||
this.statuses = next;
|
||||
this.updatedAt = opts.updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* markRejected switches every supplied id to `rejected`. Used by
|
||||
* the order tab when `submitOrder` returns `ok: false` — the
|
||||
* gateway didn't process any command, so the entire batch is
|
||||
* treated as rejected.
|
||||
*/
|
||||
markRejected(ids: string[]): void {
|
||||
const next = { ...this.statuses };
|
||||
for (const id of ids) {
|
||||
next[id] = "rejected";
|
||||
}
|
||||
this.statuses = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* revertSubmittingToValid resets every entry currently in
|
||||
* `submitting` back to its pre-submit status (typically `valid`).
|
||||
* Called when the network layer throws an exception so the
|
||||
* operator can retry without the rows looking stuck mid-flight.
|
||||
*/
|
||||
revertSubmittingToValid(): void {
|
||||
const next = { ...this.statuses };
|
||||
for (const cmd of this.commands) {
|
||||
if (next[cmd.id] === "submitting") {
|
||||
next[cmd.id] = validateCommand(cmd);
|
||||
}
|
||||
}
|
||||
this.statuses = next;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.destroyed = true;
|
||||
this.cache = null;
|
||||
}
|
||||
|
||||
private recomputeStatuses(): void {
|
||||
const next: Record<string, CommandStatus> = {};
|
||||
for (const cmd of this.commands) {
|
||||
next[cmd.id] = validateCommand(cmd);
|
||||
}
|
||||
this.statuses = next;
|
||||
}
|
||||
|
||||
private async persist(): Promise<void> {
|
||||
if (this.cache === null || this.destroyed) return;
|
||||
// `commands` is `$state`, so individual entries are proxies.
|
||||
@@ -123,3 +257,14 @@ export class OrderDraftStore {
|
||||
await this.cache.put(NAMESPACE, draftKey(this.gameId), snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
function validateCommand(cmd: OrderCommand): CommandStatus {
|
||||
switch (cmd.kind) {
|
||||
case "planetRename":
|
||||
return validateEntityName(cmd.name).ok ? "valid" : "invalid";
|
||||
case "placeholder":
|
||||
// Phase 12 placeholder entries are content-free and never
|
||||
// transition out of `draft` — they are not submittable.
|
||||
return "draft";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
// Reads back the player's stored order for the current turn through
|
||||
// `user.games.order.get`. Used by `OrderDraftStore` only when the
|
||||
// local cache row is absent (fresh install, cleared storage, or a
|
||||
// brand-new device): the local draft is the source of truth, so a
|
||||
// present-but-empty cache row means "no commands" and is honoured
|
||||
// over the server snapshot.
|
||||
|
||||
import { Builder, ByteBuffer } from "flatbuffers";
|
||||
|
||||
import type { GalaxyClient } from "../api/galaxy-client";
|
||||
import { uuidToHiLo } from "../api/game-state";
|
||||
import { UUID } from "../proto/galaxy/fbs/common";
|
||||
import {
|
||||
CommandPayload,
|
||||
CommandPlanetRename,
|
||||
UserGamesOrderGet,
|
||||
UserGamesOrderGetResponse,
|
||||
} from "../proto/galaxy/fbs/order";
|
||||
import type { OrderCommand } from "./order-types";
|
||||
|
||||
const MESSAGE_TYPE = "user.games.order.get";
|
||||
|
||||
export class OrderLoadError extends Error {
|
||||
readonly resultCode: string;
|
||||
readonly code: string;
|
||||
|
||||
constructor(resultCode: string, code: string, message: string) {
|
||||
super(message);
|
||||
this.name = "OrderLoadError";
|
||||
this.resultCode = resultCode;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
export interface FetchedOrder {
|
||||
commands: OrderCommand[];
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchOrder issues `user.games.order.get` for the given game and
|
||||
* turn, decodes the response, and returns the typed draft. A
|
||||
* `found = false` answer (no order stored on the server) surfaces as
|
||||
* an empty `commands` array — the caller treats this as a clean
|
||||
* draft. Unknown command kinds in the response are skipped with a
|
||||
* console warning so a backend-side schema bump never silently
|
||||
* corrupts the local draft.
|
||||
*/
|
||||
export async function fetchOrder(
|
||||
client: GalaxyClient,
|
||||
gameId: string,
|
||||
turn: number,
|
||||
): Promise<FetchedOrder> {
|
||||
if (turn < 0) {
|
||||
throw new OrderLoadError(
|
||||
"invalid_request",
|
||||
"invalid_request",
|
||||
`turn must be non-negative, got ${turn}`,
|
||||
);
|
||||
}
|
||||
const payload = buildRequest(gameId, turn);
|
||||
const result = await client.executeCommand(MESSAGE_TYPE, payload);
|
||||
if (result.resultCode !== "ok") {
|
||||
const { code, message } = decodeError(result.payloadBytes, result.resultCode);
|
||||
throw new OrderLoadError(result.resultCode, code, message);
|
||||
}
|
||||
return decodeResponse(result.payloadBytes);
|
||||
}
|
||||
|
||||
function buildRequest(gameId: string, turn: number): Uint8Array {
|
||||
const builder = new Builder(64);
|
||||
const [hi, lo] = uuidToHiLo(gameId);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
UserGamesOrderGet.startUserGamesOrderGet(builder);
|
||||
UserGamesOrderGet.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrderGet.addTurn(builder, BigInt(turn));
|
||||
const offset = UserGamesOrderGet.endUserGamesOrderGet(builder);
|
||||
builder.finish(offset);
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
function decodeResponse(payload: Uint8Array): FetchedOrder {
|
||||
if (payload.length === 0) {
|
||||
throw new OrderLoadError(
|
||||
"internal_error",
|
||||
"internal_error",
|
||||
"empty user.games.order.get payload",
|
||||
);
|
||||
}
|
||||
const buffer = new ByteBuffer(payload);
|
||||
const response = UserGamesOrderGetResponse.getRootAsUserGamesOrderGetResponse(buffer);
|
||||
if (!response.found()) {
|
||||
return { commands: [], updatedAt: 0 };
|
||||
}
|
||||
const order = response.order();
|
||||
if (order === null) {
|
||||
throw new OrderLoadError(
|
||||
"internal_error",
|
||||
"internal_error",
|
||||
"order missing while found=true",
|
||||
);
|
||||
}
|
||||
const commands: OrderCommand[] = [];
|
||||
const length = order.commandsLength();
|
||||
for (let i = 0; i < length; i++) {
|
||||
const item = order.commands(i);
|
||||
if (item === null) continue;
|
||||
const cmd = decodeCommand(item);
|
||||
if (cmd === null) continue;
|
||||
commands.push(cmd);
|
||||
}
|
||||
return {
|
||||
commands,
|
||||
updatedAt: Number(order.updatedAt()),
|
||||
};
|
||||
}
|
||||
|
||||
type CommandItemView = NonNullable<
|
||||
ReturnType<NonNullable<ReturnType<UserGamesOrderGetResponse["order"]>>["commands"]>
|
||||
>;
|
||||
|
||||
function decodeCommand(item: CommandItemView): OrderCommand | null {
|
||||
if (item === null) return null;
|
||||
const id = item.cmdId();
|
||||
if (id === null) return null;
|
||||
const payloadType = item.payloadType();
|
||||
switch (payloadType) {
|
||||
case CommandPayload.CommandPlanetRename: {
|
||||
const inner = new CommandPlanetRename();
|
||||
item.payload(inner);
|
||||
return {
|
||||
kind: "planetRename",
|
||||
id,
|
||||
planetNumber: Number(inner.number()),
|
||||
name: inner.name() ?? "",
|
||||
};
|
||||
}
|
||||
default:
|
||||
console.warn(
|
||||
`fetchOrder: skipping unknown command kind (payloadType=${payloadType})`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function decodeError(
|
||||
payload: Uint8Array,
|
||||
resultCode: string,
|
||||
): { code: string; message: string } {
|
||||
if (payload.length === 0) {
|
||||
return { code: resultCode, message: resultCode };
|
||||
}
|
||||
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 : resultCode,
|
||||
message: typeof parsed.message === "string" ? parsed.message : text,
|
||||
};
|
||||
} catch {
|
||||
return { code: resultCode, message: resultCode };
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,28 @@ export interface PlaceholderCommand {
|
||||
readonly label: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* PlanetRenameCommand is the first real command variant — Phase 14
|
||||
* lands the rename action together with the submit pipeline. The
|
||||
* `name` is locally validated against `validateEntityName` (the TS
|
||||
* port of `pkg/util/string.go.ValidateTypeName`) before the entry is
|
||||
* accepted into the draft; the same rules run server-side, so a
|
||||
* locally-valid command is always accepted at the wire level.
|
||||
*/
|
||||
export interface PlanetRenameCommand {
|
||||
readonly kind: "planetRename";
|
||||
readonly id: string;
|
||||
readonly planetNumber: number;
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* OrderCommand is the discriminated union of every command shape the
|
||||
* local order draft can hold. The `kind` field is the discriminator;
|
||||
* narrowing on it enables exhaustive `switch` statements at every
|
||||
* call site. Phase 14 will widen the union with `planetRename`.
|
||||
* call site.
|
||||
*/
|
||||
export type OrderCommand = PlaceholderCommand;
|
||||
export type OrderCommand = PlaceholderCommand | PlanetRenameCommand;
|
||||
|
||||
/**
|
||||
* CommandStatus is the lifecycle of a single command from the moment
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
// Drives the order submit pipeline: builds a FlatBuffers
|
||||
// `UserGamesOrder` payload from the local draft, calls
|
||||
// `client.executeCommand("user.games.order", ...)`, and translates
|
||||
// the engine response into per-command results the draft store can
|
||||
// merge with `applyResults`.
|
||||
//
|
||||
// The engine populates `cmdApplied` and `cmdErrorCode` on every
|
||||
// returned command (see `game/openapi.yaml`), so the happy path
|
||||
// reads real per-command outcomes. An empty response `commands`
|
||||
// array — the gateway's defensive fallback when no body comes back
|
||||
// — collapses to a batch-level "all applied" verdict so the player
|
||||
// is never left with submitted-without-result rows.
|
||||
//
|
||||
// Failures fall into two buckets:
|
||||
// - the gateway answers with a non-`ok` `resultCode` (auth /
|
||||
// transcoder / engine validation); the result is `ok: false`
|
||||
// and every submitted entry should flip to `rejected`;
|
||||
// - the request itself throws (network, signature mismatch, decoder
|
||||
// panic); the exception bubbles up to the caller, which leaves
|
||||
// the draft entries in `submitting` for the operator to retry.
|
||||
|
||||
import { Builder, ByteBuffer } from "flatbuffers";
|
||||
|
||||
import type { GalaxyClient } from "../api/galaxy-client";
|
||||
import { uuidToHiLo } from "../api/game-state";
|
||||
import { UUID } from "../proto/galaxy/fbs/common";
|
||||
import {
|
||||
CommandItem,
|
||||
CommandPayload,
|
||||
CommandPlanetRename,
|
||||
UserGamesOrder,
|
||||
UserGamesOrderResponse,
|
||||
} from "../proto/galaxy/fbs/order";
|
||||
import type { OrderCommand } from "./order-types";
|
||||
|
||||
const MESSAGE_TYPE = "user.games.order";
|
||||
|
||||
export class SubmitError extends Error {
|
||||
readonly resultCode: string;
|
||||
readonly code: string;
|
||||
|
||||
constructor(resultCode: string, code: string, message: string) {
|
||||
super(message);
|
||||
this.name = "SubmitError";
|
||||
this.resultCode = resultCode;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
export type CommandOutcome = "applied" | "rejected";
|
||||
|
||||
export interface SubmitSuccess {
|
||||
ok: true;
|
||||
results: Map<string, CommandOutcome>;
|
||||
errorCodes: Map<string, number | null>;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
export interface SubmitFailure {
|
||||
ok: false;
|
||||
resultCode: string;
|
||||
code: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export type SubmitResult = SubmitSuccess | SubmitFailure;
|
||||
|
||||
export interface SubmitOptions {
|
||||
updatedAt?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* submitOrder posts the `commands` slice through `user.games.order`,
|
||||
* decodes the FBS response, and returns per-command outcomes the
|
||||
* caller (the order tab) feeds back into `OrderDraftStore.applyResults`.
|
||||
*
|
||||
* @param client GalaxyClient owning the signed-gRPC transport.
|
||||
* @param gameId Stringified UUID of the game whose order is submitted.
|
||||
* @param commands Subset of the local draft to send. The caller has
|
||||
* already filtered out non-`valid` entries.
|
||||
* @param options.updatedAt Optional engine-assigned timestamp from a
|
||||
* prior submit — Phase 14 always sends `0` because stale-order
|
||||
* detection is not yet wired client-side.
|
||||
*/
|
||||
export async function submitOrder(
|
||||
client: GalaxyClient,
|
||||
gameId: string,
|
||||
commands: OrderCommand[],
|
||||
options: SubmitOptions = {},
|
||||
): Promise<SubmitResult> {
|
||||
const payload = buildOrderPayload(gameId, commands, options.updatedAt ?? 0);
|
||||
const result = await client.executeCommand(MESSAGE_TYPE, payload);
|
||||
if (result.resultCode !== "ok") {
|
||||
const { code, message } = decodeError(result.payloadBytes, result.resultCode);
|
||||
return {
|
||||
ok: false,
|
||||
resultCode: result.resultCode,
|
||||
code,
|
||||
message,
|
||||
};
|
||||
}
|
||||
return decodeOrderResponse(result.payloadBytes, commands);
|
||||
}
|
||||
|
||||
function buildOrderPayload(
|
||||
gameId: string,
|
||||
commands: OrderCommand[],
|
||||
updatedAt: number,
|
||||
): Uint8Array {
|
||||
const builder = new Builder(256);
|
||||
const itemOffsets = commands.map((cmd) => encodeCommandItem(builder, cmd));
|
||||
const commandsVec = UserGamesOrder.createCommandsVector(builder, itemOffsets);
|
||||
const [hi, lo] = uuidToHiLo(gameId);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
UserGamesOrder.startUserGamesOrder(builder);
|
||||
UserGamesOrder.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrder.addUpdatedAt(builder, BigInt(updatedAt));
|
||||
UserGamesOrder.addCommands(builder, commandsVec);
|
||||
const offset = UserGamesOrder.endUserGamesOrder(builder);
|
||||
builder.finish(offset);
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
function encodeCommandItem(builder: Builder, cmd: OrderCommand): number {
|
||||
const cmdIdOffset = builder.createString(cmd.id);
|
||||
const { payloadType, payloadOffset } = encodeCommandPayload(builder, cmd);
|
||||
CommandItem.startCommandItem(builder);
|
||||
CommandItem.addCmdId(builder, cmdIdOffset);
|
||||
CommandItem.addPayloadType(builder, payloadType);
|
||||
CommandItem.addPayload(builder, payloadOffset);
|
||||
return CommandItem.endCommandItem(builder);
|
||||
}
|
||||
|
||||
function encodeCommandPayload(
|
||||
builder: Builder,
|
||||
cmd: OrderCommand,
|
||||
): { payloadType: CommandPayload; payloadOffset: number } {
|
||||
switch (cmd.kind) {
|
||||
case "planetRename": {
|
||||
const nameOffset = builder.createString(cmd.name);
|
||||
const offset = CommandPlanetRename.createCommandPlanetRename(
|
||||
builder,
|
||||
BigInt(cmd.planetNumber),
|
||||
nameOffset,
|
||||
);
|
||||
return {
|
||||
payloadType: CommandPayload.CommandPlanetRename,
|
||||
payloadOffset: offset,
|
||||
};
|
||||
}
|
||||
case "placeholder":
|
||||
throw new SubmitError(
|
||||
"invalid_request",
|
||||
"invalid_request",
|
||||
`placeholder commands cannot be submitted (cmd id ${cmd.id})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function decodeOrderResponse(
|
||||
payload: Uint8Array,
|
||||
commands: OrderCommand[],
|
||||
): SubmitSuccess {
|
||||
const results = new Map<string, CommandOutcome>();
|
||||
const errorCodes = new Map<string, number | null>();
|
||||
let updatedAt = 0;
|
||||
|
||||
if (payload.length === 0) {
|
||||
// Empty envelope (gateway fallback). Apply batch-level verdict.
|
||||
for (const cmd of commands) {
|
||||
results.set(cmd.id, "applied");
|
||||
errorCodes.set(cmd.id, null);
|
||||
}
|
||||
return { ok: true, results, errorCodes, updatedAt };
|
||||
}
|
||||
|
||||
const buffer = new ByteBuffer(payload);
|
||||
const response = UserGamesOrderResponse.getRootAsUserGamesOrderResponse(buffer);
|
||||
updatedAt = Number(response.updatedAt());
|
||||
|
||||
const length = response.commandsLength();
|
||||
if (length === 0) {
|
||||
for (const cmd of commands) {
|
||||
results.set(cmd.id, "applied");
|
||||
errorCodes.set(cmd.id, null);
|
||||
}
|
||||
return { ok: true, results, errorCodes, updatedAt };
|
||||
}
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const item = response.commands(i);
|
||||
if (item === null) continue;
|
||||
const cmdId = item.cmdId();
|
||||
if (cmdId === null) continue;
|
||||
const applied = item.cmdApplied();
|
||||
const errorCode = item.cmdErrorCode();
|
||||
results.set(cmdId, applied === false ? "rejected" : "applied");
|
||||
errorCodes.set(cmdId, errorCode === null ? null : Number(errorCode));
|
||||
}
|
||||
|
||||
// Defensive: any submitted command not echoed back falls back to
|
||||
// applied so the draft entry leaves `submitting`.
|
||||
for (const cmd of commands) {
|
||||
if (!results.has(cmd.id)) {
|
||||
results.set(cmd.id, "applied");
|
||||
errorCodes.set(cmd.id, null);
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: true, results, errorCodes, updatedAt };
|
||||
}
|
||||
|
||||
function decodeError(
|
||||
payload: Uint8Array,
|
||||
resultCode: string,
|
||||
): { code: string; message: string } {
|
||||
if (payload.length === 0) {
|
||||
return { code: resultCode, message: resultCode };
|
||||
}
|
||||
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 : resultCode,
|
||||
message: typeof parsed.message === "string" ? parsed.message : text,
|
||||
};
|
||||
} catch {
|
||||
return { code: resultCode, message: resultCode };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// FlatBuffers payload builders for the Phase 14 Playwright suite.
|
||||
// Mirrors what `pkg/transcoder/order.go` produces in production for
|
||||
// the `user.games.order` POST response and the
|
||||
// `user.games.order.get` GET response.
|
||||
|
||||
import { Builder } from "flatbuffers";
|
||||
|
||||
import { uuidToHiLo } from "../../../src/api/game-state";
|
||||
import { UUID } from "../../../src/proto/galaxy/fbs/common";
|
||||
import {
|
||||
CommandItem,
|
||||
CommandPayload,
|
||||
CommandPlanetRename,
|
||||
UserGamesOrder,
|
||||
UserGamesOrderGetResponse,
|
||||
UserGamesOrderResponse,
|
||||
} from "../../../src/proto/galaxy/fbs/order";
|
||||
|
||||
export interface CommandResultFixture {
|
||||
cmdId: string;
|
||||
planetNumber: number;
|
||||
name: string;
|
||||
applied: boolean | null;
|
||||
errorCode: number | null;
|
||||
}
|
||||
|
||||
export function buildOrderResponsePayload(
|
||||
gameId: string,
|
||||
commands: CommandResultFixture[],
|
||||
updatedAt: number,
|
||||
): Uint8Array {
|
||||
const builder = new Builder(256);
|
||||
const itemOffsets = commands.map((c) => encodeItem(builder, c));
|
||||
const commandsVec = UserGamesOrderResponse.createCommandsVector(
|
||||
builder,
|
||||
itemOffsets,
|
||||
);
|
||||
const [hi, lo] = uuidToHiLo(gameId);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
UserGamesOrderResponse.startUserGamesOrderResponse(builder);
|
||||
UserGamesOrderResponse.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrderResponse.addUpdatedAt(builder, BigInt(updatedAt));
|
||||
UserGamesOrderResponse.addCommands(builder, commandsVec);
|
||||
const offset = UserGamesOrderResponse.endUserGamesOrderResponse(builder);
|
||||
builder.finish(offset);
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
export function buildOrderGetResponsePayload(
|
||||
gameId: string,
|
||||
commands: CommandResultFixture[],
|
||||
updatedAt: number,
|
||||
found = true,
|
||||
): Uint8Array {
|
||||
const builder = new Builder(256);
|
||||
|
||||
let orderOffset = 0;
|
||||
if (found) {
|
||||
const itemOffsets = commands.map((c) => encodeItem(builder, c));
|
||||
const commandsVec = UserGamesOrder.createCommandsVector(
|
||||
builder,
|
||||
itemOffsets,
|
||||
);
|
||||
const [hi, lo] = uuidToHiLo(gameId);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
UserGamesOrder.startUserGamesOrder(builder);
|
||||
UserGamesOrder.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrder.addUpdatedAt(builder, BigInt(updatedAt));
|
||||
UserGamesOrder.addCommands(builder, commandsVec);
|
||||
orderOffset = UserGamesOrder.endUserGamesOrder(builder);
|
||||
}
|
||||
|
||||
UserGamesOrderGetResponse.startUserGamesOrderGetResponse(builder);
|
||||
UserGamesOrderGetResponse.addFound(builder, found);
|
||||
if (orderOffset !== 0) {
|
||||
UserGamesOrderGetResponse.addOrder(builder, orderOffset);
|
||||
}
|
||||
const offset =
|
||||
UserGamesOrderGetResponse.endUserGamesOrderGetResponse(builder);
|
||||
builder.finish(offset);
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
function encodeItem(builder: Builder, c: CommandResultFixture): number {
|
||||
const cmdIdOffset = builder.createString(c.cmdId);
|
||||
const nameOffset = builder.createString(c.name);
|
||||
const inner = CommandPlanetRename.createCommandPlanetRename(
|
||||
builder,
|
||||
BigInt(c.planetNumber),
|
||||
nameOffset,
|
||||
);
|
||||
CommandItem.startCommandItem(builder);
|
||||
CommandItem.addCmdId(builder, cmdIdOffset);
|
||||
if (c.applied !== null) CommandItem.addCmdApplied(builder, c.applied);
|
||||
if (c.errorCode !== null) {
|
||||
CommandItem.addCmdErrorCode(builder, BigInt(c.errorCode));
|
||||
}
|
||||
CommandItem.addPayloadType(builder, CommandPayload.CommandPlanetRename);
|
||||
CommandItem.addPayload(builder, inner);
|
||||
return CommandItem.endCommandItem(builder);
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
// Phase 14 end-to-end coverage for the rename-planet flow. Boots an
|
||||
// authenticated session, mocks the lobby + report + order routes,
|
||||
// drives a click into the renderer to select a planet, opens the
|
||||
// Rename action, types a new name, submits, and verifies the
|
||||
// optimistic overlay (inspector + map label). A second test covers
|
||||
// the rejected path: the engine answers `cmdApplied: false` and the
|
||||
// inspector keeps the original name while the order tab row reads
|
||||
// `rejected`.
|
||||
|
||||
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 {
|
||||
UserGamesOrder,
|
||||
UserGamesOrderGet,
|
||||
} from "../../src/proto/galaxy/fbs/order";
|
||||
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";
|
||||
import {
|
||||
buildOrderGetResponsePayload,
|
||||
buildOrderResponsePayload,
|
||||
type CommandResultFixture,
|
||||
} from "./fixtures/order-fbs";
|
||||
|
||||
const SESSION_ID = "phase-14-rename-session";
|
||||
const GAME_ID = "14141414-1414-1414-1414-141414141414";
|
||||
const WORLD = 4000;
|
||||
const CENTRE = WORLD / 2;
|
||||
const TURN = 4;
|
||||
|
||||
interface MockOpts {
|
||||
storedOrder: CommandResultFixture[];
|
||||
submitOutcome: "applied" | "rejected";
|
||||
}
|
||||
|
||||
interface MockHandle {
|
||||
get submittedRenameName(): string | null;
|
||||
}
|
||||
|
||||
async function mockGateway(page: Page, opts: MockOpts): Promise<MockHandle> {
|
||||
const game: GameFixture = {
|
||||
gameId: GAME_ID,
|
||||
gameName: "Phase 14 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: TURN,
|
||||
};
|
||||
|
||||
let storedOrder = opts.storedOrder.slice();
|
||||
let lastSubmittedName: string | null = null;
|
||||
let lastReportName = "Earth";
|
||||
|
||||
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": {
|
||||
GameReportRequest.getRootAsGameReportRequest(
|
||||
new ByteBuffer(req.payloadBytes),
|
||||
).gameId(new UUID());
|
||||
payload = buildReportPayload({
|
||||
turn: TURN,
|
||||
mapWidth: WORLD,
|
||||
mapHeight: WORLD,
|
||||
localPlanets: [
|
||||
{
|
||||
number: 17,
|
||||
name: lastReportName,
|
||||
x: CENTRE,
|
||||
y: CENTRE,
|
||||
size: 1000,
|
||||
resources: 10,
|
||||
capital: 0,
|
||||
material: 0,
|
||||
population: 850,
|
||||
colonists: 25,
|
||||
industry: 700,
|
||||
production: "drive",
|
||||
freeIndustry: 175,
|
||||
},
|
||||
],
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "user.games.order": {
|
||||
const decoded = UserGamesOrder.getRootAsUserGamesOrder(
|
||||
new ByteBuffer(req.payloadBytes),
|
||||
);
|
||||
const length = decoded.commandsLength();
|
||||
const fixtures: CommandResultFixture[] = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
const item = decoded.commands(i);
|
||||
if (item === null) continue;
|
||||
const cmdId = item.cmdId() ?? "";
|
||||
// Decode the embedded planetRename payload to mirror it back
|
||||
// in the response.
|
||||
const inner = new (await import(
|
||||
"../../src/proto/galaxy/fbs/order"
|
||||
)).CommandPlanetRename();
|
||||
item.payload(inner);
|
||||
const submittedName = inner.name() ?? "";
|
||||
lastSubmittedName = submittedName;
|
||||
const applied = opts.submitOutcome === "applied";
|
||||
fixtures.push({
|
||||
cmdId,
|
||||
planetNumber: Number(inner.number()),
|
||||
name: submittedName,
|
||||
applied,
|
||||
errorCode: applied ? null : 1,
|
||||
});
|
||||
}
|
||||
if (opts.submitOutcome === "applied") {
|
||||
storedOrder = fixtures;
|
||||
lastReportName = fixtures[0]?.name ?? lastReportName;
|
||||
}
|
||||
payload = buildOrderResponsePayload(GAME_ID, fixtures, Date.now());
|
||||
break;
|
||||
}
|
||||
case "user.games.order.get": {
|
||||
UserGamesOrderGet.getRootAsUserGamesOrderGet(
|
||||
new ByteBuffer(req.payloadBytes),
|
||||
);
|
||||
payload = buildOrderGetResponsePayload(
|
||||
GAME_ID,
|
||||
storedOrder,
|
||||
Date.now(),
|
||||
storedOrder.length > 0,
|
||||
);
|
||||
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,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
await page.route(
|
||||
"**/galaxy.gateway.v1.EdgeGateway/SubscribeEvents",
|
||||
async () => {
|
||||
await new Promise<void>(() => {});
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
get submittedRenameName(): string | null {
|
||||
return lastSubmittedName;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
await page.evaluate(
|
||||
(gameId) => window.__galaxyDebug!.clearOrderDraft(gameId),
|
||||
GAME_ID,
|
||||
);
|
||||
}
|
||||
|
||||
async function clickPlanetCentre(page: Page): Promise<void> {
|
||||
const canvas = page.locator("canvas");
|
||||
const box = await canvas.boundingBox();
|
||||
expect(box).not.toBeNull();
|
||||
if (box === null) throw new Error("canvas has no bounding box");
|
||||
await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
|
||||
}
|
||||
|
||||
test("rename a seeded planet, submit, observe overlay + persist after reload", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
test.skip(
|
||||
testInfo.project.name.startsWith("chromium-mobile"),
|
||||
"phase 14 spec covers desktop layout; mobile inherits the same store",
|
||||
);
|
||||
|
||||
const handle = await mockGateway(page, {
|
||||
storedOrder: [],
|
||||
submitOutcome: "applied",
|
||||
});
|
||||
await bootSession(page);
|
||||
await page.goto(`/games/${GAME_ID}/map`);
|
||||
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
|
||||
"data-status",
|
||||
"ready",
|
||||
);
|
||||
|
||||
await clickPlanetCentre(page);
|
||||
const sidebar = page.getByTestId("sidebar-tool-inspector");
|
||||
await expect(sidebar.getByTestId("inspector-planet-name")).toHaveText("Earth");
|
||||
|
||||
await sidebar.getByTestId("inspector-planet-rename-action").click();
|
||||
const input = sidebar.getByTestId("inspector-planet-rename-input");
|
||||
await input.fill("New-Earth");
|
||||
await sidebar.getByTestId("inspector-planet-rename-confirm").click();
|
||||
|
||||
// Open the order tab and assert the row.
|
||||
await page.getByTestId("sidebar-tab-order").click();
|
||||
const orderTool = page.getByTestId("sidebar-tool-order");
|
||||
await expect(orderTool.getByTestId("order-command-label-0")).toContainText(
|
||||
"New-Earth",
|
||||
);
|
||||
await expect(orderTool.getByTestId("order-command-status-0")).toHaveText(
|
||||
"valid",
|
||||
);
|
||||
|
||||
await orderTool.getByTestId("order-submit").click();
|
||||
|
||||
await expect(orderTool.getByTestId("order-command-status-0")).toHaveText(
|
||||
"applied",
|
||||
);
|
||||
expect(handle.submittedRenameName).toBe("New-Earth");
|
||||
|
||||
// Switch back to the inspector — overlay should reflect the new name.
|
||||
await page.getByTestId("sidebar-tab-inspector").click();
|
||||
await expect(sidebar.getByTestId("inspector-planet-name")).toHaveText(
|
||||
"New-Earth",
|
||||
);
|
||||
|
||||
// Reload: the order draft is persisted; on cache-miss boots the
|
||||
// hydrate-from-server path takes over. Both round-trips re-apply
|
||||
// the overlay so the player still sees the renamed planet.
|
||||
await page.reload();
|
||||
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
|
||||
"data-status",
|
||||
"ready",
|
||||
);
|
||||
await page.getByTestId("sidebar-tab-order").click();
|
||||
await expect(orderTool.getByTestId("order-command-label-0")).toContainText(
|
||||
"New-Earth",
|
||||
);
|
||||
});
|
||||
|
||||
test("rejected submit keeps the old name and surfaces the failure", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
test.skip(
|
||||
testInfo.project.name.startsWith("chromium-mobile"),
|
||||
"phase 14 spec covers desktop layout; mobile inherits the same store",
|
||||
);
|
||||
await mockGateway(page, {
|
||||
storedOrder: [],
|
||||
submitOutcome: "rejected",
|
||||
});
|
||||
await bootSession(page);
|
||||
await page.goto(`/games/${GAME_ID}/map`);
|
||||
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
|
||||
"data-status",
|
||||
"ready",
|
||||
);
|
||||
await clickPlanetCentre(page);
|
||||
const sidebar = page.getByTestId("sidebar-tool-inspector");
|
||||
await sidebar.getByTestId("inspector-planet-rename-action").click();
|
||||
await sidebar.getByTestId("inspector-planet-rename-input").fill("Mars-2");
|
||||
await sidebar.getByTestId("inspector-planet-rename-confirm").click();
|
||||
|
||||
await page.getByTestId("sidebar-tab-order").click();
|
||||
const orderTool = page.getByTestId("sidebar-tool-order");
|
||||
await orderTool.getByTestId("order-submit").click();
|
||||
|
||||
await expect(orderTool.getByTestId("order-command-status-0")).toHaveText(
|
||||
"rejected",
|
||||
);
|
||||
|
||||
await page.getByTestId("sidebar-tab-inspector").click();
|
||||
// Overlay does not apply rejected commands — old name persists.
|
||||
await expect(sidebar.getByTestId("inspector-planet-name")).toHaveText("Earth");
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
// Parity tests for the TS port of `pkg/util/string.go.ValidateTypeName`.
|
||||
// Cases are aligned with `pkg/util/string_test.go.TestValidateString`
|
||||
// so the client-side and server-side validators reject the same set
|
||||
// of inputs — a name that's locally valid is always accepted at the
|
||||
// wire level.
|
||||
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
validateEntityName,
|
||||
type EntityNameInvalidReason,
|
||||
} from "../src/lib/util/entity-name";
|
||||
|
||||
describe("validateEntityName", () => {
|
||||
const valid: { name: string; input: string; expected: string }[] = [
|
||||
{ name: "latin + digits", input: "Hello_World-123", expected: "Hello_World-123" },
|
||||
{ name: "cyrillic", input: "Привет_мир-42", expected: "Привет_мир-42" },
|
||||
{ name: "greek", input: "Αλφα_Βητα-2024", expected: "Αλφα_Βητα-2024" },
|
||||
{ name: "arabic", input: "مرحبا_العالم-7", expected: "مرحبا_العالم-7" },
|
||||
{ name: "japanese katakana", input: "テスト_ケース-1", expected: "テスト_ケース-1" },
|
||||
{ name: "chinese", input: "你好_世界-123", expected: "你好_世界-123" },
|
||||
{ name: "hindi (combining marks)", input: "नमस्ते_दुनिया-456", expected: "नमस्ते_दुनिया-456" },
|
||||
{ name: "thai (combining marks)", input: "สวัสดี_โลก-789", expected: "สวัสดี_โลก-789" },
|
||||
{ name: "korean", input: "안녕하세요_세계-101", expected: "안녕하세요_세계-101" },
|
||||
{ name: "trim outer whitespace", input: " Earth ", expected: "Earth" },
|
||||
{ name: "valid consecutive specials", input: "Valid_(special)_Chars", expected: "Valid_(special)_Chars" },
|
||||
{ name: "all allowed specials", input: "A@#b$%c^*d-_e=+f~(g)[h]{i}j", expected: "A@#b$%c^*d-_e=+f~(g)[h]{i}j" },
|
||||
];
|
||||
for (const tc of valid) {
|
||||
test(`accepts: ${tc.name}`, () => {
|
||||
const result = validateEntityName(tc.input);
|
||||
expect(result.ok).toBe(true);
|
||||
if (result.ok) {
|
||||
expect(result.value).toBe(tc.expected);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const invalid: {
|
||||
name: string;
|
||||
input: string;
|
||||
reason: EntityNameInvalidReason;
|
||||
}[] = [
|
||||
{ name: "empty after trim", input: " ", reason: "empty" },
|
||||
{ name: "explicitly empty", input: "", reason: "empty" },
|
||||
{ name: "too long", input: "ValidatedStringHasTooManyCharacters", reason: "too_long" },
|
||||
{ name: "internal space", input: "Test 123", reason: "whitespace" },
|
||||
{ name: "internal tab", input: "Test\tName", reason: "whitespace" },
|
||||
{ name: "internal newline", input: "Test\nName", reason: "whitespace" },
|
||||
{ name: "starts with special after trim", input: " -Test123", reason: "starts_with_special" },
|
||||
{ name: "ends with special after trim", input: "Test123- ", reason: "ends_with_special" },
|
||||
{ name: "emoji", input: "Test🙂Name", reason: "disallowed_character" },
|
||||
{ name: "starts with special $", input: "$pecialString", reason: "starts_with_special" },
|
||||
{ name: "ends with special _", input: "SpecialString_", reason: "ends_with_special" },
|
||||
{ name: "too many consecutive specials", input: "Too_Many_(special[_]Chars", reason: "consecutive_specials" },
|
||||
];
|
||||
for (const tc of invalid) {
|
||||
test(`rejects: ${tc.name}`, () => {
|
||||
const result = validateEntityName(tc.input);
|
||||
expect(result.ok).toBe(false);
|
||||
if (!result.ok) {
|
||||
expect(result.reason).toBe(tc.reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -23,6 +23,14 @@ import {
|
||||
SELECTION_CONTEXT_KEY,
|
||||
SelectionStore,
|
||||
} from "../src/lib/selection.svelte";
|
||||
import {
|
||||
RENDERED_REPORT_CONTEXT_KEY,
|
||||
createRenderedReportSource,
|
||||
} from "../src/lib/rendered-report.svelte";
|
||||
import {
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
OrderDraftStore,
|
||||
} from "../src/sync/order-draft.svelte";
|
||||
import type { GameReport, ReportPlanet } from "../src/api/game-state";
|
||||
|
||||
const pageMock = vi.hoisted(() => ({
|
||||
@@ -70,17 +78,22 @@ function makeReport(planets: ReportPlanet[]): GameReport {
|
||||
function withStores(report: GameReport | null): {
|
||||
gameState: GameStateStore;
|
||||
selection: SelectionStore;
|
||||
orderDraft: OrderDraftStore;
|
||||
context: Map<unknown, unknown>;
|
||||
} {
|
||||
const gameState = new GameStateStore();
|
||||
gameState.report = report;
|
||||
gameState.status = report === null ? "idle" : "ready";
|
||||
const selection = new SelectionStore();
|
||||
const orderDraft = new OrderDraftStore();
|
||||
const renderedReport = createRenderedReportSource(gameState, orderDraft);
|
||||
const context = new Map<unknown, unknown>([
|
||||
[GAME_STATE_CONTEXT_KEY, gameState],
|
||||
[SELECTION_CONTEXT_KEY, selection],
|
||||
[ORDER_DRAFT_CONTEXT_KEY, orderDraft],
|
||||
[RENDERED_REPORT_CONTEXT_KEY, renderedReport],
|
||||
]);
|
||||
return { gameState, selection, context };
|
||||
return { gameState, selection, orderDraft, context };
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -5,12 +5,19 @@
|
||||
// drive it with synthetic `ReportPlanet` literals — no store.
|
||||
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { render } from "@testing-library/svelte";
|
||||
import "fake-indexeddb/auto";
|
||||
import { fireEvent, render } from "@testing-library/svelte";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { i18n } from "../src/lib/i18n/index.svelte";
|
||||
import type { ReportPlanet } from "../src/api/game-state";
|
||||
import Planet from "../src/lib/inspectors/planet.svelte";
|
||||
import {
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
OrderDraftStore,
|
||||
} from "../src/sync/order-draft.svelte";
|
||||
import { IDBCache } from "../src/platform/store/idb-cache";
|
||||
import { openGalaxyDB } from "../src/platform/store/idb";
|
||||
|
||||
beforeEach(() => {
|
||||
i18n.resetForTests("en");
|
||||
@@ -192,6 +199,121 @@ describe("planet inspector", () => {
|
||||
expect(ui.queryByTestId("inspector-planet-field-natural_resources")).toBeNull();
|
||||
});
|
||||
|
||||
test("Rename action is hidden for non-local planets", () => {
|
||||
const ui = render(Planet, {
|
||||
props: {
|
||||
planet: makePlanet({
|
||||
number: 9,
|
||||
name: "Far",
|
||||
kind: "other",
|
||||
owner: "Federation",
|
||||
size: 100,
|
||||
resources: 5,
|
||||
}),
|
||||
},
|
||||
});
|
||||
expect(ui.queryByTestId("inspector-planet-rename-action")).toBeNull();
|
||||
});
|
||||
|
||||
test("Rename action opens an inline editor and validates locally", async () => {
|
||||
const dbName = `galaxy-rename-${crypto.randomUUID()}`;
|
||||
const db = await openGalaxyDB(dbName);
|
||||
const cache = new IDBCache(db);
|
||||
const draft = new OrderDraftStore();
|
||||
await draft.init({ cache, gameId: "00000000-0000-0000-0000-000000000abc" });
|
||||
const context = new Map<unknown, unknown>([
|
||||
[ORDER_DRAFT_CONTEXT_KEY, draft],
|
||||
]);
|
||||
|
||||
const ui = render(Planet, {
|
||||
props: {
|
||||
planet: makePlanet({
|
||||
number: 7,
|
||||
name: "Earth",
|
||||
kind: "local",
|
||||
size: 100,
|
||||
resources: 5,
|
||||
population: 100,
|
||||
colonists: 0,
|
||||
industry: 0,
|
||||
industryStockpile: 0,
|
||||
materialsStockpile: 0,
|
||||
production: "drive",
|
||||
freeIndustry: 0,
|
||||
}),
|
||||
},
|
||||
context,
|
||||
});
|
||||
|
||||
const action = ui.getByTestId("inspector-planet-rename-action");
|
||||
await fireEvent.click(action);
|
||||
|
||||
const input = ui.getByTestId("inspector-planet-rename-input") as HTMLInputElement;
|
||||
expect(input.value).toBe("Earth");
|
||||
const confirm = ui.getByTestId("inspector-planet-rename-confirm");
|
||||
expect(confirm).not.toBeDisabled();
|
||||
|
||||
await fireEvent.input(input, { target: { value: " " } });
|
||||
expect(ui.getByTestId("inspector-planet-rename-error")).toBeVisible();
|
||||
expect(confirm).toBeDisabled();
|
||||
|
||||
await fireEvent.input(input, { target: { value: "New Earth!" } });
|
||||
// Whitespace inside disallowed
|
||||
expect(ui.getByTestId("inspector-planet-rename-error")).toBeVisible();
|
||||
expect(confirm).toBeDisabled();
|
||||
|
||||
await fireEvent.input(input, { target: { value: "Mars-2" } });
|
||||
expect(ui.queryByTestId("inspector-planet-rename-error")).toBeNull();
|
||||
expect(confirm).not.toBeDisabled();
|
||||
|
||||
await fireEvent.click(confirm);
|
||||
expect(draft.commands).toHaveLength(1);
|
||||
const cmd = draft.commands[0]!;
|
||||
expect(cmd.kind).toBe("planetRename");
|
||||
if (cmd.kind !== "planetRename") return;
|
||||
expect(cmd.planetNumber).toBe(7);
|
||||
expect(cmd.name).toBe("Mars-2");
|
||||
|
||||
draft.dispose();
|
||||
db.close();
|
||||
});
|
||||
|
||||
test("Cancel closes the editor without adding to the draft", async () => {
|
||||
const dbName = `galaxy-rename-${crypto.randomUUID()}`;
|
||||
const db = await openGalaxyDB(dbName);
|
||||
const cache = new IDBCache(db);
|
||||
const draft = new OrderDraftStore();
|
||||
await draft.init({ cache, gameId: "00000000-0000-0000-0000-000000000abc" });
|
||||
const context = new Map<unknown, unknown>([
|
||||
[ORDER_DRAFT_CONTEXT_KEY, draft],
|
||||
]);
|
||||
const ui = render(Planet, {
|
||||
props: {
|
||||
planet: makePlanet({
|
||||
number: 1,
|
||||
name: "Earth",
|
||||
kind: "local",
|
||||
size: 100,
|
||||
resources: 5,
|
||||
population: 1,
|
||||
colonists: 0,
|
||||
industry: 0,
|
||||
industryStockpile: 0,
|
||||
materialsStockpile: 0,
|
||||
production: "drive",
|
||||
freeIndustry: 0,
|
||||
}),
|
||||
},
|
||||
context,
|
||||
});
|
||||
await fireEvent.click(ui.getByTestId("inspector-planet-rename-action"));
|
||||
await fireEvent.click(ui.getByTestId("inspector-planet-rename-cancel"));
|
||||
expect(ui.queryByTestId("inspector-planet-rename")).toBeNull();
|
||||
expect(draft.commands).toEqual([]);
|
||||
draft.dispose();
|
||||
db.close();
|
||||
});
|
||||
|
||||
test("missing production string falls back to the localised placeholder", () => {
|
||||
const ui = render(Planet, {
|
||||
props: {
|
||||
|
||||
@@ -175,4 +175,158 @@ describe("OrderDraftStore", () => {
|
||||
expect(reload.commands.map((c) => c.id)).toEqual(["c1"]);
|
||||
reload.dispose();
|
||||
});
|
||||
|
||||
test("absent cache row flips needsServerHydration flag", async () => {
|
||||
const store = new OrderDraftStore();
|
||||
await store.init({ cache, gameId: GAME_ID });
|
||||
expect(store.needsServerHydration).toBe(true);
|
||||
store.dispose();
|
||||
});
|
||||
|
||||
test("explicitly empty cache row honours the user's empty draft", async () => {
|
||||
const seeded = new OrderDraftStore();
|
||||
await seeded.init({ cache, gameId: GAME_ID });
|
||||
await seeded.add({
|
||||
kind: "planetRename",
|
||||
id: "00000000-0000-0000-0000-000000000001",
|
||||
planetNumber: 7,
|
||||
name: "Earth",
|
||||
});
|
||||
await seeded.remove("00000000-0000-0000-0000-000000000001");
|
||||
seeded.dispose();
|
||||
|
||||
const reload = new OrderDraftStore();
|
||||
await reload.init({ cache, gameId: GAME_ID });
|
||||
expect(reload.needsServerHydration).toBe(false);
|
||||
expect(reload.commands).toEqual([]);
|
||||
reload.dispose();
|
||||
});
|
||||
|
||||
test("planetRename validates locally and statuses reflect valid/invalid", async () => {
|
||||
const store = new OrderDraftStore();
|
||||
await store.init({ cache, gameId: GAME_ID });
|
||||
await store.add({
|
||||
kind: "planetRename",
|
||||
id: "id-valid",
|
||||
planetNumber: 1,
|
||||
name: "Earth",
|
||||
});
|
||||
await store.add({
|
||||
kind: "planetRename",
|
||||
id: "id-invalid",
|
||||
planetNumber: 2,
|
||||
name: "$bad",
|
||||
});
|
||||
expect(store.statuses["id-valid"]).toBe("valid");
|
||||
expect(store.statuses["id-invalid"]).toBe("invalid");
|
||||
store.dispose();
|
||||
});
|
||||
|
||||
test("markSubmitting / applyResults flip the status map", async () => {
|
||||
const store = new OrderDraftStore();
|
||||
await store.init({ cache, gameId: GAME_ID });
|
||||
await store.add({
|
||||
kind: "planetRename",
|
||||
id: "id-1",
|
||||
planetNumber: 1,
|
||||
name: "Earth",
|
||||
});
|
||||
store.markSubmitting(["id-1"]);
|
||||
expect(store.statuses["id-1"]).toBe("submitting");
|
||||
store.applyResults({
|
||||
results: new Map([["id-1", "applied"] as const]),
|
||||
updatedAt: 99,
|
||||
});
|
||||
expect(store.statuses["id-1"]).toBe("applied");
|
||||
expect(store.updatedAt).toBe(99);
|
||||
store.dispose();
|
||||
});
|
||||
|
||||
test("markRejected switches submitting entries to rejected", async () => {
|
||||
const store = new OrderDraftStore();
|
||||
await store.init({ cache, gameId: GAME_ID });
|
||||
await store.add({
|
||||
kind: "planetRename",
|
||||
id: "id-1",
|
||||
planetNumber: 1,
|
||||
name: "Earth",
|
||||
});
|
||||
store.markSubmitting(["id-1"]);
|
||||
store.markRejected(["id-1"]);
|
||||
expect(store.statuses["id-1"]).toBe("rejected");
|
||||
store.dispose();
|
||||
});
|
||||
|
||||
test("revertSubmittingToValid restores status after a thrown submit", async () => {
|
||||
const store = new OrderDraftStore();
|
||||
await store.init({ cache, gameId: GAME_ID });
|
||||
await store.add({
|
||||
kind: "planetRename",
|
||||
id: "id-1",
|
||||
planetNumber: 1,
|
||||
name: "Earth",
|
||||
});
|
||||
store.markSubmitting(["id-1"]);
|
||||
store.revertSubmittingToValid();
|
||||
expect(store.statuses["id-1"]).toBe("valid");
|
||||
store.dispose();
|
||||
});
|
||||
|
||||
test("hydrateFromServer seeds the draft on a fresh cache", async () => {
|
||||
const fakeClient = {
|
||||
executeCommand: async () => {
|
||||
const { Builder } = await import("flatbuffers");
|
||||
const { UUID } = await import("../src/proto/galaxy/fbs/common");
|
||||
const order = await import("../src/proto/galaxy/fbs/order");
|
||||
const builder = new Builder(128);
|
||||
const cmdId = builder.createString("hydr-1");
|
||||
const name = builder.createString("Hydrated");
|
||||
const inner = order.CommandPlanetRename.createCommandPlanetRename(
|
||||
builder,
|
||||
BigInt(7),
|
||||
name,
|
||||
);
|
||||
order.CommandItem.startCommandItem(builder);
|
||||
order.CommandItem.addCmdId(builder, cmdId);
|
||||
order.CommandItem.addPayloadType(
|
||||
builder,
|
||||
order.CommandPayload.CommandPlanetRename,
|
||||
);
|
||||
order.CommandItem.addPayload(builder, inner);
|
||||
const item = order.CommandItem.endCommandItem(builder);
|
||||
const cmds = order.UserGamesOrder.createCommandsVector(builder, [item]);
|
||||
const [hi, lo] = (await import("../src/api/game-state")).uuidToHiLo(
|
||||
GAME_ID,
|
||||
);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
order.UserGamesOrder.startUserGamesOrder(builder);
|
||||
order.UserGamesOrder.addGameId(builder, gameIdOffset);
|
||||
order.UserGamesOrder.addUpdatedAt(builder, BigInt(7));
|
||||
order.UserGamesOrder.addCommands(builder, cmds);
|
||||
const orderOffset = order.UserGamesOrder.endUserGamesOrder(builder);
|
||||
order.UserGamesOrderGetResponse.startUserGamesOrderGetResponse(builder);
|
||||
order.UserGamesOrderGetResponse.addFound(builder, true);
|
||||
order.UserGamesOrderGetResponse.addOrder(builder, orderOffset);
|
||||
const offset =
|
||||
order.UserGamesOrderGetResponse.endUserGamesOrderGetResponse(builder);
|
||||
builder.finish(offset);
|
||||
return {
|
||||
resultCode: "ok",
|
||||
payloadBytes: builder.asUint8Array(),
|
||||
};
|
||||
},
|
||||
};
|
||||
const store = new OrderDraftStore();
|
||||
await store.init({ cache, gameId: GAME_ID });
|
||||
expect(store.needsServerHydration).toBe(true);
|
||||
await store.hydrateFromServer({
|
||||
client: fakeClient as never,
|
||||
turn: 5,
|
||||
});
|
||||
expect(store.commands).toHaveLength(1);
|
||||
expect(store.commands[0]!.id).toBe("hydr-1");
|
||||
expect(store.updatedAt).toBe(7);
|
||||
expect(store.needsServerHydration).toBe(false);
|
||||
store.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// Vitest unit coverage for `sync/order-load.ts`. Builds FBS
|
||||
// `UserGamesOrderGetResponse` payloads by hand and verifies the
|
||||
// decoder produces the expected `OrderCommand[]`.
|
||||
|
||||
import { Builder } from "flatbuffers";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import type { GalaxyClient } from "../src/api/galaxy-client";
|
||||
import { uuidToHiLo } from "../src/api/game-state";
|
||||
import { UUID } from "../src/proto/galaxy/fbs/common";
|
||||
import {
|
||||
CommandItem,
|
||||
CommandPayload,
|
||||
CommandPlanetRename,
|
||||
UserGamesOrder,
|
||||
UserGamesOrderGet,
|
||||
UserGamesOrderGetResponse,
|
||||
} from "../src/proto/galaxy/fbs/order";
|
||||
import { fetchOrder, OrderLoadError } from "../src/sync/order-load";
|
||||
|
||||
const GAME_ID = "11111111-2222-3333-4444-555555555555";
|
||||
|
||||
function mockClient(
|
||||
executeCommand: (
|
||||
messageType: string,
|
||||
payload: Uint8Array,
|
||||
) => Promise<{ resultCode: string; payloadBytes: Uint8Array }>,
|
||||
): GalaxyClient {
|
||||
return { executeCommand } as unknown as GalaxyClient;
|
||||
}
|
||||
|
||||
function buildResponse(
|
||||
commands: { id: string; planetNumber: number; name: string }[],
|
||||
updatedAt: number,
|
||||
found = true,
|
||||
): Uint8Array {
|
||||
const builder = new Builder(256);
|
||||
|
||||
let orderOffset = 0;
|
||||
if (found) {
|
||||
const itemOffsets = commands.map((c) => {
|
||||
const cmdIdOffset = builder.createString(c.id);
|
||||
const nameOffset = builder.createString(c.name);
|
||||
const inner = CommandPlanetRename.createCommandPlanetRename(
|
||||
builder,
|
||||
BigInt(c.planetNumber),
|
||||
nameOffset,
|
||||
);
|
||||
CommandItem.startCommandItem(builder);
|
||||
CommandItem.addCmdId(builder, cmdIdOffset);
|
||||
CommandItem.addPayloadType(builder, CommandPayload.CommandPlanetRename);
|
||||
CommandItem.addPayload(builder, inner);
|
||||
return CommandItem.endCommandItem(builder);
|
||||
});
|
||||
const commandsVec = UserGamesOrder.createCommandsVector(builder, itemOffsets);
|
||||
const [hi, lo] = uuidToHiLo(GAME_ID);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
UserGamesOrder.startUserGamesOrder(builder);
|
||||
UserGamesOrder.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrder.addUpdatedAt(builder, BigInt(updatedAt));
|
||||
UserGamesOrder.addCommands(builder, commandsVec);
|
||||
orderOffset = UserGamesOrder.endUserGamesOrder(builder);
|
||||
}
|
||||
|
||||
UserGamesOrderGetResponse.startUserGamesOrderGetResponse(builder);
|
||||
UserGamesOrderGetResponse.addFound(builder, found);
|
||||
if (orderOffset !== 0) {
|
||||
UserGamesOrderGetResponse.addOrder(builder, orderOffset);
|
||||
}
|
||||
const offset = UserGamesOrderGetResponse.endUserGamesOrderGetResponse(builder);
|
||||
builder.finish(offset);
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
describe("fetchOrder", () => {
|
||||
test("decodes a found response into typed commands", async () => {
|
||||
const responsePayload = buildResponse(
|
||||
[{ id: "cmd-1", planetNumber: 7, name: "Earth" }],
|
||||
42,
|
||||
);
|
||||
const exec = vi.fn(async (messageType: string) => {
|
||||
expect(messageType).toBe("user.games.order.get");
|
||||
return { resultCode: "ok", payloadBytes: responsePayload };
|
||||
});
|
||||
const result = await fetchOrder(mockClient(exec), GAME_ID, 5);
|
||||
|
||||
expect(result.commands).toHaveLength(1);
|
||||
const cmd = result.commands[0]!;
|
||||
expect(cmd.kind).toBe("planetRename");
|
||||
if (cmd.kind !== "planetRename") return;
|
||||
expect(cmd.id).toBe("cmd-1");
|
||||
expect(cmd.planetNumber).toBe(7);
|
||||
expect(cmd.name).toBe("Earth");
|
||||
expect(result.updatedAt).toBe(42);
|
||||
});
|
||||
|
||||
test("found=false surfaces as an empty draft", async () => {
|
||||
const responsePayload = buildResponse([], 0, false);
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "ok",
|
||||
payloadBytes: responsePayload,
|
||||
}));
|
||||
const result = await fetchOrder(mockClient(exec), GAME_ID, 5);
|
||||
expect(result.commands).toEqual([]);
|
||||
expect(result.updatedAt).toBe(0);
|
||||
});
|
||||
|
||||
test("rejects negative turn before issuing a request", async () => {
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "ok",
|
||||
payloadBytes: new Uint8Array(),
|
||||
}));
|
||||
await expect(fetchOrder(mockClient(exec), GAME_ID, -1)).rejects.toBeInstanceOf(
|
||||
OrderLoadError,
|
||||
);
|
||||
expect(exec).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("throws OrderLoadError on non-ok resultCode", async () => {
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "internal_error",
|
||||
payloadBytes: new TextEncoder().encode(
|
||||
JSON.stringify({ code: "boom", message: "down" }),
|
||||
),
|
||||
}));
|
||||
await expect(fetchOrder(mockClient(exec), GAME_ID, 5)).rejects.toMatchObject({
|
||||
name: "OrderLoadError",
|
||||
resultCode: "internal_error",
|
||||
code: "boom",
|
||||
});
|
||||
});
|
||||
|
||||
test("posts a well-formed UserGamesOrderGet payload", async () => {
|
||||
let captured: Uint8Array | null = null;
|
||||
const exec = vi.fn(async (_messageType, payload: Uint8Array) => {
|
||||
captured = payload;
|
||||
return {
|
||||
resultCode: "ok",
|
||||
payloadBytes: buildResponse([], 0, false),
|
||||
};
|
||||
});
|
||||
await fetchOrder(mockClient(exec), GAME_ID, 9);
|
||||
expect(captured).not.toBeNull();
|
||||
const decoded = UserGamesOrderGet.getRootAsUserGamesOrderGet(
|
||||
new (await import("flatbuffers")).ByteBuffer(captured!),
|
||||
);
|
||||
expect(Number(decoded.turn())).toBe(9);
|
||||
const id = decoded.gameId();
|
||||
expect(id).not.toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,143 @@
|
||||
// Vitest unit coverage for the pure `applyOrderOverlay` projection.
|
||||
// Phase 14 understands `planetRename` only; future phases (set
|
||||
// production, route updates) will extend the overlay and need
|
||||
// equivalent cases here.
|
||||
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import {
|
||||
applyOrderOverlay,
|
||||
type GameReport,
|
||||
type ReportPlanet,
|
||||
} from "../src/api/game-state";
|
||||
import type { CommandStatus, OrderCommand } from "../src/sync/order-types";
|
||||
|
||||
function makePlanet(overrides: Partial<ReportPlanet>): ReportPlanet {
|
||||
return {
|
||||
number: 0,
|
||||
name: "",
|
||||
x: 0,
|
||||
y: 0,
|
||||
kind: "local",
|
||||
owner: null,
|
||||
size: null,
|
||||
resources: null,
|
||||
industryStockpile: null,
|
||||
materialsStockpile: null,
|
||||
industry: null,
|
||||
population: null,
|
||||
colonists: null,
|
||||
production: null,
|
||||
freeIndustry: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function makeReport(planets: ReportPlanet[]): GameReport {
|
||||
return {
|
||||
turn: 4,
|
||||
mapWidth: 4000,
|
||||
mapHeight: 4000,
|
||||
planetCount: planets.length,
|
||||
planets,
|
||||
};
|
||||
}
|
||||
|
||||
describe("applyOrderOverlay", () => {
|
||||
test("returns the same report when no commands match", () => {
|
||||
const report = makeReport([makePlanet({ number: 1, name: "Earth" })]);
|
||||
const out = applyOrderOverlay(report, [], {});
|
||||
expect(out).toBe(report);
|
||||
});
|
||||
|
||||
test("renames a planet on applied commands", () => {
|
||||
const report = makeReport([
|
||||
makePlanet({ number: 1, name: "Earth" }),
|
||||
makePlanet({ number: 2, name: "Mars" }),
|
||||
]);
|
||||
const cmd: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "cmd-1",
|
||||
planetNumber: 1,
|
||||
name: "New Earth",
|
||||
};
|
||||
const statuses: Record<string, CommandStatus> = { "cmd-1": "applied" };
|
||||
const out = applyOrderOverlay(report, [cmd], statuses);
|
||||
|
||||
expect(out).not.toBe(report);
|
||||
expect(out.planets[0]!.name).toBe("New Earth");
|
||||
expect(out.planets[1]!.name).toBe("Mars");
|
||||
// raw report stays untouched
|
||||
expect(report.planets[0]!.name).toBe("Earth");
|
||||
});
|
||||
|
||||
test("renames on submitting too (in-flight optimistic)", () => {
|
||||
const report = makeReport([makePlanet({ number: 1, name: "Earth" })]);
|
||||
const cmd: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "cmd-1",
|
||||
planetNumber: 1,
|
||||
name: "Pending",
|
||||
};
|
||||
const out = applyOrderOverlay(report, [cmd], { "cmd-1": "submitting" });
|
||||
expect(out.planets[0]!.name).toBe("Pending");
|
||||
});
|
||||
|
||||
test("skips unsubmitted statuses (draft/valid/invalid/rejected)", () => {
|
||||
const report = makeReport([makePlanet({ number: 1, name: "Earth" })]);
|
||||
const cmd: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "cmd-1",
|
||||
planetNumber: 1,
|
||||
name: "Tentative",
|
||||
};
|
||||
for (const status of ["draft", "valid", "invalid", "rejected"] as const) {
|
||||
const out = applyOrderOverlay(report, [cmd], { "cmd-1": status });
|
||||
expect(out.planets[0]!.name).toBe("Earth");
|
||||
}
|
||||
});
|
||||
|
||||
test("ignores rename for missing planet (visibility lost)", () => {
|
||||
const report = makeReport([makePlanet({ number: 1, name: "Earth" })]);
|
||||
const cmd: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "cmd-1",
|
||||
planetNumber: 99,
|
||||
name: "Phantom",
|
||||
};
|
||||
const out = applyOrderOverlay(report, [cmd], { "cmd-1": "applied" });
|
||||
expect(out).toBe(report);
|
||||
});
|
||||
|
||||
test("placeholder commands pass through", () => {
|
||||
const report = makeReport([makePlanet({ number: 1, name: "Earth" })]);
|
||||
const cmd: OrderCommand = {
|
||||
kind: "placeholder",
|
||||
id: "cmd-1",
|
||||
label: "noop",
|
||||
};
|
||||
const out = applyOrderOverlay(report, [cmd], { "cmd-1": "applied" });
|
||||
expect(out).toBe(report);
|
||||
});
|
||||
|
||||
test("multiple renames apply in command order", () => {
|
||||
const report = makeReport([makePlanet({ number: 1, name: "Old" })]);
|
||||
const first: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "cmd-1",
|
||||
planetNumber: 1,
|
||||
name: "Mid",
|
||||
};
|
||||
const second: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "cmd-2",
|
||||
planetNumber: 1,
|
||||
name: "Final",
|
||||
};
|
||||
const out = applyOrderOverlay(report, [first, second], {
|
||||
"cmd-1": "applied",
|
||||
"cmd-2": "applied",
|
||||
});
|
||||
expect(out.planets[0]!.name).toBe("Final");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,222 @@
|
||||
// Component coverage for the Phase 14 order-tab submit flow. Drives
|
||||
// the tab against an in-memory `OrderDraftStore`, a synthetic
|
||||
// `GalaxyClient`, and a stubbed `GameStateStore.refresh`. Every
|
||||
// case asserts both the rendered DOM (status badges, button state)
|
||||
// and the side effect on the draft store (per-command status flips).
|
||||
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import "fake-indexeddb/auto";
|
||||
import { fireEvent, render, waitFor } from "@testing-library/svelte";
|
||||
import { Builder } from "flatbuffers";
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import OrderTab from "../src/lib/sidebar/order-tab.svelte";
|
||||
import {
|
||||
ORDER_DRAFT_CONTEXT_KEY,
|
||||
OrderDraftStore,
|
||||
} from "../src/sync/order-draft.svelte";
|
||||
import {
|
||||
GAME_STATE_CONTEXT_KEY,
|
||||
GameStateStore,
|
||||
} from "../src/lib/game-state.svelte";
|
||||
import {
|
||||
GALAXY_CLIENT_CONTEXT_KEY,
|
||||
GalaxyClientHolder,
|
||||
} from "../src/lib/galaxy-client-context.svelte";
|
||||
import { i18n } from "../src/lib/i18n/index.svelte";
|
||||
import { uuidToHiLo } from "../src/api/game-state";
|
||||
import type { GalaxyClient } from "../src/api/galaxy-client";
|
||||
import type { OrderCommand } from "../src/sync/order-types";
|
||||
import { IDBCache } from "../src/platform/store/idb-cache";
|
||||
import { openGalaxyDB, type GalaxyDB } from "../src/platform/store/idb";
|
||||
import type { Cache } from "../src/platform/store/index";
|
||||
import { UUID } from "../src/proto/galaxy/fbs/common";
|
||||
import {
|
||||
CommandItem,
|
||||
CommandPayload,
|
||||
CommandPlanetRename,
|
||||
UserGamesOrderResponse,
|
||||
} from "../src/proto/galaxy/fbs/order";
|
||||
|
||||
const GAME_ID = "11111111-2222-3333-4444-555555555555";
|
||||
|
||||
let db: Awaited<ReturnType<typeof openGalaxyDB>>;
|
||||
let dbName: string;
|
||||
let cache: Cache;
|
||||
|
||||
beforeEach(async () => {
|
||||
dbName = `galaxy-order-tab-${crypto.randomUUID()}`;
|
||||
db = await openGalaxyDB(dbName);
|
||||
cache = new IDBCache(db);
|
||||
i18n.resetForTests("en");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
db.close();
|
||||
await new Promise<void>((resolve) => {
|
||||
const req = indexedDB.deleteDatabase(dbName);
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = () => resolve();
|
||||
req.onblocked = () => resolve();
|
||||
});
|
||||
});
|
||||
|
||||
interface Setup {
|
||||
context: Map<unknown, unknown>;
|
||||
draft: OrderDraftStore;
|
||||
gameState: GameStateStore;
|
||||
clientHolder: GalaxyClientHolder;
|
||||
exec: ReturnType<typeof vi.fn>;
|
||||
refresh: ReturnType<typeof vi.fn>;
|
||||
}
|
||||
|
||||
function buildResponse(
|
||||
commands: { id: string; applied: boolean | null; errorCode: number | null }[],
|
||||
updatedAt: number,
|
||||
): Uint8Array {
|
||||
const builder = new Builder(256);
|
||||
const itemOffsets = commands.map((c) => {
|
||||
const cmdIdOffset = builder.createString(c.id);
|
||||
const nameOffset = builder.createString("ignored");
|
||||
const inner = CommandPlanetRename.createCommandPlanetRename(
|
||||
builder,
|
||||
BigInt(0),
|
||||
nameOffset,
|
||||
);
|
||||
CommandItem.startCommandItem(builder);
|
||||
CommandItem.addCmdId(builder, cmdIdOffset);
|
||||
if (c.applied !== null) CommandItem.addCmdApplied(builder, c.applied);
|
||||
if (c.errorCode !== null) {
|
||||
CommandItem.addCmdErrorCode(builder, BigInt(c.errorCode));
|
||||
}
|
||||
CommandItem.addPayloadType(builder, CommandPayload.CommandPlanetRename);
|
||||
CommandItem.addPayload(builder, inner);
|
||||
return CommandItem.endCommandItem(builder);
|
||||
});
|
||||
const commandsVec = UserGamesOrderResponse.createCommandsVector(
|
||||
builder,
|
||||
itemOffsets,
|
||||
);
|
||||
const [hi, lo] = uuidToHiLo(GAME_ID);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
UserGamesOrderResponse.startUserGamesOrderResponse(builder);
|
||||
UserGamesOrderResponse.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrderResponse.addUpdatedAt(builder, BigInt(updatedAt));
|
||||
UserGamesOrderResponse.addCommands(builder, commandsVec);
|
||||
const offset = UserGamesOrderResponse.endUserGamesOrderResponse(builder);
|
||||
builder.finish(offset);
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
async function makeSetup(commands: OrderCommand[]): Promise<Setup> {
|
||||
const draft = new OrderDraftStore();
|
||||
await draft.init({ cache, gameId: GAME_ID });
|
||||
for (const cmd of commands) {
|
||||
await draft.add(cmd);
|
||||
}
|
||||
const gameState = new GameStateStore();
|
||||
gameState.gameId = GAME_ID;
|
||||
gameState.status = "ready";
|
||||
const refresh = vi.fn(async () => {});
|
||||
gameState.refresh = refresh as unknown as typeof gameState.refresh;
|
||||
const clientHolder = new GalaxyClientHolder();
|
||||
const exec = vi.fn(async (_messageType: string, _payload: Uint8Array) => ({
|
||||
resultCode: "ok",
|
||||
payloadBytes: buildResponse(
|
||||
commands.map((cmd) => ({
|
||||
id: cmd.id,
|
||||
applied: true,
|
||||
errorCode: null,
|
||||
})),
|
||||
17,
|
||||
),
|
||||
}));
|
||||
clientHolder.set({ executeCommand: exec } as unknown as GalaxyClient);
|
||||
const context = new Map<unknown, unknown>([
|
||||
[ORDER_DRAFT_CONTEXT_KEY, draft],
|
||||
[GAME_STATE_CONTEXT_KEY, gameState],
|
||||
[GALAXY_CLIENT_CONTEXT_KEY, clientHolder],
|
||||
]);
|
||||
return { context, draft, gameState, clientHolder, exec, refresh };
|
||||
}
|
||||
|
||||
describe("order-tab", () => {
|
||||
test("renders the empty state when the draft has no commands", async () => {
|
||||
const { context } = await makeSetup([]);
|
||||
const ui = render(OrderTab, { context });
|
||||
expect(ui.getByTestId("order-empty")).toBeVisible();
|
||||
expect(ui.queryByTestId("order-submit")).toBeNull();
|
||||
});
|
||||
|
||||
test("Submit is disabled when every entry is invalid", async () => {
|
||||
const { context } = await makeSetup([
|
||||
{ kind: "planetRename", id: "id-1", planetNumber: 1, name: "" },
|
||||
]);
|
||||
const ui = render(OrderTab, { context });
|
||||
const submit = ui.getByTestId("order-submit");
|
||||
expect(submit).toBeDisabled();
|
||||
expect(ui.getByTestId("order-command-status-0")).toHaveTextContent(
|
||||
"invalid",
|
||||
);
|
||||
});
|
||||
|
||||
test("Submit posts every valid command and applies returned statuses", async () => {
|
||||
const { context, draft, exec, refresh } = await makeSetup([
|
||||
{ kind: "planetRename", id: "id-1", planetNumber: 1, name: "Earth" },
|
||||
]);
|
||||
const ui = render(OrderTab, { context });
|
||||
const submit = ui.getByTestId("order-submit");
|
||||
expect(submit).not.toBeDisabled();
|
||||
expect(ui.getByTestId("order-command-status-0")).toHaveTextContent("valid");
|
||||
|
||||
await fireEvent.click(submit);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(draft.statuses["id-1"]).toBe("applied");
|
||||
});
|
||||
expect(exec).toHaveBeenCalledTimes(1);
|
||||
expect(refresh).toHaveBeenCalledTimes(1);
|
||||
expect(ui.getByTestId("order-command-status-0")).toHaveTextContent(
|
||||
"applied",
|
||||
);
|
||||
});
|
||||
|
||||
test("Non-ok response marks every submitting entry as rejected", async () => {
|
||||
const { context, draft, refresh } = await makeSetup([
|
||||
{ kind: "planetRename", id: "id-1", planetNumber: 1, name: "Earth" },
|
||||
]);
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "invalid_request",
|
||||
payloadBytes: new TextEncoder().encode(
|
||||
JSON.stringify({ code: "boom", message: "down" }),
|
||||
),
|
||||
}));
|
||||
const holder = context.get(GALAXY_CLIENT_CONTEXT_KEY) as GalaxyClientHolder;
|
||||
holder.set({ executeCommand: exec } as unknown as GalaxyClient);
|
||||
|
||||
const ui = render(OrderTab, { context });
|
||||
await fireEvent.click(ui.getByTestId("order-submit"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(draft.statuses["id-1"]).toBe("rejected");
|
||||
});
|
||||
expect(refresh).not.toHaveBeenCalled();
|
||||
expect(ui.getByTestId("order-submit-error")).toHaveTextContent("down");
|
||||
});
|
||||
|
||||
test("Already-applied entries do not get re-submitted", async () => {
|
||||
const { context, draft, exec } = await makeSetup([
|
||||
{ kind: "planetRename", id: "id-1", planetNumber: 1, name: "Earth" },
|
||||
]);
|
||||
draft.markSubmitting(["id-1"]);
|
||||
draft.applyResults({
|
||||
results: new Map([["id-1", "applied"] as const]),
|
||||
updatedAt: 1,
|
||||
});
|
||||
|
||||
const ui = render(OrderTab, { context });
|
||||
const submit = ui.getByTestId("order-submit");
|
||||
expect(submit).toBeDisabled();
|
||||
expect(exec).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,181 @@
|
||||
// Vitest unit coverage for `sync/submit.ts`. Drives the submit
|
||||
// pipeline against a stub `GalaxyClient` whose `executeCommand`
|
||||
// hand-builds FBS responses, so the parser is exercised against
|
||||
// payloads identical to what the real gateway returns.
|
||||
|
||||
import { Builder } from "flatbuffers";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import type { GalaxyClient } from "../src/api/galaxy-client";
|
||||
import { uuidToHiLo } from "../src/api/game-state";
|
||||
import { UUID } from "../src/proto/galaxy/fbs/common";
|
||||
import {
|
||||
CommandItem,
|
||||
CommandPlanetRename,
|
||||
CommandPayload,
|
||||
UserGamesOrder,
|
||||
UserGamesOrderResponse,
|
||||
} from "../src/proto/galaxy/fbs/order";
|
||||
import { submitOrder } from "../src/sync/submit";
|
||||
import type { OrderCommand } from "../src/sync/order-types";
|
||||
|
||||
const GAME_ID = "11111111-2222-3333-4444-555555555555";
|
||||
|
||||
function mockClient(
|
||||
executeCommand: (
|
||||
messageType: string,
|
||||
payload: Uint8Array,
|
||||
) => Promise<{ resultCode: string; payloadBytes: Uint8Array }>,
|
||||
): GalaxyClient {
|
||||
return { executeCommand } as unknown as GalaxyClient;
|
||||
}
|
||||
|
||||
function buildResponse(
|
||||
commands: { id: string; applied: boolean | null; errorCode: number | null }[],
|
||||
updatedAt: number,
|
||||
): Uint8Array {
|
||||
const builder = new Builder(256);
|
||||
const itemOffsets = commands.map((c) => {
|
||||
const cmdIdOffset = builder.createString(c.id);
|
||||
const nameOffset = builder.createString("ignored");
|
||||
const payloadOffset = CommandPlanetRename.createCommandPlanetRename(
|
||||
builder,
|
||||
BigInt(0),
|
||||
nameOffset,
|
||||
);
|
||||
CommandItem.startCommandItem(builder);
|
||||
CommandItem.addCmdId(builder, cmdIdOffset);
|
||||
if (c.applied !== null) CommandItem.addCmdApplied(builder, c.applied);
|
||||
if (c.errorCode !== null) {
|
||||
CommandItem.addCmdErrorCode(builder, BigInt(c.errorCode));
|
||||
}
|
||||
CommandItem.addPayloadType(builder, CommandPayload.CommandPlanetRename);
|
||||
CommandItem.addPayload(builder, payloadOffset);
|
||||
return CommandItem.endCommandItem(builder);
|
||||
});
|
||||
const commandsVec = UserGamesOrderResponse.createCommandsVector(builder, itemOffsets);
|
||||
const [hi, lo] = uuidToHiLo(GAME_ID);
|
||||
const gameIdOffset = UUID.createUUID(builder, hi, lo);
|
||||
UserGamesOrderResponse.startUserGamesOrderResponse(builder);
|
||||
UserGamesOrderResponse.addGameId(builder, gameIdOffset);
|
||||
UserGamesOrderResponse.addUpdatedAt(builder, BigInt(updatedAt));
|
||||
UserGamesOrderResponse.addCommands(builder, commandsVec);
|
||||
const offset = UserGamesOrderResponse.endUserGamesOrderResponse(builder);
|
||||
builder.finish(offset);
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
const sampleRename: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "00000000-0000-0000-0000-00000000aaaa",
|
||||
planetNumber: 7,
|
||||
name: "Earth",
|
||||
};
|
||||
|
||||
describe("submitOrder", () => {
|
||||
test("decodes per-command results from a populated response", async () => {
|
||||
const responsePayload = buildResponse(
|
||||
[{ id: sampleRename.id, applied: true, errorCode: null }],
|
||||
99,
|
||||
);
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "ok",
|
||||
payloadBytes: responsePayload,
|
||||
}));
|
||||
const result = await submitOrder(mockClient(exec), GAME_ID, [sampleRename]);
|
||||
|
||||
expect(exec).toHaveBeenCalledOnce();
|
||||
expect(result.ok).toBe(true);
|
||||
if (!result.ok) return;
|
||||
expect(result.results.get(sampleRename.id)).toBe("applied");
|
||||
expect(result.errorCodes.get(sampleRename.id)).toBeNull();
|
||||
expect(result.updatedAt).toBe(99);
|
||||
});
|
||||
|
||||
test("falls back to batch-level applied when commands array is empty", async () => {
|
||||
// Hand-craft an envelope without `commands` to mimic the legacy
|
||||
// gateway behaviour (or a 204 wrapped via the fallback path).
|
||||
const builder = new Builder(64);
|
||||
UserGamesOrderResponse.startUserGamesOrderResponse(builder);
|
||||
const offset = UserGamesOrderResponse.endUserGamesOrderResponse(builder);
|
||||
builder.finish(offset);
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "ok",
|
||||
payloadBytes: builder.asUint8Array(),
|
||||
}));
|
||||
|
||||
const result = await submitOrder(mockClient(exec), GAME_ID, [sampleRename]);
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
if (!result.ok) return;
|
||||
expect(result.results.get(sampleRename.id)).toBe("applied");
|
||||
expect(result.errorCodes.get(sampleRename.id)).toBeNull();
|
||||
});
|
||||
|
||||
test("surfaces mixed applied / rejected entries by cmd id", async () => {
|
||||
const second: OrderCommand = {
|
||||
kind: "planetRename",
|
||||
id: "00000000-0000-0000-0000-00000000bbbb",
|
||||
planetNumber: 8,
|
||||
name: "Mars",
|
||||
};
|
||||
const responsePayload = buildResponse(
|
||||
[
|
||||
{ id: sampleRename.id, applied: true, errorCode: null },
|
||||
{ id: second.id, applied: false, errorCode: 42 },
|
||||
],
|
||||
120,
|
||||
);
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "ok",
|
||||
payloadBytes: responsePayload,
|
||||
}));
|
||||
|
||||
const result = await submitOrder(mockClient(exec), GAME_ID, [sampleRename, second]);
|
||||
expect(result.ok).toBe(true);
|
||||
if (!result.ok) return;
|
||||
expect(result.results.get(sampleRename.id)).toBe("applied");
|
||||
expect(result.errorCodes.get(sampleRename.id)).toBeNull();
|
||||
expect(result.results.get(second.id)).toBe("rejected");
|
||||
expect(result.errorCodes.get(second.id)).toBe(42);
|
||||
});
|
||||
|
||||
test("returns SubmitFailure on non-ok resultCode without throwing", async () => {
|
||||
const exec = vi.fn(async () => ({
|
||||
resultCode: "invalid_request",
|
||||
payloadBytes: new TextEncoder().encode(
|
||||
JSON.stringify({ code: "validation_failed", message: "bad name" }),
|
||||
),
|
||||
}));
|
||||
|
||||
const result = await submitOrder(mockClient(exec), GAME_ID, [sampleRename]);
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (result.ok) return;
|
||||
expect(result.resultCode).toBe("invalid_request");
|
||||
expect(result.code).toBe("validation_failed");
|
||||
expect(result.message).toBe("bad name");
|
||||
});
|
||||
|
||||
test("posts a well-formed UserGamesOrder payload", async () => {
|
||||
let captured: Uint8Array | null = null;
|
||||
const exec = vi.fn(async (_messageType, payload: Uint8Array) => {
|
||||
captured = payload;
|
||||
return { resultCode: "ok", payloadBytes: new Uint8Array() };
|
||||
});
|
||||
await submitOrder(mockClient(exec), GAME_ID, [sampleRename]);
|
||||
expect(captured).not.toBeNull();
|
||||
const decoded = UserGamesOrder.getRootAsUserGamesOrder(
|
||||
new (await import("flatbuffers")).ByteBuffer(captured!),
|
||||
);
|
||||
expect(decoded.commandsLength()).toBe(1);
|
||||
const item = decoded.commands(0);
|
||||
expect(item).not.toBeNull();
|
||||
expect(item!.cmdId()).toBe(sampleRename.id);
|
||||
expect(item!.payloadType()).toBe(CommandPayload.CommandPlanetRename);
|
||||
const inner = new CommandPlanetRename();
|
||||
item!.payload(inner);
|
||||
expect(Number(inner.number())).toBe(7);
|
||||
expect(inner.name()).toBe("Earth");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user