cyberia 3.2.12 → 3.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.github/workflows/engine-cyberia.cd.yml +1 -0
  2. package/.github/workflows/engine-cyberia.ci.yml +14 -2
  3. package/.github/workflows/ghpkg.ci.yml +1 -0
  4. package/.github/workflows/npmpkg.ci.yml +9 -5
  5. package/CHANGELOG.md +151 -1
  6. package/CLI-HELP.md +975 -1130
  7. package/bin/build.js +97 -136
  8. package/bin/build.template.js +25 -179
  9. package/bin/cyberia.js +11 -6
  10. package/bin/deploy.js +4 -1
  11. package/bin/index.js +11 -6
  12. package/conf.js +1 -0
  13. package/deployment.yaml +74 -2
  14. package/hardhat/package-lock.json +4 -4
  15. package/hardhat/package.json +1 -1
  16. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
  17. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  18. package/manifests/deployment/dd-cyberia-development/deployment.yaml +74 -2
  19. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  20. package/package.json +7 -7
  21. package/scripts/link-local-underpost-cli.sh +6 -0
  22. package/scripts/test-monitor.sh +250 -0
  23. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +7 -0
  24. package/src/cli/deploy.js +200 -282
  25. package/src/cli/env.js +1 -4
  26. package/src/cli/image.js +58 -4
  27. package/src/cli/index.js +47 -0
  28. package/src/cli/monitor.js +387 -6
  29. package/src/cli/release.js +26 -11
  30. package/src/cli/repository.js +101 -7
  31. package/src/cli/run.js +159 -73
  32. package/src/client/components/core/PanelForm.js +44 -44
  33. package/src/client/components/cyberia/SharedDefaultsCyberia.js +1 -1
  34. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +55 -1
  35. package/src/client/public/cyberia-docs/ARCHITECTURE.md +272 -50
  36. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +20 -11
  37. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +23 -1
  38. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  39. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  40. package/src/db/mongo/MongooseDB.js +2 -1
  41. package/src/index.js +1 -1
  42. package/src/runtime/cyberia-client/Dockerfile +4 -22
  43. package/src/runtime/cyberia-client/Dockerfile.dev +3 -18
  44. package/src/runtime/cyberia-server/Dockerfile +3 -23
  45. package/src/runtime/cyberia-server/Dockerfile.dev +3 -27
  46. package/src/runtime/wp/Dockerfile +3 -3
  47. package/src/server/catalog-underpost.js +61 -0
  48. package/src/server/catalog.js +77 -0
  49. package/src/server/conf.js +414 -56
  50. package/src/server/ipfs-client.js +5 -3
  51. package/src/server/runtime-status.js +235 -0
  52. package/src/server/start.js +32 -11
  53. package/test/deploy-monitor.test.js +251 -0
  54. package/manifests/deployment/dd-test-development/deployment.yaml +0 -256
  55. package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
@@ -1,78 +1,118 @@
1
- # Cyberia Architecture
1
+ # Cyberia Architecture
2
2
 
3
- Cyberia is the MMO extension that runs on top of Underpost Platform. Keep the model simple:
3
+ Cyberia is the real-time MMO extension that runs on Underpost Platform. This document describes the three Cyberia processes, their boundaries, the data flow between them, and the canonical model for tick, snapshot, prediction, reconciliation, interpolation, and replication.
4
4
 
5
- - Underpost Platform provides the toolchain, deployment surface, PWA delivery, and base infrastructure.
6
- - `engine-cyberia` is the content authority.
7
- - `cyberia-server` is the authoritative simulation.
8
- - `cyberia-client` is the presentation runtime.
5
+ Underpost Platform provides the toolchain, deployment surface, PWA delivery, and base infrastructure. The three Cyberia processes operate on top of it.
9
6
 
10
7
  ---
11
8
 
12
- ## System map
9
+ ## Process model
13
10
 
