cyberia 3.1.3 → 3.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -2
- package/.github/workflows/engine-cyberia.cd.yml +10 -8
- package/.github/workflows/engine-cyberia.ci.yml +12 -29
- package/.github/workflows/ghpkg.ci.yml +4 -4
- package/.github/workflows/npmpkg.ci.yml +28 -11
- package/.github/workflows/publish.ci.yml +21 -2
- package/.github/workflows/pwa-microservices-template-page.cd.yml +4 -5
- package/.github/workflows/pwa-microservices-template-test.ci.yml +3 -3
- package/.github/workflows/release.cd.yml +14 -10
- package/CHANGELOG.md +783 -1
- package/CLI-HELP.md +95 -18
- package/Dockerfile +0 -2
- package/README.md +290 -220
- package/bin/build.js +24 -7
- package/bin/cyberia.js +2838 -252
- package/bin/deploy.js +747 -125
- package/bin/file.js +9 -0
- package/bin/index.js +2838 -252
- package/bin/vs.js +1 -1
- package/conf.js +99 -65
- package/deployment.yaml +18 -164
- package/hardhat/hardhat.config.js +13 -13
- package/hardhat/ignition/modules/ObjectLayerToken.js +1 -1
- package/hardhat/package-lock.json +2559 -5864
- package/hardhat/package.json +14 -23
- package/hardhat/scripts/deployObjectLayerToken.js +1 -1
- package/hardhat/test/ObjectLayerToken.js +4 -2
- package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
- package/hardhat/types/ethers-contracts/common.ts +92 -0
- package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
- package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
- package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
- package/hardhat/types/ethers-contracts/index.ts +6 -0
- package/jsconfig.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +6 -5
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +6 -5
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +18 -164
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +7 -79
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
- package/manifests/deployment/dd-test-development/deployment.yaml +112 -28
- package/manifests/deployment/dd-test-development/proxy.yaml +46 -1
- package/manifests/deployment/playwright/deployment.yaml +1 -1
- package/nodemon.json +1 -1
- package/package.json +39 -24
- package/proxy.yaml +7 -79
- package/scripts/k3s-node-setup.sh +2 -2
- package/scripts/nat-iptables.sh +103 -18
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +58 -14
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +23 -14
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +148 -20
- package/src/api/core/core.controller.js +10 -10
- package/src/api/core/core.service.js +10 -10
- package/src/api/crypto/crypto.controller.js +8 -8
- package/src/api/crypto/crypto.service.js +8 -8
- package/src/api/cyberia-action/cyberia-action.controller.js +74 -0
- package/src/api/cyberia-action/cyberia-action.model.js +87 -0
- package/src/api/cyberia-action/cyberia-action.router.js +27 -0
- package/src/api/cyberia-action/cyberia-action.service.js +42 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +93 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +29 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +51 -0
- package/src/api/cyberia-entity/cyberia-entity.controller.js +74 -0
- package/src/api/cyberia-entity/cyberia-entity.model.js +24 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +27 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +178 -0
- package/src/api/cyberia-instance/cyberia-instance.controller.js +92 -0
- package/src/api/cyberia-instance/cyberia-instance.model.js +87 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +63 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +156 -0
- package/src/api/cyberia-instance/cyberia-portal-connector.js +260 -0
- package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +74 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +574 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +231 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +27 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +46 -0
- package/src/api/cyberia-map/cyberia-map.controller.js +79 -0
- package/src/api/cyberia-map/cyberia-map.model.js +30 -0
- package/src/api/cyberia-map/cyberia-map.router.js +40 -0
- package/src/api/cyberia-map/cyberia-map.service.js +74 -0
- package/src/api/cyberia-quest/cyberia-quest.controller.js +74 -0
- package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +27 -0
- package/src/api/cyberia-quest/cyberia-quest.service.js +42 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +74 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +27 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
- package/src/api/default/default.controller.js +10 -10
- package/src/api/default/default.service.js +10 -10
- package/src/api/document/document.controller.js +12 -12
- package/src/api/document/document.model.js +10 -16
- package/src/api/file/file.controller.js +8 -8
- package/src/api/file/file.model.js +10 -10
- package/src/api/file/file.ref.json +18 -0
- package/src/api/file/file.service.js +36 -36
- package/src/api/instance/instance.controller.js +10 -10
- package/src/api/instance/instance.model.js +4 -10
- package/src/api/instance/instance.service.js +10 -10
- package/src/api/ipfs/ipfs.controller.js +15 -36
- package/src/api/ipfs/ipfs.model.js +47 -47
- package/src/api/ipfs/ipfs.router.js +8 -13
- package/src/api/ipfs/ipfs.service.js +67 -129
- package/src/api/object-layer/object-layer.controller.js +12 -12
- package/src/api/object-layer/object-layer.model.js +4 -17
- package/src/api/object-layer/object-layer.router.js +30 -0
- package/src/api/object-layer/object-layer.service.js +126 -43
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +10 -10
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +6 -16
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +18 -14
- package/src/api/test/test.controller.js +8 -8
- package/src/api/test/test.service.js +8 -8
- package/src/api/user/guest.service.js +99 -0
- package/src/api/user/user.controller.js +6 -6
- package/src/api/user/user.model.js +8 -13
- package/src/api/user/user.service.js +11 -27
- package/src/cli/cluster.js +68 -21
- package/src/cli/db.js +753 -825
- package/src/cli/deploy.js +215 -125
- package/src/cli/env.js +29 -0
- package/src/cli/fs.js +82 -8
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +74 -3
- package/src/cli/kubectl.js +211 -0
- package/src/cli/release.js +340 -0
- package/src/cli/repository.js +475 -74
- package/src/cli/run.js +582 -43
- package/src/cli/secrets.js +73 -0
- package/src/cli/ssh.js +1 -1
- package/src/cli/static.js +43 -115
- package/src/cli/test.js +3 -3
- package/src/client/Cryptokoyn.index.js +18 -22
- package/src/client/CyberiaPortal.index.js +19 -24
- package/src/client/Default.index.js +21 -34
- package/src/client/Itemledger.index.js +20 -27
- package/src/client/Underpost.index.js +19 -24
- package/src/client/components/core/404.js +4 -4
- package/src/client/components/core/500.js +4 -4
- package/src/client/components/core/Account.js +73 -60
- package/src/client/components/core/AgGrid.js +23 -33
- package/src/client/components/core/Alert.js +12 -13
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/Auth.js +35 -37
- package/src/client/components/core/Badge.js +7 -13
- package/src/client/components/core/BtnIcon.js +15 -17
- package/src/client/components/core/CalendarCore.js +43 -64
- package/src/client/components/core/Chat.js +13 -15
- package/src/client/components/core/ClientEvents.js +87 -0
- package/src/client/components/core/ColorPaletteElement.js +309 -0
- package/src/client/components/core/Content.js +17 -14
- package/src/client/components/core/Css.js +15 -71
- package/src/client/components/core/CssCore.js +12 -16
- package/src/client/components/core/D3Chart.js +4 -4
- package/src/client/components/core/Docs.js +64 -91
- package/src/client/components/core/DropDown.js +194 -96
- package/src/client/components/core/EventBus.js +92 -0
- package/src/client/components/core/EventsUI.js +14 -17
- package/src/client/components/core/FileExplorer.js +96 -228
- package/src/client/components/core/FullScreen.js +47 -75
- package/src/client/components/core/Input.js +24 -69
- package/src/client/components/core/Keyboard.js +26 -19
- package/src/client/components/core/KeyboardAvoidance.js +145 -0
- package/src/client/components/core/LoadingAnimation.js +25 -31
- package/src/client/components/core/LogIn.js +43 -43
- package/src/client/components/core/LogOut.js +25 -16
- package/src/client/components/core/Modal.js +462 -179
- package/src/client/components/core/NotificationManager.js +14 -18
- package/src/client/components/core/Panel.js +54 -51
- package/src/client/components/core/PanelForm.js +44 -144
- package/src/client/components/core/Polyhedron.js +110 -214
- package/src/client/components/core/PublicProfile.js +39 -32
- package/src/client/components/core/Recover.js +48 -44
- package/src/client/components/core/Responsive.js +88 -32
- package/src/client/components/core/RichText.js +9 -18
- package/src/client/components/core/Router.js +24 -3
- package/src/client/components/core/SearchBox.js +37 -37
- package/src/client/components/core/SignUp.js +39 -30
- package/src/client/components/core/SocketIo.js +112 -30
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +143 -95
- package/src/client/components/core/ToggleSwitch.js +8 -20
- package/src/client/components/core/ToolTip.js +5 -17
- package/src/client/components/core/Translate.js +56 -59
- package/src/client/components/core/Validator.js +26 -16
- package/src/client/components/core/Wallet.js +15 -26
- package/src/client/components/core/Webhook.js +40 -7
- package/src/client/components/core/Worker.js +163 -27
- package/src/client/components/core/windowGetDimensions.js +7 -7
- package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +59 -59
- package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
- package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +9 -7
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +8 -6
- package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +4 -4
- package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +6 -4
- package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +3 -51
- package/src/client/components/cyberia/InstanceEngineCyberia.js +781 -0
- package/src/client/components/cyberia/MapEngineCyberia.js +1836 -2
- package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +1220 -99
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +252 -316
- package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +136 -103
- package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +462 -32
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +9 -7
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +8 -6
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +4 -4
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +60 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +4 -4
- package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +6 -4
- package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +3 -49
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -4
- package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +91 -91
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/CssDefault.js +12 -12
- package/src/client/components/default/LogInDefault.js +9 -7
- package/src/client/components/default/LogOutDefault.js +8 -6
- package/src/client/components/default/RouterDefault.js +47 -0
- package/src/client/components/default/SettingsDefault.js +4 -4
- package/src/client/components/default/SignUpDefault.js +6 -4
- package/src/client/components/default/SocketIoDefault.js +3 -51
- package/src/client/components/default/TranslateDefault.js +3 -3
- package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +59 -59
- package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
- package/src/client/components/itemledger/CssItemledger.js +15 -15
- package/src/client/components/itemledger/LogInItemledger.js +9 -7
- package/src/client/components/itemledger/LogOutItemledger.js +8 -6
- package/src/client/components/itemledger/RouterItemledger.js +38 -0
- package/src/client/components/itemledger/SettingsItemledger.js +4 -4
- package/src/client/components/itemledger/SignUpItemledger.js +6 -4
- package/src/client/components/itemledger/SocketIoItemledger.js +3 -51
- package/src/client/components/itemledger/TranslateItemledger.js +3 -3
- package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +92 -92
- package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
- package/src/client/components/underpost/CssUnderpost.js +14 -14
- package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +4 -4
- package/src/client/components/underpost/DocumentSearchProvider.js +1 -1
- package/src/client/components/underpost/LabGalleryUnderpost.js +12 -15
- package/src/client/components/underpost/LogInUnderpost.js +9 -7
- package/src/client/components/underpost/LogOutUnderpost.js +8 -6
- package/src/client/components/underpost/RouterUnderpost.js +45 -0
- package/src/client/components/underpost/SettingsUnderpost.js +4 -4
- package/src/client/components/underpost/SignUpUnderpost.js +6 -4
- package/src/client/components/underpost/SocketIoUnderpost.js +3 -51
- package/src/client/components/underpost/TranslateUnderpost.js +4 -4
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +235 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +443 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +417 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +313 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +260 -0
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +241 -0
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +279 -0
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +206 -0
- package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +732 -0
- package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +14 -20
- package/src/client/services/core/core.service.js +35 -55
- package/src/client/services/crypto/crypto.service.js +8 -13
- package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
- package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +99 -0
- package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
- package/src/client/services/cyberia-entity/cyberia-entity.service.js +99 -0
- package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
- package/src/client/services/cyberia-instance/cyberia-instance.service.js +116 -0
- package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +99 -0
- package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
- package/src/client/services/cyberia-map/cyberia-map.service.js +120 -0
- package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
- package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
- package/src/client/services/default/default.management.js +159 -267
- package/src/client/services/default/default.service.js +10 -16
- package/src/client/services/document/document.service.js +14 -19
- package/src/client/services/file/file.service.js +8 -13
- package/src/client/services/instance/instance.management.js +6 -6
- package/src/client/services/instance/instance.service.js +10 -15
- package/src/client/services/ipfs/ipfs.service.js +14 -40
- package/src/client/services/object-layer/object-layer.management.js +14 -14
- package/src/client/services/object-layer/object-layer.service.js +39 -24
- package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +10 -16
- package/src/client/services/test/test.service.js +8 -13
- package/src/client/services/user/guest.service.js +86 -0
- package/src/client/services/user/user.management.js +6 -6
- package/src/client/services/user/user.service.js +14 -20
- package/src/client/ssr/body/404.js +3 -3
- package/src/client/ssr/body/500.js +3 -3
- package/src/client/ssr/body/CacheControl.js +5 -2
- package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +13 -6
- package/src/client/ssr/head/PwaItemledger.js +197 -60
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
- package/src/client/ssr/offline/Maintenance.js +12 -11
- package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
- package/src/client/ssr/pages/CyberiaServerMetrics.js +1 -1
- package/src/client/ssr/pages/Test.js +2 -2
- package/src/client/sw/core.sw.js +212 -0
- package/src/grpc/cyberia/grpc-server.js +642 -0
- package/src/index.js +24 -1
- package/src/runtime/cyberia-client/Dockerfile +80 -0
- package/src/runtime/cyberia-server/Dockerfile +37 -0
- package/src/runtime/express/Dockerfile +5 -1
- package/src/runtime/express/Express.js +18 -1
- package/src/runtime/lampp/Dockerfile +17 -5
- package/src/runtime/lampp/Lampp.js +27 -4
- package/src/runtime/wp/Dockerfile +62 -0
- package/src/runtime/wp/Wp.js +639 -0
- package/src/server/atlas-sprite-sheet-generator.js +4 -2
- package/src/server/auth.js +24 -1
- package/src/server/backup.js +37 -9
- package/src/server/client-build-docs.js +52 -46
- package/src/server/client-build.js +356 -82
- package/src/server/client-formatted.js +140 -57
- package/src/server/conf.js +29 -13
- package/src/server/cron.js +25 -23
- package/src/server/data-query.js +32 -20
- package/src/server/dns.js +24 -1
- package/src/server/ipfs-client.js +253 -89
- package/src/server/object-layer.js +150 -114
- package/src/server/peer.js +8 -0
- package/src/server/process.js +13 -27
- package/src/server/runtime.js +25 -1
- package/src/server/semantic-layer-generator-floor.js +319 -0
- package/src/server/semantic-layer-generator-resource.js +259 -0
- package/src/server/semantic-layer-generator-skin.js +1164 -0
- package/src/server/semantic-layer-generator.js +211 -542
- package/src/server/shape-generator.js +108 -0
- package/src/server/start.js +19 -5
- package/src/server/valkey.js +141 -235
- package/src/ws/IoInterface.js +1 -10
- package/src/ws/IoServer.js +14 -33
- package/src/ws/core/channels/core.ws.chat.js +65 -20
- package/src/ws/core/channels/core.ws.mailer.js +113 -32
- package/src/ws/core/channels/core.ws.stream.js +90 -31
- package/src/ws/core/core.ws.connection.js +12 -33
- package/src/ws/core/core.ws.emit.js +10 -26
- package/src/ws/core/core.ws.server.js +25 -58
- package/src/ws/default/channels/default.ws.main.js +53 -12
- package/src/ws/default/default.ws.connection.js +26 -13
- package/src/ws/default/default.ws.server.js +30 -12
- package/tsconfig.docs.json +15 -0
- package/typedoc.dd-cyberia.json +29 -0
- package/typedoc.json +29 -0
- package/WHITE-PAPER.md +0 -1540
- package/hardhat/README.md +0 -531
- package/hardhat/WHITE-PAPER.md +0 -1540
- package/jsdoc.dd-cyberia.json +0 -59
- package/jsdoc.json +0 -59
- package/src/api/object-layer/README.md +0 -347
- package/src/client/components/core/ColorPalette.js +0 -5267
- package/src/client/components/core/JoyStick.js +0 -80
- package/src/client/components/cryptokoyn/CommonCryptokoyn.js +0 -29
- package/src/client/components/cryptokoyn/ElementsCryptokoyn.js +0 -38
- package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
- package/src/client/components/cyberia-portal/ElementsCyberiaPortal.js +0 -38
- package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -58
- package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
- package/src/client/components/default/ElementsDefault.js +0 -38
- package/src/client/components/default/RoutesDefault.js +0 -49
- package/src/client/components/itemledger/CommonItemledger.js +0 -29
- package/src/client/components/itemledger/ElementsItemledger.js +0 -38
- package/src/client/components/itemledger/RoutesItemledger.js +0 -40
- package/src/client/components/underpost/CommonUnderpost.js +0 -29
- package/src/client/components/underpost/ElementsUnderpost.js +0 -38
- package/src/client/components/underpost/RoutesUnderpost.js +0 -47
- package/src/client/sw/default.sw.js +0 -127
- package/src/client/sw/template.sw.js +0 -84
- package/src/ws/core/management/core.ws.chat.js +0 -8
- package/src/ws/core/management/core.ws.mailer.js +0 -16
- package/src/ws/core/management/core.ws.stream.js +0 -8
- package/src/ws/default/management/default.ws.main.js +0 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CoreService } from '../../services/core/core.service.js';
|
|
2
2
|
import { BtnIcon } from '../core/BtnIcon.js';
|
|
3
|
-
import { borderChar, dynamicCol } from '../core/Css.js';
|
|
3
|
+
import { borderChar, Css, dynamicCol, Themes } from '../core/Css.js';
|
|
4
4
|
import { DropDown } from '../core/DropDown.js';
|
|
5
5
|
import { EventsUI } from '../core/EventsUI.js';
|
|
6
6
|
import { Translate } from '../core/Translate.js';
|
|
@@ -16,22 +16,525 @@ import { Modal } from '../core/Modal.js';
|
|
|
16
16
|
import { LoadingAnimation } from '../core/LoadingAnimation.js';
|
|
17
17
|
import { DefaultManagement } from '../../services/default/default.management.js';
|
|
18
18
|
import * as _ from '../cyberia/ObjectLayerEngine.js';
|
|
19
|
+
import '../core/ColorPaletteElement.js';
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
const CANVAS_BEHAVIOR_ICON = 'fa-solid fa-shapes';
|
|
22
|
+
|
|
23
|
+
const DISTORTION_TYPES = Object.freeze([
|
|
24
|
+
{
|
|
25
|
+
value: 'position-jitter',
|
|
26
|
+
label: 'Position Jitter',
|
|
27
|
+
group: 'distortion',
|
|
28
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'rotation-drift',
|
|
32
|
+
label: 'Rotation Drift',
|
|
33
|
+
group: 'distortion',
|
|
34
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
value: 'scale-wobble',
|
|
38
|
+
label: 'Scale Wobble',
|
|
39
|
+
group: 'distortion',
|
|
40
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: 'particle-drift',
|
|
44
|
+
label: 'Particle Drift',
|
|
45
|
+
group: 'distortion',
|
|
46
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
const MOSAIC_TYPES = Object.freeze([
|
|
51
|
+
{
|
|
52
|
+
value: 'mosaic-diamond-checker',
|
|
53
|
+
label: 'Diamond Checker',
|
|
54
|
+
group: 'mosaic',
|
|
55
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
value: 'mosaic-rhombus-lattice',
|
|
59
|
+
label: 'Rhombus Lattice',
|
|
60
|
+
group: 'mosaic',
|
|
61
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
value: 'mosaic-zigzag-rows',
|
|
65
|
+
label: 'Zigzag Rows',
|
|
66
|
+
group: 'mosaic',
|
|
67
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
value: 'mosaic-staggered-tiles',
|
|
71
|
+
label: 'Staggered Tiles',
|
|
72
|
+
group: 'mosaic',
|
|
73
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
value: 'mosaic-brick-offset',
|
|
77
|
+
label: 'Brick Offset',
|
|
78
|
+
group: 'mosaic',
|
|
79
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
80
|
+
},
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
const CANVAS_BEHAVIORS = Object.freeze([...DISTORTION_TYPES, ...MOSAIC_TYPES]);
|
|
84
|
+
|
|
85
|
+
const DEFAULT_DISTORTION_TYPE = DISTORTION_TYPES[0].value;
|
|
86
|
+
const DEFAULT_DISTORTION_STATUS =
|
|
87
|
+
'Applies the selected canvas behavior directly to the current editor frame. factorA controls distortion density or mosaic tile scale.';
|
|
88
|
+
const DEFAULT_DISTORTION_FACTOR_A = 0.12;
|
|
89
|
+
const DEFAULT_STAT_RANDOM_MIN = 0;
|
|
90
|
+
const DEFAULT_STAT_RANDOM_MAX = 10;
|
|
91
|
+
const UNIFORM_OPACITY_TOGGLE_ID = 'ol-uniform-opacity-lock';
|
|
92
|
+
const DIRECTION_PREVIEW_MODAL_ID = 'modal-object-layer-direction-preview';
|
|
93
|
+
const CANVAS_BEHAVIOR_BY_VALUE = Object.freeze(
|
|
94
|
+
Object.fromEntries(CANVAS_BEHAVIORS.map((entry) => [entry.value, entry])),
|
|
95
|
+
);
|
|
96
|
+
const isMosaicBehavior = (value = '') => CANVAS_BEHAVIOR_BY_VALUE[value]?.group === 'mosaic';
|
|
97
|
+
const getCanvasBehaviorDisplay = (value = DEFAULT_DISTORTION_TYPE) => {
|
|
98
|
+
const behavior = CANVAS_BEHAVIOR_BY_VALUE[value] || CANVAS_BEHAVIOR_BY_VALUE[DEFAULT_DISTORTION_TYPE];
|
|
99
|
+
return `<i class="${CANVAS_BEHAVIOR_ICON}"></i> ${behavior.label}`;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const hashString = (str = '') => {
|
|
103
|
+
let hash = 0;
|
|
104
|
+
for (let i = 0; i < str.length; i++) {
|
|
105
|
+
hash = (Math.imul(31, hash) + str.charCodeAt(i)) | 0;
|
|
106
|
+
}
|
|
107
|
+
return hash;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const clampNumber = (value, min, max) => (value < min ? min : value > max ? max : value);
|
|
111
|
+
const lerp = (start, end, factor) => start + (end - start) * factor;
|
|
112
|
+
const smoothstep = (value) => value * value * (3 - 2 * value);
|
|
113
|
+
const normalizedHash = (seed, x, y) => ((hashString(`${seed}:${x}:${y}`) >>> 0) / 4294967295) * 2 - 1;
|
|
114
|
+
|
|
115
|
+
const sampleSmoothNoise = (seed, x, y) => {
|
|
116
|
+
const x0 = Math.floor(x);
|
|
117
|
+
const y0 = Math.floor(y);
|
|
118
|
+
const x1 = x0 + 1;
|
|
119
|
+
const y1 = y0 + 1;
|
|
120
|
+
|
|
121
|
+
const sx = smoothstep(x - x0);
|
|
122
|
+
const sy = smoothstep(y - y0);
|
|
123
|
+
const n00 = normalizedHash(seed, x0, y0);
|
|
124
|
+
const n10 = normalizedHash(seed, x1, y0);
|
|
125
|
+
const n01 = normalizedHash(seed, x0, y1);
|
|
126
|
+
const n11 = normalizedHash(seed, x1, y1);
|
|
127
|
+
|
|
128
|
+
return lerp(lerp(n00, n10, sx), lerp(n01, n11, sx), sy);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const isVisibleCell = (cell) => Array.isArray(cell) && (cell[3] || 0) > 0;
|
|
132
|
+
const cloneMatrix = (matrix = []) => matrix.map((row) => row.map((cell) => cell.slice()));
|
|
133
|
+
const modulo = (value, divisor) => {
|
|
134
|
+
if (!divisor) return 0;
|
|
135
|
+
return ((value % divisor) + divisor) % divisor;
|
|
136
|
+
};
|
|
137
|
+
const normalizeColorCell = (cell = [255, 0, 0, 255]) => [
|
|
138
|
+
clampNumber(Math.round(cell[0] || 0), 0, 255),
|
|
139
|
+
clampNumber(Math.round(cell[1] || 0), 0, 255),
|
|
140
|
+
clampNumber(Math.round(cell[2] || 0), 0, 255),
|
|
141
|
+
clampNumber(Math.round(cell[3] ?? 255), 0, 255),
|
|
142
|
+
];
|
|
143
|
+
const getRenderedInputNode = (id = '') => s(`.${id}`) || s(`#${id}-name`) || s(`#${id}`);
|
|
144
|
+
|
|
145
|
+
const countChangedCells = (baseMatrix = [], nextMatrix = []) => {
|
|
146
|
+
const height = Math.max(baseMatrix.length, nextMatrix.length);
|
|
147
|
+
const width = Math.max(baseMatrix[0]?.length || 0, nextMatrix[0]?.length || 0);
|
|
148
|
+
let changedCells = 0;
|
|
149
|
+
|
|
150
|
+
for (let y = 0; y < height; y++) {
|
|
151
|
+
for (let x = 0; x < width; x++) {
|
|
152
|
+
const baseCell = baseMatrix[y]?.[x] || [0, 0, 0, 0];
|
|
153
|
+
const nextCell = nextMatrix[y]?.[x] || [0, 0, 0, 0];
|
|
154
|
+
if (
|
|
155
|
+
baseCell[0] !== nextCell[0] ||
|
|
156
|
+
baseCell[1] !== nextCell[1] ||
|
|
157
|
+
baseCell[2] !== nextCell[2] ||
|
|
158
|
+
baseCell[3] !== nextCell[3]
|
|
159
|
+
) {
|
|
160
|
+
changedCells++;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return changedCells;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const deriveMatrixLayerSeed = (matrix = []) => {
|
|
169
|
+
const signature = [];
|
|
170
|
+
for (let y = 0; y < matrix.length; y++) {
|
|
171
|
+
for (let x = 0; x < (matrix[y]?.length || 0); x++) {
|
|
172
|
+
const cell = matrix[y][x];
|
|
173
|
+
if (!isVisibleCell(cell)) continue;
|
|
174
|
+
signature.push(`${x}:${y}:${cell.join(',')}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return hashString(`${matrix[0]?.length || 0}x${matrix.length}:${signature.join('|')}`);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const colorDistance = (left = [0, 0, 0, 0], right = [0, 0, 0, 0]) => {
|
|
181
|
+
const deltaRed = (left[0] - right[0]) / 255;
|
|
182
|
+
const deltaGreen = (left[1] - right[1]) / 255;
|
|
183
|
+
const deltaBlue = (left[2] - right[2]) / 255;
|
|
184
|
+
const deltaAlpha = ((left[3] || 0) - (right[3] || 0)) / 255;
|
|
185
|
+
return (
|
|
186
|
+
Math.sqrt(deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue + deltaAlpha * deltaAlpha * 0.35) /
|
|
187
|
+
1.83
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const getNeighborEntries = (matrix, x, y) => {
|
|
192
|
+
const neighbors = [];
|
|
193
|
+
const sourceCell = matrix[y]?.[x] || [0, 0, 0, 0];
|
|
194
|
+
|
|
195
|
+
for (let offsetY = -1; offsetY <= 1; offsetY++) {
|
|
196
|
+
for (let offsetX = -1; offsetX <= 1; offsetX++) {
|
|
197
|
+
if (offsetX === 0 && offsetY === 0) continue;
|
|
198
|
+
|
|
199
|
+
const neighborX = x + offsetX;
|
|
200
|
+
const neighborY = y + offsetY;
|
|
201
|
+
if (
|
|
202
|
+
neighborY < 0 ||
|
|
203
|
+
neighborX < 0 ||
|
|
204
|
+
neighborY >= matrix.length ||
|
|
205
|
+
neighborX >= (matrix[neighborY]?.length || 0)
|
|
206
|
+
) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const neighborCell = matrix[neighborY][neighborX];
|
|
211
|
+
const visible = isVisibleCell(neighborCell);
|
|
212
|
+
neighbors.push({
|
|
213
|
+
x: neighborX,
|
|
214
|
+
y: neighborY,
|
|
215
|
+
dx: offsetX,
|
|
216
|
+
dy: offsetY,
|
|
217
|
+
cell: neighborCell.slice(),
|
|
218
|
+
visible,
|
|
219
|
+
distance: visible ? colorDistance(sourceCell, neighborCell) : 1,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return neighbors;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const getDistortionTime = (distortionSeed = 0) => (Math.abs(Number(distortionSeed) || 0) % 4096) / 128 + 1;
|
|
228
|
+
|
|
229
|
+
const getDirectionalVector = ({ x, y, width, height, distortionType, frameSeed, distortionSeed }) => {
|
|
230
|
+
const distortionTime = getDistortionTime(distortionSeed);
|
|
231
|
+
const noiseX = sampleSmoothNoise(frameSeed + 211, x * 0.26 + distortionTime * 0.14, y * 0.26 + 1.9);
|
|
232
|
+
const noiseY = sampleSmoothNoise(frameSeed + 263, x * 0.26 + 7.1, y * 0.26 + distortionTime * 0.14);
|
|
233
|
+
const centerX = (width - 1) / 2;
|
|
234
|
+
const centerY = (height - 1) / 2;
|
|
235
|
+
const deltaX = x - centerX;
|
|
236
|
+
const deltaY = y - centerY;
|
|
237
|
+
const radialX = deltaX === 0 ? 0 : deltaX / Math.max(1, Math.abs(deltaX) + Math.abs(deltaY));
|
|
238
|
+
const radialY = deltaY === 0 ? 0 : deltaY / Math.max(1, Math.abs(deltaX) + Math.abs(deltaY));
|
|
239
|
+
|
|
240
|
+
if (distortionType === 'position-jitter') {
|
|
241
|
+
return { dx: noiseX, dy: noiseY };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (distortionType === 'rotation-drift') {
|
|
245
|
+
const tangentDirection = sampleSmoothNoise(frameSeed + 307, distortionTime * 0.24, 3.7) >= 0 ? 1 : -1;
|
|
246
|
+
return {
|
|
247
|
+
dx: tangentDirection * -radialY + noiseX * 0.3,
|
|
248
|
+
dy: tangentDirection * radialX + noiseY * 0.3,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (distortionType === 'scale-wobble') {
|
|
253
|
+
const radialDirection = sampleSmoothNoise(frameSeed + 359, distortionTime * 0.18, 4.6) >= 0 ? 1 : -1;
|
|
254
|
+
return {
|
|
255
|
+
dx: radialX * radialDirection + noiseX * 0.2,
|
|
256
|
+
dy: radialY * radialDirection + noiseY * 0.2,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
dx: (noiseX >= 0 ? 0.6 : -0.6) + noiseX * 0.6,
|
|
262
|
+
dy: (noiseY >= 0 ? 0.6 : -0.6) + noiseY * 0.6,
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const collectVisibleCells = (matrix = [], layerSeed, frameSeed, distortionType, distortionSeed) => {
|
|
267
|
+
const distortionTime = getDistortionTime(distortionSeed);
|
|
268
|
+
const visibleCells = [];
|
|
269
|
+
|
|
270
|
+
for (let y = 0; y < matrix.length; y++) {
|
|
271
|
+
for (let x = 0; x < (matrix[y]?.length || 0); x++) {
|
|
272
|
+
const cell = matrix[y][x];
|
|
273
|
+
if (!isVisibleCell(cell)) continue;
|
|
274
|
+
|
|
275
|
+
const neighbors = getNeighborEntries(matrix, x, y);
|
|
276
|
+
const visibleNeighbors = neighbors.filter((neighbor) => neighbor.visible);
|
|
277
|
+
const edgeScore = neighbors.some((neighbor) => !neighbor.visible) ? 1 : 0;
|
|
278
|
+
const variationScore = visibleNeighbors.length
|
|
279
|
+
? visibleNeighbors.reduce((sum, neighbor) => {
|
|
280
|
+
if (neighbor.distance < 0.01) return sum + 0.04;
|
|
281
|
+
if (neighbor.distance <= 0.35) return sum + (1 - Math.abs(neighbor.distance - 0.14) / 0.21);
|
|
282
|
+
if (neighbor.distance <= 0.55) return sum + 0.18;
|
|
283
|
+
return sum + 0.04;
|
|
284
|
+
}, 0) / visibleNeighbors.length
|
|
285
|
+
: 0;
|
|
286
|
+
|
|
287
|
+
const activity = (sampleSmoothNoise(frameSeed + 401, x * 0.24 + distortionTime * 0.1, y * 0.24 + 2.7) + 1) / 2;
|
|
288
|
+
const stabilityBias = 1 - (hashString(`${layerSeed}:${distortionType}:${x}:${y}`) >>> 0) / 4294967295;
|
|
289
|
+
|
|
290
|
+
visibleCells.push({
|
|
291
|
+
x,
|
|
292
|
+
y,
|
|
293
|
+
cell: cell.slice(),
|
|
294
|
+
neighbors,
|
|
295
|
+
edgeScore,
|
|
296
|
+
variationScore,
|
|
297
|
+
score: variationScore * 0.58 + edgeScore * 0.2 + activity * 0.18 + stabilityBias * 0.04,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return visibleCells.sort((left, right) => right.score - left.score);
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const chooseDistortionTarget = ({ entry, matrix, distortionType, frameSeed, distortionSeed, reservedCells }) => {
|
|
306
|
+
const width = matrix[0]?.length || 0;
|
|
307
|
+
const height = matrix.length;
|
|
308
|
+
const vector = getDirectionalVector({
|
|
309
|
+
x: entry.x,
|
|
310
|
+
y: entry.y,
|
|
311
|
+
width,
|
|
312
|
+
height,
|
|
313
|
+
distortionType,
|
|
314
|
+
frameSeed,
|
|
315
|
+
distortionSeed,
|
|
316
|
+
});
|
|
317
|
+
const vectorLength = Math.hypot(vector.dx, vector.dy) || 1;
|
|
318
|
+
|
|
319
|
+
return [...entry.neighbors]
|
|
320
|
+
.map((neighbor) => {
|
|
321
|
+
const alignment =
|
|
322
|
+
(neighbor.dx * vector.dx + neighbor.dy * vector.dy) /
|
|
323
|
+
((Math.hypot(neighbor.dx, neighbor.dy) || 1) * vectorLength);
|
|
324
|
+
let score = alignment * 0.55;
|
|
325
|
+
|
|
326
|
+
if (!neighbor.visible) {
|
|
327
|
+
score += 0.22 + entry.edgeScore * 0.16;
|
|
328
|
+
} else if (neighbor.distance >= 0.01 && neighbor.distance <= 0.38) {
|
|
329
|
+
score += 0.34 + (0.38 - neighbor.distance) * 0.45;
|
|
330
|
+
} else {
|
|
331
|
+
score -= 0.2;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (distortionType === 'particle-drift' && Math.abs(neighbor.dx) === 1 && Math.abs(neighbor.dy) === 1) {
|
|
335
|
+
score += 0.16;
|
|
336
|
+
}
|
|
337
|
+
if (distortionType === 'rotation-drift' && Math.abs(neighbor.dx) + Math.abs(neighbor.dy) === 1) {
|
|
338
|
+
score += 0.06;
|
|
339
|
+
}
|
|
340
|
+
if (distortionType === 'scale-wobble' && !neighbor.visible) {
|
|
341
|
+
score += 0.08;
|
|
342
|
+
}
|
|
343
|
+
if (reservedCells.has(`${neighbor.x}:${neighbor.y}`)) {
|
|
344
|
+
score = -Infinity;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return { ...neighbor, score };
|
|
348
|
+
})
|
|
349
|
+
.sort((left, right) => right.score - left.score)
|
|
350
|
+
.find((candidate) => candidate.score > 0.02);
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
const buildDistortedMatrix = (
|
|
354
|
+
baseMatrix,
|
|
355
|
+
distortionType,
|
|
356
|
+
factorA = DEFAULT_DISTORTION_FACTOR_A,
|
|
357
|
+
distortionSeed = Date.now(),
|
|
358
|
+
) => {
|
|
359
|
+
const layerSeed = deriveMatrixLayerSeed(baseMatrix);
|
|
360
|
+
const normalizedSeed = Number.isFinite(distortionSeed) ? distortionSeed : hashString(String(distortionSeed));
|
|
361
|
+
const frameSeed = hashString(`${layerSeed}:${distortionType}:${normalizedSeed}`);
|
|
362
|
+
const visibleCells = collectVisibleCells(baseMatrix, layerSeed, frameSeed, distortionType, normalizedSeed);
|
|
363
|
+
const result = cloneMatrix(baseMatrix);
|
|
364
|
+
|
|
365
|
+
if (!visibleCells.length) {
|
|
366
|
+
return { matrix: result, changedCells: 0, appliedDistortions: 0, layerSeed, frameSeed };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const densityFactor = clampNumber(Number.isFinite(factorA) ? factorA : DEFAULT_DISTORTION_FACTOR_A, 0.01, 1);
|
|
370
|
+
const maxBudget = Math.max(1, Math.round(visibleCells.length * 0.35));
|
|
371
|
+
const distortionBudget = clampNumber(Math.round(visibleCells.length * densityFactor), 1, maxBudget);
|
|
372
|
+
const reservedCells = new Set();
|
|
373
|
+
let appliedDistortions = 0;
|
|
374
|
+
|
|
375
|
+
for (const entry of visibleCells) {
|
|
376
|
+
if (appliedDistortions >= distortionBudget) break;
|
|
377
|
+
|
|
378
|
+
const sourceKey = `${entry.x}:${entry.y}`;
|
|
379
|
+
if (reservedCells.has(sourceKey)) continue;
|
|
380
|
+
|
|
381
|
+
const target = chooseDistortionTarget({
|
|
382
|
+
entry,
|
|
383
|
+
matrix: baseMatrix,
|
|
384
|
+
distortionType,
|
|
385
|
+
frameSeed,
|
|
386
|
+
distortionSeed: normalizedSeed,
|
|
387
|
+
reservedCells,
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
if (!target) continue;
|
|
391
|
+
|
|
392
|
+
if (target.visible) {
|
|
393
|
+
const nextCell = result[target.y][target.x].slice();
|
|
394
|
+
result[target.y][target.x] = entry.cell.slice();
|
|
395
|
+
result[entry.y][entry.x] = nextCell;
|
|
396
|
+
} else {
|
|
397
|
+
result[target.y][target.x] = entry.cell.slice();
|
|
398
|
+
result[entry.y][entry.x] = [0, 0, 0, 0];
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
reservedCells.add(sourceKey);
|
|
402
|
+
reservedCells.add(`${target.x}:${target.y}`);
|
|
403
|
+
appliedDistortions++;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
let changedCells = countChangedCells(baseMatrix, result);
|
|
407
|
+
|
|
408
|
+
if (changedCells === 0) {
|
|
409
|
+
for (const entry of visibleCells) {
|
|
410
|
+
const transparentTarget = entry.neighbors.find((neighbor) => !neighbor.visible);
|
|
411
|
+
if (!transparentTarget) continue;
|
|
412
|
+
result[transparentTarget.y][transparentTarget.x] = entry.cell.slice();
|
|
413
|
+
result[entry.y][entry.x] = [0, 0, 0, 0];
|
|
414
|
+
appliedDistortions = 1;
|
|
415
|
+
changedCells = countChangedCells(baseMatrix, result);
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return {
|
|
421
|
+
matrix: result,
|
|
422
|
+
changedCells,
|
|
423
|
+
appliedDistortions,
|
|
424
|
+
densityFactor,
|
|
425
|
+
layerSeed,
|
|
426
|
+
frameSeed,
|
|
427
|
+
};
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const getMosaicTileSize = (width, height, factorA = DEFAULT_DISTORTION_FACTOR_A) => {
|
|
431
|
+
const minDimension = Math.max(1, Math.min(width, height));
|
|
432
|
+
const normalizedFactor = clampNumber(Number.isFinite(factorA) ? factorA : DEFAULT_DISTORTION_FACTOR_A, 0.01, 1);
|
|
433
|
+
return clampNumber(
|
|
434
|
+
Math.round(1 + normalizedFactor * Math.max(2, Math.min(10, Math.floor(minDimension / 2)))),
|
|
435
|
+
1,
|
|
436
|
+
minDimension,
|
|
437
|
+
);
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const buildMosaicMatrix = (
|
|
441
|
+
baseMatrix,
|
|
442
|
+
mosaicType,
|
|
443
|
+
factorA = DEFAULT_DISTORTION_FACTOR_A,
|
|
444
|
+
brushCell = [255, 0, 0, 255],
|
|
445
|
+
) => {
|
|
446
|
+
const height = baseMatrix.length;
|
|
447
|
+
const width = baseMatrix[0]?.length || 0;
|
|
448
|
+
const result = cloneMatrix(baseMatrix);
|
|
449
|
+
|
|
450
|
+
if (!height || !width) {
|
|
451
|
+
return { matrix: result, changedCells: 0, paintedCells: 0, tileSize: 1 };
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const tileSize = getMosaicTileSize(width, height, factorA);
|
|
455
|
+
const gap = Math.max(1, Math.floor(tileSize / 2));
|
|
456
|
+
const thickness = Math.max(1, Math.ceil(tileSize / 3));
|
|
457
|
+
const paintCell = normalizeColorCell(brushCell);
|
|
458
|
+
let paintedCells = 0;
|
|
459
|
+
|
|
460
|
+
const shouldPaint = (x, y) => {
|
|
461
|
+
switch (mosaicType) {
|
|
462
|
+
case 'mosaic-diamond-checker': {
|
|
463
|
+
const span = tileSize * 2 + gap;
|
|
464
|
+
const tileX = Math.floor(x / span);
|
|
465
|
+
const tileY = Math.floor(y / span);
|
|
466
|
+
if ((tileX + tileY) % 2 !== 0) return false;
|
|
467
|
+
const localX = modulo(x, span) - tileSize;
|
|
468
|
+
const localY = modulo(y, span) - tileSize;
|
|
469
|
+
return Math.abs(localX) + Math.abs(localY) <= tileSize - 1;
|
|
470
|
+
}
|
|
471
|
+
case 'mosaic-rhombus-lattice': {
|
|
472
|
+
const period = tileSize * 2 + gap;
|
|
473
|
+
const diagonalA = modulo(x + y, period);
|
|
474
|
+
const diagonalB = modulo(x - y, period);
|
|
475
|
+
return diagonalA < thickness || diagonalB < thickness;
|
|
476
|
+
}
|
|
477
|
+
case 'mosaic-zigzag-rows': {
|
|
478
|
+
const zigzagWidth = Math.max(2, tileSize * 2 + gap);
|
|
479
|
+
const bandHeight = Math.max(1, tileSize);
|
|
480
|
+
const rowIndex = Math.floor(y / bandHeight);
|
|
481
|
+
const localX = modulo(x + (rowIndex % 2) * tileSize, zigzagWidth);
|
|
482
|
+
const ridge = modulo(y, bandHeight);
|
|
483
|
+
return Math.abs(localX - ridge) < thickness || Math.abs(localX - (zigzagWidth - ridge - 1)) < thickness;
|
|
484
|
+
}
|
|
485
|
+
case 'mosaic-staggered-tiles': {
|
|
486
|
+
const step = tileSize + gap;
|
|
487
|
+
const rowIndex = Math.floor(y / step);
|
|
488
|
+
const localX = modulo(x + (rowIndex % 2) * Math.floor(step / 2), step);
|
|
489
|
+
const localY = modulo(y, step);
|
|
490
|
+
return localX < tileSize && localY < tileSize;
|
|
491
|
+
}
|
|
492
|
+
case 'mosaic-brick-offset': {
|
|
493
|
+
const brickWidth = tileSize * 2 + gap;
|
|
494
|
+
const brickHeight = tileSize + gap;
|
|
495
|
+
const rowIndex = Math.floor(y / brickHeight);
|
|
496
|
+
const localX = modulo(x + (rowIndex % 2) * Math.floor(brickWidth / 2), brickWidth);
|
|
497
|
+
const localY = modulo(y, brickHeight);
|
|
498
|
+
return localX < brickWidth - gap && localY < tileSize;
|
|
499
|
+
}
|
|
500
|
+
default:
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
for (let y = 0; y < height; y++) {
|
|
506
|
+
for (let x = 0; x < width; x++) {
|
|
507
|
+
if (!shouldPaint(x, y)) continue;
|
|
508
|
+
paintedCells++;
|
|
509
|
+
result[y][x] = paintCell.slice();
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return {
|
|
514
|
+
matrix: result,
|
|
515
|
+
changedCells: countChangedCells(baseMatrix, result),
|
|
516
|
+
paintedCells,
|
|
517
|
+
tileSize,
|
|
518
|
+
};
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
class ObjectLayerEngineModal {
|
|
522
|
+
static selectItemType = 'skin';
|
|
523
|
+
static itemActivable = false;
|
|
524
|
+
static renderFrameDuration = 100;
|
|
525
|
+
static existingObjectLayerId = null;
|
|
526
|
+
static originalDirectionCodes = [];
|
|
527
|
+
static selectedDistortionType = DEFAULT_DISTORTION_TYPE;
|
|
528
|
+
static distortionFactorA = DEFAULT_DISTORTION_FACTOR_A;
|
|
529
|
+
static uniformOpacityEnabled = false;
|
|
530
|
+
static templates = [
|
|
28
531
|
{
|
|
29
532
|
label: 'empty',
|
|
30
533
|
id: 'empty',
|
|
31
534
|
data: [],
|
|
32
535
|
},
|
|
33
|
-
]
|
|
34
|
-
statDescriptions
|
|
536
|
+
];
|
|
537
|
+
static statDescriptions = {
|
|
35
538
|
effect: {
|
|
36
539
|
title: 'Effect',
|
|
37
540
|
icon: 'fa-solid fa-burst',
|
|
@@ -69,9 +572,9 @@ const ObjectLayerEngineModal = {
|
|
|
69
572
|
description: 'Reduces the cooldown time between actions, allowing for more frequent actions.',
|
|
70
573
|
detail: 'It also increases the chance to trigger life-regeneration events.',
|
|
71
574
|
},
|
|
72
|
-
}
|
|
575
|
+
};
|
|
73
576
|
|
|
74
|
-
RenderTemplate
|
|
577
|
+
static RenderTemplate = (colorTemplate) => {
|
|
75
578
|
const ole = s('object-layer-engine');
|
|
76
579
|
if (!ole) {
|
|
77
580
|
return;
|
|
@@ -84,17 +587,20 @@ const ObjectLayerEngineModal = {
|
|
|
84
587
|
|
|
85
588
|
const matrix = colorTemplate.map((row) => row.map((hex) => [...hexToRgbA(hex), 255]));
|
|
86
589
|
ole.loadMatrix(matrix);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
static ObjectLayerData = {};
|
|
593
|
+
|
|
594
|
+
static clearData() {
|
|
91
595
|
this.ObjectLayerData = {};
|
|
92
596
|
this.selectItemType = 'skin';
|
|
93
597
|
this.itemActivable = false;
|
|
94
|
-
this.renderIsStateless = false;
|
|
95
598
|
this.renderFrameDuration = 100;
|
|
96
599
|
this.existingObjectLayerId = null;
|
|
97
600
|
this.originalDirectionCodes = [];
|
|
601
|
+
this.selectedDistortionType = DEFAULT_DISTORTION_TYPE;
|
|
602
|
+
this.distortionFactorA = DEFAULT_DISTORTION_FACTOR_A;
|
|
603
|
+
this.uniformOpacityEnabled = false;
|
|
98
604
|
this.templates = [
|
|
99
605
|
{
|
|
100
606
|
label: 'empty',
|
|
@@ -103,13 +609,11 @@ const ObjectLayerEngineModal = {
|
|
|
103
609
|
},
|
|
104
610
|
];
|
|
105
611
|
|
|
106
|
-
// Clear the canvas if it exists
|
|
107
612
|
const ole = s('object-layer-engine');
|
|
108
613
|
if (ole && typeof ole.clear === 'function') {
|
|
109
614
|
ole.clear();
|
|
110
615
|
}
|
|
111
616
|
|
|
112
|
-
// Clear all frame previews from DOM for all direction codes
|
|
113
617
|
const directionCodes = ['08', '18', '02', '12', '04', '14', '06', '16'];
|
|
114
618
|
for (const directionCode of directionCodes) {
|
|
115
619
|
const framesContainer = s(`.frames-${directionCode}`);
|
|
@@ -132,24 +636,42 @@ const ObjectLayerEngineModal = {
|
|
|
132
636
|
const activableCheckbox = s('#ol-toggle-item-activable');
|
|
133
637
|
if (activableCheckbox) activableCheckbox.checked = false;
|
|
134
638
|
|
|
135
|
-
const statelessCheckbox = s('#ol-toggle-render-is-stateless');
|
|
136
|
-
if (statelessCheckbox) statelessCheckbox.checked = false;
|
|
137
|
-
|
|
138
639
|
// Clear stat inputs with correct IDs
|
|
139
640
|
const statTypes = Object.keys(ObjectLayerEngineModal.statDescriptions);
|
|
140
641
|
for (const stat of statTypes) {
|
|
141
|
-
const statInput =
|
|
642
|
+
const statInput = getRenderedInputNode(`ol-input-item-stats-${stat}`);
|
|
142
643
|
if (statInput) statInput.value = '0';
|
|
143
644
|
}
|
|
144
645
|
|
|
646
|
+
const statRandomMinInput = getRenderedInputNode('ol-input-stats-random-min');
|
|
647
|
+
if (statRandomMinInput) statRandomMinInput.value = String(DEFAULT_STAT_RANDOM_MIN);
|
|
648
|
+
|
|
649
|
+
const statRandomMaxInput = getRenderedInputNode('ol-input-stats-random-max');
|
|
650
|
+
if (statRandomMaxInput) statRandomMaxInput.value = String(DEFAULT_STAT_RANDOM_MAX);
|
|
651
|
+
|
|
145
652
|
// Clear DropDown displays
|
|
146
653
|
const templateDropdownCurrent = s(`.dropdown-current-ol-dropdown-template`);
|
|
147
654
|
if (templateDropdownCurrent) templateDropdownCurrent.innerHTML = '';
|
|
148
655
|
|
|
149
656
|
const itemTypeDropdownCurrent = s(`.dropdown-current-ol-dropdown-item-type`);
|
|
150
657
|
if (itemTypeDropdownCurrent) itemTypeDropdownCurrent.innerHTML = 'skin';
|
|
151
|
-
|
|
152
|
-
|
|
658
|
+
|
|
659
|
+
const distortionDropdownCurrent = s(`.dropdown-current-ol-dropdown-distortion-type`);
|
|
660
|
+
if (distortionDropdownCurrent) {
|
|
661
|
+
distortionDropdownCurrent.innerHTML = getCanvasBehaviorDisplay(DEFAULT_DISTORTION_TYPE);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const distortionFactorInput = s('#ol-input-distortion-factor-a') || s('.ol-input-distortion-factor-a');
|
|
665
|
+
if (distortionFactorInput) distortionFactorInput.value = String(DEFAULT_DISTORTION_FACTOR_A);
|
|
666
|
+
|
|
667
|
+
const distortionStatusNode = s(`.ol-distortion-status`);
|
|
668
|
+
if (distortionStatusNode) {
|
|
669
|
+
distortionStatusNode.style.color = '#888';
|
|
670
|
+
distortionStatusNode.innerHTML = DEFAULT_DISTORTION_STATUS;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
static loadFromDatabase = async (objectLayerId) => {
|
|
153
675
|
try {
|
|
154
676
|
// Load metadata first (lightweight)
|
|
155
677
|
const { status: metaStatus, data: metadata } = await ObjectLayerService.getMetadata({ id: objectLayerId });
|
|
@@ -184,12 +706,13 @@ const ObjectLayerEngineModal = {
|
|
|
184
706
|
});
|
|
185
707
|
return null;
|
|
186
708
|
}
|
|
187
|
-
}
|
|
188
|
-
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
static instance = async (options = { idModal: '', appStore: {} }) => {
|
|
189
712
|
// Clear all cached data at the start of each render to prevent contamination
|
|
190
713
|
ObjectLayerEngineModal.clearData();
|
|
191
714
|
|
|
192
|
-
const {
|
|
715
|
+
const { appStore } = options;
|
|
193
716
|
|
|
194
717
|
const directionCodes = ['08', '18', '02', '12', '04', '14', '06', '16'];
|
|
195
718
|
const directionCodeLabels = {
|
|
@@ -202,8 +725,14 @@ const ObjectLayerEngineModal = {
|
|
|
202
725
|
'06': 'Right Idle',
|
|
203
726
|
16: 'Right Walk',
|
|
204
727
|
};
|
|
205
|
-
const itemTypes = ['skin', 'weapon', 'armor', 'artifact', 'floor'];
|
|
728
|
+
const itemTypes = ['skin', 'weapon', 'armor', 'artifact', 'floor', 'resource', 'obstacle', 'foreground', 'portal'];
|
|
206
729
|
const statTypes = ['effect', 'resistance', 'agility', 'range', 'intelligence', 'utility'];
|
|
730
|
+
const distortionDropdownId = 'ol-dropdown-distortion-type';
|
|
731
|
+
const distortionApplyBtnClass = 'ol-btn-apply-distortion';
|
|
732
|
+
const distortionStatusClass = 'ol-distortion-status';
|
|
733
|
+
const statsRandomizeBtnClass = 'ol-btn-randomize-stats';
|
|
734
|
+
const statsRandomMinInputId = 'ol-input-stats-random-min';
|
|
735
|
+
const statsRandomMaxInputId = 'ol-input-stats-random-max';
|
|
207
736
|
|
|
208
737
|
// Check if we have an 'id' query parameter to load existing object layer
|
|
209
738
|
const queryParams = getQueryParams();
|
|
@@ -213,6 +742,130 @@ const ObjectLayerEngineModal = {
|
|
|
213
742
|
let editingFrameId = null;
|
|
214
743
|
let editingDirectionCode = null;
|
|
215
744
|
|
|
745
|
+
const readDistortionFactorA = () => {
|
|
746
|
+
const factorInput = s('.ol-input-distortion-factor-a') || s('#ol-input-distortion-factor-a');
|
|
747
|
+
const parsedFactor = Number.parseFloat(factorInput?.value);
|
|
748
|
+
const normalizedFactor = clampNumber(
|
|
749
|
+
Number.isFinite(parsedFactor)
|
|
750
|
+
? parsedFactor
|
|
751
|
+
: ObjectLayerEngineModal.distortionFactorA || DEFAULT_DISTORTION_FACTOR_A,
|
|
752
|
+
0.01,
|
|
753
|
+
1,
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
ObjectLayerEngineModal.distortionFactorA = normalizedFactor;
|
|
757
|
+
if (factorInput) {
|
|
758
|
+
factorInput.value = String(Math.round(normalizedFactor * 100) / 100);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return normalizedFactor;
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
const readRandomStatBounds = () => {
|
|
765
|
+
const minInput = getRenderedInputNode(statsRandomMinInputId);
|
|
766
|
+
const maxInput = getRenderedInputNode(statsRandomMaxInputId);
|
|
767
|
+
let minValue = Number.parseInt(minInput?.value, 10);
|
|
768
|
+
let maxValue = Number.parseInt(maxInput?.value, 10);
|
|
769
|
+
|
|
770
|
+
minValue = clampNumber(Number.isFinite(minValue) ? minValue : DEFAULT_STAT_RANDOM_MIN, 0, 10);
|
|
771
|
+
maxValue = clampNumber(Number.isFinite(maxValue) ? maxValue : DEFAULT_STAT_RANDOM_MAX, 0, 10);
|
|
772
|
+
|
|
773
|
+
if (minValue > maxValue) {
|
|
774
|
+
const nextMin = maxValue;
|
|
775
|
+
maxValue = minValue;
|
|
776
|
+
minValue = nextMin;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (minInput) minInput.value = String(minValue);
|
|
780
|
+
if (maxInput) maxInput.value = String(maxValue);
|
|
781
|
+
|
|
782
|
+
return { minValue, maxValue };
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
const randomizeStatInputs = () => {
|
|
786
|
+
const { minValue, maxValue } = readRandomStatBounds();
|
|
787
|
+
|
|
788
|
+
for (const statType of statTypes) {
|
|
789
|
+
const statInput = getRenderedInputNode(`ol-input-item-stats-${statType}`);
|
|
790
|
+
if (!statInput) continue;
|
|
791
|
+
|
|
792
|
+
const randomValue = Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
|
|
793
|
+
statInput.value = String(randomValue);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
NotificationManager.Push({
|
|
797
|
+
html: `Stats randomized between ${minValue} and ${maxValue}.`,
|
|
798
|
+
status: 'success',
|
|
799
|
+
});
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
let uniformOpacitySyncInProgress = false;
|
|
803
|
+
|
|
804
|
+
const buildUniformOpacityMatrix = (matrix = [], targetAlpha = 255) => {
|
|
805
|
+
const clampedAlpha = clampNumber(Number(targetAlpha) || 0, 0, 255);
|
|
806
|
+
let changedCells = 0;
|
|
807
|
+
const nextMatrix = matrix.map((row) =>
|
|
808
|
+
row.map((cell) => {
|
|
809
|
+
const nextCell = cell.slice();
|
|
810
|
+
if (isVisibleCell(nextCell) && nextCell[3] !== clampedAlpha) {
|
|
811
|
+
nextCell[3] = clampedAlpha;
|
|
812
|
+
changedCells++;
|
|
813
|
+
}
|
|
814
|
+
return nextCell;
|
|
815
|
+
}),
|
|
816
|
+
);
|
|
817
|
+
|
|
818
|
+
return { matrix: nextMatrix, changedCells, alpha: clampedAlpha };
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
const applyUniformOpacityToEditor = ({ captureUndo = false } = {}) => {
|
|
822
|
+
const ole = s('object-layer-engine');
|
|
823
|
+
if (!ole || !ObjectLayerEngineModal.uniformOpacityEnabled || uniformOpacitySyncInProgress) return false;
|
|
824
|
+
|
|
825
|
+
let currentFrame = null;
|
|
826
|
+
try {
|
|
827
|
+
const exportedMatrix = ole.exportMatrixJSON();
|
|
828
|
+
currentFrame = typeof exportedMatrix === 'string' ? JSON.parse(exportedMatrix) : exportedMatrix;
|
|
829
|
+
} catch (error) {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
const currentMatrix = currentFrame?.matrix;
|
|
834
|
+
if (!Array.isArray(currentMatrix) || !currentMatrix.length || !currentMatrix[0]?.length) {
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const targetAlpha = clampNumber(ole.getBrushAlpha?.() ?? ole.getBrushColor?.()?.[3] ?? 255, 0, 255);
|
|
839
|
+
const nextFrame = buildUniformOpacityMatrix(currentMatrix, targetAlpha);
|
|
840
|
+
if (!nextFrame.changedCells) return false;
|
|
841
|
+
|
|
842
|
+
const nextSnapshot = {
|
|
843
|
+
width: currentFrame.width || currentMatrix[0].length,
|
|
844
|
+
height: currentFrame.height || currentMatrix.length,
|
|
845
|
+
matrix: nextFrame.matrix,
|
|
846
|
+
};
|
|
847
|
+
const beforeSnapshot = captureUndo && typeof ole._snapshot === 'function' ? ole._snapshot() : null;
|
|
848
|
+
|
|
849
|
+
if (
|
|
850
|
+
captureUndo &&
|
|
851
|
+
beforeSnapshot &&
|
|
852
|
+
typeof ole._pushUndo === 'function' &&
|
|
853
|
+
typeof ole._matricesEqual === 'function' &&
|
|
854
|
+
!ole._matricesEqual(beforeSnapshot, nextSnapshot)
|
|
855
|
+
) {
|
|
856
|
+
ole._pushUndo(beforeSnapshot);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
uniformOpacitySyncInProgress = true;
|
|
860
|
+
try {
|
|
861
|
+
ole.loadMatrix(nextFrame.matrix);
|
|
862
|
+
} finally {
|
|
863
|
+
uniformOpacitySyncInProgress = false;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
return true;
|
|
867
|
+
};
|
|
868
|
+
|
|
216
869
|
// Helper function to update UI when entering edit mode
|
|
217
870
|
const enterEditMode = (frameId, directionCode) => {
|
|
218
871
|
editingFrameId = frameId;
|
|
@@ -331,7 +984,6 @@ const ObjectLayerEngineModal = {
|
|
|
331
984
|
}
|
|
332
985
|
}
|
|
333
986
|
if (objectLayerRenderFramesId) {
|
|
334
|
-
ObjectLayerEngineModal.renderIsStateless = objectLayerRenderFramesId.is_stateless || false;
|
|
335
987
|
ObjectLayerEngineModal.renderFrameDuration = objectLayerRenderFramesId.frame_duration || 100;
|
|
336
988
|
}
|
|
337
989
|
}
|
|
@@ -352,10 +1004,169 @@ const ObjectLayerEngineModal = {
|
|
|
352
1004
|
}
|
|
353
1005
|
}
|
|
354
1006
|
|
|
355
|
-
|
|
356
|
-
|
|
1007
|
+
let cellsW = 26;
|
|
1008
|
+
let cellsH = 26;
|
|
1009
|
+
if (loadedData && loadedData.objectLayerRenderFramesId && loadedData.objectLayerRenderFramesId.frames) {
|
|
1010
|
+
const frames = loadedData.objectLayerRenderFramesId.frames;
|
|
1011
|
+
for (const direction of Object.keys(frames)) {
|
|
1012
|
+
if (frames[direction] && frames[direction].length > 0 && frames[direction][0].length > 0) {
|
|
1013
|
+
cellsH = frames[direction][0].length;
|
|
1014
|
+
cellsW = frames[direction][0][0].length;
|
|
1015
|
+
break;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
const pixelSize = parseInt(320 / Math.max(cellsW, cellsH));
|
|
357
1020
|
const idSectionA = 'template-section-a';
|
|
358
1021
|
const idSectionB = 'template-section-b';
|
|
1022
|
+
const colorPaletteClass = 'ol-color-palette';
|
|
1023
|
+
let directionPreviewRuntime = null;
|
|
1024
|
+
|
|
1025
|
+
const cleanupDirectionPreviewRuntime = () => {
|
|
1026
|
+
if (!directionPreviewRuntime) return;
|
|
1027
|
+
if (directionPreviewRuntime.intervalId) {
|
|
1028
|
+
clearInterval(directionPreviewRuntime.intervalId);
|
|
1029
|
+
}
|
|
1030
|
+
for (const frameUrl of directionPreviewRuntime.frameUrls || []) {
|
|
1031
|
+
URL.revokeObjectURL(frameUrl);
|
|
1032
|
+
}
|
|
1033
|
+
directionPreviewRuntime = null;
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
const cleanupDirectionPreviewModal = () => {
|
|
1037
|
+
cleanupDirectionPreviewRuntime();
|
|
1038
|
+
if (s(`.${DIRECTION_PREVIEW_MODAL_ID}`)) {
|
|
1039
|
+
Modal.removeModal(DIRECTION_PREVIEW_MODAL_ID);
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
if (Modal.Data[options.idModal]) {
|
|
1044
|
+
Modal.Data[options.idModal].onCloseListener[`${options.idModal}-direction-preview-cleanup`] = () => {
|
|
1045
|
+
cleanupDirectionPreviewModal();
|
|
1046
|
+
delete Modal.Data[options.idModal]?.onCloseListener?.[`${options.idModal}-direction-preview-cleanup`];
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
const getCurrentFrameDuration = () => {
|
|
1051
|
+
const durationInput = s('.ol-input-render-frame-duration') || s('#ol-input-render-frame-duration');
|
|
1052
|
+
const parsedDuration = Number.parseInt(durationInput?.value, 10);
|
|
1053
|
+
return Math.max(
|
|
1054
|
+
100,
|
|
1055
|
+
Number.isFinite(parsedDuration) ? parsedDuration : ObjectLayerEngineModal.renderFrameDuration || 100,
|
|
1056
|
+
);
|
|
1057
|
+
};
|
|
1058
|
+
|
|
1059
|
+
const openDirectionPreviewModal = async (directionCode) => {
|
|
1060
|
+
const frames = ObjectLayerEngineModal.ObjectLayerData[directionCode] || [];
|
|
1061
|
+
if (!frames.length) {
|
|
1062
|
+
NotificationManager.Push({
|
|
1063
|
+
html: `No frames available yet for ${directionCodeLabels[directionCode] || directionCode}.`,
|
|
1064
|
+
status: 'warning',
|
|
1065
|
+
});
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
const frameUrls = frames
|
|
1070
|
+
.map((frame) => {
|
|
1071
|
+
if (!frame?.image) return null;
|
|
1072
|
+
return URL.createObjectURL(frame.image);
|
|
1073
|
+
})
|
|
1074
|
+
.filter(Boolean);
|
|
1075
|
+
|
|
1076
|
+
if (!frameUrls.length) {
|
|
1077
|
+
NotificationManager.Push({
|
|
1078
|
+
html: `Could not build a local preview for ${directionCodeLabels[directionCode] || directionCode}.`,
|
|
1079
|
+
status: 'error',
|
|
1080
|
+
});
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
cleanupDirectionPreviewModal();
|
|
1085
|
+
|
|
1086
|
+
const { barConfig } = await Themes[Css.currentTheme]();
|
|
1087
|
+
const frameDuration = getCurrentFrameDuration();
|
|
1088
|
+
const previewWidth = Math.max(180, cellsW * pixelSize);
|
|
1089
|
+
const previewHeight = Math.max(180, cellsH * pixelSize);
|
|
1090
|
+
|
|
1091
|
+
await Modal.instance({
|
|
1092
|
+
id: DIRECTION_PREVIEW_MODAL_ID,
|
|
1093
|
+
barConfig,
|
|
1094
|
+
title: `${directionCodeLabels[directionCode] || directionCode} Preview`,
|
|
1095
|
+
html: () => html`
|
|
1096
|
+
<div class="in section-mp" style="text-align: center; min-width: ${previewWidth}px;">
|
|
1097
|
+
<div class="in" style="font-size: 12px; color: #999; margin-bottom: 8px;">
|
|
1098
|
+
${frames.length} frame${frames.length === 1 ? '' : 's'} at ${frameDuration}ms
|
|
1099
|
+
</div>
|
|
1100
|
+
<div
|
|
1101
|
+
class="in direction-preview-stage"
|
|
1102
|
+
style="display: inline-flex; align-items: center; justify-content: center; min-height: ${previewHeight}px; min-width: ${previewWidth}px; background-image: linear-gradient(45deg, rgba(255,255,255,0.08) 25%, transparent 25%), linear-gradient(-45deg, rgba(255,255,255,0.08) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(255,255,255,0.08) 75%), linear-gradient(-45deg, transparent 75%, rgba(255,255,255,0.08) 75%); background-size: 24px 24px; background-position: 0 0, 0 12px, 12px -12px, -12px 0; border: 1px solid rgba(255,255,255,0.15);"
|
|
1103
|
+
>
|
|
1104
|
+
<img
|
|
1105
|
+
class="direction-preview-image"
|
|
1106
|
+
src="${frameUrls[0]}"
|
|
1107
|
+
style="image-rendering: pixelated; width: ${previewWidth}px; height: ${previewHeight}px; object-fit: contain;"
|
|
1108
|
+
/>
|
|
1109
|
+
</div>
|
|
1110
|
+
<div class="fl" style="justify-content: center; gap: 6px; flex-wrap: wrap; margin-top: 10px;">
|
|
1111
|
+
${frameUrls.map(
|
|
1112
|
+
(frameUrl, frameIndex) => html`
|
|
1113
|
+
<img
|
|
1114
|
+
src="${frameUrl}"
|
|
1115
|
+
style="width: 48px; height: 48px; object-fit: contain; image-rendering: pixelated; border: 1px solid rgba(255,255,255,0.15); background: rgba(0,0,0,0.25);"
|
|
1116
|
+
title="Frame ${frameIndex + 1}"
|
|
1117
|
+
/>
|
|
1118
|
+
`,
|
|
1119
|
+
)}
|
|
1120
|
+
</div>
|
|
1121
|
+
</div>
|
|
1122
|
+
`,
|
|
1123
|
+
style: {
|
|
1124
|
+
width: `${Math.max(300, previewWidth + 40)}px`,
|
|
1125
|
+
height: `${Math.max(260, previewHeight + 150)}px`,
|
|
1126
|
+
border: '1px solid rgba(255,255,255,0.15)',
|
|
1127
|
+
'z-index': 10,
|
|
1128
|
+
},
|
|
1129
|
+
slideMenu: 'modal-menu',
|
|
1130
|
+
});
|
|
1131
|
+
|
|
1132
|
+
const previewImage = s(`.${DIRECTION_PREVIEW_MODAL_ID} .direction-preview-image`);
|
|
1133
|
+
if (!previewImage) {
|
|
1134
|
+
cleanupDirectionPreviewRuntime();
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
let currentFrameIndex = 0;
|
|
1139
|
+
const advancePreviewFrame = () => {
|
|
1140
|
+
if (!previewImage) return;
|
|
1141
|
+
currentFrameIndex = (currentFrameIndex + 1) % frameUrls.length;
|
|
1142
|
+
previewImage.src = frameUrls[currentFrameIndex];
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
directionPreviewRuntime = {
|
|
1146
|
+
frameUrls,
|
|
1147
|
+
intervalId: frameUrls.length > 1 ? setInterval(advancePreviewFrame, frameDuration) : null,
|
|
1148
|
+
};
|
|
1149
|
+
|
|
1150
|
+
if (Modal.Data[DIRECTION_PREVIEW_MODAL_ID]) {
|
|
1151
|
+
Modal.Data[DIRECTION_PREVIEW_MODAL_ID].onCloseListener[DIRECTION_PREVIEW_MODAL_ID] = () => {
|
|
1152
|
+
cleanupDirectionPreviewRuntime();
|
|
1153
|
+
delete Modal.Data[DIRECTION_PREVIEW_MODAL_ID]?.onCloseListener?.[DIRECTION_PREVIEW_MODAL_ID];
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
const rgbaToHex = (rgba = [0, 0, 0]) => {
|
|
1159
|
+
const red = Math.max(0, Math.min(255, rgba[0] || 0))
|
|
1160
|
+
.toString(16)
|
|
1161
|
+
.padStart(2, '0');
|
|
1162
|
+
const green = Math.max(0, Math.min(255, rgba[1] || 0))
|
|
1163
|
+
.toString(16)
|
|
1164
|
+
.padStart(2, '0');
|
|
1165
|
+
const blue = Math.max(0, Math.min(255, rgba[2] || 0))
|
|
1166
|
+
.toString(16)
|
|
1167
|
+
.padStart(2, '0');
|
|
1168
|
+
return `#${red}${green}${blue}`.toUpperCase();
|
|
1169
|
+
};
|
|
359
1170
|
|
|
360
1171
|
let directionsCodeBarRender = '';
|
|
361
1172
|
|
|
@@ -378,11 +1189,11 @@ const ObjectLayerEngineModal = {
|
|
|
378
1189
|
src="${URL.createObjectURL(image)}"
|
|
379
1190
|
data-direction-code="${capturedDirectionCode}"
|
|
380
1191
|
/>
|
|
381
|
-
${await BtnIcon.
|
|
1192
|
+
${await BtnIcon.instance({
|
|
382
1193
|
label: html`<i class="fa-solid fa-edit"></i>`,
|
|
383
1194
|
class: `abs direction-code-bar-edit-btn direction-code-bar-edit-btn-${id}`,
|
|
384
1195
|
})}
|
|
385
|
-
${await BtnIcon.
|
|
1196
|
+
${await BtnIcon.instance({
|
|
386
1197
|
label: html`<i class="fa-solid fa-trash"></i>`,
|
|
387
1198
|
class: `abs direction-code-bar-trash-btn direction-code-bar-trash-btn-${id}`,
|
|
388
1199
|
})}
|
|
@@ -527,14 +1338,18 @@ const ObjectLayerEngineModal = {
|
|
|
527
1338
|
<div class="fl">
|
|
528
1339
|
<div class="in fll">
|
|
529
1340
|
<div class="in direction-code-bar-frames-title">${directionCodeLabels[directionCode]}</div>
|
|
530
|
-
<div class="
|
|
531
|
-
${await BtnIcon.
|
|
1341
|
+
<div class="fl direction-code-bar-btn-row" style="gap: 6px;">
|
|
1342
|
+
${await BtnIcon.instance({
|
|
532
1343
|
label: html`
|
|
533
1344
|
<i class="fa-solid fa-plus direction-code-bar-frames-btn-icon-add-${directionCode}"></i>
|
|
534
1345
|
<i class="fa-solid fa-edit direction-code-bar-frames-btn-icon-edit-${directionCode} hide"></i>
|
|
535
1346
|
`,
|
|
536
1347
|
class: `direction-code-bar-frames-btn-add direction-code-bar-frames-btn-${directionCode}`,
|
|
537
1348
|
})}
|
|
1349
|
+
${await BtnIcon.instance({
|
|
1350
|
+
label: html`<i class="fa-solid fa-play"></i>`,
|
|
1351
|
+
class: `direction-code-bar-preview-btn direction-code-bar-preview-btn-${directionCode}`,
|
|
1352
|
+
})}
|
|
538
1353
|
</div>
|
|
539
1354
|
</div>
|
|
540
1355
|
<div class="frames-${directionCode}"></div>
|
|
@@ -549,7 +1364,7 @@ const ObjectLayerEngineModal = {
|
|
|
549
1364
|
const statValue = loadedData?.metadata?.data?.stats?.[statType] || 0;
|
|
550
1365
|
statsInputsRender += html`
|
|
551
1366
|
<div class="inl" style="margin-bottom: 10px; position: relative;">
|
|
552
|
-
${await Input.
|
|
1367
|
+
${await Input.instance({
|
|
553
1368
|
id: `ol-input-item-stats-${statType}`,
|
|
554
1369
|
label: html`<div
|
|
555
1370
|
title="${statInfo.description} ${statInfo.detail}"
|
|
@@ -640,8 +1455,13 @@ const ObjectLayerEngineModal = {
|
|
|
640
1455
|
}
|
|
641
1456
|
|
|
642
1457
|
const buttonSelector = `.direction-code-bar-frames-btn-${currentDirectionCode}`;
|
|
1458
|
+
const previewButtonSelector = `.direction-code-bar-preview-btn-${currentDirectionCode}`;
|
|
643
1459
|
console.log(`Registering click handler for: ${buttonSelector}`);
|
|
644
1460
|
|
|
1461
|
+
EventsUI.onClick(previewButtonSelector, async () => {
|
|
1462
|
+
await openDirectionPreviewModal(currentDirectionCode);
|
|
1463
|
+
});
|
|
1464
|
+
|
|
645
1465
|
EventsUI.onClick(buttonSelector, async () => {
|
|
646
1466
|
console.log(`Add frame button clicked for direction: ${currentDirectionCode}`);
|
|
647
1467
|
const ole = s('object-layer-engine');
|
|
@@ -727,7 +1547,165 @@ const ObjectLayerEngineModal = {
|
|
|
727
1547
|
await loadFrames();
|
|
728
1548
|
s('object-layer-engine').clear();
|
|
729
1549
|
|
|
730
|
-
|
|
1550
|
+
const editor = s('object-layer-engine');
|
|
1551
|
+
const colorPalette = s(`.${colorPaletteClass}`);
|
|
1552
|
+
|
|
1553
|
+
const syncPaletteFromEditor = (event = null) => {
|
|
1554
|
+
if (!colorPalette || !editor) {
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
const nextHex = event?.detail?.hex || rgbaToHex(editor.getBrushColor?.());
|
|
1558
|
+
if (nextHex && colorPalette.value !== nextHex) {
|
|
1559
|
+
colorPalette.value = nextHex;
|
|
1560
|
+
}
|
|
1561
|
+
};
|
|
1562
|
+
|
|
1563
|
+
const syncEditorFromPalette = (event) => {
|
|
1564
|
+
if (!editor) {
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
const nextHex = event.detail?.value || event.detail?.hex;
|
|
1568
|
+
if (!nextHex) {
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
const [red, green, blue] = hexToRgbA(nextHex);
|
|
1572
|
+
const alpha = editor.getBrushAlpha?.() ?? editor.getBrushColor?.()?.[3] ?? 255;
|
|
1573
|
+
editor.setBrushColor([red, green, blue, alpha]);
|
|
1574
|
+
};
|
|
1575
|
+
|
|
1576
|
+
if (colorPalette) {
|
|
1577
|
+
colorPalette.addEventListener('colorchange', syncEditorFromPalette);
|
|
1578
|
+
}
|
|
1579
|
+
if (editor) {
|
|
1580
|
+
editor.addEventListener('brushcolorchange', syncPaletteFromEditor);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
const syncUniformOpacityFromEditor = () => {
|
|
1584
|
+
applyUniformOpacityToEditor();
|
|
1585
|
+
};
|
|
1586
|
+
|
|
1587
|
+
if (editor) {
|
|
1588
|
+
editor.addEventListener('brushcolorchange', syncUniformOpacityFromEditor);
|
|
1589
|
+
editor.addEventListener('matrixload', syncUniformOpacityFromEditor);
|
|
1590
|
+
}
|
|
1591
|
+
syncPaletteFromEditor();
|
|
1592
|
+
|
|
1593
|
+
const setDistortionStatus = (message, tone = 'muted') => {
|
|
1594
|
+
const statusNode = s(`.${distortionStatusClass}`);
|
|
1595
|
+
if (!statusNode) return;
|
|
1596
|
+
statusNode.style.color = tone === 'success' ? '#8fd18c' : tone === 'error' ? '#ff8a8a' : '#888';
|
|
1597
|
+
statusNode.innerHTML = message;
|
|
1598
|
+
};
|
|
1599
|
+
|
|
1600
|
+
const applyDistortionToCurrentFrame = async () => {
|
|
1601
|
+
const ole = s('object-layer-engine');
|
|
1602
|
+
if (!ole || typeof ole.exportMatrixJSON !== 'function' || typeof ole.loadMatrix !== 'function') return;
|
|
1603
|
+
|
|
1604
|
+
let currentJson = null;
|
|
1605
|
+
let currentFrame = null;
|
|
1606
|
+
|
|
1607
|
+
try {
|
|
1608
|
+
currentJson = ole.exportMatrixJSON();
|
|
1609
|
+
currentFrame = typeof currentJson === 'string' ? JSON.parse(currentJson) : currentJson;
|
|
1610
|
+
} catch (error) {
|
|
1611
|
+
setDistortionStatus('Could not read the current frame from the editor.', 'error');
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
const currentMatrix = currentFrame?.matrix;
|
|
1616
|
+
if (!Array.isArray(currentMatrix) || !currentMatrix.length || !currentMatrix[0]?.length) {
|
|
1617
|
+
setDistortionStatus('The current frame has no editable matrix data.', 'error');
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
const selectedDistortionType = ObjectLayerEngineModal.selectedDistortionType || DEFAULT_DISTORTION_TYPE;
|
|
1621
|
+
const selectedBehavior =
|
|
1622
|
+
CANVAS_BEHAVIOR_BY_VALUE[selectedDistortionType] || CANVAS_BEHAVIOR_BY_VALUE[DEFAULT_DISTORTION_TYPE];
|
|
1623
|
+
const distortionFactorA = readDistortionFactorA();
|
|
1624
|
+
const isMosaicMode = isMosaicBehavior(selectedDistortionType);
|
|
1625
|
+
|
|
1626
|
+
if (!isMosaicMode && !currentMatrix.some((row) => row.some((cell) => isVisibleCell(cell)))) {
|
|
1627
|
+
setDistortionStatus('Paint something on the current frame before applying a distortion.', 'error');
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
const baseFrame = currentFrame;
|
|
1632
|
+
let transformationResult = null;
|
|
1633
|
+
|
|
1634
|
+
if (isMosaicMode) {
|
|
1635
|
+
const activeBrushColor = normalizeColorCell(ole.getBrushColor?.() || [255, 0, 0, 255]);
|
|
1636
|
+
transformationResult = buildMosaicMatrix(
|
|
1637
|
+
baseFrame.matrix,
|
|
1638
|
+
selectedDistortionType,
|
|
1639
|
+
distortionFactorA,
|
|
1640
|
+
activeBrushColor,
|
|
1641
|
+
);
|
|
1642
|
+
} else {
|
|
1643
|
+
const seedBase = Date.now() + hashString(currentJson);
|
|
1644
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
1645
|
+
const distortionSeed = seedBase + attempt * 977;
|
|
1646
|
+
transformationResult = buildDistortedMatrix(
|
|
1647
|
+
baseFrame.matrix,
|
|
1648
|
+
selectedDistortionType,
|
|
1649
|
+
distortionFactorA,
|
|
1650
|
+
distortionSeed,
|
|
1651
|
+
);
|
|
1652
|
+
if (transformationResult.changedCells > 0) break;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
if (!transformationResult || transformationResult.changedCells === 0) {
|
|
1657
|
+
setDistortionStatus(
|
|
1658
|
+
isMosaicMode
|
|
1659
|
+
? 'No visible mosaic was painted on the current frame. Try another factorA value or a different active color.'
|
|
1660
|
+
: 'No visible distortion was produced for the current frame. Try applying again or edit the frame shape first.',
|
|
1661
|
+
'error',
|
|
1662
|
+
);
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
const nextSnapshot = {
|
|
1667
|
+
width: baseFrame.width,
|
|
1668
|
+
height: baseFrame.height,
|
|
1669
|
+
matrix: transformationResult.matrix,
|
|
1670
|
+
};
|
|
1671
|
+
const beforeSnapshot = typeof ole._snapshot === 'function' ? ole._snapshot() : null;
|
|
1672
|
+
|
|
1673
|
+
if (
|
|
1674
|
+
beforeSnapshot &&
|
|
1675
|
+
typeof ole._pushUndo === 'function' &&
|
|
1676
|
+
typeof ole._matricesEqual === 'function' &&
|
|
1677
|
+
!ole._matricesEqual(beforeSnapshot, nextSnapshot)
|
|
1678
|
+
) {
|
|
1679
|
+
ole._pushUndo(beforeSnapshot);
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
ole.loadMatrix(transformationResult.matrix);
|
|
1683
|
+
|
|
1684
|
+
if (isMosaicMode) {
|
|
1685
|
+
setDistortionStatus(
|
|
1686
|
+
`${selectedBehavior.label} painted on the current frame with the active color. tileSize ${transformationResult.tileSize}, ${transformationResult.paintedCells || 0} pattern cells, ${transformationResult.changedCells} cells changed, factorA=${distortionFactorA.toFixed(2)}.`,
|
|
1687
|
+
'success',
|
|
1688
|
+
);
|
|
1689
|
+
} else {
|
|
1690
|
+
setDistortionStatus(
|
|
1691
|
+
`${selectedBehavior.label} applied to the current frame. ${transformationResult.appliedDistortions || 0} local shifts, ${transformationResult.changedCells} cells changed, factorA=${distortionFactorA.toFixed(2)}.`,
|
|
1692
|
+
'success',
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1697
|
+
EventsUI.onClick(`.${distortionApplyBtnClass}`, async () => {
|
|
1698
|
+
await applyDistortionToCurrentFrame();
|
|
1699
|
+
});
|
|
1700
|
+
setDistortionStatus(DEFAULT_DISTORTION_STATUS);
|
|
1701
|
+
|
|
1702
|
+
EventsUI.onClick(`.${statsRandomizeBtnClass}`, async () => {
|
|
1703
|
+
randomizeStatInputs();
|
|
1704
|
+
});
|
|
1705
|
+
|
|
1706
|
+
const persistObjectLayer = async ({ clone = false } = {}) => {
|
|
1707
|
+
const isUpdateMode = Boolean(ObjectLayerEngineModal.existingObjectLayerId) && !clone;
|
|
1708
|
+
|
|
731
1709
|
// Validate minimum frame_duration 100ms
|
|
732
1710
|
const frameDuration = parseInt(s(`.ol-input-render-frame-duration`).value);
|
|
733
1711
|
if (!frameDuration || frameDuration < 100) {
|
|
@@ -765,7 +1743,6 @@ const ObjectLayerEngineModal = {
|
|
|
765
1743
|
frames: {},
|
|
766
1744
|
colors: [],
|
|
767
1745
|
frame_duration: ObjectLayerEngineModal.renderFrameDuration,
|
|
768
|
-
is_stateless: ObjectLayerEngineModal.renderIsStateless,
|
|
769
1746
|
};
|
|
770
1747
|
|
|
771
1748
|
const objectLayer = {
|
|
@@ -811,7 +1788,6 @@ const ObjectLayerEngineModal = {
|
|
|
811
1788
|
}
|
|
812
1789
|
}
|
|
813
1790
|
objectLayerRenderFramesData.frame_duration = parseInt(s(`.ol-input-render-frame-duration`).value);
|
|
814
|
-
objectLayerRenderFramesData.is_stateless = ObjectLayerEngineModal.renderIsStateless;
|
|
815
1791
|
objectLayer.data.stats = {
|
|
816
1792
|
effect: parseInt(s(`.ol-input-item-stats-effect`).value),
|
|
817
1793
|
resistance: parseInt(s(`.ol-input-item-stats-resistance`).value),
|
|
@@ -827,18 +1803,18 @@ const ObjectLayerEngineModal = {
|
|
|
827
1803
|
description: s(`.ol-input-item-description`).value,
|
|
828
1804
|
};
|
|
829
1805
|
|
|
830
|
-
// Add _id
|
|
831
|
-
if (
|
|
1806
|
+
// Add _id only when updating the existing object layer.
|
|
1807
|
+
if (isUpdateMode) {
|
|
832
1808
|
objectLayer._id = ObjectLayerEngineModal.existingObjectLayerId;
|
|
833
1809
|
}
|
|
834
1810
|
|
|
835
1811
|
console.warn(
|
|
836
1812
|
'objectLayer',
|
|
837
1813
|
objectLayer,
|
|
838
|
-
|
|
1814
|
+
clone ? '(CLONE MODE)' : isUpdateMode ? '(UPDATE MODE)' : '(CREATE MODE)',
|
|
839
1815
|
);
|
|
840
1816
|
|
|
841
|
-
if (
|
|
1817
|
+
if (appStore.Data.user.main.model.user.role === 'guest') {
|
|
842
1818
|
NotificationManager.Push({
|
|
843
1819
|
html: 'Guests cannot save object layers. Please log in.',
|
|
844
1820
|
status: 'warning',
|
|
@@ -852,14 +1828,14 @@ const ObjectLayerEngineModal = {
|
|
|
852
1828
|
const directionCodesToUpload = Object.keys(ObjectLayerEngineModal.ObjectLayerData);
|
|
853
1829
|
|
|
854
1830
|
// In UPDATE mode, also include original direction codes that may have been cleared
|
|
855
|
-
const allDirectionCodes =
|
|
1831
|
+
const allDirectionCodes = isUpdateMode
|
|
856
1832
|
? [...new Set([...directionCodesToUpload, ...ObjectLayerEngineModal.originalDirectionCodes])]
|
|
857
1833
|
: directionCodesToUpload;
|
|
858
1834
|
|
|
859
1835
|
console.warn(
|
|
860
1836
|
`Uploading frames for ${allDirectionCodes.length} directions:`,
|
|
861
1837
|
allDirectionCodes,
|
|
862
|
-
|
|
1838
|
+
clone ? '(CLONE MODE)' : isUpdateMode ? '(UPDATE MODE)' : '(CREATE MODE)',
|
|
863
1839
|
);
|
|
864
1840
|
|
|
865
1841
|
for (const directionCode of allDirectionCodes) {
|
|
@@ -884,7 +1860,7 @@ const ObjectLayerEngineModal = {
|
|
|
884
1860
|
|
|
885
1861
|
// Send all frames for this direction in one request (even if empty, to remove frames)
|
|
886
1862
|
try {
|
|
887
|
-
if (
|
|
1863
|
+
if (isUpdateMode) {
|
|
888
1864
|
// UPDATE: use PUT endpoint with object layer ID
|
|
889
1865
|
const { status, data } = await ObjectLayerService.put({
|
|
890
1866
|
id: `${ObjectLayerEngineModal.existingObjectLayerId}/frame-image/${objectLayer.data.item.type}/${objectLayer.data.item.id}/${directionCode}`,
|
|
@@ -925,7 +1901,7 @@ const ObjectLayerEngineModal = {
|
|
|
925
1901
|
};
|
|
926
1902
|
|
|
927
1903
|
let response;
|
|
928
|
-
if (
|
|
1904
|
+
if (isUpdateMode) {
|
|
929
1905
|
// UPDATE existing object layer
|
|
930
1906
|
console.warn(
|
|
931
1907
|
'PUT path:',
|
|
@@ -946,22 +1922,28 @@ const ObjectLayerEngineModal = {
|
|
|
946
1922
|
const { status, data, message } = response;
|
|
947
1923
|
|
|
948
1924
|
if (status === 'success') {
|
|
1925
|
+
const successAction = clone ? 'cloned' : isUpdateMode ? 'updated' : 'created';
|
|
949
1926
|
NotificationManager.Push({
|
|
950
|
-
html: `Object layer "${objectLayer.data.item.id}" ${
|
|
951
|
-
ObjectLayerEngineModal.existingObjectLayerId ? 'updated' : 'created'
|
|
952
|
-
} successfully!`,
|
|
1927
|
+
html: `Object layer "${objectLayer.data.item.id}" ${successAction} successfully!`,
|
|
953
1928
|
status: 'success',
|
|
954
1929
|
});
|
|
955
1930
|
ObjectLayerEngineModal.toManagement(data?._id || ObjectLayerEngineModal.existingObjectLayerId);
|
|
956
1931
|
} else {
|
|
1932
|
+
const errorAction = clone ? 'cloning' : isUpdateMode ? 'updating' : 'creating';
|
|
957
1933
|
NotificationManager.Push({
|
|
958
|
-
html: `Error ${
|
|
959
|
-
ObjectLayerEngineModal.existingObjectLayerId ? 'updating' : 'creating'
|
|
960
|
-
} object layer: ${message}`,
|
|
1934
|
+
html: `Error ${errorAction} object layer: ${message}`,
|
|
961
1935
|
status: 'error',
|
|
962
1936
|
});
|
|
963
1937
|
}
|
|
964
1938
|
}
|
|
1939
|
+
};
|
|
1940
|
+
|
|
1941
|
+
EventsUI.onClick(`.ol-btn-save`, async () => {
|
|
1942
|
+
await persistObjectLayer();
|
|
1943
|
+
});
|
|
1944
|
+
|
|
1945
|
+
EventsUI.onClick(`.ol-btn-clone`, async () => {
|
|
1946
|
+
await persistObjectLayer({ clone: true });
|
|
965
1947
|
});
|
|
966
1948
|
|
|
967
1949
|
// Add reset button event listener
|
|
@@ -1029,6 +2011,10 @@ const ObjectLayerEngineModal = {
|
|
|
1029
2011
|
color: white;
|
|
1030
2012
|
border: none !important;
|
|
1031
2013
|
}
|
|
2014
|
+
.direction-code-bar-preview-btn {
|
|
2015
|
+
color: white;
|
|
2016
|
+
border: none !important;
|
|
2017
|
+
}
|
|
1032
2018
|
.direction-code-bar-trash-btn:hover {
|
|
1033
2019
|
background: none !important;
|
|
1034
2020
|
color: red;
|
|
@@ -1041,6 +2027,10 @@ const ObjectLayerEngineModal = {
|
|
|
1041
2027
|
background: none !important;
|
|
1042
2028
|
color: #c7ff58;
|
|
1043
2029
|
}
|
|
2030
|
+
.direction-code-bar-preview-btn:hover {
|
|
2031
|
+
background: none !important;
|
|
2032
|
+
color: #5ee6ff;
|
|
2033
|
+
}
|
|
1044
2034
|
.ol-btn-save {
|
|
1045
2035
|
width: 120px;
|
|
1046
2036
|
padding: 0.5rem;
|
|
@@ -1053,6 +2043,16 @@ const ObjectLayerEngineModal = {
|
|
|
1053
2043
|
font-size: 20px;
|
|
1054
2044
|
min-height: 50px;
|
|
1055
2045
|
}
|
|
2046
|
+
.ol-btn-clone {
|
|
2047
|
+
width: 120px;
|
|
2048
|
+
padding: 0.5rem;
|
|
2049
|
+
font-size: 20px;
|
|
2050
|
+
min-height: 50px;
|
|
2051
|
+
}
|
|
2052
|
+
.ol-btn-randomize-stats {
|
|
2053
|
+
min-height: 50px;
|
|
2054
|
+
padding: 0.5rem 0.75rem;
|
|
2055
|
+
}
|
|
1056
2056
|
.ol-number-label {
|
|
1057
2057
|
width: 120px;
|
|
1058
2058
|
font-size: 16px;
|
|
@@ -1091,6 +2091,7 @@ const ObjectLayerEngineModal = {
|
|
|
1091
2091
|
'.direction-code-bar-edit-btn',
|
|
1092
2092
|
'.direction-code-bar-trash-btn',
|
|
1093
2093
|
'.direction-code-bar-frames-btn-add',
|
|
2094
|
+
'.direction-code-bar-preview-btn',
|
|
1094
2095
|
])}
|
|
1095
2096
|
<div class="in frame-editor-container-loading">
|
|
1096
2097
|
<div class="abs center frame-editor-container-loading-center"></div>
|
|
@@ -1098,22 +2099,119 @@ const ObjectLayerEngineModal = {
|
|
|
1098
2099
|
<div class="in section-mp section-mp-border frame-editor-container">
|
|
1099
2100
|
<div class="in sub-title-modal"><i class="fa-solid fa-table-cells-large"></i> Frame editor</div>
|
|
1100
2101
|
|
|
1101
|
-
<object-layer-engine id="ole" width="${
|
|
2102
|
+
<object-layer-engine id="ole" width="${cellsW}" height="${cellsH}" pixel-size="${pixelSize}">
|
|
1102
2103
|
</object-layer-engine>
|
|
2104
|
+
<div class="in section-mp-border" style="margin-top: 10px;">
|
|
2105
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-palette"></i> Brush palette</div>
|
|
2106
|
+
<color-palette class="${colorPaletteClass}" value="#FF0000"></color-palette>
|
|
2107
|
+
<div class="fl" style="align-items: center; gap: 8px; margin-top: 8px;">
|
|
2108
|
+
${await ToggleSwitch.instance({
|
|
2109
|
+
id: UNIFORM_OPACITY_TOGGLE_ID,
|
|
2110
|
+
type: 'checkbox',
|
|
2111
|
+
displayMode: 'checkbox',
|
|
2112
|
+
containerClass: 'in fll',
|
|
2113
|
+
checked: ObjectLayerEngineModal.uniformOpacityEnabled,
|
|
2114
|
+
on: {
|
|
2115
|
+
checked: () => {
|
|
2116
|
+
ObjectLayerEngineModal.uniformOpacityEnabled = true;
|
|
2117
|
+
applyUniformOpacityToEditor({ captureUndo: true });
|
|
2118
|
+
},
|
|
2119
|
+
unchecked: () => {
|
|
2120
|
+
ObjectLayerEngineModal.uniformOpacityEnabled = false;
|
|
2121
|
+
},
|
|
2122
|
+
},
|
|
2123
|
+
})}
|
|
2124
|
+
<div class="section-mp" style="font-size: 14px;">
|
|
2125
|
+
Keep all visible cells at the current opacity bar value
|
|
2126
|
+
</div>
|
|
2127
|
+
</div>
|
|
2128
|
+
</div>
|
|
2129
|
+
<div class="in section-mp-border" style="margin-top: 10px;">
|
|
2130
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-wand-magic-sparkles"></i> Canvas macro</div>
|
|
2131
|
+
<div class="fl" style="align-items: flex-start; gap: 8px; flex-wrap: wrap;">
|
|
2132
|
+
<div class="in fll" style="min-width: 240px;">
|
|
2133
|
+
${await DropDown.instance({
|
|
2134
|
+
id: distortionDropdownId,
|
|
2135
|
+
value: ObjectLayerEngineModal.selectedDistortionType,
|
|
2136
|
+
label: html`Select behavior`,
|
|
2137
|
+
disableSearchBox: true,
|
|
2138
|
+
data: [
|
|
2139
|
+
{
|
|
2140
|
+
kind: 'group',
|
|
2141
|
+
value: 'group-distortion-behaviors',
|
|
2142
|
+
display: html`<div style="padding: 0 6px; color: #9d9d9d;">Distortion behaviors</div>`,
|
|
2143
|
+
},
|
|
2144
|
+
...DISTORTION_TYPES.map((distortion) => ({
|
|
2145
|
+
value: distortion.value,
|
|
2146
|
+
display: html`<i class="${CANVAS_BEHAVIOR_ICON}"></i> ${distortion.label}`,
|
|
2147
|
+
onClick: async () => {
|
|
2148
|
+
ObjectLayerEngineModal.selectedDistortionType = distortion.value;
|
|
2149
|
+
readDistortionFactorA();
|
|
2150
|
+
const statusNode = s(`.${distortionStatusClass}`);
|
|
2151
|
+
if (statusNode) {
|
|
2152
|
+
statusNode.style.color = '#888';
|
|
2153
|
+
statusNode.innerHTML = `${distortion.label} ready for direct canvas apply. factorA controls local distortion density.`;
|
|
2154
|
+
}
|
|
2155
|
+
},
|
|
2156
|
+
})),
|
|
2157
|
+
{
|
|
2158
|
+
kind: 'group',
|
|
2159
|
+
value: 'group-mosaic-behaviors',
|
|
2160
|
+
display: html`<div style="padding: 0 6px; color: #9d9d9d;">Mosaic drawing behaviors</div>`,
|
|
2161
|
+
},
|
|
2162
|
+
...MOSAIC_TYPES.map((mosaic) => ({
|
|
2163
|
+
value: mosaic.value,
|
|
2164
|
+
display: html`<i class="${CANVAS_BEHAVIOR_ICON}"></i> ${mosaic.label}`,
|
|
2165
|
+
onClick: async () => {
|
|
2166
|
+
ObjectLayerEngineModal.selectedDistortionType = mosaic.value;
|
|
2167
|
+
readDistortionFactorA();
|
|
2168
|
+
const statusNode = s(`.${distortionStatusClass}`);
|
|
2169
|
+
if (statusNode) {
|
|
2170
|
+
statusNode.style.color = '#888';
|
|
2171
|
+
statusNode.innerHTML = `${mosaic.label} ready for direct canvas apply. factorA controls tile size and density.`;
|
|
2172
|
+
}
|
|
2173
|
+
},
|
|
2174
|
+
})),
|
|
2175
|
+
],
|
|
2176
|
+
})}
|
|
2177
|
+
</div>
|
|
2178
|
+
<div class="in fll" style="width: 120px;">
|
|
2179
|
+
${await Input.instance({
|
|
2180
|
+
id: `ol-input-distortion-factor-a`,
|
|
2181
|
+
label: html`factorA`,
|
|
2182
|
+
containerClass: 'inl',
|
|
2183
|
+
type: 'number',
|
|
2184
|
+
min: 0.01,
|
|
2185
|
+
max: 1,
|
|
2186
|
+
step: 0.01,
|
|
2187
|
+
value: ObjectLayerEngineModal.distortionFactorA,
|
|
2188
|
+
})}
|
|
2189
|
+
</div>
|
|
2190
|
+
<div class="in fll">
|
|
2191
|
+
${await BtnIcon.instance({
|
|
2192
|
+
class: distortionApplyBtnClass,
|
|
2193
|
+
label: html`<i class="fa-solid fa-bolt"></i> Apply To Frame`,
|
|
2194
|
+
})}
|
|
2195
|
+
</div>
|
|
2196
|
+
</div>
|
|
2197
|
+
<div class="in ${distortionStatusClass}" style="margin-top: 6px; font-size: 12px; color: #888;">
|
|
2198
|
+
${DEFAULT_DISTORTION_STATUS}
|
|
2199
|
+
</div>
|
|
2200
|
+
</div>
|
|
1103
2201
|
<object-layer-png-loader id="loader" editor-selector="#ole"></object-layer-png-loader>
|
|
1104
2202
|
</div>
|
|
1105
2203
|
|
|
1106
2204
|
<div class="in section-mp section-mp-border">
|
|
1107
|
-
<div class="in sub-title-modal"><i class="fa-solid fa-database"></i>
|
|
2205
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-database"></i> instance data</div>
|
|
1108
2206
|
${dynamicCol({ containerSelector: options.idModal, id: idSectionA })}
|
|
1109
2207
|
|
|
1110
2208
|
<div class="fl">
|
|
1111
2209
|
<div class="in fll ${idSectionA}-col-a">
|
|
1112
2210
|
<div class="in section-mp">
|
|
1113
|
-
${await DropDown.
|
|
2211
|
+
${await DropDown.instance({
|
|
1114
2212
|
id: 'ol-dropdown-template',
|
|
1115
2213
|
value: ObjectLayerEngineModal.templates[0].id,
|
|
1116
|
-
label: html`${Translate.
|
|
2214
|
+
label: html`${Translate.instance('select-template')}`,
|
|
1117
2215
|
data: ObjectLayerEngineModal.templates.map((template) => {
|
|
1118
2216
|
return {
|
|
1119
2217
|
value: template.id,
|
|
@@ -1128,7 +2226,7 @@ const ObjectLayerEngineModal = {
|
|
|
1128
2226
|
</div>
|
|
1129
2227
|
<div class="in fll ${idSectionA}-col-b">
|
|
1130
2228
|
<div class="in section-mp-border" style="width: 135px;">
|
|
1131
|
-
${await Input.
|
|
2229
|
+
${await Input.instance({
|
|
1132
2230
|
id: `ol-input-render-frame-duration`,
|
|
1133
2231
|
label: html`<div class="inl ol-number-label">
|
|
1134
2232
|
<i class="fa-solid fa-chart-simple"></i> Frame duration
|
|
@@ -1141,25 +2239,6 @@ const ObjectLayerEngineModal = {
|
|
|
1141
2239
|
value: ObjectLayerEngineModal.renderFrameDuration,
|
|
1142
2240
|
})}
|
|
1143
2241
|
</div>
|
|
1144
|
-
<div class="in section-mp">
|
|
1145
|
-
${await ToggleSwitch.Render({
|
|
1146
|
-
id: 'ol-toggle-render-is-stateless',
|
|
1147
|
-
wrapper: true,
|
|
1148
|
-
wrapperLabel: html`${Translate.Render('is-stateless')}`,
|
|
1149
|
-
disabledOnClick: true,
|
|
1150
|
-
checked: ObjectLayerEngineModal.renderIsStateless,
|
|
1151
|
-
on: {
|
|
1152
|
-
unchecked: () => {
|
|
1153
|
-
ObjectLayerEngineModal.renderIsStateless = false;
|
|
1154
|
-
console.warn('renderIsStateless', ObjectLayerEngineModal.renderIsStateless);
|
|
1155
|
-
},
|
|
1156
|
-
checked: () => {
|
|
1157
|
-
ObjectLayerEngineModal.renderIsStateless = true;
|
|
1158
|
-
console.warn('renderIsStateless', ObjectLayerEngineModal.renderIsStateless);
|
|
1159
|
-
},
|
|
1160
|
-
},
|
|
1161
|
-
})}
|
|
1162
|
-
</div>
|
|
1163
2242
|
</div>
|
|
1164
2243
|
</div>
|
|
1165
2244
|
${directionsCodeBarRender}
|
|
@@ -1170,25 +2249,25 @@ const ObjectLayerEngineModal = {
|
|
|
1170
2249
|
<div class="in fll ${idSectionB}-col-a">
|
|
1171
2250
|
<div class="in section-mp section-mp-border">
|
|
1172
2251
|
<div class="in sub-title-modal"><i class="fa-solid fa-database"></i> Item data</div>
|
|
1173
|
-
${await Input.
|
|
2252
|
+
${await Input.instance({
|
|
1174
2253
|
id: `ol-input-item-id`,
|
|
1175
|
-
label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.
|
|
2254
|
+
label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.instance('item-id')}`,
|
|
1176
2255
|
containerClass: '',
|
|
1177
2256
|
placeholder: true,
|
|
1178
2257
|
value: loadedData?.metadata?.data?.item?.id || '',
|
|
1179
2258
|
})}
|
|
1180
|
-
${await Input.
|
|
2259
|
+
${await Input.instance({
|
|
1181
2260
|
id: `ol-input-item-description`,
|
|
1182
|
-
label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.
|
|
2261
|
+
label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.instance('item-description')}`,
|
|
1183
2262
|
containerClass: '',
|
|
1184
2263
|
placeholder: true,
|
|
1185
2264
|
value: loadedData?.metadata?.data?.item?.description || '',
|
|
1186
2265
|
})}
|
|
1187
2266
|
<div class="in section-mp">
|
|
1188
|
-
${await DropDown.
|
|
2267
|
+
${await DropDown.instance({
|
|
1189
2268
|
id: 'ol-dropdown-item-type',
|
|
1190
2269
|
value: ObjectLayerEngineModal.selectItemType,
|
|
1191
|
-
label: html`${Translate.
|
|
2270
|
+
label: html`${Translate.instance('select-item-type')}`,
|
|
1192
2271
|
data: itemTypes.map((itemType) => {
|
|
1193
2272
|
return {
|
|
1194
2273
|
value: itemType,
|
|
@@ -1202,10 +2281,10 @@ const ObjectLayerEngineModal = {
|
|
|
1202
2281
|
})}
|
|
1203
2282
|
</div>
|
|
1204
2283
|
<div class="in section-mp">
|
|
1205
|
-
${await ToggleSwitch.
|
|
2284
|
+
${await ToggleSwitch.instance({
|
|
1206
2285
|
id: 'ol-toggle-item-activable',
|
|
1207
2286
|
wrapper: true,
|
|
1208
|
-
wrapperLabel: html`${Translate.
|
|
2287
|
+
wrapperLabel: html`${Translate.instance('item-activable')}`,
|
|
1209
2288
|
disabledOnClick: true,
|
|
1210
2289
|
checked: ObjectLayerEngineModal.itemActivable,
|
|
1211
2290
|
on: {
|
|
@@ -1225,25 +2304,65 @@ const ObjectLayerEngineModal = {
|
|
|
1225
2304
|
<div class="in fll ${idSectionB}-col-b">
|
|
1226
2305
|
<div class="in section-mp section-mp-border">
|
|
1227
2306
|
<div class="in sub-title-modal"><i class="fa-solid fa-database"></i> Stats data</div>
|
|
2307
|
+
<div class="fl" style="align-items: flex-end; gap: 8px; flex-wrap: wrap; margin-bottom: 10px;">
|
|
2308
|
+
<div class="in fll" style="width: 110px;">
|
|
2309
|
+
${await Input.instance({
|
|
2310
|
+
id: statsRandomMinInputId,
|
|
2311
|
+
label: html`Random min`,
|
|
2312
|
+
containerClass: 'inl',
|
|
2313
|
+
type: 'number',
|
|
2314
|
+
min: 0,
|
|
2315
|
+
max: 10,
|
|
2316
|
+
placeholder: true,
|
|
2317
|
+
value: DEFAULT_STAT_RANDOM_MIN,
|
|
2318
|
+
})}
|
|
2319
|
+
</div>
|
|
2320
|
+
<div class="in fll" style="width: 110px;">
|
|
2321
|
+
${await Input.instance({
|
|
2322
|
+
id: statsRandomMaxInputId,
|
|
2323
|
+
label: html`Random max`,
|
|
2324
|
+
containerClass: 'inl',
|
|
2325
|
+
type: 'number',
|
|
2326
|
+
min: 0,
|
|
2327
|
+
max: 10,
|
|
2328
|
+
placeholder: true,
|
|
2329
|
+
value: DEFAULT_STAT_RANDOM_MAX,
|
|
2330
|
+
})}
|
|
2331
|
+
</div>
|
|
2332
|
+
<div class="in fll">
|
|
2333
|
+
${await BtnIcon.instance({
|
|
2334
|
+
label: html`<i class="fa-solid fa-dice"></i> Randomize`,
|
|
2335
|
+
class: statsRandomizeBtnClass,
|
|
2336
|
+
})}
|
|
2337
|
+
</div>
|
|
2338
|
+
</div>
|
|
1228
2339
|
${statsInputsRender}
|
|
1229
2340
|
</div>
|
|
1230
2341
|
</div>
|
|
1231
2342
|
</div>
|
|
1232
2343
|
|
|
1233
2344
|
<div class="fl section-mp">
|
|
1234
|
-
${await BtnIcon.
|
|
1235
|
-
label: html`<i class="submit-btn-icon fa-solid fa-folder-open"></i>
|
|
2345
|
+
${await BtnIcon.instance({
|
|
2346
|
+
label: html`<i class="submit-btn-icon fa-solid fa-folder-open"></i>
|
|
2347
|
+
${ObjectLayerEngineModal.existingObjectLayerId ? 'Update' : Translate.instance('save')}`,
|
|
1236
2348
|
class: `in flr ol-btn-save`,
|
|
1237
2349
|
})}
|
|
1238
|
-
${
|
|
1239
|
-
|
|
2350
|
+
${ObjectLayerEngineModal.existingObjectLayerId
|
|
2351
|
+
? await BtnIcon.instance({
|
|
2352
|
+
label: html`<i class="submit-btn-icon fa-solid fa-clone"></i> Clone`,
|
|
2353
|
+
class: `in flr ol-btn-clone`,
|
|
2354
|
+
})
|
|
2355
|
+
: ''}
|
|
2356
|
+
${await BtnIcon.instance({
|
|
2357
|
+
label: html`<i class="submit-btn-icon fa-solid fa-broom"></i> ${Translate.instance('reset')}`,
|
|
1240
2358
|
class: `in flr ol-btn-reset`,
|
|
1241
2359
|
})}
|
|
1242
2360
|
</div>
|
|
1243
2361
|
<div class="in section-mp"></div>
|
|
1244
2362
|
`;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
2363
|
+
};
|
|
2364
|
+
|
|
2365
|
+
static getDirectionsFromDirectionCode(directionCode = '08') {
|
|
1247
2366
|
let objectLayerFrameDirections = [];
|
|
1248
2367
|
|
|
1249
2368
|
switch (directionCode) {
|
|
@@ -1274,8 +2393,9 @@ const ObjectLayerEngineModal = {
|
|
|
1274
2393
|
}
|
|
1275
2394
|
|
|
1276
2395
|
return objectLayerFrameDirections;
|
|
1277
|
-
}
|
|
1278
|
-
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
static toManagement = async (id = null) => {
|
|
1279
2399
|
await ObjectLayerEngineModal.clearData();
|
|
1280
2400
|
const subModalId = 'management';
|
|
1281
2401
|
const modalId = `modal-object-layer-engine-${subModalId}`;
|
|
@@ -1302,8 +2422,9 @@ const ObjectLayerEngineModal = {
|
|
|
1302
2422
|
await DefaultManagement.waitGridReady(modalId);
|
|
1303
2423
|
await DefaultManagement.loadTable(modalId, { force: true, reload: true });
|
|
1304
2424
|
});
|
|
1305
|
-
}
|
|
1306
|
-
|
|
2425
|
+
};
|
|
2426
|
+
|
|
2427
|
+
static async Reload() {
|
|
1307
2428
|
// Clear data before reload to prevent contamination
|
|
1308
2429
|
ObjectLayerEngineModal.clearData();
|
|
1309
2430
|
const idModal = 'modal-object-layer-engine';
|
|
@@ -1312,7 +2433,7 @@ const ObjectLayerEngineModal = {
|
|
|
1312
2433
|
idModal,
|
|
1313
2434
|
html: await Modal.Data[idModal].options.html(),
|
|
1314
2435
|
});
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
1317
2438
|
|
|
1318
2439
|
export { ObjectLayerEngineModal };
|