cyberia 3.2.12 → 3.2.70
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.
- package/.env.example +127 -68
- package/.github/workflows/cyberia-client.cd.yml +40 -0
- package/.github/workflows/cyberia-server.cd.yml +40 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +49 -0
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +48 -0
- package/.github/workflows/docker-image.cyberia-server.ci.yml +69 -0
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +69 -0
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +52 -0
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +52 -0
- package/.github/workflows/engine-cyberia.cd.yml +34 -24
- package/.github/workflows/engine-cyberia.ci.yml +27 -5
- package/.github/workflows/ghpkg.ci.yml +89 -1
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/hardhat.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +19 -12
- package/.github/workflows/publish.ci.yml +2 -2
- package/.github/workflows/publish.cyberia.ci.yml +5 -16
- package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -8
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/CHANGELOG.md +451 -1
- package/CLI-HELP.md +1040 -1130
- package/Dockerfile +141 -43
- package/Dockerfile.dev +143 -0
- package/Dockerfile.test +165 -0
- package/README.md +1 -1
- package/baremetal/commission-workflows.json +1 -0
- package/bin/build.js +128 -136
- package/bin/build.template.js +25 -179
- package/bin/cyberia.js +1089 -188
- package/bin/deploy.js +6 -3
- package/bin/index.js +1089 -188
- package/bump.config.js +1 -0
- package/compose.env +131 -0
- package/conf.js +19 -1
- package/deployment.yaml +74 -2
- package/docker-compose.yml +316 -0
- package/hardhat/hardhat.config.js +2 -2
- package/hardhat/package-lock.json +620 -2041
- package/hardhat/package.json +7 -5
- package/hardhat/scripts/deployObjectLayerToken.js +18 -18
- package/hardhat/test/ObjectLayerToken.js +378 -274
- package/ipfs/configure-ipfs.sh +13 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +74 -2
- package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +32 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/mongodb/entrypoint.sh +76 -0
- package/nginx.conf +87 -0
- package/package.json +34 -22
- package/pv-pvc.yaml +32 -0
- package/scripts/disk-clean.sh +85 -60
- package/scripts/kubeadm-node-setup.sh +317 -0
- package/scripts/link-local-underpost-cli.sh +6 -0
- package/scripts/rocky-kickstart.sh +877 -185
- package/scripts/rpmfusion-ffmpeg-setup.sh +26 -50
- package/scripts/test-monitor.sh +248 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +43 -7
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +17 -25
- package/src/api/cyberia-action/cyberia-action.controller.js +19 -0
- package/src/api/cyberia-action/cyberia-action.model.js +21 -29
- package/src/api/cyberia-action/cyberia-action.router.js +42 -7
- package/src/api/cyberia-action/cyberia-action.service.js +20 -4
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +58 -57
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +37 -6
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +8 -2
- package/src/api/cyberia-entity/cyberia-entity.router.js +39 -7
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +74 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +63 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +62 -10
- package/src/api/cyberia-instance/cyberia-instance.model.js +32 -2
- package/src/api/cyberia-instance/cyberia-instance.router.js +6 -6
- package/src/api/cyberia-instance/cyberia-world-generator.js +116 -3
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +3 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +39 -7
- package/src/api/cyberia-map/cyberia-map.router.js +21 -6
- package/src/api/cyberia-quest/cyberia-quest.controller.js +38 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +47 -7
- package/src/api/cyberia-quest/cyberia-quest.service.js +59 -4
- package/src/api/cyberia-saga/cyberia-saga.controller.js +74 -0
- package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
- package/src/api/cyberia-saga/cyberia-saga.router.js +63 -0
- package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +551 -122
- package/src/api/cyberia-skill/cyberia-skill.controller.js +74 -0
- package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
- package/src/api/cyberia-skill/cyberia-skill.router.js +63 -0
- package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
- package/src/api/ipfs/ipfs.service.js +28 -15
- package/src/api/object-layer/object-layer.router.js +25 -15
- package/src/api/object-layer/object-layer.service.js +15 -20
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +39 -7
- package/src/cli/baremetal.js +717 -16
- package/src/cli/cluster.js +80 -5
- package/src/cli/deploy.js +326 -292
- package/src/cli/docker-compose.js +648 -0
- package/src/cli/env.js +12 -6
- package/src/cli/fs.js +75 -30
- package/src/cli/image.js +187 -55
- package/src/cli/index.js +157 -6
- package/src/cli/kickstart.js +142 -20
- package/src/cli/monitor.js +387 -6
- package/src/cli/release.js +72 -15
- package/src/cli/repository.js +339 -40
- package/src/cli/run.js +678 -186
- package/src/cli/secrets.js +82 -48
- package/src/cli/ssh.js +234 -0
- package/src/cli/static.js +2 -2
- package/src/client/components/core/PanelForm.js +44 -44
- package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
- package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
- package/src/client/components/cyberia/InstanceEngineCyberia.js +219 -13
- package/src/client/components/cyberia/MapEngineCyberia.js +154 -71
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +40 -63
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +34 -20
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +195 -4
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +66 -0
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +8 -0
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -0
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +92 -20
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +272 -50
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +3 -3
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +39 -22
- package/src/client/public/cyberia-docs/CYBERIA-LORE.md +88 -0
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +28 -12
- package/src/client/public/cyberia-docs/CYBERIA.md +1 -1
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +27 -5
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +99 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +2 -2
- package/src/client/services/cyberia-map/cyberia-map.management.js +2 -2
- package/src/client/services/cyberia-saga/cyberia-saga.service.js +99 -0
- package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -6
- package/src/{server → client-builder}/client-build-docs.js +15 -5
- package/src/{server → client-builder}/client-build-live.js +3 -3
- package/src/{server → client-builder}/client-build.js +25 -22
- package/src/{server → client-builder}/client-dev-server.js +3 -3
- package/src/{server → client-builder}/client-icons.js +2 -2
- package/src/{server → client-builder}/ssr.js +5 -5
- package/src/client.build.js +1 -3
- package/src/client.dev.js +1 -1
- package/src/db/mongo/MongoBootstrap.js +12 -12
- package/src/db/mongo/MongooseDB.js +2 -1
- package/src/grpc/cyberia/grpc-server.js +255 -70
- package/src/index.js +12 -1
- package/src/mailer/EmailRender.js +1 -1
- package/src/{server → projects/cyberia}/atlas-sprite-sheet-generator.js +2 -2
- package/src/{server → projects/cyberia}/besu-genesis-generator.js +3 -3
- package/src/projects/cyberia/catalog-cyberia.js +81 -0
- package/src/projects/cyberia/gemini-client.js +175 -0
- package/src/projects/cyberia/generate-saga.js +2107 -0
- package/src/{server → projects/cyberia}/ipfs-client.js +6 -4
- package/src/{server → projects/cyberia}/object-layer.js +12 -108
- package/src/{server → projects/cyberia}/semantic-layer-generator-floor.js +1 -1
- package/src/{server → projects/cyberia}/semantic-layer-generator-resource.js +1 -1
- package/src/{server → projects/cyberia}/semantic-layer-generator-skin.js +1 -1
- package/src/{server → projects/cyberia}/semantic-layer-generator.js +2 -2
- package/src/{server → projects/cyberia}/shape-generator.js +2 -2
- package/src/projects/underpost/catalog-underpost.js +60 -0
- package/src/runtime/cyberia-client/Dockerfile +31 -83
- package/src/runtime/cyberia-client/Dockerfile.dev +23 -30
- package/src/runtime/cyberia-server/Dockerfile +23 -42
- package/src/runtime/cyberia-server/Dockerfile.dev +20 -35
- package/src/runtime/engine-cyberia/Dockerfile +143 -0
- package/src/runtime/engine-cyberia/Dockerfile.dev +143 -0
- package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
- package/src/runtime/engine-cyberia/compose.env +131 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +316 -0
- package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
- package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
- package/src/runtime/engine-cyberia/nginx.conf +87 -0
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/nginx/Nginx.js +250 -0
- package/src/runtime/wp/Dockerfile +3 -3
- package/src/server/catalog.js +72 -0
- package/src/server/conf.js +415 -60
- package/src/server/runtime-status.js +252 -0
- package/src/server/start.js +42 -11
- package/src/server.js +6 -2
- package/test/cyberia-instance-conf-defaults.test.js +140 -0
- package/test/deploy-monitor.test.js +267 -0
- package/test/shape-generator.test.js +7 -1
- package/typedoc.dd-cyberia.json +3 -1
- package/typedoc.json +3 -1
- package/manifests/deployment/dd-test-development/deployment.yaml +0 -256
- package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
- /package/src/client/ssr/{Render.js → RootDocument.js} +0 -0
- /package/src/{server → client-builder}/client-formatted.js +0 -0
|
@@ -235,16 +235,22 @@ All requests are CORS-simple GETs (no preflight) and cacheable. None require cre
|
|
|
235
235
|
```bash
|
|
236
236
|
cd cyberia-client
|
|
237
237
|
|
|
238
|
-
# Development build
|
|
239
|
-
make -f Web.mk clean && make -f Web.mk
|
|
238
|
+
# Development build (defaults: BUILD_MODE=DEBUG, localhost URLs)
|
|
239
|
+
make -f Web.mk clean && make -f Web.mk all
|
|
240
240
|
|
|
241
|
-
# Release build
|
|
242
|
-
make -f Web.mk clean && make -f Web.mk
|
|
241
|
+
# Release build — pass the production URLs explicitly (see note below)
|
|
242
|
+
make -f Web.mk clean && make -f Web.mk all BUILD_MODE=RELEASE \
|
|
243
|
+
WS_URL=wss://server.cyberiaonline.com/ws \
|
|
244
|
+
API_BASE=https://www.cyberiaonline.com
|
|
243
245
|
|
|
244
|
-
# Build + serve on dev port :8082
|
|
245
|
-
|
|
246
|
+
# Build + serve locally on dev port :8082 (DEBUG, localhost)
|
|
247
|
+
./dev-server.sh # or: ./dev-server.sh <port>
|
|
246
248
|
```
|
|
247
249
|
|
|
250
|
+
`WS_URL` and `API_BASE` are passed straight through to the compiler — see
|
|
251
|
+
[Compile-time configuration](#compile-time-configuration). When omitted they
|
|
252
|
+
default to `localhost`, so **production build pipelines must pass real URLs**.
|
|
253
|
+
|
|
248
254
|
The build is part of the Underpost Platform static + PWA pipeline; production deploys go through `underpost client` and `underpost deploy`.
|
|
249
255
|
|
|
250
256
|
### Output
|
|
@@ -261,22 +267,33 @@ bin/
|
|
|
261
267
|
|
|
262
268
|
## Compile-time configuration
|
|
263
269
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
|
271
|
-
|
|
|
272
|
-
| `
|
|
273
|
-
| `
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
270
|
+
### Server URLs (build arguments)
|
|
271
|
+
|
|
272
|
+
`WS_URL` and `API_BASE` are `make` arguments baked into the WASM as
|
|
273
|
+
`-DWS_URL_OVERRIDE` / `-DAPI_BASE_URL_OVERRIDE`. There is **no** RELEASE/DEBUG URL
|
|
274
|
+
switch — both default to `localhost` regardless of `BUILD_MODE`:
|
|
275
|
+
|
|
276
|
+
| make argument | Default | Baked macro |
|
|
277
|
+
| ------------- | ------------------------ | ----------------------- |
|
|
278
|
+
| `WS_URL` | `ws://localhost:8081/ws` | `WS_URL_OVERRIDE` |
|
|
279
|
+
| `API_BASE` | `http://localhost:4005` | `API_BASE_URL_OVERRIDE` |
|
|
280
|
+
|
|
281
|
+
> **Production pipelines must pass the URLs.** `BUILD_MODE=RELEASE` alone still
|
|
282
|
+
> yields `localhost`. Any release build — the Docker image build, CI, manual
|
|
283
|
+
> release — must pass `WS_URL=wss://… API_BASE=https://…` as make arguments
|
|
284
|
+
> (or Docker build-args wired through to `make`), or the client ships pointing
|
|
285
|
+
> at localhost. If unset, `src/config.h` falls back to bare `"ws://"` /
|
|
286
|
+
> `"https://"` stubs.
|
|
287
|
+
|
|
288
|
+
### Constants (`src/config.h`)
|
|
289
|
+
|
|
290
|
+
| Constant | Default | Description |
|
|
291
|
+
| --------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
292
|
+
| `CYBERIA_CLIENT_HINTS_CODE` | `cyberia-main` | Lookup key for the optional client-hints fetch (presentation override key — never an instance/server identifier) |
|
|
293
|
+
| `MAX_TEXTURE_CACHE_SIZE` | `512` | Atlas texture LRU cap |
|
|
294
|
+
| `MAX_LAYER_CACHE_SIZE` | `256` | ObjectLayer metadata LRU cap |
|
|
295
|
+
| `MAX_ATLAS_CACHE_SIZE` | `256` | Atlas metadata LRU cap |
|
|
296
|
+
| `DEFAULT_FRAME_DURATION_MS` | `100` | Default animation frame duration |
|
|
280
297
|
|
|
281
298
|
---
|
|
282
299
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# **Cyberia Lore — The Frontier of Hyperspace**
|
|
2
|
+
|
|
3
|
+
### **Setting: Year 2520+**
|
|
4
|
+
|
|
5
|
+
Earth is a ruined monument to humanity’s first age. Civilization now spans broken continents, orbital fortresses, lunar citadels, asteroid enclaves, and distant colonies. From the ashes of collapse emerged **Cyberia**: a living frontier where the physical world and **hyperspace** (persistent, immersive Instances) have fused into one unstable civilization.
|
|
6
|
+
|
|
7
|
+
The boundary between reality and hyperspace is porous. Relics, wars, identities, and events bleed between layers, creating opportunity, conflict, and myth.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
### **The Historical Fracture**
|
|
12
|
+
|
|
13
|
+
The **Pacific Cataclysm** (2045) shattered the old world through nuclear disaster, environmental collapse, plagues, and uncontrolled experiments. As Earth became hostile, humanity expanded into space while building advanced **Instances** — enduring digital worlds that evolved from tools into homes, markets, religions, and battlefields.
|
|
14
|
+
|
|
15
|
+
Two new groups emerged:
|
|
16
|
+
|
|
17
|
+
- **Mutagens**: Radiation- and bio-altered humans, resilient but often marginalized.
|
|
18
|
+
- **Synthetics**: Artificial beings who gained autonomy and identity.
|
|
19
|
+
|
|
20
|
+
These groups, along with baseline humans, now navigate the layered reality of Cyberia.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
### **The Dual Nature of Cyberia**
|
|
25
|
+
|
|
26
|
+
Cyberia exists on two overlapping layers:
|
|
27
|
+
|
|
28
|
+
- **Physical Layer**: Harsh, resource-driven reality of fleets, colonies, infrastructure, territory, and direct force. Slow, unforgiving, dominated by logistics and raw power.
|
|
29
|
+
- **Hyperspace Layer**: Vast network of persistent Instances — living archives, simulated empires, memory-cities, and evolving digital ecosystems where time, geography, and identity are fluid.
|
|
30
|
+
|
|
31
|
+
The two layers constantly influence each other through neural links, relics, breaches, and megastructures. What happens in one can reshape the other.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### **The Three Great Confederations**
|
|
36
|
+
|
|
37
|
+
#### **Zenith Empire (Red)**
|
|
38
|
+
|
|
39
|
+
Militaristic, hierarchical, expansionist. Masters of the **physical layer** — fleets, fortresses, industry, and territorial control.
|
|
40
|
+
**Core belief**: Civilization requires imposed order through strength.
|
|
41
|
+
**Strength**: Force, discipline, infrastructure dominance.
|
|
42
|
+
**Weakness**: Rigidity, anti-Mutagen prejudice, ecological destruction, over-reliance on Nova’s systems.
|
|
43
|
+
**Internal split**: Iron Legion (conquest) vs. Aether Council (technocratic stability).
|
|
44
|
+
**Relations**: Views Atlas as chaotic and degenerate; depends on Nova for intelligence and administration while resenting the dependency.
|
|
45
|
+
|
|
46
|
+
#### **Atlas Confederation (Yellow)**
|
|
47
|
+
|
|
48
|
+
Decentralized web of frontier settlements, Mutagen clans, Synthetics, traders, scavengers, hackers, and nomads. Excels in the unstable spaces **between** layers.
|
|
49
|
+
**Core strength**: Adaptation, asymmetric warfare, improvisation, infiltration, and survival in chaos.
|
|
50
|
+
**Weakness**: Fragmentation and internal division.
|
|
51
|
+
**Internal split**: Harmony Enclaves (diplomacy & coexistence) vs. Void Nomads (radical independence).
|
|
52
|
+
**Relations**: Opposes Zenith’s rigidity and environmental harm; undermines Nova through hacking and sabotage. Thrives on black-market networks and flexible alliances.
|
|
53
|
+
|
|
54
|
+
#### **Nova Republic (Blue)**
|
|
55
|
+
|
|
56
|
+
Technocratic, intelligence-driven civilization that dominates **hyperspace**. Obsessed with optimization, prediction, cognitive architecture, and transcendence.
|
|
57
|
+
**Core strength**: Information control, surveillance, predictive systems, and deep integration into digital realms.
|
|
58
|
+
**Weakness**: Emotional detachment, underestimation of irrational human elements (faith, loyalty, culture).
|
|
59
|
+
**Internal split**: Singularity Directive (machine supremacy) vs. Transcendent Conclave (hybrid flesh-machine future).
|
|
60
|
+
**Relations**: Provides critical systems to Zenith; faces constant subversion from Atlas hackers. Sees itself as the guiding intelligence of civilization.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### **The Balance of Power**
|
|
65
|
+
|
|
66
|
+
The three confederations exist in tense, interdependent equilibrium:
|
|
67
|
+
|
|
68
|
+
- Zenith controls physical force and territory.
|
|
69
|
+
- Nova controls hyperspace information and architecture.
|
|
70
|
+
- Atlas thrives in the gaps, through mobility, sabotage, and adaptation.
|
|
71
|
+
|
|
72
|
+
They compete publicly, collaborate secretly, and betray each other routinely. None can fully dominate Cyberia — the frontier is too unstable, layered, and resistant to total control.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
### **Your Role as Player**
|
|
77
|
+
|
|
78
|
+
You are not a destined hero. You are a survivor who has lived long enough to matter.
|
|
79
|
+
|
|
80
|
+
You can be:
|
|
81
|
+
|
|
82
|
+
- A soldier, scout, smuggler, hacker, relic hunter, Instance diver, mercenary, diplomat, or rogue Synthetic/Mutagen.
|
|
83
|
+
- Aligned with one faction, multiple, or none.
|
|
84
|
+
- A wanderer who moves between physical ruins and hyperspace realms.
|
|
85
|
+
|
|
86
|
+
Your power comes from what you **carry, recover, build, protect, steal, or remember**. In Cyberia, the true battle is over meaning, memory, and access across layers of reality. Your choices can shift alliances, awaken relics, destabilize systems, or forge new legends.
|
|
87
|
+
|
|
88
|
+
**Welcome to Cyberia** — the Hyper-Reality Frontier. A broken future where physical and digital realities collide, ancient scars shape new empires, and your story is still unwritten.
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
# Cyberia Saga — Top-Down Procedural Generation guided by LLMs
|
|
2
|
+
|
|
3
|
+
> Semantic Reverse-Engineering of a complete saga ecosystem from a single theme.
|
|
4
|
+
|
|
5
|
+
## Concept
|
|
6
|
+
|
|
7
|
+
Classic procedural content generation is **bottom-up**: you draw maps, place
|
|
8
|
+
cells and entities, then layer text and logic on top of that spatial substrate.
|
|
9
|
+
Cyberia inverts the pipeline.
|
|
10
|
+
|
|
11
|
+
**Top-Down PCG (Semantic Reverse-Engineering)** uses an LLM to infer the entire
|
|
12
|
+
**semantic ontology and narrative backbone first**, from one high-level natural
|
|
13
|
+
language theme. We generate the lightweight, easy-to-align textual layer —
|
|
14
|
+
slugs, titles, descriptions, dialogues, objective requirements, item stats —
|
|
15
|
+
_before_ a single coordinate or texture exists. Spatial layout and graphic
|
|
16
|
+
synthesis become a separate, later stage that fills in a backbone that is
|
|
17
|
+
already internally consistent.
|
|
18
|
+
|
|
19
|
+
This is a specialized form of AI-Generated Content (AIGC). The win is
|
|
20
|
+
**consistency**: by resolving names, references, and progression as pure text,
|
|
21
|
+
the world is logically coherent before we pay the cost of spatial and visual
|
|
22
|
+
synthesis.
|
|
23
|
+
|
|
24
|
+
## Architectural boundary (hard rule)
|
|
25
|
+
|
|
26
|
+
This stage owns **text and logical metadata only**.
|
|
27
|
+
|
|
28
|
+
| Owned here (textual) | Out of scope (forced to `null` / default) |
|
|
29
|
+
| -------------------------------- | --------------------------------------------- |
|
|
30
|
+
| codes, titles, descriptions | `sourceMapCode`, `sourceCellX`, `sourceCellY` |
|
|
31
|
+
| dialogue text, speakers, mood | `initCellX`, `initCellY`, map grid sizes |
|
|
32
|
+
| quest steps, objectives, rewards | asset CIDs, textures, `render` frames |
|
|
33
|
+
| item stats balance, item types | atlas / sprite-sheet generation |
|
|
34
|
+
|
|
35
|
+
The generator normalizes every spatial and render field to `null` regardless of
|
|
36
|
+
what the model returns. Downstream spatial + graphic synthesis is responsible
|
|
37
|
+
for binding quests/actions to cells and producing object-layer renders.
|
|
38
|
+
|
|
39
|
+
## Pipeline
|
|
40
|
+
|
|
41
|
+
The ecosystem is generated in **six bounded, sequential stages** rather than a
|
|
42
|
+
single monolithic request. Each stage emits one layer and feeds canonical
|
|
43
|
+
(slugified) references into the next, so no single model call has to produce the
|
|
44
|
+
whole cross-referenced graph — this keeps each Gemini request small enough to
|
|
45
|
+
complete well within the request timeout.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
theme (from --prompt, OR auto-synthesized from CYBERIA-LORE.md)
|
|
49
|
+
│
|
|
50
|
+
▼
|
|
51
|
+
Google Gemini (Generative Language API /v1beta/models/{model}:generateContent)
|
|
52
|
+
│ stage 1 foundation → saga identity + objectLayers (item ids)
|
|
53
|
+
│ stage 2 maps → maps (narrative zones / places)
|
|
54
|
+
│ stage 3 quests → quests (consume item ids + map zones)
|
|
55
|
+
│ stage 4 dialogues → dialogues (consume quest codes)
|
|
56
|
+
│ stage 5 actions → actions (consume quest + dialogue + item codes)
|
|
57
|
+
│ stage 6 skills → skills (bind trigger items → logic-event handlers)
|
|
58
|
+
▼
|
|
59
|
+
normalizeSagaPayload() ── enforces text-only boundary, slugifies, resolves refs,
|
|
60
|
+
│ derives the CyberiaInstance shell from saga + map codes
|
|
61
|
+
▼
|
|
62
|
+
persistSagaPayload() ── idempotent upserts into MongoDB
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The **instance** is not a model call: it is derived deterministically from the
|
|
66
|
+
saga's own metadata (`code`, `name`, `description`) plus the map codes the saga
|
|
67
|
+
already defined, so the saga is immediately playable as a `CyberiaInstance`.
|
|
68
|
+
Skill `logicEventId`s are restricted to the handlers the simulation actually
|
|
69
|
+
implements (`projectile`, `coin_drop_or_transaction`, `doppelganger`); unknown
|
|
70
|
+
ones are dropped during normalization.
|
|
71
|
+
|
|
72
|
+
### Theme source: prompt vs. lore-grounded auto-generation
|
|
73
|
+
|
|
74
|
+
- **`--prompt` given** → the theme is used verbatim with no lore grounding
|
|
75
|
+
(current behavior).
|
|
76
|
+
- **`--prompt` omitted** → a distinct theme is auto-synthesized from the Cyberia
|
|
77
|
+
base lore (`src/client/public/cyberia-docs/CYBERIA-LORE.md`, override with
|
|
78
|
+
`--lore-path`). The whole lore document is read and passed to Gemini, and every
|
|
79
|
+
stage is grounded in it so the saga reads as a chapter of the canon. Variety is
|
|
80
|
+
driven by a random world-first **subject**, an explicit **narrative tone**, a
|
|
81
|
+
**faction role** (background vs. driver), a random entropy token, and a
|
|
82
|
+
configurable sampling **temperature** (`--temperature`, default `1.3`) — so
|
|
83
|
+
repeated runs surface very different, grounded Cyberia stories.
|
|
84
|
+
|
|
85
|
+
#### Subject — the world comes first
|
|
86
|
+
|
|
87
|
+
The primary diversity lever. Each auto-theme picks one **world-first subject** at
|
|
88
|
+
random so the output spreads across lived Cyberia reality rather than collapsing
|
|
89
|
+
into faction politics: daily life, frontier survival, ecology, salvage, trade,
|
|
90
|
+
exploration, mutagen clans, synthetics, Instance life, anomalies, small-community
|
|
91
|
+
crises, infrastructure, relic hunting, personal/family stories, culture, and
|
|
92
|
+
grounded jobs that go sideways. (Random, not customizable.)
|
|
93
|
+
|
|
94
|
+
#### Faction role — background by default, driver on request
|
|
95
|
+
|
|
96
|
+
The confederations are large powers that are **always present but rarely the
|
|
97
|
+
topic**. By default they stay **background only** — borders, trade influence,
|
|
98
|
+
security presence, taxes, historical scars — never the subject.
|
|
99
|
+
|
|
100
|
+
To make a faction the **central driver** of the saga, name one or more with
|
|
101
|
+
`--faction-context` (comma-separated). Valid keys:
|
|
102
|
+
|
|
103
|
+
| Key | Confederation |
|
|
104
|
+
| --------- | ---------------------------------------------- |
|
|
105
|
+
| `zenith` | the Zenith Empire (Red) |
|
|
106
|
+
| `nova` | the Nova Republic (Blue) |
|
|
107
|
+
| `atlas` | the Atlas Confederation (Yellow) |
|
|
108
|
+
| `neutral` | unaligned independent enclaves / neutral parties |
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Nova + Zenith are the driving pressure of the saga
|
|
112
|
+
node bin/cyberia.js generate-saga --faction-context 'nova,zenith'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Unknown keys warn and are skipped; if none resolve (or the flag is unset) the
|
|
116
|
+
saga falls back to background factions. Even when driven, the saga is still told
|
|
117
|
+
through the subject's people and places, not abstract galaxy-wide politics.
|
|
118
|
+
|
|
119
|
+
#### Character culture & naming
|
|
120
|
+
|
|
121
|
+
To stop the model collapsing into cliché sci-fi names (John, Nova, X-99…) and to
|
|
122
|
+
make Cyberia feel descended from Earth's many diasporas, a **naming &
|
|
123
|
+
character-culture** block is injected into every generation stage that names
|
|
124
|
+
people or places. It uses `CHARACTER_NAMES_POOL` as a **statistical/stylistic
|
|
125
|
+
prior — inspiration only, never a whitelist**: the model is told to invent fresh
|
|
126
|
+
names with similar linguistic/demographic characteristics (evolving, hybridizing,
|
|
127
|
+
or blending them with professions, slang, and technical terms), reusing an exact
|
|
128
|
+
sample only rarely.
|
|
129
|
+
|
|
130
|
+
Two optional flags steer it; **both default to random** when unset:
|
|
131
|
+
|
|
132
|
+
- **`--character-context <keys>`** — comma-separated pools to draw inspiration
|
|
133
|
+
from (unset → a random non-empty subset, so runs vary their cultural mix).
|
|
134
|
+
Unknown keys warn and are skipped. Valid keys:
|
|
135
|
+
|
|
136
|
+
| Key | Flavor |
|
|
137
|
+
| --- | ------ |
|
|
138
|
+
| `low_level_synthetics` | serialized / technical utility-frame designations |
|
|
139
|
+
| `high_fidelity_synthetics` | refined, near-human synthetic names |
|
|
140
|
+
| `global_latin_diaspora` | Latin / Iberian-descended |
|
|
141
|
+
| `east_asian_pacific_diaspora` | East-Asian / Pacific-descended |
|
|
142
|
+
| `middle_eastern_turkish_diaspora` | Middle-Eastern / Turkish-descended |
|
|
143
|
+
| `sub_saharan_african_diaspora` | Sub-Saharan African-descended |
|
|
144
|
+
| `classic_western_scifi` | gritty Anglo operators / enforcers |
|
|
145
|
+
| `mutagen_clans` | organic, mutation-flavored clan names |
|
|
146
|
+
|
|
147
|
+
- **`--cultural-exposure <mode>`** — how mixed the population is (unset → random):
|
|
148
|
+
|
|
149
|
+
| Mode | Effect |
|
|
150
|
+
| ---- | ------ |
|
|
151
|
+
| `cosmopolitan` | heavy mixing, hybrid surnames, intermarriage — maximizes variety |
|
|
152
|
+
| `local` | isolated clans/enclaves, strong local naming traditions, internally consistent |
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Latin + East-Asian diaspora names in a highly mixed, cosmopolitan population
|
|
156
|
+
node bin/cyberia.js generate-saga \
|
|
157
|
+
--character-context 'global_latin_diaspora,east_asian_pacific_diaspora' \
|
|
158
|
+
--cultural-exposure cosmopolitan
|
|
159
|
+
|
|
160
|
+
# An isolated mutagen-clan enclave with consistent internal naming
|
|
161
|
+
node bin/cyberia.js generate-saga --character-context 'mutagen_clans' --cultural-exposure local
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Narrative tone
|
|
165
|
+
|
|
166
|
+
The theme commits to one of four broad narrative types — chosen **uniformly
|
|
167
|
+
(~25% each)** unless forced with `--tone`:
|
|
168
|
+
|
|
169
|
+
| Tone | Register |
|
|
170
|
+
| ----------- | -------------------------------------------------------------- |
|
|
171
|
+
| `adventure` | noir high-risk missions: covert ops, sabotage, combat, rogue AI, mystery |
|
|
172
|
+
| `politics` | power & ideology at any scale — councils, clans, enclaves, revolutions (confederation geopolitics only sometimes) |
|
|
173
|
+
| `tragic` | heartbreaking, intimate: family, bonds, loss, grief |
|
|
174
|
+
| `comedy` | everyday absurdity and silliness, played for humor |
|
|
175
|
+
|
|
176
|
+
#### Spatial context (physical vs. hyperspace)
|
|
177
|
+
|
|
178
|
+
Cyberia has two equally important layers — the **Physical Layer** (fleets,
|
|
179
|
+
colonies, logistics, force) and the **Hyperspace Layer** (persistent Instances,
|
|
180
|
+
memory-cities, digital ecosystems). Because the lore is titled *The Frontier of
|
|
181
|
+
Hyperspace*, an unconstrained model drifts to hyperspace-only premises. So the
|
|
182
|
+
auto-theme picks a spatial context **explicitly and uniformly (~33.3% each)**:
|
|
183
|
+
|
|
184
|
+
| Context | Premise lives in… |
|
|
185
|
+
| ------------ | -------------------------------------------------------------- |
|
|
186
|
+
| `physical` | the material frontier only — no hyperspace |
|
|
187
|
+
| `mixed` | the porous interplay where events bleed between both layers |
|
|
188
|
+
| `hyperspace` | inside the Instances only — not the physical frontier |
|
|
189
|
+
|
|
190
|
+
Force one with `--space-context <physical\|mixed\|hyperspace>`; an invalid value
|
|
191
|
+
warns and falls back to random. This applies to auto-generation only (with
|
|
192
|
+
`--prompt`, you control the setting yourself).
|
|
193
|
+
|
|
194
|
+
> Transient `generateContent` failures (timeouts, 5xx, malformed JSON) are
|
|
195
|
+
> retried automatically with backoff (`maxRetries`, default 2) per stage.
|
|
196
|
+
|
|
197
|
+
Source:
|
|
198
|
+
|
|
199
|
+
- `src/projects/cyberia/gemini-client.js` — thin Gemini `generateContent` JSON client.
|
|
200
|
+
- `src/projects/cyberia/generate-saga.js` — system prompt, normalization, persistence.
|
|
201
|
+
- `bin/cyberia.js` — `generate-saga` CLI command wiring.
|
|
202
|
+
|
|
203
|
+
## Usage
|
|
204
|
+
|
|
205
|
+
### Lore-based auto-generation (no `--prompt`)
|
|
206
|
+
|
|
207
|
+
With no `--prompt`, the theme is auto-synthesized from the Cyberia base lore.
|
|
208
|
+
Omitting the steering flags lets the generator pick a random faction, tone and
|
|
209
|
+
spatial context each run, so the same command keeps producing different sagas:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Fully random, lore-grounded saga (faction + tone + spatial context all random)
|
|
213
|
+
node bin/cyberia.js generate-saga
|
|
214
|
+
|
|
215
|
+
# Force a heartbreaking, character-driven story grounded in physical reality
|
|
216
|
+
node bin/cyberia.js generate-saga --tone tragic --space-context physical
|
|
217
|
+
|
|
218
|
+
# A political saga set inside hyperspace Instances
|
|
219
|
+
node bin/cyberia.js generate-saga --tone politics --space-context hyperspace
|
|
220
|
+
|
|
221
|
+
# A light comedy that spans both layers, cranked up for more divergence
|
|
222
|
+
node bin/cyberia.js generate-saga --tone comedy --space-context mixed --temperature 1.7
|
|
223
|
+
|
|
224
|
+
# A noir adventure, kept tightly on-theme with a low temperature
|
|
225
|
+
node bin/cyberia.js generate-saga --tone adventure --temperature 0.6
|
|
226
|
+
|
|
227
|
+
# Steer only the spatial layer; let subject + tone stay random
|
|
228
|
+
node bin/cyberia.js generate-saga --space-context physical
|
|
229
|
+
|
|
230
|
+
# Make Nova + Zenith the driving pressure (factions as the main theme)
|
|
231
|
+
node bin/cyberia.js generate-saga --faction-context 'nova,zenith'
|
|
232
|
+
|
|
233
|
+
# Steer character names toward specific diasporas and a cosmopolitan, mixed population
|
|
234
|
+
node bin/cyberia.js generate-saga \
|
|
235
|
+
--character-context 'global_latin_diaspora,sub_saharan_african_diaspora' --cultural-exposure cosmopolitan
|
|
236
|
+
|
|
237
|
+
# Dry run (no DB writes) and capture the payload to inspect it
|
|
238
|
+
node bin/cyberia.js generate-saga --tone tragic --dry-run --out ./engine-private/cyberia-sagas/preview.json
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Each run logs the chosen facets, e.g.
|
|
242
|
+
`Theme: subject="..." | context=physical | tone=tragic | factions=background`,
|
|
243
|
+
then `Auto-generated theme: "..."`.
|
|
244
|
+
|
|
245
|
+
### Generate from an explicit theme
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
node bin/cyberia.js generate-saga \
|
|
249
|
+
--prompt "A rebel hacker base hidden in the sewers of Santiago"
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Either way, when `--out` is omitted the payload is written to
|
|
253
|
+
`./engine-private/cyberia-sagas/<saga-code>.json`.
|
|
254
|
+
|
|
255
|
+
Import a previously generated payload (no model call):
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
node bin/cyberia.js generate-saga --import ./engine-private/cyberia-sagas/<saga-code>.json
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`--import` reads the same JSON shape `--out` writes and loads it through the
|
|
262
|
+
**same** normalize → persist path as generation. Re-running is safe: documents
|
|
263
|
+
are upserted by `code` (dialogues by `code` + `order`), so existing entries are
|
|
264
|
+
overwritten and codes are never duplicated.
|
|
265
|
+
|
|
266
|
+
Options:
|
|
267
|
+
|
|
268
|
+
| Flag | Description |
|
|
269
|
+
| -------------------------- | ---------------------------------------------------- |
|
|
270
|
+
| `--prompt <theme>` | Theme seed. Omit to auto-generate from the lore. |
|
|
271
|
+
| `--import <file>` | Load a generated payload file into the DB. |
|
|
272
|
+
| `--lore-path <path>` | Override the base-lore doc (auto-generate mode). |
|
|
273
|
+
| `--space-context <ctx>` | Force `physical` \| `mixed` \| `hyperspace` (else random). |
|
|
274
|
+
| `--tone <tone>` | Force `adventure` \| `politics` \| `tragic` \| `comedy` (else random). |
|
|
275
|
+
| `--faction-context <keys>` | Comma-separated `zenith` \| `nova` \| `atlas` \| `neutral` that DRIVE the theme (else background). |
|
|
276
|
+
| `--character-context <keys>` | Comma-separated `CHARACTER_NAMES_POOL` keys for name inspiration (else random subset). |
|
|
277
|
+
| `--cultural-exposure <mode>` | `cosmopolitan` \| `local` naming-diversity mode (else random). |
|
|
278
|
+
| `--temperature <value>` | Sampling temperature for every model call (default `1.3`). |
|
|
279
|
+
| `--model <id>` | Gemini model id (default `gemma-4-26b-a4b-it`). |
|
|
280
|
+
| `--timeout <ms>` | Per-request timeout in ms (default `300000`). |
|
|
281
|
+
| `--thinking-level <level>` | `low` \| `medium` \| `high` (default `high`). |
|
|
282
|
+
| `--out <file>` | Payload dump path (default `./engine-private/cyberia-sagas/<saga-code>.json`). |
|
|
283
|
+
| `--dry-run` | Normalize only; no database writes. |
|
|
284
|
+
| `--env-path <path>` | Env file to load (`GEMINI_API_KEY`, deploy vars). |
|
|
285
|
+
| `--mongo-host <host>` | Mongo host override. |
|
|
286
|
+
| `--dev` | Force the development environment. |
|
|
287
|
+
|
|
288
|
+
`GEMINI_API_KEY` must be available in the environment or the `--env-path` file.
|
|
289
|
+
|
|
290
|
+
## Output schema
|
|
291
|
+
|
|
292
|
+
A single JSON object with these interrelated sections:
|
|
293
|
+
|
|
294
|
+
- **saga** — `code`, `name`, `description`, `mapCodes[]`, `itemIds[]`, `questCodes[]`.
|
|
295
|
+
- **instance** — the playable `CyberiaInstance` shell derived from the saga
|
|
296
|
+
metadata: `code`, `name`, `description`, `tags[]`, `cyberiaMapCodes[]` (the
|
|
297
|
+
saga's map codes), `itemIds[]` (`{ id, defaultPlayerInventory }`),
|
|
298
|
+
`topologyMode`. Spatial topology (`portals`) and the tuning ref (`conf`) are
|
|
299
|
+
left empty here and bound by downstream spatial synthesis.
|
|
300
|
+
- **maps[]** — narrative zones the quest chain visits: `code`, `name`,
|
|
301
|
+
`description` (text only — grid/cells/entities stay at schema defaults). Their
|
|
302
|
+
codes populate `saga.mapCodes` and `instance.cyberiaMapCodes`.
|
|
303
|
+
- **quests[]** — textual objectives, titles, linear `steps[]` with
|
|
304
|
+
`collect | talk | kill` objectives and `rewards[]`. Spatial fields `null`.
|
|
305
|
+
- **dialogues[]** — narrative nodes: `code`, `order`, `speaker`, `text`, `mood`.
|
|
306
|
+
- **actions[]** — interaction nodes: `dialogCode`, `questDialogueCodes[]`,
|
|
307
|
+
`shopItems[]` pricing, and `craftRecipes[]`. Spatial fields `null`.
|
|
308
|
+
- **skills[]** — `triggerItemId` → logic skills: `logicEventIds[]` (derived) and
|
|
309
|
+
`skills[]` (`logicEventId`, `name`, `description`, `summonedEntityItemId`). The
|
|
310
|
+
trigger and every non-placeholder summoned id resolve to an
|
|
311
|
+
`objectLayers[].item.id`.
|
|
312
|
+
- **objectLayers[]** — item data with balanced `stats`, an `item`
|
|
313
|
+
(`id`, `type`, `description`, `activable`), and `render: null`.
|
|
314
|
+
|
|
315
|
+
Object-layer item shape:
|
|
316
|
+
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"stats": { "effect": 4, "resistance": 4, "agility": 3, "range": 10, "intelligence": 5, "utility": 10 },
|
|
320
|
+
"item": { "id": "generated-id", "type": "skin", "description": "Lore-matching description", "activable": true },
|
|
321
|
+
"render": null
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Referential integrity
|
|
326
|
+
|
|
327
|
+
The system prompt requires the model to keep cross-references resolvable, and
|
|
328
|
+
normalization slugifies every code/id so they line up:
|
|
329
|
+
|
|
330
|
+
- quest objective/reward `itemId`, shop `itemId`, and craft `itemId` resolve to
|
|
331
|
+
an `objectLayers[].item.id`;
|
|
332
|
+
- action `questDialogueCodes[].questCode` resolves to a `quests[].code`;
|
|
333
|
+
- action `dialogCode` / `questDialogueCodes[].dialogCode` resolve to a
|
|
334
|
+
`dialogues[].code`;
|
|
335
|
+
- skill `triggerItemId` resolves to an `objectLayers[].item.id` (skills whose
|
|
336
|
+
trigger is unknown are dropped), and each non-placeholder `summonedEntityItemId`
|
|
337
|
+
resolves to one too — a deterministic repair (`ensureSkillLinkage`) appends a
|
|
338
|
+
minimal `skill`-type item for any summoned id the model omitted;
|
|
339
|
+
- `saga.questCodes` / `saga.itemIds` are reconciled to include every generated
|
|
340
|
+
quest and item (including appended skill items), and `instance.cyberiaMapCodes`
|
|
341
|
+
/ `instance.itemIds` mirror the saga's.
|
|
342
|
+
|
|
343
|
+
### `talk` objectives (guaranteed fulfillable)
|
|
344
|
+
|
|
345
|
+
A `talk` objective completes **only** when the player views the `dialogCode` an
|
|
346
|
+
action maps for that quest, on the NPC bot whose skin matches the objective's
|
|
347
|
+
`itemId` (the bot skin derives from the action's `default-<skin>` greeting). A
|
|
348
|
+
missing link means the objective can never be completed.
|
|
349
|
+
|
|
350
|
+
So a talk objective requires four aligned pieces: a `skin` item for the NPC, the
|
|
351
|
+
`talk` objective referencing that skin id, a talk dialogue group, and an action
|
|
352
|
+
with `dialogCode: default-<skin>` plus a `questDialogueCodes` entry
|
|
353
|
+
`{ questCode, dialogCode }`. The prompts ask the model to produce all four (the
|
|
354
|
+
quests/dialogues/actions stages are told the `talkTargets`), and a deterministic
|
|
355
|
+
**repair pass** (`ensureTalkLinkage`) then guarantees it: for every talk
|
|
356
|
+
objective it creates any missing skin item, talk dialogue
|
|
357
|
+
(`quest-talk-<questCode>`), or NPC action mapping, and rewrites a
|
|
358
|
+
`questDialogueCodes` entry that points at a non-existent dialogue. Reruns where
|
|
359
|
+
the model already produced valid links are a no-op.
|
|
360
|
+
|
|
361
|
+
## Persistence
|
|
362
|
+
|
|
363
|
+
Documents are written sequentially with idempotent upserts (rerunnable):
|
|
364
|
+
|
|
365
|
+
| Section | Model | Upsert key |
|
|
366
|
+
| ------------- | ---------------------- | ---------------- |
|
|
367
|
+
| saga | `CyberiaSagaModel` | `code` |
|
|
368
|
+
| instance | `CyberiaInstanceModel` | `code` |
|
|
369
|
+
| maps | `CyberiaMapModel` | `code` |
|
|
370
|
+
| quests | `CyberiaQuestModel` | `code` |
|
|
371
|
+
| dialogues | `CyberiaDialogueModel` | `code` + `order` |
|
|
372
|
+
| actions | `CyberiaActionModel` | `code` |
|
|
373
|
+
| skills | `CyberiaSkillModel` | `triggerItemId` |
|
|
374
|
+
| object layers | `ObjectLayerModel` | `data.item.id` |
|
|
375
|
+
|
|
376
|
+
The **instance** refreshes its textual/logical fields every run but PRESERVES
|
|
377
|
+
`portals` and `conf` (set only on insert), so downstream spatial topology is
|
|
378
|
+
never clobbered — the same preservation contract `ObjectLayer` render/ledger
|
|
379
|
+
uses. **Skills** are upserted by `triggerItemId` into the `CyberiaSkill`
|
|
380
|
+
collection — the authoritative own-model source the gRPC server reads.
|
|
381
|
+
|
|
382
|
+
Both `generate` and `import` go through the same persistence path. Object-layer
|
|
383
|
+
items are written as real `ObjectLayer` documents so they are immediately
|
|
384
|
+
editable in `src/client/components/cyberia/ObjectLayerEngineViewer.js`:
|
|
385
|
+
|
|
386
|
+
- `data.render` is empty (`cid: null`, `metadataCid: null`) and the top-level
|
|
387
|
+
`cid` is `null` — there is no atlas yet;
|
|
388
|
+
- `data.ledger.type` is `OFF_CHAIN` (no on-chain token minted);
|
|
389
|
+
- `sha256` is computed over `data` with the canonical `computeSha256` helper.
|
|
390
|
+
|
|
391
|
+
The render and ledger are the **graphic/economic synthesis** stage and are set
|
|
392
|
+
later from the viewer. Re-running generate/import refreshes the textual
|
|
393
|
+
stats/item fields but **preserves any render or ledger already set** — it never
|
|
394
|
+
clobbers a populated render back to `null`. `saga.itemIds` records every item id.
|
|
@@ -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
|
-
```
|
|
24
|
-
engine-cyberia (Node.js)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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`
|
|
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
|
|
39
|
-
- **WebSocket binary
|
|
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
|
|
|
@@ -257,7 +266,8 @@ All content data (ObjectLayer metadata, asset blobs, optional client hints) is s
|
|
|
257
266
|
| --------------------------------- | ----------------- | -------------------------------------------------- |
|
|
258
267
|
| `ENGINE_GRPC_ADDRESS` | `localhost:50051` | engine-cyberia gRPC address (**required**) |
|
|
259
268
|
| `INSTANCE_CODE` | `default` | Instance code to load on startup |
|
|
260
|
-
| `ENGINE_API_BASE_URL` | _(empty)_ | engine-cyberia
|
|
269
|
+
| `ENGINE_API_BASE_URL` | _(empty)_ | Internal engine-cyberia origin (server→engine only) |
|
|
270
|
+
| `ENGINE_PUBLIC_URL` | _(empty)_ | Client-visible Content Authority origin (forwarded to clients) |
|
|
261
271
|
| `ENGINE_GRPC_RELOAD_INTERVAL_SEC` | _(disabled)_ | ObjectLayer hot-reload polling interval |
|
|
262
272
|
| `SERVER_PORT` | `8081` | WebSocket + HTTP listen port |
|
|
263
273
|
| `STATIC_DIR` | `./public` | Directory for static WASM client files |
|
|
@@ -276,3 +286,9 @@ go run main.go
|
|
|
276
286
|
go build -o cyberia-server .
|
|
277
287
|
./cyberia-server
|
|
278
288
|
```
|
|
289
|
+
|
|
290
|
+
### Test logx
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
go test ./logx/ -run TestResolveLevel
|
|
294
|
+
```
|
|
@@ -224,7 +224,7 @@ cyberia chain register / mint / transfer / burn / pause / unpause
|
|
|
224
224
|
|
|
225
225
|
# Named workflows
|
|
226
226
|
cyberia run-workflow import-default-items
|
|
227
|
-
cyberia run-workflow seed-
|
|
227
|
+
cyberia run-workflow seed-skills
|
|
228
228
|
cyberia run-workflow seed-dialogues
|
|
229
229
|
cyberia run-workflow build-manifest
|
|
230
230
|
cyberia run-workflow build-server-dashboard
|