cyberia 3.2.9 → 3.2.12
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/.github/workflows/engine-cyberia.cd.yml +6 -0
- package/.github/workflows/npmpkg.ci.yml +1 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -0
- package/.vscode/extensions.json +9 -9
- package/.vscode/settings.json +20 -4
- package/CHANGELOG.md +213 -1
- package/CLI-HELP.md +92 -23
- package/README.md +190 -348
- package/bin/build.js +24 -8
- package/bin/build.template.js +187 -0
- package/bin/cyberia.js +229 -52
- package/bin/deploy.js +12 -2
- package/bin/index.js +229 -52
- package/bump.config.js +26 -0
- package/conf.js +130 -24
- package/deployment.yaml +4 -2
- package/hardhat/package-lock.json +113 -144
- package/hardhat/package.json +4 -3
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +4 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +4 -2
- package/manifests/kind-config-dev.yaml +8 -0
- package/manifests/lxd/lxd-admin-profile.yaml +12 -3
- package/manifests/mongodb/pv-pvc.yaml +44 -8
- package/manifests/mongodb/statefulset.yaml +55 -68
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +3 -1
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/valkey/statefulset.yaml +1 -1
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/package.json +27 -15
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +81 -46
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +38 -33
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +16 -16
- package/src/api/core/core.router.js +19 -14
- package/src/api/core/core.service.js +5 -5
- package/src/api/crypto/crypto.router.js +18 -12
- package/src/api/crypto/crypto.service.js +3 -3
- package/src/api/cyberia-action/cyberia-action.model.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +22 -18
- package/src/api/cyberia-action/cyberia-action.service.js +5 -5
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +74 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +99 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +98 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +25 -20
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +6 -6
- package/src/api/cyberia-entity/cyberia-entity.router.js +22 -18
- package/src/api/cyberia-entity/cyberia-entity.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-fallback-world.js +79 -4
- package/src/api/cyberia-instance/cyberia-instance.router.js +57 -52
- package/src/api/cyberia-instance/cyberia-instance.service.js +10 -10
- package/src/api/cyberia-instance/cyberia-world-generator.js +3 -3
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +14 -48
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +22 -18
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +5 -5
- package/src/api/cyberia-map/cyberia-map.router.js +35 -30
- package/src/api/cyberia-map/cyberia-map.service.js +7 -7
- package/src/api/cyberia-quest/cyberia-quest.model.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +22 -18
- package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +22 -18
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +5 -5
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +451 -0
- package/src/api/default/default.router.js +22 -18
- package/src/api/default/default.service.js +5 -5
- package/src/api/document/document.router.js +28 -23
- package/src/api/document/document.service.js +100 -23
- package/src/api/file/file.router.js +19 -13
- package/src/api/file/file.service.js +9 -7
- package/src/api/instance/instance.router.js +29 -24
- package/src/api/instance/instance.service.js +6 -6
- package/src/api/ipfs/ipfs.router.js +21 -16
- package/src/api/ipfs/ipfs.service.js +8 -8
- package/src/api/object-layer/object-layer.router.js +512 -507
- package/src/api/object-layer/object-layer.service.js +17 -14
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +22 -18
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +5 -5
- package/src/api/test/test.router.js +17 -12
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +5 -4
- package/src/api/user/user.router.js +297 -288
- package/src/api/user/user.service.js +100 -35
- package/src/cli/baremetal.js +132 -101
- package/src/cli/cluster.js +700 -232
- package/src/cli/db.js +59 -60
- package/src/cli/deploy.js +216 -137
- package/src/cli/fs.js +13 -3
- package/src/cli/index.js +80 -15
- package/src/cli/ipfs.js +4 -6
- package/src/cli/kubectl.js +4 -1
- package/src/cli/lxd.js +1099 -223
- package/src/cli/monitor.js +9 -3
- package/src/cli/release.js +334 -140
- package/src/cli/repository.js +68 -23
- package/src/cli/run.js +193 -49
- package/src/cli/secrets.js +11 -2
- package/src/cli/test.js +9 -3
- package/src/client/Default.index.js +9 -3
- package/src/client/components/core/Auth.js +5 -0
- package/src/client/components/core/ClientEvents.js +76 -0
- package/src/client/components/core/EventBus.js +4 -0
- package/src/client/components/core/Modal.js +82 -41
- package/src/client/components/core/PanelForm.js +56 -52
- package/src/client/components/core/Worker.js +162 -363
- package/src/client/components/cyberia/MapEngineCyberia.js +1 -1
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +330 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +50 -410
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +114 -327
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +200 -222
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +203 -185
- package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +2 -2
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-client-hints/cyberia-client-hints.service.js +99 -0
- package/src/client/ssr/views/CyberiaServerMetrics.js +982 -0
- package/src/client/sw/core.sw.js +174 -112
- package/src/db/DataBaseProvider.js +115 -15
- package/src/db/mariadb/MariaDB.js +2 -1
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +129 -21
- package/src/grpc/cyberia/grpc-server.js +25 -57
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +24 -3
- package/src/runtime/cyberia-client/Dockerfile.dev +82 -0
- package/src/runtime/cyberia-server/Dockerfile +29 -4
- package/src/runtime/cyberia-server/Dockerfile.dev +71 -0
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/wp/Wp.js +8 -5
- package/src/server/auth.js +2 -2
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build.js +94 -129
- package/src/server/conf.js +86 -83
- package/src/server/process.js +180 -19
- package/src/server/proxy.js +9 -2
- package/src/server/runtime.js +1 -1
- package/src/server/start.js +17 -5
- package/src/server/valkey.js +2 -0
- package/src/ws/IoInterface.js +16 -16
- package/src/ws/core/channels/core.ws.chat.js +11 -11
- package/src/ws/core/channels/core.ws.mailer.js +29 -29
- package/src/ws/core/channels/core.ws.stream.js +19 -19
- package/src/ws/core/core.ws.connection.js +8 -8
- package/src/ws/core/core.ws.server.js +6 -5
- package/src/ws/default/channels/default.ws.main.js +10 -10
- package/src/ws/default/default.ws.connection.js +4 -4
- package/src/ws/default/default.ws.server.js +4 -3
- package/bin/file.js +0 -202
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +0 -574
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +0 -467
- package/src/client/ssr/email/DefaultRecoverEmail.js +0 -21
- package/src/client/ssr/email/DefaultVerifyEmail.js +0 -17
- package/src/client/ssr/pages/CyberiaServerMetrics.js +0 -461
- /package/src/client/ssr/{offline → views}/Maintenance.js +0 -0
- /package/src/client/ssr/{offline → views}/NoNetworkConnection.js +0 -0
- /package/src/client/ssr/{pages → views}/Test.js +0 -0
|
@@ -1,269 +1,252 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://www.cyberiaonline.com/assets/splash/apple-touch-icon-precomposed.png" alt="CYBERIA online"/>
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<div align="center">
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<h1>cyberia client</h1>
|
|
8
|
+
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
**Path:** `cyberia-client/` · **Language:** C11/GNU11 → WebAssembly (Emscripten) · **Role:** presentation runtime for Cyberia
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
`cyberia-client` is the rendering and interactive runtime for the Cyberia MMO extension on Underpost Platform. It captures input, predicts the local player, reconciles against authoritative snapshots, interpolates remote entities, and renders the world. It owns the render policy locally.
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
It is **not** a world-simulation authority. The authoritative simulation runs on `cyberia-server`. Persistent content and asset metadata come from `engine-cyberia` via REST.
|
|
10
16
|
|
|
11
17
|
---
|
|
12
18
|
|
|
13
|
-
##
|
|
19
|
+
## Operating model
|
|
14
20
|
|
|
21
|
+
Three independent processes, non-overlapping roles. The ecosystem is playable only when all three are running and healthy at the same time.
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
engine-cyberia cyberia-server cyberia-client
|
|
25
|
+
content authority simulation authority presentation runtime
|
|
26
|
+
^ REST | WebSocket binary
|
|
27
|
+
| atlases, asset | snapshots (server -> client)
|
|
28
|
+
| metadata, optional | input cmds (client -> server)
|
|
29
|
+
| client hints v
|
|
30
|
+
`---------------- Browser tab: prediction, reconciliation, interpolation, render
|
|
15
31
|
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
│ │ │ AOI decoder ← binary_aoi_decoder.c │ │ │
|
|
28
|
-
│ │ │ ObjectLayer cache ← object_layer.c │ │ │
|
|
29
|
-
│ │ │ Texture manager ← texture_manager.c │ │ │
|
|
30
|
-
│ │ │ Game state ← game_state.c │ │ │
|
|
31
|
-
│ │ │ Network I/O ← network.c │ │ │
|
|
32
|
-
│ │ │ UI components ← modal.c, inventory_*.c│ │ │
|
|
33
|
-
│ │ └────────────────────────────────────────────────┘ │ │
|
|
34
|
-
│ └──────────────────────────────────────────────────────┘ │
|
|
35
|
-
│ │ WebSocket binary ↑ HTTP JSON │
|
|
36
|
-
└───────┼─────────────────────────────────┼──────────────────┘
|
|
37
|
-
│ │
|
|
38
|
-
▼ ▼
|
|
39
|
-
Go Game Server :8081 Engine REST API :4005
|
|
40
|
-
(AOI binary protocol) (atlas, file/blob, object-layer)
|
|
41
|
-
```
|
|
32
|
+
|
|
33
|
+
- Each service owns its own monitor and reconnector.
|
|
34
|
+
- The client reconnects to `cyberia-server` over WebSocket and fetches content from `engine-cyberia` over REST.
|
|
35
|
+
- If any of the three services is unhealthy, the game moves to standby until all three recover.
|
|
36
|
+
|
|
37
|
+
The client speaks two transports:
|
|
38
|
+
|
|
39
|
+
- **WebSocket binary** to `cyberia-server` for snapshots and input commands
|
|
40
|
+
- **REST** to `engine-cyberia` for atlas frames, asset blobs, and optional client-hints overrides
|
|
41
|
+
|
|
42
|
+
Asset distribution flows through Underpost Platform's static and PWA pipeline.
|
|
42
43
|
|
|
43
44
|
---
|
|
44
45
|
|
|
45
|
-
##
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
| `object_layers_management.c / object_layers_management.h` | ObjectLayer fetch pipeline (API → cache → render) |
|
|
59
|
-
| `texture_manager.c / texture_manager.h` | Atlas texture LRU cache keyed by IPFS CID |
|
|
60
|
-
| `layer_z_order.c / layer_z_order.h` | Z-order comparator for entity layer stack rendering |
|
|
61
|
-
| `serial.c / serial.h` | IDBFS-based persistent local storage |
|
|
62
|
-
| `input.c / input.h` | Mouse/touch event → game action translation |
|
|
63
|
-
| `tap_effect.c / tap_effect.h` | Visual tap ripple animation |
|
|
64
|
-
| `floating_combat_text.c / floating_combat_text.h` | FCT pop-up renderer (damage, regen, coin, item) |
|
|
65
|
-
| `interaction_bubble.c / interaction_bubble.h` | NPC interaction indicator bubble above entity |
|
|
66
|
-
| `entity_overhead_ui.c / entity_overhead_ui.h` | Name plates, HP bars above entities |
|
|
67
|
-
| `nameplate.c / nameplate.h` | Entity nameplate rendering |
|
|
68
|
-
| `inventory_bar.c / inventory_bar.h` | Equipped items bar (bottom of screen) |
|
|
69
|
-
| `inventory_modal.c / inventory_modal.h` | Full inventory grid modal |
|
|
70
|
-
| `modal.c / modal.h` | Base modal container (backdrop, open/close animation) |
|
|
71
|
-
| `modal_dialogue.c / modal_dialogue.h` | Dialogue modal — renders NPC conversation + choices |
|
|
72
|
-
| `modal_player.c / modal_player.h` | Player profile modal (stats, wallet, equipment) |
|
|
73
|
-
| `dialogue_data.c / dialogue_data.h` | Dialogue tree data structure |
|
|
74
|
-
| `ol_as_animated_ico.c / ol_as_animated_ico.h` | Render ObjectLayer as animated icon (inventory cells) |
|
|
75
|
-
| `ol_stack_ico.c / ol_stack_ico.h` | Render ObjectLayer stack as composite icon |
|
|
76
|
-
| `ui_icon.c / ui_icon.h` | Generic icon primitives |
|
|
77
|
-
| `dev_ui.c / dev_ui.h` | Development overlay (coords, FPS, entity count) |
|
|
78
|
-
| `helper.h` | Common macros and utility definitions |
|
|
79
|
-
| `config.h` | Compile-time configuration constants |
|
|
80
|
-
| `shell.html` | Emscripten HTML shell template |
|
|
81
|
-
| `js/services.js` | JS↔WASM bridge: fetch atlas, file blob, object-layer |
|
|
82
|
-
| `js/interact_overlay.js` | JS overlay for tap-to-interact element |
|
|
83
|
-
| `js/notify_badge.js` | Browser notification badge helper |
|
|
46
|
+
## Render loop
|
|
47
|
+
|
|
48
|
+
The render loop runs at vsync. Tick simulation is decoupled from render frames via a fixed-timestep accumulator. Step ordering inside one render frame:
|
|
49
|
+
|
|
50
|
+
1. **Optional client hints poll** — advance the asynchronous hints fetch state machine.
|
|
51
|
+
2. **Input capture** — drain raw OS events.
|
|
52
|
+
3. **Input dispatch** — UI hit-test → build typed input command (`kind`, `clientTick`, `sequence`, payload) → apply to prediction → send on the wire.
|
|
53
|
+
4. **Reconciliation** — apply latest snapshot's `lastAcked`: drop acknowledged input commands from the replay buffer; rewind predicted self to authoritative position; replay unacked input commands.
|
|
54
|
+
5. **Fixed-timestep prediction** — while accumulator ≥ `tickDuration`, advance prediction one tick.
|
|
55
|
+
6. **Interpolation** — compute remote-entity view positions at `renderTick = serverTickEstimate − INTERP_TICKS`.
|
|
56
|
+
7. **Render** — read view models; never mutate world state.
|
|
57
|
+
|
|
58
|
+
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.
|
|
84
59
|
|
|
85
60
|
---
|
|
86
61
|
|
|
87
|
-
##
|
|
62
|
+
## Module map
|
|
88
63
|
|
|
89
|
-
|
|
64
|
+
Directional dependency: from outermost (UI / render) inward toward `domain/`. Nothing in `domain/` imports outward.
|
|
90
65
|
|
|
91
66
|
```
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
67
|
+
src/
|
|
68
|
+
domain/
|
|
69
|
+
tick.h tick rate constants, monotonic types
|
|
70
|
+
presentation_runtime.{c,h} sole owner of presentation: async fetch of
|
|
71
|
+
/api/cyberia-client-hints/:CYBERIA_CLIENT_HINTS_CODE,
|
|
72
|
+
palette/status-icon/camera accessors, tiny
|
|
73
|
+
inline bootstrap fallback
|
|
74
|
+
input/
|
|
75
|
+
input_command.{c,h} typed InputCommand factory; sequence allocation
|
|
76
|
+
prediction/
|
|
77
|
+
prediction.{c,h} predicted self position; replay buffer; reconcile
|
|
78
|
+
interpolation/
|
|
79
|
+
interpolation.{c,h} remote entity view positions at renderTick
|
|
80
|
+
network/
|
|
81
|
+
session.{c,h} last server tick, last acked sequence, tick estimate
|
|
82
|
+
client.{c,h} WebSocket lifecycle + binary I/O
|
|
83
|
+
socket.{c,h} Emscripten WebSocket bridge
|
|
84
|
+
ui/ modals, HUD, inventory bar, FCT, nameplates
|
|
85
|
+
game_state.{c,h} world state mirror (gameplay subset only)
|
|
86
|
+
binary_aoi_decoder.{c,h} server snapshot parser
|
|
87
|
+
game_render.{c,h}, render.{c,h} render pipeline
|
|
88
|
+
main.c entry point + render loop
|
|
89
|
+
js/services.{js,c,h} REST fetch bridge (atlas, ui-icons, client-hints)
|
|
108
90
|
```
|
|
109
91
|
|
|
110
|
-
|
|
92
|
+
| Owner | Owns | Reads | Writes |
|
|
93
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
94
|
+
| `domain/presentation_runtime` | the entire presentation surface (palette, entity colour keys, status icons, camera, cell, interpolation). Inline bootstrap fallback while the fetch is in flight. | JSON response from `/api/cyberia-client-hints` | own table + one-shot hydration of `g_game_state.cell_size`, `.interpolation_ms`, `.camera.zoom` |
|
|
95
|
+
| `input/input_command` | typed InputCommand factory | session for tick + sequence | — |
|
|
96
|
+
| `prediction/` | predicted self position, input replay buffer | snapshot self + session ack | predicted self |
|
|
97
|
+
| `interpolation/` | remote entity `interp_pos` | snapshot history | remote `interp_pos` only |
|
|
98
|
+
| `network/session` | last server tick, last acked sequence | snapshot header | session singletons |
|
|
99
|
+
| `binary_aoi_decoder` | wire parser | binary frames | `game_state` + session + prediction (via callback) |
|
|
100
|
+
| `game_state` | gameplay world mirror | — | — |
|
|
101
|
+
| `render/`, `ui/` | rendering | view models | screen |
|
|
102
|
+
|
|
103
|
+
`game_state` holds only the gameplay subset of world state (entities, positions, life, AOI, equipment, frozen flag, coins). It does not carry palette state, status-icon visuals, or any other presentation field.
|
|
111
104
|
|
|
112
105
|
---
|
|
113
106
|
|
|
114
|
-
##
|
|
107
|
+
## Presentation ownership
|
|
115
108
|
|
|
116
|
-
|
|
109
|
+
The client owns its render policy. The authoritative server holds no presentation state.
|
|
117
110
|
|
|
118
|
-
|
|
119
|
-
| ------------ | ------ | ------------------- | ----------------------------------------- |
|
|
120
|
-
| `aoi_update` | `0x01` | `decode_aoi_update` | Delta AOI — entities entered/left view |
|
|
121
|
-
| `init_data` | `0x02` | `decode_init_data` | Full config on connect (JSON sub-payload) |
|
|
122
|
-
| `full_aoi` | `0x03` | `decode_full_aoi` | Full AOI snapshot |
|
|
123
|
-
| `FCT` | `0x04` | `decode_fct` | Floating Combat Text (14-byte fixed) |
|
|
124
|
-
| `ItemFCT` | `0x05` | `decode_item_fct` | Item FCT with string item ID (variable) |
|
|
111
|
+
Three layers, strictly inward-dependent:
|
|
125
112
|
|
|
126
|
-
|
|
113
|
+
1. **`domain/presentation_runtime.{c,h}`** — sole owner of every presentation value. Fires a single asynchronous GET against `/api/cyberia-client-hints/:CYBERIA_CLIENT_HINTS_CODE` at startup, polled once per render frame. When the response settles, parses palette, entity colour keys, status-icon visuals, and camera/cell tunings into a process-local table and writes a one-shot hydration into `g_game_state` (cell_size, interpolation_ms, camera.zoom). The C client carries NO compile-time palette or status table — only a tiny inline neutral-grey bootstrap so the splash screen has something to draw while the fetch is in flight. The canonical schema for the response lives at engine-cyberia's `src/client/components/cyberia/SharedDefaultsCyberia.js`.
|
|
114
|
+
2. **Renderers** — call `presentation_runtime_palette("KEY")`, `presentation_runtime_status_icon(u8)`, `presentation_runtime_status_border(u8)`, `presentation_runtime_entity_fallback_color(entity_type)` at each use site.
|
|
127
115
|
|
|
128
|
-
|
|
116
|
+
What lives in this layer:
|
|
129
117
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
| ItemLoss | `0x05` | Purple |
|
|
118
|
+
- Named palette (colors).
|
|
119
|
+
- Per-entity-type fallback color keys.
|
|
120
|
+
- Status-icon visual table (icon stem + border color per numeric ID).
|
|
121
|
+
- Camera smoothing / zoom defaults.
|
|
122
|
+
- Interpolation window.
|
|
123
|
+
- Dev-overlay flag.
|
|
124
|
+
- Viewport screen factors.
|
|
138
125
|
|
|
139
|
-
|
|
126
|
+
What does **not** travel on the WebSocket init or AOI streams:
|
|
140
127
|
|
|
141
|
-
|
|
128
|
+
- Palette.
|
|
129
|
+
- Camera knobs.
|
|
130
|
+
- Dev-overlay flag.
|
|
131
|
+
- Interpolation window.
|
|
132
|
+
- Status-icon visuals.
|
|
133
|
+
- Per-entity-type color keys.
|
|
142
134
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
Fetch pipeline per item ID:
|
|
147
|
-
1. Check LRU cache → hit? return immediately
|
|
148
|
-
2. Call JS bridge: services.fetchObjectLayer(itemId)
|
|
149
|
-
→ GET {API_BASE_URL}/api/object-layer/{itemId}
|
|
150
|
-
3. Parse JSON response → populate ObjectLayerMetadata
|
|
151
|
-
4. Evict LRU entry if cache full → insert new entry
|
|
152
|
-
5. Trigger texture fetch for each layer CID
|
|
153
|
-
```
|
|
135
|
+
The numeric status-icon u8 still rides on the AOI wire — that is the protocol-level half. The icon stem and border color are presentation and are resolved entirely on the client.
|
|
154
136
|
|
|
155
|
-
|
|
137
|
+
### Optional client hints
|
|
156
138
|
|
|
157
|
-
|
|
139
|
+
`GET /api/cyberia-client-hints/:instanceCode` (engine-cyberia REST, **not** cyberia-server) returns a JSON document mirroring the structure of the compile-time defaults. The client is required to function with no successful call to this endpoint:
|
|
158
140
|
|
|
159
|
-
`
|
|
141
|
+
- 200 with `{ palette, entityColorKeys, statusIcons, cameraSmoothing, cameraZoom, defaultWidthScreenFactor, defaultHeightScreenFactor, interpolationMs, devUi }` — overrides applied on top of defaults.
|
|
142
|
+
- 404 if the instance has no overrides — defaults are used.
|
|
143
|
+
- Network error — defaults are used.
|
|
160
144
|
|
|
161
|
-
|
|
162
|
-
Fetch pipeline per CID:
|
|
163
|
-
1. Check cache by CID → hit? return Texture2D*
|
|
164
|
-
2. Call JS bridge: services.fetchFileBlob(cid)
|
|
165
|
-
→ GET {API_BASE_URL}/api/file/blob/{cid}
|
|
166
|
-
3. Decode PNG blob → Raylib Image → Texture2D (GPU upload)
|
|
167
|
-
4. Evict LRU on full cache → insert new entry
|
|
168
|
-
```
|
|
145
|
+
No authentication; presentation hints are not secret. The Go authoritative server never calls this endpoint.
|
|
169
146
|
|
|
170
147
|
---
|
|
171
148
|
|
|
172
|
-
##
|
|
149
|
+
## Tick-aware components
|
|
173
150
|
|
|
174
|
-
|
|
151
|
+
### Session
|
|
175
152
|
|
|
176
|
-
|
|
177
|
-
| ------------------------------- | ------------------------------------------------------------ |
|
|
178
|
-
| Tap empty tile | Send `tap_move` WS message → player moves to cell |
|
|
179
|
-
| Tap entity (NPC/resource) | Send `tap_entity` WS message → server dispatches interaction |
|
|
180
|
-
| Tap inventory item | Toggle equip/unequip → send `item_activation` |
|
|
181
|
-
| Tap interact overlay (JS layer) | Opens action modal via `_c_open_dialogue_from_js` |
|
|
153
|
+
`network/session.{c,h}` tracks per-connection tick state:
|
|
182
154
|
|
|
183
|
-
`
|
|
155
|
+
- `last_server_tick` — highest snapshot tick observed.
|
|
156
|
+
- `last_acked_input_sequence` — highest sequence the server has applied for this client; echoed in every snapshot header.
|
|
157
|
+
- `next_input_sequence` — monotonic counter for outgoing input commands.
|
|
158
|
+
- `server_tick_estimate` — extrapolation of last server tick by elapsed wall time, used to stamp outgoing input commands and to compute `renderTick`.
|
|
184
159
|
|
|
185
|
-
|
|
160
|
+
### Prediction
|
|
186
161
|
|
|
187
|
-
|
|
162
|
+
`prediction/prediction.{c,h}` owns the predicted self position. It is the only writer of the predicted state. Internally it tracks **two** positions: the discrete per-tick `predicted_pos` (where the simulation says the player is) and the continuous render-frame `display_pos` (what the renderer reads). The renderer never sees the discrete value.
|
|
188
163
|
|
|
189
|
-
|
|
164
|
+
- `prediction_apply(cmd)` — optimistic local apply of an input command + push onto replay buffer.
|
|
165
|
+
- `prediction_step(dt)` — fixed-timestep advance, called by the accumulator. Mutates `predicted_pos` only.
|
|
166
|
+
- `prediction_reconcile()` — on snapshot arrival: drop acknowledged inputs, rewind self to authoritative position, replay unacked inputs. Mutates `predicted_pos` only.
|
|
167
|
+
- `prediction_display_step(frame_dt)` — per-render-frame exponential lerp of `display_pos` toward `predicted_pos`. This is the layer that absorbs reconcile snaps and sim-tick stepping so the visible main player moves continuously.
|
|
168
|
+
- `prediction_self_position()` — render-time accessor; returns the smoothed `display_pos`.
|
|
190
169
|
|
|
191
|
-
|
|
192
|
-
| --------------------------------- | --------------------------------------------- |
|
|
193
|
-
| `_c_send_ws_message(ptr, len)` | Send raw bytes over the WebSocket |
|
|
194
|
-
| `_c_open_dialogue_from_js(ptr)` | Open dialogue modal with serialized JSON |
|
|
195
|
-
| `_c_interact_overlay_did_close()` | Notify WASM that the JS overlay was dismissed |
|
|
170
|
+
### Interpolation
|
|
196
171
|
|
|
197
|
-
|
|
172
|
+
`interpolation/interpolation.{c,h}` owns remote-entity render-time positions. It is the only writer of remote `interp_pos`. It never touches the local player (prediction owns that). Sampling happens at `renderTick = serverTickEstimate − INTERP_TICKS`.
|
|
198
173
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
174
|
+
### Input command pipeline
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
mouse / touch / keyboard
|
|
178
|
+
│
|
|
179
|
+
▼
|
|
180
|
+
input/input_capture
|
|
181
|
+
│
|
|
182
|
+
▼
|
|
183
|
+
UI hit-test cascade ──► modal/inventory/HUD consumed?
|
|
184
|
+
│ no
|
|
185
|
+
▼
|
|
186
|
+
input_command_build_* stamps client_tick + sequence
|
|
187
|
+
│
|
|
188
|
+
▼
|
|
189
|
+
prediction_apply optimistic local apply
|
|
190
|
+
│
|
|
191
|
+
▼
|
|
192
|
+
uplink send WebSocket binary frame
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`InputCommand.Sequence` is allocated by `session_next_input_sequence`. Monotonic, never reused. The server echoes the highest applied sequence in every snapshot header; the prediction module drops acked commands from its replay buffer on reconciliation.
|
|
206
196
|
|
|
207
197
|
---
|
|
208
198
|
|
|
209
|
-
##
|
|
199
|
+
## Binary AOI snapshot format
|
|
200
|
+
|
|
201
|
+
The client decodes server-pushed AOI frames. Header (little-endian, 11 bytes for `0x01`/`0x03`):
|
|
210
202
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
| `MAX_LAYER_CACHE_SIZE` | `256` | Max ObjectLayer metadata entries in cache |
|
|
218
|
-
| `MAX_ATLAS_CACHE_SIZE` | `256` | Max atlas sprite sheet metadata entries |
|
|
219
|
-
| `DEFAULT_FRAME_DURATION_MS` | `100` | Default animation frame rate |
|
|
220
|
-
| `ENABLE_DEV_UI` | `false` | Force dev overlay on (override server setting) |
|
|
221
|
-
| `APP_VERSION` | `"1.0.0"` | Application version string |
|
|
203
|
+
```
|
|
204
|
+
[0] u8 msgType 0x01 aoi_update | 0x03 full_aoi
|
|
205
|
+
[1..4] u32 tick simulation tick at which the snapshot was produced
|
|
206
|
+
[5..8] u32 lastAcked highest InputCommand.Sequence applied for this client
|
|
207
|
+
[9..10] u16 entityCount entity blocks that follow
|
|
208
|
+
```
|
|
222
209
|
|
|
223
|
-
|
|
210
|
+
After parsing the header, the decoder invokes `session_on_snapshot(tick, lastAcked)` and then `prediction_reconcile()` so the predicted self stays consistent with the just-arrived authoritative state.
|
|
224
211
|
|
|
225
|
-
|
|
212
|
+
Other message types — init data (0x02), FCT (0x04), ItemFCT (0x05) — carry their own headers and are not part of the per-tick replication stream.
|
|
226
213
|
|
|
227
|
-
|
|
214
|
+
---
|
|
228
215
|
|
|
229
|
-
|
|
216
|
+
## REST fetches (engine-cyberia)
|
|
230
217
|
|
|
231
|
-
|
|
232
|
-
| ---------- | ------- | ----------------------------------- |
|
|
233
|
-
| Emscripten | ≥ 3.1 | C → WASM compiler + JS runtime |
|
|
234
|
-
| Raylib | ≥ 5.0 | Rendering (OpenGL ES2 via WebGL) |
|
|
235
|
-
| cJSON | 1.7.x | JSON parsing (ObjectLayer metadata) |
|
|
218
|
+
The client speaks REST directly to engine-cyberia for content. None of these calls go through cyberia-server.
|
|
236
219
|
|
|
237
|
-
|
|
220
|
+
| Endpoint | Purpose |
|
|
221
|
+
| ------------------------------------------------ | ------------------------------------ |
|
|
222
|
+
| `GET /api/atlas-sprite-sheet/metadata/:itemKey` | Frame layout JSON for a sprite atlas |
|
|
223
|
+
| `GET /api/atlas-sprite-sheet/blob/:itemKey` | Atlas PNG |
|
|
224
|
+
| `GET /api/object-layer/:itemId` | ObjectLayer JSON metadata |
|
|
225
|
+
| `GET /api/cyberia-dialogue/code/default-:itemId` | Dialogue lines for an NPC |
|
|
226
|
+
| `GET /assets/ui-icons/:iconId.png` | Status-bar icons |
|
|
227
|
+
| `GET /api/cyberia-client-hints/:instanceCode` | Optional presentation overrides |
|
|
238
228
|
|
|
239
|
-
|
|
229
|
+
All requests are CORS-simple GETs (no preflight) and cacheable. None require credentials.
|
|
240
230
|
|
|
241
|
-
|
|
242
|
-
| ----------------- | -------------------- | ----------------------------------------------- |
|
|
243
|
-
| `DEBUG` (default) | `-O0 -g --profiling` | Development — includes symbols, no optimization |
|
|
244
|
-
| `RELEASE` | `-O3 -DNDEBUG` | Production — fully optimized |
|
|
231
|
+
---
|
|
245
232
|
|
|
246
|
-
|
|
233
|
+
## Build and run
|
|
247
234
|
|
|
248
235
|
```bash
|
|
249
236
|
cd cyberia-client
|
|
250
237
|
|
|
251
|
-
#
|
|
252
|
-
make -f Web.mk
|
|
238
|
+
# Development build
|
|
239
|
+
make -f Web.mk clean && make -f Web.mk web
|
|
253
240
|
|
|
254
241
|
# Release build
|
|
255
|
-
make -f Web.mk BUILD_MODE=RELEASE
|
|
242
|
+
make -f Web.mk clean && make -f Web.mk web BUILD_MODE=RELEASE
|
|
256
243
|
|
|
257
244
|
# Build + serve on dev port :8082
|
|
258
245
|
make -f Web.mk serve-development
|
|
259
|
-
|
|
260
|
-
# Build release + serve on production port :8081
|
|
261
|
-
make -f Web.mk serve-production
|
|
262
|
-
|
|
263
|
-
# Clean build artifacts
|
|
264
|
-
make -f Web.mk clean
|
|
265
246
|
```
|
|
266
247
|
|
|
248
|
+
The build is part of the Underpost Platform static + PWA pipeline; production deploys go through `underpost client` and `underpost deploy`.
|
|
249
|
+
|
|
267
250
|
### Output
|
|
268
251
|
|
|
269
252
|
```
|
|
@@ -271,43 +254,38 @@ bin/
|
|
|
271
254
|
index.html — Emscripten HTML container (from shell.html template)
|
|
272
255
|
index.wasm — Compiled WebAssembly module
|
|
273
256
|
index.js — Emscripten JS glue
|
|
274
|
-
index.data — Preloaded data bundle
|
|
257
|
+
index.data — Preloaded data bundle
|
|
275
258
|
```
|
|
276
259
|
|
|
277
260
|
---
|
|
278
261
|
|
|
279
|
-
##
|
|
262
|
+
## Compile-time configuration
|
|
280
263
|
|
|
281
|
-
`
|
|
264
|
+
`src/config.h`:
|
|
282
265
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
266
|
+
| Constant | Default | Description |
|
|
267
|
+
| --------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
268
|
+
| `WS_URL` | `wss://server.cyberiaonline.com/ws` | WebSocket endpoint of cyberia-server |
|
|
269
|
+
| `API_BASE_URL` | `https://www.cyberiaonline.com` | engine-cyberia REST base URL |
|
|
270
|
+
| `CYBERIA_CLIENT_HINTS_CODE` | `cyberia-main` | Lookup key for the optional client-hints fetch (presentation override key — never an instance/server identifier) |
|
|
271
|
+
| `HTTP_TIMEOUT_SECONDS` | `10` | HTTP request timeout |
|
|
272
|
+
| `MAX_TEXTURE_CACHE_SIZE` | `512` | Atlas texture LRU cap |
|
|
273
|
+
| `MAX_LAYER_CACHE_SIZE` | `256` | ObjectLayer metadata LRU cap |
|
|
274
|
+
| `MAX_ATLAS_CACHE_SIZE` | `256` | Atlas metadata LRU cap |
|
|
275
|
+
| `DEFAULT_FRAME_DURATION_MS` | `100` | Default animation frame duration |
|
|
276
|
+
| `ENABLE_DEV_UI` | `false` | Force dev overlay regardless of presentation hints |
|
|
277
|
+
| `APP_VERSION` | `"1.0.0"` | Application version string |
|
|
286
278
|
|
|
287
|
-
|
|
279
|
+
For local development, point `WS_URL` and `API_BASE_URL` at `localhost` before rebuilding.
|
|
288
280
|
|
|
289
281
|
---
|
|
290
282
|
|
|
291
|
-
##
|
|
292
|
-
|
|
293
|
-
Change these two constants in `src/config.h` and rebuild:
|
|
294
|
-
|
|
295
|
-
```c
|
|
296
|
-
static const char* WS_URL = "ws://localhost:8081/ws";
|
|
297
|
-
static const char* API_BASE_URL = "http://localhost:4005";
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
Then:
|
|
283
|
+
## Persistent storage
|
|
301
284
|
|
|
302
|
-
|
|
303
|
-
# Terminal 1 — Engine (Node.js)
|
|
304
|
-
cd /path/to/engine && node src/index.js
|
|
285
|
+
`serial.c` uses Emscripten's IDBFS (IndexedDB File System) at `/persistent/` for:
|
|
305
286
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
# Terminal 3 — Client build + serve
|
|
310
|
-
cd cyberia-client && make -f Web.mk serve-development
|
|
311
|
-
```
|
|
287
|
+
- Player authentication token (EIP-712 signature).
|
|
288
|
+
- Local game settings (audio volume, key bindings).
|
|
289
|
+
- Cached ObjectLayer metadata (session warm-up cache).
|
|
312
290
|
|
|
313
|
-
|
|
291
|
+
No game state is persisted client-side; the authoritative server is the source of truth.
|