14
- ```text
15
- Underpost Platform
16
- -> toolchain, deploy, PWA build, static delivery, monitoring
11
+ ```
12
+ ┌─────────────────────────────────────────────────────────────────────────┐
13
+ UNDERPOST PLATFORM (infra · toolchain · deploy · PWA/Workbox) │
14
+ │ │
15
+ │ ┌─────────────────────┐ │
16
+ │ │ Persistent backend │ ← Cyberia content authority + asset backend │
17
+ │ │ ────────────────── │ │
18
+ │ │ engine-cyberia │ Node.js │
19
+ │ │ MongoDB │ │
20
+ │ │ IPFS / Cloudinary │ │
21
+ │ │ ObjectLayerToken │ Hyperledger Besu (off-line dependency) │
22
+ │ └─────────┬───────────┘ │
23
+ │ │ gRPC (world load, hot reload) │
24
+ │ ▼ │
25
+ │ ┌─────────────────────┐ │
26
+ │ │ Authoritative │ ← Cyberia simulation authority │
27
+ │ │ simulation runtime │ │
28
+ │ │ ────────────────── │ │
29
+ │ │ cyberia-server │ Go │
30
+ │ └─────────┬───────────┘ │
31
+ │ │ WebSocket (binary AOI snapshots, typed input commands) │
32
+ │ ▼ │
33
+ │ ┌─────────────────────┐ │
34
+ │ │ Presentation │ ← Cyberia render + prediction client │
35
+ │ │ runtime │ │
36
+ │ │ ────────────────── │ │
37
+ │ │ cyberia-client │ C / WebAssembly (Raylib · Emscripten) │
38
+ │ └─────────────────────┘ │
39
+ │ │ │
40
+ │ │ REST (atlas frames, asset metadata, optional client hints) │
41
+ │ └──→ engine-cyberia │
42
+ └─────────────────────────────────────────────────────────────────────────┘
43
+ ```
17
44
 
18
- engine-cyberia (Node.js)
19
- -> content, validation, persistence, gRPC/REST data services, asset metadata
20
- -> feeds cyberia-server and cyberia-client
45
+ Three processes, strict role separation. The ecosystem is fully operational only when all three are running and healthy at the same time.
21
46
 
22
- cyberia-server (Go)
23
- -> authoritative simulation and tick processing
24
- -> feeds cyberia-client over WebSocket
47
+ ---
25
48
 
26
- cyberia-client (C/WASM)
27
- -> rendering, input, prediction, presentation
28
- ```
49
+ ## Role definitions
29
50
 
30
- ---
51
+ ### engine-cyberia (Node.js) — content authority
31
52
 
32
- ## Responsibility split
53
+ The content-authoring backend and persistence layer for Cyberia. Owns persisted data and exposes it through two transports: gRPC (consumed by `cyberia-server` at boot and during hot reload) and REST (consumed by `cyberia-client` for asset distribution and optional presentation overrides).
33
54
 
34
- | Service | Owns | Must not own |
35
- | ---------------- | ------------------------------------------------------------------------- | --------------------------------------------- |
36
- | `engine-cyberia` | content, validation, persistence, gRPC/REST data services, asset metadata | authoritative simulation, render policy |
37
- | `cyberia-server` | authoritative simulation, world tick, gameplay mutation, AOI replication | content authority, presentation metadata |
38
- | `cyberia-client` | rendering, input, prediction, interpolation, presentation | authoritative world state, gameplay authority |
55
+ What it owns:
39
56
 
40
- Two boundaries are non-negotiable:
57
+ - Content generation, validation, and persistence.
58
+ - Maps, portals, object layers, atlas/sprite-sheet metadata.
59
+ - World configuration: AOI radius, economy rules, skill rules, equipment rules, entity gameplay defaults.
60
+ - Persisted character/quest/dialogue/action data.
61
+ - gRPC `CyberiaDataService` for world load and content streaming.
62
+ - REST APIs for assets and the optional client-hints overrides.
63
+ - Static content distribution + Cloudinary-backed asset flow.
64
+ - Editor and CLI integration for content workflows.
41
65
 
42
- - Do not move authoritative logic into the client.
43
- - Do not move content-authority logic into the Go runtime.
66
+ What it does NOT own:
44
67
 
45
- ---
68
+ - Real-time simulation. It is not a gameplay runtime.
69
+ - Per-tick state advancement.
70
+ - Client presentation policy (palette, camera, dev overlay, icon visuals).
71
+ - World mutation during gameplay.
46
72
 
47
- ## Data flow
73
+ ### cyberia-server (Go) — authoritative simulation runtime
48
74
 
49
- ```text
50
- engine-cyberia --gRPC--> cyberia-server --WebSocket--> cyberia-client
51
- engine-cyberia --REST-------------------------------> cyberia-client
52
- ```
75
+ The tick-based authoritative simulation. Owns world state and the gameplay rules that mutate it.
53
76
 
54
- - `engine-cyberia` publishes world content, validation rules, persistence-backed data, and asset metadata.
55
- - `cyberia-server` loads authoritative world data, advances the simulation tick, and emits per-player AOI snapshots.
56
- - `cyberia-client` sends typed input commands upstream and renders the result locally with prediction and interpolation.
77
+ What it owns:
57
78
 
58
- There is one source of truth per concern:
79
+ - Authoritative world state.
80
+ - The tick: a `uint32` advanced once per simulation step at a fixed `tickRate`.
81
+ - Simulation phases — the only allowed mutators of world state.
82
+ - AOI replication: per-player interest filtering and snapshot emission.
83
+ - Input command processing: typed input commands drained from per-player queues each tick.
84
+ - Snapshot generation and delivery via WebSocket.
59
85
 
60
- - Content and world configuration: `engine-cyberia`
61
- - Real-time authoritative state: `cyberia-server`
62
- - Presentation and local interaction: `cyberia-client`
86
+ What it does NOT own:
63
87
 
