@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
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback-world capture — materialise the in-memory procedural world into
|
|
3
|
+
* MongoDB so it can be exported, versioned, and re-imported like any authored
|
|
4
|
+
* instance.
|
|
5
|
+
*
|
|
6
|
+
* The fallback world (cyberia-fallback-world.js) is never persisted: every
|
|
7
|
+
* engine process rebuilds it from code defaults at boot and serves it whenever
|
|
8
|
+
* a requested instance is absent. Capturing it means writing everything that
|
|
9
|
+
* in-memory world serves under a real instance code:
|
|
10
|
+
*
|
|
11
|
+
* - CyberiaInstance — map graph, portal edges, player spawn, item ids
|
|
12
|
+
* - CyberiaMap — one document per generated map (entities included)
|
|
13
|
+
* - CyberiaInstanceConf — the world's simulation config
|
|
14
|
+
* - CyberiaSkill / CyberiaEntityTypeDefault / CyberiaDialogue /
|
|
15
|
+
* CyberiaAction / CyberiaQuest — the content collections the fallback path
|
|
16
|
+
* reads from code defaults INSTEAD of Mongo; a persisted instance reads
|
|
17
|
+
* them from Mongo, so they must exist there for the capture to serve the
|
|
18
|
+
* same world (see instance-data.js#fetchFullInstance).
|
|
19
|
+
* - CyberiaMapAudioConf — one per captured map. The client asks for audio by
|
|
20
|
+
* map code, so a namespaced capture would otherwise play nothing.
|
|
21
|
+
*
|
|
22
|
+
* CyberiaAudio assets are NOT captured: an asset is global, identified by its
|
|
23
|
+
* code, and imported once by `cyberia audio --import`. The capture reports the
|
|
24
|
+
* codes it bound that no asset carries yet.
|
|
25
|
+
*
|
|
26
|
+
* ObjectLayer/atlas assets are NOT generated here — they come from the asset
|
|
27
|
+
* pipeline (`bin/cyberia ol <ids> --import`). The capture reports the missing
|
|
28
|
+
* ids so the caller can stop before writing an incomplete backup.
|
|
29
|
+
*
|
|
30
|
+
* Map and content codes are namespaced under the instance code by default, so
|
|
31
|
+
* two captures never overwrite each other's documents (map/action/quest codes
|
|
32
|
+
* are globally unique). `keepFallbackCodes` preserves the raw
|
|
33
|
+
* `fallback-map-*` / canonical action-quest codes instead.
|
|
34
|
+
*
|
|
35
|
+
* @module src/api/cyberia-instance/cyberia-fallback-capture
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { loggerFactory } from '../../server/ops/logger.js';
|
|
39
|
+
import { collectReferencedItemIds } from './cyberia-fallback-world.js';
|
|
40
|
+
import { collectInstanceItemIds } from './cyberia-instance-items.js';
|
|
41
|
+
import { fallbackAudioConfig } from '../../projects/cyberia/seed-audio.js';
|
|
42
|
+
import {
|
|
43
|
+
DefaultCyberiaActions,
|
|
44
|
+
DefaultCyberiaQuests,
|
|
45
|
+
DefaultCyberiaDialogues,
|
|
46
|
+
DefaultSkillConfig,
|
|
47
|
+
ENTITY_TYPE_DEFAULTS,
|
|
48
|
+
fillInstanceConfDefaults,
|
|
49
|
+
} from '../cyberia-server-defaults/cyberia-server-defaults.js';
|
|
50
|
+
|
|
51
|
+
const logger = loggerFactory(import.meta);
|
|
52
|
+
|
|
53
|
+
const FALLBACK_MAP_CODE_PREFIX = 'fallback-map-';
|
|
54
|
+
|
|
55
|
+
/** Mongo document keys that must never travel inside a `$set` payload. */
|
|
56
|
+
const DOC_METADATA_KEYS = ['_id', '__v', 'createdAt', 'updatedAt'];
|
|
57
|
+
|
|
58
|
+
const stripDocMetadata = (doc, extraKeys = []) => {
|
|
59
|
+
const out = { ...doc };
|
|
60
|
+
for (const key of [...DOC_METADATA_KEYS, ...extraKeys]) delete out[key];
|
|
61
|
+
return out;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const escapeRegExp = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
65
|
+
|
|
66
|
+
/** Namespaced map code for a captured fallback map (`fallback-map-2` → `X-map-2`). */
|
|
67
|
+
function captureMapCode(mapCode, instanceCode) {
|
|
68
|
+
const suffix = mapCode.startsWith(FALLBACK_MAP_CODE_PREFIX)
|
|
69
|
+
? mapCode.slice(FALLBACK_MAP_CODE_PREFIX.length)
|
|
70
|
+
: mapCode;
|
|
71
|
+
return `${instanceCode}-map-${suffix}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Namespaced action/quest code for a captured world. */
|
|
75
|
+
const captureContentCode = (code, instanceCode) => `${instanceCode}-${code}`;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Build the code translation tables for one capture.
|
|
79
|
+
*
|
|
80
|
+
* @param {object} world Result of `generateFallbackWorld()`.
|
|
81
|
+
* @param {string} instanceCode
|
|
82
|
+
* @param {boolean} keepFallbackCodes
|
|
83
|
+
* @returns {{ mapCodes: Map<string,string>, questCodes: Map<string,string>, actionCodes: Map<string,string> }}
|
|
84
|
+
*/
|
|
85
|
+
function buildCaptureCodeMaps({ world, instanceCode, keepFallbackCodes, actions, quests }) {
|
|
86
|
+
const mapCodes = new Map();
|
|
87
|
+
const rememberMapCode = (code) => {
|
|
88
|
+
if (!code || mapCodes.has(code)) return;
|
|
89
|
+
mapCodes.set(code, keepFallbackCodes ? code : captureMapCode(code, instanceCode));
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
for (const code of world.instance?.cyberiaMapCodes || []) rememberMapCode(code);
|
|
93
|
+
for (const map of world.maps || []) rememberMapCode(map.code);
|
|
94
|
+
for (const portal of world.instance?.portals || []) {
|
|
95
|
+
rememberMapCode(portal.sourceMapCode);
|
|
96
|
+
rememberMapCode(portal.targetMapCode);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const contentCodes = (docs) =>
|
|
100
|
+
new Map(
|
|
101
|
+
(docs || [])
|
|
102
|
+
.filter((doc) => doc?.code)
|
|
103
|
+
.map((doc) => [doc.code, keepFallbackCodes ? doc.code : captureContentCode(doc.code, instanceCode)]),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return { mapCodes, actionCodes: contentCodes(actions), questCodes: contentCodes(quests) };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Translate one default action into its captured form. Returns `null` when the
|
|
111
|
+
* action lives on a map this world does not contain — a persisted instance
|
|
112
|
+
* only ever serves actions bound to its own maps.
|
|
113
|
+
*/
|
|
114
|
+
function captureAction(action, { mapCodes, actionCodes, questCodes }) {
|
|
115
|
+
const sourceMapCode = mapCodes.get(action.sourceMapCode);
|
|
116
|
+
if (!sourceMapCode) return null;
|
|
117
|
+
return {
|
|
118
|
+
...action,
|
|
119
|
+
code: actionCodes.get(action.code) || action.code,
|
|
120
|
+
sourceMapCode,
|
|
121
|
+
questDialogueCodes: (action.questDialogueCodes || []).map((entry) => ({
|
|
122
|
+
...entry,
|
|
123
|
+
questCode: questCodes.get(entry.questCode) || entry.questCode,
|
|
124
|
+
})),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Translate one default quest into its captured form (`null` = foreign map). */
|
|
129
|
+
function captureQuest(quest, { mapCodes, questCodes }) {
|
|
130
|
+
const sourceMapCode = mapCodes.get(quest.sourceMapCode);
|
|
131
|
+
if (!sourceMapCode) return null;
|
|
132
|
+
const translate = (codes) => (codes || []).map((code) => questCodes.get(code) || code);
|
|
133
|
+
return {
|
|
134
|
+
...quest,
|
|
135
|
+
code: questCodes.get(quest.code) || quest.code,
|
|
136
|
+
sourceMapCode,
|
|
137
|
+
prerequisiteCodes: translate(quest.prerequisiteCodes),
|
|
138
|
+
unlocksQuestCodes: translate(quest.unlocksQuestCodes),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Pure planner: turn an in-memory fallback world into the exact set of
|
|
144
|
+
* documents a capture writes. No I/O — the whole translation is testable
|
|
145
|
+
* without a database.
|
|
146
|
+
*
|
|
147
|
+
* @param {object} params
|
|
148
|
+
* @param {object} params.world Result of `generateFallbackWorld()`.
|
|
149
|
+
* @param {string} params.instanceCode Code the capture is stored under.
|
|
150
|
+
* @param {boolean} [params.keepFallbackCodes=false]
|
|
151
|
+
* @param {Array} [params.actions=DefaultCyberiaActions]
|
|
152
|
+
* @param {Array} [params.quests=DefaultCyberiaQuests]
|
|
153
|
+
* @returns {{
|
|
154
|
+
* instance: object, conf: object, maps: object[], actions: object[], quests: object[],
|
|
155
|
+
* codeMaps: object, skippedActionCodes: string[], skippedQuestCodes: string[], itemIds: string[]
|
|
156
|
+
* }}
|
|
157
|
+
*/
|
|
158
|
+
function planFallbackCapture({
|
|
159
|
+
world,
|
|
160
|
+
instanceCode,
|
|
161
|
+
keepFallbackCodes = false,
|
|
162
|
+
actions = DefaultCyberiaActions,
|
|
163
|
+
quests = DefaultCyberiaQuests,
|
|
164
|
+
}) {
|
|
165
|
+
if (!world?.instance || !Array.isArray(world.maps)) throw new Error('planFallbackCapture: invalid world');
|
|
166
|
+
if (!instanceCode) throw new Error('planFallbackCapture: instanceCode is required');
|
|
167
|
+
|
|
168
|
+
const codeMaps = buildCaptureCodeMaps({ world, instanceCode, keepFallbackCodes, actions, quests });
|
|
169
|
+
const { mapCodes } = codeMaps;
|
|
170
|
+
|
|
171
|
+
const maps = world.maps.map((map) => ({
|
|
172
|
+
code: mapCodes.get(map.code) || map.code,
|
|
173
|
+
name: map.name || mapCodes.get(map.code) || map.code,
|
|
174
|
+
description: map.description || '',
|
|
175
|
+
gridX: map.gridX,
|
|
176
|
+
gridY: map.gridY,
|
|
177
|
+
cellWidth: map.cellWidth,
|
|
178
|
+
cellHeight: map.cellHeight,
|
|
179
|
+
entities: (map.entities || []).map((entity) => ({ ...entity })),
|
|
180
|
+
tags: ['fallback', 'procedural', 'captured'],
|
|
181
|
+
}));
|
|
182
|
+
|
|
183
|
+
const spawn = world.instance.playerSpawn || {};
|
|
184
|
+
const instance = {
|
|
185
|
+
code: instanceCode,
|
|
186
|
+
name: instanceCode,
|
|
187
|
+
description: 'Captured procedural fallback world',
|
|
188
|
+
tags: ['fallback', 'procedural', 'captured'],
|
|
189
|
+
cyberiaMapCodes: (world.instance.cyberiaMapCodes || []).map((code) => mapCodes.get(code) || code),
|
|
190
|
+
portals: (world.instance.portals || []).map((portal) => ({
|
|
191
|
+
...portal,
|
|
192
|
+
sourceMapCode: mapCodes.get(portal.sourceMapCode) || portal.sourceMapCode,
|
|
193
|
+
targetMapCode: mapCodes.get(portal.targetMapCode) || portal.targetMapCode,
|
|
194
|
+
})),
|
|
195
|
+
playerSpawn: {
|
|
196
|
+
...spawn,
|
|
197
|
+
...(spawn.sourceMapCode ? { sourceMapCode: mapCodes.get(spawn.sourceMapCode) || spawn.sourceMapCode } : {}),
|
|
198
|
+
},
|
|
199
|
+
topologyMode: 'procedural',
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const conf = { ...fillInstanceConfDefaults(world.config || {}), instanceCode };
|
|
203
|
+
|
|
204
|
+
const capturedActions = [];
|
|
205
|
+
const skippedActionCodes = [];
|
|
206
|
+
for (const action of actions) {
|
|
207
|
+
const captured = captureAction(action, codeMaps);
|
|
208
|
+
if (captured) capturedActions.push(captured);
|
|
209
|
+
else skippedActionCodes.push(action.code);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const capturedQuests = [];
|
|
213
|
+
const skippedQuestCodes = [];
|
|
214
|
+
for (const quest of quests) {
|
|
215
|
+
const captured = captureQuest(quest, codeMaps);
|
|
216
|
+
if (captured) capturedQuests.push(captured);
|
|
217
|
+
else skippedQuestCodes.push(quest.code);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
instance,
|
|
222
|
+
conf,
|
|
223
|
+
maps,
|
|
224
|
+
actions: capturedActions,
|
|
225
|
+
quests: capturedQuests,
|
|
226
|
+
codeMaps,
|
|
227
|
+
skippedActionCodes,
|
|
228
|
+
skippedQuestCodes,
|
|
229
|
+
itemIds: collectCaptureItemIds({ maps, actions: capturedActions, quests: capturedQuests }),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Every ObjectLayer item id the captured instance needs an atlas for: the canonical world's
|
|
235
|
+
* own ids, plus what this instance names — its maps, its entity-type defaults, and the
|
|
236
|
+
* vendor/assembler/quest catalogs the interact modal draws icons for.
|
|
237
|
+
*
|
|
238
|
+
* @returns {string[]} Sorted, de-duplicated item ids.
|
|
239
|
+
*/
|
|
240
|
+
function collectCaptureItemIds({ maps, actions, quests, entityDefaults = [] }) {
|
|
241
|
+
// The canonical world's own ids — every fallback default, including the skill triggers and
|
|
242
|
+
// summoned entities DefaultSkillConfig names. What the captured instance adds on top follows
|
|
243
|
+
// the same rule the export and the boot payload use.
|
|
244
|
+
const ids = collectReferencedItemIds();
|
|
245
|
+
// The conf references its entity-type defaults by _id, so the documents arrive resolved.
|
|
246
|
+
for (const itemId of collectInstanceItemIds({ maps, entityDefaults, actions, quests })) ids.add(itemId);
|
|
247
|
+
return [...ids].sort();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Insert the content collections the fallback path serves from code defaults.
|
|
252
|
+
*
|
|
253
|
+
* Insert-only: an existing document is left exactly as the operator (or an
|
|
254
|
+
* earlier import) left it, so a capture never silently rewrites content shared
|
|
255
|
+
* with other instances. Returns per-collection insert counts.
|
|
256
|
+
*/
|
|
257
|
+
async function seedMissingContentDefaults({ CyberiaSkill, CyberiaEntityTypeDefault, CyberiaDialogue }) {
|
|
258
|
+
const inserted = { skills: 0, entityTypeDefaults: 0, dialogues: 0 };
|
|
259
|
+
|
|
260
|
+
const insertIfMissing = async (Model, filter, doc, counterKey) => {
|
|
261
|
+
if (!Model) return;
|
|
262
|
+
const existing = await Model.findOne(filter).lean();
|
|
263
|
+
if (existing) return;
|
|
264
|
+
await Model.create(doc);
|
|
265
|
+
inserted[counterKey]++;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
for (const skill of DefaultSkillConfig) {
|
|
269
|
+
await insertIfMissing(
|
|
270
|
+
CyberiaSkill,
|
|
271
|
+
{ triggerItemId: skill.triggerItemId },
|
|
272
|
+
{ triggerItemId: skill.triggerItemId, logicEventIds: skill.logicEventIds || [], skills: skill.skills || [] },
|
|
273
|
+
'skills',
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
for (const entityDefault of ENTITY_TYPE_DEFAULTS) {
|
|
278
|
+
await insertIfMissing(
|
|
279
|
+
CyberiaEntityTypeDefault,
|
|
280
|
+
{ entityType: entityDefault.entityType, liveItemIds: entityDefault.liveItemIds || [] },
|
|
281
|
+
{
|
|
282
|
+
entityType: entityDefault.entityType,
|
|
283
|
+
liveItemIds: entityDefault.liveItemIds || [],
|
|
284
|
+
deadItemIds: entityDefault.deadItemIds || [],
|
|
285
|
+
dropItemIds: entityDefault.dropItemIds || [],
|
|
286
|
+
inventoryItemsIds: entityDefault.inventoryItemsIds || [],
|
|
287
|
+
overrideItemsIdsState: entityDefault.overrideItemsIdsState || [],
|
|
288
|
+
behavior: entityDefault.behavior || '',
|
|
289
|
+
},
|
|
290
|
+
'entityTypeDefaults',
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
for (const dialogue of DefaultCyberiaDialogues) {
|
|
295
|
+
await insertIfMissing(
|
|
296
|
+
CyberiaDialogue,
|
|
297
|
+
{ code: dialogue.code, order: dialogue.order },
|
|
298
|
+
{ ...dialogue },
|
|
299
|
+
'dialogues',
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return inserted;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Write the audio configuration of the captured maps.
|
|
308
|
+
*
|
|
309
|
+
* Audio reaches the client per map code, so a world captured under namespaced codes needs its
|
|
310
|
+
* bindings rewritten under those codes — the same reason the actions and quests are re-coded.
|
|
311
|
+
* Only codes an imported asset actually carries are bound: a binding to an absent asset would be
|
|
312
|
+
* a dangling name, and the caller is told which ones are missing instead.
|
|
313
|
+
*
|
|
314
|
+
* @param {object} params
|
|
315
|
+
* @param {object} params.models - `{ CyberiaMapAudioConf, CyberiaAudio }`.
|
|
316
|
+
* @param {object} params.plan - Result of `planFallbackCapture()`.
|
|
317
|
+
* @returns {Promise<{audioConfs: number, missingAudioCodes: string[]}>}
|
|
318
|
+
*/
|
|
319
|
+
async function captureAudioConfig({ models, plan }) {
|
|
320
|
+
const { CyberiaMapAudioConf, CyberiaAudio } = models;
|
|
321
|
+
if (!CyberiaMapAudioConf) return { audioConfs: 0, missingAudioCodes: [] };
|
|
322
|
+
|
|
323
|
+
const config = fallbackAudioConfig();
|
|
324
|
+
const bound = new Set(
|
|
325
|
+
[...config.events.map(({ audioCode }) => audioCode), ...config.maps.map(({ defaultMusic }) => defaultMusic)].filter(
|
|
326
|
+
Boolean,
|
|
327
|
+
),
|
|
328
|
+
);
|
|
329
|
+
const present = new Set(
|
|
330
|
+
CyberiaAudio
|
|
331
|
+
? (await CyberiaAudio.find({ code: { $in: [...bound] } }, { code: 1 }).lean()).map((doc) => doc.code)
|
|
332
|
+
: [],
|
|
333
|
+
);
|
|
334
|
+
const events = config.events.filter(({ audioCode }) => present.has(audioCode));
|
|
335
|
+
|
|
336
|
+
let audioConfs = 0;
|
|
337
|
+
for (const map of config.maps) {
|
|
338
|
+
const mapCode = plan.codeMaps.mapCodes.get(map.mapCode);
|
|
339
|
+
if (!mapCode) continue;
|
|
340
|
+
await CyberiaMapAudioConf.findOneAndUpdate(
|
|
341
|
+
{ mapCode },
|
|
342
|
+
{
|
|
343
|
+
$set: {
|
|
344
|
+
defaultMusic: present.has(map.defaultMusic) ? map.defaultMusic : '',
|
|
345
|
+
settings: config.settings,
|
|
346
|
+
events,
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
{ upsert: true },
|
|
350
|
+
);
|
|
351
|
+
audioConfs++;
|
|
352
|
+
}
|
|
353
|
+
return { audioConfs, missingAudioCodes: [...bound].filter((code) => !present.has(code)).sort() };
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Remove documents that a larger previous capture left in this capture's own
|
|
358
|
+
* namespace. Touches only codes prefixed with the instance code, and never runs
|
|
359
|
+
* in `keepFallbackCodes` mode, where the codes are the shared canonical ones.
|
|
360
|
+
*/
|
|
361
|
+
async function pruneStaleCaptureDocs({ models, instanceCode, plan }) {
|
|
362
|
+
const namespace = new RegExp(`^${escapeRegExp(instanceCode)}-`);
|
|
363
|
+
const pruned = { maps: 0, actions: 0, quests: 0 };
|
|
364
|
+
|
|
365
|
+
const prune = async (Model, keepCodes, counterKey) => {
|
|
366
|
+
if (!Model) return;
|
|
367
|
+
const result = await Model.deleteMany({ code: { $regex: namespace, $nin: keepCodes } });
|
|
368
|
+
pruned[counterKey] = result?.deletedCount || 0;
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
await prune(
|
|
372
|
+
models.CyberiaMap,
|
|
373
|
+
plan.maps.map((map) => map.code),
|
|
374
|
+
'maps',
|
|
375
|
+
);
|
|
376
|
+
await prune(
|
|
377
|
+
models.CyberiaAction,
|
|
378
|
+
plan.actions.map((action) => action.code),
|
|
379
|
+
'actions',
|
|
380
|
+
);
|
|
381
|
+
await prune(
|
|
382
|
+
models.CyberiaQuest,
|
|
383
|
+
plan.quests.map((quest) => quest.code),
|
|
384
|
+
'quests',
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
return pruned;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Materialise an in-memory fallback world into MongoDB under `instanceCode`.
|
|
392
|
+
*
|
|
393
|
+
* Idempotent: every write is an upsert keyed by the document's natural code,
|
|
394
|
+
* so re-running a capture converges on the same state. Nothing is deleted
|
|
395
|
+
* except stale documents inside this capture's own code namespace.
|
|
396
|
+
*
|
|
397
|
+
* @param {object} params
|
|
398
|
+
* @param {object} params.models `{ CyberiaInstance, CyberiaInstanceConf, CyberiaMap, CyberiaAction,
|
|
399
|
+
* CyberiaQuest, CyberiaSkill, CyberiaEntityTypeDefault,
|
|
400
|
+
* CyberiaDialogue, CyberiaMapAudioConf, CyberiaAudio,
|
|
401
|
+
* ObjectLayer }`
|
|
402
|
+
* @param {object} params.world Result of `generateFallbackWorld()`.
|
|
403
|
+
* @param {string} params.instanceCode
|
|
404
|
+
* @param {boolean} [params.keepFallbackCodes=false]
|
|
405
|
+
* @returns {Promise<{plan: object, inserted: object, pruned: object, missingObjectLayerItemIds: string[]}>}
|
|
406
|
+
*/
|
|
407
|
+
async function captureFallbackWorld({ models, world, instanceCode, keepFallbackCodes = false }) {
|
|
408
|
+
const plan = planFallbackCapture({ world, instanceCode, keepFallbackCodes });
|
|
409
|
+
|
|
410
|
+
// Conf first: the instance document carries the ObjectId ref to it.
|
|
411
|
+
const confDoc = await models.CyberiaInstanceConf.findOneAndUpdate(
|
|
412
|
+
{ instanceCode },
|
|
413
|
+
{ $set: stripDocMetadata(plan.conf, ['instanceCode']) },
|
|
414
|
+
{ upsert: true, returnDocument: 'after' },
|
|
415
|
+
);
|
|
416
|
+
logger.info('Captured CyberiaInstanceConf', { instanceCode });
|
|
417
|
+
|
|
418
|
+
for (const map of plan.maps) {
|
|
419
|
+
await models.CyberiaMap.findOneAndUpdate(
|
|
420
|
+
{ code: map.code },
|
|
421
|
+
{ $set: stripDocMetadata(map, ['code']) },
|
|
422
|
+
{ upsert: true },
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
logger.info(`Captured ${plan.maps.length} CyberiaMap document(s)`, { codes: plan.maps.map((m) => m.code) });
|
|
426
|
+
|
|
427
|
+
await models.CyberiaInstance.findOneAndUpdate(
|
|
428
|
+
{ code: instanceCode },
|
|
429
|
+
{
|
|
430
|
+
$set: {
|
|
431
|
+
...stripDocMetadata(plan.instance, ['code']),
|
|
432
|
+
...(confDoc?._id ? { conf: confDoc._id } : {}),
|
|
433
|
+
},
|
|
434
|
+
$setOnInsert: { status: 'unlisted' },
|
|
435
|
+
},
|
|
436
|
+
{ upsert: true },
|
|
437
|
+
);
|
|
438
|
+
logger.info('Captured CyberiaInstance', { code: instanceCode, maps: plan.instance.cyberiaMapCodes.length });
|
|
439
|
+
|
|
440
|
+
for (const action of plan.actions) {
|
|
441
|
+
await models.CyberiaAction.findOneAndUpdate(
|
|
442
|
+
{ code: action.code },
|
|
443
|
+
{ $set: stripDocMetadata(action, ['code']) },
|
|
444
|
+
{ upsert: true },
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
for (const quest of plan.quests) {
|
|
448
|
+
await models.CyberiaQuest.findOneAndUpdate(
|
|
449
|
+
{ code: quest.code },
|
|
450
|
+
{ $set: stripDocMetadata(quest, ['code']) },
|
|
451
|
+
{ upsert: true },
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
logger.info(`Captured ${plan.actions.length} CyberiaAction and ${plan.quests.length} CyberiaQuest document(s)`);
|
|
455
|
+
if (plan.skippedActionCodes.length > 0 || plan.skippedQuestCodes.length > 0) {
|
|
456
|
+
logger.warn('Skipped mission content bound to maps outside the captured world', {
|
|
457
|
+
actions: plan.skippedActionCodes,
|
|
458
|
+
quests: plan.skippedQuestCodes,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const inserted = await seedMissingContentDefaults(models);
|
|
463
|
+
logger.info('Seeded missing content defaults', inserted);
|
|
464
|
+
|
|
465
|
+
const audio = await captureAudioConfig({ models, plan });
|
|
466
|
+
logger.info(`Captured ${audio.audioConfs} CyberiaMapAudioConf document(s)`);
|
|
467
|
+
if (audio.missingAudioCodes.length > 0) {
|
|
468
|
+
logger.warn(
|
|
469
|
+
'Audio codes with no imported CyberiaAudio document were left unbound — ' +
|
|
470
|
+
'run `node bin/cyberia run-workflow seed-audio` to record and import them',
|
|
471
|
+
{ codes: audio.missingAudioCodes },
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// `keepFallbackCodes` reuses the globally shared canonical codes, so nothing
|
|
476
|
+
// in that namespace belongs exclusively to this capture.
|
|
477
|
+
const pruned = keepFallbackCodes
|
|
478
|
+
? { maps: 0, actions: 0, quests: 0 }
|
|
479
|
+
: await pruneStaleCaptureDocs({ models, instanceCode, plan });
|
|
480
|
+
if (pruned.maps || pruned.actions || pruned.quests)
|
|
481
|
+
logger.info('Pruned stale documents from a previous capture', pruned);
|
|
482
|
+
|
|
483
|
+
const presentItemIds = new Set(
|
|
484
|
+
(await models.ObjectLayer.find({ 'data.item.id': { $in: plan.itemIds } }, { 'data.item.id': 1 }).lean()).map(
|
|
485
|
+
(doc) => doc.data?.item?.id,
|
|
486
|
+
),
|
|
487
|
+
);
|
|
488
|
+
const missingObjectLayerItemIds = plan.itemIds.filter((id) => !presentItemIds.has(id));
|
|
489
|
+
|
|
490
|
+
return { plan, inserted, pruned, audio, missingObjectLayerItemIds };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export {
|
|
494
|
+
planFallbackCapture,
|
|
495
|
+
captureAudioConfig,
|
|
496
|
+
captureFallbackWorld,
|
|
497
|
+
collectCaptureItemIds,
|
|
498
|
+
captureMapCode,
|
|
499
|
+
captureContentCode,
|
|
500
|
+
seedMissingContentDefaults,
|
|
501
|
+
FALLBACK_MAP_CODE_PREFIX,
|
|
502
|
+
};
|
|
@@ -53,19 +53,26 @@ import {
|
|
|
53
53
|
const DEFAULT_MAP_COUNT = 4;
|
|
54
54
|
const DEFAULT_GRID_SIZE = 64;
|
|
55
55
|
|
|
56
|
+
const getFallbackMapCodes = (mapCount = DEFAULT_MAP_COUNT) =>
|
|
57
|
+
Array.from({ length: mapCount }, (_, index) => `fallback-map-${index}`);
|
|
58
|
+
|
|
56
59
|
// ── Asset-id integrity ──────────────────────────────────────────────────────
|
|
57
60
|
//
|
|
58
|
-
// Every item id
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
// back to a solid-colour rectangle instead of the intended sprite.
|
|
61
|
+
// Every item id the fallback world can place must also be in
|
|
62
|
+
// DefaultCyberiaItems. Otherwise the `import-default-items` seed creates no
|
|
63
|
+
// ObjectLayer for it and the client draws a solid-colour rectangle.
|
|
62
64
|
//
|
|
63
|
-
// auditFallbackItemIds() returns the
|
|
64
|
-
// canonical defaults so callers (CLI, test harness, gRPC fallback path)
|
|
65
|
-
// can surface drift immediately. Returns an empty array when in sync.
|
|
65
|
+
// auditFallbackItemIds() returns the unknown ids, empty when in sync.
|
|
66
66
|
|
|
67
67
|
const KNOWN_DEFAULT_ITEM_IDS = new Set(DefaultCyberiaItems.map((e) => e.item.id));
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Every item id the canonical defaults can place, equip, summon, sell, or
|
|
71
|
+
* craft. Shared with the fallback-world capture, which must resolve an atlas
|
|
72
|
+
* for each of them before writing a backup.
|
|
73
|
+
*
|
|
74
|
+
* @returns {Set<string>}
|
|
75
|
+
*/
|
|
69
76
|
function collectReferencedItemIds() {
|
|
70
77
|
const ids = new Set();
|
|
71
78
|
const push = (id) => {
|
|
@@ -76,7 +83,7 @@ function collectReferencedItemIds() {
|
|
|
76
83
|
(e.liveItemIds || []).forEach(push);
|
|
77
84
|
(e.deadItemIds || []).forEach(push);
|
|
78
85
|
(e.dropItemIds || []).forEach(push);
|
|
79
|
-
(e.
|
|
86
|
+
(e.inventoryItemsIds || []).forEach(push);
|
|
80
87
|
}
|
|
81
88
|
for (const r of RESOURCE_ENTITY_TYPE_DEFAULTS) {
|
|
82
89
|
(r.liveItemIds || []).forEach(push);
|
|
@@ -232,11 +239,6 @@ function generateFallbackMap(mapCode, colors, opts = {}) {
|
|
|
232
239
|
* @param {number} [opts.resourceCount] Resources per map (random if omitted).
|
|
233
240
|
* @param {number} [opts.staticCount] Static decorators per map (random if omitted).
|
|
234
241
|
* @param {Array} [opts.colors] Override palette.
|
|
235
|
-
* @param {Array<{id: string, defaultPlayerInventory: boolean}>} [opts.itemIds=[]]
|
|
236
|
-
* Instance-level default items, mirroring `CyberiaInstance.itemIds`. Entries
|
|
237
|
-
* flagged `defaultPlayerInventory` are merged into the player entity default
|
|
238
|
-
* by `applyInstanceDefaultPlayerInventory`; every id is also resolved to an
|
|
239
|
-
* atlas at boot. Layout is unaffected, so this stays outside the world seed.
|
|
240
242
|
* @returns {{
|
|
241
243
|
* instance: object,
|
|
242
244
|
* maps: object[],
|
|
@@ -255,18 +257,13 @@ function generateFallbackWorld(opts = {}) {
|
|
|
255
257
|
botCount,
|
|
256
258
|
resourceCount,
|
|
257
259
|
staticCount,
|
|
258
|
-
// Palette
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
// fallback before atlases load. The C client resolves real colours
|
|
262
|
-
// through domain/presentation_runtime — it does not read this value.
|
|
260
|
+
// Palette from SharedDefaultsCyberia. The generator only stamps a cosmetic
|
|
261
|
+
// rgba(...) string on entities, for previews drawn before atlases load. The
|
|
262
|
+
// game client resolves its own colours and ignores this value.
|
|
263
263
|
colors = PALETTE,
|
|
264
|
-
itemIds = [],
|
|
265
264
|
} = opts;
|
|
266
265
|
|
|
267
|
-
//
|
|
268
|
-
// `bin/cyberia run-workflow import-default-items` run shows up at startup
|
|
269
|
-
// instead of as silent grey rectangles later.
|
|
266
|
+
// Report item-id drift at the first build, not as grey rectangles later.
|
|
270
267
|
const missing = auditFallbackItemIds();
|
|
271
268
|
if (missing.length > 0) {
|
|
272
269
|
// eslint-disable-next-line no-console
|
|
@@ -277,18 +274,12 @@ function generateFallbackWorld(opts = {}) {
|
|
|
277
274
|
);
|
|
278
275
|
}
|
|
279
276
|
|
|
280
|
-
|
|
281
|
-
const mapCodes = [];
|
|
282
|
-
for (let i = 0; i < mapCount; i++) {
|
|
283
|
-
mapCodes.push(`fallback-map-${i}`);
|
|
284
|
-
}
|
|
277
|
+
const mapCodes = getFallbackMapCodes(mapCount);
|
|
285
278
|
|
|
286
|
-
// Deterministic layout:
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
// lands exactly where the preview draws that resource. The seed folds in the
|
|
291
|
-
// layout-affecting options so a custom count set stays internally consistent.
|
|
279
|
+
// Deterministic layout: the seeded random source makes every call reproduce
|
|
280
|
+
// the same world. The `/static` POIs and the `/preview` image come from
|
|
281
|
+
// independent requests and must agree on where each entity sits. The seed
|
|
282
|
+
// folds in the layout options, so a custom count set stays consistent.
|
|
292
283
|
const seed = `cyberia-fallback-world-v1:${mapCount}:${gridSize ?? ''}:${obstacleCount ?? ''}:${
|
|
293
284
|
foregroundCount ?? ''
|
|
294
285
|
}:${botCount ?? ''}:${resourceCount ?? ''}:${staticCount ?? ''}`;
|
|
@@ -320,7 +311,6 @@ function generateFallbackWorld(opts = {}) {
|
|
|
320
311
|
portals,
|
|
321
312
|
topologyMode: 'procedural',
|
|
322
313
|
playerSpawn: { ...DEFAULT_PLAYER_SPAWN },
|
|
323
|
-
itemIds: itemIds.map((entry) => ({ ...entry })),
|
|
324
314
|
};
|
|
325
315
|
|
|
326
316
|
return {
|
|
@@ -336,12 +326,9 @@ function generateFallbackWorld(opts = {}) {
|
|
|
336
326
|
|
|
337
327
|
// ── Selection-view fallback instance ─────────────────────────────────────────
|
|
338
328
|
//
|
|
339
|
-
// A
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
// CyberiaInstance list row — only the fields InstanceSelectionView reads
|
|
343
|
-
// (code/name/description/tags/status/thumbnail). Injected into the instance list
|
|
344
|
-
// return by CyberiaInstanceService.get when the caller opts in (?fallback=true).
|
|
329
|
+
// A never-persisted instance row that keeps the selection list non-empty. It
|
|
330
|
+
// points at the always-on TEST variant and carries only the fields the
|
|
331
|
+
// selection view reads. CyberiaInstanceService.get injects it on ?fallback=true.
|
|
345
332
|
|
|
346
333
|
const DEFAULT_FALLBACK_INSTANCE_CODE = 'TEST';
|
|
347
334
|
|
|
@@ -363,9 +350,11 @@ function fallbackListInstance() {
|
|
|
363
350
|
// ── Public API ───────────────────────────────────────────────────────────────
|
|
364
351
|
|
|
365
352
|
export {
|
|
353
|
+
getFallbackMapCodes,
|
|
366
354
|
generateFallbackWorld,
|
|
367
355
|
generateFallbackMap,
|
|
368
356
|
auditFallbackItemIds,
|
|
357
|
+
collectReferencedItemIds,
|
|
369
358
|
fallbackListInstance,
|
|
370
359
|
DEFAULT_FALLBACK_INSTANCE_CODE,
|
|
371
360
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* REST boot service — the /api/cyberia-instance/boot/* fallback transport.
|
|
3
3
|
*
|
|
4
|
-
* Serves the
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* src/grpc/cyberia/grpc-server.js so both transports stay equivalent.
|
|
4
|
+
* Serves the CyberiaDataService payloads (world load, hot reload) over REST, so
|
|
5
|
+
* the game server can boot from its --data-server-url when the engine gRPC
|
|
6
|
+
* server is off for the deploy. The data assembly lives in
|
|
7
|
+
* src/projects/cyberia/instance-data.js, shared with
|
|
8
|
+
* src/grpc/cyberia/grpc-server.js, so both transports stay equivalent.
|
|
9
9
|
*
|
|
10
10
|
* Endpoints (all GET, internal server-to-server, mirroring the RPCs):
|
|
11
11
|
* /boot/ping → { serverTimeMs }
|