@underpostnet/cyberia 3.3.73 → 3.3.77
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 +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +10 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.ci.yml +1 -1
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +1 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +1 -1
- package/.github/workflows/engine-cyberia.ci.yml +1 -1
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/AGENTS.md +61 -12
- package/CHANGELOG.md +159 -161
- package/CLI-HELP.md +20 -13
- package/Dockerfile +1 -1
- package/Dockerfile.dev +1 -1
- package/Dockerfile.test +2 -2
- package/README.md +28 -28
- package/bin/build.js +96 -21
- package/bin/cyberia.js +1247 -1373
- package/bin/index.js +1247 -1373
- package/compose.env +17 -5
- package/conf.js +7 -4
- package/deploy/cyberia-client/deploy.sh +10 -11
- package/deploy/cyberia-client/package.sh +0 -1
- package/deploy/cyberia-client/state.sh +3 -2
- package/deploy/cyberia-server/deploy.sh +10 -11
- package/deploy/cyberia-server/package.sh +0 -1
- package/deploy/cyberia-server/state.sh +3 -2
- package/deploy/dd-cyberia/deploy.sh +5 -5
- package/deploy/dd-cyberia/init.sh +15 -14
- package/deploy/dd-cyberia/package.sh +0 -1
- package/deploy/dd-cyberia/state.sh +2 -2
- package/deploy/dd-cyberia/sync-deploy.sh +139 -75
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +92 -76
- package/deploy/lib/host.sh +28 -19
- package/deploy/lib/state.sh +4 -1
- package/deploy/pwa-microservices-template/deploy.sh +10 -8
- package/deploy/release/deploy.sh +0 -2
- package/deployment.yaml +1 -1
- package/docker-compose.yml +23 -17
- package/docs/coverage/cyberia/api/cyberia-instance/cyberia-fallback-capture.js.html +1591 -0
- package/docs/coverage/cyberia/api/cyberia-instance/index.html +116 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/cyberia-server-defaults.js.html +4138 -0
- package/docs/coverage/cyberia/api/cyberia-server-defaults/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/index.html +116 -0
- package/docs/coverage/cyberia/api/object-layer/object-layer.model.js.html +1393 -0
- package/docs/coverage/cyberia/base.css +362 -0
- package/docs/coverage/cyberia/block-navigation.js +82 -0
- package/docs/coverage/cyberia/favicon.png +0 -0
- package/docs/coverage/cyberia/index.html +161 -0
- package/docs/coverage/cyberia/prettify.css +101 -0
- package/docs/coverage/cyberia/prettify.js +937 -0
- package/docs/coverage/cyberia/projects/cyberia/atlas-sprite-sheet-generator.js.html +1315 -0
- package/docs/coverage/cyberia/projects/cyberia/index.html +176 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-backup.js.html +715 -0
- package/docs/coverage/cyberia/projects/cyberia/instance-data.js.html +2182 -0
- package/docs/coverage/cyberia/projects/cyberia/shape-generator.js.html +3265 -0
- package/docs/coverage/cyberia/projects/cyberia/stat-balance.js.html +328 -0
- package/docs/coverage/cyberia/sort-arrow-sprite.png +0 -0
- package/docs/coverage/cyberia/sorter.js +205 -0
- package/hardhat/package-lock.json +2 -2
- package/hardhat/package.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/mongo-express/deployment.yaml +46 -27
- package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
- package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
- package/manifests/deployment/mongo-express/service.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
- package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
- package/package.json +19 -17
- package/scripts/test-monitor.sh +3 -3
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +14 -9
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +88 -184
- package/src/api/cyberia-action/cyberia-action.router.js +2 -2
- package/src/api/cyberia-action/cyberia-action.service.js +3 -4
- package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
- package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
- package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
- package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -3
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +12 -34
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +15 -32
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +1 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +16 -1
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +466 -3
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +87 -51
- package/src/api/cyberia-instance/cyberia-fallback-world.js +21 -40
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +34 -141
- package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -4
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +3 -16
- package/src/api/cyberia-instance/cyberia-instance.service.js +3 -43
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +74 -1
- package/src/api/cyberia-map/cyberia-map.service.js +6 -2
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
- package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +3 -3
- package/src/api/cyberia-quest/cyberia-quest.service.js +3 -3
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -188
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- package/src/api/file/file.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- package/src/api/object-layer/object-layer.model.js +47 -12
- package/src/api/object-layer/object-layer.router.js +10 -3
- package/src/api/object-layer/object-layer.service.js +113 -120
- package/src/cli/app.js +12 -1
- package/src/cli/client.js +2 -2
- package/src/cli/cluster.js +80 -18
- package/src/cli/deploy.js +215 -34
- package/src/cli/docker-compose.js +1 -1
- package/src/cli/fs-selection.js +115 -0
- package/src/cli/fs.js +158 -342
- package/src/cli/index.js +22 -10
- package/src/cli/release.js +3 -1
- package/src/cli/repository.js +35 -9
- package/src/cli/run.js +80 -199
- package/src/cli/test.js +4 -0
- package/src/cli/wireguard.js +32 -31
- package/src/client/components/core/Badge.js +0 -1
- package/src/client/components/core/CssCore.js +8 -1
- package/src/client/components/core/Docs.js +77 -100
- package/src/client/components/core/Modal.js +77 -23
- package/src/client/components/core/ToolTip.js +15 -0
- package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +0 -2
- package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
- package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
- package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
- package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
- package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
- package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +0 -34
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +0 -4
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/components/default/AppShellDefault.js +1 -4
- package/src/client/components/itemledger/AppShellItemledger.js +0 -2
- package/src/client/components/underpost/AppShellUnderpost.js +1 -1
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +280 -24
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
- package/src/client/public/cyberia-docs/CYBERIA.md +28 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
- package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
- package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
- package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
- package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
- package/src/client/services/object-layer/object-layer.management.js +6 -10
- package/src/client/services/object-layer/object-layer.service.js +3 -1
- package/src/client/ssr/views/Cyberia404.js +3 -3
- package/src/client-builder/client-build-docs.js +52 -52
- package/src/client-builder/client-build.js +67 -44
- package/src/client-builder/client-bundle.js +347 -0
- package/src/db/mongo/MongoExpress.js +187 -0
- package/src/grpc/cyberia/grpc-server.js +5 -7
- package/src/index.js +1 -1
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +143 -146
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +5 -14
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +3 -2
- package/src/projects/cyberia/gemini-client.js +3 -3
- package/src/projects/cyberia/generate-saga.js +4 -11
- package/src/projects/cyberia/hot-reload-trigger.js +17 -28
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +177 -257
- package/src/projects/cyberia/map-preview-generator.js +32 -68
- package/src/projects/cyberia/object-layer.js +152 -319
- package/src/projects/cyberia/seed-audio.js +139 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
- package/src/projects/cyberia/semantic-layer-generator.js +2 -18
- package/src/projects/cyberia/stat-balance.js +81 -0
- package/src/projects/cyberia/stat-commands.js +23 -0
- package/src/projects/cyberia/stat-contract-generator.js +101 -0
- package/src/runtime/cyberia-client/Dockerfile +8 -4
- package/src/runtime/cyberia-client/Dockerfile.dev +5 -2
- package/src/runtime/cyberia-server/Dockerfile +9 -2
- package/src/runtime/cyberia-server/Dockerfile.dev +8 -1
- package/src/runtime/engine-cyberia/Dockerfile +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.dev +1 -1
- package/src/runtime/engine-cyberia/Dockerfile.test +2 -2
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- package/src/server/build/coverage.js +113 -42
- package/src/server/build/package.js +55 -12
- package/src/server/build/testing.js +59 -9
- package/src/server/network/middlewares.js +8 -2
- package/src/server/network/underpost-gateway.js +113 -14
- package/src/server/ops/logger.js +70 -35
- package/src/server/runtime/conf.js +40 -9
- package/src/server/runtime/start.js +11 -2
- package/src/server/storage/data-query.js +16 -0
- package/src/server/storage/downloader.js +62 -14
- package/src/server/storage/zip.js +153 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
- package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
- package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +34 -0
- package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
- package/test/integration/app/cyberia/cyberia-instance-conf-defaults.test.js +16 -22
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +6 -7
- package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
- package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
- package/test/integration/app/cyberia/fallback-world-capture.test.js +87 -2
- package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
- package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
- package/test/integration/app/cyberia/seed-audio.test.js +275 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +33 -9
- package/test/integration/infra/2-network/wireguard-edge.test.js +58 -18
- package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
- package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
- package/test/integration/infra/4-ingress/underpost-ingress.test.js +1 -1
- package/test/unit/catalog.test.js +13 -2
- package/test/unit/client-build-docs.test.js +97 -70
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-resolution.test.js +58 -7
- package/test/unit/coverage-artifact.test.js +120 -29
- package/test/unit/cyberia/instance-backup.test.js +183 -0
- package/test/unit/cyberia/instance-data.test.js +314 -0
- package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
- package/test/unit/cyberia/publish-workflow.test.js +22 -0
- package/test/unit/cyberia/stat-balance.test.js +69 -0
- package/test/unit/deploy-legacy-gateway-sweep.test.js +63 -0
- package/test/unit/deploy-log-table.test.js +76 -5
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/gateway-pod-fetch.test.js +95 -0
- package/test/unit/letsencrypt-issuer.test.js +101 -0
- package/test/unit/logger-redaction.test.js +29 -0
- package/test/unit/package.test.js +70 -16
- package/test/unit/prepare-host.test.js +84 -1
- package/test/unit/release-bump.test.js +3 -1
- package/test/unit/start-options.test.js +12 -0
- package/test/unit/test-tiers.test.js +27 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +11 -3
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { getFallbackMapCodes } from '../../api/cyberia-instance/cyberia-fallback-world.js';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_AUDIO_BANK,
|
|
7
|
+
DEFAULT_AUDIO_SETTINGS,
|
|
8
|
+
DEFAULT_MAP_MUSIC,
|
|
9
|
+
buildAudioEventBindings,
|
|
10
|
+
} from '../../api/cyberia-server-defaults/cyberia-server-defaults.js';
|
|
11
|
+
import { CyberiaAudioService } from '../../api/cyberia-audio/cyberia-audio.service.js';
|
|
12
|
+
import { CyberiaMapAudioConfService } from '../../api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js';
|
|
13
|
+
import { DataBaseProviderService } from '../../db/DataBaseProvider.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the canonical audio defaults against a list of map codes.
|
|
17
|
+
*
|
|
18
|
+
* The vocabulary, the bank and the bindings are owned by cyberia-server-defaults; this only states
|
|
19
|
+
* them per map. Every map of a world carries the same bed and the same bindings, so a world sounds
|
|
20
|
+
* like itself wherever the player stands, and what changes a place is the event that fires there.
|
|
21
|
+
*
|
|
22
|
+
* @param {string[]} mapCodes - Map codes the world declares.
|
|
23
|
+
* @returns {{assets: string[], settings: object, events: object[], maps: object[]}}
|
|
24
|
+
*/
|
|
25
|
+
const audioConfigForMaps = (mapCodes) => ({
|
|
26
|
+
// The codes the world needs imported; the client fetches every one of them by code.
|
|
27
|
+
assets: DEFAULT_AUDIO_BANK.map(({ code }) => code),
|
|
28
|
+
settings: DEFAULT_AUDIO_SETTINGS,
|
|
29
|
+
events: buildAudioEventBindings(),
|
|
30
|
+
maps: mapCodes.map((mapCode) => ({ mapCode, defaultMusic: DEFAULT_MAP_MUSIC })),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/** The canonical audio configuration of the fallback world. */
|
|
34
|
+
const fallbackAudioConfig = () => audioConfigForMaps(getFallbackMapCodes());
|
|
35
|
+
|
|
36
|
+
// The renderer lives in cyberia-audio, a sibling repository this one does not contain (see
|
|
37
|
+
// .gitignore, alongside cyberia-server and cyberia-client). Named once so the runtime and the
|
|
38
|
+
// suites that need real bytes ask the same question of the same path.
|
|
39
|
+
const AUDIO_RENDERER_URL = new URL('../../../cyberia-audio/src/dispatcher.js', import.meta.url);
|
|
40
|
+
|
|
41
|
+
/** Whether the cyberia-audio renderer is present beside this repository. */
|
|
42
|
+
const hasAudioRenderer = () => fs.existsSync(AUDIO_RENDERER_URL);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Loads the cyberia-audio dispatcher, or says plainly what is missing.
|
|
46
|
+
*
|
|
47
|
+
* A bare dynamic import fails here with a resolver message that names neither the project nor
|
|
48
|
+
* what to do about it, and a fresh checkout hits that before anything else.
|
|
49
|
+
*
|
|
50
|
+
* @returns {Promise<{dispatch: Function}>}
|
|
51
|
+
*/
|
|
52
|
+
async function loadAudioRenderer() {
|
|
53
|
+
if (!hasAudioRenderer()) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`cyberia-audio renderer not found at ${fileURLToPath(AUDIO_RENDERER_URL)}. It is a sibling ` +
|
|
56
|
+
'repository, not part of engine — clone it beside this one to record the audio bank.',
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return await import(AUDIO_RENDERER_URL.href);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Records the fallback audio the world needs, as `<code>.wav` + `<code>.json` pairs.
|
|
64
|
+
*
|
|
65
|
+
* Recording is where the bytes are produced and nowhere else: the client ships no audio and
|
|
66
|
+
* fetches every asset from engine-cyberia by code, so there is no bundle to build alongside these.
|
|
67
|
+
*
|
|
68
|
+
* @param {{recordsPath: string}} params - Output directory for the recorded pairs.
|
|
69
|
+
* @returns {Promise<object>} The fallback audio configuration these recordings satisfy.
|
|
70
|
+
*/
|
|
71
|
+
async function prepareFallbackAudio({ recordsPath }) {
|
|
72
|
+
const { dispatch } = await loadAudioRenderer();
|
|
73
|
+
const config = fallbackAudioConfig();
|
|
74
|
+
await fs.ensureDir(recordsPath);
|
|
75
|
+
for (const { code, bus, options } of DEFAULT_AUDIO_BANK) {
|
|
76
|
+
const output = path.resolve(recordsPath, `${code}.wav`);
|
|
77
|
+
await dispatch(bus, code, { sampleRate: 22050, ...options }, { play: false, record: true, path: output });
|
|
78
|
+
}
|
|
79
|
+
return config;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Imports the bank and writes one complete audio configuration per map.
|
|
84
|
+
*
|
|
85
|
+
* @param {object} config - As {@link audioConfigForMaps} resolves it.
|
|
86
|
+
* @param {{recordsPath: string}} params - Directory holding the recorded pairs.
|
|
87
|
+
* @param {{host: string, path: string}} options - Provider context.
|
|
88
|
+
* @returns {Promise<{assets: object[], maps: object[]}>}
|
|
89
|
+
*/
|
|
90
|
+
async function seedMapAudio(config, { recordsPath }, options) {
|
|
91
|
+
const assets = await CyberiaAudioService.importRecords({ recordsPath, codes: config.assets }, options);
|
|
92
|
+
if (assets.length !== config.assets.length) throw new Error('Seeding audio requires every WAV and manifest pair');
|
|
93
|
+
const maps = [];
|
|
94
|
+
for (const map of config.maps) {
|
|
95
|
+
// The seed states the whole configuration, so re-running it converges: a binding whose logic
|
|
96
|
+
// event this bank no longer declares is dropped rather than left behind pointing at an asset
|
|
97
|
+
// the client can no longer resolve.
|
|
98
|
+
maps.push(
|
|
99
|
+
await CyberiaMapAudioConfService.assign(
|
|
100
|
+
{ ...map, settings: config.settings, events: config.events, replaceEvents: true },
|
|
101
|
+
options,
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return { assets, maps };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const seedFallbackAudio = ({ recordsPath }, options) =>
|
|
109
|
+
seedMapAudio(fallbackAudioConfig(), { recordsPath }, options);
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Scores one instance's maps with the canonical bank.
|
|
113
|
+
*
|
|
114
|
+
* Every map the instance declares is scored with the same bank, bed and bindings the fallback
|
|
115
|
+
* world uses, so any world sounds the way that one does.
|
|
116
|
+
*
|
|
117
|
+
* @param {{instanceCode: string, recordsPath: string}} params - Target instance and records directory.
|
|
118
|
+
* @param {{host: string, path: string}} options - Provider context.
|
|
119
|
+
* @returns {Promise<{assets: object[], maps: object[]}>}
|
|
120
|
+
* @throws {Error} When the instance does not exist or declares no maps.
|
|
121
|
+
*/
|
|
122
|
+
async function seedInstanceAudio({ instanceCode, recordsPath }, options) {
|
|
123
|
+
const CyberiaInstance = DataBaseProviderService.getModel('CyberiaInstance', options);
|
|
124
|
+
const instance = await CyberiaInstance.findOne({ code: instanceCode }).select('cyberiaMapCodes').lean();
|
|
125
|
+
if (!instance) throw new Error(`cyberia-instance not found for code="${instanceCode}"`);
|
|
126
|
+
const mapCodes = instance.cyberiaMapCodes ?? [];
|
|
127
|
+
if (mapCodes.length === 0) throw new Error(`cyberia-instance "${instanceCode}" declares no maps`);
|
|
128
|
+
return seedMapAudio(audioConfigForMaps(mapCodes), { recordsPath }, options);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export {
|
|
132
|
+
audioConfigForMaps,
|
|
133
|
+
fallbackAudioConfig,
|
|
134
|
+
hasAudioRenderer,
|
|
135
|
+
loadAudioRenderer,
|
|
136
|
+
prepareFallbackAudio,
|
|
137
|
+
seedFallbackAudio,
|
|
138
|
+
seedInstanceAudio,
|
|
139
|
+
};
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
* @namespace SemanticLayerGeneratorSkin
|
|
29
29
|
*/
|
|
30
30
|
import { readFileSync } from 'fs';
|
|
31
|
+
import { STAT_DEFAULTS } from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
31
32
|
import path from 'path';
|
|
32
33
|
import { fileURLToPath } from 'url';
|
|
33
34
|
import crypto from 'crypto';
|
|
@@ -1070,14 +1071,7 @@ function generateSkinMultiFrame(options, _descriptor) {
|
|
|
1070
1071
|
description: `Procedurally generated character skin (seed: ${seed})`,
|
|
1071
1072
|
activable: true,
|
|
1072
1073
|
},
|
|
1073
|
-
stats: {
|
|
1074
|
-
effect: 0,
|
|
1075
|
-
resistance: 0,
|
|
1076
|
-
agility: 0,
|
|
1077
|
-
range: 0,
|
|
1078
|
-
intelligence: 0,
|
|
1079
|
-
utility: 0,
|
|
1080
|
-
},
|
|
1074
|
+
stats: { ...STAT_DEFAULTS },
|
|
1081
1075
|
ledger: { type: 'OFF_CHAIN' },
|
|
1082
1076
|
seed: localSeedToUUIDv4(`${seed}:${itemId}`),
|
|
1083
1077
|
},
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import crypto from 'crypto';
|
|
20
|
+
import { generateRandomStats } from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
20
21
|
|
|
21
22
|
import { createRng, seedToInt, createNoise2D, generateShape, listShapes } from './shape-generator.js';
|
|
22
23
|
import { loggerFactory } from '../../server/ops/logger.js';
|
|
@@ -703,14 +704,7 @@ export function generateMultiFrame(options) {
|
|
|
703
704
|
description: `Procedurally generated ${descriptor.semanticTags.join(', ')} (seed: ${seed})`,
|
|
704
705
|
activable: true,
|
|
705
706
|
},
|
|
706
|
-
stats:
|
|
707
|
-
effect: hashMod(seed + ':effect', 11),
|
|
708
|
-
resistance: hashMod(seed + ':resistance', 11),
|
|
709
|
-
agility: hashMod(seed + ':agility', 11),
|
|
710
|
-
range: hashMod(seed + ':range', 11),
|
|
711
|
-
intelligence: hashMod(seed + ':intelligence', 11),
|
|
712
|
-
utility: hashMod(seed + ':utility', 11),
|
|
713
|
-
},
|
|
707
|
+
stats: generateRandomStats(undefined, undefined, createRng(seedToInt(seed + ':stats'))),
|
|
714
708
|
ledger: { type: 'OFF_CHAIN' },
|
|
715
709
|
seed: seedToUUIDv4(seed + ':' + itemId),
|
|
716
710
|
},
|
|
@@ -726,16 +720,6 @@ export function generateMultiFrame(options) {
|
|
|
726
720
|
};
|
|
727
721
|
}
|
|
728
722
|
|
|
729
|
-
/**
|
|
730
|
-
* Deterministic modulo hash for stat generation.
|
|
731
|
-
* @param {string} str
|
|
732
|
-
* @param {number} mod
|
|
733
|
-
* @returns {number}
|
|
734
|
-
*/
|
|
735
|
-
function hashMod(str, mod) {
|
|
736
|
-
return ((hashString(str) % mod) + mod) % mod;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
723
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
740
724
|
* EXPORTS
|
|
741
725
|
* ═══════════════════════════════════════════════════════════════════════════ */
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STAT_MODIFIER_MAX,
|
|
3
|
+
STAT_MODIFIER_MIN,
|
|
4
|
+
STAT_TYPES,
|
|
5
|
+
statBoundsForType,
|
|
6
|
+
validateStatModifier,
|
|
7
|
+
validateStats,
|
|
8
|
+
} from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Stat balancing for every object layer the content pipeline writes.
|
|
12
|
+
*
|
|
13
|
+
* One policy resolves the bounds each stat may take, then either clamps the stats the content
|
|
14
|
+
* carries or draws new ones inside those bounds. The same policy answers every write path, so a
|
|
15
|
+
* run with a given policy over given content is deterministic.
|
|
16
|
+
*
|
|
17
|
+
* @typedef {Object} StatPolicy
|
|
18
|
+
* @property {boolean} [normalize=false] - Bound each stat by the item type's semantic range.
|
|
19
|
+
* @property {boolean} [random=false] - Replace every stat with a value drawn inside its bounds.
|
|
20
|
+
* @property {number} [min] - Narrow every bound from below.
|
|
21
|
+
* @property {number} [max] - Narrow every bound from above.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** Whether a policy changes anything at all. */
|
|
25
|
+
export const statPolicyActive = ({ normalize = false, random = false } = {}) => normalize || random;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The inclusive `[min, max]` each stat may take under a policy for one item type.
|
|
29
|
+
*
|
|
30
|
+
* The semantic range wins: `min` and `max` narrow it, and a request that leaves no overlap pins
|
|
31
|
+
* the stat to the semantic edge nearest the request. Without `normalize` the contract range is
|
|
32
|
+
* the whole range.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} itemType
|
|
35
|
+
* @param {StatPolicy} policy
|
|
36
|
+
* @returns {Record<string,[number,number]>}
|
|
37
|
+
*/
|
|
38
|
+
export function resolveStatBounds(itemType, { normalize = false, min, max } = {}) {
|
|
39
|
+
if (min !== undefined) validateStatModifier(min);
|
|
40
|
+
if (max !== undefined) validateStatModifier(max);
|
|
41
|
+
if (min !== undefined && max !== undefined && min > max)
|
|
42
|
+
throw new RangeError('Stat minimum must not exceed maximum.');
|
|
43
|
+
const semantic = normalize
|
|
44
|
+
? statBoundsForType(itemType)
|
|
45
|
+
: Object.fromEntries(STAT_TYPES.map((key) => [key, [STAT_MODIFIER_MIN, STAT_MODIFIER_MAX]]));
|
|
46
|
+
return Object.fromEntries(
|
|
47
|
+
STAT_TYPES.map((key) => {
|
|
48
|
+
const [lo, hi] = semantic[key];
|
|
49
|
+
const low = Math.max(lo, min ?? lo);
|
|
50
|
+
const high = Math.min(hi, max ?? hi);
|
|
51
|
+
if (low <= high) return [key, [low, high]];
|
|
52
|
+
// No overlap: the semantic edge the request points at.
|
|
53
|
+
const pinned = (min ?? lo) > hi ? hi : lo;
|
|
54
|
+
return [key, [pinned, pinned]];
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Applies a policy to one item's stats.
|
|
61
|
+
*
|
|
62
|
+
* @param {Object} params
|
|
63
|
+
* @param {Object} params.stats - Stats as the content carries them.
|
|
64
|
+
* @param {string} params.itemType
|
|
65
|
+
* @param {StatPolicy} [params.policy]
|
|
66
|
+
* @param {() => number} [params.random=Math.random] - Source in [0, 1) for a random draw.
|
|
67
|
+
* @returns {Record<string,number>} The balanced stats, in canonical order.
|
|
68
|
+
*/
|
|
69
|
+
export function balanceStats({ stats, itemType, policy = {}, random = Math.random }) {
|
|
70
|
+
const current = validateStats(stats);
|
|
71
|
+
const bounds = resolveStatBounds(itemType, policy);
|
|
72
|
+
return Object.fromEntries(
|
|
73
|
+
STAT_TYPES.map((key) => {
|
|
74
|
+
const [lo, hi] = bounds[key];
|
|
75
|
+
if (!policy.random) return [key, Math.min(hi, Math.max(lo, current[key]))];
|
|
76
|
+
const value = random();
|
|
77
|
+
if (!Number.isFinite(value) || value < 0 || value >= 1) throw new RangeError('Random source must return [0, 1).');
|
|
78
|
+
return [key, Math.floor(value * (hi - lo + 1)) + lo];
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { generateRandomStats, validateStats } from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
3
|
+
import { PROGRESSION_RULES_DEFAULTS } from '../../api/cyberia-server-defaults/cyberia-server-defaults.js';
|
|
4
|
+
import { generateStatContract } from './stat-contract-generator.js';
|
|
5
|
+
|
|
6
|
+
export function registerStatCommands(program) {
|
|
7
|
+
const stats = program.command('stats').description('Validate signed stats and inspect progression rules.');
|
|
8
|
+
stats.command('random').option('--min <number>').option('--max <number>').action((options) => {
|
|
9
|
+
const min = options.min === undefined ? undefined : Number(options.min);
|
|
10
|
+
const max = options.max === undefined ? undefined : Number(options.max);
|
|
11
|
+
console.log(JSON.stringify(generateRandomStats(min, max), null, 2));
|
|
12
|
+
});
|
|
13
|
+
stats.command('validate <file>').action(async (file) => {
|
|
14
|
+
const input = JSON.parse(await readFile(file, 'utf8'));
|
|
15
|
+
const records = Array.isArray(input) ? input : [input];
|
|
16
|
+
for (const record of records) validateStats(record.data?.stats ?? record.stats ?? record);
|
|
17
|
+
console.log(JSON.stringify({ valid: true, records: records.length }));
|
|
18
|
+
});
|
|
19
|
+
stats.command('progression').action(() => console.log(JSON.stringify(PROGRESSION_RULES_DEFAULTS, null, 2)));
|
|
20
|
+
program.command('stat-contract').option('--check', 'Check generated Go and C files.').action(async (options) => {
|
|
21
|
+
console.log(JSON.stringify(await generateStatContract({ check: !!options.check })));
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { buildBootContractArtifacts } from './boot-contract-fixtures.js';
|
|
2
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { resolve, dirname } from 'node:path';
|
|
9
|
+
import { STAT_TYPES, STAT_DEFINITIONS, STAT_MODIFIER_MIN, STAT_MODIFIER_MAX, STAT_EFFECTIVE_FLOORS, STAT_SCALES, STAT_REGEN_PER_RESISTANCE } from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
10
|
+
import { PROGRESSION_RULES_DEFAULTS, PROGRESSION_RULE_LIMITS } from '../../api/cyberia-server-defaults/cyberia-server-defaults.js';
|
|
11
|
+
|
|
12
|
+
const field = (key) => key[0].toUpperCase() + key.slice(1);
|
|
13
|
+
const values = (stats) => STAT_TYPES.map((key) => stats[key]).join(', ');
|
|
14
|
+
|
|
15
|
+
export function buildStatContractArtifacts() {
|
|
16
|
+
const go = `// Code generated by Cyberia stat-contract. DO NOT EDIT.
|
|
17
|
+
package game
|
|
18
|
+
const StatCount = ${STAT_TYPES.length}
|
|
19
|
+
const StatModifierMin = ${STAT_MODIFIER_MIN}
|
|
20
|
+
const StatModifierMax = ${STAT_MODIFIER_MAX}
|
|
21
|
+
func (r ProgressionRules) validScalarBounds() bool { return ${Object.entries(PROGRESSION_RULE_LIMITS).map(([key, [min, max]]) => `r.${field(key)} >= ${min} && r.${field(key)} <= ${max}`).join(' && ')} }
|
|
22
|
+
var statNames = [StatCount]string{${STAT_TYPES.map(JSON.stringify).join(', ')}}
|
|
23
|
+
var statEffectiveFloors = [StatCount]float64{${values(STAT_EFFECTIVE_FLOORS)}}
|
|
24
|
+
// statScales is what one point of each stat is worth in the simulation.
|
|
25
|
+
var statScales = ComputedStats{${STAT_TYPES.map((key) => `${field(key)}: ${STAT_SCALES[key]}`).join(', ')}}
|
|
26
|
+
const statRegenPerResistance = ${STAT_REGEN_PER_RESISTANCE}
|
|
27
|
+
type Stats struct {
|
|
28
|
+
${STAT_TYPES.map((key) => `${field(key)} int \`json:"${key}"\``).join('\n')}
|
|
29
|
+
}
|
|
30
|
+
type ComputedStats struct {
|
|
31
|
+
${STAT_TYPES.map((key) => `${field(key)} float64 \`json:"${key}"\``).join('\n')}
|
|
32
|
+
}
|
|
33
|
+
func (s Stats) computed() ComputedStats { return ComputedStats{${STAT_TYPES.map((key) => `${field(key)}: float64(s.${field(key)})`).join(', ')}} }
|
|
34
|
+
func (s ComputedStats) Values() [StatCount]float64 { return [StatCount]float64{${STAT_TYPES.map((key) => `s.${field(key)}`).join(', ')}} }
|
|
35
|
+
func statsFromValues(v [StatCount]float64) ComputedStats { return ComputedStats{${STAT_TYPES.map((key, i) => `${field(key)}: v[${i}]`).join(', ')}} }
|
|
36
|
+
func defaultProgressionRules() ProgressionRules { return ProgressionRules{
|
|
37
|
+
${Object.entries(PROGRESSION_RULES_DEFAULTS).map(([key, value]) => `${field(key)}: ${typeof value === 'object' ? `ComputedStats{${values(value)}}` : value},`).join('\n')}
|
|
38
|
+
} }
|
|
39
|
+
`;
|
|
40
|
+
const header = `/* Code generated by Cyberia stat-contract. DO NOT EDIT. */
|
|
41
|
+
#ifndef CYBERIA_STAT_CONTRACT_H
|
|
42
|
+
#define CYBERIA_STAT_CONTRACT_H
|
|
43
|
+
#define CYBERIA_STAT_COUNT ${STAT_TYPES.length}
|
|
44
|
+
static const char* const CYBERIA_STAT_NAMES[CYBERIA_STAT_COUNT] = {${STAT_TYPES.map(JSON.stringify).join(', ')}};
|
|
45
|
+
typedef struct {
|
|
46
|
+
${STAT_TYPES.map((key) => ' int ' + key + ';').join('\n')}
|
|
47
|
+
} Stats;
|
|
48
|
+
static inline void cyberia_stats_values(const Stats* stats, int values[CYBERIA_STAT_COUNT]) {
|
|
49
|
+
${STAT_TYPES.map((key, i) => ' values[' + i + '] = stats->' + key + ';').join('\n')}
|
|
50
|
+
}
|
|
51
|
+
static inline Stats cyberia_stats_from_values(const int values[CYBERIA_STAT_COUNT]) {
|
|
52
|
+
return (Stats){${STAT_TYPES.map((key, i) => 'values[' + i + ']').join(', ')}};
|
|
53
|
+
}
|
|
54
|
+
static const char* const CYBERIA_STAT_ICONS[CYBERIA_STAT_COUNT] = {${STAT_TYPES.map((key) => JSON.stringify('stat-' + key)).join(', ')}};
|
|
55
|
+
static const char* const CYBERIA_STAT_LABELS[CYBERIA_STAT_COUNT] = {${STAT_DEFINITIONS.map(({ title }) => JSON.stringify(title)).join(', ')}};
|
|
56
|
+
#endif
|
|
57
|
+
`;
|
|
58
|
+
const temporary = mkdtempSync(join(tmpdir(), 'cyberia-stat-contract-'));
|
|
59
|
+
let formatted;
|
|
60
|
+
try {
|
|
61
|
+
const source = join(temporary, 'contract.go');
|
|
62
|
+
writeFileSync(source, go);
|
|
63
|
+
execFileSync('gofmt', ['-w', source], { stdio: 'inherit', timeout: 30000 });
|
|
64
|
+
formatted = readFileSync(source, 'utf8');
|
|
65
|
+
} finally {
|
|
66
|
+
rmSync(temporary, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
'cyberia-server/game/stat_contract_generated.go': formatted,
|
|
70
|
+
'cyberia-client/src/domain/stat_contract_generated.h': header,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Whether cyberia-server and cyberia-client sit beside this repository.
|
|
76
|
+
*
|
|
77
|
+
* Both are gitignored siblings (see .gitignore, alongside cyberia-audio), so a checkout that
|
|
78
|
+
* publishes only this repo's tracked tree — the engine-cyberia npm mirrors, for one — never has
|
|
79
|
+
* them. {@link generateStatContract} writes into both; callers that only run in a full
|
|
80
|
+
* multi-repo checkout should skip rather than fail on a missing sibling.
|
|
81
|
+
*
|
|
82
|
+
* @param {string} [root] - Defaults to this repository's own root.
|
|
83
|
+
* @returns {boolean}
|
|
84
|
+
*/
|
|
85
|
+
export function hasCyberiaSiblings(root = fileURLToPath(new URL('../../../', import.meta.url))) {
|
|
86
|
+
return existsSync(resolve(root, 'cyberia-server')) && existsSync(resolve(root, 'cyberia-client'));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function generateStatContract({ root = fileURLToPath(new URL('../../../', import.meta.url)), check = false } = {}) {
|
|
90
|
+
const artifacts = { ...buildStatContractArtifacts(), ...buildBootContractArtifacts() };
|
|
91
|
+
for (const [path, content] of Object.entries(artifacts)) {
|
|
92
|
+
const target = resolve(root, path);
|
|
93
|
+
if (check) {
|
|
94
|
+
if (await readFile(target, 'utf8') !== content) throw new Error(`Regenerate ${path} with cyberia stat-contract.`);
|
|
95
|
+
} else {
|
|
96
|
+
await mkdir(dirname(target), { recursive: true });
|
|
97
|
+
await writeFile(target, content);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return Object.keys(artifacts);
|
|
101
|
+
}
|
|
@@ -38,17 +38,21 @@ RUN set -eux; \
|
|
|
38
38
|
underpost --version
|
|
39
39
|
|
|
40
40
|
# Path + server layout is the contract with conf.instances.json mmo-client cmd,
|
|
41
|
-
# which execs `python3 /home/dd/engine/cyberia-client/
|
|
42
|
-
#
|
|
41
|
+
# which execs `python3 /home/dd/engine/cyberia-client/wasm-driver.py --port=<port>
|
|
42
|
+
# --directory=/home/dd/engine/cyberia-client/bin --data-server-url=<url>` in both
|
|
43
|
+
# development and production.
|
|
43
44
|
# Keep this identical to Dockerfile.dev so prod and dev images are interchangeable.
|
|
44
45
|
WORKDIR /home/dd/engine/cyberia-client
|
|
45
46
|
|
|
46
|
-
COPY --from=builder /cyberia-client/
|
|
47
|
+
COPY --from=builder /cyberia-client/wasm-driver.py ./wasm-driver.py
|
|
47
48
|
COPY --from=builder /cyberia-client/bin ./bin/
|
|
48
49
|
|
|
49
50
|
ENV PYTHONUNBUFFERED=1
|
|
50
51
|
ENV CYBERIA_PORT=8081
|
|
52
|
+
# Mirrors the --data-server-url default in wasm-driver.py: the CMD below always passes the flag,
|
|
53
|
+
# so leaving this unset would hand the client an empty origin rather than that default.
|
|
54
|
+
ENV CYBERIA_DATA_SERVER_URL=https://cyberiaonline.com
|
|
51
55
|
|
|
52
56
|
EXPOSE 8081
|
|
53
57
|
|
|
54
|
-
CMD ["sh", "-c", "exec python3
|
|
58
|
+
CMD ["sh", "-c", "exec python3 wasm-driver.py --port=${CYBERIA_PORT} --directory=bin --data-server-url=${CYBERIA_DATA_SERVER_URL}"]
|
|
@@ -71,11 +71,14 @@ RUN set -eux; \
|
|
|
71
71
|
|
|
72
72
|
WORKDIR /home/dd/engine/cyberia-client
|
|
73
73
|
|
|
74
|
-
COPY --from=builder /cyberia-client/
|
|
74
|
+
COPY --from=builder /cyberia-client/wasm-driver.py ./wasm-driver.py
|
|
75
75
|
COPY --from=builder /cyberia-client/bin ./bin/
|
|
76
76
|
|
|
77
77
|
ENV CYBERIA_PORT=8082
|
|
78
|
+
# Mirrors the --data-server-url default in wasm-driver.py: the CMD below always passes the flag,
|
|
79
|
+
# so leaving this unset would hand the client an empty origin rather than that default.
|
|
80
|
+
ENV CYBERIA_DATA_SERVER_URL=https://cyberiaonline.com
|
|
78
81
|
|
|
79
82
|
EXPOSE 8081 8082
|
|
80
83
|
|
|
81
|
-
CMD ["sh", "-c", "exec python3
|
|
84
|
+
CMD ["sh", "-c", "exec python3 wasm-driver.py --port=${CYBERIA_PORT} --directory=bin --data-server-url=${CYBERIA_DATA_SERVER_URL}"]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# --- Build Image ---
|
|
2
|
-
FROM golang:1.
|
|
2
|
+
FROM golang:1.25 AS builder
|
|
3
3
|
|
|
4
4
|
WORKDIR /build
|
|
5
5
|
|
|
@@ -45,4 +45,11 @@ COPY public/ ./public/
|
|
|
45
45
|
|
|
46
46
|
EXPOSE 8081
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
# Both Data Server endpoints are flags, not environment reads (cmd/cyberia-server/main.go), and
|
|
49
|
+
# the server refuses to start without them. Passing them here from the environment is what lets a
|
|
50
|
+
# plain `docker run` or a Compose service that sets no command still start: a Kubernetes pod spec
|
|
51
|
+
# supplies its own command and overrides this.
|
|
52
|
+
ENV CYBERIA_DATA_SERVER_URL=http://engine-cyberia
|
|
53
|
+
ENV CYBERIA_DATA_SERVER_GRPC=engine-cyberia-runtime:50051
|
|
54
|
+
|
|
55
|
+
CMD ["sh", "-c", "exec /home/dd/engine/cyberia-server/server --data-server-url=${CYBERIA_DATA_SERVER_URL} --data-server-grpc=${CYBERIA_DATA_SERVER_GRPC}"]
|
|
@@ -59,4 +59,11 @@ COPY public/ ./public/
|
|
|
59
59
|
|
|
60
60
|
EXPOSE 8081
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
# Both Data Server endpoints are flags, not environment reads (cmd/cyberia-server/main.go), and
|
|
63
|
+
# the server refuses to start without them. Passing them here from the environment is what lets a
|
|
64
|
+
# plain `docker run` or a Compose service that sets no command still start: a Kubernetes pod spec
|
|
65
|
+
# supplies its own command and overrides this.
|
|
66
|
+
ENV CYBERIA_DATA_SERVER_URL=http://engine-cyberia
|
|
67
|
+
ENV CYBERIA_DATA_SERVER_GRPC=engine-cyberia-runtime:50051
|
|
68
|
+
|
|
69
|
+
CMD ["sh", "-c", "exec /home/dd/engine/cyberia-server/server --data-server-url=${CYBERIA_DATA_SERVER_URL} --data-server-grpc=${CYBERIA_DATA_SERVER_GRPC}"]
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
|
|
7
7
|
# ---------------------------------------------------------------------------
|
|
8
8
|
FROM rockylinux/rockylinux:9 AS builder
|
|
9
|
-
ARG UNDERPOST_VERSION=3.3.
|
|
9
|
+
ARG UNDERPOST_VERSION=3.3.77
|
|
10
10
|
# Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
|
|
11
11
|
# underpost's dependencies require >=24.15.0, so install the official binary.
|
|
12
12
|
ARG NODE_VERSION=24.15.0
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
|
|
7
7
|
# ---------------------------------------------------------------------------
|
|
8
8
|
FROM rockylinux/rockylinux:9 AS builder
|
|
9
|
-
ARG UNDERPOST_VERSION=3.3.
|
|
9
|
+
ARG UNDERPOST_VERSION=3.3.77
|
|
10
10
|
# Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
|
|
11
11
|
# underpost's dependencies require >=24.15.0, so install the official binary.
|
|
12
12
|
ARG NODE_VERSION=24.15.0
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Stage 1 — builder: clone the private deploy, build it, then scrub secrets.
|
|
7
7
|
# ---------------------------------------------------------------------------
|
|
8
8
|
FROM rockylinux/rockylinux:9 AS builder
|
|
9
|
-
ARG UNDERPOST_VERSION=3.3.
|
|
9
|
+
ARG UNDERPOST_VERSION=3.3.77
|
|
10
10
|
# Pin Node to an exact patch: dnf's nodejs:24 module lags (24.14.1) while
|
|
11
11
|
# underpost's dependencies require >=24.15.0, so install the official binary.
|
|
12
12
|
ARG NODE_VERSION=24.15.0
|
|
@@ -72,7 +72,7 @@ RUN --mount=type=secret,id=github_token \
|
|
|
72
72
|
# --- install deps + env, then replay build-safe itc provisioning ----------
|
|
73
73
|
npm install; \
|
|
74
74
|
node bin app load --env development --args deploy-id=dd-cyberia; \
|
|
75
|
-
node bin fs --pull --
|
|
75
|
+
node bin fs --pull --tracked --deploy-id dd-cyberia --storage-id engine-cyberia; \
|
|
76
76
|
( cd /home/dd/engine/hardhat && npm install --include=dev ); \
|
|
77
77
|
( cd /home/dd/engine && underpost clone underpostnet/cyberia-server ); \
|
|
78
78
|
\
|
|
@@ -43,25 +43,37 @@ VALKEY_PORT=6379
|
|
|
43
43
|
# cyberia-server-* -> stable engine gateway for HTTP and the raw engine runtime
|
|
44
44
|
# for gRPC. The public engine-cyberia name belongs to nginx, avoiding ambiguous
|
|
45
45
|
# Docker DNS while keeping one stable HTTP endpoint for every module.
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
CYBERIA_DATA_SERVER_URL=http://engine-cyberia
|
|
47
|
+
CYBERIA_DATA_SERVER_GRPC=engine-cyberia-runtime:50051
|
|
48
48
|
|
|
49
49
|
# Client-visible Content Authority origin, forwarded to browser/Raylib clients
|
|
50
50
|
# for every engine-cyberia content/asset/metadata request. Host-reachable
|
|
51
51
|
# (Docker publishes the raw engine runtime on host :4005). Unlike the internal
|
|
52
|
-
#
|
|
52
|
+
# CYBERIA_DATA_SERVER_URL, this value is consumed outside the Compose network:
|
|
53
53
|
# the two responsibilities must never overwrite each other.
|
|
54
54
|
ENGINE_PUBLIC_URL=http://localhost:4005
|
|
55
55
|
ENGINE_GRPC_RELOAD_INTERVAL_SEC=300
|
|
56
56
|
|
|
57
|
-
#
|
|
57
|
+
# Shared secret between the engine and every game server. It guards the server
|
|
58
|
+
# registry report (server -> engine) and the hot-reload trigger (engine ->
|
|
59
|
+
# server). Unset disables both: a server then stays out of the public list.
|
|
60
|
+
CYBERIA_SERVER_API_KEY=change_me_dev_server_api_key
|
|
61
|
+
|
|
62
|
+
# Public origin of the server gateway. Each server reports this origin plus its
|
|
63
|
+
# own sub-path, which is the URL a client dials.
|
|
64
|
+
CYBERIA_SERVER_PUBLIC_ORIGIN=http://localhost:8081
|
|
65
|
+
|
|
66
|
+
# --- Browser-facing client runtime config (injected by wasm-driver.py) -----
|
|
58
67
|
# The single WASM bundle resolves its instance from the URL sub-path and builds
|
|
59
68
|
# its endpoints from these origins. HTTP client/API traffic uses nginx on :80;
|
|
60
69
|
# WebSocket traffic uses the dedicated multi-path server gateway on :8081.
|
|
61
70
|
# http://localhost/ -> default, ws://localhost:8081/ws
|
|
62
71
|
# http://localhost/FOREST -> FOREST, ws://localhost:8081/FOREST/ws
|
|
63
72
|
CYBERIA_WS_ORIGIN=ws://localhost:8081
|
|
64
|
-
|
|
73
|
+
# The browser's own route to the Data Server, through nginx on :80. Distinct from the internal
|
|
74
|
+
# CYBERIA_DATA_SERVER_URL above: both name a Data Server origin, but from opposite sides of the
|
|
75
|
+
# Compose network, and one file cannot hold two values under one name.
|
|
76
|
+
CYBERIA_CLIENT_DATA_SERVER_URL=http://localhost
|
|
65
77
|
CYBERIA_DEFAULT_INSTANCE=amethyst-strata-expansion
|
|
66
78
|
|
|
67
79
|
# cyberia-server logging. This is the dev stack, so default to DEBUG. Set
|