From e506b98e865d659aac6e77a5de8b43528836ab1f Mon Sep 17 00:00:00 2001 From: adtpdn Date: Sun, 5 Jul 2026 13:45:41 +0800 Subject: [PATCH] docs: rewrite skin creation workflow for current Lua backend --- Architecture-Server-check.md | 78 ++++++++++ Skin-Creation-Workflow.-.md | 287 +++++++++++++++++++++++++++++------ 2 files changed, 320 insertions(+), 45 deletions(-) create mode 100644 Architecture-Server-check.md diff --git a/Architecture-Server-check.md b/Architecture-Server-check.md new file mode 100644 index 0000000..2d76767 --- /dev/null +++ b/Architecture-Server-check.md @@ -0,0 +1,78 @@ + + +# Tekton Dash Armageddon - Server Architecture + +## Nakama Backend (`server/nakama/lua/`) + +[Back to top](#top) + + +The backend runs on Nakama, written in Lua. It provides authoritative server-side logic for the economy, anti-cheat, mail, and gacha pulls. + +Godot clients call these endpoints via `BackendService.api_rpc_async()`. + +### Key Lua Modules + +[Back to top](#top) + +- **`economy.lua`:** + - `buy_currency`: Validates mock/Google/Apple receipts and directly adds Gold or subtracts Gold for Stars via `nk.wallet_update`. + - `purchase_item`: Buys cosmetic items from the shop catalog. Validates wallet funds and writes to `inventory` storage. +- **`gacha.lua`:** + - `perform_gacha_pull`: Reads banner drop rates, rolls RNG on the server, manages pity counters, and deducts the pull cost from the wallet. Prevents client-side RNG manipulation. +- **`inbox.lua`:** + - `get_mail` / `claim_mail_reward`: Server-authoritative mail system. Rewards attached to mail are granted directly to the wallet on claim. +- **`user.lua` & `admin.lua`:** + - `admin_topup_gold`: Admin-only RPC to grant 999,999 gold. + - `admin_ban_player`: Banning tool. + - Profile and friend sync logic. + +## Client / Server Wallet Synchronization + +[Back to top](#top) + + +There is **only one authoritative wallet** per user stored on the Nakama backend. + +1. Lua calls `nk.wallet_update(changeset)` upon any transaction. +2. The Godot client calls `UserProfileManager._reload_wallet()`. +3. Godot fetches the new JSON string from `account.wallet`. +4. `UserProfileManager` emits `profile_updated`. +5. All connected UI components (Lobby Top Bar, Shop Panel, Gacha Panel) instantly update their text labels to reflect the unified `gold` and `star` balances. + +## CI/CD and Hot-Patching Pipeline (`.gitea/workflows/`) + +[Back to top](#top) + + +The game features two distinct automated deployment pipelines. + +### Full Releases (`ci.yml`) + +[Back to top](#top) + +- **Trigger:** Pushing a git tag (e.g. `v3.0.0`). +- **Purpose:** Compiling heavy native binaries (Windows `.exe`, Linux binaries, macOS `.app`). +- **Flow:** + 1. Clones repository. + 2. Pulls cached Godot 4.7 binary and export templates from `/cache/` on the runner to skip the 1.3GB download. + 3. Runs `godot --headless --export-release` for each platform. + 4. Zips outputs and uploads to Gitea's release asset API. +- **Player Experience:** Must download and replace their entire game folder/executable. + +### Hot-Patching (`deploy_patch.yml`) + +[Back to top](#top) + +- **Trigger:** Manual `workflow_dispatch` button from the Gitea UI. +- **Purpose:** Pushing lightweight Godot asset changes (Scripts, Scenes, VFX, Sounds) instantly. +- **Flow:** + 1. Python script `generate_version_json.py` consumes `CHANGELOG_DRAFT.md` and bumps `version.json`. + 2. Runs `godot --headless --export-pack` to build a single, shared `patch.pck` file. + 3. Force-pushes `patch.pck` and `version.json` to the orphan `patches` git branch. + 4. A `gitea-pages` Docker container serves this branch publicly at `https://raw.klud.top`. +- **Player Experience:** + 1. Game boots to `boot_screen.tscn`. + 2. Fetches `https://raw.klud.top/danchie/tekton/version.json`. + 3. Downloads `patch.pck` if the version is newer. + 4. Mounts it into `user://` to override the base `res://` filesystem seamlessly. diff --git a/Skin-Creation-Workflow.-.md b/Skin-Creation-Workflow.-.md index f6bda97..ef54a79 100644 --- a/Skin-Creation-Workflow.-.md +++ b/Skin-Creation-Workflow.-.md @@ -1,60 +1,257 @@ # Skin Creation Workflow -How to author a new character skin and register it in the in-game shop. + -## 1. Create the Skin Material +How to author a new character skin, register it in the game's shop/gacha catalog, and ship it to players. -Use the in-editor tool to build a color-maskable 3D material for a new character skin. +--- -- Open the **Skin Shader Generator**: `res://scenes/tools/skin_shader_generator.tscn` -- Run the scene (F6). -- Import your base albedo and mask textures. -- Use the UI to visualize UV overlays and adjust color channels (Red, Green, Blue, Alpha masks). -- Export the configured material as a `.tres` file into `assets/materials/skins/`. +## Overview -## 2. Add the Skin to the Shop +Each skin is defined in two places that must stay in sync: -Update the game's catalog. The editor tool rewrites both the local script and the server-side module in one click. +| Layer | File | What it stores | +|---|---|---| +| **Client (visual)** | `scripts/managers/skin_manager.gd` | Mesh slots, material paths, override/overlay mode | +| **Server (shop)** | `server/nakama/lua/economy.lua` | Item ID, name, category, price (gold/star) | -- Open the **Skin Catalog Editor**: `res://scenes/tools/skin_catalog_editor.tscn` -- Press **F6** (or Right-click → Run Current Scene). -- Click **"+ New Skin"** and fill in: - - **ID** - - **Name** - - **Category** - - **Price** (Gold / Stars) - - The `.tres` material path exported in step 1. -- Click **"💾 Save & Generate"**. This rewrites: - - `res://scripts/managers/skin_manager.gd` (local catalog) - - `res://server/nakama/tekton_admin.js` (server-side shop logic) +The item `id` in `economy.lua` must match the dictionary key in `skin_manager.gd` `SKIN_CATALOG` exactly -- the Godot client looks up the item ID from the wallet/inventory and applies the matching skin data. -## Flow +[Back to top](#top) -```mermaid -flowchart TD - subgraph phase1 [Skin Material Creation] - A[Albedo & Mask Textures] --> B{Skin Shader Generator} - B -->|Export| C[material.tres] - end +--- - subgraph phase2 [Catalog Definition] - C --> D{Skin Catalog Editor} - D -->|Save & Generate| E[tekton_admin.js] - D -->|Save & Generate| F[skin_manager.gd] - end +## Step 1: Create the Skin Material - subgraph phase3 [Shop Backend] - E -->|SSH & nano| G[VPS: ~/tekton_admin.js] - G -->|docker cp| H[Nakama Container] - H -->|Restart| I[Live Shop Logic Sync] - end +Open the **Skin Shader Generator** at `res://scenes/tools/skin_shader_generator.tscn`. - subgraph phase4 [Asset Delivery] - C --> J[Git Push] - F --> J - J -->|CI/CD| K[patch.pck] - K -->|Auto Download| L[Player Client Assets] - end +1. Run the scene (F6). +2. Import your base albedo and mask textures (PNG with color/alpha channels). +3. Use the UI to visualize UV overlays and adjust color channels (Red, Green, Blue, Alpha). +4. Export the configured material as a `.tres` file into `assets/materials/skins/` or a subfolder: + - `assets/characters/skins/hat/` + - `assets/characters/skins/clothing/` + - `assets/characters/skins/gloves/` + +**Material path conventions (Oldpop character):** + +| Category | Example path | +|---|---| +| hat | `res://assets/characters/skins/hat/oldpop_mat_hat_blue.tres` | +| costume/clothing | `res://assets/characters/skins/clothing/oldpop_mat_cloth_red_pant.tres` | +| glove | `res://assets/characters/skins/gloves/oldpop_mat_gloves_blue.tres` | +| accessory | `res://assets/characters/skins/accessory/` | + +[Back to top](#top) + +--- + +## Step 2: Register the Skin in SkinManager (Client) + +Open `res://scripts/managers/skin_manager.gd` and add a new entry inside `SKIN_CATALOG` (between `[BEGIN_SKIN_CATALOG]` and `[END_SKIN_CATALOG]` markers). + +### Entry format + +```gdscript +"item_id": { + "category": "head", # head | costume | glove | accessory + "character": "Oldpop", # node name under CharacterRoot + "slots": [ + { + "mesh": "oldpop-hat1", # MeshInstance3D child name + "mode": "override", # "override" | "overlay" + "material": "res://path/to/material.tres" + }, + ] +} ``` -After step 2, follow the [Nakama Deployment](./Nakama-Deployment) page to sync the backend, then the [Patch Release Workflow](./Patch-Release-Workflow) page to ship the assets. +### Slot modes + +- **`override`** -- `set_surface_override_material(0, mat)`. Replaces the base material entirely. Preserves the outline shader (`next_pass`) automatically. +- **`overlay`** -- `material_overlay = mat`. Transparent layer on top of the base material. Good for costume/pant patterns. + +### Multi-slot skins (costume example) + +Costumes typically touch 3 meshes: + +```gdscript +"oldpop-grey-pant": { + "category": "costume", + "character": "Oldpop", + "slots": [ + { "mesh": "oldpop-body", "mode": "overlay", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" }, + { "mesh": "oldpop-bottom1", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" }, + { "mesh": "oldpop-bottom2", "mode": "override", "material": "res://assets/characters/skins/clothing/oldpop_mat_cloth_grey_pant.tres" }, + ] +}, +``` + +### Tips + +- Leave `"material"` as `""` if the `.tres` file is not ready yet. The slot is skipped gracefully. +- Use the **Skin Catalog Editor** (`res://scenes/tools/skin_catalog_editor.tscn`) to avoid manual edits. Click **Save & Generate** to rewrite both `skin_manager.gd` and `economy.lua`. + +[Back to top](#top) + +--- + +## Step 3: Register the Skin in Economy (Server) + +Open `server/nakama/lua/economy.lua` and add a new entry to `SHOP_CATALOG_DEFS`. + +### Catalog entry format + +```lua +{ id = "oldpop-blue-hat", name = "Oldpop Blue Hat", category = "head", gold = 100, star = 0, rarity = "Common", character = "Oldpop" }, +``` + +| Field | Type | Description | +|---|---|---| +| `id` | string | Must match the `SKIN_CATALOG` key in `skin_manager.gd` exactly | +| `name` | string | Display name shown in shop | +| `category` | string | `head` / `costume` / `glove` / `accessory` | +| `gold` | number | Gold coin price (0 = not sold for gold) | +| `star` | number | Star gem price (0 = not sold for stars) | +| `rarity` | string | `"Common"` / `"Uncommon"` / `"Rare"` -- cosmetic label only | +| `character` | string | Character this skin belongs to (e.g. `"Oldpop"`) | + +### Existing catalog (12 items) + +``` +oldpop-blue-hat head 100 gold Common Oldpop +oldpop-green-hat head 100 gold Common Oldpop +oldpop-red-hat head 100 gold Common Oldpop +oldpop-yellow-hat head 100 gold Common Oldpop +oldpop-og-pant costume 0 gold Common Oldpop (free) +oldpop-grey-pant costume 150 gold Common Oldpop +oldpop-red-pant costume 150 gold Common Oldpop +oldpop-yellow-pant costume 150 gold Common Oldpop +oldpop-blue-gloves glove 75 gold Common Oldpop +oldpop-green-gloves glove 75 gold Common Oldpop +oldpop-red-gloves glove 75 gold Common Oldpop +oldpop-yellow-gloves glove 75 gold Common Oldpop +``` + +[Back to top](#top) + +--- + +## Step 4 (Optional): Add Skin as Gacha Prize + +Gacha-only skins are registered in `server/nakama/lua/gacha.lua` inside `GACHA_DATA.real_prize_catalog`. + +### Existing gacha skins (4 items) + +```lua +skin_gacha_rainbow_suit = { name = "Rainbow Suit", category = "costume", rarity = "real_prize", character = "" } +skin_gacha_dragon_hat = { name = "Dragon Hat", category = "head", rarity = "real_prize", character = "" } +skin_gacha_phantom_gloves = { name = "Phantom Gloves", category = "glove", rarity = "real_prize", character = "" } +skin_gacha_neon_acc = { name = "Neon Accessory", category = "accessory", rarity = "real_prize", character = "" } +``` + +Gacha skins also need a `skin_manager.gd` entry (same step 2 format) and a `skin_catalog_editor` entry so `SkinManager.apply_loadout()` can render them. The server catalog is optional -- gacha skins are not sold in the shop directly. + +The gacha pulls these IDs from `GACHA_DATA.pools.real_prize`, so add your item_id there too. + +```lua +pools = { + common = {"frag_common"}, + uncommon = {"frag_uncommon"}, + rare = {"frag_rare"}, + real_prize = { + "skin_gacha_rainbow_suit", + "skin_gacha_dragon_hat", + "skin_gacha_phantom_gloves", + "skin_gacha_neon_acc", + -- add new skin here + } +}, +``` + +[Back to top](#top) + +--- + +## Step 5: Deploy + +### Hot patch (content only) -- recommended for skins + +1. Commit changes to `experimental` branch: + - `scripts/managers/skin_manager.gd` + - `server/nakama/lua/economy.lua` (if shop item) + - `server/nakama/lua/gacha.lua` (if gacha prize) + - Material `.tres` files + +2. Push to `experimental`. + +3. Trigger `deploy_patch.yml` via Gitea UI workflow dispatch. + - CI runs `--export-pack` to build `patch.pck`. + - CI force-pushes `patch.pck` + `version.json` to `patches` branch. + - Existing players auto-download on next boot via `GameUpdateManager`. + +### Full binary release (if engine/templates changed) + +Tag a version (e.g. `v2.5.0`) and push. CI builds all platform binaries and uploads to the release. + +[Back to top](#top) + +--- + +## Full Flow Diagram + +``` +┌──────────────────────┐ +│ 1. Create Material │ +│ skin_shader_generator │ +│ ────────────────── │ +│ Export .tres file │ +└────────┬─────────────┘ + v +┌──────────────────────────────┐ +│ 2. Register in SkinManager │ +│ skin_manager.gd │ +│ ────────────────── │ +│ Add SKIN_CATALOG entry │ +│ (mesh slots + material) │ +└────────┬─────────────────────┘ + v +┌──────────────────────────────┐ +│ 3. Register in Economy │ +│ economy.lua │ +│ ────────────────── │ +│ Add SHOP_CATALOG_DEFS │ +│ (price, name, category) │ +└────────┬─────────────────────┘ + v (optional) +┌──────────────────────────────┐ +│ 4. Gacha Prize │ +│ gacha.lua │ +│ ────────────────── │ +│ real_prize_catalog + pools │ +└────────┬─────────────────────┘ + v +┌──────────────────────┐ +│ 5. Git Push & CI │ +│ deploy_patch.yml │ +│ ────────────────── │ +│ patch.pck → players │ +└──────────────────────┘ +``` + +[Back to top](#top) + +--- + +## Troubleshooting + +| Symptom | Cause | Fix | +|---|---|---| +| Skin visible in editor but not in-game | Material path wrong or `.tres` not exported | Verify `res://` path in SKIN_CATALOG, run `--export-pack` | +| Skin purchase fails: "NotEnoughFunds" | Wallet balance insufficient | Check gold/star prices in economy.lua | +| Skin visible on all characters | `character` field wrong | Set correct character node name | +| Skin purchase fails: "ItemNotFound" | Item ID not in SHOP_CATALOG_DEFS | Add entry matching SKIN_CATALOG key | +| Player downloads patch but skin missing | econmy.lua change didn't reach server | Nakama hot-reload: restart Nakama container or wait for next restart | +| Outline shader lost on skin | next_pass not preserved | SkinManager preserves it automatically -- verify with latest `skin_manager.gd` | + +[Back to top](#top)