cyberia 3.1.3 → 3.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -2
- package/.github/workflows/engine-cyberia.cd.yml +10 -8
- package/.github/workflows/engine-cyberia.ci.yml +12 -29
- package/.github/workflows/ghpkg.ci.yml +4 -4
- package/.github/workflows/npmpkg.ci.yml +28 -11
- package/.github/workflows/publish.ci.yml +21 -2
- package/.github/workflows/pwa-microservices-template-page.cd.yml +4 -5
- package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
- package/.github/workflows/release.cd.yml +14 -10
- package/CHANGELOG.md +783 -1
- package/CLI-HELP.md +95 -18
- package/Dockerfile +0 -2
- package/README.md +290 -220
- package/bin/build.js +24 -7
- package/bin/cyberia.js +2838 -252
- package/bin/deploy.js +747 -125
- package/bin/file.js +9 -0
- package/bin/index.js +2838 -252
- package/bin/vs.js +1 -1
- package/conf.js +99 -65
- package/deployment.yaml +18 -164
- package/hardhat/hardhat.config.js +13 -13
- package/hardhat/ignition/modules/ObjectLayerToken.js +1 -1
- package/hardhat/package-lock.json +2559 -5864
- package/hardhat/package.json +14 -23
- package/hardhat/scripts/deployObjectLayerToken.js +1 -1
- package/hardhat/test/ObjectLayerToken.js +4 -2
- package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
- package/hardhat/types/ethers-contracts/common.ts +92 -0
- package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
- package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
- package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
- package/hardhat/types/ethers-contracts/index.ts +6 -0
- package/jsconfig.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +6 -5
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +6 -5
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +18 -164
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +7 -79
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
- package/manifests/deployment/dd-test-development/deployment.yaml +112 -28
- package/manifests/deployment/dd-test-development/proxy.yaml +46 -1
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/nodemon.json +1 -1
- package/package.json +39 -24
- package/proxy.yaml +7 -79
- package/scripts/k3s-node-setup.sh +2 -2
- package/scripts/nat-iptables.sh +103 -18
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +58 -14
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +23 -14
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +148 -20
- package/src/api/core/core.controller.js +10 -10
- package/src/api/core/core.service.js +10 -10
- package/src/api/crypto/crypto.controller.js +8 -8
- package/src/api/crypto/crypto.service.js +8 -8
- package/src/api/cyberia-action/cyberia-action.controller.js +74 -0
- package/src/api/cyberia-action/cyberia-action.model.js +87 -0
- package/src/api/cyberia-action/cyberia-action.router.js +27 -0
- package/src/api/cyberia-action/cyberia-action.service.js +42 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
- package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
- package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +178 -0
- package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
- package/src/api/cyberia-instance/cyberia-instance.model.js +87 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +156 -0
- package/src/api/cyberia-instance/cyberia-portal-connector.js +260 -0
- package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +574 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +231 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +46 -0
- package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
- package/src/api/cyberia-map/cyberia-map.model.js +30 -0
- package/src/api/cyberia-map/cyberia-map.router.js +40 -0
- package/src/api/cyberia-map/cyberia-map.service.js +74 -0
- package/src/api/cyberia-quest/cyberia-quest.controller.js +74 -0
- package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +27 -0
- package/src/api/cyberia-quest/cyberia-quest.service.js +42 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +74 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +27 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
- package/src/api/default/default.controller.js +10 -10
- package/src/api/default/default.service.js +10 -10
- package/src/api/document/document.controller.js +12 -12
- package/src/api/document/document.model.js +10 -16
- package/src/api/file/file.controller.js +8 -8
- package/src/api/file/file.model.js +10 -10
- package/src/api/file/file.ref.json +18 -0
- package/src/api/file/file.service.js +36 -36
- package/src/api/instance/instance.controller.js +10 -10
- package/src/api/instance/instance.model.js +4 -10
- package/src/api/instance/instance.service.js +10 -10
- package/src/api/ipfs/ipfs.controller.js +15 -36
- package/src/api/ipfs/ipfs.model.js +47 -47
- package/src/api/ipfs/ipfs.router.js +8 -13
- package/src/api/ipfs/ipfs.service.js +67 -129
- package/src/api/object-layer/object-layer.controller.js +12 -12
- package/src/api/object-layer/object-layer.model.js +4 -17
- package/src/api/object-layer/object-layer.router.js +30 -0
- package/src/api/object-layer/object-layer.service.js +126 -43
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +10 -10
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +6 -16
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +18 -14
- package/src/api/test/test.controller.js +8 -8
- package/src/api/test/test.service.js +8 -8
- package/src/api/user/guest.service.js +99 -0
- package/src/api/user/user.controller.js +6 -6
- package/src/api/user/user.model.js +8 -13
- package/src/api/user/user.service.js +11 -27
- package/src/cli/cluster.js +68 -21
- package/src/cli/db.js +753 -825
- package/src/cli/deploy.js +215 -125
- package/src/cli/env.js +29 -0
- package/src/cli/fs.js +82 -8
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +74 -3
- package/src/cli/kubectl.js +211 -0
- package/src/cli/release.js +340 -0
- package/src/cli/repository.js +475 -74
- package/src/cli/run.js +582 -43
- package/src/cli/secrets.js +73 -0
- package/src/cli/ssh.js +1 -1
- package/src/cli/static.js +43 -115
- package/src/cli/test.js +3 -3
- package/src/client/Cryptokoyn.index.js +18 -22
- package/src/client/CyberiaPortal.index.js +19 -24
- package/src/client/Default.index.js +21 -34
- package/src/client/Itemledger.index.js +20 -27
- package/src/client/Underpost.index.js +19 -24
- package/src/client/components/core/404.js +4 -4
- package/src/client/components/core/500.js +4 -4
- package/src/client/components/core/Account.js +73 -60
- package/src/client/components/core/AgGrid.js +23 -33
- package/src/client/components/core/Alert.js +12 -13
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/Auth.js +35 -37
- package/src/client/components/core/Badge.js +7 -13
- package/src/client/components/core/BtnIcon.js +15 -17
- package/src/client/components/core/CalendarCore.js +43 -64
- package/src/client/components/core/Chat.js +13 -15
- package/src/client/components/core/ClientEvents.js +87 -0
- package/src/client/components/core/ColorPaletteElement.js +309 -0
- package/src/client/components/core/Content.js +17 -14
- package/src/client/components/core/Css.js +15 -71
- package/src/client/components/core/CssCore.js +12 -16
- package/src/client/components/core/D3Chart.js +4 -4
- package/src/client/components/core/Docs.js +64 -91
- package/src/client/components/core/DropDown.js +194 -96
- package/src/client/components/core/EventBus.js +92 -0
- package/src/client/components/core/EventsUI.js +14 -17
- package/src/client/components/core/FileExplorer.js +96 -228
- package/src/client/components/core/FullScreen.js +47 -75
- package/src/client/components/core/Input.js +24 -69
- package/src/client/components/core/Keyboard.js +26 -19
- package/src/client/components/core/KeyboardAvoidance.js +145 -0
- package/src/client/components/core/LoadingAnimation.js +25 -31
- package/src/client/components/core/LogIn.js +43 -43
- package/src/client/components/core/LogOut.js +25 -16
- package/src/client/components/core/Modal.js +462 -179
- package/src/client/components/core/NotificationManager.js +14 -18
- package/src/client/components/core/Panel.js +54 -51
- package/src/client/components/core/PanelForm.js +44 -144
- package/src/client/components/core/Polyhedron.js +110 -214
- package/src/client/components/core/PublicProfile.js +39 -32
- package/src/client/components/core/Recover.js +48 -44
- package/src/client/components/core/Responsive.js +88 -32
- package/src/client/components/core/RichText.js +9 -18
- package/src/client/components/core/Router.js +24 -3
- package/src/client/components/core/SearchBox.js +37 -37
- package/src/client/components/core/SignUp.js +39 -30
- package/src/client/components/core/SocketIo.js +112 -30
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +143 -95
- package/src/client/components/core/ToggleSwitch.js +8 -20
- package/src/client/components/core/ToolTip.js +5 -17
- package/src/client/components/core/Translate.js +56 -59
- package/src/client/components/core/Validator.js +26 -16
- package/src/client/components/core/Wallet.js +15 -26
- package/src/client/components/core/Webhook.js +40 -7
- package/src/client/components/core/Worker.js +163 -27
- package/src/client/components/core/windowGetDimensions.js +7 -7
- package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +59 -59
- package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
- package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +9 -7
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +8 -6
- package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +4 -4
- package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +6 -4
- package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
- package/src/client/components/cyberia/InstanceEngineCyberia.js +781 -0
- package/src/client/components/cyberia/MapEngineCyberia.js +1836 -2
- package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +1220 -99
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +252 -316
- package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +136 -103
- package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +462 -32
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +9 -7
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +8 -6
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +4 -4
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +60 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +4 -4
- package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +6 -4
- package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -4
- package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +91 -91
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/CssDefault.js +12 -12
- package/src/client/components/default/LogInDefault.js +9 -7
- package/src/client/components/default/LogOutDefault.js +8 -6
- package/src/client/components/default/RouterDefault.js +47 -0
- package/src/client/components/default/SettingsDefault.js +4 -4
- package/src/client/components/default/SignUpDefault.js +6 -4
- package/src/client/components/default/SocketIoDefault.js +3 -51
- package/src/client/components/default/TranslateDefault.js +3 -3
- package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +59 -59
- package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
- package/src/client/components/itemledger/CssItemledger.js +15 -15
- package/src/client/components/itemledger/LogInItemledger.js +9 -7
- package/src/client/components/itemledger/LogOutItemledger.js +8 -6
- package/src/client/components/itemledger/RouterItemledger.js +38 -0
- package/src/client/components/itemledger/SettingsItemledger.js +4 -4
- package/src/client/components/itemledger/SignUpItemledger.js +6 -4
- package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
- package/src/client/components/itemledger/TranslateItemledger.js +3 -3
- package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +92 -92
- package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
- package/src/client/components/underpost/CssUnderpost.js +14 -14
- package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +4 -4
- package/src/client/components/underpost/DocumentSearchProvider.js +1 -1
- package/src/client/components/underpost/LabGalleryUnderpost.js +12 -15
- package/src/client/components/underpost/LogInUnderpost.js +9 -7
- package/src/client/components/underpost/LogOutUnderpost.js +8 -6
- package/src/client/components/underpost/RouterUnderpost.js +45 -0
- package/src/client/components/underpost/SettingsUnderpost.js +4 -4
- package/src/client/components/underpost/SignUpUnderpost.js +6 -4
- package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
- package/src/client/components/underpost/TranslateUnderpost.js +4 -4
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +235 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +443 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +417 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +313 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +260 -0
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +241 -0
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +279 -0
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +206 -0
- package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +732 -0
- package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +14 -20
- package/src/client/services/core/core.service.js +35 -55
- package/src/client/services/crypto/crypto.service.js +8 -13
- package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
- package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +99 -0
- package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
- package/src/client/services/cyberia-entity/cyberia-entity.service.js +99 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +116 -0
- package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +99 -0
- package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
- package/src/client/services/cyberia-map/cyberia-map.service.js +120 -0
- package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
- package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
- package/src/client/services/default/default.management.js +159 -267
- package/src/client/services/default/default.service.js +10 -16
- package/src/client/services/document/document.service.js +14 -19
- package/src/client/services/file/file.service.js +8 -13
- package/src/client/services/instance/instance.management.js +6 -6
- package/src/client/services/instance/instance.service.js +10 -15
- package/src/client/services/ipfs/ipfs.service.js +14 -40
- package/src/client/services/object-layer/object-layer.management.js +14 -14
- package/src/client/services/object-layer/object-layer.service.js +39 -24
- package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +10 -16
- package/src/client/services/test/test.service.js +8 -13
- package/src/client/services/user/guest.service.js +86 -0
- package/src/client/services/user/user.management.js +6 -6
- package/src/client/services/user/user.service.js +14 -20
- package/src/client/ssr/body/404.js +3 -3
- package/src/client/ssr/body/500.js +3 -3
- package/src/client/ssr/body/CacheControl.js +5 -2
- package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +13 -6
- package/src/client/ssr/head/PwaItemledger.js +197 -60
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
- package/src/client/ssr/offline/Maintenance.js +12 -11
- package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
- package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/pages/Test.js +2 -2
- package/src/client/sw/core.sw.js +212 -0
- package/src/grpc/cyberia/grpc-server.js +642 -0
- package/src/index.js +24 -1
- package/src/runtime/cyberia-client/Dockerfile +80 -0
- package/src/runtime/cyberia-server/Dockerfile +37 -0
- package/src/runtime/express/Dockerfile +5 -1
- package/src/runtime/express/Express.js +18 -1
- package/src/runtime/lampp/Dockerfile +17 -5
- package/src/runtime/lampp/Lampp.js +27 -4
- package/src/runtime/wp/Dockerfile +62 -0
- package/src/runtime/wp/Wp.js +639 -0
- package/src/server/atlas-sprite-sheet-generator.js +4 -2
- package/src/server/auth.js +24 -1
- package/src/server/backup.js +37 -9
- package/src/server/client-build-docs.js +52 -46
- package/src/server/client-build.js +356 -82
- package/src/server/client-formatted.js +140 -57
- package/src/server/conf.js +29 -13
- package/src/server/cron.js +25 -23
- package/src/server/data-query.js +32 -20
- package/src/server/dns.js +24 -1
- package/src/server/ipfs-client.js +253 -89
- package/src/server/object-layer.js +150 -114
- package/src/server/peer.js +8 -0
- package/src/server/process.js +13 -27
- package/src/server/runtime.js +25 -1
- package/src/server/semantic-layer-generator-floor.js +319 -0
- package/src/server/semantic-layer-generator-resource.js +259 -0
- package/src/server/semantic-layer-generator-skin.js +1164 -0
- package/src/server/semantic-layer-generator.js +211 -542
- package/src/server/shape-generator.js +108 -0
- package/src/server/start.js +19 -5
- package/src/server/valkey.js +141 -235
- package/src/ws/IoInterface.js +1 -10
- package/src/ws/IoServer.js +14 -33
- package/src/ws/core/channels/core.ws.chat.js +65 -20
- package/src/ws/core/channels/core.ws.mailer.js +113 -32
- package/src/ws/core/channels/core.ws.stream.js +90 -31
- package/src/ws/core/core.ws.connection.js +12 -33
- package/src/ws/core/core.ws.emit.js +10 -26
- package/src/ws/core/core.ws.server.js +25 -58
- package/src/ws/default/channels/default.ws.main.js +53 -12
- package/src/ws/default/default.ws.connection.js +26 -13
- package/src/ws/default/default.ws.server.js +30 -12
- package/tsconfig.docs.json +15 -0
- package/typedoc.dd-cyberia.json +29 -0
- package/typedoc.json +29 -0
- package/WHITE-PAPER.md +0 -1540
- package/hardhat/README.md +0 -531
- package/hardhat/WHITE-PAPER.md +0 -1540
- package/jsdoc.dd-cyberia.json +0 -59
- package/jsdoc.json +0 -59
- package/src/api/object-layer/README.md +0 -347
- package/src/client/components/core/ColorPalette.js +0 -5267
- package/src/client/components/core/JoyStick.js +0 -80
- package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
- package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
- package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
- package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
- package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -58
- package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
- package/src/client/components/default/ElementsDefault.js +0 -38
- package/src/client/components/default/RoutesDefault.js +0 -49
- package/src/client/components/itemledger/CommonItemledger.js +0 -29
- package/src/client/components/itemledger/ElementsItemledger.js +0 -38
- package/src/client/components/itemledger/RoutesItemledger.js +0 -40
- package/src/client/components/underpost/CommonUnderpost.js +0 -29
- package/src/client/components/underpost/ElementsUnderpost.js +0 -38
- package/src/client/components/underpost/RoutesUnderpost.js +0 -47
- package/src/client/sw/default.sw.js +0 -127
- package/src/client/sw/template.sw.js +0 -84
- package/src/ws/core/management/core.ws.chat.js +0 -8
- package/src/ws/core/management/core.ws.mailer.js +0 -16
- package/src/ws/core/management/core.ws.stream.js +0 -8
- package/src/ws/default/management/default.ws.main.js +0 -8
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gRPC server for the Cyberia Engine data pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Runs alongside Express on a separate port (default 50051).
|
|
5
|
+
* Provides read-only RPCs for the Go game server to fetch
|
|
6
|
+
* ObjectLayers, Instances, and Maps from MongoDB.
|
|
7
|
+
*
|
|
8
|
+
* @module src/grpc/cyberia/grpc-server.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import * as grpc from '@grpc/grpc-js';
|
|
12
|
+
import * as protoLoader from '@grpc/proto-loader';
|
|
13
|
+
import crypto from 'crypto';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { fileURLToPath } from 'url';
|
|
16
|
+
import { DataBaseProvider } from '../../db/DataBaseProvider.js';
|
|
17
|
+
import { loggerFactory } from '../../server/logger.js';
|
|
18
|
+
import {
|
|
19
|
+
CYBERIA_INSTANCE_CONF_DEFAULTS as FALLBACK_CONFIG_DEFAULTS,
|
|
20
|
+
ENTITY_TYPE_DEFAULTS,
|
|
21
|
+
STATUS_ICONS,
|
|
22
|
+
} from '../../api/cyberia-instance-conf/cyberia-instance-conf.defaults.js';
|
|
23
|
+
import { generateFallbackWorld } from '../../api/cyberia-instance/cyberia-fallback-world.js';
|
|
24
|
+
|
|
25
|
+
const logger = loggerFactory(import.meta);
|
|
26
|
+
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
28
|
+
const __dirname = path.dirname(__filename);
|
|
29
|
+
|
|
30
|
+
const PROTO_PATH = path.resolve(__dirname, '../../../cyberia-server/proto/cyberia.proto');
|
|
31
|
+
|
|
32
|
+
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
|
|
33
|
+
keepCase: false,
|
|
34
|
+
longs: Number,
|
|
35
|
+
enums: String,
|
|
36
|
+
defaults: true,
|
|
37
|
+
oneofs: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const proto = grpc.loadPackageDefinition(packageDefinition).cyberia;
|
|
41
|
+
|
|
42
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
43
|
+
// Helpers
|
|
44
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
45
|
+
|
|
46
|
+
function getModels(dbKey) {
|
|
47
|
+
const bucket = DataBaseProvider.instance[dbKey];
|
|
48
|
+
if (!bucket || !bucket.mongoose || !bucket.mongoose.models) {
|
|
49
|
+
throw new Error(`DataBaseProvider not loaded for key "${dbKey}"`);
|
|
50
|
+
}
|
|
51
|
+
return bucket.mongoose.models;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function countSharedItemIds(source = [], target = []) {
|
|
55
|
+
if (!Array.isArray(source) || source.length === 0 || !Array.isArray(target) || target.length === 0) {
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
const targetSet = new Set(target.filter(Boolean));
|
|
59
|
+
let count = 0;
|
|
60
|
+
for (const itemId of source) {
|
|
61
|
+
if (targetSet.has(itemId)) {
|
|
62
|
+
count += 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return count;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeEntityDefault(entityDefault = {}, canonical = {}) {
|
|
69
|
+
const defaultObjectLayers = entityDefault.defaultObjectLayers ?? canonical.defaultObjectLayers ?? [];
|
|
70
|
+
return {
|
|
71
|
+
entityType: entityDefault.entityType ?? canonical.entityType ?? '',
|
|
72
|
+
liveItemIds: [...(entityDefault.liveItemIds ?? canonical.liveItemIds ?? [])],
|
|
73
|
+
deadItemIds: [...(entityDefault.deadItemIds ?? canonical.deadItemIds ?? [])],
|
|
74
|
+
dropItemIds: [...(entityDefault.dropItemIds ?? canonical.dropItemIds ?? [])],
|
|
75
|
+
colorKey: entityDefault.colorKey ?? canonical.colorKey ?? '',
|
|
76
|
+
defaultObjectLayers: defaultObjectLayers.map((ol) => ({
|
|
77
|
+
itemId: ol.itemId || '',
|
|
78
|
+
active: !!ol.active,
|
|
79
|
+
quantity: ol.quantity || 0,
|
|
80
|
+
})),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function selectCanonicalEntityDefaultIndex(entityDefault, canonicalDefaults, usedIndexes) {
|
|
85
|
+
const pickBestIndex = (candidateIndexes) => {
|
|
86
|
+
let firstSameTypeIndex = -1;
|
|
87
|
+
let bestLiveOverlapIndex = -1;
|
|
88
|
+
let bestLiveOverlap = 0;
|
|
89
|
+
let bestLiveItemCount = Number.POSITIVE_INFINITY;
|
|
90
|
+
|
|
91
|
+
for (const index of candidateIndexes) {
|
|
92
|
+
const canonical = canonicalDefaults[index];
|
|
93
|
+
if (canonical.entityType !== entityDefault.entityType) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (firstSameTypeIndex === -1) {
|
|
97
|
+
firstSameTypeIndex = index;
|
|
98
|
+
}
|
|
99
|
+
if (entityDefault.colorKey && canonical.colorKey === entityDefault.colorKey) {
|
|
100
|
+
return index;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const liveOverlap = countSharedItemIds(entityDefault.liveItemIds, canonical.liveItemIds);
|
|
104
|
+
if (
|
|
105
|
+
liveOverlap > 0 &&
|
|
106
|
+
(bestLiveOverlapIndex === -1 ||
|
|
107
|
+
liveOverlap > bestLiveOverlap ||
|
|
108
|
+
(liveOverlap === bestLiveOverlap && (canonical.liveItemIds?.length ?? 0) < bestLiveItemCount))
|
|
109
|
+
) {
|
|
110
|
+
bestLiveOverlapIndex = index;
|
|
111
|
+
bestLiveOverlap = liveOverlap;
|
|
112
|
+
bestLiveItemCount = canonical.liveItemIds?.length ?? 0;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (bestLiveOverlapIndex !== -1) {
|
|
117
|
+
return bestLiveOverlapIndex;
|
|
118
|
+
}
|
|
119
|
+
return firstSameTypeIndex;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const unusedCandidateIndexes = canonicalDefaults.map((_, index) => index).filter((index) => !usedIndexes.has(index));
|
|
123
|
+
|
|
124
|
+
const preferredIndex = pickBestIndex(unusedCandidateIndexes);
|
|
125
|
+
if (preferredIndex !== -1) {
|
|
126
|
+
return preferredIndex;
|
|
127
|
+
}
|
|
128
|
+
return pickBestIndex(canonicalDefaults.map((_, index) => index));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function mergeEntityDefaults(entityDefaults = []) {
|
|
132
|
+
const mergedDefaults = ENTITY_TYPE_DEFAULTS.map((canonical) => normalizeEntityDefault(canonical, canonical));
|
|
133
|
+
const usedCanonicalIndexes = new Set();
|
|
134
|
+
|
|
135
|
+
for (const entityDefault of entityDefaults) {
|
|
136
|
+
const canonicalIndex = selectCanonicalEntityDefaultIndex(entityDefault, ENTITY_TYPE_DEFAULTS, usedCanonicalIndexes);
|
|
137
|
+
if (canonicalIndex === -1) {
|
|
138
|
+
mergedDefaults.push(normalizeEntityDefault(entityDefault));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
mergedDefaults[canonicalIndex] = normalizeEntityDefault(entityDefault, ENTITY_TYPE_DEFAULTS[canonicalIndex]);
|
|
143
|
+
usedCanonicalIndexes.add(canonicalIndex);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return mergedDefaults;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ── Mongoose doc → protobuf message converters ───────────────────
|
|
150
|
+
|
|
151
|
+
function toObjectLayerMsg(doc) {
|
|
152
|
+
const d = doc.data || {};
|
|
153
|
+
const item = d.item || {};
|
|
154
|
+
const stats = d.stats || {};
|
|
155
|
+
const ledger = d.ledger || {};
|
|
156
|
+
const render = d.render || {};
|
|
157
|
+
return {
|
|
158
|
+
mongoId: String(doc._id),
|
|
159
|
+
stats: {
|
|
160
|
+
effect: stats.effect || 0,
|
|
161
|
+
resistance: stats.resistance || 0,
|
|
162
|
+
agility: stats.agility || 0,
|
|
163
|
+
range: stats.range || 0,
|
|
164
|
+
intelligence: stats.intelligence || 0,
|
|
165
|
+
utility: stats.utility || 0,
|
|
166
|
+
},
|
|
167
|
+
item: {
|
|
168
|
+
id: item.id || '',
|
|
169
|
+
type: item.type || '',
|
|
170
|
+
description: item.description || '',
|
|
171
|
+
activable: !!item.activable,
|
|
172
|
+
},
|
|
173
|
+
ledger: {
|
|
174
|
+
type: ledger.type || 'OFF_CHAIN',
|
|
175
|
+
address: ledger.address || '',
|
|
176
|
+
tokenId: ledger.tokenId || '',
|
|
177
|
+
},
|
|
178
|
+
render: {
|
|
179
|
+
cid: render.cid || '',
|
|
180
|
+
metadataCid: render.metadataCid || '',
|
|
181
|
+
},
|
|
182
|
+
sha256: doc.sha256 || '',
|
|
183
|
+
cid: doc.cid || '',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Parse a CSS rgba() colour string into {r, g, b, a} integer components.
|
|
189
|
+
* Returns {r:0, g:0, b:0, a:0} (transparent) when the string is absent or malformed.
|
|
190
|
+
*/
|
|
191
|
+
function parseRgba(str) {
|
|
192
|
+
if (!str) return { r: 0, g: 0, b: 0, a: 0 };
|
|
193
|
+
const m = str.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/);
|
|
194
|
+
if (!m) return { r: 0, g: 0, b: 0, a: 0 };
|
|
195
|
+
// CSS alpha is 0-1 (float); proto uses 0-255 (int).
|
|
196
|
+
const cssAlpha = m[4] !== undefined ? parseFloat(m[4]) : 1;
|
|
197
|
+
return { r: Number(m[1]), g: Number(m[2]), b: Number(m[3]), a: Math.round(cssAlpha * 255) };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function toEntityMsg(ent) {
|
|
201
|
+
const rgba = parseRgba(ent.color);
|
|
202
|
+
return {
|
|
203
|
+
entityType: ent.entityType || 'floor',
|
|
204
|
+
initCellX: ent.initCellX || 0,
|
|
205
|
+
initCellY: ent.initCellY || 0,
|
|
206
|
+
dimX: ent.dimX || 1,
|
|
207
|
+
dimY: ent.dimY || 1,
|
|
208
|
+
color: ent.color || '',
|
|
209
|
+
objectLayerItemIds: ent.objectLayerItemIds || [],
|
|
210
|
+
spawnRadius: ent.spawnRadius || 0,
|
|
211
|
+
aggroRange: ent.aggroRange || 0,
|
|
212
|
+
maxLife: ent.maxLife || 0,
|
|
213
|
+
lifeRegen: ent.lifeRegen || 0,
|
|
214
|
+
portalSubtype: ent.portalSubtype || '',
|
|
215
|
+
colorR: rgba.r,
|
|
216
|
+
colorG: rgba.g,
|
|
217
|
+
colorB: rgba.b,
|
|
218
|
+
colorA: rgba.a,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function toMapMsg(doc) {
|
|
223
|
+
return {
|
|
224
|
+
mongoId: String(doc._id),
|
|
225
|
+
code: doc.code || '',
|
|
226
|
+
name: doc.name || '',
|
|
227
|
+
gridX: doc.gridX || 16,
|
|
228
|
+
gridY: doc.gridY || 16,
|
|
229
|
+
cellWidth: doc.cellWidth || 32,
|
|
230
|
+
cellHeight: doc.cellHeight || 32,
|
|
231
|
+
entities: (doc.entities || []).map(toEntityMsg),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function toInstanceMsg(doc) {
|
|
236
|
+
return {
|
|
237
|
+
mongoId: String(doc._id),
|
|
238
|
+
code: doc.code || '',
|
|
239
|
+
name: doc.name || '',
|
|
240
|
+
description: doc.description || '',
|
|
241
|
+
tags: doc.tags || [],
|
|
242
|
+
mapCodes: doc.cyberiaMapCodes || [],
|
|
243
|
+
portals: (doc.portals || []).map((p) => ({
|
|
244
|
+
sourceMapCode: p.sourceMapCode || '',
|
|
245
|
+
sourceCellX: p.sourceCellX || 0,
|
|
246
|
+
sourceCellY: p.sourceCellY || 0,
|
|
247
|
+
targetMapCode: p.targetMapCode || '',
|
|
248
|
+
targetCellX: p.targetCellX || 0,
|
|
249
|
+
targetCellY: p.targetCellY || 0,
|
|
250
|
+
portalMode: p.portalMode || 'inter-portal',
|
|
251
|
+
})),
|
|
252
|
+
topologyMode: doc.topologyMode || 'hybrid',
|
|
253
|
+
seed: doc.seed || '',
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Converts a CyberiaInstanceConf Mongoose document (or plain object) into
|
|
259
|
+
* a complete InstanceConfig proto message.
|
|
260
|
+
* Any field that is null/undefined in `gc` falls back to FALLBACK_CONFIG_DEFAULTS,
|
|
261
|
+
* so partial DB documents always produce a fully playable config.
|
|
262
|
+
*/
|
|
263
|
+
function toInstanceConfig(gc) {
|
|
264
|
+
const fb = FALLBACK_CONFIG_DEFAULTS;
|
|
265
|
+
if (!gc) return buildFallbackConfig();
|
|
266
|
+
|
|
267
|
+
// Per-key merge: start with canonical defaults, overlay any DB-defined colours.
|
|
268
|
+
const dbColorMap = new Map((gc.colors || []).map((c) => [c.key, c]));
|
|
269
|
+
const colors = fb.colors.map((c) => {
|
|
270
|
+
const ov = dbColorMap.get(c.key);
|
|
271
|
+
return ov ? { key: c.key, r: ov.r ?? c.r, g: ov.g ?? c.g, b: ov.b ?? c.b, a: ov.a ?? c.a } : { ...c };
|
|
272
|
+
});
|
|
273
|
+
// Append any DB colours whose keys are absent from the canonical defaults.
|
|
274
|
+
for (const [key, c] of dbColorMap) {
|
|
275
|
+
if (!colors.some((fc) => fc.key === key)) {
|
|
276
|
+
colors.push({ key, r: c.r ?? 0, g: c.g ?? 0, b: c.b ?? 0, a: c.a ?? 255 });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Merge entity defaults while preserving duplicate builds (for example,
|
|
281
|
+
// multiple resource or portal variants sharing the same entityType).
|
|
282
|
+
const gcDefaults = gc.entityDefaults && gc.entityDefaults.length > 0 ? gc.entityDefaults : [];
|
|
283
|
+
const entityDefaults = mergeEntityDefaults(gcDefaults);
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
cellSize: gc.cellSize ?? fb.cellSize,
|
|
287
|
+
fps: gc.fps ?? fb.fps,
|
|
288
|
+
interpolationMs: gc.interpolationMs ?? fb.interpolationMs,
|
|
289
|
+
defaultObjWidth: gc.defaultObjWidth ?? fb.defaultObjWidth,
|
|
290
|
+
defaultObjHeight: gc.defaultObjHeight ?? fb.defaultObjHeight,
|
|
291
|
+
cameraSmoothing: gc.cameraSmoothing ?? fb.cameraSmoothing,
|
|
292
|
+
cameraZoom: gc.cameraZoom ?? fb.cameraZoom,
|
|
293
|
+
defaultWidthScreenFactor: gc.defaultWidthScreenFactor ?? fb.defaultWidthScreenFactor,
|
|
294
|
+
defaultHeightScreenFactor: gc.defaultHeightScreenFactor ?? fb.defaultHeightScreenFactor,
|
|
295
|
+
devUi: gc.devUi ?? fb.devUi,
|
|
296
|
+
colors,
|
|
297
|
+
aoiRadius: gc.aoiRadius ?? fb.aoiRadius,
|
|
298
|
+
portalHoldTimeMs: gc.portalHoldTimeMs ?? fb.portalHoldTimeMs,
|
|
299
|
+
portalSpawnRadius: gc.portalSpawnRadius ?? fb.portalSpawnRadius,
|
|
300
|
+
entityBaseSpeed: gc.entityBaseSpeed ?? fb.entityBaseSpeed,
|
|
301
|
+
entityBaseMaxLife: gc.entityBaseMaxLife ?? fb.entityBaseMaxLife,
|
|
302
|
+
entityBaseActionCooldownMs: gc.entityBaseActionCooldownMs ?? fb.entityBaseActionCooldownMs,
|
|
303
|
+
entityBaseMinActionCooldownMs: gc.entityBaseMinActionCooldownMs ?? fb.entityBaseMinActionCooldownMs,
|
|
304
|
+
botAggroRange: gc.botAggroRange ?? fb.botAggroRange,
|
|
305
|
+
defaultPlayerWidth: gc.defaultPlayerWidth ?? fb.defaultPlayerWidth,
|
|
306
|
+
defaultPlayerHeight: gc.defaultPlayerHeight ?? fb.defaultPlayerHeight,
|
|
307
|
+
playerBaseLifeRegenMin: gc.playerBaseLifeRegenMin ?? fb.playerBaseLifeRegenMin,
|
|
308
|
+
playerBaseLifeRegenMax: gc.playerBaseLifeRegenMax ?? fb.playerBaseLifeRegenMax,
|
|
309
|
+
sumStatsLimit: gc.sumStatsLimit ?? fb.sumStatsLimit,
|
|
310
|
+
maxActiveLayers: gc.maxActiveLayers ?? fb.maxActiveLayers,
|
|
311
|
+
initialLifeFraction: gc.initialLifeFraction ?? fb.initialLifeFraction,
|
|
312
|
+
respawnDurationMs: gc.respawnDurationMs ?? fb.respawnDurationMs,
|
|
313
|
+
collisionLifeLoss: gc.collisionLifeLoss ?? fb.collisionLifeLoss,
|
|
314
|
+
// Economy — Fountain & Sink (nested, mirrors EconomyRules proto message).
|
|
315
|
+
economyRules: {
|
|
316
|
+
botSpawnCoins: gc.economyRules?.botSpawnCoins ?? fb.economyRules.botSpawnCoins,
|
|
317
|
+
playerSpawnCoins: gc.economyRules?.playerSpawnCoins ?? fb.economyRules.playerSpawnCoins,
|
|
318
|
+
coinKillPercentVsBot: gc.economyRules?.coinKillPercentVsBot ?? fb.economyRules.coinKillPercentVsBot,
|
|
319
|
+
coinKillPercentVsPlayer: gc.economyRules?.coinKillPercentVsPlayer ?? fb.economyRules.coinKillPercentVsPlayer,
|
|
320
|
+
coinKillMinAmount: gc.economyRules?.coinKillMinAmount ?? fb.economyRules.coinKillMinAmount,
|
|
321
|
+
respawnCostPercent: gc.economyRules?.respawnCostPercent ?? fb.economyRules.respawnCostPercent,
|
|
322
|
+
portalFee: gc.economyRules?.portalFee ?? fb.economyRules.portalFee,
|
|
323
|
+
craftingFeePercent: gc.economyRules?.craftingFeePercent ?? fb.economyRules.craftingFeePercent,
|
|
324
|
+
},
|
|
325
|
+
lifeRegenChance: gc.lifeRegenChance ?? fb.lifeRegenChance,
|
|
326
|
+
maxChance: gc.maxChance ?? fb.maxChance,
|
|
327
|
+
entityDefaults,
|
|
328
|
+
skillConfig: (gc.skillConfig && gc.skillConfig.length > 0 ? gc.skillConfig : fb.skillConfig).map((sc) => ({
|
|
329
|
+
triggerItemId: sc.triggerItemId || '',
|
|
330
|
+
skills: (sc.skills || []).map((sk) => ({
|
|
331
|
+
logicEventId: sk.logicEventId || '',
|
|
332
|
+
name: sk.name || '',
|
|
333
|
+
description: sk.description || '',
|
|
334
|
+
summonedEntityItemId: sk.summonedEntityItemId || '',
|
|
335
|
+
})),
|
|
336
|
+
})),
|
|
337
|
+
skillRules: {
|
|
338
|
+
projectileSpawnChance: gc.skillRules?.projectileSpawnChance ?? fb.skillRules.projectileSpawnChance,
|
|
339
|
+
projectileLifetimeMs: gc.skillRules?.projectileLifetimeMs ?? fb.skillRules.projectileLifetimeMs,
|
|
340
|
+
projectileWidth: gc.skillRules?.projectileWidth ?? fb.skillRules.projectileWidth,
|
|
341
|
+
projectileHeight: gc.skillRules?.projectileHeight ?? fb.skillRules.projectileHeight,
|
|
342
|
+
projectileSpeedMultiplier: gc.skillRules?.projectileSpeedMultiplier ?? fb.skillRules.projectileSpeedMultiplier,
|
|
343
|
+
doppelgangerSpawnChance: gc.skillRules?.doppelgangerSpawnChance ?? fb.skillRules.doppelgangerSpawnChance,
|
|
344
|
+
doppelgangerLifetimeMs: gc.skillRules?.doppelgangerLifetimeMs ?? fb.skillRules.doppelgangerLifetimeMs,
|
|
345
|
+
doppelgangerSpawnRadius: gc.skillRules?.doppelgangerSpawnRadius ?? fb.skillRules.doppelgangerSpawnRadius,
|
|
346
|
+
doppelgangerInitialLifeFraction:
|
|
347
|
+
gc.skillRules?.doppelgangerInitialLifeFraction ?? fb.skillRules.doppelgangerInitialLifeFraction,
|
|
348
|
+
},
|
|
349
|
+
// Equipment rules — governs activation constraints (nested, mirrors EquipmentRules proto message).
|
|
350
|
+
equipmentRules: {
|
|
351
|
+
activeItemTypes: gc.equipmentRules?.activeItemTypes ?? fb.equipmentRules.activeItemTypes,
|
|
352
|
+
onePerType: gc.equipmentRules?.onePerType ?? fb.equipmentRules.onePerType,
|
|
353
|
+
requireSkin: gc.equipmentRules?.requireSkin ?? fb.equipmentRules.requireSkin,
|
|
354
|
+
},
|
|
355
|
+
// Status icon mapping — u8 ID → icon filename stem + border colour.
|
|
356
|
+
// Border colours come from the frozen STATUS_ICONS constant (canonical
|
|
357
|
+
// source of truth). DB entries may override iconId but borderColor is
|
|
358
|
+
// always canonical — the DB schema defaults are generic grey, not the
|
|
359
|
+
// actual per-status colours.
|
|
360
|
+
statusIcons: STATUS_ICONS.map((canon) => {
|
|
361
|
+
const dbEntry = (gc.statusIcons || []).find((s) => s.id === canon.id);
|
|
362
|
+
const bc = canon.borderColor || {};
|
|
363
|
+
return {
|
|
364
|
+
id: canon.id,
|
|
365
|
+
iconId: (dbEntry && dbEntry.iconId) || canon.iconId || '',
|
|
366
|
+
borderColorR: bc.r ?? 100,
|
|
367
|
+
borderColorG: bc.g ?? 100,
|
|
368
|
+
borderColorB: bc.b ?? 100,
|
|
369
|
+
borderColorA: bc.a ?? 200,
|
|
370
|
+
};
|
|
371
|
+
}),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Builds a minimal InstanceConfig with playable defaults.
|
|
377
|
+
* Derived from CYBERIA_INSTANCE_CONF_DEFAULTS (shared with the Mongoose model).
|
|
378
|
+
* Used when the requested instance does not exist in the database.
|
|
379
|
+
*/
|
|
380
|
+
function buildFallbackConfig() {
|
|
381
|
+
return JSON.parse(JSON.stringify(FALLBACK_CONFIG_DEFAULTS));
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
385
|
+
// RPC handler factory
|
|
386
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
387
|
+
|
|
388
|
+
function buildHandlers(dbKey) {
|
|
389
|
+
return {
|
|
390
|
+
async ping(_call, callback) {
|
|
391
|
+
callback(null, { serverTimeMs: Date.now() });
|
|
392
|
+
},
|
|
393
|
+
|
|
394
|
+
// Server-streaming: streams all ObjectLayers
|
|
395
|
+
async getObjectLayerBatch(call) {
|
|
396
|
+
try {
|
|
397
|
+
const models = getModels(dbKey);
|
|
398
|
+
const filter = {};
|
|
399
|
+
if (call.request.itemTypeFilter) {
|
|
400
|
+
filter['data.item.type'] = call.request.itemTypeFilter;
|
|
401
|
+
}
|
|
402
|
+
const cursor = models.ObjectLayer.find(filter).lean().cursor();
|
|
403
|
+
for await (const doc of cursor) {
|
|
404
|
+
call.write(toObjectLayerMsg(doc));
|
|
405
|
+
}
|
|
406
|
+
call.end();
|
|
407
|
+
} catch (err) {
|
|
408
|
+
logger.error('getObjectLayerBatch:', err);
|
|
409
|
+
call.destroy(new Error(err.message));
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
async getObjectLayer(call, callback) {
|
|
414
|
+
try {
|
|
415
|
+
const models = getModels(dbKey);
|
|
416
|
+
const doc = await models.ObjectLayer.findOne({ 'data.item.id': call.request.itemId }).lean();
|
|
417
|
+
if (!doc)
|
|
418
|
+
return callback({ code: grpc.status.NOT_FOUND, message: `ObjectLayer "${call.request.itemId}" not found` });
|
|
419
|
+
callback(null, toObjectLayerMsg(doc));
|
|
420
|
+
} catch (err) {
|
|
421
|
+
logger.error('getObjectLayer:', err);
|
|
422
|
+
callback({ code: grpc.status.INTERNAL, message: err.message });
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
|
|
426
|
+
async getMapData(call, callback) {
|
|
427
|
+
try {
|
|
428
|
+
const models = getModels(dbKey);
|
|
429
|
+
const { mapCode, instanceCode } = call.request;
|
|
430
|
+
const doc = await models.CyberiaMap.findOne({ code: mapCode }).lean();
|
|
431
|
+
if (!doc) return callback({ code: grpc.status.NOT_FOUND, message: `Map "${mapCode}" not found` });
|
|
432
|
+
|
|
433
|
+
// Track which instance is serving each mapCode in real time.
|
|
434
|
+
// instanceCode is provided by the Go server in every GetMapData request.
|
|
435
|
+
if (instanceCode) {
|
|
436
|
+
models.GlobalMapCodeRegistry.findOneAndUpdate(
|
|
437
|
+
{ mapCode },
|
|
438
|
+
{ instanceCode, status: 'active' },
|
|
439
|
+
{ upsert: true, returnDocument: 'after', timestamps: true },
|
|
440
|
+
).catch((err) => logger.warn('getMapData registry update failed:', err.message));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
callback(null, { map: toMapMsg(doc) });
|
|
444
|
+
} catch (err) {
|
|
445
|
+
logger.error('getMapData:', err);
|
|
446
|
+
callback({ code: grpc.status.INTERNAL, message: err.message });
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
|
|
450
|
+
async getFullInstance(call, callback) {
|
|
451
|
+
try {
|
|
452
|
+
const models = getModels(dbKey);
|
|
453
|
+
// Normalise empty instanceCode to the canonical fallback name.
|
|
454
|
+
const instanceCode = call.request.instanceCode || 'default';
|
|
455
|
+
const inst = await models.CyberiaInstance.findOne({ code: instanceCode }).populate('conf').lean();
|
|
456
|
+
|
|
457
|
+
// ── Fallback: instance not found → return a multi-map procedural world ──
|
|
458
|
+
if (!inst) {
|
|
459
|
+
logger.info(`Instance "${instanceCode}" not found — returning fallback world.`);
|
|
460
|
+
const world = generateFallbackWorld();
|
|
461
|
+
const fallbackConf = buildFallbackConfig();
|
|
462
|
+
|
|
463
|
+
// Collect all objectLayerItemIds from the generated maps so the
|
|
464
|
+
// Go server can resolve atlases at startup.
|
|
465
|
+
const fallbackItemIds = new Set();
|
|
466
|
+
for (const m of world.maps) {
|
|
467
|
+
for (const e of m.entities || []) {
|
|
468
|
+
for (const id of e.objectLayerItemIds || []) fallbackItemIds.add(id);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// Also include system OL items from entity defaults.
|
|
472
|
+
for (const d of fallbackConf.entityDefaults || []) {
|
|
473
|
+
for (const id of d.liveItemIds || []) fallbackItemIds.add(id);
|
|
474
|
+
for (const id of d.deadItemIds || []) fallbackItemIds.add(id);
|
|
475
|
+
for (const id of d.dropItemIds || []) fallbackItemIds.add(id);
|
|
476
|
+
for (const ol of d.defaultObjectLayers || []) {
|
|
477
|
+
if (ol.itemId) fallbackItemIds.add(ol.itemId);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const fallbackOlDocs = fallbackItemIds.size
|
|
482
|
+
? await models.ObjectLayer.find({ 'data.item.id': { $in: [...fallbackItemIds] } }).lean()
|
|
483
|
+
: [];
|
|
484
|
+
|
|
485
|
+
callback(null, {
|
|
486
|
+
instance: toInstanceMsg({
|
|
487
|
+
_id: '',
|
|
488
|
+
code: 'fallback',
|
|
489
|
+
name: 'Fallback Instance',
|
|
490
|
+
description: 'Auto-generated procedural world (not persisted)',
|
|
491
|
+
tags: ['fallback', 'procedural'],
|
|
492
|
+
cyberiaMapCodes: world.instance.cyberiaMapCodes,
|
|
493
|
+
portals: world.portals,
|
|
494
|
+
topologyMode: 'procedural',
|
|
495
|
+
seed: instanceCode,
|
|
496
|
+
}),
|
|
497
|
+
maps: world.maps.map((m) => ({
|
|
498
|
+
mongoId: '',
|
|
499
|
+
code: m.code,
|
|
500
|
+
name: m.name,
|
|
501
|
+
gridX: m.gridX,
|
|
502
|
+
gridY: m.gridY,
|
|
503
|
+
cellWidth: m.cellWidth,
|
|
504
|
+
cellHeight: m.cellHeight,
|
|
505
|
+
entities: (m.entities || []).map(toEntityMsg),
|
|
506
|
+
})),
|
|
507
|
+
objectLayers: fallbackOlDocs.map(toObjectLayerMsg),
|
|
508
|
+
config: toInstanceConfig(fallbackConf),
|
|
509
|
+
version: 'fallback',
|
|
510
|
+
});
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// ── Instance found — load maps + entity OLs + config default OLs ──────
|
|
515
|
+
// `populate('conf')` returns null when the ObjectId ref is missing or
|
|
516
|
+
// orphaned (e.g. after a --conf import that preserved a stale _id).
|
|
517
|
+
// Fall back to a direct instanceCode lookup so aoiRadius and all other
|
|
518
|
+
// tuning fields are always read from the database, never silently
|
|
519
|
+
// replaced by FALLBACK_CONFIG_DEFAULTS.
|
|
520
|
+
let conf = inst.conf;
|
|
521
|
+
if (!conf) {
|
|
522
|
+
conf = await models.CyberiaInstanceConf.findOne({ instanceCode }).lean();
|
|
523
|
+
if (conf) {
|
|
524
|
+
logger.warn(
|
|
525
|
+
`getFullInstance: conf ref missing on instance "${instanceCode}" — resolved by instanceCode lookup`,
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
conf = conf || {};
|
|
530
|
+
const mapCodes = inst.cyberiaMapCodes || [];
|
|
531
|
+
const mapDocs = mapCodes.length ? await models.CyberiaMap.find({ code: { $in: mapCodes } }).lean() : [];
|
|
532
|
+
|
|
533
|
+
// Collect all item IDs referenced by map entities.
|
|
534
|
+
const itemIds = new Set();
|
|
535
|
+
for (const m of mapDocs) {
|
|
536
|
+
for (const e of m.entities || []) {
|
|
537
|
+
for (const id of e.objectLayerItemIds || []) itemIds.add(id);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Include system OL items from BOTH canonical ENTITY_TYPE_DEFAULTS AND
|
|
542
|
+
// the DB conf so the Go server always caches all default atlases even if
|
|
543
|
+
// the DB doc has incomplete entityDefaults.
|
|
544
|
+
for (const d of [...ENTITY_TYPE_DEFAULTS, ...(conf.entityDefaults || [])]) {
|
|
545
|
+
for (const id of d.liveItemIds || []) itemIds.add(id);
|
|
546
|
+
for (const id of d.deadItemIds || []) itemIds.add(id);
|
|
547
|
+
for (const id of d.dropItemIds || []) itemIds.add(id);
|
|
548
|
+
for (const ol of d.defaultObjectLayers || []) {
|
|
549
|
+
if (ol.itemId) itemIds.add(ol.itemId);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const olDocs = itemIds.size
|
|
554
|
+
? await models.ObjectLayer.find({ 'data.item.id': { $in: [...itemIds] } }).lean()
|
|
555
|
+
: [];
|
|
556
|
+
|
|
557
|
+
// Opaque version string from updatedAt timestamps — the Go server
|
|
558
|
+
// compares this to skip full world rebuilds when nothing changed.
|
|
559
|
+
const versionParts = [String(inst.updatedAt || inst._id)];
|
|
560
|
+
for (const m of mapDocs) versionParts.push(String(m.updatedAt || m._id));
|
|
561
|
+
if (conf.updatedAt) versionParts.push(String(conf.updatedAt));
|
|
562
|
+
const version = crypto.createHash('sha256').update(versionParts.join('|')).digest('hex');
|
|
563
|
+
|
|
564
|
+
callback(null, {
|
|
565
|
+
instance: toInstanceMsg(inst),
|
|
566
|
+
maps: mapDocs.map(toMapMsg),
|
|
567
|
+
objectLayers: olDocs.map(toObjectLayerMsg),
|
|
568
|
+
config: toInstanceConfig(conf),
|
|
569
|
+
version,
|
|
570
|
+
});
|
|
571
|
+
} catch (err) {
|
|
572
|
+
logger.error('getFullInstance:', err);
|
|
573
|
+
callback({ code: grpc.status.INTERNAL, message: err.message });
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
|
|
577
|
+
async getObjectLayerManifest(_call, callback) {
|
|
578
|
+
try {
|
|
579
|
+
const models = getModels(dbKey);
|
|
580
|
+
const docs = await models.ObjectLayer.find({}, { 'data.item.id': 1, sha256: 1 }).lean();
|
|
581
|
+
callback(null, {
|
|
582
|
+
entries: docs.map((d) => ({ itemId: d.data?.item?.id || '', sha256: d.sha256 || '' })),
|
|
583
|
+
});
|
|
584
|
+
} catch (err) {
|
|
585
|
+
logger.error('getObjectLayerManifest:', err);
|
|
586
|
+
callback({ code: grpc.status.INTERNAL, message: err.message });
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
593
|
+
// Server lifecycle
|
|
594
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
595
|
+
|
|
596
|
+
class GrpcServer {
|
|
597
|
+
static _server = null;
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* @param {Object} opts
|
|
601
|
+
* @param {string} opts.host - DataBaseProvider host key
|
|
602
|
+
* @param {string} opts.path - DataBaseProvider path key
|
|
603
|
+
* @param {number} [opts.port=50051]
|
|
604
|
+
*/
|
|
605
|
+
static async start({ host, path: dbPath, port = 50051 } = {}) {
|
|
606
|
+
const dbKey = `${host}${dbPath}`;
|
|
607
|
+
const server = new grpc.Server({
|
|
608
|
+
'grpc.max_send_message_length': 64 * 1024 * 1024,
|
|
609
|
+
'grpc.max_receive_message_length': 16 * 1024 * 1024,
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
server.addService(proto.CyberiaDataService.service, buildHandlers(dbKey));
|
|
613
|
+
|
|
614
|
+
// gRPC runs over Kubernetes internal network (ClusterIP) — always insecure
|
|
615
|
+
const creds = grpc.ServerCredentials.createInsecure();
|
|
616
|
+
|
|
617
|
+
return new Promise((resolve, reject) => {
|
|
618
|
+
server.bindAsync(`0.0.0.0:${port}`, creds, (err) => {
|
|
619
|
+
if (err) {
|
|
620
|
+
logger.error('gRPC bind failed:', err);
|
|
621
|
+
return reject(err);
|
|
622
|
+
}
|
|
623
|
+
GrpcServer._server = server;
|
|
624
|
+
logger.info(`gRPC server listening on 0.0.0.0:${port}`);
|
|
625
|
+
resolve(server);
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
static async stop() {
|
|
631
|
+
if (!GrpcServer._server) return;
|
|
632
|
+
return new Promise((resolve) => {
|
|
633
|
+
GrpcServer._server.tryShutdown(() => {
|
|
634
|
+
GrpcServer._server = null;
|
|
635
|
+
logger.info('gRPC server stopped');
|
|
636
|
+
resolve();
|
|
637
|
+
});
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
export { GrpcServer };
|