cyberia 3.2.9 → 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.
- package/.github/workflows/engine-cyberia.cd.yml +7 -0
- package/.github/workflows/engine-cyberia.ci.yml +14 -2
- package/.github/workflows/ghpkg.ci.yml +1 -0
- package/.github/workflows/npmpkg.ci.yml +10 -5
- 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 +363 -1
- package/CLI-HELP.md +975 -1061
- package/README.md +190 -348
- package/bin/build.js +102 -125
- package/bin/build.template.js +33 -0
- package/bin/cyberia.js +238 -56
- package/bin/deploy.js +16 -3
- package/bin/index.js +238 -56
- package/bump.config.js +26 -0
- package/conf.js +131 -24
- package/deployment.yaml +76 -2
- package/hardhat/package-lock.json +113 -144
- package/hardhat/package.json +4 -3
- 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 +76 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -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 +31 -19
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +81 -46
- package/scripts/link-local-underpost-cli.sh +6 -0
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/scripts/test-monitor.sh +250 -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 +458 -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 +291 -294
- package/src/cli/env.js +1 -4
- package/src/cli/fs.js +13 -3
- package/src/cli/image.js +58 -4
- package/src/cli/index.js +127 -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 +396 -9
- package/src/cli/release.js +355 -146
- package/src/cli/repository.js +169 -30
- package/src/cli/run.js +347 -117
- 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 +14 -10
- 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/ACTION-SYSTEM.md +55 -1
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +223 -361
- 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 +212 -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/QUEST-SYSTEM.md +23 -1
- 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 +130 -21
- package/src/grpc/cyberia/grpc-server.js +25 -57
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +10 -7
- package/src/runtime/cyberia-client/Dockerfile.dev +67 -0
- package/src/runtime/cyberia-server/Dockerfile +11 -6
- package/src/runtime/cyberia-server/Dockerfile.dev +47 -0
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/wp/Dockerfile +3 -3
- package/src/runtime/wp/Wp.js +8 -5
- package/src/server/auth.js +2 -2
- package/src/server/catalog-underpost.js +61 -0
- package/src/server/catalog.js +77 -0
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build.js +94 -129
- package/src/server/conf.js +496 -135
- package/src/server/ipfs-client.js +5 -3
- package/src/server/process.js +180 -19
- package/src/server/proxy.js +9 -2
- package/src/server/runtime-status.js +235 -0
- package/src/server/runtime.js +1 -1
- package/src/server/start.js +44 -11
- 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/test/deploy-monitor.test.js +251 -0
- package/bin/file.js +0 -202
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
- package/manifests/deployment/dd-test-development/deployment.yaml +0 -254
- package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
- 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
|
@@ -13,7 +13,7 @@ import { DefaultManagement } from '../../services/default/default.management.js'
|
|
|
13
13
|
import { getApiBaseUrl } from '../../services/core/core.service.js';
|
|
14
14
|
import { ObjectLayerService } from '../../services/object-layer/object-layer.service.js';
|
|
15
15
|
import { getProxyPath } from '../core/Router.js';
|
|
16
|
-
import { ENTITY_TYPES, getDefaultCyberiaItemById } from '
|
|
16
|
+
import { ENTITY_TYPES, getDefaultCyberiaItemById } from './SharedDefaultsCyberia.js';
|
|
17
17
|
import '../core/ColorPaletteElement.js';
|
|
18
18
|
|
|
19
19
|
const DEFAULT_ENTITY_TYPE = ENTITY_TYPES.floor;
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Cyberia defaults — isomorphic, dependency-free, importable from
|
|
3
|
+
* **both** Node and the browser.
|
|
4
|
+
*
|
|
5
|
+
* Pure plain-data ESM module: no Node built-ins, no DOM APIs, no
|
|
6
|
+
* environment guards. Every export is a frozen literal, a constant
|
|
7
|
+
* lookup table, or a pure function over those tables. Side-effect free
|
|
8
|
+
* on import.
|
|
9
|
+
*
|
|
10
|
+
* Two responsibilities, no others:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Presentation values** — palette, entity colour keys, status-icon
|
|
13
|
+
* visuals (icon stem + border colour + bounce), camera tunings,
|
|
14
|
+
* render flags. Mirrored 1-to-1 by the C/WASM client's compile-time
|
|
15
|
+
* defaults in `cyberia-client/src/domain/presentation_defaults.h`.
|
|
16
|
+
* Optionally overridable per deployment through the REST endpoint
|
|
17
|
+
* `/api/cyberia-client-hints/:code`.
|
|
18
|
+
*
|
|
19
|
+
* 2. **Shared content vocabulary** — `ITEM_TYPES`, `ENTITY_TYPES`,
|
|
20
|
+
* `DefaultCyberiaItems` registry + lookups, type-to-item mapping,
|
|
21
|
+
* quest step / action type enums. The data shape both the
|
|
22
|
+
* browser-side editor UI and the engine REST controllers need to
|
|
23
|
+
* understand; it is **not** simulation state.
|
|
24
|
+
*
|
|
25
|
+
* STRICT BOUNDARIES
|
|
26
|
+
* -----------------
|
|
27
|
+
* - The cyberia-server (Go) MUST NOT load this file. None of these
|
|
28
|
+
* values influence the authoritative simulation. The server owns the
|
|
29
|
+
* numeric Entity Status Indicator IDs only (see `cyberia-server-defaults`).
|
|
30
|
+
*
|
|
31
|
+
* - The C/WASM cyberia-client embeds *presentation* defaults at compile
|
|
32
|
+
* time and fetches optional overrides through REST. It does NOT carry
|
|
33
|
+
* the JS vocabulary constants — entity-type and item-id strings
|
|
34
|
+
* arrive on the wire and are matched directly.
|
|
35
|
+
*
|
|
36
|
+
* - The browser editor bundles this file via esbuild. It MUST NOT
|
|
37
|
+
* import `cyberia-server-defaults.js` — that would pull simulation
|
|
38
|
+
* rules, economy, and seed content into the browser bundle. All
|
|
39
|
+
* shared vocabulary the editor needs lives here.
|
|
40
|
+
*
|
|
41
|
+
* Naming: this file is intentionally placed under `src/client/` so its
|
|
42
|
+
* URL is `/components/cyberia/SharedDefaultsCyberia.js` when the engine
|
|
43
|
+
* static server resolves it. Node-side importers reach in with a
|
|
44
|
+
* relative path; both halves see the same module instance.
|
|
45
|
+
*
|
|
46
|
+
* @module src/client/components/cyberia/SharedDefaultsCyberia.js
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
50
|
+
// Shared content vocabulary
|
|
51
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Canonical set of ObjectLayer item type names. Used as the
|
|
55
|
+
* `data.item.type` discriminator and as the asset directory name on disk.
|
|
56
|
+
*
|
|
57
|
+
* Values intentionally equal their keys — this is a string enum, not a
|
|
58
|
+
* z-order map. Render layer ordering lives in `entity_render.c`.
|
|
59
|
+
*
|
|
60
|
+
* @type {Readonly<Record<string,string>>}
|
|
61
|
+
*/
|
|
62
|
+
export const ITEM_TYPES = Object.freeze({
|
|
63
|
+
skin: 'skin',
|
|
64
|
+
breastplate: 'breastplate',
|
|
65
|
+
weapon: 'weapon',
|
|
66
|
+
skill: 'skill',
|
|
67
|
+
coin: 'coin',
|
|
68
|
+
floor: 'floor',
|
|
69
|
+
obstacle: 'obstacle',
|
|
70
|
+
portal: 'portal',
|
|
71
|
+
foreground: 'foreground',
|
|
72
|
+
resource: 'resource',
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Canonical set of entity category names used by the Go simulation,
|
|
77
|
+
* the C/WASM client, and the browser editor UI.
|
|
78
|
+
*
|
|
79
|
+
* @type {Readonly<Record<string,string>>}
|
|
80
|
+
*/
|
|
81
|
+
export const ENTITY_TYPES = Object.freeze({
|
|
82
|
+
player: 'player',
|
|
83
|
+
other_player: 'other_player',
|
|
84
|
+
bot: 'bot',
|
|
85
|
+
skill: 'skill',
|
|
86
|
+
coin: 'coin',
|
|
87
|
+
floor: 'floor',
|
|
88
|
+
obstacle: 'obstacle',
|
|
89
|
+
portal: 'portal',
|
|
90
|
+
foreground: 'foreground',
|
|
91
|
+
resource: 'resource',
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/** Per-entity-type allowlist of item types that may appear on the entity. */
|
|
95
|
+
export const ENTITY_TYPE_TO_ITEM_TYPES = Object.freeze({
|
|
96
|
+
[ENTITY_TYPES.player]: Object.freeze([ITEM_TYPES.skin, ITEM_TYPES.breastplate, ITEM_TYPES.weapon]),
|
|
97
|
+
[ENTITY_TYPES.other_player]: Object.freeze([ITEM_TYPES.skin, ITEM_TYPES.breastplate, ITEM_TYPES.weapon]),
|
|
98
|
+
[ENTITY_TYPES.bot]: Object.freeze([ITEM_TYPES.skin, ITEM_TYPES.weapon]),
|
|
99
|
+
[ENTITY_TYPES.skill]: Object.freeze([ITEM_TYPES.skill]),
|
|
100
|
+
[ENTITY_TYPES.coin]: Object.freeze([ITEM_TYPES.coin]),
|
|
101
|
+
[ENTITY_TYPES.floor]: Object.freeze([ITEM_TYPES.floor]),
|
|
102
|
+
[ENTITY_TYPES.obstacle]: Object.freeze([ITEM_TYPES.obstacle]),
|
|
103
|
+
[ENTITY_TYPES.portal]: Object.freeze([ITEM_TYPES.portal]),
|
|
104
|
+
[ENTITY_TYPES.foreground]: Object.freeze([ITEM_TYPES.foreground]),
|
|
105
|
+
[ENTITY_TYPES.resource]: Object.freeze([ITEM_TYPES.resource]),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/** Quest step objective types accepted by the quest-progress engine. */
|
|
109
|
+
export const QUEST_STEPS_TYPES = Object.freeze(['collect', 'talk', 'kill']);
|
|
110
|
+
|
|
111
|
+
/** Action categories accepted by the cyberia-action engine. */
|
|
112
|
+
export const CYBERIA_ACTION_TYPES = Object.freeze(['craft', 'shop', 'storage', 'talk', 'quest-talk']);
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Canonical (itemId → itemType) registry shipped with the engine. Used
|
|
116
|
+
* by the import-default-items seed, the on-chain ObjectLayerToken bridge,
|
|
117
|
+
* the fallback world generator, the CLI tooling, and the browser editor.
|
|
118
|
+
*
|
|
119
|
+
* Adding a new item here is the **only** place it needs to be declared.
|
|
120
|
+
*/
|
|
121
|
+
export const DefaultCyberiaItems = [
|
|
122
|
+
{ item: { id: 'coin', type: ITEM_TYPES.coin } },
|
|
123
|
+
{ item: { id: 'hatchet-skill', type: ITEM_TYPES.skill } },
|
|
124
|
+
{ item: { id: 'atlas_pistol_mk2', type: ITEM_TYPES.weapon } },
|
|
125
|
+
{ item: { id: 'atlas_pistol_mk2_bullet', type: ITEM_TYPES.skill } },
|
|
126
|
+
{ item: { id: 'tim-knife', type: ITEM_TYPES.weapon } },
|
|
127
|
+
{ item: { id: 'hatchet', type: ITEM_TYPES.weapon } },
|
|
128
|
+
{ item: { id: 'wason', type: ITEM_TYPES.skin } },
|
|
129
|
+
{ item: { id: 'scp-2040', type: ITEM_TYPES.skin } },
|
|
130
|
+
{ item: { id: 'purple', type: ITEM_TYPES.skin } },
|
|
131
|
+
{ item: { id: 'punk', type: ITEM_TYPES.skin } },
|
|
132
|
+
{ item: { id: 'lain', type: ITEM_TYPES.skin } },
|
|
133
|
+
{ item: { id: 'kaneki', type: ITEM_TYPES.skin } },
|
|
134
|
+
{ item: { id: 'junko', type: ITEM_TYPES.skin } },
|
|
135
|
+
{ item: { id: 'ghost', type: ITEM_TYPES.skin } },
|
|
136
|
+
{ item: { id: 'eiri', type: ITEM_TYPES.skin } },
|
|
137
|
+
{ item: { id: 'anon', type: ITEM_TYPES.skin } },
|
|
138
|
+
{ item: { id: 'alex', type: ITEM_TYPES.skin } },
|
|
139
|
+
{ item: { id: 'agent', type: ITEM_TYPES.skin } },
|
|
140
|
+
{ item: { id: 'grass', type: ITEM_TYPES.floor } },
|
|
141
|
+
{ item: { id: 'wood-1', type: ITEM_TYPES.resource } },
|
|
142
|
+
{ item: { id: 'wood-2', type: ITEM_TYPES.resource } },
|
|
143
|
+
{ item: { id: 'wood-extracted-1', type: ITEM_TYPES.resource } },
|
|
144
|
+
{ item: { id: 'wood-extracted-2', type: ITEM_TYPES.resource } },
|
|
145
|
+
{ item: { id: 'wood-drop-1', type: ITEM_TYPES.resource } },
|
|
146
|
+
{ item: { id: 'wood-drop-2', type: ITEM_TYPES.resource } },
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
const _ITEM_BY_ID = Object.freeze(
|
|
150
|
+
DefaultCyberiaItems.reduce((acc, entry) => {
|
|
151
|
+
acc[entry.item.id] = entry;
|
|
152
|
+
return acc;
|
|
153
|
+
}, {}),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
/** O(1) lookup: item id → registry entry, or `null` if unknown. */
|
|
157
|
+
export const getDefaultCyberiaItemById = (itemId) => _ITEM_BY_ID[itemId] || null;
|
|
158
|
+
|
|
159
|
+
/** All registry entries of a given item type. */
|
|
160
|
+
export const getDefaultCyberiaItemsByItemType = (itemType) =>
|
|
161
|
+
DefaultCyberiaItems.filter((entry) => entry.item.type === itemType);
|
|
162
|
+
|
|
163
|
+
/** All registry entries whose item type is permitted on a given entity type. */
|
|
164
|
+
export const getDefaultCyberiaItemsByEntityType = (entityType) => {
|
|
165
|
+
const allowed = ENTITY_TYPE_TO_ITEM_TYPES[entityType] || [];
|
|
166
|
+
return DefaultCyberiaItems.filter((entry) => allowed.includes(entry.item.type));
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
170
|
+
// Presentation defaults
|
|
171
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Named colour palette. Solid-color fallbacks for entity types, plus
|
|
175
|
+
* UI-only entries (WEAPON, SELF_BORDER) the renderer uses for HUD.
|
|
176
|
+
*
|
|
177
|
+
* Keys are stable identifiers shared with the C client's local palette.
|
|
178
|
+
* Adding a new key here requires adding it to
|
|
179
|
+
* `cyberia-client/src/domain/presentation_defaults.h` to keep parity.
|
|
180
|
+
*
|
|
181
|
+
* @type {ReadonlyArray<{key:string,r:number,g:number,b:number,a:number}>}
|
|
182
|
+
*/
|
|
183
|
+
export const PALETTE = Object.freeze([
|
|
184
|
+
{ key: 'BACKGROUND', r: 30, g: 30, b: 30, a: 255 },
|
|
185
|
+
{ key: 'FLOOR_BACKGROUND', r: 45, g: 45, b: 45, a: 255 },
|
|
186
|
+
{ key: 'FLOOR', r: 60, g: 60, b: 60, a: 255 },
|
|
187
|
+
{ key: 'OBSTACLE', r: 80, g: 80, b: 80, a: 255 },
|
|
188
|
+
{ key: 'PORTAL', r: 0, g: 200, b: 200, a: 255 },
|
|
189
|
+
{ key: 'PORTAL_INTER_PORTAL', r: 0, g: 200, b: 200, a: 255 },
|
|
190
|
+
{ key: 'PORTAL_INTER_RANDOM', r: 80, g: 130, b: 255, a: 255 },
|
|
191
|
+
{ key: 'PORTAL_INTRA_RANDOM', r: 220, g: 200, b: 50, a: 255 },
|
|
192
|
+
{ key: 'PORTAL_INTRA_PORTAL', r: 200, g: 80, b: 200, a: 255 },
|
|
193
|
+
{ key: 'FOREGROUND', r: 255, g: 255, b: 255, a: 189 },
|
|
194
|
+
{ key: 'PLAYER', r: 0, g: 255, b: 0, a: 255 },
|
|
195
|
+
{ key: 'OTHER_PLAYER', r: 128, g: 128, b: 255, a: 255 },
|
|
196
|
+
{ key: 'BOT', r: 255, g: 128, b: 0, a: 255 },
|
|
197
|
+
{ key: 'GHOST', r: 200, g: 200, b: 255, a: 100 },
|
|
198
|
+
{ key: 'COIN', r: 255, g: 215, b: 0, a: 255 },
|
|
199
|
+
{ key: 'SKILL', r: 255, g: 255, b: 50, a: 255 },
|
|
200
|
+
{ key: 'RESOURCE', r: 100, g: 180, b: 80, a: 255 },
|
|
201
|
+
{ key: 'WEAPON', r: 180, g: 50, b: 50, a: 255 },
|
|
202
|
+
{ key: 'SELF_BORDER', r: 220, g: 190, b: 60, a: 240 },
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Per-entity-type palette key. Tells the client which palette entry to
|
|
207
|
+
* use as the solid-colour fallback for an entity that has no active
|
|
208
|
+
* ObjectLayer items.
|
|
209
|
+
*/
|
|
210
|
+
export const ENTITY_COLOR_KEYS = Object.freeze([
|
|
211
|
+
{ entityType: 'player', colorKey: 'PLAYER' },
|
|
212
|
+
{ entityType: 'other_player', colorKey: 'OTHER_PLAYER' },
|
|
213
|
+
{ entityType: 'bot', colorKey: 'BOT' },
|
|
214
|
+
{ entityType: 'skill', colorKey: 'SKILL' },
|
|
215
|
+
{ entityType: 'coin', colorKey: 'COIN' },
|
|
216
|
+
{ entityType: 'floor', colorKey: 'FLOOR' },
|
|
217
|
+
{ entityType: 'obstacle', colorKey: 'OBSTACLE' },
|
|
218
|
+
{ entityType: 'portal', colorKey: 'PORTAL' },
|
|
219
|
+
{ entityType: 'foreground', colorKey: 'FOREGROUND' },
|
|
220
|
+
{ entityType: 'resource', colorKey: 'RESOURCE' },
|
|
221
|
+
]);
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Camera and render-tuning defaults. Pure presentation — the cyberia-server
|
|
225
|
+
* never reads any of these. The cyberia-client fetches the whole bundle
|
|
226
|
+
* from /api/cyberia-client-hints/:CYBERIA_CLIENT_HINTS_CODE at startup
|
|
227
|
+
* and treats this object as the on-disk schema.
|
|
228
|
+
*
|
|
229
|
+
* cellSize — pixels per simulation cell on the client viewport.
|
|
230
|
+
* Authoritative server works in cell units; this value
|
|
231
|
+
* only governs how cells map to pixels for rendering.
|
|
232
|
+
* interpolationMs — render-time smoothing window for remote entities.
|
|
233
|
+
* Server ticks at TickRate, snapshots at SnapshotRate,
|
|
234
|
+
* client decides how to display the stream.
|
|
235
|
+
* defaultObjWidth /
|
|
236
|
+
* defaultObjHeight — default entity dimensions used by the world editor
|
|
237
|
+
* and the client when a doc omits dims. Presentation
|
|
238
|
+
* because dims-in-cells is just a visual sizing.
|
|
239
|
+
*/
|
|
240
|
+
export const RENDER_DEFAULTS = Object.freeze({
|
|
241
|
+
cellSize: 45,
|
|
242
|
+
defaultObjWidth: 1,
|
|
243
|
+
defaultObjHeight: 1,
|
|
244
|
+
cameraSmoothing: 0.1,
|
|
245
|
+
cameraZoom: 1.0,
|
|
246
|
+
defaultWidthScreenFactor: 1,
|
|
247
|
+
defaultHeightScreenFactor: 1,
|
|
248
|
+
interpolationMs: 100,
|
|
249
|
+
devUi: false,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Status-icon presentation half. The numeric `id` is shared with the
|
|
254
|
+
* simulation (it travels on the wire as a u8 inside the AOI binary
|
|
255
|
+
* entity-status indicator field). Everything else here — icon filename,
|
|
256
|
+
* border colour, bounce animation — is purely cosmetic and resolved on
|
|
257
|
+
* the client.
|
|
258
|
+
*
|
|
259
|
+
* IDs MUST stay aligned with `STATUS_ICONS` in `cyberia-server-defaults.js`.
|
|
260
|
+
*/
|
|
261
|
+
export const STATUS_ICONS_PRESENTATION = Object.freeze([
|
|
262
|
+
{ id: 0, iconId: null, bounce: false, borderColor: { r: 70, g: 70, b: 120, a: 200 } },
|
|
263
|
+
{ id: 1, iconId: 'arrow-down-gray', bounce: false, borderColor: { r: 130, g: 140, b: 160, a: 200 } },
|
|
264
|
+
{ id: 2, iconId: 'arrow-down-red', bounce: true, borderColor: { r: 210, g: 50, b: 50, a: 240 } },
|
|
265
|
+
{ id: 3, iconId: 'chat', bounce: true, borderColor: { r: 80, g: 160, b: 220, a: 240 } },
|
|
266
|
+
{ id: 4, iconId: 'arrow-down', bounce: false, borderColor: { r: 60, g: 190, b: 90, a: 240 } },
|
|
267
|
+
{ id: 5, iconId: 'skull', bounce: false, borderColor: { r: 160, g: 130, b: 200, a: 200 } },
|
|
268
|
+
{ id: 6, iconId: 'arrow-down-gray', bounce: false, borderColor: { r: 100, g: 180, b: 80, a: 220 } },
|
|
269
|
+
{ id: 7, iconId: 'clock', bounce: false, borderColor: { r: 160, g: 130, b: 200, a: 200 } },
|
|
270
|
+
{ id: 8, iconId: 'chat', bounce: true, borderColor: { r: 220, g: 190, b: 60, a: 240 } },
|
|
271
|
+
]);
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Build the full client-hints document for a given instance.
|
|
275
|
+
*
|
|
276
|
+
* @param {Object} [overrides] DB document fragments that may override
|
|
277
|
+
* palette colours, render defaults, status-icon iconIds, etc.
|
|
278
|
+
* Anything missing falls back to the canonical defaults exported here.
|
|
279
|
+
* @returns {Object} JSON-friendly client hints object.
|
|
280
|
+
*/
|
|
281
|
+
export function buildClientHints(overrides = {}) {
|
|
282
|
+
const ov = overrides || {};
|
|
283
|
+
|
|
284
|
+
// Palette merge: canonical first, DB overrides keyed by name, append any
|
|
285
|
+
// truly new keys at the end.
|
|
286
|
+
const dbColors = new Map((ov.colors || []).map((c) => [c.key, c]));
|
|
287
|
+
const palette = PALETTE.map((c) => {
|
|
288
|
+
const o = dbColors.get(c.key);
|
|
289
|
+
return o ? { key: c.key, r: o.r ?? c.r, g: o.g ?? c.g, b: o.b ?? c.b, a: o.a ?? c.a } : { ...c };
|
|
290
|
+
});
|
|
291
|
+
for (const [key, c] of dbColors) {
|
|
292
|
+
if (!palette.some((p) => p.key === key)) {
|
|
293
|
+
palette.push({ key, r: c.r ?? 0, g: c.g ?? 0, b: c.b ?? 0, a: c.a ?? 255 });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Status icons: only iconId is overridable. Border colour stays canonical
|
|
298
|
+
// because the DB schema defaults for that field are placeholder values.
|
|
299
|
+
const dbIcons = new Map((ov.statusIcons || []).map((s) => [s.id, s]));
|
|
300
|
+
const statusIcons = STATUS_ICONS_PRESENTATION.map((canon) => {
|
|
301
|
+
const o = dbIcons.get(canon.id);
|
|
302
|
+
return {
|
|
303
|
+
id: canon.id,
|
|
304
|
+
iconId: (o && o.iconId) || canon.iconId || '',
|
|
305
|
+
bounce: canon.bounce,
|
|
306
|
+
borderColor: { ...canon.borderColor },
|
|
307
|
+
};
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
palette,
|
|
312
|
+
entityColorKeys: ENTITY_COLOR_KEYS.map((e) => ({ ...e })),
|
|
313
|
+
statusIcons,
|
|
314
|
+
cellSize: ov.cellSize ?? RENDER_DEFAULTS.cellSize,
|
|
315
|
+
defaultObjWidth: ov.defaultObjWidth ?? RENDER_DEFAULTS.defaultObjWidth,
|
|
316
|
+
defaultObjHeight: ov.defaultObjHeight ?? RENDER_DEFAULTS.defaultObjHeight,
|
|
317
|
+
cameraSmoothing: ov.cameraSmoothing ?? RENDER_DEFAULTS.cameraSmoothing,
|
|
318
|
+
cameraZoom: ov.cameraZoom ?? RENDER_DEFAULTS.cameraZoom,
|
|
319
|
+
defaultWidthScreenFactor: ov.defaultWidthScreenFactor ?? RENDER_DEFAULTS.defaultWidthScreenFactor,
|
|
320
|
+
defaultHeightScreenFactor: ov.defaultHeightScreenFactor ?? RENDER_DEFAULTS.defaultHeightScreenFactor,
|
|
321
|
+
interpolationMs: ov.interpolationMs ?? RENDER_DEFAULTS.interpolationMs,
|
|
322
|
+
devUi: ov.devUi ?? RENDER_DEFAULTS.devUi,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Canonical hints document — what the client gets when no DB overrides
|
|
328
|
+
* exist (or the engine endpoint is unreachable).
|
|
329
|
+
*/
|
|
330
|
+
export const CYBERIA_CLIENT_HINTS_DEFAULTS = buildClientHints({});
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
The Action System defines how NPC entities interact with players. An **Action** is a spatial, typed payload attached to a map entity that the player activates by tapping the NPC. Actions drive dialogue, shops, crafting, storage, and quest grant events.
|
|
10
10
|
|
|
11
|
-
> **Implementation status —
|
|
11
|
+
> **Implementation status — Alpha (talk / quest-talk):** The CyberiaAction and CyberiaDialogue MongoDB schemas and Engine REST API (`src/api/cyberia-action`, `src/api/cyberia-dialogue`) are defined. The `talk` and `quest-talk` paths are wired end-to-end: the Go server binds actions to entities at instance init, validates dialogue completion, grants quests, and advances `talk` objectives (see **Dialogue Interaction Protocol** below). Shop / craft / storage transaction processing remains planned for a later Alpha increment. The `freeze_start`/`freeze_end` WS messages for modal protection are implemented; dialogue freeze now rides on the `dlg_*` frames.
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -154,6 +154,60 @@ sequenceDiagram
|
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
|
+
## Dialogue Interaction Protocol (talk / quest-talk)
|
|
158
|
+
|
|
159
|
+
Tapping an interaction bubble opens the Raylib-native **`modal_interact`** modal
|
|
160
|
+
first — the general-purpose entry point. Its `[Talk]` tab (shown only when the
|
|
161
|
+
entity has dialogue) opens `modal_dialogue`; its `[Chat / Profile]` tab opens the
|
|
162
|
+
JS overlay with no freeze.
|
|
163
|
+
|
|
164
|
+
The client is identical for `talk` and `quest-talk`; the **server** branches after
|
|
165
|
+
`dlg_complete`. The client never declares the action type, quest code, or quest
|
|
166
|
+
dialogue codes — the server resolves the bound action from its own
|
|
167
|
+
`entityId → CyberiaAction` cache (bound at instance init).
|
|
168
|
+
|
|
169
|
+
### Wire messages
|
|
170
|
+
|
|
171
|
+
| Direction | Message | When | Payload |
|
|
172
|
+
| --------- | -------------- | ------------------------------------- | ------------------------------------ |
|
|
173
|
+
| C → S | `dlg_start` | `modal_dialogue` opens | `{ entityId, itemId }` |
|
|
174
|
+
| C → S | `dlg_complete` | player reads all lines, closes | `{ entityId, itemId, dialogCode }` |
|
|
175
|
+
| C → S | `dlg_cancel` | player dismisses early (✕ / outside) | `{ entityId, itemId }` |
|
|
176
|
+
| S → C | `dlg_ack` | after `dlg_complete` is processed | `{ questGranted, objectivesDone, quests[] }` |
|
|
177
|
+
|
|
178
|
+
Binary uplink opcodes: `dlg_start` `0x17`, `dlg_complete` `0x18`, `dlg_cancel`
|
|
179
|
+
`0x19` (JSON aliases of the same names are also accepted).
|
|
180
|
+
|
|
181
|
+
`dlg_ack` is notify-only — it carries the affected quest snapshot entries the
|
|
182
|
+
client upserts into its local `quest_store` (Quest Journal); it never gates
|
|
183
|
+
simulation state.
|
|
184
|
+
|
|
185
|
+
### Server `dlg_complete` handling
|
|
186
|
+
|
|
187
|
+
1. Validate `player.activeDialogueEntityID == msg.entityId`; drop otherwise.
|
|
188
|
+
2. Clear the dialogue context and thaw the player (modal protection off).
|
|
189
|
+
3. Resolve the action from `actionCache[entityId]`. `talk` → ack only.
|
|
190
|
+
4. `quest-talk`: on first contact grant `grantQuestCode`; then for every active
|
|
191
|
+
quest whose **current step** has a `{ type: 'talk', itemId == provideItemId }`
|
|
192
|
+
objective, increment it — **only** when `msg.dialogCode` is in the action's
|
|
193
|
+
`questDialogueCodes`. On quest completion, deliver rewards (FCT) and unlock
|
|
194
|
+
successors.
|
|
195
|
+
|
|
196
|
+
> **Dialogue-code contract.** The C client fetches dialogue groups at
|
|
197
|
+
> `/api/cyberia-dialogue/code/default-<itemId>`, so the code it reports on
|
|
198
|
+
> `dlg_complete` is `default-<provideItemId>`. For a `quest-talk` objective to
|
|
199
|
+
> advance, the action's `questDialogueCodes` must contain that code.
|
|
200
|
+
|
|
201
|
+
### Freeze semantics
|
|
202
|
+
|
|
203
|
+
| Event | Player state |
|
|
204
|
+
| ---------------------------------- | ------------------------- |
|
|
205
|
+
| `modal_interact` open | Active (no freeze) |
|
|
206
|
+
| `dlg_start` sent | Frozen — immune to damage |
|
|
207
|
+
| `dlg_complete` / `dlg_cancel` sent | Unfrozen |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
157
211
|
## Spatial Binding and Instance Init
|
|
158
212
|
|
|
159
213
|
`sourceMapCode + sourceCellX + sourceCellY` links an Action to a specific entity cell in a specific map. During instance initialization:
|