64
- ---
88
+ - Persistence (loaded once at boot from engine-cyberia).
89
+ - Client presentation. The server holds no palette, no camera knobs, no dev-overlay flag, no status-icon visuals.
90
+
91
+ ### cyberia-client (C / WebAssembly) — presentation runtime
92
+
93
+ The render and interactive runtime. Compiled to WASM via Emscripten and served as a Progressive Web App through the Underpost Platform delivery pipeline.
65
94
 
66
- ## Operational guardrails
95
+ What it owns:
67
96
 
68
- - Prefer one source of truth for config, deploy IDs, runtime selection, startup behavior, and generated assets.
69
- - Reuse existing helpers and conventions instead of creating parallel implementations.
70
- - Do not duplicate parsing, env resolution, or path normalization logic across modules.
71
- - Treat generated artifacts as outputs only; never hand-edit them.
97
+ - Rendering and UI.
98
+ - Input capture: raw OS events typed input commands with monotonic sequence numbers.
99
+ - Prediction of the local player.
100
+ - Reconciliation against authoritative snapshots.
101
+ - Interpolation of remote entities.
102
+ - Presentation defaults (palette, status-icon visuals, camera knobs, interpolation window, dev-overlay flag) — loaded at startup from the client-hints REST endpoint.
103
+ - Optional client-hints fetch for per-instance presentation overrides.
104
+
105
+ What it does NOT own:
106
+
107
+ - World simulation.
108
+ - Economy outcomes, combat resolution, skill dispatch decisions.
109
+ - Any state another client depends on for correctness.
72
110
 
73
111
  ---
74
112
 
75
- ## Health states
113
+ ## Runtime operating model
114
+
115
+ The three processes are supervised independently. Each service owns its own monitor and reconnector. The game is playable only when all three are healthy at the same time.
76
116
 
77
117
  | State | Meaning |
78
118
  | ---------- | -------------------------------------------------------------------- |
@@ -80,4 +120,186 @@ There is one source of truth per concern:
80
120
  | `degraded` | at least one service is reconnecting or unavailable |
81
121
  | `standby` | gameplay is paused because the full three-service set is not healthy |
82
122
 
