@underpostnet/cyberia 3.3.0 → 3.3.76
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/.dockerignore +1 -0
- package/.env.example +17 -5
- package/.github/workflows/coverall.cyberia.ci.yml +39 -14
- package/.github/workflows/cyberia-client.cd.yml +5 -0
- package/.github/workflows/cyberia-server.cd.yml +5 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
- package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
- package/.github/workflows/engine-cyberia.cd.yml +3 -0
- package/.github/workflows/engine-cyberia.ci.yml +4 -5
- package/.github/workflows/ghpkg.ci.yml +35 -20
- package/.github/workflows/hardhat.ci.yml +12 -11
- package/.github/workflows/npmpkg.ci.yml +17 -15
- package/.github/workflows/publish.cyberia.ci.yml +44 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
- package/.github/workflows/release.cd.yml +1 -0
- package/.prettierignore +1 -0
- package/AGENTS.md +96 -0
- package/CHANGELOG.md +653 -2513
- package/CLI-HELP.md +323 -157
- package/Dockerfile +25 -9
- package/Dockerfile.dev +25 -9
- package/Dockerfile.test +5 -5
- package/README.md +48 -28
- package/bin/build.js +86 -41
- package/bin/build.template.js +8 -3
- package/bin/cyberia.js +1494 -1403
- package/bin/deploy.js +18 -104
- package/bin/index.js +1494 -1403
- package/compose.env +17 -5
- package/conf.js +98 -7
- package/deploy/cyberia-client/deploy.sh +46 -0
- package/deploy/cyberia-client/package.sh +17 -0
- package/deploy/cyberia-client/state.sh +15 -0
- package/deploy/cyberia-server/deploy.sh +46 -0
- package/deploy/cyberia-server/package.sh +17 -0
- package/deploy/cyberia-server/state.sh +15 -0
- package/deploy/dd-cyberia/deploy.sh +9 -29
- package/deploy/dd-cyberia/init.sh +38 -45
- package/deploy/dd-cyberia/package.sh +16 -0
- package/deploy/dd-cyberia/state.sh +14 -0
- package/deploy/dd-cyberia/sync-deploy.sh +133 -147
- package/deploy/lib/config.sh +29 -0
- package/deploy/lib/github-actions-logging.sh +610 -0
- package/deploy/lib/host.sh +194 -0
- package/deploy/lib/state.sh +65 -0
- package/deploy/pwa-microservices-template/deploy.sh +17 -42
- package/deploy/release/deploy.sh +9 -41
- package/deployment.yaml +7 -2
- package/docker-compose.yml +23 -17
- package/examples/static-page/README.md +19 -19
- package/examples/static-page/ssr-components/CustomPage.js +2 -2
- package/hardhat/hardhat.config.js +1 -6
- package/hardhat/package-lock.json +101 -40
- package/hardhat/package.json +2 -2
- package/manifests/alertmanager/deployment.yaml +81 -0
- package/manifests/blackbox-exporter/deployment.yaml +75 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
- package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
- 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/manifests/grafana/deployment.yaml +26 -7
- package/manifests/grafana/kustomization.yaml +1 -0
- package/manifests/grafana/service.yaml +6 -1
- package/manifests/mariadb/pv.yaml +1 -0
- package/manifests/mongodb/statefulset.yaml +9 -2
- package/manifests/mysql/pv-pvc.yaml +14 -1
- package/manifests/postgresql/pv.yaml +12 -1
- package/manifests/postgresql/pvc.yaml +1 -0
- package/manifests/prometheus/deployment.yaml +18 -22
- package/package.json +87 -12
- package/scripts/event-monitor.sh +56 -0
- package/scripts/k3s-node-setup.sh +27 -14
- package/scripts/kubeadm-node-setup.sh +31 -11
- package/scripts/maas-setup.sh +8 -8
- package/scripts/selinux-normalize.sh +907 -0
- package/scripts/shutdown-machine.sh +843 -0
- package/scripts/test-monitor.sh +5 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +15 -10
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +7 -2
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +90 -186
- package/src/api/core/core.controller.js +1 -1
- package/src/api/core/core.router.js +2 -2
- package/src/api/core/core.service.js +2 -2
- package/src/api/crypto/crypto.controller.js +1 -1
- package/src/api/crypto/crypto.service.js +1 -1
- package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +3 -3
- package/src/api/cyberia-action/cyberia-action.service.js +5 -6
- 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 +2 -4
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +13 -35
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +17 -34
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
- package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
- package/src/api/cyberia-entity/cyberia-entity.service.js +3 -3
- 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 +17 -2
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +468 -5
- package/src/api/cyberia-instance/cyberia-fallback-capture.js +502 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +29 -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 +35 -142
- package/src/api/cyberia-instance/cyberia-instance.controller.js +2 -5
- package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
- package/src/api/cyberia-instance/cyberia-instance.router.js +5 -18
- package/src/api/cyberia-instance/cyberia-instance.service.js +5 -45
- package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +76 -3
- package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
- package/src/api/cyberia-map/cyberia-map.router.js +1 -1
- package/src/api/cyberia-map/cyberia-map.service.js +8 -4
- 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.controller.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +4 -4
- package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
- package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
- package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -214
- package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
- package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
- package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
- package/src/api/default/default.controller.js +1 -1
- package/src/api/default/default.router.js +1 -1
- package/src/api/default/default.service.js +2 -2
- package/src/api/document/document.controller.js +1 -1
- package/src/api/document/document.router.js +1 -1
- package/src/api/document/document.service.js +2 -2
- package/src/api/file/file.controller.js +1 -1
- package/src/api/file/file.ref.js +153 -0
- package/src/api/file/file.ref.json +11 -2
- package/src/api/file/file.router.js +1 -1
- package/src/api/file/file.service.js +2 -2
- package/src/api/instance/instance.controller.js +1 -1
- package/src/api/instance/instance.router.js +1 -1
- package/src/api/instance/instance.service.js +2 -2
- package/src/api/ipfs/ipfs.controller.js +1 -1
- package/src/api/ipfs/ipfs.router.js +2 -2
- package/src/api/ipfs/ipfs.service.js +2 -2
- package/src/api/object-layer/object-layer.controller.js +1 -1
- package/src/api/object-layer/object-layer.model.js +47 -12
- package/src/api/object-layer/object-layer.router.js +12 -5
- package/src/api/object-layer/object-layer.service.js +116 -123
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
- package/src/api/test/test.controller.js +1 -1
- package/src/api/test/test.service.js +1 -1
- package/src/api/user/guest.service.js +3 -3
- package/src/api/user/user.controller.js +1 -1
- package/src/api/user/user.router.js +2 -2
- package/src/api/user/user.service.js +4 -4
- package/src/api.js +5 -9
- package/src/cli/app.js +402 -0
- package/src/cli/baremetal.js +30 -35
- package/src/cli/client.js +306 -0
- package/src/cli/cloud-init.js +3 -3
- package/src/cli/cluster.js +191 -82
- package/src/cli/db.js +120 -68
- package/src/cli/deploy.js +157 -75
- package/src/cli/docker-compose.js +5 -5
- package/src/cli/domains.js +184 -0
- package/src/cli/dotenv-store.js +143 -0
- package/src/cli/event.js +2281 -0
- package/src/cli/fs-selection.js +115 -0
- package/src/cli/fs.js +159 -343
- package/src/cli/host.js +672 -0
- package/src/cli/image.js +4 -6
- package/src/cli/index.js +343 -151
- package/src/cli/ipfs.js +34 -30
- package/src/cli/kickstart.js +1 -1
- package/src/cli/kubectl.js +218 -41
- package/src/cli/lxd.js +3 -3
- package/src/cli/monitor.js +1359 -26
- package/src/cli/package.js +90 -0
- package/src/cli/release.js +16 -12
- package/src/cli/repository.js +586 -363
- package/src/cli/run.js +398 -843
- package/src/cli/secrets.js +2158 -964
- package/src/cli/ssh.js +478 -279
- package/src/cli/state.js +394 -0
- package/src/cli/static.js +2 -2
- package/src/cli/system.js +1 -1
- package/src/cli/test.js +203 -125
- package/src/cli/vultr.js +61 -21
- package/src/cli/wireguard.js +1112 -306
- package/src/client/components/core/CalendarCore.js +53 -96
- package/src/client/components/core/Docs.js +327 -303
- package/src/client/components/core/FileExplorer.js +0 -21
- package/src/client/components/core/Modal.js +56 -1
- package/src/client/components/core/PanelForm.js +4 -4
- package/src/client/components/core/Repository.js +56 -0
- package/src/client/components/core/Translate.js +7 -0
- package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
- package/src/client/components/core/Wallet.js +0 -11
- package/src/client/components/core/Worker.js +7 -1
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -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 +2 -35
- 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/SettingsCyberiaPortal.js +2 -2
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
- package/src/client/components/default/AppShellDefault.js +1 -1
- package/src/client/components/default/SettingsDefault.js +2 -2
- package/src/client/components/itemledger/SettingsItemledger.js +2 -2
- package/src/client/components/underpost/AppShellUnderpost.js +3 -2
- package/src/client/components/underpost/SettingsUnderpost.js +2 -2
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +313 -30
- 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 +48 -28
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
- 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/public/default/android-chrome-144x144.png +0 -0
- package/src/client/public/default/android-chrome-192x192.png +0 -0
- package/src/client/public/default/android-chrome-256x256.png +0 -0
- package/src/client/public/default/android-chrome-36x36.png +0 -0
- package/src/client/public/default/android-chrome-384x384.png +0 -0
- package/src/client/public/default/android-chrome-48x48.png +0 -0
- package/src/client/public/default/android-chrome-512x512.png +0 -0
- package/src/client/public/default/android-chrome-72x72.png +0 -0
- package/src/client/public/default/android-chrome-96x96.png +0 -0
- package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
- package/src/client/public/default/assets/background/white.jpg +0 -0
- package/src/client/public/default/browserconfig.xml +1 -1
- package/src/client/public/default/favicon-16x16.png +0 -0
- package/src/client/public/default/favicon-32x32.png +0 -0
- package/src/client/public/default/favicon-48x48.png +0 -0
- package/src/client/public/default/favicon.ico +0 -0
- package/src/client/public/default/manifest.webmanifest +5 -5
- package/src/client/public/default/mstile-144x144.png +0 -0
- package/src/client/public/default/mstile-150x150.png +0 -0
- package/src/client/public/default/mstile-310x150.png +0 -0
- package/src/client/public/default/mstile-310x310.png +0 -0
- package/src/client/public/default/mstile-70x70.png +0 -0
- package/src/client/public/default/yandex-browser-50x50.png +0 -0
- package/src/client/public/default/yandex-browser-manifest.json +1 -1
- 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/RootDocument.js +1 -1
- package/src/client/ssr/body/404.js +1 -1
- package/src/client/ssr/body/500.js +1 -1
- package/src/client/ssr/body/CacheControl.js +1 -1
- package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
- package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
- package/src/client/ssr/head/CryptokoynScripts.js +1 -1
- package/src/client/ssr/head/Css.js +1 -1
- package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
- package/src/client/ssr/head/DefaultScripts.js +1 -1
- package/src/client/ssr/head/ItemledgerScripts.js +1 -1
- package/src/client/ssr/head/Microdata.js +1 -1
- package/src/client/ssr/head/Production.js +1 -1
- package/src/client/ssr/head/Pwa.js +1 -1
- package/src/client/ssr/head/PwaItemledger.js +1 -1
- package/src/client/ssr/head/Seo.js +1 -1
- package/src/client/ssr/head/UnderpostScripts.js +1 -1
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
- package/src/client/ssr/views/Cyberia404.js +7 -5
- package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/views/Maintenance.js +1 -1
- package/src/client/ssr/views/NoNetworkConnection.js +1 -1
- package/src/client/ssr/views/Test.js +1 -1
- package/src/client/sw/core.sw.js +20 -14
- package/src/client-builder/client-build-docs.js +92 -77
- package/src/client-builder/client-build-live.js +2 -2
- package/src/client-builder/client-build.js +105 -74
- package/src/client-builder/client-bundle.js +347 -0
- package/src/client-builder/client-dev-server.js +3 -3
- package/src/client-builder/client-icons.js +2 -2
- package/src/client-builder/ssr.js +3 -3
- package/src/client.build.js +3 -6
- package/src/client.dev.js +3 -6
- package/src/db/DataBaseProvider.js +186 -3
- package/src/db/mariadb/MariaDB.js +3 -2
- package/src/db/mongo/MongoBootstrap.js +273 -101
- package/src/db/mongo/MongoExpress.js +187 -0
- package/src/db/mongo/MongooseDB.js +7 -8
- package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
- package/src/grpc/cyberia/grpc-server.js +6 -8
- package/src/index.js +79 -23
- package/src/mailer/EmailRender.js +2 -2
- package/src/mailer/MailerInterceptor.js +87 -0
- package/src/mailer/MailerProvider.js +50 -6
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +144 -147
- package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
- package/src/projects/cyberia/besu-genesis-generator.js +8 -17
- package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
- package/src/projects/cyberia/catalog-cyberia.js +54 -10
- package/src/projects/cyberia/gemini-client.js +4 -4
- package/src/projects/cyberia/generate-saga.js +5 -12
- package/src/projects/cyberia/hot-reload-trigger.js +18 -29
- package/src/projects/cyberia/instance-backup.js +210 -0
- package/src/projects/cyberia/instance-data.js +178 -258
- package/src/projects/cyberia/ipfs-client.js +4 -4
- package/src/projects/cyberia/map-preview-generator.js +33 -69
- package/src/projects/cyberia/object-layer.js +153 -320
- 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 +3 -19
- 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/projects/underpost/catalog-underpost.js +9 -1
- package/src/proxy.js +4 -7
- package/src/runtime/cyberia-client/Dockerfile +17 -8
- package/src/runtime/cyberia-client/Dockerfile.dev +13 -4
- package/src/runtime/cyberia-server/Dockerfile +18 -6
- package/src/runtime/cyberia-server/Dockerfile.dev +16 -3
- package/src/runtime/engine-cyberia/Dockerfile +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
- package/src/runtime/engine-cyberia/Dockerfile.test +5 -5
- package/src/runtime/engine-cyberia/compose.env +17 -5
- package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
- package/src/runtime/express/Express.js +32 -27
- package/src/runtime/lampp/Lampp.js +22 -70
- package/src/runtime/nginx/Nginx.js +1 -1
- package/src/runtime/wp/Wp.js +16 -48
- package/src/server/{catalog.js → build/catalog.js} +15 -5
- package/src/server/build/coverage.js +188 -0
- package/src/server/build/execution.js +402 -0
- package/src/server/build/package.js +508 -0
- package/src/server/build/testing.js +578 -0
- package/src/server/{dns.js → network/dns.js} +144 -11
- package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
- package/src/server/{middlewares.js → network/middlewares.js} +11 -5
- package/src/server/network/node-capability.js +98 -0
- package/src/server/{peer.js → network/peer.js} +3 -3
- package/src/server/{proxy.js → network/proxy.js} +7 -13
- package/src/server/network/router.js +356 -0
- package/src/server/{tls.js → network/tls.js} +2 -2
- package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
- package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
- package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
- package/src/server/{cri.js → ops/cri.js} +2 -2
- package/src/server/{cron.js → ops/cron.js} +349 -74
- package/src/server/ops/event-notification.js +284 -0
- package/src/server/{logger.js → ops/logger.js} +143 -23
- package/src/server/ops/monitoring.js +1724 -0
- package/src/server/{systemd.js → ops/systemd.js} +55 -1
- package/src/server/{conf.js → runtime/conf.js} +516 -423
- package/src/server/runtime/config-scope.js +215 -0
- package/src/server/runtime/environment.js +149 -0
- package/src/server/{process.js → runtime/process.js} +153 -12
- package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
- package/src/server/{runtime.js → runtime/runtime.js} +12 -8
- package/src/server/{start.js → runtime/start.js} +128 -39
- package/src/server/{auth.js → security/auth.js} +7 -8
- package/src/server/security/container-storage.js +382 -0
- package/src/server/{crypto.js → security/crypto.js} +1 -1
- package/src/server/{selinux.js → security/selinux.js} +1 -1
- package/src/server/{backup.js → storage/backup.js} +17 -8
- package/src/server/{data-query.js → storage/data-query.js} +17 -1
- package/src/server/storage/downloader.js +121 -0
- package/src/server/storage/repository.js +68 -0
- package/src/server/storage/zip.js +153 -0
- package/src/server.js +4 -7
- package/src/ws/IoInterface.js +1 -1
- package/src/ws/IoServer.js +1 -1
- package/src/ws/core/core.ws.connection.js +1 -1
- package/src/ws/core/core.ws.emit.js +1 -1
- package/src/ws/core/core.ws.server.js +1 -1
- package/src/ws/default/default.ws.connection.js +1 -1
- package/src/ws/default/default.ws.emit.js +1 -1
- package/src/ws/default/default.ws.server.js +1 -1
- package/test/e2e/event-e2e-public-ingress-down.js +45 -0
- package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
- package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
- package/test/{api.test.js → integration/app/api.test.js} +33 -14
- 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 +64 -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/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +17 -23
- package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
- package/test/integration/app/cyberia/cyberia-load.test.js +466 -0
- 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 +338 -0
- package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
- 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/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
- package/test/integration/infra/1-security/config-scope.test.js +305 -0
- package/test/integration/infra/1-security/container-storage.test.js +356 -0
- package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
- package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
- package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
- package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
- package/test/integration/infra/1-security/systemd-service.test.js +70 -0
- package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
- package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
- package/test/integration/infra/2-network/node-capability.test.js +182 -0
- package/test/integration/infra/2-network/wireguard-cli.test.js +1187 -0
- package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +649 -55
- package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
- package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
- package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
- 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/deploy-routes.test.js +379 -0
- package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
- package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
- package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
- package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
- package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
- package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
- package/test/integration/infra/5-observability/event-notification.test.js +197 -0
- package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
- package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
- package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
- package/test/support/shell-harness.js +73 -0
- package/test/unit/build-template.test.js +97 -0
- package/test/unit/build-workflow-offline.test.js +132 -0
- package/test/unit/catalog.test.js +71 -0
- package/test/unit/client-build-docs.test.js +361 -0
- package/test/unit/client-bundle.test.js +313 -0
- package/test/unit/conf-loading.test.js +303 -0
- package/test/unit/conf-resolution.test.js +996 -0
- package/test/unit/coverage-artifact.test.js +221 -0
- package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
- package/test/unit/cyberia/instance-backup.test.js +183 -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-env-resolution.test.js +38 -0
- package/test/unit/deploy-log-table.test.js +518 -0
- package/test/unit/downloader-integrity.test.js +98 -0
- package/test/unit/execution-profiles.test.js +219 -0
- package/test/unit/file-reference-registry.test.js +141 -0
- package/test/unit/fleet-sync-source.test.js +149 -0
- package/test/unit/fs-storage-paths.test.js +596 -0
- package/test/unit/logger-redaction.test.js +141 -0
- package/test/unit/package.test.js +457 -0
- package/test/unit/prepare-host.test.js +382 -0
- package/test/unit/process-environment.test.js +18 -0
- package/test/unit/propagation-message.test.js +78 -0
- package/test/unit/redeploy-plan.test.js +24 -0
- package/test/unit/release-bump.test.js +474 -0
- package/test/unit/ssh-output-redaction.test.js +28 -0
- package/test/unit/start-options.test.js +46 -0
- package/test/unit/test-tiers.test.js +220 -0
- package/test/unit/zip-archive.test.js +142 -0
- package/vitest.config.js +66 -0
- package/.nycrc +0 -9
- package/deploy/lib/logging.sh +0 -96
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
- package/manifests/mongodb/pv-pvc.yaml +0 -59
- package/scripts/coverall-test-cyberia.sh +0 -24
- package/scripts/coverall-test.sh +0 -24
- package/scripts/link-local-underpost-cli.sh +0 -6
- package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
- package/src/api/user/user.build.js +0 -16
- package/src/cli/env.js +0 -177
- package/src/client/components/core/Blockchain.js +0 -41
- package/src/client/components/core/Blog.js +0 -9
- package/src/client/components/core/KeyboardAvoidance.js +0 -145
- package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/white0-min.jpg +0 -0
- package/src/client/public/default/assets/background/white0.jpg +0 -0
- package/src/client/public/doc/favicon.ico +0 -0
- package/src/client/public/doc/sitemap +0 -148
- package/src/server/downloader.js +0 -73
- package/src/server/environment.js +0 -98
|
@@ -1,78 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical
|
|
2
|
+
* Canonical simulation defaults for the Cyberia runtime: per-entity-type item
|
|
3
|
+
* sets, simulation / AOI / combat / economy / skill rules, equipment rules,
|
|
4
|
+
* status-icon numeric IDs, and the seed content (dialogues, actions, quests)
|
|
5
|
+
* the CLI writes to Mongo.
|
|
3
6
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
7
|
+
* STRICT BOUNDARY: never import this from `src/client/`. The browser bundler
|
|
8
|
+
* resolves imports recursively, so one browser-side import ships the whole
|
|
9
|
+
* simulation defaults in the public JS payload.
|
|
6
10
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - status-icon **numeric IDs** (visuals live in client defaults)
|
|
11
|
-
* - seed content (dialogues, actions, quests) consumed by the
|
|
12
|
-
* persistence/CLI tooling that bootstraps the world
|
|
13
|
-
* - native-dependency pin list for chain-bridge tooling
|
|
14
|
-
*
|
|
15
|
-
* STRICT BOUNDARY
|
|
16
|
-
* ---------------
|
|
17
|
-
* NEVER imported from any file under `src/client/`. The browser bundler
|
|
18
|
-
* resolves imports recursively, so a single browser-side import would drag
|
|
19
|
-
* the entire simulation defaults into the public JS payload.
|
|
20
|
-
*
|
|
21
|
-
* Shared content **vocabulary** (item/entity type enums, the
|
|
22
|
-
* `DefaultCyberiaItems` registry, `ENTITY_TYPE_TO_ITEM_TYPES`, the quest
|
|
23
|
-
* step objective enum) lives in `SharedDefaultsCyberia.js`. This file
|
|
24
|
-
* re-imports those so the browser editor never needs to reach into
|
|
25
|
-
* server-defaults to learn the schema.
|
|
26
|
-
*
|
|
27
|
-
* Consumers:
|
|
28
|
-
* - cyberia-instance-conf model + grpc-server (gameplay config)
|
|
29
|
-
* - cyberia-world-generator / cyberia-fallback-world (world build)
|
|
30
|
-
* - cyberia-quest / cyberia-action / Mongo seed scripts (content)
|
|
31
|
-
* - bin/cyberia + bin/build + bin/deploy (CLI + chain bridge)
|
|
11
|
+
* Shared content vocabulary (item / entity type enums, `DefaultCyberiaItems`,
|
|
12
|
+
* `ENTITY_TYPE_TO_ITEM_TYPES`, quest step objectives) lives in
|
|
13
|
+
* `SharedDefaultsCyberia.js`.
|
|
32
14
|
*
|
|
33
15
|
* @module src/api/cyberia-server-defaults/cyberia-server-defaults.js
|
|
34
16
|
*/
|
|
35
17
|
|
|
36
|
-
//
|
|
37
|
-
// browser bundler can resolve the URL inside the client tree. Engine-side
|
|
38
|
-
// Node imports work from any path, so we reach into it from here.
|
|
18
|
+
// Shared vocabulary lives under src/client/ so the browser bundler resolves it.
|
|
39
19
|
import {
|
|
40
20
|
ITEM_TYPES,
|
|
21
|
+
STAT_TYPES,
|
|
22
|
+
STAT_MODIFIER_MAX,
|
|
23
|
+
ENTITY_LEVEL_MAX,
|
|
41
24
|
ENTITY_TYPES,
|
|
42
25
|
SKILL_LOGIC_ID_VALUES,
|
|
43
26
|
isCanonicalSkillLogicId,
|
|
27
|
+
AUDIO_BUSES,
|
|
28
|
+
AUDIO_BUS_MUSIC,
|
|
29
|
+
AUDIO_BUS_SFX,
|
|
30
|
+
AUDIO_LOGIC_ID_BUSES,
|
|
31
|
+
AUDIO_LOGIC_ID_VALUES,
|
|
32
|
+
isCanonicalAudioLogicId,
|
|
44
33
|
} from '../../client/components/cyberia/SharedDefaultsCyberia.js';
|
|
45
34
|
|
|
46
35
|
export const DOCKER_COMPOSE_ID = 'cyberia';
|
|
47
36
|
|
|
48
37
|
export const DEPLOY_ID = 'dd-cyberia';
|
|
49
38
|
|
|
50
|
-
/**
|
|
51
|
-
* Native-dependency pin list. Consumed by `bin/build.js` and `bin/deploy.js`
|
|
52
|
-
* when materialising the Cyberia subtree so versions stay reproducible
|
|
53
|
-
* across CI / production deploys.
|
|
54
|
-
*/
|
|
55
|
-
export class CyberiaDependencies {
|
|
56
|
-
static 'maxrects-packer' = '^2.7.3';
|
|
57
|
-
static pngjs = '^7.0.0';
|
|
58
|
-
static jimp = '^1.6.0';
|
|
59
|
-
static sharp = '^0.34.5';
|
|
60
|
-
static ethers = '~6.16.0';
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export const DOCKER_SCRIPTS = {
|
|
64
|
-
'docker:generate': `node bin docker-compose --generate --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
65
|
-
'docker:up': `node bin docker-compose --up --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
66
|
-
'docker:up:build': `node bin docker-compose --up --build --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
67
|
-
'docker:down': `node bin docker-compose --down --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
68
|
-
'docker:down:volumes': `node bin docker-compose --down --volumes --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
69
|
-
'docker:restart': `node bin docker-compose --restart --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
70
|
-
'docker:pull': `node bin docker-compose --pull --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
71
|
-
'docker:logs': `node bin docker-compose --logs --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
72
|
-
'docker:status': `node bin docker-compose --status --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
73
|
-
'docker:reset': `node bin docker-compose --reset --deploy-id ${DEPLOY_ID} --docker-compose-id ${DOCKER_COMPOSE_ID}`,
|
|
74
|
-
};
|
|
75
|
-
|
|
76
39
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
77
40
|
// Skill / action / quest seed content
|
|
78
41
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -86,10 +49,9 @@ export const DOCKER_SCRIPTS = {
|
|
|
86
49
|
* - `skills` (expanded metadata with name, description, summoned entity)
|
|
87
50
|
*
|
|
88
51
|
* Consumers:
|
|
89
|
-
* - `
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* `skills` metadata the instance-conf skillConfig schema drops)
|
|
52
|
+
* - `bin/cyberia.js seed-skills` (upsert into the cyberia-skill collection, which is the
|
|
53
|
+
* authoritative store — an instance then runs the subset its own content triggers)
|
|
54
|
+
* - the fallback world, which has no collection to read
|
|
93
55
|
*/
|
|
94
56
|
export const DefaultSkillConfig = [
|
|
95
57
|
{
|
|
@@ -118,18 +80,6 @@ export const DefaultSkillConfig = [
|
|
|
118
80
|
},
|
|
119
81
|
],
|
|
120
82
|
},
|
|
121
|
-
// {
|
|
122
|
-
// triggerItemId: 'anon',
|
|
123
|
-
// logicEventIds: ['doppelganger'],
|
|
124
|
-
// skills: [
|
|
125
|
-
// {
|
|
126
|
-
// logicEventId: 'doppelganger',
|
|
127
|
-
// name: 'Doppelganger',
|
|
128
|
-
// description: 'Summons a passive clone of yourself that wanders nearby. Spawn chance scales with Intelligence.',
|
|
129
|
-
// summonedEntityItemId: '$active_skin',
|
|
130
|
-
// },
|
|
131
|
-
// ],
|
|
132
|
-
// },
|
|
133
83
|
{
|
|
134
84
|
triggerItemId: 'hatchet',
|
|
135
85
|
logicEventIds: ['projectile'],
|
|
@@ -145,9 +95,7 @@ export const DefaultSkillConfig = [
|
|
|
145
95
|
},
|
|
146
96
|
];
|
|
147
97
|
|
|
148
|
-
//
|
|
149
|
-
// SharedDefaultsCyberia.js is the single source of truth, so a typo or a handler
|
|
150
|
-
// the dispatcher does not know must surface at boot, not as a silent no-op skill.
|
|
98
|
+
// A logicEventId absent from the SharedDefaultsCyberia registry fails at boot.
|
|
151
99
|
for (const cfg of DefaultSkillConfig) {
|
|
152
100
|
for (const logicEventId of [...(cfg.logicEventIds || []), ...(cfg.skills || []).map((sk) => sk.logicEventId)]) {
|
|
153
101
|
if (!isCanonicalSkillLogicId(logicEventId)) {
|
|
@@ -163,18 +111,11 @@ for (const cfg of DefaultSkillConfig) {
|
|
|
163
111
|
// Lain demo quests (testing only) — single source of truth
|
|
164
112
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
165
113
|
//
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
// These specs drive THREE derived structures so they can never drift apart:
|
|
170
|
-
// - DefaultCyberiaQuests — the quest definitions
|
|
171
|
-
// - DefaultCyberiaDialogues — one quest-talk dialogue per talk objective
|
|
172
|
-
// - DefaultCyberiaActions — Lain's questDialogueCodes mapping
|
|
114
|
+
// No-prerequisite quests offered by Lain (15,22). These specs derive the quest
|
|
115
|
+
// definitions, their quest-talk dialogues, and Lain's questDialogueCodes map.
|
|
173
116
|
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
// completed dialogue matches that mapping, so a quest without one could be
|
|
177
|
-
// satisfied by reading the NPC's default greeting.
|
|
117
|
+
// Each `talk` objective needs its own quest-talk dialogue on the provider's
|
|
118
|
+
// action. The server validates a talk only against that mapping.
|
|
178
119
|
|
|
179
120
|
const LAIN_DEMO_QUEST_SPECS = [
|
|
180
121
|
{
|
|
@@ -288,12 +229,7 @@ const LAIN_DEMO_TALK_SPECS = LAIN_DEMO_QUEST_SPECS.filter((q) =>
|
|
|
288
229
|
(q.steps || []).some((s) => (s.objectives || []).some((o) => o.type === 'talk' && o.itemId === 'lain')),
|
|
289
230
|
);
|
|
290
231
|
|
|
291
|
-
/**
|
|
292
|
-
* Default dialogue seeds. Mirrors `CyberiaDialogue` model schema:
|
|
293
|
-
* { code, order, speaker, text, mood }
|
|
294
|
-
*
|
|
295
|
-
* Used by the seed/migration script to populate Mongo on first boot.
|
|
296
|
-
*/
|
|
232
|
+
/** Dialogue seeds ({ code, order, speaker, text, mood }) the CLI writes to Mongo. */
|
|
297
233
|
export const DefaultCyberiaDialogues = [
|
|
298
234
|
{
|
|
299
235
|
code: 'default-coin',
|
|
@@ -553,12 +489,10 @@ export const DefaultCyberiaDialogues = [
|
|
|
553
489
|
* Each entry follows the `CyberiaAction` model schema.
|
|
554
490
|
*/
|
|
555
491
|
export const DefaultCyberiaActions = [
|
|
556
|
-
// An action
|
|
557
|
-
//
|
|
558
|
-
//
|
|
559
|
-
//
|
|
560
|
-
// handles to the dialogue shown for it (offer + talk-objective validation).
|
|
561
|
-
// The quests an NPC OFFERS are those whose source cell matches the action's.
|
|
492
|
+
// An action declares the capabilities available at a cell. `code` is a
|
|
493
|
+
// location slug, `label` the bot's overhead name, and the NPC skin comes from
|
|
494
|
+
// `dialogCode` (default-<skin>). `questDialogueCodes` maps a quest to its
|
|
495
|
+
// dialogue. An NPC offers the quests whose source cell matches the action's.
|
|
562
496
|
{
|
|
563
497
|
code: 'loc-fallback-map-0-12-10',
|
|
564
498
|
label: 'Wason',
|
|
@@ -592,9 +526,8 @@ export const DefaultCyberiaActions = [
|
|
|
592
526
|
questDialogueCodes: [{ questCode: 'bounty-quest-alpha', dialogCode: 'quest-talk-agent' }],
|
|
593
527
|
},
|
|
594
528
|
{
|
|
595
|
-
// Shop capability: an action
|
|
596
|
-
//
|
|
597
|
-
// against this catalog (price item + quantity).
|
|
529
|
+
// Shop capability: an action with shopItems is a vendor. The simulation
|
|
530
|
+
// validates every purchase against this catalog (price item + quantity).
|
|
598
531
|
code: 'loc-fallback-map-0-18-16',
|
|
599
532
|
label: 'Punk',
|
|
600
533
|
sourceMapCode: 'fallback-map-0',
|
|
@@ -604,12 +537,9 @@ export const DefaultCyberiaActions = [
|
|
|
604
537
|
shopItems: [{ itemId: 'tim-knife', priceItemId: 'coin', priceQty: 10 }],
|
|
605
538
|
},
|
|
606
539
|
{
|
|
607
|
-
// Assembler capability: an action
|
|
608
|
-
// terminal. The
|
|
609
|
-
//
|
|
610
|
-
// Every id here is obtainable inside the fallback world — wood from the
|
|
611
|
-
// resource nodes, coin from field drops — so the loop is playable on a
|
|
612
|
-
// fresh spawn with no seeding.
|
|
540
|
+
// Assembler capability: an action with craftRecipes is a fabrication
|
|
541
|
+
// terminal. The simulation validates every synthesis against these recipes.
|
|
542
|
+
// Every id here is obtainable in the fallback world with no seeding.
|
|
613
543
|
code: 'loc-fallback-map-0-15-16',
|
|
614
544
|
label: 'Eiri',
|
|
615
545
|
sourceMapCode: 'fallback-map-0',
|
|
@@ -635,10 +565,7 @@ export const DefaultCyberiaActions = [
|
|
|
635
565
|
craftTimeMs: 5000,
|
|
636
566
|
},
|
|
637
567
|
{
|
|
638
|
-
// Multi-output: one blade breaks down into three
|
|
639
|
-
// the assembly UI and the arrival flights are exercised with more than
|
|
640
|
-
// a single result slot. Closes the loop with Punk's shop — buy a knife,
|
|
641
|
-
// salvage it back into parts.
|
|
568
|
+
// Multi-output salvage recipe: one blade breaks down into three stacks.
|
|
642
569
|
outputItems: [
|
|
643
570
|
{ itemId: 'wood-drop-1', qty: 2 },
|
|
644
571
|
{ itemId: 'wood-drop-2', qty: 1 },
|
|
@@ -650,9 +577,8 @@ export const DefaultCyberiaActions = [
|
|
|
650
577
|
],
|
|
651
578
|
},
|
|
652
579
|
{
|
|
653
|
-
// Storage capability: an action
|
|
654
|
-
//
|
|
655
|
-
// capacity (25 → 5x5) and the simulation owns the contents.
|
|
580
|
+
// Storage capability: an action with storageSlots is a personal vault. The
|
|
581
|
+
// simulation owns the contents; the slot count sizes the grid (25 → 5x5).
|
|
656
582
|
code: 'loc-fallback-map-0-12-22',
|
|
657
583
|
label: 'Kaneki',
|
|
658
584
|
sourceMapCode: 'fallback-map-0',
|
|
@@ -668,9 +594,7 @@ export const DefaultCyberiaActions = [
|
|
|
668
594
|
sourceCellX: 15,
|
|
669
595
|
sourceCellY: 22,
|
|
670
596
|
dialogCode: 'default-lain',
|
|
671
|
-
//
|
|
672
|
-
// dialogue here — without the mapping the server would accept the
|
|
673
|
-
// default greeting as the talk, and no quest-talk button would show.
|
|
597
|
+
// One quest-talk dialogue per demo quest that carries a `talk` objective.
|
|
674
598
|
questDialogueCodes: LAIN_DEMO_TALK_SPECS.map((q) => ({
|
|
675
599
|
questCode: lainDemoQuestCode(q.suffix),
|
|
676
600
|
dialogCode: lainDemoTalkDialogCode(q.suffix),
|
|
@@ -713,8 +637,7 @@ export const DefaultCyberiaQuests = [
|
|
|
713
637
|
rewards: [{ itemId: 'coin', quantity: 50 }],
|
|
714
638
|
},
|
|
715
639
|
{
|
|
716
|
-
// Parallel initial mission
|
|
717
|
-
// prerequisites, so the player can accept it alongside the intro quest.
|
|
640
|
+
// Parallel initial mission: same source cell as the intro quest, no prerequisites.
|
|
718
641
|
code: 'wason-errand',
|
|
719
642
|
title: "Wason's Errand",
|
|
720
643
|
description: 'Gather coins from the field and bring them back to Wason.',
|
|
@@ -767,8 +690,7 @@ export const DefaultCyberiaQuests = [
|
|
|
767
690
|
rewards: [{ itemId: 'hatchet', quantity: 1 }],
|
|
768
691
|
},
|
|
769
692
|
// ── Demo quests (testing only) ─────────────────────────────────────────────
|
|
770
|
-
//
|
|
771
|
-
// quest-talk dialogues, and Lain's questDialogueCodes mapping stay in sync.
|
|
693
|
+
// Derived from LAIN_DEMO_QUEST_SPECS.
|
|
772
694
|
...LAIN_DEMO_QUEST_SPECS.map((q) => ({
|
|
773
695
|
code: lainDemoQuestCode(q.suffix),
|
|
774
696
|
title: q.title,
|
|
@@ -788,11 +710,9 @@ export const DefaultCyberiaQuests = [
|
|
|
788
710
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
789
711
|
|
|
790
712
|
/**
|
|
791
|
-
*
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
* of the entity's current state: liveItemIds while alive, deadItemIds while
|
|
795
|
-
* in the Fragmented State (see DEFAULT_DEAD_ITEM_ID).
|
|
713
|
+
* Which ObjectLayer item types may be active together on an entity. The server
|
|
714
|
+
* validates every item_activation against these rules, scoped to the item set
|
|
715
|
+
* of the entity state: liveItemIds while alive, deadItemIds while dead.
|
|
796
716
|
*/
|
|
797
717
|
export const EQUIPMENT_RULES_DEFAULTS = Object.freeze({
|
|
798
718
|
activeItemTypes: [ITEM_TYPES.skin, ITEM_TYPES.breastplate, ITEM_TYPES.weapon],
|
|
@@ -805,13 +725,10 @@ export const EQUIPMENT_RULES_DEFAULTS = Object.freeze({
|
|
|
805
725
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
806
726
|
|
|
807
727
|
/**
|
|
808
|
-
* Numeric Entity Status Indicator (ESI) IDs.
|
|
809
|
-
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
* IDs MUST stay in sync with:
|
|
814
|
-
* cyberia-server/src/entity_status.go (StatusNone … StatusResourceExtracted)
|
|
728
|
+
* Numeric Entity Status Indicator (ESI) IDs. The server stamps one u8 ID on
|
|
729
|
+
* every entity in the AOI wire format; the client resolves the icon from
|
|
730
|
+
* `SharedDefaultsCyberia.js#STATUS_ICONS_PRESENTATION`. These IDs are wire
|
|
731
|
+
* contract: append only, never renumber.
|
|
815
732
|
*/
|
|
816
733
|
export const STATUS_ICONS = Object.freeze([
|
|
817
734
|
{ id: 0, name: 'none', description: 'No icon (skill/coin bots, world objects)' },
|
|
@@ -862,14 +779,14 @@ export const RESOURCE_ENTITY_TYPE_DEFAULTS = Object.freeze([
|
|
|
862
779
|
liveItemIds: ['wood-1'],
|
|
863
780
|
deadItemIds: ['wood-extracted-1'],
|
|
864
781
|
dropItemIds: ['wood-drop-1'],
|
|
865
|
-
|
|
782
|
+
inventoryItemsIds: [],
|
|
866
783
|
}),
|
|
867
784
|
Object.freeze({
|
|
868
785
|
entityType: ENTITY_TYPES.resource,
|
|
869
786
|
liveItemIds: ['wood-2'],
|
|
870
787
|
deadItemIds: ['wood-extracted-2'],
|
|
871
788
|
dropItemIds: ['wood-drop-2'],
|
|
872
|
-
|
|
789
|
+
inventoryItemsIds: [],
|
|
873
790
|
}),
|
|
874
791
|
]);
|
|
875
792
|
|
|
@@ -877,63 +794,51 @@ export const RESOURCE_ENTITY_TYPE_DEFAULTS = Object.freeze([
|
|
|
877
794
|
export const RESOURCE_ENTITY_TYPE_DEFAULT = RESOURCE_ENTITY_TYPE_DEFAULTS[0];
|
|
878
795
|
|
|
879
796
|
/**
|
|
880
|
-
* Canonical dead-state visual (Fragmentation)
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
* EQUIPMENT_RULES_DEFAULTS scoped to the dead-item set, and remembered across
|
|
885
|
-
* deaths. Only this default id is excluded from the player inventory wire;
|
|
886
|
-
* the rest appear (lock-badged while alive). No defaultObjectLayers row is
|
|
887
|
-
* needed — the death handler appends missing dead items on demand.
|
|
888
|
-
* Mirrored by `defaultDeadItemID` in cyberia-server/game/dead_items.go.
|
|
797
|
+
* Canonical dead-state visual (Fragmentation). The server applies it when an
|
|
798
|
+
* entity-type default declares no deadItemIds. Dead items are equippable only
|
|
799
|
+
* while the entity is dead and are kept across deaths. This id stays out of
|
|
800
|
+
* the player inventory wire; other dead items appear in it.
|
|
889
801
|
*/
|
|
890
802
|
export const DEFAULT_DEAD_ITEM_ID = 'fragmentation';
|
|
891
803
|
|
|
892
804
|
/**
|
|
893
|
-
* Per-entity-type defaults
|
|
894
|
-
*
|
|
805
|
+
* Per-entity-type defaults the simulation consumes: live / dead / drop item IDs
|
|
806
|
+
* and the seed inventory of a new entity.
|
|
895
807
|
*
|
|
896
808
|
* Field reference:
|
|
897
|
-
* entityType
|
|
898
|
-
* liveItemIds
|
|
899
|
-
*
|
|
900
|
-
* dropItemIds
|
|
901
|
-
*
|
|
809
|
+
* entityType — server-side category string.
|
|
810
|
+
* liveItemIds — ObjectLayer item IDs while the entity is alive.
|
|
811
|
+
* deadItemIDs — IDs swapped in on death / ghost state.
|
|
812
|
+
* dropItemIds — IDs granted to the killer on resource depletion.
|
|
813
|
+
* inventoryItemsIds — IDs the entity carries but never activates by lifecycle.
|
|
814
|
+
* overrideItemsIdsState — per-id overrides of what those lists derive.
|
|
815
|
+
*
|
|
816
|
+
* The three lifecycle lists are discriminators, not separate inventories: an entity holds one
|
|
817
|
+
* inventory and the runtime activates the slots the context calls for. `inventoryItemsIds` is only
|
|
818
|
+
* for what no lifecycle state ever activates — a coin balance, say. See
|
|
819
|
+
* {@link resolveEntityInventory}, which is where that single inventory is derived.
|
|
902
820
|
*/
|
|
903
821
|
export const ENTITY_TYPE_DEFAULTS = Object.freeze([
|
|
904
822
|
{
|
|
905
823
|
entityType: ENTITY_TYPES.player,
|
|
906
824
|
liveItemIds: ['anon', 'atlas_pistol_mk2'],
|
|
907
825
|
deadItemIds: [DEFAULT_DEAD_ITEM_ID],
|
|
908
|
-
|
|
909
|
-
{ itemId: 'anon', active: true, quantity: 1 },
|
|
910
|
-
{ itemId: 'atlas_pistol_mk2', active: true, quantity: 1 },
|
|
911
|
-
{ itemId: 'coin', active: false, quantity: 0 },
|
|
912
|
-
],
|
|
826
|
+
inventoryItemsIds: ['coin'],
|
|
913
827
|
},
|
|
914
828
|
{
|
|
915
829
|
entityType: ENTITY_TYPES.other_player,
|
|
916
830
|
liveItemIds: ['anon', 'atlas_pistol_mk2'],
|
|
917
831
|
deadItemIds: [DEFAULT_DEAD_ITEM_ID],
|
|
918
|
-
|
|
919
|
-
{ itemId: 'anon', active: true, quantity: 1 },
|
|
920
|
-
{ itemId: 'atlas_pistol_mk2', active: true, quantity: 1 },
|
|
921
|
-
{ itemId: 'coin', active: false, quantity: 0 },
|
|
922
|
-
],
|
|
832
|
+
inventoryItemsIds: ['coin'],
|
|
923
833
|
},
|
|
924
834
|
{
|
|
925
835
|
entityType: ENTITY_TYPES.bot,
|
|
926
836
|
liveItemIds: ['purple'],
|
|
927
837
|
deadItemIds: [DEFAULT_DEAD_ITEM_ID],
|
|
928
|
-
|
|
929
|
-
{ itemId: 'purple', active: true, quantity: 1 },
|
|
930
|
-
{ itemId: 'coin', active: false, quantity: 0 },
|
|
931
|
-
],
|
|
838
|
+
inventoryItemsIds: ['coin'],
|
|
932
839
|
},
|
|
933
|
-
// Fallback-world mission
|
|
934
|
-
//
|
|
935
|
-
// barely move from their spawn and are immortal. Lain only talks in place, so
|
|
936
|
-
// she is fully static. Authors can retarget any of these via EntityEngineCyberia.
|
|
840
|
+
// Fallback-world mission givers, keyed by their active skin. `provider` bots
|
|
841
|
+
// stay near their spawn and are immortal; `provider-static` bots do not move.
|
|
937
842
|
{ entityType: ENTITY_TYPES.bot, liveItemIds: ['wason'], deadItemIds: [DEFAULT_DEAD_ITEM_ID], behavior: 'provider' },
|
|
938
843
|
{ entityType: ENTITY_TYPES.bot, liveItemIds: ['alex'], deadItemIds: [DEFAULT_DEAD_ITEM_ID], behavior: 'provider' },
|
|
939
844
|
{ entityType: ENTITY_TYPES.bot, liveItemIds: ['agent'], deadItemIds: [DEFAULT_DEAD_ITEM_ID], behavior: 'provider' },
|
|
@@ -960,37 +865,277 @@ export const ENTITY_TYPE_DEFAULTS = Object.freeze([
|
|
|
960
865
|
entityType: ENTITY_TYPES.skill,
|
|
961
866
|
liveItemIds: ['atlas_pistol_mk2_bullet'],
|
|
962
867
|
deadItemIds: [],
|
|
963
|
-
|
|
868
|
+
inventoryItemsIds: [],
|
|
964
869
|
},
|
|
965
870
|
{
|
|
966
871
|
entityType: ENTITY_TYPES.coin,
|
|
967
872
|
liveItemIds: ['coin'],
|
|
968
873
|
deadItemIds: [],
|
|
969
|
-
|
|
874
|
+
inventoryItemsIds: [],
|
|
970
875
|
},
|
|
971
|
-
{ entityType: ENTITY_TYPES.floor, liveItemIds: ['grass'], deadItemIds: [], dropItemIds: [],
|
|
972
|
-
{ entityType: ENTITY_TYPES.obstacle, liveItemIds: [], deadItemIds: [], dropItemIds: [],
|
|
973
|
-
{ entityType: ENTITY_TYPES.portal, liveItemIds: [], deadItemIds: [], dropItemIds: [],
|
|
974
|
-
{ entityType: ENTITY_TYPES.foreground, liveItemIds: [], deadItemIds: [], dropItemIds: [],
|
|
876
|
+
{ entityType: ENTITY_TYPES.floor, liveItemIds: ['grass'], deadItemIds: [], dropItemIds: [], inventoryItemsIds: [] },
|
|
877
|
+
{ entityType: ENTITY_TYPES.obstacle, liveItemIds: [], deadItemIds: [], dropItemIds: [], inventoryItemsIds: [] },
|
|
878
|
+
{ entityType: ENTITY_TYPES.portal, liveItemIds: [], deadItemIds: [], dropItemIds: [], inventoryItemsIds: [] },
|
|
879
|
+
{ entityType: ENTITY_TYPES.foreground, liveItemIds: [], deadItemIds: [], dropItemIds: [], inventoryItemsIds: [] },
|
|
975
880
|
// Static decorator — non-moving, passable, depth-sorted. Visuals come from the
|
|
976
881
|
// map definition / world generator; no live/dead/drop rotation.
|
|
977
|
-
{ entityType: ENTITY_TYPES.static, liveItemIds: [], deadItemIds: [], dropItemIds: [],
|
|
882
|
+
{ entityType: ENTITY_TYPES.static, liveItemIds: [], deadItemIds: [], dropItemIds: [], inventoryItemsIds: [] },
|
|
978
883
|
...RESOURCE_ENTITY_TYPE_DEFAULTS,
|
|
979
884
|
]);
|
|
980
885
|
|
|
886
|
+
/**
|
|
887
|
+
* The default a placed entity resolves to, by the item ids it already carries.
|
|
888
|
+
*
|
|
889
|
+
* Mirrors `resolveEntityDefaultBuild` in cyberia-server/game/entity_defaults.go, which is the rule
|
|
890
|
+
* the simulation applies at spawn: a default matches only when the entity carries ALL of its live
|
|
891
|
+
* ids, and the most specific match wins — the one requiring the largest set, so `{purple, pistol}`
|
|
892
|
+
* beats `{purple}`. Ties keep the earlier default, which makes the order a world declares them in
|
|
893
|
+
* significant. With no containing match, the first default of that type answers.
|
|
894
|
+
*
|
|
895
|
+
* @param {{entityType: string, itemIds?: string[]}} entity - Placed entity type and its item ids.
|
|
896
|
+
* @param {Array<{entityType: string, liveItemIds?: string[]}>} defaults - Candidate defaults, in order.
|
|
897
|
+
* @returns {object|undefined} The matched default, or undefined when the type has none.
|
|
898
|
+
*/
|
|
899
|
+
export function resolveEntityDefaultBuild({ entityType, itemIds = [] }, defaults = []) {
|
|
900
|
+
const carried = new Set(itemIds.filter(Boolean));
|
|
901
|
+
let firstOfType;
|
|
902
|
+
let matched;
|
|
903
|
+
let matchedSize = 0;
|
|
904
|
+
for (const candidate of defaults) {
|
|
905
|
+
if (candidate?.entityType !== entityType) continue;
|
|
906
|
+
firstOfType ??= candidate;
|
|
907
|
+
const liveItemIds = candidate.liveItemIds || [];
|
|
908
|
+
if (carried.size === 0 || liveItemIds.length === 0) continue;
|
|
909
|
+
if (!liveItemIds.every((itemId) => carried.has(itemId))) continue;
|
|
910
|
+
if (liveItemIds.length > matchedSize) {
|
|
911
|
+
matched = candidate;
|
|
912
|
+
matchedSize = liveItemIds.length;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
return matched ?? firstOfType;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* The canonical inventory contract: one entity, one inventory, derived.
|
|
920
|
+
*
|
|
921
|
+
* An entity carries the union of every item id its default names — the lifecycle discriminators
|
|
922
|
+
* (live / dead / drop) and the inventory-only extras — deduplicated, in that order. Which slots
|
|
923
|
+
* are *active* is not stored anywhere: it follows from the discriminator the id belongs to, and
|
|
924
|
+
* the runtime flips them as context changes (`activateOrAppendLayer` in
|
|
925
|
+
* cyberia-server/game/dead_items.go activates the slot that is already there). Seeding the whole
|
|
926
|
+
* union is what lets it activate rather than append.
|
|
927
|
+
*
|
|
928
|
+
* Spawn state is alive, so the live ids are the active ones. A worn item and an inventory-only
|
|
929
|
+
* item are stock the entity holds, so each starts as one unit. A dead or drop id is a lifecycle
|
|
930
|
+
* slot the runtime activates or scatters later, so it starts empty. The server owns the coin
|
|
931
|
+
* quantity from spawn on, whatever the seed says.
|
|
932
|
+
*
|
|
933
|
+
* `overrideItemsIdsState` adjusts that derivation for one carried id: `active` forces the spawn
|
|
934
|
+
* state — a skin the equipment rules would otherwise leave inactive — and `quantity` sizes a
|
|
935
|
+
* stack, which is how a drop bundle declares how many it scatters. It never adds an id: the union
|
|
936
|
+
* decides membership, an override only what a member starts as, so a rule naming an id no list
|
|
937
|
+
* carries does nothing at all.
|
|
938
|
+
*
|
|
939
|
+
* Activating one item can deactivate another. `EQUIPMENT_RULES_DEFAULTS` allows one active item
|
|
940
|
+
* per type, so an override that activates a skin is a decision about which skin the entity wears:
|
|
941
|
+
* the one the lists derived gives way to the one the author named. Only the governed types are
|
|
942
|
+
* constrained, and only where the item's type is known — a resource visual, a coin, anything the
|
|
943
|
+
* rules do not name, passes through untouched.
|
|
944
|
+
*
|
|
945
|
+
* @param {{liveItemIds?:string[],deadItemIds?:string[],dropItemIds?:string[],inventoryItemsIds?:string[],
|
|
946
|
+
* overrideItemsIdsState?:Array<{itemId:string,active?:boolean,quantity?:number}>}} entityDefault
|
|
947
|
+
* @param {{itemTypes?:Object<string,string>|Map<string,string>}} [context] - itemId → item type, where known.
|
|
948
|
+
* @returns {Array<{itemId:string,active:boolean,quantity:number}>} Inventory rows, as the wire carries them.
|
|
949
|
+
*/
|
|
950
|
+
export function resolveEntityInventory(entityDefault = {}, { itemTypes } = {}) {
|
|
951
|
+
const live = new Set(entityDefault.liveItemIds || []);
|
|
952
|
+
const overrides = new Map(
|
|
953
|
+
(entityDefault.overrideItemsIdsState || []).filter((rule) => rule?.itemId).map((rule) => [rule.itemId, rule]),
|
|
954
|
+
);
|
|
955
|
+
const itemIds = [
|
|
956
|
+
...new Set(
|
|
957
|
+
[
|
|
958
|
+
...(entityDefault.liveItemIds || []),
|
|
959
|
+
...(entityDefault.deadItemIds || []),
|
|
960
|
+
...(entityDefault.dropItemIds || []),
|
|
961
|
+
...(entityDefault.inventoryItemsIds || []),
|
|
962
|
+
].filter(Boolean),
|
|
963
|
+
),
|
|
964
|
+
];
|
|
965
|
+
const drops = new Set(entityDefault.dropItemIds || []);
|
|
966
|
+
const stock = new Set(entityDefault.inventoryItemsIds || []);
|
|
967
|
+
const rows = itemIds.map((itemId) => {
|
|
968
|
+
const override = overrides.get(itemId);
|
|
969
|
+
const active = 'boolean' === typeof override?.active ? override.active : live.has(itemId);
|
|
970
|
+
const held = active || stock.has(itemId);
|
|
971
|
+
const quantity = Number.isFinite(override?.quantity) ? override.quantity : held ? 1 : 0;
|
|
972
|
+
// A drop id scatters on death unless an override says how often. Rows that are not drops
|
|
973
|
+
// carry the same 1, so every consumer reads one field and never a missing one.
|
|
974
|
+
const dropChance =
|
|
975
|
+
drops.has(itemId) && Number.isFinite(override?.dropChance)
|
|
976
|
+
? Math.min(1, Math.max(0, override.dropChance))
|
|
977
|
+
: 1;
|
|
978
|
+
return { itemId, active, quantity, dropChance };
|
|
979
|
+
});
|
|
980
|
+
return applyEquipmentRules(rows, { itemTypes, overrides });
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* One active item per governed type, with the authored choice ahead of the derived one.
|
|
985
|
+
*
|
|
986
|
+
* An override that activates an item states which item of its type the entity wears; a row the
|
|
987
|
+
* lists merely derived yields to it. Two overrides of the same type resolve in list order, first
|
|
988
|
+
* kept — the same first-wins the runtime applies when it normalizes a loadout.
|
|
989
|
+
*
|
|
990
|
+
* @param {Array<{itemId:string,active:boolean,quantity:number}>} rows - Resolved inventory rows.
|
|
991
|
+
* @param {{itemTypes?:Object<string,string>|Map<string,string>, overrides?:Map<string,object>}} context
|
|
992
|
+
* @returns {Array<{itemId:string,active:boolean,quantity:number}>} The same rows, contested types settled.
|
|
993
|
+
*/
|
|
994
|
+
function applyEquipmentRules(rows, { itemTypes, overrides = new Map() } = {}) {
|
|
995
|
+
if (!itemTypes || !EQUIPMENT_RULES_DEFAULTS.onePerType) return rows;
|
|
996
|
+
const typeOf = (itemId) => (itemTypes instanceof Map ? itemTypes.get(itemId) : itemTypes[itemId]) || '';
|
|
997
|
+
const governed = new Set(EQUIPMENT_RULES_DEFAULTS.activeItemTypes);
|
|
998
|
+
const claimed = new Set();
|
|
999
|
+
// Authored first, so an override wins the slot it asks for; the derived rows fill what is left.
|
|
1000
|
+
const contenders = [
|
|
1001
|
+
...rows.filter((row) => row.active && overrides.get(row.itemId)?.active === true),
|
|
1002
|
+
...rows.filter((row) => row.active && overrides.get(row.itemId)?.active !== true),
|
|
1003
|
+
];
|
|
1004
|
+
const deactivated = new Set();
|
|
1005
|
+
for (const row of contenders) {
|
|
1006
|
+
const type = typeOf(row.itemId);
|
|
1007
|
+
if (!governed.has(type)) continue;
|
|
1008
|
+
if (claimed.has(type)) deactivated.add(row.itemId);
|
|
1009
|
+
else claimed.add(type);
|
|
1010
|
+
}
|
|
1011
|
+
// Taking something off does not take it away: the entity still carries the stack, so only the
|
|
1012
|
+
// worn flag changes. A row emptied here would leave the inventory holding nothing.
|
|
1013
|
+
return rows.map((row) => (deactivated.has(row.itemId) ? { ...row, active: false } : row));
|
|
1014
|
+
}
|
|
1015
|
+
|
|
981
1016
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
982
|
-
//
|
|
1017
|
+
// Audio seed content
|
|
983
1018
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
984
1019
|
|
|
985
1020
|
/**
|
|
986
|
-
*
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
990
|
-
*
|
|
1021
|
+
* The audio bank the seeded world needs: one `cyberia-audio` module per asset code.
|
|
1022
|
+
*
|
|
1023
|
+
* `bus` names the module directory (`cyberia-audio/src/audio-module/<bus-id>/<code>`) and is the
|
|
1024
|
+
* asset's natural route; `options` are that module's render parameters. The code is also the
|
|
1025
|
+
* identity the client fetches by, so a code here must exist as a module there.
|
|
1026
|
+
*
|
|
1027
|
+
* @type {ReadonlyArray<{code:string,bus:'music'|'sfx',options?:object}>}
|
|
1028
|
+
*/
|
|
1029
|
+
export const DEFAULT_AUDIO_BANK = Object.freeze([
|
|
1030
|
+
...['shoot', 'coin', 'drop', 'item-pickup', 'victory', 'level-up', 'death', 'heal', 'hit', 'portal', 'ui-click', 'footsteps'].map(
|
|
1031
|
+
(code) => Object.freeze({ code, bus: AUDIO_BUS_SFX }),
|
|
1032
|
+
),
|
|
1033
|
+
Object.freeze({ code: 'exploration', bus: AUDIO_BUS_MUSIC, options: { cycles: 1 } }),
|
|
1034
|
+
Object.freeze({ code: 'combat', bus: AUDIO_BUS_MUSIC, options: { rounds: 1 } }),
|
|
1035
|
+
Object.freeze({ code: 'boss', bus: AUDIO_BUS_MUSIC }),
|
|
1036
|
+
Object.freeze({ code: 'portal-cooldown', bus: AUDIO_BUS_MUSIC }),
|
|
1037
|
+
Object.freeze({ code: 'craft', bus: AUDIO_BUS_MUSIC }),
|
|
1038
|
+
]);
|
|
1039
|
+
|
|
1040
|
+
/** Map-level audio settings the seed writes onto every seeded map. */
|
|
1041
|
+
export const DEFAULT_AUDIO_SETTINGS = Object.freeze({ volume: 0.8, crossfadeMs: 800 });
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* The music bed a seeded map falls back to when no event is holding the bus.
|
|
1045
|
+
*
|
|
1046
|
+
* One bed for every map of a world: what a map sounds like when nothing is happening is the
|
|
1047
|
+
* world's ambient identity, and the events are what make a place sound different — a combat or a
|
|
1048
|
+
* boss bed is bound to the moment it belongs to, not to a map index.
|
|
1049
|
+
*/
|
|
1050
|
+
export const DEFAULT_MAP_MUSIC = 'exploration';
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Canonical runtime-event → asset bindings.
|
|
1054
|
+
*
|
|
1055
|
+
* `logicEventId` is the semantic event the client emits (an audio LogicId, or a skill LogicId the
|
|
1056
|
+
* dispatcher runs); `audioCode` is the bank entry that answers it.
|
|
1057
|
+
*
|
|
1058
|
+
* @type {ReadonlyArray<{logicEventId:string,audioCode:string}>}
|
|
1059
|
+
*/
|
|
1060
|
+
export const DEFAULT_AUDIO_BINDINGS = Object.freeze([
|
|
1061
|
+
Object.freeze({ logicEventId: 'projectile', audioCode: 'shoot' }),
|
|
1062
|
+
Object.freeze({ logicEventId: 'coin_drop_or_transaction', audioCode: 'coin' }),
|
|
1063
|
+
Object.freeze({ logicEventId: 'drop', audioCode: 'drop' }),
|
|
1064
|
+
Object.freeze({ logicEventId: 'item-pickup', audioCode: 'item-pickup' }),
|
|
1065
|
+
Object.freeze({ logicEventId: 'craft', audioCode: 'craft' }),
|
|
1066
|
+
Object.freeze({ logicEventId: 'heal', audioCode: 'heal' }),
|
|
1067
|
+
Object.freeze({ logicEventId: 'hit', audioCode: 'hit' }),
|
|
1068
|
+
Object.freeze({ logicEventId: 'portal', audioCode: 'portal' }),
|
|
1069
|
+
Object.freeze({ logicEventId: 'ui-click', audioCode: 'ui-click' }),
|
|
1070
|
+
Object.freeze({ logicEventId: 'footsteps', audioCode: 'footsteps' }),
|
|
1071
|
+
Object.freeze({ logicEventId: 'combat', audioCode: 'combat' }),
|
|
1072
|
+
Object.freeze({ logicEventId: 'boss', audioCode: 'boss' }),
|
|
1073
|
+
Object.freeze({ logicEventId: 'victory', audioCode: 'victory' }),
|
|
1074
|
+
Object.freeze({ logicEventId: 'level-up', audioCode: 'level-up' }),
|
|
1075
|
+
Object.freeze({ logicEventId: 'death', audioCode: 'death' }),
|
|
1076
|
+
Object.freeze({ logicEventId: 'portal-cooldown', audioCode: 'portal-cooldown' }),
|
|
1077
|
+
]);
|
|
1078
|
+
|
|
1079
|
+
const AUDIO_BANK_CODES = DEFAULT_AUDIO_BANK.map(({ code }) => code);
|
|
1080
|
+
|
|
1081
|
+
for (const { code, bus } of DEFAULT_AUDIO_BANK) {
|
|
1082
|
+
if (!AUDIO_BUSES.includes(bus)) {
|
|
1083
|
+
throw new Error(`DEFAULT_AUDIO_BANK: "${code}" names bus "${bus}". Allowed: ${AUDIO_BUSES.join(', ')}`);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// Fail fast on an audio binding the runtime cannot honour: an unknown event would never fire, and
|
|
1088
|
+
// an unbanked code would leave the client requesting an asset the seed never imported. Both read
|
|
1089
|
+
// as silence at play time, so they must surface at boot instead.
|
|
1090
|
+
for (const { logicEventId, audioCode } of DEFAULT_AUDIO_BINDINGS) {
|
|
1091
|
+
if (!isCanonicalAudioLogicId(logicEventId)) {
|
|
1092
|
+
throw new Error(
|
|
1093
|
+
`DEFAULT_AUDIO_BINDINGS: unknown logicEventId "${logicEventId}". ` +
|
|
1094
|
+
`Allowed (SharedDefaultsCyberia): ${[...AUDIO_LOGIC_ID_VALUES, ...SKILL_LOGIC_ID_VALUES].join(', ')}`,
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
if (!AUDIO_BANK_CODES.includes(audioCode)) {
|
|
1098
|
+
throw new Error(
|
|
1099
|
+
`DEFAULT_AUDIO_BINDINGS: "${logicEventId}" binds audioCode "${audioCode}", ` +
|
|
1100
|
+
`absent from DEFAULT_AUDIO_BANK: ${AUDIO_BANK_CODES.join(', ')}`,
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
if (!AUDIO_BANK_CODES.includes(DEFAULT_MAP_MUSIC)) {
|
|
1105
|
+
throw new Error(`Default map music "${DEFAULT_MAP_MUSIC}" is absent from DEFAULT_AUDIO_BANK`);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* Expands {@link DEFAULT_AUDIO_BINDINGS} into `cyberia-map-audio-conf` event records.
|
|
1110
|
+
*
|
|
1111
|
+
* Routing is derived, not restated: an event's bus comes from the canonical audio registry
|
|
1112
|
+
* (a skill LogicId is a one-shot, so it falls back to sfx), music holds the bed in a loop unless
|
|
1113
|
+
* the binding is a one-shot cue, and only music crossfades.
|
|
991
1114
|
*
|
|
992
|
-
*
|
|
993
|
-
*
|
|
1115
|
+
* @param {{volume?:number,crossfadeMs?:number}} [settings=DEFAULT_AUDIO_SETTINGS]
|
|
1116
|
+
* @returns {Array<{logicEventId:string,audioCode:string,settings:object}>}
|
|
1117
|
+
*/
|
|
1118
|
+
export function buildAudioEventBindings(settings = DEFAULT_AUDIO_SETTINGS) {
|
|
1119
|
+
const { volume, crossfadeMs } = { ...DEFAULT_AUDIO_SETTINGS, ...settings };
|
|
1120
|
+
return DEFAULT_AUDIO_BINDINGS.map(({ logicEventId, audioCode }) => {
|
|
1121
|
+
const bus = AUDIO_LOGIC_ID_BUSES[logicEventId] ?? AUDIO_BUS_SFX;
|
|
1122
|
+
const music = AUDIO_BUS_MUSIC === bus;
|
|
1123
|
+
return {
|
|
1124
|
+
logicEventId,
|
|
1125
|
+
audioCode,
|
|
1126
|
+
settings: { bus, volume, loop: music, crossfadeMs: music ? crossfadeMs : 0 },
|
|
1127
|
+
};
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1132
|
+
// Player spawn
|
|
1133
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1134
|
+
|
|
1135
|
+
/**
|
|
1136
|
+
* Default player spawn policy, the shape of PlayerSpawnSchema. With `random`
|
|
1137
|
+
* false and `sourceMapCode` naming a loaded map, players spawn at
|
|
1138
|
+
* (sourceCellX, sourceCellY). Otherwise they spawn on a random walkable cell.
|
|
994
1139
|
*/
|
|
995
1140
|
export const DEFAULT_PLAYER_SPAWN = Object.freeze({
|
|
996
1141
|
sourceMapCode: 'fallback-map-0',
|
|
@@ -1012,6 +1157,58 @@ export const DEFAULT_PLAYER_SPAWN = Object.freeze({
|
|
|
1012
1157
|
* forbidden — see `SharedDefaultsCyberia.js` and the
|
|
1013
1158
|
* `/api/cyberia-client-hints` REST endpoint for presentation overrides.
|
|
1014
1159
|
*/
|
|
1160
|
+
export const PROGRESSION_RULES_DEFAULTS = Object.freeze({
|
|
1161
|
+
maxLevel: 100,
|
|
1162
|
+
xpPerLevel: 100,
|
|
1163
|
+
baseStats: Object.freeze({ effect: 5, resistance: 10, agility: 0, range: 0, intelligence: 0, utility: 0 }),
|
|
1164
|
+
perLevelStats: Object.freeze({ effect: 2, resistance: 5, agility: 1, range: 10, intelligence: 1, utility: 1 }),
|
|
1165
|
+
killXp: 25,
|
|
1166
|
+
questXp: 100,
|
|
1167
|
+
objectiveXp: 10,
|
|
1168
|
+
minAwardIntervalMs: 500,
|
|
1169
|
+
repeatWindowMs: 60000,
|
|
1170
|
+
maxRepeatAwards: 4,
|
|
1171
|
+
maxAwardsPerWindow: 30,
|
|
1172
|
+
defaultBotLevel: 1,
|
|
1173
|
+
});
|
|
1174
|
+
|
|
1175
|
+
export const PROGRESSION_RULE_LIMITS = Object.freeze(Object.fromEntries(Object.entries({
|
|
1176
|
+
maxLevel: [1, ENTITY_LEVEL_MAX], xpPerLevel: [1, 1000000],
|
|
1177
|
+
killXp: [0, 1000000], questXp: [0, 1000000], objectiveXp: [0, 1000000],
|
|
1178
|
+
minAwardIntervalMs: [1, 60000], repeatWindowMs: [1000, 3600000],
|
|
1179
|
+
maxRepeatAwards: [1, 100], maxAwardsPerWindow: [1, 1000], defaultBotLevel: [1, ENTITY_LEVEL_MAX],
|
|
1180
|
+
}).map(([key, bounds]) => [key, Object.freeze(bounds)])));
|
|
1181
|
+
|
|
1182
|
+
export function resolveProgressionRules(input = {}) {
|
|
1183
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new TypeError('Progression rules must be an object.');
|
|
1184
|
+
const defaults = PROGRESSION_RULES_DEFAULTS;
|
|
1185
|
+
const rules = {
|
|
1186
|
+
...defaults, ...input,
|
|
1187
|
+
baseStats: { ...defaults.baseStats, ...input.baseStats },
|
|
1188
|
+
perLevelStats: { ...defaults.perLevelStats, ...input.perLevelStats },
|
|
1189
|
+
};
|
|
1190
|
+
for (const key of ['baseStats', 'perLevelStats']) {
|
|
1191
|
+
if (input[key] !== undefined && (!input[key] || typeof input[key] !== 'object' || Array.isArray(input[key]))) {
|
|
1192
|
+
throw new TypeError('Base stat curve must be an object: ' + key);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (rules.defaultBotLevel > rules.maxLevel) throw new RangeError('Default bot level exceeds maximum level.');
|
|
1196
|
+
for (const [key, [min, max]] of Object.entries(PROGRESSION_RULE_LIMITS)) {
|
|
1197
|
+
if (!Number.isInteger(rules[key]) || rules[key] < min || rules[key] > max) throw new RangeError('Invalid progression rule: ' + key);
|
|
1198
|
+
}
|
|
1199
|
+
for (const block of [rules.baseStats, rules.perLevelStats]) {
|
|
1200
|
+
for (const [key, value] of Object.entries(block)) {
|
|
1201
|
+
if (!STAT_TYPES.includes(key) || !Number.isInteger(value) || value < 0 || value > STAT_MODIFIER_MAX) {
|
|
1202
|
+
throw new RangeError('Invalid base stat curve: ' + key);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
for (const key of Object.keys(rules)) {
|
|
1207
|
+
if (!(key in defaults)) throw new TypeError('Unknown progression rule: ' + key);
|
|
1208
|
+
}
|
|
1209
|
+
return rules;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1015
1212
|
export const CYBERIA_INSTANCE_CONF_DEFAULTS = {
|
|
1016
1213
|
// ── Tick model ─────────────────────────────────────────────────────
|
|
1017
1214
|
tickRate: 60,
|
|
@@ -1040,7 +1237,7 @@ export const CYBERIA_INSTANCE_CONF_DEFAULTS = {
|
|
|
1040
1237
|
// projectiles and every other entity keep entityBaseSpeed. 0 falls back to
|
|
1041
1238
|
// entityBaseSpeed.
|
|
1042
1239
|
playerBaseSpeed: 8,
|
|
1043
|
-
|
|
1240
|
+
progressionRules: PROGRESSION_RULES_DEFAULTS,
|
|
1044
1241
|
maxActiveLayers: 4,
|
|
1045
1242
|
initialLifeFraction: 1.0,
|
|
1046
1243
|
|
|
@@ -1060,29 +1257,33 @@ export const CYBERIA_INSTANCE_CONF_DEFAULTS = {
|
|
|
1060
1257
|
craftingFeePercent: 0.0,
|
|
1061
1258
|
},
|
|
1062
1259
|
|
|
1063
|
-
// ──
|
|
1064
|
-
lifeRegenChance
|
|
1065
|
-
maxChance
|
|
1260
|
+
// ── Chances, as fractions of 1 ───────────────────────────────────
|
|
1261
|
+
// A tap has lifeRegenChance to regenerate life; utility raises it. No chance the
|
|
1262
|
+
// stats raise passes maxChance, so nothing becomes a certainty.
|
|
1263
|
+
lifeRegenChance: 0.15,
|
|
1264
|
+
maxChance: 0.95,
|
|
1066
1265
|
|
|
1067
1266
|
// ── Per-entity-type defaults ───────────────────────────────────────
|
|
1068
|
-
|
|
1267
|
+
// References into the CyberiaEntityTypeDefault collection — see the schema.
|
|
1268
|
+
// Empty by default: a conf that names no document resolves against the
|
|
1269
|
+
// canonical ENTITY_TYPE_DEFAULTS above, so a fresh world is complete without
|
|
1270
|
+
// owning a single row.
|
|
1271
|
+
entityDefaults: [],
|
|
1069
1272
|
|
|
1070
1273
|
// ── Status icons (numeric IDs only — visuals live in client defaults) ──
|
|
1071
1274
|
statusIcons: STATUS_ICONS.map((s) => ({ ...s })),
|
|
1072
1275
|
|
|
1073
1276
|
// ── Skill system ───────────────────────────────────────────────────
|
|
1074
|
-
//
|
|
1075
|
-
//
|
|
1076
|
-
//
|
|
1077
|
-
skillConfig: DefaultSkillConfig,
|
|
1078
|
-
|
|
1277
|
+
// No skillConfig: the skills an instance runs are derived from its own content, never
|
|
1278
|
+
// stored on the conf. See DefaultSkillConfig above for the definitions and
|
|
1279
|
+
// cyberia-instance-items.js for the membership rule.
|
|
1079
1280
|
skillRules: {
|
|
1080
|
-
projectileSpawnChance: 0.
|
|
1281
|
+
projectileSpawnChance: 0.75,
|
|
1081
1282
|
projectileLifetimeMs: 2000,
|
|
1082
1283
|
projectileWidth: 1,
|
|
1083
1284
|
projectileHeight: 1,
|
|
1084
1285
|
projectileSpeedMultiplier: 3,
|
|
1085
|
-
doppelgangerSpawnChance: 0.
|
|
1286
|
+
doppelgangerSpawnChance: 0.6,
|
|
1086
1287
|
doppelgangerLifetimeMs: 5000,
|
|
1087
1288
|
doppelgangerSpawnRadius: 3,
|
|
1088
1289
|
doppelgangerInitialLifeFraction: 1.0,
|
|
@@ -1104,7 +1305,7 @@ const _cloneDefault = (v) => JSON.parse(JSON.stringify(v));
|
|
|
1104
1305
|
* Recursively backfill one value against its canonical default:
|
|
1105
1306
|
* - null / undefined → deep clone of the default
|
|
1106
1307
|
* - empty array → deep clone of the default (config lists must never
|
|
1107
|
-
* export empty — e.g.
|
|
1308
|
+
* export empty — e.g. entityDefaults, statusIcons)
|
|
1108
1309
|
* - non-empty array → kept verbatim (author content)
|
|
1109
1310
|
* - plain object → keep author-set keys, recurse to fill missing default keys
|
|
1110
1311
|
* - scalar → kept verbatim when present (0, '', false count as present)
|
|
@@ -1124,26 +1325,12 @@ function _deepFillDefaults(value, defaultValue) {
|
|
|
1124
1325
|
return value;
|
|
1125
1326
|
}
|
|
1126
1327
|
|
|
1127
|
-
/**
|
|
1128
|
-
* Normalise a skillConfig array to the shape CyberiaInstanceConfSchema stores
|
|
1129
|
-
* (`SkillConfigEntrySchema` = { triggerItemId, logicEventIds }). The canonical
|
|
1130
|
-
* DefaultSkillConfig carries extra `skills` metadata the schema drops on write;
|
|
1131
|
-
* stripping it here keeps export ⇄ DB round-trips churn-free.
|
|
1132
|
-
*/
|
|
1133
|
-
function _normaliseSkillConfig(skillConfig) {
|
|
1134
|
-
if (!Array.isArray(skillConfig)) return [];
|
|
1135
|
-
return skillConfig.map((entry) => ({
|
|
1136
|
-
triggerItemId: entry.triggerItemId,
|
|
1137
|
-
logicEventIds: [...(entry.logicEventIds || [])],
|
|
1138
|
-
}));
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
1328
|
/**
|
|
1142
1329
|
* Return a copy of a CyberiaInstanceConf document with every field defined by
|
|
1143
1330
|
* CyberiaInstanceConfSchema present. Missing, null/undefined, or empty-array
|
|
1144
1331
|
* fields — common when a doc is read with `.lean()` (which skips Mongoose schema
|
|
1145
1332
|
* defaults), was created before a schema field existed, or was seeded with the
|
|
1146
|
-
* schema's empty-array default (e.g. `
|
|
1333
|
+
* schema's empty-array default (e.g. `entityDefaults`) — are filled from
|
|
1147
1334
|
* CYBERIA_INSTANCE_CONF_DEFAULTS, the same canonical values the fallback world
|
|
1148
1335
|
* uses. Author-set scalars (including 0, '', false), non-empty arrays, and DB
|
|
1149
1336
|
* metadata (_id, instanceCode, timestamps) are preserved untouched.
|
|
@@ -1157,6 +1344,8 @@ export function fillInstanceConfDefaults(conf = {}) {
|
|
|
1157
1344
|
for (const key of Object.keys(CYBERIA_INSTANCE_CONF_DEFAULTS)) {
|
|
1158
1345
|
out[key] = _deepFillDefaults(source[key], CYBERIA_INSTANCE_CONF_DEFAULTS[key]);
|
|
1159
1346
|
}
|
|
1160
|
-
|
|
1347
|
+
// A conf from before skills were derived still carries the field; it is not part of the
|
|
1348
|
+
// schema any more, and leaving it would put a stale second answer back on the wire.
|
|
1349
|
+
delete out.skillConfig;
|
|
1161
1350
|
return out;
|
|
1162
1351
|
}
|