Initial scaffold: Nakama backend, Godot client, content schema

Sets up the Step 1 (Project Foundation) and Step 2 (Content Schemas) scaffold
from the implementation sequence. Includes Docker Compose stack, Nakama
TypeScript module stubs, PostgreSQL migration, Godot 4 project shell with
scene stubs and NakamaClient singleton, YAML content schemas for all entity
types, and example data for 3 characters, 2 jobs, and all 7 core resources.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
caoimhinr 2026-06-02 23:33:06 +02:00
commit fb00954954
37 changed files with 2730 additions and 0 deletions

52
nakama/modules/main.ts Normal file
View file

@ -0,0 +1,52 @@
// Xyvera — Nakama server-side TypeScript runtime entry point
// All game logic that touches currency, pulls, or inventory must execute
// server-side only. The client is never trusted for economy-critical decisions.
import * as auth from "./auth";
import * as gacha from "./gacha";
import * as inventory from "./inventory";
import * as progression from "./progression";
import * as village from "./village";
// InitModule is called once by Nakama at startup.
// Register all RPCs and hooks here.
function InitModule(
ctx: nkruntime.Context,
logger: nkruntime.Logger,
nk: nkruntime.Nakama,
initializer: nkruntime.Initializer
): Error | void {
logger.info("Xyvera module initialising");
// ── Auth ──────────────────────────────────────────────────────────────────
// Called after a new account is created. Seeds the player's starting state.
initializer.registerAfterAuthenticateDevice(auth.afterAuthenticateDevice);
// ── Gacha ─────────────────────────────────────────────────────────────────
// Authoritative pull execution. Client never resolves pull outcomes.
initializer.registerRpc("gacha/pull", gacha.rpcGachaPull);
initializer.registerRpc("gacha/banners", gacha.rpcListBanners);
initializer.registerRpc("gacha/pity", gacha.rpcGetPity);
initializer.registerRpc("gacha/history", gacha.rpcGetPullHistory);
// ── Inventory ─────────────────────────────────────────────────────────────
initializer.registerRpc("inventory/get", inventory.rpcGetInventory);
initializer.registerRpc("inventory/resources", inventory.rpcGetResources);
// ── Progression ───────────────────────────────────────────────────────────
initializer.registerRpc("progression/level_up", progression.rpcLevelUp);
initializer.registerRpc("progression/ascend", progression.rpcAscend);
initializer.registerRpc("progression/upgrade_skill", progression.rpcUpgradeSkill);
// ── Village and assignment ─────────────────────────────────────────────────
// Passive resource accumulation is calculated server-side at claim time.
initializer.registerRpc("village/state", village.rpcGetVillageState);
initializer.registerRpc("village/assign", village.rpcAssignCharacter);
initializer.registerRpc("village/unassign", village.rpcUnassignCharacter);
initializer.registerRpc("village/collect", village.rpcCollectPassiveResources);
// Manual micro-management endpoint — the core differentiating mechanic.
// Server enforces diminishing returns and daily caps.
initializer.registerRpc("village/manual_work", village.rpcManualWork);
logger.info("Xyvera module initialised successfully");
}