83
- This is the model to document, operate, and monitor against.
123
+ Dependency between services is handled by supervision and reconnect loops:
124
+
125
+ - `cyberia-server` dials `engine-cyberia` gRPC at boot and exits on dial failure rather than fabricate a world. On reconnect, it reloads world configuration.
126
+ - `cyberia-client` reconnects to `cyberia-server` over WebSocket and re-fetches content from `engine-cyberia` over REST independently.
127
+ - If any one of the three services goes unhealthy, the game moves to standby until all three recover.
128
+
129
+ Underpost Platform deploy orchestration ensures the backend layer is ready before the simulation layer is started, and the simulation layer is ready before the presentation layer connects. This ordering is an infrastructure concern, not a documentation model: the processes themselves are supervised and reconnect without requiring a manual restart chain.
130
+
131
+ ---
132
+
133
+ ## Tick model
134
+
135
+ The tick is the universal coordinate of the simulation. Every server→client snapshot and every client→server input command carries a tick value.
136
+
137
+ | Concept | Value | Notes |
138
+ | ------------------------ | ------------------------------------- | ------------------------------------------------------------------------------------------------------- |
139
+ | **tick** | `uint32` | Monotonic simulation step counter on `cyberia-server`. Resets only on world rebuild. |
140
+ | **tick rate** | Hz (default `30`) | Simulation frequency. Authoritative; comes from world configuration. The string "fps" is never used to describe the server. |
141
+ | **snapshot rate** | Hz (default `20`) | AOI replication frequency. Decoupled from tick rate so bandwidth scales independently of simulation fidelity. |
142
+ | **tick duration** | `1 / tick_rate` | The dt used by every simulation phase. |
143
+ | **client tick estimate** | derived | Client estimate of the server's current tick, used to stamp outgoing input commands. |
144
+ | **render tick** | `server_tick_estimate − INTERP_TICKS` | The tick the interpolation module samples remote entities at. |
145
+
146
+ Three clocks, one tick number: simulation tick (server), snapshot tick (server replication), render frame (client). The tick number is the only synchronization point.
147
+
148
+ ---
149
+
150
+ ## Simulation phases
151
+
152
+ Inside one simulation tick, `cyberia-server` runs the following phases in fixed order. These are the only functions that mutate authoritative world state:
153
+
154
+ 1. `phaseInput` — drain each player's `InputQueue`; dispatch typed input commands to gameplay handlers.
155
+ 2. `phaseLifecycle` — respawn timers, despawn expirations.
156
+ 3. `phaseSkills` — skill projectile collisions.
157
+ 4. `phaseAI` — bot behaviour decisions.
158
+ 5. `phaseMovement` — integrate positions using `tickDuration`.
159
+ 6. `phasePortals` — portal entry and teleport.
160
+
161
+ A separate ticker runs replication independently of the simulation:
162
+
163
+ - `phaseReplication` — per player: compute AOI, encode snapshot, dispatch. Runs at `snapshotRate`.
164
+
165
+ Phases never read presentation data. They consume world configuration loaded at boot (gameplay rules) and the input queue.
166
+
167
+ ---
168
+
169
+ ## Client render frame
170
+
171
+ The render frame runs at vsync. Inside one render frame, `cyberia-client` performs:
172
+
173
+ 1. Poll any pending optional client-hints fetch.
174
+ 2. Capture raw input → build typed input command (`kind`, `clientTick`, `sequence`, payload) → apply to prediction → send on the wire.
175
+ 3. Reconcile against the latest snapshot: drop input commands ≤ `lastAckedSequence`, rewind self to authoritative position, replay unacked commands.
176
+ 4. Fixed-timestep simulation: while accumulator ≥ `tickDuration`, advance prediction one tick.
177
+ 5. Interpolation: compute remote-entity view positions at `renderTick`.
178
+ 6. Render. Read view models; never mutate world state.
179
+
180
+ Render frame rate is independent of simulation tick rate. The fixed-timestep accumulator ensures the predicted simulation advances at the authoritative `tickRate` regardless of FPS.
181
+
182
+ ---
183
+
184
+ ## Wire protocol — AOI snapshot header
185
+
186
+ Snapshots travel as binary WebSocket frames. The header carries the simulation tick and the per-player acknowledged input sequence.
187
+
188
+ ```
189
+ Header (binary, little-endian, 11 bytes for AOI snapshots):
190
+ [0] u8 msgType 0x01 = aoi_update, 0x03 = full_aoi
191
+ [1..4] u32 tick simulation tick at which the snapshot was produced
192
+ [5..8] u32 lastAcked highest InputCommand.Sequence applied for this player
193
+ [9..10] u16 entityCount entity blocks that follow
194
+ ```
195
+
196
+ Other message types (init data, FCT) use their own headers and are not part of the per-tick replication stream.
197
+
198
+ ---
199
+
200
+ ## Input command pipeline
201
+
202
+ Client input flows through a typed pipeline. There is no JSON intermediate on the binary path. The simulation tick is the only consumer.
203
+
204
+ ```
205
+ WS frame (binary) → decode → typed InputCommand{kind, clientTick, sequence, payload}
206
+
207
+ dispatchInputCommand
208
+
209
+ PlayerState.InputQueue (per-player, bounded)
210
+
211
+ phaseInput (under world mutex, once per simulation tick)
212
+
213
+ phase_input_handlers.go — typed dispatch per InputKind
214
+
215
+ authoritative world state
216
+ ```
217
+
218
+ `InputCommand.Sequence` is monotonic per client. The server tracks the highest applied sequence per player; `phaseReplication` writes it into every snapshot header. The client drops acknowledged input commands from its prediction replay buffer using this value.
219
+
220
+ ---
221
+
222
+ ## Presentation metadata ownership
223
+
224
+ Presentation is client-owned. The authoritative server holds no presentation state.
225
+
226
+ | Concern | Owner | Mechanism |
227
+ | ------------------------------------------------ | --------------------- | ------------------------------------------------------------------------------- |
228
+ | Palette (named ColorRGBA entries) | engine-cyberia (REST) | served by `GET /api/cyberia-client-hints/:CYBERIA_CLIENT_HINTS_CODE`. Source schema: `SharedDefaultsCyberia.js`. |
229
+ | Status-icon visuals (icon stems + border colors) | engine-cyberia (REST) | same |
230
+ | Per-entity-type fallback color keys | engine-cyberia (REST) | same |
231
+ | Camera defaults (smoothing, zoom) | engine-cyberia (REST) | same |
232
+ | Cell-pixel size, default object dims | engine-cyberia (REST) | same |
233
+ | Interpolation window | engine-cyberia (REST) | same |
234
+ | Dev-overlay flag | engine-cyberia (REST) | same |
235
+ | World configuration (gameplay rules) | engine-cyberia (gRPC) | `CyberiaInstanceConf` — no presentation; only simulation |
236
+
237
+ The cyberia-client carries **no** compile-time palette. `domain/presentation_runtime.{c,h}` fetches the full presentation surface on startup; until the fetch settles the runtime returns a tiny inline neutral-grey bootstrap so the splash screen has something to draw. The simulation is unaffected by the fetch outcome.
238
+
239
+ `cyberia-server` never reads any presentation field. The only "representational" data on the simulation wire is the **active item IDs** carried inside each AOI snapshot. Everything else visual is the client's job, fed by the hints REST endpoint.
240
+
241
+ ---
242
+
243
+ ## Canonical vocabulary
244
+
245
+ Every Cyberia document uses the same terms. Aliases are not permitted.
246
+
247
+ | Term | Definition |
248
+ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
249
+ | **tick** | Monotonic simulation step counter. |
250
+ | **tick rate** | Simulation Hz on `cyberia-server`. |
251
+ | **snapshot** | AOI-filtered world view at one tick for one player. |
252
+ | **prediction** | Optimistic local apply of input commands to the predicted self entity. |
253
+ | **reconciliation** | Drop acknowledged inputs, rewind self to authoritative position, replay unacked inputs. |
254
+ | **display smoothing** | Per-render-frame exponential lerp from the discrete predicted self position to a continuous on-screen position. Decouples the visible main player from sim-tick boundaries. |
255
+ | **interpolation** | Render-time smoothing of remote entities, sampled from snapshot history. |
256
+ | **authoritative server** | `cyberia-server`. Sole authority on world state. |
257
+ | **content authority** | `engine-cyberia`. Sole authority on persisted content and world configuration. |
258
+ | **client hints** | Optional presentation overrides served by engine-cyberia. |
259
+ | **world configuration** | Gameplay parameters loaded at server boot from engine-cyberia. |
260
+ | **presentation metadata** | Render-only data. Client-owned. |
261
+ | **input command** | Typed client→server frame with kind, clientTick, sequence, payload. |
262
+ | **AOI** | Area of interest — the spatial filter that defines which entities a given player receives. |
263
+ | **replication** | Production and delivery of snapshots from server to clients. |
264
+ | **simulation phase** | A named step inside one simulation tick. |
265
+ | **healthy** | All three Cyberia services up and connected; game is playable. |
266
+ | **standby** | Game paused because at least one of the three services is not healthy. |
267
+
268
+ Forbidden usages:
269
+
270
+ - "fps" on `cyberia-server` (use **tick rate**).
271
+ - "frame-based" simulation language on the server.
272
+ - "game_state" as a god object on the client.
273
+ - Render metadata in `cyberia-server` state.
274
+ - "engine" without qualifier when the project name is intended. Use **engine-cyberia** for the Cyberia content backend; use **Underpost Platform** for the umbrella product.
275
+
276
+ ---
277
+
278
+ ## Instance topology
279
+
280
+ A `CyberiaInstance` (persisted in MongoDB, served by engine-cyberia) is a directed graph:
281
+
282
+ - **Vertices** — `CyberiaMap` documents (grid-based maps).
283
+ - **Edges** — `PortalEdge` records connecting source cell → target map/cell.
284
+
285
+ Portal modes:
286
+
287
+ | Mode | Behaviour |
288
+ | -------------- | ----------------------------------------------- |
289
+ | `inter-portal` | Teleport to a specific cell on a target map |
290
+ | `inter-random` | Teleport to a random valid cell on a target map |
291
+ | `intra-portal` | Teleport within the same map to a specific cell |
292
+ | `intra-random` | Teleport within the same map to a random cell |
293
+
294
+ Topology modes: `linear`, `hub-spoke`, `open`, `grid`.
295
+
296
+ ---
297
+
298
+ ## Entity types
299
+
300
+ | Type | Behavior | Description |
301
+ | -------------- | --------------------- | --------------------------- |
302
+ | `player` | interactive | Local player (self) |
303
+ | `other_player` | interactive | Remote players inside AOI |
304
+ | `bot` | `hostile` / `passive` | AI-controlled entities |
305
+ | `skill` | `skill` | Runtime-spawned projectile |
@@ -12,7 +12,7 @@
12
12
 
