cyberia 3.2.5 → 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/.github/workflows/engine-cyberia.cd.yml +2 -2
- package/.github/workflows/release.cd.yml +1 -2
- package/CHANGELOG.md +351 -1
- package/CLI-HELP.md +40 -13
- package/Dockerfile +0 -4
- package/README.md +242 -497
- package/bin/build.js +19 -5
- package/bin/cyberia.js +1149 -240
- package/bin/deploy.js +570 -1
- package/bin/file.js +6 -0
- package/bin/index.js +1149 -240
- package/bin/vs.js +1 -1
- package/conf.js +67 -89
- package/deployment.yaml +4 -222
- package/hardhat/package-lock.json +32 -32
- package/hardhat/package.json +3 -3
- package/jsconfig.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -2
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +4 -222
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +10 -118
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
- package/manifests/deployment/dd-test-development/deployment.yaml +136 -66
- package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
- package/package.json +23 -14
- package/proxy.yaml +10 -118
- package/scripts/k3s-node-setup.sh +2 -2
- package/scripts/nat-iptables.sh +103 -18
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +18 -18
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +7 -14
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +76 -21
- 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 +13 -13
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +11 -11
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +16 -16
- package/src/api/cyberia-entity/cyberia-entity.controller.js +10 -10
- package/src/api/cyberia-entity/cyberia-entity.service.js +10 -10
- package/src/api/cyberia-instance/cyberia-fallback-world.js +19 -209
- package/src/api/cyberia-instance/cyberia-instance.controller.js +14 -14
- package/src/api/cyberia-instance/cyberia-instance.model.js +3 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +22 -57
- package/src/api/cyberia-instance/cyberia-portal-connector.js +20 -246
- package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +10 -10
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +216 -55
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +4 -1
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +18 -14
- package/src/api/cyberia-map/cyberia-map.controller.js +10 -10
- package/src/api/cyberia-map/cyberia-map.service.js +10 -10
- 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.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 +12 -12
- package/src/api/ipfs/ipfs.model.js +4 -13
- package/src/api/ipfs/ipfs.service.js +14 -28
- 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.service.js +12 -12
- 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 +3 -20
- package/src/cli/cluster.js +61 -14
- package/src/cli/db.js +47 -2
- package/src/cli/deploy.js +67 -35
- package/src/cli/fs.js +79 -8
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +26 -1
- package/src/cli/release.js +57 -1
- package/src/cli/repository.js +69 -31
- package/src/cli/run.js +415 -36
- package/src/cli/ssh.js +1 -1
- package/src/cli/static.js +43 -115
- package/src/client/Cryptokoyn.index.js +18 -21
- package/src/client/CyberiaPortal.index.js +19 -23
- package/src/client/Default.index.js +21 -33
- package/src/client/Itemledger.index.js +20 -26
- package/src/client/Underpost.index.js +19 -23
- 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 +1 -1
- 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 +42 -63
- 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 +69 -91
- 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 +25 -18
- 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 +41 -41
- package/src/client/components/core/LogOut.js +23 -14
- package/src/client/components/core/Modal.js +462 -178
- package/src/client/components/core/NotificationManager.js +14 -18
- package/src/client/components/core/Panel.js +54 -50
- package/src/client/components/core/PanelForm.js +25 -125
- 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 +31 -2
- package/src/client/components/core/SocketIoHandler.js +6 -6
- 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/Worker.js +163 -27
- package/src/client/components/core/windowGetDimensions.js +7 -7
- package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +57 -57
- package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +6 -4
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +6 -4
- 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/cyberia/InstanceEngineCyberia.js +141 -60
- package/src/client/components/cyberia/MapEngineCyberia.js +691 -214
- package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +1204 -94
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +196 -298
- package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +102 -102
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +305 -61
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +6 -4
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +6 -4
- 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/TranslateCyberiaPortal.js +4 -4
- package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
- package/src/client/components/default/CssDefault.js +12 -12
- package/src/client/components/default/LogInDefault.js +6 -4
- package/src/client/components/default/LogOutDefault.js +6 -4
- 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/TranslateDefault.js +3 -3
- package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +57 -57
- package/src/client/components/itemledger/CssItemledger.js +15 -15
- package/src/client/components/itemledger/LogInItemledger.js +6 -4
- package/src/client/components/itemledger/LogOutItemledger.js +6 -4
- 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/TranslateItemledger.js +3 -3
- package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +88 -88
- 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 +6 -4
- package/src/client/components/underpost/LogOutUnderpost.js +6 -4
- 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/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 +17 -49
- 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 +10 -16
- package/src/client/services/cyberia-entity/cyberia-entity.management.js +5 -5
- package/src/client/services/cyberia-entity/cyberia-entity.service.js +10 -16
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +6 -6
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +12 -18
- package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +10 -16
- package/src/client/services/cyberia-map/cyberia-map.management.js +6 -6
- package/src/client/services/cyberia-map/cyberia-map.service.js +12 -18
- 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 +5 -5
- package/src/client/services/instance/instance.service.js +10 -15
- package/src/client/services/ipfs/ipfs.service.js +12 -18
- package/src/client/services/object-layer/object-layer.management.js +12 -12
- package/src/client/services/object-layer/object-layer.service.js +20 -26
- 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 +5 -5
- 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/Test.js +2 -2
- package/src/client/sw/core.sw.js +212 -0
- package/src/grpc/cyberia/grpc-server.js +179 -67
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +80 -0
- package/src/runtime/cyberia-server/Dockerfile +37 -0
- package/src/runtime/express/Dockerfile +4 -4
- package/src/runtime/lampp/Dockerfile +8 -7
- package/src/runtime/wp/Dockerfile +11 -17
- package/src/server/atlas-sprite-sheet-generator.js +4 -2
- package/src/server/client-build-docs.js +45 -46
- package/src/server/client-build.js +334 -60
- package/src/server/client-formatted.js +47 -16
- package/src/server/conf.js +5 -4
- package/src/server/data-query.js +32 -20
- package/src/server/dns.js +22 -0
- package/src/server/ipfs-client.js +232 -91
- package/src/server/object-layer.js +1 -6
- package/src/server/process.js +13 -27
- package/src/server/semantic-layer-generator-floor.js +11 -51
- package/src/server/semantic-layer-generator-resource.js +259 -0
- package/src/server/semantic-layer-generator-skin.js +41 -171
- package/src/server/semantic-layer-generator.js +122 -14
- package/src/server/shape-generator.js +108 -0
- package/src/server/start.js +17 -3
- package/src/server/valkey.js +141 -235
- 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 -68
- package/jsdoc.json +0 -68
- package/src/api/object-layer/README.md +0 -672
- package/src/client/components/core/ColorPalette.js +0 -5267
- package/src/client/components/core/JoyStick.js +0 -80
- package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
- package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -62
- package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
- package/src/client/components/default/RoutesDefault.js +0 -49
- package/src/client/components/itemledger/RoutesItemledger.js +0 -40
- 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/grpc/cyberia/OFF_CHAIN_ECONOMY.md +0 -305
- package/src/grpc/cyberia/README.md +0 -326
package/bin/cyberia.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import dotenv from 'dotenv';
|
|
17
17
|
import { Command } from 'commander';
|
|
18
18
|
import fs from 'fs-extra';
|
|
19
|
+
import stringify from 'fast-json-stable-stringify';
|
|
19
20
|
import { shellExec } from '../src/server/process.js';
|
|
20
21
|
import { loggerFactory } from '../src/server/logger.js';
|
|
21
22
|
import { generateBesuManifests, deployBesu, removeBesu } from '../src/server/besu-genesis-generator.js';
|
|
@@ -28,24 +29,22 @@ import {
|
|
|
28
29
|
getKeyFramesDirectionsFromNumberFolderDirection,
|
|
29
30
|
buildImgFromTile,
|
|
30
31
|
} from '../src/server/object-layer.js';
|
|
31
|
-
import { ITEM_TYPES as itemTypes } from '../src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js';
|
|
32
32
|
import { AtlasSpriteSheetGenerator } from '../src/server/atlas-sprite-sheet-generator.js';
|
|
33
|
-
import {
|
|
34
|
-
generateFrame,
|
|
35
|
-
generateMultiFrame,
|
|
36
|
-
lookupSemantic,
|
|
37
|
-
semanticRegistry,
|
|
38
|
-
} from '../src/server/semantic-layer-generator.js';
|
|
33
|
+
import { generateMultiFrame, lookupSemantic, semanticRegistry } from '../src/server/semantic-layer-generator.js';
|
|
39
34
|
import { IpfsClient } from '../src/server/ipfs-client.js';
|
|
40
35
|
import { createPinRecord } from '../src/api/ipfs/ipfs.service.js';
|
|
41
36
|
import { program as underpostProgram } from '../src/cli/index.js';
|
|
42
37
|
import crypto from 'crypto';
|
|
43
38
|
import nodePath from 'path';
|
|
44
39
|
import Underpost from '../src/index.js';
|
|
40
|
+
import { newInstance } from '../src/client/components/core/CommonJs.js';
|
|
45
41
|
import {
|
|
42
|
+
ITEM_TYPES as itemTypes,
|
|
46
43
|
DefaultCyberiaItems,
|
|
47
44
|
DefaultSkillConfig,
|
|
48
45
|
DefaultCyberiaDialogues,
|
|
46
|
+
DefaultCyberiaActions,
|
|
47
|
+
DefaultCyberiaQuests,
|
|
49
48
|
} from '../src/client/components/cyberia-portal/CommonCyberiaPortal.js';
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -1705,7 +1704,11 @@ try {
|
|
|
1705
1704
|
.command('instance [instance-code]')
|
|
1706
1705
|
.option('--export [path]', 'Export instance and related documents to a backup directory')
|
|
1707
1706
|
.option('--import [path]', 'Import instance and related documents from a backup directory (preserveUUID, upsert)')
|
|
1708
|
-
.option(
|
|
1707
|
+
.option(
|
|
1708
|
+
'--conf',
|
|
1709
|
+
'When used with --export or --import, only process cyberia-instance.json and cyberia-instance-conf.json',
|
|
1710
|
+
)
|
|
1711
|
+
.option('--drop', 'Drop all documents associated with the instance code before importing or as a standalone action')
|
|
1709
1712
|
.option('--env-path <env-path>', 'Env path e.g. ./engine-private/conf/dd-cyberia/.env.development')
|
|
1710
1713
|
.option('--mongo-host <mongo-host>', 'Mongo host override')
|
|
1711
1714
|
.option('--dev', 'Force development environment')
|
|
@@ -1749,6 +1752,8 @@ try {
|
|
|
1749
1752
|
await DataBaseProvider.load({
|
|
1750
1753
|
apis: [
|
|
1751
1754
|
'cyberia-instance',
|
|
1755
|
+
'cyberia-instance-conf',
|
|
1756
|
+
'cyberia-dialogue',
|
|
1752
1757
|
'cyberia-map',
|
|
1753
1758
|
'cyberia-entity',
|
|
1754
1759
|
'object-layer',
|
|
@@ -1764,6 +1769,8 @@ try {
|
|
|
1764
1769
|
|
|
1765
1770
|
const dbModels = DataBaseProvider.instance[`${host}${path}`].mongoose.models;
|
|
1766
1771
|
const CyberiaInstance = dbModels.CyberiaInstance;
|
|
1772
|
+
const CyberiaInstanceConf = dbModels.CyberiaInstanceConf;
|
|
1773
|
+
const CyberiaDialogue = dbModels.CyberiaDialogue;
|
|
1767
1774
|
const CyberiaMap = dbModels.CyberiaMap;
|
|
1768
1775
|
const ObjectLayer = dbModels.ObjectLayer;
|
|
1769
1776
|
const ObjectLayerRenderFrames = dbModels.ObjectLayerRenderFrames;
|
|
@@ -1771,6 +1778,134 @@ try {
|
|
|
1771
1778
|
const File = dbModels.File;
|
|
1772
1779
|
const Ipfs = dbModels.Ipfs;
|
|
1773
1780
|
|
|
1781
|
+
const toBuffer = (value) => {
|
|
1782
|
+
if (!value) return null;
|
|
1783
|
+
if (Buffer.isBuffer(value)) return value;
|
|
1784
|
+
if (value.type === 'Buffer' && Array.isArray(value.data)) return Buffer.from(value.data);
|
|
1785
|
+
if (value.buffer) return Buffer.from(value.buffer);
|
|
1786
|
+
return Buffer.from(value);
|
|
1787
|
+
};
|
|
1788
|
+
|
|
1789
|
+
const getCanonicalIpfsPaths = (itemKey) => ({
|
|
1790
|
+
objectLayerData: `/object-layer/${itemKey}/${itemKey}_data.json`,
|
|
1791
|
+
atlasSpriteSheet: `/object-layer/${itemKey}/${itemKey}_atlas_sprite_sheet.png`,
|
|
1792
|
+
atlasMetadata: `/object-layer/${itemKey}/${itemKey}_atlas_sprite_sheet_metadata.json`,
|
|
1793
|
+
});
|
|
1794
|
+
|
|
1795
|
+
const collectMfsPaths = (doc = {}) => {
|
|
1796
|
+
const paths = new Set();
|
|
1797
|
+
if (doc.mfsPath) paths.add(doc.mfsPath);
|
|
1798
|
+
for (const p of doc.mfsPaths || []) {
|
|
1799
|
+
if (p) paths.add(p);
|
|
1800
|
+
}
|
|
1801
|
+
return [...paths];
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
const inferResourceType = (doc = {}) => {
|
|
1805
|
+
if (doc.resourceType) return doc.resourceType;
|
|
1806
|
+
for (const path of collectMfsPaths(doc)) {
|
|
1807
|
+
if (path.endsWith('_atlas_sprite_sheet.png')) return 'atlas-sprite-sheet';
|
|
1808
|
+
if (path.endsWith('_atlas_sprite_sheet_metadata.json')) return 'atlas-metadata';
|
|
1809
|
+
if (path.endsWith('_data.json')) return 'object-layer-data';
|
|
1810
|
+
}
|
|
1811
|
+
return null;
|
|
1812
|
+
};
|
|
1813
|
+
|
|
1814
|
+
const findInstanceRelatedIpfsDoc = (ipfsDocs, { linkedCid, resourceType, mfsPath }) =>
|
|
1815
|
+
ipfsDocs.find(
|
|
1816
|
+
(doc) =>
|
|
1817
|
+
inferResourceType(doc) === resourceType &&
|
|
1818
|
+
linkedCid &&
|
|
1819
|
+
doc.cid === linkedCid &&
|
|
1820
|
+
collectMfsPaths(doc).includes(mfsPath),
|
|
1821
|
+
) ||
|
|
1822
|
+
ipfsDocs.find((doc) => inferResourceType(doc) === resourceType && linkedCid && doc.cid === linkedCid) ||
|
|
1823
|
+
ipfsDocs.find((doc) => inferResourceType(doc) === resourceType && collectMfsPaths(doc).includes(mfsPath)) ||
|
|
1824
|
+
null;
|
|
1825
|
+
|
|
1826
|
+
const upsertCanonicalPinEntry = (pinMap, { cid, resourceType, mfsPath = '' }) => {
|
|
1827
|
+
if (!cid || !resourceType) return;
|
|
1828
|
+
const key = `${resourceType}:${cid}`;
|
|
1829
|
+
const nextPath = mfsPath || '';
|
|
1830
|
+
if (!pinMap.has(key)) {
|
|
1831
|
+
pinMap.set(key, {
|
|
1832
|
+
cid,
|
|
1833
|
+
resourceType,
|
|
1834
|
+
mfsPath: nextPath,
|
|
1835
|
+
mfsPaths: nextPath ? [nextPath] : [],
|
|
1836
|
+
});
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
const existing = pinMap.get(key);
|
|
1841
|
+
if (nextPath && !existing.mfsPaths.includes(nextPath)) {
|
|
1842
|
+
existing.mfsPaths.push(nextPath);
|
|
1843
|
+
}
|
|
1844
|
+
if (!existing.mfsPath && nextPath) {
|
|
1845
|
+
existing.mfsPath = nextPath;
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
const serialiseCanonicalPins = (pinMap) =>
|
|
1850
|
+
[...pinMap.values()].map((entry) => ({
|
|
1851
|
+
cid: entry.cid,
|
|
1852
|
+
resourceType: entry.resourceType,
|
|
1853
|
+
...(entry.mfsPath ? { mfsPath: entry.mfsPath } : {}),
|
|
1854
|
+
...(entry.mfsPaths.length ? { mfsPaths: entry.mfsPaths } : {}),
|
|
1855
|
+
}));
|
|
1856
|
+
|
|
1857
|
+
const getDefaultDialoguesByItemId = (itemIds = []) => {
|
|
1858
|
+
const requestedItemIds = new Set(itemIds.filter(Boolean));
|
|
1859
|
+
const defaultsByItemId = new Map();
|
|
1860
|
+
|
|
1861
|
+
for (const dialogue of DefaultCyberiaDialogues) {
|
|
1862
|
+
// Match by code prefix: "default-<itemId>" covers the common case;
|
|
1863
|
+
// callers may also pass a full code directly.
|
|
1864
|
+
const matchingIds = [...requestedItemIds].filter(
|
|
1865
|
+
(id) => dialogue.code === `default-${id}` || dialogue.code === id,
|
|
1866
|
+
);
|
|
1867
|
+
if (!matchingIds.length) continue;
|
|
1868
|
+
for (const id of matchingIds) {
|
|
1869
|
+
if (!defaultsByItemId.has(id)) defaultsByItemId.set(id, []);
|
|
1870
|
+
defaultsByItemId.get(id).push({
|
|
1871
|
+
code: dialogue.code,
|
|
1872
|
+
order: dialogue.order ?? 0,
|
|
1873
|
+
speaker: dialogue.speaker ?? '',
|
|
1874
|
+
text: dialogue.text,
|
|
1875
|
+
mood: dialogue.mood ?? 'neutral',
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
for (const dialogues of defaultsByItemId.values()) {
|
|
1881
|
+
dialogues.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
return defaultsByItemId;
|
|
1885
|
+
};
|
|
1886
|
+
|
|
1887
|
+
const rewriteImportedCidReferences = async ({ oldCid, newCid, resourceType }) => {
|
|
1888
|
+
if (!oldCid || !newCid || oldCid === newCid) return;
|
|
1889
|
+
|
|
1890
|
+
if (resourceType === 'object-layer-data') {
|
|
1891
|
+
await ObjectLayer.updateMany({ cid: oldCid }, { $set: { cid: newCid } });
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
if (resourceType === 'atlas-sprite-sheet') {
|
|
1896
|
+
await AtlasSpriteSheet.updateMany({ cid: oldCid }, { $set: { cid: newCid } });
|
|
1897
|
+
await ObjectLayer.updateMany({ 'data.render.cid': oldCid }, { $set: { 'data.render.cid': newCid } });
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
if (resourceType === 'atlas-metadata') {
|
|
1902
|
+
await ObjectLayer.updateMany(
|
|
1903
|
+
{ 'data.render.metadataCid': oldCid },
|
|
1904
|
+
{ $set: { 'data.render.metadataCid': newCid } },
|
|
1905
|
+
);
|
|
1906
|
+
}
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1774
1909
|
// ── EXPORT ──────────────────────────────────────────────────────
|
|
1775
1910
|
if (options.export !== undefined) {
|
|
1776
1911
|
const instance = await CyberiaInstance.findOne({ code: instanceCode }).lean();
|
|
@@ -1788,13 +1923,12 @@ try {
|
|
|
1788
1923
|
fs.ensureDirSync(backupDir);
|
|
1789
1924
|
logger.info('Exporting instance', { code: instanceCode, backupDir });
|
|
1790
1925
|
|
|
1791
|
-
fs.ensureDirSync(`${backupDir}/files`);
|
|
1792
|
-
|
|
1793
1926
|
// Helper: export a File document to the files/ directory
|
|
1794
1927
|
const exportFileDoc = async (fileId, fileKey) => {
|
|
1795
1928
|
if (!fileId) return;
|
|
1796
1929
|
const file = await File.findById(fileId).lean();
|
|
1797
1930
|
if (!file) return;
|
|
1931
|
+
fs.ensureDirSync(`${backupDir}/files`);
|
|
1798
1932
|
const fileExport = { ...file };
|
|
1799
1933
|
// Handle both Node.js Buffer and BSON Binary types from .lean()
|
|
1800
1934
|
if (fileExport.data) {
|
|
@@ -1808,11 +1942,46 @@ try {
|
|
|
1808
1942
|
|
|
1809
1943
|
// 1. Save instance document + thumbnail
|
|
1810
1944
|
fs.writeJsonSync(`${backupDir}/cyberia-instance.json`, instance, { spaces: 2 });
|
|
1811
|
-
if (instance.thumbnail) {
|
|
1945
|
+
if (!options.conf && instance.thumbnail) {
|
|
1812
1946
|
await exportFileDoc(instance.thumbnail, `thumb-instance-${instanceCode}`);
|
|
1813
1947
|
}
|
|
1814
1948
|
logger.info('Exported CyberiaInstance', { code: instanceCode });
|
|
1815
1949
|
|
|
1950
|
+
// 1b. Export linked CyberiaInstanceConf (skillRules, equipmentRules, entityDefaults, etc.)
|
|
1951
|
+
// If no conf doc exists yet (instance created before auto-upsert logic), create one using
|
|
1952
|
+
// schema defaults — identical to the behaviour in CyberiaInstanceService.post().
|
|
1953
|
+
let instanceConf =
|
|
1954
|
+
(await CyberiaInstanceConf.findOne({ instanceCode }).lean()) ||
|
|
1955
|
+
(instance.conf ? await CyberiaInstanceConf.findById(instance.conf).lean() : null);
|
|
1956
|
+
if (!instanceConf) {
|
|
1957
|
+
logger.info('No CyberiaInstanceConf found — creating default', { instanceCode });
|
|
1958
|
+
const created = await CyberiaInstanceConf.findOneAndUpdate(
|
|
1959
|
+
{ instanceCode },
|
|
1960
|
+
{ $setOnInsert: { instanceCode } },
|
|
1961
|
+
{ upsert: true, returnDocument: 'after' },
|
|
1962
|
+
);
|
|
1963
|
+
// Back-fill the instance.conf ref if it was missing
|
|
1964
|
+
if (created && !instance.conf) {
|
|
1965
|
+
await CyberiaInstance.findByIdAndUpdate(instance._id, { conf: created._id });
|
|
1966
|
+
}
|
|
1967
|
+
instanceConf = created?.toObject ? created.toObject() : created;
|
|
1968
|
+
}
|
|
1969
|
+
if (instanceConf) {
|
|
1970
|
+
fs.writeJsonSync(`${backupDir}/cyberia-instance-conf.json`, instanceConf, { spaces: 2 });
|
|
1971
|
+
logger.info('Exported CyberiaInstanceConf', { instanceCode });
|
|
1972
|
+
} else {
|
|
1973
|
+
logger.warn('Could not create or find CyberiaInstanceConf', { instanceCode });
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
if (options.conf) {
|
|
1977
|
+
logger.info('Instance export completed in --conf mode', {
|
|
1978
|
+
backupDir,
|
|
1979
|
+
exportedFiles: ['cyberia-instance.json', 'cyberia-instance-conf.json'],
|
|
1980
|
+
});
|
|
1981
|
+
await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1816
1985
|
// 2. Collect all map codes (instance maps + portal targets)
|
|
1817
1986
|
const mapCodes = new Set(instance.cyberiaMapCodes || []);
|
|
1818
1987
|
for (const portal of instance.portals || []) {
|
|
@@ -1841,6 +2010,100 @@ try {
|
|
|
1841
2010
|
}
|
|
1842
2011
|
}
|
|
1843
2012
|
|
|
2013
|
+
// 4b. Add instance-level itemIds
|
|
2014
|
+
for (const id of instance.itemIds || []) {
|
|
2015
|
+
if (id) objectLayerItemIds.add(id);
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
// 4c. Add all itemIds referenced by CyberiaInstanceConf (entityDefaults + skillConfig).
|
|
2019
|
+
// This ensures liveItemIds, deadItemIds, dropItemIds, defaultObjectLayers and
|
|
2020
|
+
// skill trigger items are included even if no map entity currently uses them.
|
|
2021
|
+
if (instanceConf) {
|
|
2022
|
+
for (const ed of instanceConf.entityDefaults || []) {
|
|
2023
|
+
for (const id of ed.liveItemIds || []) if (id) objectLayerItemIds.add(id);
|
|
2024
|
+
for (const id of ed.deadItemIds || []) if (id) objectLayerItemIds.add(id);
|
|
2025
|
+
for (const id of ed.dropItemIds || []) if (id) objectLayerItemIds.add(id);
|
|
2026
|
+
for (const slot of ed.defaultObjectLayers || []) {
|
|
2027
|
+
if (slot.itemId) objectLayerItemIds.add(slot.itemId);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
for (const sc of instanceConf.skillConfig || []) {
|
|
2031
|
+
if (sc.triggerItemId) objectLayerItemIds.add(sc.triggerItemId);
|
|
2032
|
+
for (const skill of sc.skills || []) {
|
|
2033
|
+
if (skill.summonedEntityItemId && !skill.summonedEntityItemId.startsWith('$')) {
|
|
2034
|
+
objectLayerItemIds.add(skill.summonedEntityItemId);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// 4d. Export dialogues for all relevant object-layer items. Codes follow the pattern
|
|
2041
|
+
// "default-<itemId>". If an item has no dialogue docs yet but ships with
|
|
2042
|
+
// DefaultCyberiaDialogues, seed those defaults into Mongo first.
|
|
2043
|
+
if (objectLayerItemIds.size > 0) {
|
|
2044
|
+
const requestedItemIds = [...objectLayerItemIds];
|
|
2045
|
+
const requestedCodes = requestedItemIds.map((id) => `default-${id}`);
|
|
2046
|
+
const defaultDialoguesByItemId = getDefaultDialoguesByItemId(requestedItemIds);
|
|
2047
|
+
const existingDialogueDocs = await CyberiaDialogue.find({
|
|
2048
|
+
code: { $in: requestedCodes },
|
|
2049
|
+
})
|
|
2050
|
+
.sort({ code: 1, order: 1 })
|
|
2051
|
+
.lean();
|
|
2052
|
+
|
|
2053
|
+
const existingDialogueCodes = new Set(existingDialogueDocs.map((dialogue) => dialogue.code).filter(Boolean));
|
|
2054
|
+
let seededDialogueCount = 0;
|
|
2055
|
+
|
|
2056
|
+
for (const [itemId, dialogues] of defaultDialoguesByItemId.entries()) {
|
|
2057
|
+
const firstCode = dialogues[0]?.code;
|
|
2058
|
+
if (firstCode && existingDialogueCodes.has(firstCode)) continue;
|
|
2059
|
+
|
|
2060
|
+
for (const dialogue of dialogues) {
|
|
2061
|
+
await CyberiaDialogue.findOneAndUpdate(
|
|
2062
|
+
{ code: dialogue.code, order: dialogue.order },
|
|
2063
|
+
{
|
|
2064
|
+
$set: {
|
|
2065
|
+
speaker: dialogue.speaker,
|
|
2066
|
+
text: dialogue.text,
|
|
2067
|
+
mood: dialogue.mood,
|
|
2068
|
+
},
|
|
2069
|
+
},
|
|
2070
|
+
{ upsert: true },
|
|
2071
|
+
);
|
|
2072
|
+
seededDialogueCount++;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
const dialogueDocs = await CyberiaDialogue.find({ code: { $in: requestedCodes } })
|
|
2077
|
+
.sort({ code: 1, order: 1 })
|
|
2078
|
+
.lean();
|
|
2079
|
+
|
|
2080
|
+
if (seededDialogueCount > 0) {
|
|
2081
|
+
logger.info(`Seeded ${seededDialogueCount} CyberiaDialogue default record(s) for export`);
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
if (dialogueDocs.length > 0) {
|
|
2085
|
+
fs.ensureDirSync(`${backupDir}/cyberia-dialogues`);
|
|
2086
|
+
const dialoguesByCode = new Map();
|
|
2087
|
+
|
|
2088
|
+
for (const dialogue of dialogueDocs) {
|
|
2089
|
+
if (!dialoguesByCode.has(dialogue.code)) {
|
|
2090
|
+
dialoguesByCode.set(dialogue.code, []);
|
|
2091
|
+
}
|
|
2092
|
+
dialoguesByCode.get(dialogue.code).push(dialogue);
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
for (const [code, dialogues] of dialoguesByCode.entries()) {
|
|
2096
|
+
fs.writeJsonSync(`${backupDir}/cyberia-dialogues/${encodeURIComponent(code)}.json`, dialogues, {
|
|
2097
|
+
spaces: 2,
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
logger.info(`Exported ${dialogueDocs.length} CyberiaDialogue document(s)`, {
|
|
2102
|
+
codes: [...dialoguesByCode.keys()],
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
|
|
1844
2107
|
// 5. Export object layers with related render frames, atlas, files, and IPFS records
|
|
1845
2108
|
if (objectLayerItemIds.size > 0) {
|
|
1846
2109
|
const objectLayers = await ObjectLayer.find({
|
|
@@ -1851,48 +2114,245 @@ try {
|
|
|
1851
2114
|
fs.ensureDirSync(`${backupDir}/render-frames`);
|
|
1852
2115
|
fs.ensureDirSync(`${backupDir}/atlas-sprite-sheets`);
|
|
1853
2116
|
fs.ensureDirSync(`${backupDir}/ipfs`);
|
|
2117
|
+
fs.ensureDirSync(`${backupDir}/ipfs/content`);
|
|
2118
|
+
|
|
2119
|
+
const canonicalPins = new Map();
|
|
2120
|
+
const expectedObjectLayerIpfsRefs = [];
|
|
2121
|
+
const ipfsPayloadFailures = [];
|
|
2122
|
+
let ipfsPayloadExportCount = 0;
|
|
2123
|
+
let ipfsPayloadAliasCount = 0;
|
|
2124
|
+
|
|
2125
|
+
const writeBackupPayload = (cid, payloadBuffer) => {
|
|
2126
|
+
if (!cid) return false;
|
|
2127
|
+
const payloadPath = `${backupDir}/ipfs/content/${cid}.bin`;
|
|
2128
|
+
if (fs.existsSync(payloadPath)) return false;
|
|
2129
|
+
fs.writeFileSync(payloadPath, payloadBuffer);
|
|
2130
|
+
ipfsPayloadExportCount++;
|
|
2131
|
+
return true;
|
|
2132
|
+
};
|
|
2133
|
+
|
|
2134
|
+
const writeBackupPayloadAlias = ({ canonicalCid, linkedCid, payloadBuffer }) => {
|
|
2135
|
+
if (!linkedCid || linkedCid === canonicalCid) return;
|
|
2136
|
+
if (writeBackupPayload(linkedCid, payloadBuffer)) {
|
|
2137
|
+
ipfsPayloadAliasCount++;
|
|
2138
|
+
}
|
|
2139
|
+
};
|
|
2140
|
+
|
|
2141
|
+
const exportCanonicalPayload = async ({ payloadBuffer, resourceType, mfsPath, filename, itemKey }) => {
|
|
2142
|
+
const hashResult = await IpfsClient.hashBufferForIpfs(payloadBuffer, filename);
|
|
2143
|
+
if (!hashResult?.cid) {
|
|
2144
|
+
ipfsPayloadFailures.push({ itemKey, resourceType, mfsPath, reason: 'Failed to hash payload via Kubo' });
|
|
2145
|
+
return null;
|
|
2146
|
+
}
|
|
1854
2147
|
|
|
1855
|
-
|
|
2148
|
+
writeBackupPayload(hashResult.cid, payloadBuffer);
|
|
2149
|
+
return hashResult.cid;
|
|
2150
|
+
};
|
|
1856
2151
|
|
|
1857
2152
|
for (const ol of objectLayers) {
|
|
1858
|
-
const
|
|
1859
|
-
|
|
2153
|
+
const itemKey = ol.data?.item?.id || ol._id.toString();
|
|
2154
|
+
const itemPaths = getCanonicalIpfsPaths(itemKey);
|
|
2155
|
+
const objectLayerExport = newInstance(ol);
|
|
2156
|
+
|
|
2157
|
+
if (!objectLayerExport.data.render) {
|
|
2158
|
+
objectLayerExport.data.render = {};
|
|
2159
|
+
}
|
|
1860
2160
|
|
|
1861
2161
|
// Export ObjectLayerRenderFrames
|
|
1862
2162
|
if (ol.objectLayerRenderFramesId) {
|
|
1863
2163
|
const rf = await ObjectLayerRenderFrames.findById(ol.objectLayerRenderFramesId).lean();
|
|
1864
2164
|
if (rf) {
|
|
1865
|
-
fs.writeJsonSync(`${backupDir}/render-frames/${
|
|
2165
|
+
fs.writeJsonSync(`${backupDir}/render-frames/${itemKey}.json`, rf, { spaces: 2 });
|
|
1866
2166
|
}
|
|
1867
2167
|
}
|
|
1868
2168
|
|
|
1869
|
-
// Export AtlasSpriteSheet + its File
|
|
2169
|
+
// Export AtlasSpriteSheet + its File using canonical payload bytes from the DB state.
|
|
1870
2170
|
if (ol.atlasSpriteSheetId) {
|
|
1871
2171
|
const atlas = await AtlasSpriteSheet.findById(ol.atlasSpriteSheetId).lean();
|
|
1872
|
-
if (atlas) {
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
2172
|
+
if (!atlas) {
|
|
2173
|
+
ipfsPayloadFailures.push({
|
|
2174
|
+
itemKey,
|
|
2175
|
+
resourceType: 'atlas-sprite-sheet',
|
|
2176
|
+
mfsPath: itemPaths.atlasSpriteSheet,
|
|
2177
|
+
reason: 'AtlasSpriteSheet document not found in MongoDB',
|
|
2178
|
+
});
|
|
2179
|
+
continue;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
const atlasExport = newInstance(atlas);
|
|
2183
|
+
if (atlas.fileId) {
|
|
2184
|
+
await exportFileDoc(atlas.fileId, `atlas-${itemKey}`);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
const atlasFile = atlas.fileId ? await File.findById(atlas.fileId).lean() : null;
|
|
2188
|
+
const atlasBuffer = toBuffer(atlasFile?.data);
|
|
2189
|
+
if (!atlasBuffer) {
|
|
2190
|
+
ipfsPayloadFailures.push({
|
|
2191
|
+
itemKey,
|
|
2192
|
+
resourceType: 'atlas-sprite-sheet',
|
|
2193
|
+
mfsPath: itemPaths.atlasSpriteSheet,
|
|
2194
|
+
reason: 'Atlas File payload not found in MongoDB',
|
|
2195
|
+
});
|
|
2196
|
+
continue;
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
const atlasCid = await exportCanonicalPayload({
|
|
2200
|
+
payloadBuffer: atlasBuffer,
|
|
2201
|
+
resourceType: 'atlas-sprite-sheet',
|
|
2202
|
+
mfsPath: itemPaths.atlasSpriteSheet,
|
|
2203
|
+
filename: `${itemKey}_atlas_sprite_sheet.png`,
|
|
2204
|
+
itemKey,
|
|
2205
|
+
});
|
|
2206
|
+
if (!atlasCid) continue;
|
|
2207
|
+
|
|
2208
|
+
const linkedAtlasCid = atlas.cid || ol.data?.render?.cid || atlasCid;
|
|
2209
|
+
writeBackupPayloadAlias({
|
|
2210
|
+
canonicalCid: atlasCid,
|
|
2211
|
+
linkedCid: linkedAtlasCid,
|
|
2212
|
+
payloadBuffer: atlasBuffer,
|
|
2213
|
+
});
|
|
2214
|
+
expectedObjectLayerIpfsRefs.push({
|
|
2215
|
+
itemKey,
|
|
2216
|
+
resourceType: 'atlas-sprite-sheet',
|
|
2217
|
+
mfsPath: itemPaths.atlasSpriteSheet,
|
|
2218
|
+
linkedCid: linkedAtlasCid,
|
|
2219
|
+
fallbackCid: atlasCid,
|
|
2220
|
+
});
|
|
2221
|
+
|
|
2222
|
+
const atlasMetadataBuffer = Buffer.from(stringify(atlasExport.metadata || {}), 'utf-8');
|
|
2223
|
+
const atlasMetadataCid = await exportCanonicalPayload({
|
|
2224
|
+
payloadBuffer: atlasMetadataBuffer,
|
|
2225
|
+
resourceType: 'atlas-metadata',
|
|
2226
|
+
mfsPath: itemPaths.atlasMetadata,
|
|
2227
|
+
filename: `${itemKey}_atlas_sprite_sheet_metadata.json`,
|
|
2228
|
+
itemKey,
|
|
2229
|
+
});
|
|
2230
|
+
if (!atlasMetadataCid) continue;
|
|
2231
|
+
|
|
2232
|
+
const linkedAtlasMetadataCid = ol.data?.render?.metadataCid || atlasMetadataCid;
|
|
2233
|
+
writeBackupPayloadAlias({
|
|
2234
|
+
canonicalCid: atlasMetadataCid,
|
|
2235
|
+
linkedCid: linkedAtlasMetadataCid,
|
|
2236
|
+
payloadBuffer: atlasMetadataBuffer,
|
|
2237
|
+
});
|
|
2238
|
+
expectedObjectLayerIpfsRefs.push({
|
|
2239
|
+
itemKey,
|
|
2240
|
+
resourceType: 'atlas-metadata',
|
|
2241
|
+
mfsPath: itemPaths.atlasMetadata,
|
|
2242
|
+
linkedCid: linkedAtlasMetadataCid,
|
|
2243
|
+
fallbackCid: atlasMetadataCid,
|
|
2244
|
+
});
|
|
2245
|
+
|
|
2246
|
+
atlasExport.cid = atlasCid;
|
|
2247
|
+
objectLayerExport.data.render.cid = atlasCid;
|
|
2248
|
+
objectLayerExport.data.render.metadataCid = atlasMetadataCid;
|
|
2249
|
+
fs.writeJsonSync(`${backupDir}/atlas-sprite-sheets/${itemKey}.json`, atlasExport, { spaces: 2 });
|
|
2250
|
+
} else {
|
|
2251
|
+
if (objectLayerExport.data.render?.cid || objectLayerExport.data.render?.metadataCid) {
|
|
2252
|
+
ipfsPayloadFailures.push({
|
|
2253
|
+
itemKey,
|
|
2254
|
+
resourceType: 'atlas-sprite-sheet',
|
|
2255
|
+
mfsPath: itemPaths.atlasSpriteSheet,
|
|
2256
|
+
reason: 'ObjectLayer references atlas CIDs but no AtlasSpriteSheet document exists',
|
|
2257
|
+
});
|
|
2258
|
+
continue;
|
|
1878
2259
|
}
|
|
2260
|
+
delete objectLayerExport.data.render.cid;
|
|
2261
|
+
delete objectLayerExport.data.render.metadataCid;
|
|
1879
2262
|
}
|
|
1880
2263
|
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
2264
|
+
const objectLayerBuffer = Buffer.from(stringify(objectLayerExport.data || {}), 'utf-8');
|
|
2265
|
+
const objectLayerCid = await exportCanonicalPayload({
|
|
2266
|
+
payloadBuffer: objectLayerBuffer,
|
|
2267
|
+
resourceType: 'object-layer-data',
|
|
2268
|
+
mfsPath: itemPaths.objectLayerData,
|
|
2269
|
+
filename: `${itemKey}_data.json`,
|
|
2270
|
+
itemKey,
|
|
2271
|
+
});
|
|
2272
|
+
if (!objectLayerCid) continue;
|
|
2273
|
+
|
|
2274
|
+
const linkedObjectLayerCid = ol.cid || objectLayerCid;
|
|
2275
|
+
writeBackupPayloadAlias({
|
|
2276
|
+
canonicalCid: objectLayerCid,
|
|
2277
|
+
linkedCid: linkedObjectLayerCid,
|
|
2278
|
+
payloadBuffer: objectLayerBuffer,
|
|
2279
|
+
});
|
|
2280
|
+
expectedObjectLayerIpfsRefs.push({
|
|
2281
|
+
itemKey,
|
|
2282
|
+
resourceType: 'object-layer-data',
|
|
2283
|
+
mfsPath: itemPaths.objectLayerData,
|
|
2284
|
+
linkedCid: linkedObjectLayerCid,
|
|
2285
|
+
fallbackCid: objectLayerCid,
|
|
2286
|
+
});
|
|
2287
|
+
|
|
2288
|
+
objectLayerExport.cid = objectLayerCid;
|
|
2289
|
+
fs.writeJsonSync(`${backupDir}/object-layers/${itemKey}.json`, objectLayerExport, { spaces: 2 });
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
if (ipfsPayloadFailures.length > 0) {
|
|
2293
|
+
for (const failure of ipfsPayloadFailures) {
|
|
2294
|
+
logger.error('Canonical IPFS payload export failed', failure);
|
|
2295
|
+
}
|
|
2296
|
+
await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
2297
|
+
process.exit(1);
|
|
1885
2298
|
}
|
|
1886
2299
|
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
2300
|
+
const relatedPinPaths = [
|
|
2301
|
+
...new Set(expectedObjectLayerIpfsRefs.map((entry) => entry.mfsPath).filter(Boolean)),
|
|
2302
|
+
];
|
|
2303
|
+
const relatedPinCids = [
|
|
2304
|
+
...new Set(
|
|
2305
|
+
expectedObjectLayerIpfsRefs.flatMap((entry) => [entry.linkedCid, entry.fallbackCid]).filter(Boolean),
|
|
2306
|
+
),
|
|
2307
|
+
];
|
|
2308
|
+
const relatedIpfsDocs =
|
|
2309
|
+
relatedPinPaths.length > 0 || relatedPinCids.length > 0
|
|
2310
|
+
? await Ipfs.find({
|
|
2311
|
+
$or: [
|
|
2312
|
+
...(relatedPinPaths.length ? [{ mfsPath: { $in: relatedPinPaths } }] : []),
|
|
2313
|
+
...(relatedPinPaths.length ? [{ mfsPaths: { $in: relatedPinPaths } }] : []),
|
|
2314
|
+
...(relatedPinCids.length ? [{ cid: { $in: relatedPinCids } }] : []),
|
|
2315
|
+
],
|
|
2316
|
+
}).lean()
|
|
2317
|
+
: [];
|
|
2318
|
+
|
|
2319
|
+
let ipfsCollectionMatchCount = 0;
|
|
2320
|
+
let ipfsCollectionFallbackCount = 0;
|
|
2321
|
+
|
|
2322
|
+
for (const ref of expectedObjectLayerIpfsRefs) {
|
|
2323
|
+
const matchingDoc = findInstanceRelatedIpfsDoc(relatedIpfsDocs, ref);
|
|
2324
|
+
const exportCid = matchingDoc?.cid || ref.linkedCid || ref.fallbackCid;
|
|
2325
|
+
|
|
2326
|
+
if (!exportCid) {
|
|
2327
|
+
logger.warn('Skipping instance IPFS pin export because the ObjectLayer ref has no linked CID', {
|
|
2328
|
+
itemKey: ref.itemKey,
|
|
2329
|
+
resourceType: ref.resourceType,
|
|
2330
|
+
mfsPath: ref.mfsPath,
|
|
2331
|
+
});
|
|
2332
|
+
continue;
|
|
1893
2333
|
}
|
|
2334
|
+
|
|
2335
|
+
upsertCanonicalPinEntry(canonicalPins, {
|
|
2336
|
+
cid: exportCid,
|
|
2337
|
+
resourceType: ref.resourceType,
|
|
2338
|
+
mfsPath: ref.mfsPath,
|
|
2339
|
+
});
|
|
2340
|
+
|
|
2341
|
+
if (matchingDoc) ipfsCollectionMatchCount++;
|
|
2342
|
+
else ipfsCollectionFallbackCount++;
|
|
1894
2343
|
}
|
|
1895
2344
|
|
|
2345
|
+
const sanitised = serialiseCanonicalPins(canonicalPins);
|
|
2346
|
+
fs.writeJsonSync(`${backupDir}/ipfs/pins.json`, sanitised, { spaces: 2 });
|
|
2347
|
+
logger.info(
|
|
2348
|
+
`Exported ${sanitised.length} instance-related Ipfs pin record(s) and ${ipfsPayloadExportCount} raw payload file(s)`,
|
|
2349
|
+
{
|
|
2350
|
+
matchedFromIpfsCollection: ipfsCollectionMatchCount,
|
|
2351
|
+
fallbackFromObjectLayerRefs: ipfsCollectionFallbackCount,
|
|
2352
|
+
rawPayloadAliases: ipfsPayloadAliasCount,
|
|
2353
|
+
},
|
|
2354
|
+
);
|
|
2355
|
+
|
|
1896
2356
|
logger.info(`Exported ${objectLayers.length} ObjectLayer document(s)`, {
|
|
1897
2357
|
itemIds: [...objectLayerItemIds],
|
|
1898
2358
|
});
|
|
@@ -1919,7 +2379,7 @@ try {
|
|
|
1919
2379
|
logger.info('Importing instance', { code: instanceCode, backupDir });
|
|
1920
2380
|
|
|
1921
2381
|
// 0. Drop existing documents if --drop is set
|
|
1922
|
-
if (options.drop) {
|
|
2382
|
+
if (options.drop && !options.conf) {
|
|
1923
2383
|
const existingInstance = await CyberiaInstance.findOne({ code: instanceCode }).lean();
|
|
1924
2384
|
if (existingInstance) {
|
|
1925
2385
|
const dropMapCodes = new Set(existingInstance.cyberiaMapCodes || []);
|
|
@@ -1931,13 +2391,41 @@ try {
|
|
|
1931
2391
|
// Collect thumbnail File IDs to drop
|
|
1932
2392
|
const thumbFileIds = [];
|
|
1933
2393
|
if (existingInstance.thumbnail) thumbFileIds.push(existingInstance.thumbnail);
|
|
2394
|
+
const dropOlItemIds = new Set();
|
|
1934
2395
|
|
|
1935
2396
|
// Query other instances/maps for shared thumbnail exclusion
|
|
1936
2397
|
const otherInstances = await CyberiaInstance.find({ code: { $ne: instanceCode } }, { thumbnail: 1 }).lean();
|
|
1937
2398
|
|
|
2399
|
+
// Add instance-level itemIds (may not appear in any map entity)
|
|
2400
|
+
for (const id of existingInstance.itemIds || []) if (id) dropOlItemIds.add(id);
|
|
2401
|
+
|
|
2402
|
+
// Add conf entityDefaults and skillConfig itemIds (liveItemIds, deadItemIds, dropItemIds, defaultObjectLayers)
|
|
2403
|
+
const existingConf =
|
|
2404
|
+
(await CyberiaInstanceConf.findOne({ instanceCode }).lean()) ||
|
|
2405
|
+
(existingInstance.conf ? await CyberiaInstanceConf.findById(existingInstance.conf).lean() : null);
|
|
2406
|
+
if (existingConf) {
|
|
2407
|
+
for (const ed of existingConf.entityDefaults || []) {
|
|
2408
|
+
for (const id of ed.liveItemIds || []) if (id) dropOlItemIds.add(id);
|
|
2409
|
+
for (const id of ed.deadItemIds || []) if (id) dropOlItemIds.add(id);
|
|
2410
|
+
for (const id of ed.dropItemIds || []) if (id) dropOlItemIds.add(id);
|
|
2411
|
+
for (const slot of ed.defaultObjectLayers || []) if (slot.itemId) dropOlItemIds.add(slot.itemId);
|
|
2412
|
+
}
|
|
2413
|
+
for (const sc of existingConf.skillConfig || []) {
|
|
2414
|
+
if (sc.triggerItemId) dropOlItemIds.add(sc.triggerItemId);
|
|
2415
|
+
for (const skill of sc.skills || []) {
|
|
2416
|
+
if (skill.summonedEntityItemId && !skill.summonedEntityItemId.startsWith('$'))
|
|
2417
|
+
dropOlItemIds.add(skill.summonedEntityItemId);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
const otherMaps = await CyberiaMap.find(
|
|
2423
|
+
{ code: { $nin: [...dropMapCodes] } },
|
|
2424
|
+
{ 'entities.objectLayerItemIds': 1, thumbnail: 1 },
|
|
2425
|
+
).lean();
|
|
2426
|
+
|
|
1938
2427
|
if (dropMapCodes.size > 0) {
|
|
1939
2428
|
const dropMaps = await CyberiaMap.find({ code: { $in: [...dropMapCodes] } }).lean();
|
|
1940
|
-
const dropOlItemIds = new Set();
|
|
1941
2429
|
for (const map of dropMaps) {
|
|
1942
2430
|
if (map.thumbnail) thumbFileIds.push(map.thumbnail);
|
|
1943
2431
|
for (const entity of map.entities || []) {
|
|
@@ -1947,110 +2435,105 @@ try {
|
|
|
1947
2435
|
}
|
|
1948
2436
|
}
|
|
1949
2437
|
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
{ 'entities.objectLayerItemIds': 1, thumbnail: 1 },
|
|
1954
|
-
).lean();
|
|
1955
|
-
const sharedOlItemIds = new Set();
|
|
1956
|
-
for (const m of otherMaps) {
|
|
1957
|
-
for (const entity of m.entities || []) {
|
|
1958
|
-
for (const itemId of entity.objectLayerItemIds || []) {
|
|
1959
|
-
if (dropOlItemIds.has(itemId)) sharedOlItemIds.add(itemId);
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
for (const shared of sharedOlItemIds) dropOlItemIds.delete(shared);
|
|
1964
|
-
if (sharedOlItemIds.size > 0) {
|
|
1965
|
-
logger.info(`Preserved ${sharedOlItemIds.size} ObjectLayer(s) shared with other maps`);
|
|
1966
|
-
}
|
|
2438
|
+
const mapResult = await CyberiaMap.deleteMany({ code: { $in: [...dropMapCodes] } });
|
|
2439
|
+
logger.info(`Dropped ${mapResult.deletedCount} CyberiaMap document(s)`);
|
|
2440
|
+
}
|
|
1967
2441
|
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
const
|
|
1972
|
-
|
|
1973
|
-
|
|
2442
|
+
// Exclude OL item IDs referenced by maps outside this instance
|
|
2443
|
+
const sharedOlItemIds = new Set();
|
|
2444
|
+
for (const m of otherMaps) {
|
|
2445
|
+
for (const entity of m.entities || []) {
|
|
2446
|
+
for (const itemId of entity.objectLayerItemIds || []) {
|
|
2447
|
+
if (dropOlItemIds.has(itemId)) sharedOlItemIds.add(itemId);
|
|
2448
|
+
}
|
|
1974
2449
|
}
|
|
2450
|
+
}
|
|
2451
|
+
for (const shared of sharedOlItemIds) dropOlItemIds.delete(shared);
|
|
2452
|
+
if (sharedOlItemIds.size > 0) {
|
|
2453
|
+
logger.info(`Preserved ${sharedOlItemIds.size} ObjectLayer(s) shared with other maps`);
|
|
2454
|
+
}
|
|
1975
2455
|
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
'data.render': 1,
|
|
1984
|
-
objectLayerRenderFramesId: 1,
|
|
1985
|
-
atlasSpriteSheetId: 1,
|
|
1986
|
-
},
|
|
1987
|
-
).lean();
|
|
1988
|
-
|
|
1989
|
-
const cidsToUnpin = new Set();
|
|
1990
|
-
const renderFrameIds = [];
|
|
1991
|
-
const atlasIds = [];
|
|
1992
|
-
const itemKeysToClean = new Set();
|
|
1993
|
-
|
|
1994
|
-
for (const doc of olDocs) {
|
|
1995
|
-
if (doc.cid) cidsToUnpin.add(doc.cid);
|
|
1996
|
-
if (doc.data?.render?.cid) cidsToUnpin.add(doc.data.render.cid);
|
|
1997
|
-
if (doc.data?.render?.metadataCid) cidsToUnpin.add(doc.data.render.metadataCid);
|
|
1998
|
-
if (doc.data?.item?.id) itemKeysToClean.add(doc.data.item.id);
|
|
1999
|
-
if (doc.objectLayerRenderFramesId) renderFrameIds.push(doc.objectLayerRenderFramesId);
|
|
2000
|
-
if (doc.atlasSpriteSheetId) atlasIds.push(doc.atlasSpriteSheetId);
|
|
2001
|
-
}
|
|
2456
|
+
// Exclude thumbnail File IDs referenced by other instances or maps
|
|
2457
|
+
const otherMapThumbs = otherMaps.map((m) => m.thumbnail?.toString()).filter(Boolean);
|
|
2458
|
+
const otherInstThumbs = otherInstances.map((i) => i.thumbnail?.toString()).filter(Boolean);
|
|
2459
|
+
const sharedThumbIds = new Set([...otherMapThumbs, ...otherInstThumbs]);
|
|
2460
|
+
for (let i = thumbFileIds.length - 1; i >= 0; i--) {
|
|
2461
|
+
if (sharedThumbIds.has(thumbFileIds[i].toString())) thumbFileIds.splice(i, 1);
|
|
2462
|
+
}
|
|
2002
2463
|
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
const atlasResult = await AtlasSpriteSheet.deleteMany({ _id: { $in: atlasIds } });
|
|
2018
|
-
logger.info(`Dropped ${atlasResult.deletedCount} AtlasSpriteSheet document(s)`);
|
|
2019
|
-
}
|
|
2464
|
+
if (dropOlItemIds.size > 0) {
|
|
2465
|
+
const dropDialogueCodes = [...dropOlItemIds].map((id) => `default-${id}`);
|
|
2466
|
+
const dialogueResult = await CyberiaDialogue.deleteMany({ code: { $in: dropDialogueCodes } });
|
|
2467
|
+
logger.info(`Dropped ${dialogueResult.deletedCount} CyberiaDialogue document(s)`);
|
|
2468
|
+
const olDocs = await ObjectLayer.find(
|
|
2469
|
+
{ 'data.item.id': { $in: [...dropOlItemIds] } },
|
|
2470
|
+
{
|
|
2471
|
+
cid: 1,
|
|
2472
|
+
'data.item.id': 1,
|
|
2473
|
+
'data.render': 1,
|
|
2474
|
+
objectLayerRenderFramesId: 1,
|
|
2475
|
+
atlasSpriteSheetId: 1,
|
|
2476
|
+
},
|
|
2477
|
+
).lean();
|
|
2020
2478
|
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
}
|
|
2479
|
+
const cidsToUnpin = new Set();
|
|
2480
|
+
const renderFrameIds = [];
|
|
2481
|
+
const atlasIds = [];
|
|
2482
|
+
const itemKeysToClean = new Set();
|
|
2026
2483
|
|
|
2027
|
-
|
|
2028
|
-
if (cidsToUnpin.
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2484
|
+
for (const doc of olDocs) {
|
|
2485
|
+
if (doc.cid) cidsToUnpin.add(doc.cid);
|
|
2486
|
+
if (doc.data?.render?.cid) cidsToUnpin.add(doc.data.render.cid);
|
|
2487
|
+
if (doc.data?.render?.metadataCid) cidsToUnpin.add(doc.data.render.metadataCid);
|
|
2488
|
+
if (doc.data?.item?.id) itemKeysToClean.add(doc.data.item.id);
|
|
2489
|
+
if (doc.objectLayerRenderFramesId) renderFrameIds.push(doc.objectLayerRenderFramesId);
|
|
2490
|
+
if (doc.atlasSpriteSheetId) atlasIds.push(doc.atlasSpriteSheetId);
|
|
2491
|
+
}
|
|
2032
2492
|
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2493
|
+
// Delete AtlasSpriteSheet + referenced File docs
|
|
2494
|
+
if (atlasIds.length > 0) {
|
|
2495
|
+
const atlasDocs = await AtlasSpriteSheet.find({ _id: { $in: atlasIds } }, { fileId: 1, cid: 1 }).lean();
|
|
2496
|
+
const atlasFileIds = atlasDocs.map((a) => a.fileId).filter(Boolean);
|
|
2497
|
+
for (const atlas of atlasDocs) {
|
|
2498
|
+
if (atlas.cid) cidsToUnpin.add(atlas.cid);
|
|
2038
2499
|
}
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
if (ok) mfsCount++;
|
|
2500
|
+
if (atlasFileIds.length > 0) {
|
|
2501
|
+
const fileResult = await File.deleteMany({ _id: { $in: atlasFileIds } });
|
|
2502
|
+
logger.info(`Dropped ${fileResult.deletedCount} File document(s) (atlas)`);
|
|
2043
2503
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2504
|
+
const atlasResult = await AtlasSpriteSheet.deleteMany({ _id: { $in: atlasIds } });
|
|
2505
|
+
logger.info(`Dropped ${atlasResult.deletedCount} AtlasSpriteSheet document(s)`);
|
|
2506
|
+
}
|
|
2047
2507
|
|
|
2048
|
-
|
|
2049
|
-
|
|
2508
|
+
// Delete RenderFrames
|
|
2509
|
+
if (renderFrameIds.length > 0) {
|
|
2510
|
+
const rfResult = await ObjectLayerRenderFrames.deleteMany({ _id: { $in: renderFrameIds } });
|
|
2511
|
+
logger.info(`Dropped ${rfResult.deletedCount} ObjectLayerRenderFrames document(s)`);
|
|
2050
2512
|
}
|
|
2051
2513
|
|
|
2052
|
-
|
|
2053
|
-
|
|
2514
|
+
// Delete IPFS pin records
|
|
2515
|
+
if (cidsToUnpin.size > 0) {
|
|
2516
|
+
const ipfsResult = await Ipfs.deleteMany({ cid: { $in: [...cidsToUnpin] } });
|
|
2517
|
+
logger.info(`Dropped ${ipfsResult.deletedCount} Ipfs pin record(s)`);
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
// Unpin CIDs from IPFS Kubo + Cluster and remove MFS paths
|
|
2521
|
+
let unpinCount = 0;
|
|
2522
|
+
for (const cid of cidsToUnpin) {
|
|
2523
|
+
const ok = await IpfsClient.unpinCid(cid);
|
|
2524
|
+
if (ok) unpinCount++;
|
|
2525
|
+
}
|
|
2526
|
+
let mfsCount = 0;
|
|
2527
|
+
for (const itemKey of itemKeysToClean) {
|
|
2528
|
+
const ok = await IpfsClient.removeMfsPath(`/object-layer/${itemKey}`);
|
|
2529
|
+
if (ok) mfsCount++;
|
|
2530
|
+
}
|
|
2531
|
+
logger.info(
|
|
2532
|
+
`IPFS cleanup: ${unpinCount}/${cidsToUnpin.size} CIDs unpinned, ${mfsCount}/${itemKeysToClean.size} MFS paths removed`,
|
|
2533
|
+
);
|
|
2534
|
+
|
|
2535
|
+
const olResult = await ObjectLayer.deleteMany({ 'data.item.id': { $in: [...dropOlItemIds] } });
|
|
2536
|
+
logger.info(`Dropped ${olResult.deletedCount} ObjectLayer document(s)`);
|
|
2054
2537
|
}
|
|
2055
2538
|
|
|
2056
2539
|
// Drop thumbnail File documents (instance + maps), excluding shared ones
|
|
@@ -2061,9 +2544,58 @@ try {
|
|
|
2061
2544
|
|
|
2062
2545
|
await CyberiaInstance.deleteOne({ code: instanceCode });
|
|
2063
2546
|
logger.info('Dropped CyberiaInstance', { code: instanceCode });
|
|
2547
|
+
await CyberiaInstanceConf.deleteOne({ instanceCode });
|
|
2548
|
+
logger.info('Dropped CyberiaInstanceConf', { instanceCode });
|
|
2064
2549
|
} else {
|
|
2065
2550
|
logger.info('No existing instance to drop', { code: instanceCode });
|
|
2066
2551
|
}
|
|
2552
|
+
} else if (options.drop && options.conf) {
|
|
2553
|
+
logger.info(
|
|
2554
|
+
'Skipping full instance drop because --conf only imports cyberia-instance.json and cyberia-instance-conf.json',
|
|
2555
|
+
);
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
if (options.conf) {
|
|
2559
|
+
const confImportPath = `${backupDir}/cyberia-instance-conf.json`;
|
|
2560
|
+
let importedConf = null;
|
|
2561
|
+
if (fs.existsSync(confImportPath)) {
|
|
2562
|
+
const confData = fs.readJsonSync(confImportPath);
|
|
2563
|
+
if (confData._id) await CyberiaInstanceConf.deleteOne({ _id: confData._id });
|
|
2564
|
+
await CyberiaInstanceConf.deleteOne({ instanceCode: confData.instanceCode });
|
|
2565
|
+
// Always bump updatedAt so the Go server's version hash changes and
|
|
2566
|
+
// ReloadWorld re-applies the config without requiring a full restart.
|
|
2567
|
+
confData.updatedAt = new Date();
|
|
2568
|
+
importedConf = await CyberiaInstanceConf.create(confData);
|
|
2569
|
+
logger.info('Imported CyberiaInstanceConf', { instanceCode: confData.instanceCode });
|
|
2570
|
+
} else {
|
|
2571
|
+
logger.warn(`CyberiaInstanceConf backup not found: ${confImportPath}`);
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
// In --conf mode we must NOT delete + recreate the CyberiaInstance because
|
|
2575
|
+
// that would overwrite cyberiaMapCodes / portals / itemIds with whatever was
|
|
2576
|
+
// in the (possibly stale) backup, effectively removing the live maps and OLs
|
|
2577
|
+
// from the instance. Only update the conf ref and bump updatedAt so the Go
|
|
2578
|
+
// server's version hash changes and ReloadWorld re-applies the config.
|
|
2579
|
+
if (importedConf) {
|
|
2580
|
+
const result = await CyberiaInstance.updateOne(
|
|
2581
|
+
{ code: instanceCode },
|
|
2582
|
+
{ $set: { conf: importedConf._id, updatedAt: new Date() } },
|
|
2583
|
+
);
|
|
2584
|
+
if (result.matchedCount > 0) {
|
|
2585
|
+
logger.info('Updated CyberiaInstance conf ref', { code: instanceCode });
|
|
2586
|
+
} else {
|
|
2587
|
+
logger.warn(`CyberiaInstance not found in DB for code "${instanceCode}" — cannot update conf ref`);
|
|
2588
|
+
}
|
|
2589
|
+
} else {
|
|
2590
|
+
logger.warn(`Skipping CyberiaInstance conf ref update — no conf was imported`);
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
logger.info('Instance import completed in --conf mode', {
|
|
2594
|
+
backupDir,
|
|
2595
|
+
importedFiles: ['cyberia-instance.json', 'cyberia-instance-conf.json'],
|
|
2596
|
+
});
|
|
2597
|
+
await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
2598
|
+
return;
|
|
2067
2599
|
}
|
|
2068
2600
|
|
|
2069
2601
|
// 1. Import File documents first (atlas PNG + thumbnail dependencies)
|
|
@@ -2113,6 +2645,9 @@ try {
|
|
|
2113
2645
|
for (const f of atlasFiles) {
|
|
2114
2646
|
const atlasData = fs.readJsonSync(`${atlasDir}/${f}`);
|
|
2115
2647
|
await AtlasSpriteSheet.deleteOne({ _id: atlasData._id });
|
|
2648
|
+
if (atlasData.metadata?.itemKey) {
|
|
2649
|
+
await AtlasSpriteSheet.deleteOne({ 'metadata.itemKey': atlasData.metadata.itemKey });
|
|
2650
|
+
}
|
|
2116
2651
|
await AtlasSpriteSheet.create(atlasData);
|
|
2117
2652
|
atlasCount++;
|
|
2118
2653
|
}
|
|
@@ -2127,45 +2662,71 @@ try {
|
|
|
2127
2662
|
for (const file of olFiles) {
|
|
2128
2663
|
const olData = fs.readJsonSync(`${olDir}/${file}`);
|
|
2129
2664
|
await ObjectLayer.deleteOne({ _id: olData._id });
|
|
2665
|
+
if (olData.sha256) {
|
|
2666
|
+
await ObjectLayer.deleteOne({ sha256: olData.sha256 });
|
|
2667
|
+
}
|
|
2130
2668
|
await ObjectLayer.create(olData);
|
|
2131
2669
|
olCount++;
|
|
2132
2670
|
}
|
|
2133
2671
|
logger.info(`Imported ${olCount} ObjectLayer document(s)`);
|
|
2134
2672
|
}
|
|
2135
2673
|
|
|
2136
|
-
//
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2674
|
+
// 4b. Regenerate static frame PNGs from imported render-frames + object-layer documents.
|
|
2675
|
+
// Mirrors the writeStaticFrameAssets call in `ol --import` so src/client/public/cyberia
|
|
2676
|
+
// and the public/<host><path> deployment dir are populated even when the cyberia
|
|
2677
|
+
// asset directory was wiped (e.g. git clean / rm -rf).
|
|
2678
|
+
const rfImportDir = `${backupDir}/render-frames`;
|
|
2679
|
+
const olImportDir = `${backupDir}/object-layers`;
|
|
2680
|
+
if (fs.existsSync(rfImportDir) && fs.existsSync(olImportDir)) {
|
|
2681
|
+
const srcBasePath = './src/client/public/cyberia/';
|
|
2682
|
+
const publicBasePath = `./public/${host}${path}`;
|
|
2683
|
+
let staticWriteCount = 0;
|
|
2684
|
+
const rfFileList = fs.readdirSync(rfImportDir).filter((f) => f.endsWith('.json'));
|
|
2685
|
+
for (const rfFile of rfFileList) {
|
|
2686
|
+
const rfData = fs.readJsonSync(`${rfImportDir}/${rfFile}`);
|
|
2687
|
+
const itemId = nodePath.basename(rfFile, '.json');
|
|
2688
|
+
const olFile = `${olImportDir}/${itemId}.json`;
|
|
2689
|
+
if (!fs.existsSync(olFile)) {
|
|
2690
|
+
logger.warn(`Skipping static asset generation for '${itemId}' — no matching object-layer file`);
|
|
2691
|
+
continue;
|
|
2692
|
+
}
|
|
2693
|
+
const olData = fs.readJsonSync(olFile);
|
|
2694
|
+
const itemType = olData.data?.item?.type;
|
|
2695
|
+
if (!itemType) {
|
|
2696
|
+
logger.warn(`Skipping static asset generation for '${itemId}' — missing data.item.type`);
|
|
2697
|
+
continue;
|
|
2698
|
+
}
|
|
2699
|
+
// rfData matches the ObjectLayerRenderFrames schema: { frames, colors, frame_duration }
|
|
2700
|
+
const objectLayerRenderFramesData = {
|
|
2701
|
+
frames: rfData.frames || {},
|
|
2702
|
+
colors: rfData.colors || [],
|
|
2703
|
+
frame_duration: rfData.frame_duration ?? 100,
|
|
2704
|
+
};
|
|
2705
|
+
try {
|
|
2706
|
+
const written = await ObjectLayerEngine.writeStaticFrameAssets({
|
|
2707
|
+
basePaths: [srcBasePath, publicBasePath],
|
|
2708
|
+
itemType,
|
|
2709
|
+
itemId,
|
|
2710
|
+
objectLayerRenderFramesData,
|
|
2711
|
+
objectLayerData: olData,
|
|
2712
|
+
cellPixelDim: 20,
|
|
2713
|
+
});
|
|
2714
|
+
staticWriteCount += written.length;
|
|
2715
|
+
} catch (err) {
|
|
2716
|
+
logger.warn(`Failed to write static assets for '${itemId}': ${err.message}`);
|
|
2717
|
+
}
|
|
2155
2718
|
}
|
|
2156
|
-
logger.info(`
|
|
2719
|
+
logger.info(`Static frame PNGs written: ${staticWriteCount} file(s) across src/client/public and public/`);
|
|
2157
2720
|
}
|
|
2158
2721
|
|
|
2159
|
-
//
|
|
2722
|
+
// 5. Import maps (preserveUUID: delete by code then create with exact _id)
|
|
2160
2723
|
const mapsDir = `${backupDir}/maps`;
|
|
2161
2724
|
if (fs.existsSync(mapsDir)) {
|
|
2162
2725
|
const mapFiles = fs.readdirSync(mapsDir).filter((f) => f.endsWith('.json'));
|
|
2163
2726
|
let mapCount = 0;
|
|
2164
2727
|
for (const file of mapFiles) {
|
|
2165
2728
|
const mapData = fs.readJsonSync(`${mapsDir}/${file}`);
|
|
2166
|
-
// Remove any existing map with this code (may have different _id)
|
|
2167
2729
|
await CyberiaMap.deleteOne({ code: mapData.code });
|
|
2168
|
-
// Also remove if an old doc with this _id exists
|
|
2169
2730
|
await CyberiaMap.deleteOne({ _id: mapData._id });
|
|
2170
2731
|
await CyberiaMap.create(mapData);
|
|
2171
2732
|
mapCount++;
|
|
@@ -2173,6 +2734,18 @@ try {
|
|
|
2173
2734
|
logger.info(`Imported ${mapCount} CyberiaMap document(s)`);
|
|
2174
2735
|
}
|
|
2175
2736
|
|
|
2737
|
+
// 6. Import CyberiaInstanceConf (skillRules, equipmentRules, entityDefaults, etc.)
|
|
2738
|
+
const confImportPath = `${backupDir}/cyberia-instance-conf.json`;
|
|
2739
|
+
if (fs.existsSync(confImportPath)) {
|
|
2740
|
+
const confData = fs.readJsonSync(confImportPath);
|
|
2741
|
+
if (confData._id) await CyberiaInstanceConf.deleteOne({ _id: confData._id });
|
|
2742
|
+
await CyberiaInstanceConf.deleteOne({ instanceCode: confData.instanceCode });
|
|
2743
|
+
await CyberiaInstanceConf.create(confData);
|
|
2744
|
+
logger.info('Imported CyberiaInstanceConf', { instanceCode: confData.instanceCode });
|
|
2745
|
+
} else {
|
|
2746
|
+
logger.warn(`CyberiaInstanceConf backup not found: ${confImportPath}`);
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2176
2749
|
// 7. Import instance (preserveUUID: delete by code then create with exact _id)
|
|
2177
2750
|
const instancePath = `${backupDir}/cyberia-instance.json`;
|
|
2178
2751
|
if (fs.existsSync(instancePath)) {
|
|
@@ -2185,6 +2758,283 @@ try {
|
|
|
2185
2758
|
logger.warn(`Instance file not found: ${instancePath}`);
|
|
2186
2759
|
}
|
|
2187
2760
|
|
|
2761
|
+
// 8. Import CyberiaDialogue documents
|
|
2762
|
+
const dialoguesDir = `${backupDir}/cyberia-dialogues`;
|
|
2763
|
+
if (fs.existsSync(dialoguesDir)) {
|
|
2764
|
+
const dialogueFiles = fs.readdirSync(dialoguesDir).filter((f) => f.endsWith('.json'));
|
|
2765
|
+
let dialogueCount = 0;
|
|
2766
|
+
|
|
2767
|
+
for (const file of dialogueFiles) {
|
|
2768
|
+
const rawDialogueData = fs.readJsonSync(`${dialoguesDir}/${file}`);
|
|
2769
|
+
const dialogues = Array.isArray(rawDialogueData) ? rawDialogueData : [rawDialogueData];
|
|
2770
|
+
const dialogueCodes = [...new Set(dialogues.map((dialogue) => dialogue.code).filter(Boolean))];
|
|
2771
|
+
if (dialogueCodes.length === 0) {
|
|
2772
|
+
logger.warn(`Skipping CyberiaDialogue backup without code: ${file}`);
|
|
2773
|
+
continue;
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
await CyberiaDialogue.deleteMany({ code: { $in: dialogueCodes } });
|
|
2777
|
+
|
|
2778
|
+
const dialogueIds = dialogues.map((dialogue) => dialogue._id).filter(Boolean);
|
|
2779
|
+
if (dialogueIds.length > 0) {
|
|
2780
|
+
await CyberiaDialogue.deleteMany({ _id: { $in: dialogueIds } });
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
await CyberiaDialogue.create(dialogues);
|
|
2784
|
+
dialogueCount += dialogues.length;
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
logger.info(`Imported ${dialogueCount} CyberiaDialogue document(s)`);
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
// 9. Restore IPFS pin records and payloads
|
|
2791
|
+
const ipfsFile = `${backupDir}/ipfs/pins.json`;
|
|
2792
|
+
if (fs.existsSync(ipfsFile)) {
|
|
2793
|
+
const ipfsDocs = fs.readJsonSync(ipfsFile);
|
|
2794
|
+
const ipfsContentDir = `${backupDir}/ipfs/content`;
|
|
2795
|
+
let ipfsCount = 0;
|
|
2796
|
+
let ipfsSkipped = 0;
|
|
2797
|
+
|
|
2798
|
+
const backupPins = new Map();
|
|
2799
|
+
for (const doc of ipfsDocs) {
|
|
2800
|
+
const resourceType = inferResourceType(doc);
|
|
2801
|
+
if (!resourceType) {
|
|
2802
|
+
logger.warn(
|
|
2803
|
+
`Ipfs record is missing resourceType and cannot be inferred (cid: ${doc.cid}, mfsPath: ${doc.mfsPath ?? '(none)'}) — skipping`,
|
|
2804
|
+
);
|
|
2805
|
+
ipfsSkipped++;
|
|
2806
|
+
continue;
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
const mfsPaths = collectMfsPaths(doc);
|
|
2810
|
+
if (mfsPaths.length === 0) {
|
|
2811
|
+
upsertCanonicalPinEntry(backupPins, { cid: doc.cid, resourceType, mfsPath: '' });
|
|
2812
|
+
} else {
|
|
2813
|
+
for (const mfsPath of mfsPaths) {
|
|
2814
|
+
upsertCanonicalPinEntry(backupPins, { cid: doc.cid, resourceType, mfsPath });
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
const backupPinEntries = serialiseCanonicalPins(backupPins);
|
|
2820
|
+
const backupCids = [...new Set(backupPinEntries.map((entry) => entry.cid).filter(Boolean))];
|
|
2821
|
+
if (backupCids.length > 0) {
|
|
2822
|
+
await Ipfs.deleteMany({ cid: { $in: backupCids } });
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
const restoreAdditionalMfsPaths = async (cid, mfsPaths, primaryPath) => {
|
|
2826
|
+
let restoredCount = 0;
|
|
2827
|
+
for (const mfsPath of mfsPaths) {
|
|
2828
|
+
if (!mfsPath || mfsPath === primaryPath) continue;
|
|
2829
|
+
const ok = await IpfsClient.restoreMfsPath(cid, mfsPath);
|
|
2830
|
+
if (ok) restoredCount++;
|
|
2831
|
+
}
|
|
2832
|
+
return restoredCount;
|
|
2833
|
+
};
|
|
2834
|
+
|
|
2835
|
+
const upsertImportedPin = async ({ cid, resourceType, mfsPath }) => {
|
|
2836
|
+
if (!cid || !resourceType) return;
|
|
2837
|
+
await Ipfs.deleteMany({ cid, resourceType });
|
|
2838
|
+
await createPinRecord({ cid, resourceType, mfsPath: mfsPath || '', options: { host, path } });
|
|
2839
|
+
};
|
|
2840
|
+
|
|
2841
|
+
if (fs.existsSync(ipfsContentDir)) {
|
|
2842
|
+
let cidRewriteCount = 0;
|
|
2843
|
+
let extraMfsRestoreCount = 0;
|
|
2844
|
+
|
|
2845
|
+
for (const [index, doc] of backupPinEntries.entries()) {
|
|
2846
|
+
const mfsPaths = collectMfsPaths(doc);
|
|
2847
|
+
const primaryPath = mfsPaths[0] || '';
|
|
2848
|
+
const payloadPath = `${ipfsContentDir}/${doc.cid}.bin`;
|
|
2849
|
+
|
|
2850
|
+
logger.info('IPFS raw payload restore start', {
|
|
2851
|
+
index: index + 1,
|
|
2852
|
+
total: backupPinEntries.length,
|
|
2853
|
+
cid: doc.cid,
|
|
2854
|
+
resourceType: doc.resourceType,
|
|
2855
|
+
mfsPath: primaryPath || null,
|
|
2856
|
+
});
|
|
2857
|
+
|
|
2858
|
+
if (!fs.existsSync(payloadPath)) {
|
|
2859
|
+
logger.warn('IPFS raw payload file missing from backup', {
|
|
2860
|
+
cid: doc.cid,
|
|
2861
|
+
resourceType: doc.resourceType,
|
|
2862
|
+
mfsPath: primaryPath || null,
|
|
2863
|
+
});
|
|
2864
|
+
ipfsSkipped++;
|
|
2865
|
+
continue;
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
const addResult = await IpfsClient.addToIpfs(
|
|
2869
|
+
fs.readFileSync(payloadPath),
|
|
2870
|
+
nodePath.basename(primaryPath || doc.cid),
|
|
2871
|
+
primaryPath || undefined,
|
|
2872
|
+
);
|
|
2873
|
+
|
|
2874
|
+
if (!addResult?.cid) {
|
|
2875
|
+
logger.warn('IPFS raw payload restore failed', {
|
|
2876
|
+
cid: doc.cid,
|
|
2877
|
+
resourceType: doc.resourceType,
|
|
2878
|
+
mfsPath: primaryPath || null,
|
|
2879
|
+
});
|
|
2880
|
+
ipfsSkipped++;
|
|
2881
|
+
continue;
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
const finalCid = addResult.cid;
|
|
2885
|
+
if (doc.cid !== finalCid) {
|
|
2886
|
+
await rewriteImportedCidReferences({
|
|
2887
|
+
oldCid: doc.cid,
|
|
2888
|
+
newCid: finalCid,
|
|
2889
|
+
resourceType: doc.resourceType,
|
|
2890
|
+
});
|
|
2891
|
+
cidRewriteCount++;
|
|
2892
|
+
logger.warn('IPFS raw payload CID mismatch during import; rewriting imported references', {
|
|
2893
|
+
oldCid: doc.cid,
|
|
2894
|
+
newCid: finalCid,
|
|
2895
|
+
resourceType: doc.resourceType,
|
|
2896
|
+
mfsPath: primaryPath || null,
|
|
2897
|
+
});
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2900
|
+
extraMfsRestoreCount += await restoreAdditionalMfsPaths(finalCid, mfsPaths, primaryPath);
|
|
2901
|
+
await upsertImportedPin({ cid: finalCid, resourceType: doc.resourceType, mfsPath: primaryPath });
|
|
2902
|
+
ipfsCount++;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
logger.info(
|
|
2906
|
+
`Imported ${ipfsCount} Ipfs pin record(s) from exact backup payloads${ipfsSkipped ? `, skipped ${ipfsSkipped}` : ''}`,
|
|
2907
|
+
);
|
|
2908
|
+
logger.info(
|
|
2909
|
+
`IPFS raw payload restore: ${ipfsCount}/${backupPinEntries.length} record(s) restored, ${extraMfsRestoreCount} additional MFS path(s) restored${cidRewriteCount ? `, ${cidRewriteCount} CID rewrite(s)` : ''}`,
|
|
2910
|
+
);
|
|
2911
|
+
} else {
|
|
2912
|
+
logger.warn(
|
|
2913
|
+
'Backup has no raw IPFS payload files under ipfs/content/. Rebuilding a canonical IPFS layout from imported ObjectLayer, AtlasSpriteSheet, and File documents.',
|
|
2914
|
+
);
|
|
2915
|
+
|
|
2916
|
+
const importedItemIds = fs.existsSync(olDir)
|
|
2917
|
+
? fs
|
|
2918
|
+
.readdirSync(olDir)
|
|
2919
|
+
.filter((f) => f.endsWith('.json'))
|
|
2920
|
+
.map((f) => nodePath.basename(f, '.json'))
|
|
2921
|
+
: [];
|
|
2922
|
+
const importedObjectLayers = importedItemIds.length
|
|
2923
|
+
? await ObjectLayer.find({ 'data.item.id': { $in: importedItemIds } }).lean()
|
|
2924
|
+
: [];
|
|
2925
|
+
|
|
2926
|
+
let rebuiltObjectLayers = 0;
|
|
2927
|
+
|
|
2928
|
+
for (const [index, objectLayerDoc] of importedObjectLayers.entries()) {
|
|
2929
|
+
const itemKey = objectLayerDoc.data?.item?.id || objectLayerDoc._id.toString();
|
|
2930
|
+
const itemPaths = getCanonicalIpfsPaths(itemKey);
|
|
2931
|
+
const updatedData = newInstance(objectLayerDoc.data || {});
|
|
2932
|
+
if (!updatedData.render) updatedData.render = {};
|
|
2933
|
+
|
|
2934
|
+
logger.info('IPFS legacy canonical rebuild start', {
|
|
2935
|
+
index: index + 1,
|
|
2936
|
+
total: importedObjectLayers.length,
|
|
2937
|
+
itemKey,
|
|
2938
|
+
});
|
|
2939
|
+
|
|
2940
|
+
let atlasCid = '';
|
|
2941
|
+
let atlasMetadataCid = '';
|
|
2942
|
+
|
|
2943
|
+
if (objectLayerDoc.atlasSpriteSheetId) {
|
|
2944
|
+
const atlasDoc = await AtlasSpriteSheet.findById(objectLayerDoc.atlasSpriteSheetId).lean();
|
|
2945
|
+
if (atlasDoc) {
|
|
2946
|
+
const atlasFile = atlasDoc.fileId ? await File.findById(atlasDoc.fileId).lean() : null;
|
|
2947
|
+
const atlasBuffer = toBuffer(atlasFile?.data);
|
|
2948
|
+
|
|
2949
|
+
if (atlasBuffer) {
|
|
2950
|
+
const atlasAddResult = await IpfsClient.addBufferToIpfs(
|
|
2951
|
+
atlasBuffer,
|
|
2952
|
+
`${itemKey}_atlas_sprite_sheet.png`,
|
|
2953
|
+
itemPaths.atlasSpriteSheet,
|
|
2954
|
+
);
|
|
2955
|
+
if (atlasAddResult?.cid) {
|
|
2956
|
+
atlasCid = atlasAddResult.cid;
|
|
2957
|
+
await AtlasSpriteSheet.updateOne({ _id: atlasDoc._id }, { $set: { cid: atlasCid } });
|
|
2958
|
+
await createPinRecord({
|
|
2959
|
+
cid: atlasCid,
|
|
2960
|
+
resourceType: 'atlas-sprite-sheet',
|
|
2961
|
+
mfsPath: itemPaths.atlasSpriteSheet,
|
|
2962
|
+
options: { host, path },
|
|
2963
|
+
});
|
|
2964
|
+
ipfsCount++;
|
|
2965
|
+
} else {
|
|
2966
|
+
logger.warn(`Failed to rebuild atlas sprite sheet payload for '${itemKey}'`);
|
|
2967
|
+
}
|
|
2968
|
+
} else if (atlasDoc.fileId) {
|
|
2969
|
+
logger.warn(`Atlas File payload missing for '${itemKey}'`);
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
const atlasMetadataResult = await IpfsClient.addJsonToIpfs(
|
|
2973
|
+
atlasDoc.metadata || {},
|
|
2974
|
+
`${itemKey}_atlas_sprite_sheet_metadata.json`,
|
|
2975
|
+
itemPaths.atlasMetadata,
|
|
2976
|
+
);
|
|
2977
|
+
if (atlasMetadataResult?.cid) {
|
|
2978
|
+
atlasMetadataCid = atlasMetadataResult.cid;
|
|
2979
|
+
await createPinRecord({
|
|
2980
|
+
cid: atlasMetadataCid,
|
|
2981
|
+
resourceType: 'atlas-metadata',
|
|
2982
|
+
mfsPath: itemPaths.atlasMetadata,
|
|
2983
|
+
options: { host, path },
|
|
2984
|
+
});
|
|
2985
|
+
ipfsCount++;
|
|
2986
|
+
} else {
|
|
2987
|
+
logger.warn(`Failed to rebuild atlas metadata payload for '${itemKey}'`);
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
if (atlasCid) {
|
|
2993
|
+
updatedData.render.cid = atlasCid;
|
|
2994
|
+
} else {
|
|
2995
|
+
delete updatedData.render.cid;
|
|
2996
|
+
}
|
|
2997
|
+
if (atlasMetadataCid) {
|
|
2998
|
+
updatedData.render.metadataCid = atlasMetadataCid;
|
|
2999
|
+
} else {
|
|
3000
|
+
delete updatedData.render.metadataCid;
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
const objectLayerAddResult = await IpfsClient.addJsonToIpfs(
|
|
3004
|
+
updatedData,
|
|
3005
|
+
`${itemKey}_data.json`,
|
|
3006
|
+
itemPaths.objectLayerData,
|
|
3007
|
+
);
|
|
3008
|
+
if (objectLayerAddResult?.cid) {
|
|
3009
|
+
await ObjectLayer.updateOne(
|
|
3010
|
+
{ _id: objectLayerDoc._id },
|
|
3011
|
+
{
|
|
3012
|
+
$set: {
|
|
3013
|
+
cid: objectLayerAddResult.cid,
|
|
3014
|
+
data: updatedData,
|
|
3015
|
+
},
|
|
3016
|
+
},
|
|
3017
|
+
);
|
|
3018
|
+
await createPinRecord({
|
|
3019
|
+
cid: objectLayerAddResult.cid,
|
|
3020
|
+
resourceType: 'object-layer-data',
|
|
3021
|
+
mfsPath: itemPaths.objectLayerData,
|
|
3022
|
+
options: { host, path },
|
|
3023
|
+
});
|
|
3024
|
+
ipfsCount++;
|
|
3025
|
+
rebuiltObjectLayers++;
|
|
3026
|
+
} else {
|
|
3027
|
+
logger.warn(`Failed to rebuild object-layer-data payload for '${itemKey}'`);
|
|
3028
|
+
ipfsSkipped++;
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
logger.info(
|
|
3033
|
+
`Legacy IPFS rebuild: ${rebuiltObjectLayers}/${importedObjectLayers.length} ObjectLayer payload(s) rebuilt, ${ipfsCount} canonical pin record(s) upserted${ipfsSkipped ? `, skipped ${ipfsSkipped}` : ''}`,
|
|
3034
|
+
);
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
|
|
2188
3038
|
logger.info('Instance import completed', { backupDir });
|
|
2189
3039
|
}
|
|
2190
3040
|
|
|
@@ -2201,13 +3051,41 @@ try {
|
|
|
2201
3051
|
// Collect thumbnail File IDs to drop
|
|
2202
3052
|
const thumbFileIds = [];
|
|
2203
3053
|
if (existingInstance.thumbnail) thumbFileIds.push(existingInstance.thumbnail);
|
|
3054
|
+
const dropOlItemIds = new Set();
|
|
2204
3055
|
|
|
2205
3056
|
// Query other instances for shared thumbnail exclusion
|
|
2206
3057
|
const otherInstances = await CyberiaInstance.find({ code: { $ne: instanceCode } }, { thumbnail: 1 }).lean();
|
|
2207
3058
|
|
|
3059
|
+
// Add instance-level itemIds (may not appear in any map entity)
|
|
3060
|
+
for (const id of existingInstance.itemIds || []) if (id) dropOlItemIds.add(id);
|
|
3061
|
+
|
|
3062
|
+
// Add conf entityDefaults and skillConfig itemIds (liveItemIds, deadItemIds, dropItemIds, defaultObjectLayers)
|
|
3063
|
+
const existingConf =
|
|
3064
|
+
(await CyberiaInstanceConf.findOne({ instanceCode }).lean()) ||
|
|
3065
|
+
(existingInstance.conf ? await CyberiaInstanceConf.findById(existingInstance.conf).lean() : null);
|
|
3066
|
+
if (existingConf) {
|
|
3067
|
+
for (const ed of existingConf.entityDefaults || []) {
|
|
3068
|
+
for (const id of ed.liveItemIds || []) if (id) dropOlItemIds.add(id);
|
|
3069
|
+
for (const id of ed.deadItemIds || []) if (id) dropOlItemIds.add(id);
|
|
3070
|
+
for (const id of ed.dropItemIds || []) if (id) dropOlItemIds.add(id);
|
|
3071
|
+
for (const slot of ed.defaultObjectLayers || []) if (slot.itemId) dropOlItemIds.add(slot.itemId);
|
|
3072
|
+
}
|
|
3073
|
+
for (const sc of existingConf.skillConfig || []) {
|
|
3074
|
+
if (sc.triggerItemId) dropOlItemIds.add(sc.triggerItemId);
|
|
3075
|
+
for (const skill of sc.skills || []) {
|
|
3076
|
+
if (skill.summonedEntityItemId && !skill.summonedEntityItemId.startsWith('$'))
|
|
3077
|
+
dropOlItemIds.add(skill.summonedEntityItemId);
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
const otherMaps = await CyberiaMap.find(
|
|
3083
|
+
{ code: { $nin: [...dropMapCodes] } },
|
|
3084
|
+
{ 'entities.objectLayerItemIds': 1, thumbnail: 1 },
|
|
3085
|
+
).lean();
|
|
3086
|
+
|
|
2208
3087
|
if (dropMapCodes.size > 0) {
|
|
2209
3088
|
const dropMaps = await CyberiaMap.find({ code: { $in: [...dropMapCodes] } }).lean();
|
|
2210
|
-
const dropOlItemIds = new Set();
|
|
2211
3089
|
for (const map of dropMaps) {
|
|
2212
3090
|
if (map.thumbnail) thumbFileIds.push(map.thumbnail);
|
|
2213
3091
|
for (const entity of map.entities || []) {
|
|
@@ -2216,103 +3094,102 @@ try {
|
|
|
2216
3094
|
}
|
|
2217
3095
|
}
|
|
2218
3096
|
}
|
|
3097
|
+
const mapResult = await CyberiaMap.deleteMany({ code: { $in: [...dropMapCodes] } });
|
|
3098
|
+
logger.info(`Dropped ${mapResult.deletedCount} CyberiaMap document(s)`);
|
|
3099
|
+
}
|
|
2219
3100
|
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
for (const m of otherMaps) {
|
|
2227
|
-
for (const entity of m.entities || []) {
|
|
2228
|
-
for (const itemId of entity.objectLayerItemIds || []) {
|
|
2229
|
-
if (dropOlItemIds.has(itemId)) sharedOlItemIds.add(itemId);
|
|
2230
|
-
}
|
|
3101
|
+
// Exclude OL item IDs referenced by maps outside this instance
|
|
3102
|
+
const sharedOlItemIds = new Set();
|
|
3103
|
+
for (const m of otherMaps) {
|
|
3104
|
+
for (const entity of m.entities || []) {
|
|
3105
|
+
for (const itemId of entity.objectLayerItemIds || []) {
|
|
3106
|
+
if (dropOlItemIds.has(itemId)) sharedOlItemIds.add(itemId);
|
|
2231
3107
|
}
|
|
2232
3108
|
}
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
}
|
|
3109
|
+
}
|
|
3110
|
+
for (const shared of sharedOlItemIds) dropOlItemIds.delete(shared);
|
|
3111
|
+
if (sharedOlItemIds.size > 0) {
|
|
3112
|
+
logger.info(`Preserved ${sharedOlItemIds.size} ObjectLayer(s) shared with other maps`);
|
|
3113
|
+
}
|
|
2237
3114
|
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
3115
|
+
// Exclude thumbnail File IDs referenced by other instances or maps
|
|
3116
|
+
const otherMapThumbs = otherMaps.map((m) => m.thumbnail?.toString()).filter(Boolean);
|
|
3117
|
+
const otherInstThumbs = otherInstances.map((i) => i.thumbnail?.toString()).filter(Boolean);
|
|
3118
|
+
const sharedThumbIds = new Set([...otherMapThumbs, ...otherInstThumbs]);
|
|
3119
|
+
for (let i = thumbFileIds.length - 1; i >= 0; i--) {
|
|
3120
|
+
if (sharedThumbIds.has(thumbFileIds[i].toString())) thumbFileIds.splice(i, 1);
|
|
3121
|
+
}
|
|
2245
3122
|
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
3123
|
+
if (dropOlItemIds.size > 0) {
|
|
3124
|
+
const dropDialogueCodes = [...dropOlItemIds].map((id) => `default-${id}`);
|
|
3125
|
+
const dialogueResult = await CyberiaDialogue.deleteMany({ code: { $in: dropDialogueCodes } });
|
|
3126
|
+
logger.info(`Dropped ${dialogueResult.deletedCount} CyberiaDialogue document(s)`);
|
|
3127
|
+
|
|
3128
|
+
const olDocs = await ObjectLayer.find(
|
|
3129
|
+
{ 'data.item.id': { $in: [...dropOlItemIds] } },
|
|
3130
|
+
{
|
|
3131
|
+
cid: 1,
|
|
3132
|
+
'data.item.id': 1,
|
|
3133
|
+
'data.render': 1,
|
|
3134
|
+
objectLayerRenderFramesId: 1,
|
|
3135
|
+
atlasSpriteSheetId: 1,
|
|
3136
|
+
},
|
|
3137
|
+
).lean();
|
|
2257
3138
|
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
3139
|
+
const cidsToUnpin = new Set();
|
|
3140
|
+
const renderFrameIds = [];
|
|
3141
|
+
const atlasIds = [];
|
|
3142
|
+
const itemKeysToClean = new Set();
|
|
2262
3143
|
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
3144
|
+
for (const doc of olDocs) {
|
|
3145
|
+
if (doc.cid) cidsToUnpin.add(doc.cid);
|
|
3146
|
+
if (doc.data?.render?.cid) cidsToUnpin.add(doc.data.render.cid);
|
|
3147
|
+
if (doc.data?.render?.metadataCid) cidsToUnpin.add(doc.data.render.metadataCid);
|
|
3148
|
+
if (doc.data?.item?.id) itemKeysToClean.add(doc.data.item.id);
|
|
3149
|
+
if (doc.objectLayerRenderFramesId) renderFrameIds.push(doc.objectLayerRenderFramesId);
|
|
3150
|
+
if (doc.atlasSpriteSheetId) atlasIds.push(doc.atlasSpriteSheetId);
|
|
3151
|
+
}
|
|
2271
3152
|
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
}
|
|
2278
|
-
if (atlasFileIds.length > 0) {
|
|
2279
|
-
const fileResult = await File.deleteMany({ _id: { $in: atlasFileIds } });
|
|
2280
|
-
logger.info(`Dropped ${fileResult.deletedCount} File document(s) (atlas)`);
|
|
2281
|
-
}
|
|
2282
|
-
const atlasResult = await AtlasSpriteSheet.deleteMany({ _id: { $in: atlasIds } });
|
|
2283
|
-
logger.info(`Dropped ${atlasResult.deletedCount} AtlasSpriteSheet document(s)`);
|
|
3153
|
+
if (atlasIds.length > 0) {
|
|
3154
|
+
const atlasDocs = await AtlasSpriteSheet.find({ _id: { $in: atlasIds } }, { fileId: 1, cid: 1 }).lean();
|
|
3155
|
+
const atlasFileIds = atlasDocs.map((a) => a.fileId).filter(Boolean);
|
|
3156
|
+
for (const atlas of atlasDocs) {
|
|
3157
|
+
if (atlas.cid) cidsToUnpin.add(atlas.cid);
|
|
2284
3158
|
}
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
logger.info(`Dropped ${rfResult.deletedCount} ObjectLayerRenderFrames document(s)`);
|
|
3159
|
+
if (atlasFileIds.length > 0) {
|
|
3160
|
+
const fileResult = await File.deleteMany({ _id: { $in: atlasFileIds } });
|
|
3161
|
+
logger.info(`Dropped ${fileResult.deletedCount} File document(s) (atlas)`);
|
|
2289
3162
|
}
|
|
3163
|
+
const atlasResult = await AtlasSpriteSheet.deleteMany({ _id: { $in: atlasIds } });
|
|
3164
|
+
logger.info(`Dropped ${atlasResult.deletedCount} AtlasSpriteSheet document(s)`);
|
|
3165
|
+
}
|
|
2290
3166
|
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
3167
|
+
if (renderFrameIds.length > 0) {
|
|
3168
|
+
const rfResult = await ObjectLayerRenderFrames.deleteMany({ _id: { $in: renderFrameIds } });
|
|
3169
|
+
logger.info(`Dropped ${rfResult.deletedCount} ObjectLayerRenderFrames document(s)`);
|
|
3170
|
+
}
|
|
2295
3171
|
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
}
|
|
2301
|
-
let mfsCount = 0;
|
|
2302
|
-
for (const itemKey of itemKeysToClean) {
|
|
2303
|
-
const ok = await IpfsClient.removeMfsPath(`/object-layer/${itemKey}`);
|
|
2304
|
-
if (ok) mfsCount++;
|
|
2305
|
-
}
|
|
2306
|
-
logger.info(
|
|
2307
|
-
`IPFS cleanup: ${unpinCount}/${cidsToUnpin.size} CIDs unpinned, ${mfsCount}/${itemKeysToClean.size} MFS paths removed`,
|
|
2308
|
-
);
|
|
3172
|
+
if (cidsToUnpin.size > 0) {
|
|
3173
|
+
const ipfsResult = await Ipfs.deleteMany({ cid: { $in: [...cidsToUnpin] } });
|
|
3174
|
+
logger.info(`Dropped ${ipfsResult.deletedCount} Ipfs pin record(s)`);
|
|
3175
|
+
}
|
|
2309
3176
|
|
|
2310
|
-
|
|
2311
|
-
|
|
3177
|
+
let unpinCount = 0;
|
|
3178
|
+
for (const cid of cidsToUnpin) {
|
|
3179
|
+
const ok = await IpfsClient.unpinCid(cid);
|
|
3180
|
+
if (ok) unpinCount++;
|
|
3181
|
+
}
|
|
3182
|
+
let mfsCount = 0;
|
|
3183
|
+
for (const itemKey of itemKeysToClean) {
|
|
3184
|
+
const ok = await IpfsClient.removeMfsPath(`/object-layer/${itemKey}`);
|
|
3185
|
+
if (ok) mfsCount++;
|
|
2312
3186
|
}
|
|
3187
|
+
logger.info(
|
|
3188
|
+
`IPFS cleanup: ${unpinCount}/${cidsToUnpin.size} CIDs unpinned, ${mfsCount}/${itemKeysToClean.size} MFS paths removed`,
|
|
3189
|
+
);
|
|
2313
3190
|
|
|
2314
|
-
const
|
|
2315
|
-
logger.info(`Dropped ${
|
|
3191
|
+
const olResult = await ObjectLayer.deleteMany({ 'data.item.id': { $in: [...dropOlItemIds] } });
|
|
3192
|
+
logger.info(`Dropped ${olResult.deletedCount} ObjectLayer document(s)`);
|
|
2316
3193
|
}
|
|
2317
3194
|
|
|
2318
3195
|
// Drop thumbnail File documents (instance + maps), excluding shared ones
|
|
@@ -2323,6 +3200,8 @@ try {
|
|
|
2323
3200
|
|
|
2324
3201
|
await CyberiaInstance.deleteOne({ code: instanceCode });
|
|
2325
3202
|
logger.info('Dropped CyberiaInstance', { code: instanceCode });
|
|
3203
|
+
await CyberiaInstanceConf.deleteOne({ instanceCode });
|
|
3204
|
+
logger.info('Dropped CyberiaInstanceConf', { instanceCode });
|
|
2326
3205
|
} else {
|
|
2327
3206
|
logger.info('No existing instance to drop', { code: instanceCode });
|
|
2328
3207
|
}
|
|
@@ -3273,11 +4152,11 @@ try {
|
|
|
3273
4152
|
|
|
3274
4153
|
const CyberiaDialogue = DataBaseProvider.instance[`${host}${path}`].mongoose.models.CyberiaDialogue;
|
|
3275
4154
|
|
|
3276
|
-
// Upsert each dialogue record keyed by (
|
|
4155
|
+
// Upsert each dialogue record keyed by (code, order) — idempotent.
|
|
3277
4156
|
let upserted = 0;
|
|
3278
4157
|
for (const dlg of DefaultCyberiaDialogues) {
|
|
3279
4158
|
await CyberiaDialogue.findOneAndUpdate(
|
|
3280
|
-
{
|
|
4159
|
+
{ code: dlg.code, order: dlg.order },
|
|
3281
4160
|
{ $set: { speaker: dlg.speaker, text: dlg.text, mood: dlg.mood } },
|
|
3282
4161
|
{ upsert: true },
|
|
3283
4162
|
);
|
|
@@ -3298,17 +4177,37 @@ try {
|
|
|
3298
4177
|
.description('Generate one procedural example of every registered semantic prefix')
|
|
3299
4178
|
.action(async (options) => {
|
|
3300
4179
|
const SEMANTIC_TYPES = [
|
|
3301
|
-
'floor-desert',
|
|
3302
|
-
'floor-grass',
|
|
4180
|
+
// 'floor-desert',
|
|
4181
|
+
// 'floor-grass',
|
|
3303
4182
|
// 'floor-water',
|
|
3304
4183
|
// 'floor-stone',
|
|
3305
4184
|
// 'floor-lava',
|
|
3306
4185
|
'skin-random',
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
4186
|
+
'skin-dark',
|
|
4187
|
+
'skin-light',
|
|
4188
|
+
'skin-vivid',
|
|
4189
|
+
'skin-natural',
|
|
3311
4190
|
'skin-shaved',
|
|
4191
|
+
// 'resource-desert-petal',
|
|
4192
|
+
// 'resource-desert-stone',
|
|
4193
|
+
// 'resource-desert-polygon',
|
|
4194
|
+
// 'resource-desert-thread',
|
|
4195
|
+
// 'resource-grass-petal',
|
|
4196
|
+
// 'resource-grass-stone',
|
|
4197
|
+
// 'resource-grass-polygon',
|
|
4198
|
+
// 'resource-grass-thread',
|
|
4199
|
+
// 'resource-water-petal',
|
|
4200
|
+
// 'resource-water-stone',
|
|
4201
|
+
// 'resource-water-polygon',
|
|
4202
|
+
// 'resource-water-thread',
|
|
4203
|
+
// 'resource-stone-petal',
|
|
4204
|
+
// 'resource-stone-stone',
|
|
4205
|
+
// 'resource-stone-polygon',
|
|
4206
|
+
// 'resource-stone-thread',
|
|
4207
|
+
// 'resource-lava-petal',
|
|
4208
|
+
// 'resource-lava-stone',
|
|
4209
|
+
// 'resource-lava-polygon',
|
|
4210
|
+
// 'resource-lava-thread',
|
|
3312
4211
|
];
|
|
3313
4212
|
|
|
3314
4213
|
const baseSeed = options.seed || 'example';
|
|
@@ -3330,6 +4229,16 @@ try {
|
|
|
3330
4229
|
logger.info('All semantic examples generated.');
|
|
3331
4230
|
});
|
|
3332
4231
|
|
|
4232
|
+
runner
|
|
4233
|
+
.command('build-manifest')
|
|
4234
|
+
.description('Build k8s resource manifest YAML files from templates')
|
|
4235
|
+
.action(() => {
|
|
4236
|
+
shellExec(`node bin run instance-build-manifest 'dd-cyberia,mmo-client,./cyberia-client' --kubeadm`);
|
|
4237
|
+
shellExec(`node bin run instance-build-manifest 'dd-cyberia,mmo-client,./cyberia-client' --kind --dev`);
|
|
4238
|
+
shellExec(`node bin run instance-build-manifest 'dd-cyberia,mmo-server,./cyberia-server' --kubeadm`);
|
|
4239
|
+
shellExec(`node bin run instance-build-manifest 'dd-cyberia,mmo-server,./cyberia-server' --kind --dev`);
|
|
4240
|
+
});
|
|
4241
|
+
|
|
3333
4242
|
if (underpostProgram.commands.find((c) => c._name == process.argv[2]))
|
|
3334
4243
|
throw new Error('Trigger underpost passthrough');
|
|
3335
4244
|
|