13
13
  `cyberia-server` is the authoritative simulation runtime for the Cyberia MMO extension on Underpost Platform. It owns world state, advances a fixed-rate tick, drains typed input commands from connected clients, and dispatches AOI-filtered snapshots on a separately-paced replication tick.
14
14
 
15
- It is **not** the content authority. World content is loaded from `engine-cyberia` over gRPC. It is **not** the render-policy authority. Presentation is owned by `cyberia-client`.
15
+ It is **not** the content authority. World content is loaded once at boot from `engine-cyberia` over gRPC. It is **not** the render-policy authority. Presentation is owned by `cyberia-client`.
16
16
 
17
17
  ---
18
18
 
@@ -20,23 +20,32 @@ It is **not** the content authority. World content is loaded from `engine-cyberi
20
20
 
21
21
  Three independent processes, non-overlapping roles. The ecosystem is playable only when all three are running and healthy at the same time.
22
22
 
23
- ```text
24
- engine-cyberia (Node.js) cyberia-server (Go) cyberia-client (C/WASM)
25
- content authority authoritative simulation presentation runtime
26
- gRPC + REST tick + AOI + snapshots render + prediction
27
-
28
- └── gRPC GetFullInstance ──► └── WebSocket binary ──►
29
- world config snapshots -> / input <-
23
+ ```
24
+ engine-cyberia (Node.js) cyberia-server (Go) cyberia-client (C/WASM)
25
+ ───────────────────────── ────────────────── ──────────────────────
26
+ content authority authoritative simulation presentation runtime
27
+ persisted maps + rules tick + AOI + snapshots render + prediction
28
+
29
+ │ gRPC GetFullInstance │ WebSocket binary
30
+ │────────────────────────────────────► │ AOI snapshots + init
31
+ │ (world configuration: │ ▲
32
+ │ AOI radius, economy, │ │ typed input commands
33
+ │ skill, equipment, │ │
34
+ │ entity gameplay defaults) │ │
35
+ │ │ │
36
+ ▼ ▼ ▼
37
+ (boot + hot reload) tick loop + replication
30
38
  ```
31
39
 
32
40
  - Each service is supervised independently and owns its own monitor and reconnector.
33
- - `cyberia-server` loads world configuration from `engine-cyberia` and does not fabricate a world.
41
+ - `cyberia-server` dials `engine-cyberia` gRPC at boot and exits on dial failure rather than fabricate a world.
42
+ - On reconnect, world configuration is reloaded via `GetFullInstance(instanceCode)`.
34
43
  - If any one of the three services is unhealthy, the game moves to standby until all three recover.
35
44
 
36
45
  The server speaks two protocols:
37
46
 
38
- - **gRPC inbound** to consume world configuration from `engine-cyberia`
39
- - **WebSocket binary** to deliver snapshots and accept typed input commands
47
+ - **gRPC, inbound, at boot and hot reload:** consumes world configuration from `engine-cyberia`.
48
+ - **WebSocket binary, ongoing:** delivers AOI snapshots to clients, accepts typed input commands.
40
49
 
41
50
  There is no per-tick traffic between `cyberia-server` and `engine-cyberia`, and no presentation authority in the Go runtime.
42
51
 
@@ -10,7 +10,7 @@ The Quest System is a **chain/tree-structured progression framework** linking NP
10
10
 
11
11
  Quests are defined server-side as MongoDB documents and delivered to the client through the Engine REST API. Progress is tracked per-player in `CyberiaQuestProgress` documents.
12
12
 
13
- > **Implementation status — Pre-alpha:** The Quest and QuestProgress MongoDB schemas and Engine REST API (`src/api/cyberia-quest`, `src/api/cyberia-quest-progress`) are defined and seeded. Go server integration (quest tracking, objective evaluation, reward delivery via FCT) is planned for the **Alpha milestone**. For pre-alpha, quest progress is ephemeral: it lives in the client session only and resets on page reload.
13
+ > **Implementation status — Alpha (talk objectives):** The Quest and QuestProgress MongoDB schemas and Engine REST API (`src/api/cyberia-quest`, `src/api/cyberia-quest-progress`) are defined and seeded. The Go server fetches quest definitions at instance init and now evaluates `talk` objectives, grants quests, advances steps, and delivers rewards via FCT on completion (driven by `dlg_complete` — see ACTION-SYSTEM.md). `collect` and `kill` objective evaluation remains planned for a later Alpha increment. Quest progress is authoritative **per Go session** (in-memory) and best-effort mirrored to `POST /api/cyberia-quest-progress`; it resets on reconnect. The C client surfaces it through the **Quest Journal** (see below).
14
14
 
15
15
  ---
16
16
 
@@ -168,6 +168,28 @@ On quest completion, the Engine grants each `rewards[].{itemId, quantity}` to th
168
168
 
169
169
  ---
170
170
 
171
+ ## Quest Journal (client)
172
+
173
+ The C client keeps a local `quest_store` (in `cyberia-client/src/ui/quest_store.c`)
174
+ populated from two server sources — **no extra REST calls**:
175
+
176
+ - `init_data.quests[]` — the player's active/completed snapshot on connect.
177
+ - `dlg_ack.quests[]` — live upserts as quests are granted or completed.
178
+
179
+ The **Quest Journal** modal (`ui/quest_journal.c`) renders this store on the
180
+ right side below the map info modal: a three-section tree (Active / Completed /
181
+ Failed), each section independently collapsible via the shared `ui_toggle`
182
+ component, each with its own 10-per-page pagination cursor. The interaction
183
+ bubble column on the left is collapsible by the same toggle pattern. Both panels
184
+ default collapsed on screens narrower than 600 px. Collapse state is not
185
+ persisted across sessions.
186
+
187
+ Each server quest snapshot entry carries `{ code, title, description, status,
188
+ activeStep, objectivesText }` so the journal can render rows and inline detail
189
+ without re-fetching the quest definition.
190
+
191
+ ---
192
+
171
193
  ## Indexes
172
194
 
173
195
  ```javascript
@@ -1,6 +1,6 @@
1
1
  # Cyberia Online — Development Roadmap
2
2
 
3
- **Current version:** 3.2.12 | **Target milestone:** Open Alpha
3
+ **Current version:** 3.2.22 | **Target milestone:** Open Alpha
4
4
 
5
5
  ---
6
6
 
@@ -18,7 +18,7 @@ _Stackable Rendering Layers as a Unified Tokenized Reality_
18
18
 
19
19
  ---
20
20
 
21
- **Version:** 3.2.12 | **Status:** Draft | **Authors:** Underpost Engineering
21
+ **Version:** 3.2.22 | **Status:** Draft | **Authors:** Underpost Engineering
22
22
 
23
23
  ---
24
24
 
@@ -86,7 +86,8 @@ class MongooseDBService {
86
86
 
87
87
  const user = config.user || process.env.DB_USER || '';
88
88
  const password = config.password || process.env.DB_PASSWORD || '';
89
- const directConnection = hosts.length === 1;
89
+ const hasExplicitReplicaSet = !!(config.replicaSet || process.env.DB_REPLICA_SET);
90
+ const directConnection = hosts.length === 1 && !hasExplicitReplicaSet;
90
91
  const replicaSet = directConnection
91
92
  ? ''
92
93
  : config.replicaSet || process.env.DB_REPLICA_SET || MONGODB_DEFAULT_REPLICA_SET;
package/src/index.js CHANGED
@@ -44,7 +44,7 @@ class Underpost {
44
44
  * @type {String}
45
45
  * @memberof Underpost
46
46
  */
47
- static version = 'v3.2.12';
47
+ static version = 'v3.2.22';
48
48
 
49
49
  /**
50
50
  * Required Node.js major version
@@ -1,9 +1,9 @@
1
1
  # BUILD_MODE: RELEASE | DEBUG
2
2
  ARG BUILD_MODE=RELEASE
3
3
 
4
- # --- Build Image
4
+ # --- Build Image ---
5
5
  FROM rockylinux/rockylinux:9 AS builder
6
- # Re-declare ARG after FROM so it is in scope for RUN
6
+
7
7
  ARG BUILD_MODE=RELEASE
8
8
 
9
9
  RUN dnf -y update && \
@@ -44,7 +44,6 @@ RUN dnf groupinstall -y "Development Tools" && \
44
44
  ENV EMSDK=/opt/emsdk
45
45
  ENV PATH="${EMSDK}:${EMSDK}/upstream/emscripten:${PATH}"
46
46
 
47
- # Pin emsdk version for reproducible builds
48
47
  ARG EMSDK_VERSION=5.0.6
49
48
  WORKDIR /opt
50
49
  RUN git clone https://github.com/emscripten-core/emsdk.git ${EMSDK}
@@ -53,28 +52,14 @@ RUN ./emsdk install ${EMSDK_VERSION} && \
53
52
  ./emsdk activate ${EMSDK_VERSION}
54
53
 
55
54
  WORKDIR /cyberia-client
56
- # Build context is the cyberia-client project repo root (the workflow
57
- # in .github/workflows/docker-image.cyberia-client.ci.yml sets
58
- # context: . from the cyberia-client checkout). The legacy
59
- # engine-context layout (COPY cyberia-client/ .) is no longer used.
55
+
60
56
  COPY . .
61
57
 
62
- # `make clean` first so stale bin/ or build/ artefacts copied in from a
63
- # developer's local checkout (or a previous Docker layer cache hit)
64
- # can't shadow a fresh BUILD_MODE rebuild — e.g. mixing a DEBUG-mode
65
- # index.wasm with a RELEASE-mode index.js once produced the
66
- # "corrupted heap memory area" panic that masked the real Closure bug.
67
58
  RUN make -f Web.mk clean && make -f Web.mk all BUILD_MODE=${BUILD_MODE} OUTPUT_DIR=bin/
68
59
 
69
- # --- Runtime Image
60
+ # --- Runtime Image ---
70
61
  FROM rockylinux/rockylinux:9 AS runtime
71
62
 
72
- # Runtime needs:
73
- # - python3 (serves the built /bin/ static files via server.py)
74
- # - nodejs + the underpost CLI globally, for the container-status
75
- # lifecycle hooks invoked from conf.instances.json before / after
76
- # launching server.py. Installing it at build time avoids the slow
77
- # `npm install -g` startup the K8S cmd would otherwise repeat.
78
63
  ARG UNDERPOST_VERSION=3.2.9
79
64
  RUN dnf -y update && \
80
65
  dnf -y install epel-release && \
@@ -95,7 +80,4 @@ ENV CYBERIA_MODE=production
95
80
 
96
81
  EXPOSE 8081 8082
97
82
 
98
- # Default CMD when the image is run directly (not via K8S cmd).
99
- # In K8S deploys conf.instances.json supplies its own cmd that wraps
100
- # container-status hooks + this same server.py invocation.
101
83
  CMD ["sh", "-c", "exec python3 server.py ${CYBERIA_PORT} bin ${CYBERIA_MODE}"]
@@ -1,22 +1,8 @@
1
1
  # cyberia-client DEV runtime image.
2
- #
3
- # Differences vs the production Dockerfile in this same directory:
4
- # - Builds the C/WASM bundle with BUILD_MODE=DEBUG (raylib + emcc keep
5
- # symbols, asserts, and DWARF info; the bundle is larger but
6
- # debuggable in the browser devtools).
7
- # - Default CYBERIA_MODE is `development` instead of `production`.
8
- # - Default CYBERIA_PORT is `8082` (debug port) instead of `8081`.
9
- # - Keeps `vim-minimal`, `lsof`, `strace`, `procps-ng` in the runtime
10
- # image so the operator can attach and inspect a misbehaving pod.
11
- # - Does NOT clean the npm cache.
12
- #
13
- # Selected automatically by `node bin run instance-build-manifest`
14
- # whenever the `--dev` flag is set; the production Dockerfile in the
15
- # same directory is used otherwise.
16
2
 
17
3
  ARG BUILD_MODE=DEBUG
18
4
 
19
- # --- Build Image
5
+ # --- Build Image ---
20
6
  FROM rockylinux/rockylinux:9 AS builder
21
7
  ARG BUILD_MODE=DEBUG
22
8
 
@@ -48,14 +34,13 @@ RUN ./emsdk install ${EMSDK_VERSION} && \
48
34
  ./emsdk activate ${EMSDK_VERSION}
49
35
 
50
36
  WORKDIR /cyberia-client
51
- # Build context is the cyberia-client project repo root (see the
52
- # production Dockerfile in this directory for the rationale).
37
+
53
38
  COPY . .
54
39
 
55
40
  # Dev build: BUILD_MODE=DEBUG keeps symbols, asserts, source maps.
56
41
  RUN make -f Web.mk all BUILD_MODE=${BUILD_MODE} OUTPUT_DIR=bin/
57
42
 
58
- # --- Runtime Image
43
+ # --- Runtime Image ---
59
44
  FROM rockylinux/rockylinux:9 AS runtime
60
45
 
61
46
  ARG UNDERPOST_VERSION=3.2.9
@@ -1,4 +1,4 @@
1
- # --- Build Image
1
+ # --- Build Image ---
2
2
  FROM rockylinux/rockylinux:9 AS builder
3
3
 
4
4
  RUN dnf -y update && \
@@ -11,27 +11,16 @@ RUN dnf -y update && \
11
11
 
12
12
  WORKDIR /build
13
13
 
14
- # Build context is the cyberia-server project repo root (the workflow
15
- # in .github/workflows/docker-image.cyberia-server.ci.yml sets
16
- # context: . from the cyberia-server checkout). The legacy
17
- # engine-context layout (COPY cyberia-server/ .) is no longer used.
14
+
18
15
  COPY go.mod go.sum ./
19
16
  RUN go mod download
20
17
 
21
18
  COPY . ./
22
19
  RUN chmod +x build.sh && ./build.sh
23
20
 
24
- # --- Runtime Image
21
+ # --- Runtime Image ---
25
22
  FROM rockylinux/rockylinux:9 AS runtime
26
23
 
27
- # Runtime needs:
28
- # - the compiled Go binary (cyberia-server itself)
29
- # - nodejs + the underpost CLI globally, for the container-status
30
- # lifecycle hooks (`underpost config set container-status ...`) that
31
- # the conf.instances.json cmd invokes before / after launching the
32
- # server binary. Installing it at build time avoids the slow
33
- # `npm install -g` startup the K8S cmd would otherwise have to do
34
- # on every pod boot.
35
24
  ARG UNDERPOST_VERSION=3.2.9
36
25
  RUN dnf -y update && \
37
26
  dnf -y install epel-release && \
@@ -46,17 +35,8 @@ WORKDIR /home/dd/engine/cyberia-server
46
35
 
47
36
  COPY --from=builder /build/server ./server
48
37
 
49
- # Static SSR dashboard rendered by `node bin/cyberia run-workflow
50
- # build-server-dashboard --output-path <project-root>/public/index.html`
51
- # from inside the engine repo checkout. The Go server's findPublicDir()
52
- # hard-requires public/index.html at boot and log.Fatalf's without it.
53
- # CI writes the dashboard into ./public/ at the cyberia-server repo root
54
- # before docker build picks it up here.
55
38
  COPY public/ ./public/
56
39
 
57
40
  EXPOSE 8081
58
41
 
59
- # Default entrypoint when the image is run directly (not via K8S cmd).
60
- # In K8S deploys conf.instances.json supplies its own cmd that wraps env
61
- # sourcing + container-status hooks + this same binary.
62
42
  ENTRYPOINT ["/home/dd/engine/cyberia-server/server"]