@underpostnet/cyberia 3.2.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +14 -0
- package/.env.example +144 -0
- package/.github/workflows/cyberia-client.cd.yml +40 -0
- package/.github/workflows/cyberia-server.cd.yml +40 -0
- package/.github/workflows/docker-image.cyberia-client.ci.yml +71 -0
- package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +70 -0
- package/.github/workflows/docker-image.cyberia-server.ci.yml +71 -0
- package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +71 -0
- package/.github/workflows/docker-image.engine-cyberia.ci.yml +53 -0
- package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +53 -0
- package/.github/workflows/engine-cyberia.cd.yml +157 -0
- package/.github/workflows/engine-cyberia.ci.yml +125 -0
- package/.github/workflows/ghpkg.ci.yml +160 -0
- package/.github/workflows/gitlab.ci.yml +20 -0
- package/.github/workflows/hardhat.ci.yml +82 -0
- package/.github/workflows/npmpkg.ci.yml +126 -0
- package/.github/workflows/publish.ci.yml +87 -0
- package/.github/workflows/publish.cyberia.ci.yml +79 -0
- package/.github/workflows/pwa-microservices-template-page.cd.yml +65 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +33 -0
- package/.github/workflows/release.cd.yml +46 -0
- package/.nycrc +9 -0
- package/.prettierignore +12 -0
- package/.prettierrc +9 -0
- package/.vscode/extensions.json +10 -0
- package/.vscode/settings.json +26 -0
- package/CHANGELOG.md +2516 -0
- package/CLI-HELP.md +1099 -0
- package/Dockerfile +161 -0
- package/Dockerfile.dev +161 -0
- package/Dockerfile.test +165 -0
- package/LICENSE +21 -0
- package/README.md +259 -0
- package/baremetal/commission-workflows.json +211 -0
- package/baremetal/packer-workflows.json +24 -0
- package/bin/build.js +261 -0
- package/bin/build.template.js +33 -0
- package/bin/cyberia.js +5627 -0
- package/bin/deploy.js +1547 -0
- package/bin/index.js +5627 -0
- package/bump.config.js +27 -0
- package/compose.env +144 -0
- package/conf.js +952 -0
- package/deployment.yaml +418 -0
- package/docker-compose.yml +434 -0
- package/examples/static-page/README.md +150 -0
- package/examples/static-page/ssr-components/CustomPage.js +554 -0
- package/examples/static-page/static-config-example.json +57 -0
- package/hardhat/.env.example +31 -0
- package/hardhat/contracts/ObjectLayerToken.sol +391 -0
- package/hardhat/deployments/.gitkeep +0 -0
- package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
- package/hardhat/hardhat.config.js +136 -0
- package/hardhat/ignition/modules/.gitkeep +0 -0
- package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
- package/hardhat/networks/besu-object-layer.network.json +138 -0
- package/hardhat/package-lock.json +2871 -0
- package/hardhat/package.json +43 -0
- package/hardhat/scripts/deployObjectLayerToken.js +98 -0
- package/hardhat/test/ObjectLayerToken.js +696 -0
- 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/ipfs/configure-ipfs.sh +13 -0
- package/jsconfig.json +9 -0
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +48 -0
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +48 -0
- package/manifests/deployment/adminer/deployment.yaml +32 -0
- package/manifests/deployment/adminer/kustomization.yaml +7 -0
- package/manifests/deployment/adminer/service.yaml +13 -0
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +418 -0
- package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
- package/manifests/deployment/dd-cyberia-development/proxy.yaml +189 -0
- package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +164 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +163 -0
- package/manifests/deployment/dd-default-development/proxy.yaml +46 -0
- package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
- package/manifests/deployment/fastapi/backend-service.yml +19 -0
- package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
- package/manifests/deployment/fastapi/frontend-service.yml +15 -0
- package/manifests/deployment/fastapi/initial_data.sh +8 -0
- package/manifests/deployment/kafka/deployment.yaml +67 -0
- package/manifests/deployment/mongo-express/deployment.yaml +62 -0
- package/manifests/deployment/phpmyadmin/deployment.yaml +54 -0
- package/manifests/deployment/playwright/deployment.yaml +52 -0
- package/manifests/deployment/spark/spark-pi-py.yaml +20 -0
- package/manifests/deployment/tensorflow/tf-gpu-test.yaml +63 -0
- package/manifests/envoy-service-nodeport.yaml +22 -0
- package/manifests/grafana/deployment.yaml +64 -0
- package/manifests/grafana/kustomization.yaml +7 -0
- package/manifests/grafana/pvc.yaml +12 -0
- package/manifests/grafana/service.yaml +14 -0
- package/manifests/grafana/storage-class.yaml +9 -0
- package/manifests/ipfs/configmap.yaml +64 -0
- package/manifests/ipfs/headless-service.yaml +35 -0
- package/manifests/ipfs/kustomization.yaml +8 -0
- package/manifests/ipfs/statefulset.yaml +149 -0
- package/manifests/ipfs/storage-class.yaml +9 -0
- package/manifests/kind-config-dev.yaml +20 -0
- package/manifests/kind-config.yaml +12 -0
- package/manifests/kubeadm-calico-config.yaml +14 -0
- package/manifests/letsencrypt-prod.yaml +14 -0
- package/manifests/lxd/lxd-admin-profile.yaml +26 -0
- package/manifests/lxd/lxd-preseed.yaml +30 -0
- package/manifests/mariadb/kustomization.yaml +9 -0
- package/manifests/mariadb/pv.yaml +12 -0
- package/manifests/mariadb/pvc.yaml +10 -0
- package/manifests/mariadb/service.yaml +10 -0
- package/manifests/mariadb/statefulset.yaml +56 -0
- package/manifests/mariadb/storage-class.yaml +10 -0
- package/manifests/mongodb/headless-service.yaml +10 -0
- package/manifests/mongodb/kustomization.yaml +11 -0
- package/manifests/mongodb/pv-pvc.yaml +59 -0
- package/manifests/mongodb/statefulset.yaml +113 -0
- package/manifests/mongodb/storage-class.yaml +9 -0
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +9 -0
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +19 -0
- package/manifests/mongodb-4.4/service-deployment.yaml +61 -0
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/mysql/kustomization.yaml +7 -0
- package/manifests/mysql/pv-pvc.yaml +27 -0
- package/manifests/mysql/statefulset.yaml +55 -0
- package/manifests/postgresql/configmap.yaml +9 -0
- package/manifests/postgresql/kustomization.yaml +10 -0
- package/manifests/postgresql/pv.yaml +15 -0
- package/manifests/postgresql/pvc.yaml +13 -0
- package/manifests/postgresql/service.yaml +10 -0
- package/manifests/postgresql/statefulset.yaml +37 -0
- package/manifests/prometheus/deployment.yaml +82 -0
- package/manifests/pv-pvc-dd.yaml +34 -0
- package/manifests/valkey/kustomization.yaml +7 -0
- package/manifests/valkey/service.yaml +10 -0
- package/manifests/valkey/statefulset.yaml +37 -0
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/mongodb/entrypoint.sh +76 -0
- package/nginx.conf +128 -0
- package/nodemon.json +6 -0
- package/package.json +101 -0
- package/packer/images/Rocky9Amd64/Makefile +62 -0
- package/packer/images/Rocky9Amd64/QUICKSTART.md +113 -0
- package/packer/images/Rocky9Amd64/README.md +122 -0
- package/packer/images/Rocky9Amd64/http/rocky9.ks.pkrtpl.hcl +114 -0
- package/packer/images/Rocky9Amd64/rocky9.pkr.hcl +164 -0
- package/packer/images/Rocky9Arm64/Makefile +69 -0
- package/packer/images/Rocky9Arm64/README.md +122 -0
- package/packer/images/Rocky9Arm64/http/rocky9.ks.pkrtpl.hcl +114 -0
- package/packer/images/Rocky9Arm64/rocky9.pkr.hcl +171 -0
- package/packer/scripts/fuse-nbd +64 -0
- package/packer/scripts/fuse-tar-root +63 -0
- package/proxy.yaml +189 -0
- package/pv-pvc.yaml +164 -0
- package/scripts/device-scan.sh +65 -0
- package/scripts/disk-clean.sh +182 -0
- package/scripts/disk-devices.sh +13 -0
- package/scripts/gen-fqdns.sh +14 -0
- package/scripts/gpu-diag.sh +19 -0
- package/scripts/ip-info.sh +118 -0
- package/scripts/ipxe-setup.sh +200 -0
- package/scripts/k3s-node-setup.sh +124 -0
- package/scripts/kubeadm-node-setup.sh +317 -0
- package/scripts/link-local-underpost-cli.sh +6 -0
- package/scripts/lxd-vm-setup.sh +208 -0
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/scripts/maas-setup.sh +135 -0
- package/scripts/maas-upload-boot-resource.sh +183 -0
- package/scripts/nat-iptables.sh +111 -0
- package/scripts/nvim.sh +91 -0
- package/scripts/packer-init-vars-file.sh +40 -0
- package/scripts/packer-setup.sh +289 -0
- package/scripts/ports-ls.sh +33 -0
- package/scripts/quick-tftp.sh +19 -0
- package/scripts/rhel-grpc-setup.sh +56 -0
- package/scripts/rocky-kickstart.sh +986 -0
- package/scripts/rocky-pwa.sh +200 -0
- package/scripts/rocky-setup.sh +106 -0
- package/scripts/rpmfusion-ffmpeg-setup.sh +32 -0
- package/scripts/ssl.sh +170 -0
- package/scripts/test-monitor.sh +248 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +30 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +155 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +39 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +382 -0
- package/src/api/core/core.controller.js +8 -0
- package/src/api/core/core.model.js +11 -0
- package/src/api/core/core.router.js +23 -0
- package/src/api/core/core.service.js +30 -0
- package/src/api/crypto/crypto.controller.js +10 -0
- package/src/api/crypto/crypto.model.js +23 -0
- package/src/api/crypto/crypto.router.js +23 -0
- package/src/api/crypto/crypto.service.js +64 -0
- package/src/api/cyberia-action/cyberia-action.controller.js +8 -0
- package/src/api/cyberia-action/cyberia-action.model.js +79 -0
- package/src/api/cyberia-action/cyberia-action.router.js +21 -0
- package/src/api/cyberia-action/cyberia-action.service.js +58 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +27 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +100 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +70 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +8 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +20 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +57 -0
- package/src/api/cyberia-entity/cyberia-entity.controller.js +6 -0
- package/src/api/cyberia-entity/cyberia-entity.model.js +25 -0
- package/src/api/cyberia-entity/cyberia-entity.router.js +17 -0
- package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +6 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -0
- package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
- package/src/api/cyberia-instance/cyberia-fallback-world.js +337 -0
- package/src/api/cyberia-instance/cyberia-instance-boot.service.js +57 -0
- package/src/api/cyberia-instance/cyberia-instance-map.service.js +583 -0
- package/src/api/cyberia-instance/cyberia-instance.controller.js +42 -0
- package/src/api/cyberia-instance/cyberia-instance.model.js +117 -0
- package/src/api/cyberia-instance/cyberia-instance.router.js +75 -0
- package/src/api/cyberia-instance/cyberia-instance.service.js +190 -0
- package/src/api/cyberia-instance/cyberia-portal-connector.js +260 -0
- package/src/api/cyberia-instance/cyberia-world-generator.js +618 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +6 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +200 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +17 -0
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +46 -0
- package/src/api/cyberia-map/cyberia-map.controller.js +6 -0
- package/src/api/cyberia-map/cyberia-map.model.js +33 -0
- package/src/api/cyberia-map/cyberia-map.router.js +19 -0
- package/src/api/cyberia-map/cyberia-map.service.js +76 -0
- package/src/api/cyberia-quest/cyberia-quest.controller.js +9 -0
- package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
- package/src/api/cyberia-quest/cyberia-quest.router.js +26 -0
- package/src/api/cyberia-quest/cyberia-quest.service.js +97 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +6 -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 +21 -0
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
- package/src/api/cyberia-saga/cyberia-saga.controller.js +6 -0
- package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
- package/src/api/cyberia-saga/cyberia-saga.router.js +17 -0
- package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +1076 -0
- package/src/api/cyberia-skill/cyberia-skill.controller.js +6 -0
- package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
- package/src/api/cyberia-skill/cyberia-skill.router.js +17 -0
- package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
- package/src/api/default/default.controller.js +6 -0
- package/src/api/default/default.model.js +20 -0
- package/src/api/default/default.router.js +21 -0
- package/src/api/default/default.service.js +42 -0
- package/src/api/document/document.controller.js +9 -0
- package/src/api/document/document.model.js +95 -0
- package/src/api/document/document.router.js +32 -0
- package/src/api/document/document.service.js +633 -0
- package/src/api/file/file.controller.js +15 -0
- package/src/api/file/file.model.js +127 -0
- package/src/api/file/file.ref.json +39 -0
- package/src/api/file/file.router.js +36 -0
- package/src/api/file/file.service.js +499 -0
- package/src/api/instance/instance.controller.js +8 -0
- package/src/api/instance/instance.model.js +34 -0
- package/src/api/instance/instance.router.js +27 -0
- package/src/api/instance/instance.service.js +75 -0
- package/src/api/ipfs/ipfs.controller.js +8 -0
- package/src/api/ipfs/ipfs.model.js +77 -0
- package/src/api/ipfs/ipfs.router.js +26 -0
- package/src/api/ipfs/ipfs.service.js +145 -0
- package/src/api/object-layer/object-layer.controller.js +18 -0
- package/src/api/object-layer/object-layer.model.js +200 -0
- package/src/api/object-layer/object-layer.router.js +729 -0
- package/src/api/object-layer/object-layer.service.js +894 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +6 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +93 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +17 -0
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +46 -0
- package/src/api/test/test.controller.js +14 -0
- package/src/api/test/test.model.js +14 -0
- package/src/api/test/test.router.js +23 -0
- package/src/api/test/test.service.js +35 -0
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +100 -0
- package/src/api/user/postman_collection.json +216 -0
- package/src/api/user/user.build.js +16 -0
- package/src/api/user/user.controller.js +35 -0
- package/src/api/user/user.model.js +142 -0
- package/src/api/user/user.router.js +367 -0
- package/src/api/user/user.service.js +582 -0
- package/src/api.js +23 -0
- package/src/cli/baremetal.js +3947 -0
- package/src/cli/cloud-init.js +673 -0
- package/src/cli/cluster.js +1395 -0
- package/src/cli/db.js +1533 -0
- package/src/cli/deploy.js +1542 -0
- package/src/cli/docker-compose.js +802 -0
- package/src/cli/env.js +177 -0
- package/src/cli/fs.js +380 -0
- package/src/cli/image.js +389 -0
- package/src/cli/index.js +1059 -0
- package/src/cli/ipfs.js +182 -0
- package/src/cli/kickstart.js +271 -0
- package/src/cli/kubectl.js +214 -0
- package/src/cli/lxd.js +1232 -0
- package/src/cli/monitor.js +659 -0
- package/src/cli/release.js +595 -0
- package/src/cli/repository.js +1969 -0
- package/src/cli/run.js +3326 -0
- package/src/cli/secrets.js +151 -0
- package/src/cli/ssh.js +975 -0
- package/src/cli/static.js +653 -0
- package/src/cli/system.js +332 -0
- package/src/cli/test.js +176 -0
- package/src/client/Cryptokoyn.index.js +30 -0
- package/src/client/CyberiaPortal.index.js +31 -0
- package/src/client/Default.index.js +77 -0
- package/src/client/Itemledger.index.js +35 -0
- package/src/client/Underpost.index.js +31 -0
- package/src/client/components/core/404.js +20 -0
- package/src/client/components/core/500.js +20 -0
- package/src/client/components/core/Account.js +630 -0
- package/src/client/components/core/AgGrid.js +238 -0
- package/src/client/components/core/Alert.js +76 -0
- package/src/client/components/core/AppStore.js +69 -0
- package/src/client/components/core/Auth.js +353 -0
- package/src/client/components/core/Badge.js +26 -0
- package/src/client/components/core/Blockchain.js +41 -0
- package/src/client/components/core/Blog.js +9 -0
- package/src/client/components/core/BtnIcon.js +109 -0
- package/src/client/components/core/CalendarCore.js +437 -0
- package/src/client/components/core/Chat.js +62 -0
- package/src/client/components/core/ClientEvents.js +163 -0
- package/src/client/components/core/ColorPaletteElement.js +309 -0
- package/src/client/components/core/CommonJs.js +1014 -0
- package/src/client/components/core/Content.js +349 -0
- package/src/client/components/core/Css.js +1134 -0
- package/src/client/components/core/CssCore.js +881 -0
- package/src/client/components/core/D3Chart.js +44 -0
- package/src/client/components/core/Docs.js +478 -0
- package/src/client/components/core/DropDown.js +321 -0
- package/src/client/components/core/EventBus.js +96 -0
- package/src/client/components/core/EventsUI.js +130 -0
- package/src/client/components/core/FileExplorer.js +1406 -0
- package/src/client/components/core/FullScreen.js +201 -0
- package/src/client/components/core/Input.js +537 -0
- package/src/client/components/core/Keyboard.js +80 -0
- package/src/client/components/core/KeyboardAvoidance.js +145 -0
- package/src/client/components/core/LoadingAnimation.js +152 -0
- package/src/client/components/core/LogIn.js +212 -0
- package/src/client/components/core/LogOut.js +72 -0
- package/src/client/components/core/Logger.js +22 -0
- package/src/client/components/core/Modal.js +2956 -0
- package/src/client/components/core/NotificationManager.js +80 -0
- package/src/client/components/core/Pagination.js +252 -0
- package/src/client/components/core/Panel.js +1308 -0
- package/src/client/components/core/PanelForm.js +915 -0
- package/src/client/components/core/Polyhedron.js +947 -0
- package/src/client/components/core/PublicProfile.js +895 -0
- package/src/client/components/core/Recover.js +211 -0
- package/src/client/components/core/Responsive.js +146 -0
- package/src/client/components/core/RichText.js +33 -0
- package/src/client/components/core/Router.js +523 -0
- package/src/client/components/core/Scroll.js +76 -0
- package/src/client/components/core/SearchBox.js +1007 -0
- package/src/client/components/core/SignUp.js +153 -0
- package/src/client/components/core/SocketIo.js +163 -0
- package/src/client/components/core/SocketIoHandler.js +75 -0
- package/src/client/components/core/Stream.js +161 -0
- package/src/client/components/core/ToggleSwitch.js +89 -0
- package/src/client/components/core/ToolTip.js +78 -0
- package/src/client/components/core/Translate.js +694 -0
- package/src/client/components/core/Validator.js +140 -0
- package/src/client/components/core/VanillaJs.js +485 -0
- package/src/client/components/core/Wallet.js +95 -0
- package/src/client/components/core/WebComponent.js +44 -0
- package/src/client/components/core/Webhook.js +58 -0
- package/src/client/components/core/Worker.js +313 -0
- package/src/client/components/core/windowGetDimensions.js +269 -0
- package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +352 -0
- package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
- package/src/client/components/cryptokoyn/CssCryptokoyn.js +212 -0
- package/src/client/components/cryptokoyn/LogInCryptokoyn.js +16 -0
- package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +12 -0
- package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
- package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +16 -0
- package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +11 -0
- package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +6 -0
- package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
- package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
- package/src/client/components/cyberia/InstanceEngineCyberia.js +1088 -0
- package/src/client/components/cyberia/InstanceSelectionView.js +900 -0
- package/src/client/components/cyberia/MapEngineCyberia.js +1976 -0
- package/src/client/components/cyberia/ObjectLayerEngine.js +1540 -0
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +2420 -0
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +1522 -0
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +528 -0
- package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +772 -0
- package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
- package/src/client/components/cyberia-portal/CssCyberiaPortal.js +254 -0
- package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +21 -0
- package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +16 -0
- package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +518 -0
- package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +72 -0
- package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +16 -0
- package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +13 -0
- package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +6 -0
- package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +48 -0
- package/src/client/components/default/AppShellDefault.js +765 -0
- package/src/client/components/default/AppStoreDefault.js +5 -0
- package/src/client/components/default/CommonDefault.js +29 -0
- package/src/client/components/default/CssDefault.js +27 -0
- package/src/client/components/default/LogInDefault.js +16 -0
- package/src/client/components/default/LogOutDefault.js +12 -0
- package/src/client/components/default/RouterDefault.js +47 -0
- package/src/client/components/default/SettingsDefault.js +16 -0
- package/src/client/components/default/SignUpDefault.js +11 -0
- package/src/client/components/default/SocketIoDefault.js +6 -0
- package/src/client/components/default/TranslateDefault.js +7 -0
- package/src/client/components/itemledger/AppShellItemledger.js +353 -0
- package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
- package/src/client/components/itemledger/CssItemledger.js +212 -0
- package/src/client/components/itemledger/LogInItemledger.js +17 -0
- package/src/client/components/itemledger/LogOutItemledger.js +12 -0
- package/src/client/components/itemledger/RouterItemledger.js +38 -0
- package/src/client/components/itemledger/SettingsItemledger.js +16 -0
- package/src/client/components/itemledger/SignUpItemledger.js +11 -0
- package/src/client/components/itemledger/SocketIoItemledger.js +6 -0
- package/src/client/components/itemledger/TranslateItemledger.js +7 -0
- package/src/client/components/underpost/AppShellUnderpost.js +691 -0
- package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
- package/src/client/components/underpost/CssUnderpost.js +281 -0
- package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +879 -0
- package/src/client/components/underpost/DocumentSearchProvider.js +448 -0
- package/src/client/components/underpost/LabGalleryUnderpost.js +79 -0
- package/src/client/components/underpost/LogInUnderpost.js +25 -0
- package/src/client/components/underpost/LogOutUnderpost.js +17 -0
- package/src/client/components/underpost/RouterUnderpost.js +45 -0
- package/src/client/components/underpost/SettingsUnderpost.js +16 -0
- package/src/client/components/underpost/SignUpUnderpost.js +11 -0
- package/src/client/components/underpost/SocketIoUnderpost.js +6 -0
- package/src/client/components/underpost/TranslateUnderpost.js +10 -0
- package/src/client/public/cryptokoyn/assets/banner/koyn-social.png +0 -0
- package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
- package/src/client/public/cryptokoyn/assets/logo/cryptokoyn.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-144x144.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-192x192.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-256x256.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-36x36.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-48x48.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-72x72.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/android-chrome-96x96.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-114x114-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-120x120-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-144x144-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-152x152-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-180x180-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-57x57-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-60x60-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-72x72-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-76x76-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/favicon-16x16.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/favicon-32x32.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-144x144.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-150x150.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-310x150.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-310x310.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/mstile-70x70.png +0 -0
- package/src/client/public/cryptokoyn/assets/splash/safari-pinned-tab.svg +42 -0
- package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
- package/src/client/public/cryptokoyn/favicon.ico +0 -0
- package/src/client/public/cryptokoyn/microdata.json +85 -0
- package/src/client/public/cryptokoyn/site.webmanifest +57 -0
- package/src/client/public/cryptokoyn/sitemap +148 -0
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +307 -0
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +309 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +204 -0
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +341 -0
- package/src/client/public/cyberia-docs/CYBERIA-LORE.md +84 -0
- package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +294 -0
- package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
- package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +242 -0
- package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +309 -0
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +228 -0
- package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
- package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +740 -0
- package/src/client/public/default/android-chrome-144x144.png +0 -0
- package/src/client/public/default/android-chrome-192x192.png +0 -0
- package/src/client/public/default/android-chrome-256x256.png +0 -0
- package/src/client/public/default/android-chrome-36x36.png +0 -0
- package/src/client/public/default/android-chrome-384x384.png +0 -0
- package/src/client/public/default/android-chrome-48x48.png +0 -0
- package/src/client/public/default/android-chrome-512x512.png +0 -0
- package/src/client/public/default/android-chrome-72x72.png +0 -0
- package/src/client/public/default/android-chrome-96x96.png +0 -0
- package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/default/apple-touch-icon.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
- package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
- package/src/client/public/default/assets/background/dark.jpg +0 -0
- package/src/client/public/default/assets/background/dark.svg +557 -0
- package/src/client/public/default/assets/background/white.jpg +0 -0
- package/src/client/public/default/assets/background/white0-min.jpg +0 -0
- package/src/client/public/default/assets/background/white0.jpg +0 -0
- package/src/client/public/default/assets/logo/base-icon.png +0 -0
- package/src/client/public/default/assets/logo/underpost.gif +0 -0
- package/src/client/public/default/assets/mailer/api-user-check.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-invalid-token.png +0 -0
- package/src/client/public/default/assets/mailer/api-user-recover.png +0 -0
- package/src/client/public/default/browserconfig.xml +12 -0
- package/src/client/public/default/favicon-16x16.png +0 -0
- package/src/client/public/default/favicon-32x32.png +0 -0
- package/src/client/public/default/favicon-48x48.png +0 -0
- package/src/client/public/default/favicon.ico +0 -0
- package/src/client/public/default/manifest.webmanifest +69 -0
- package/src/client/public/default/mstile-144x144.png +0 -0
- package/src/client/public/default/mstile-150x150.png +0 -0
- package/src/client/public/default/mstile-310x150.png +0 -0
- package/src/client/public/default/mstile-310x310.png +0 -0
- package/src/client/public/default/mstile-70x70.png +0 -0
- package/src/client/public/default/safari-pinned-tab.svg +24 -0
- package/src/client/public/default/site.webmanifest +69 -0
- package/src/client/public/default/sitemap +148 -0
- package/src/client/public/default/yandex-browser-50x50.png +0 -0
- package/src/client/public/default/yandex-browser-manifest.json +9 -0
- package/src/client/public/doc/favicon.ico +0 -0
- package/src/client/public/doc/sitemap +148 -0
- package/src/client/public/itemledger/android-chrome-144x144.png +0 -0
- package/src/client/public/itemledger/android-chrome-192x192.png +0 -0
- package/src/client/public/itemledger/android-chrome-256x256.png +0 -0
- package/src/client/public/itemledger/android-chrome-36x36.png +0 -0
- package/src/client/public/itemledger/android-chrome-384x384.png +0 -0
- package/src/client/public/itemledger/android-chrome-48x48.png +0 -0
- package/src/client/public/itemledger/android-chrome-512x512.png +0 -0
- package/src/client/public/itemledger/android-chrome-72x72.png +0 -0
- package/src/client/public/itemledger/android-chrome-96x96.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-1024x1024.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-114x114.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-120x120.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-144x144.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-152x152.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-167x167.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-180x180.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-57x57.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-60x60.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-72x72.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-76x76.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon-precomposed.png +0 -0
- package/src/client/public/itemledger/apple-touch-icon.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1125x2436.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1136x640.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1170x2532.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1179x2556.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1242x2208.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1242x2688.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1284x2778.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1290x2796.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1334x750.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1488x2266.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1536x2048.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1620x2160.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1640x2160.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1668x2224.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1668x2388.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-1792x828.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2048x1536.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2048x2732.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2160x1620.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2160x1640.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2208x1242.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2224x1668.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2266x1488.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2388x1668.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2436x1125.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2532x1170.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2556x1179.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2688x1242.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2732x2048.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2778x1284.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-2796x1290.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-640x1136.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-750x1334.png +0 -0
- package/src/client/public/itemledger/apple-touch-startup-image-828x1792.png +0 -0
- package/src/client/public/itemledger/assets/logo/base-icon.png +0 -0
- package/src/client/public/itemledger/browserconfig.xml +12 -0
- package/src/client/public/itemledger/favicon-16x16.png +0 -0
- package/src/client/public/itemledger/favicon-32x32.png +0 -0
- package/src/client/public/itemledger/favicon-48x48.png +0 -0
- package/src/client/public/itemledger/favicon.ico +0 -0
- package/src/client/public/itemledger/manifest.webmanifest +69 -0
- package/src/client/public/itemledger/microdata.json +71 -0
- package/src/client/public/itemledger/mstile-144x144.png +0 -0
- package/src/client/public/itemledger/mstile-150x150.png +0 -0
- package/src/client/public/itemledger/mstile-310x150.png +0 -0
- package/src/client/public/itemledger/mstile-310x310.png +0 -0
- package/src/client/public/itemledger/mstile-70x70.png +0 -0
- package/src/client/public/itemledger/sitemap +148 -0
- package/src/client/public/itemledger/yandex-browser-50x50.png +0 -0
- package/src/client/public/itemledger/yandex-browser-manifest.json +9 -0
- package/src/client/public/test/favicon.ico +0 -0
- package/src/client/public/test/sitemap +148 -0
- package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +137 -0
- package/src/client/services/core/core.service.js +309 -0
- package/src/client/services/crypto/crypto.service.js +68 -0
- package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
- package/src/client/services/cyberia-client-hints/cyberia-client-hints.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-entity-type-default/cyberia-entity-type-default.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 +137 -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/cyberia-saga/cyberia-saga.service.js +99 -0
- package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
- package/src/client/services/default/default.management.js +1015 -0
- package/src/client/services/default/default.service.js +99 -0
- package/src/client/services/document/document.service.js +134 -0
- package/src/client/services/file/file.service.js +94 -0
- package/src/client/services/instance/instance.management.js +78 -0
- package/src/client/services/instance/instance.service.js +107 -0
- package/src/client/services/ipfs/ipfs.service.js +118 -0
- package/src/client/services/object-layer/object-layer.management.js +414 -0
- package/src/client/services/object-layer/object-layer.service.js +208 -0
- package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +99 -0
- package/src/client/services/test/test.service.js +68 -0
- package/src/client/services/user/guest.service.js +86 -0
- package/src/client/services/user/user.management.js +51 -0
- package/src/client/services/user/user.service.js +106 -0
- package/src/client/ssr/RootDocument.js +237 -0
- package/src/client/ssr/body/404.js +77 -0
- package/src/client/ssr/body/500.js +76 -0
- package/src/client/ssr/body/CacheControl.js +117 -0
- package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +97 -0
- package/src/client/ssr/body/DefaultSplashScreen.js +97 -0
- package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
- package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +90 -0
- package/src/client/ssr/head/CryptokoynScripts.js +4 -0
- package/src/client/ssr/head/Css.js +241 -0
- package/src/client/ssr/head/CyberiaPortalScripts.js +6 -0
- package/src/client/ssr/head/DefaultScripts.js +6 -0
- package/src/client/ssr/head/ItemledgerScripts.js +4 -0
- package/src/client/ssr/head/Microdata.js +11 -0
- package/src/client/ssr/head/Production.js +1 -0
- package/src/client/ssr/head/Pwa.js +146 -0
- package/src/client/ssr/head/PwaItemledger.js +197 -0
- package/src/client/ssr/head/Seo.js +15 -0
- package/src/client/ssr/head/UnderpostScripts.js +6 -0
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +20 -0
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +16 -0
- package/src/client/ssr/views/Cyberia404.js +328 -0
- package/src/client/ssr/views/CyberiaServerMetrics.js +1070 -0
- package/src/client/ssr/views/Maintenance.js +64 -0
- package/src/client/ssr/views/NoNetworkConnection.js +68 -0
- package/src/client/ssr/views/Test.js +199 -0
- package/src/client/sw/core.sw.js +274 -0
- package/src/client-builder/client-build-docs.js +493 -0
- package/src/client-builder/client-build-live.js +100 -0
- package/src/client-builder/client-build.js +1092 -0
- package/src/client-builder/client-dev-server.js +88 -0
- package/src/client-builder/client-formatted.js +170 -0
- package/src/client-builder/client-icons.js +108 -0
- package/src/client-builder/ssr.js +124 -0
- package/src/client.build.js +17 -0
- package/src/client.dev.js +21 -0
- package/src/db/DataBaseProvider.js +213 -0
- package/src/db/mariadb/MariaDB.js +72 -0
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +199 -0
- package/src/grpc/cyberia/grpc-server.js +162 -0
- package/src/index.js +357 -0
- package/src/mailer/EmailRender.js +116 -0
- package/src/mailer/MailerProvider.js +213 -0
- package/src/projects/cyberia/atlas-sprite-sheet-generator.js +413 -0
- package/src/projects/cyberia/besu-genesis-generator.js +1630 -0
- package/src/projects/cyberia/catalog-cyberia.js +90 -0
- package/src/projects/cyberia/gemini-client.js +175 -0
- package/src/projects/cyberia/generate-saga.js +2137 -0
- package/src/projects/cyberia/hot-reload-trigger.js +163 -0
- package/src/projects/cyberia/instance-data.js +719 -0
- package/src/projects/cyberia/ipfs-client.js +599 -0
- package/src/projects/cyberia/map-preview-generator.js +304 -0
- package/src/projects/cyberia/object-layer.js +978 -0
- package/src/projects/cyberia/semantic-layer-generator-floor.js +319 -0
- package/src/projects/cyberia/semantic-layer-generator-resource.js +259 -0
- package/src/projects/cyberia/semantic-layer-generator-skin.js +1164 -0
- package/src/projects/cyberia/semantic-layer-generator.js +753 -0
- package/src/projects/cyberia/shape-generator.js +1060 -0
- package/src/projects/underpost/catalog-underpost.js +60 -0
- package/src/proxy.js +19 -0
- package/src/runtime/cyberia-client/Dockerfile +49 -0
- package/src/runtime/cyberia-client/Dockerfile.dev +75 -0
- package/src/runtime/cyberia-server/Dockerfile +43 -0
- package/src/runtime/cyberia-server/Dockerfile.dev +56 -0
- package/src/runtime/engine-cyberia/Dockerfile +161 -0
- package/src/runtime/engine-cyberia/Dockerfile.dev +161 -0
- package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
- package/src/runtime/engine-cyberia/compose.env +144 -0
- package/src/runtime/engine-cyberia/docker-compose.yml +434 -0
- package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
- package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
- package/src/runtime/engine-cyberia/nginx.conf +128 -0
- package/src/runtime/express/Dockerfile +45 -0
- package/src/runtime/express/Express.js +285 -0
- package/src/runtime/lampp/Dockerfile +62 -0
- package/src/runtime/lampp/Lampp.js +359 -0
- package/src/runtime/nginx/Nginx.js +250 -0
- package/src/runtime/wp/Dockerfile +62 -0
- package/src/runtime/wp/Wp.js +642 -0
- package/src/server/auth.js +713 -0
- package/src/server/backup.js +102 -0
- package/src/server/catalog.js +72 -0
- package/src/server/conf.js +2316 -0
- package/src/server/cron.js +476 -0
- package/src/server/crypto.js +210 -0
- package/src/server/data-query.js +461 -0
- package/src/server/dns.js +553 -0
- package/src/server/downloader.js +73 -0
- package/src/server/logger.js +229 -0
- package/src/server/middlewares.js +152 -0
- package/src/server/peer.js +75 -0
- package/src/server/process.js +299 -0
- package/src/server/proxy.js +139 -0
- package/src/server/runtime-status.js +252 -0
- package/src/server/runtime.js +183 -0
- package/src/server/start.js +272 -0
- package/src/server/tls.js +254 -0
- package/src/server/valkey.js +201 -0
- package/src/server.js +25 -0
- package/src/ws/IoInterface.js +129 -0
- package/src/ws/IoServer.js +68 -0
- package/src/ws/core/channels/core.ws.chat.js +68 -0
- package/src/ws/core/channels/core.ws.mailer.js +116 -0
- package/src/ws/core/channels/core.ws.stream.js +90 -0
- package/src/ws/core/core.ws.connection.js +41 -0
- package/src/ws/core/core.ws.emit.js +37 -0
- package/src/ws/core/core.ws.server.js +44 -0
- package/src/ws/default/channels/default.ws.main.js +57 -0
- package/src/ws/default/default.ws.connection.js +35 -0
- package/src/ws/default/default.ws.emit.js +14 -0
- package/src/ws/default/default.ws.server.js +39 -0
- package/test/api.test.js +53 -0
- package/test/crypto.test.js +117 -0
- package/test/cyberia-instance-conf-defaults.test.js +140 -0
- package/test/deploy-monitor.test.js +267 -0
- package/test/shape-generator.test.js +463 -0
- package/tsconfig.docs.json +15 -0
- package/typedoc.dd-cyberia.json +31 -0
- package/typedoc.json +31 -0
|
@@ -0,0 +1,2420 @@
|
|
|
1
|
+
import { CoreService } from '../../services/core/core.service.js';
|
|
2
|
+
import { BtnIcon } from '../core/BtnIcon.js';
|
|
3
|
+
import { borderChar, Css, dynamicCol, Themes } from '../core/Css.js';
|
|
4
|
+
import { DropDown } from '../core/DropDown.js';
|
|
5
|
+
import { EventsUI } from '../core/EventsUI.js';
|
|
6
|
+
import { Translate } from '../core/Translate.js';
|
|
7
|
+
import { s, append, hexToRgbA } from '../core/VanillaJs.js';
|
|
8
|
+
import { getProxyPath, getQueryParams, setPath, setQueryParams, RouterEvents } from '../core/Router.js';
|
|
9
|
+
import { s4, commonModeratorGuard } from '../core/CommonJs.js';
|
|
10
|
+
import { Input } from '../core/Input.js';
|
|
11
|
+
import { ToggleSwitch } from '../core/ToggleSwitch.js';
|
|
12
|
+
import { ObjectLayerService } from '../../services/object-layer/object-layer.service.js';
|
|
13
|
+
import { NotificationManager } from '../core/NotificationManager.js';
|
|
14
|
+
import { AgGrid } from '../core/AgGrid.js';
|
|
15
|
+
import { Modal } from '../core/Modal.js';
|
|
16
|
+
import { LoadingAnimation } from '../core/LoadingAnimation.js';
|
|
17
|
+
import { DefaultManagement } from '../../services/default/default.management.js';
|
|
18
|
+
import * as _ from '../cyberia/ObjectLayerEngine.js';
|
|
19
|
+
import {
|
|
20
|
+
ITEM_TYPES,
|
|
21
|
+
OBJECT_LAYER_DIRECTION_CODES,
|
|
22
|
+
OBJECT_LAYER_DIRECTION_LABELS,
|
|
23
|
+
getKeyframeDirectionsByCode,
|
|
24
|
+
STAT_TYPES,
|
|
25
|
+
} from './SharedDefaultsCyberia.js';
|
|
26
|
+
import '../core/ColorPaletteElement.js';
|
|
27
|
+
|
|
28
|
+
const CANVAS_BEHAVIOR_ICON = 'fa-solid fa-shapes';
|
|
29
|
+
|
|
30
|
+
const DISTORTION_TYPES = Object.freeze([
|
|
31
|
+
{
|
|
32
|
+
value: 'position-jitter',
|
|
33
|
+
label: 'Position Jitter',
|
|
34
|
+
group: 'distortion',
|
|
35
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
value: 'rotation-drift',
|
|
39
|
+
label: 'Rotation Drift',
|
|
40
|
+
group: 'distortion',
|
|
41
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
value: 'scale-wobble',
|
|
45
|
+
label: 'Scale Wobble',
|
|
46
|
+
group: 'distortion',
|
|
47
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
value: 'particle-drift',
|
|
51
|
+
label: 'Particle Drift',
|
|
52
|
+
group: 'distortion',
|
|
53
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
const MOSAIC_TYPES = Object.freeze([
|
|
58
|
+
{
|
|
59
|
+
value: 'mosaic-diamond-checker',
|
|
60
|
+
label: 'Diamond Checker',
|
|
61
|
+
group: 'mosaic',
|
|
62
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
value: 'mosaic-rhombus-lattice',
|
|
66
|
+
label: 'Rhombus Lattice',
|
|
67
|
+
group: 'mosaic',
|
|
68
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
value: 'mosaic-zigzag-rows',
|
|
72
|
+
label: 'Zigzag Rows',
|
|
73
|
+
group: 'mosaic',
|
|
74
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
value: 'mosaic-staggered-tiles',
|
|
78
|
+
label: 'Staggered Tiles',
|
|
79
|
+
group: 'mosaic',
|
|
80
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
value: 'mosaic-brick-offset',
|
|
84
|
+
label: 'Brick Offset',
|
|
85
|
+
group: 'mosaic',
|
|
86
|
+
icon: CANVAS_BEHAVIOR_ICON,
|
|
87
|
+
},
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
const CANVAS_BEHAVIORS = Object.freeze([...DISTORTION_TYPES, ...MOSAIC_TYPES]);
|
|
91
|
+
|
|
92
|
+
const DEFAULT_DISTORTION_TYPE = DISTORTION_TYPES[0].value;
|
|
93
|
+
const DEFAULT_DISTORTION_STATUS =
|
|
94
|
+
'Applies the selected canvas behavior directly to the current editor frame. factorA controls distortion density or mosaic tile scale.';
|
|
95
|
+
const DEFAULT_DISTORTION_FACTOR_A = 0.12;
|
|
96
|
+
const DEFAULT_STAT_RANDOM_MIN = 0;
|
|
97
|
+
const DEFAULT_STAT_RANDOM_MAX = 10;
|
|
98
|
+
const UNIFORM_OPACITY_TOGGLE_ID = 'ol-uniform-opacity-lock';
|
|
99
|
+
const DIRECTION_PREVIEW_MODAL_ID = 'modal-object-layer-direction-preview';
|
|
100
|
+
const CANVAS_BEHAVIOR_BY_VALUE = Object.freeze(
|
|
101
|
+
Object.fromEntries(CANVAS_BEHAVIORS.map((entry) => [entry.value, entry])),
|
|
102
|
+
);
|
|
103
|
+
const isMosaicBehavior = (value = '') => CANVAS_BEHAVIOR_BY_VALUE[value]?.group === 'mosaic';
|
|
104
|
+
const getCanvasBehaviorDisplay = (value = DEFAULT_DISTORTION_TYPE) => {
|
|
105
|
+
const behavior = CANVAS_BEHAVIOR_BY_VALUE[value] || CANVAS_BEHAVIOR_BY_VALUE[DEFAULT_DISTORTION_TYPE];
|
|
106
|
+
return `<i class="${CANVAS_BEHAVIOR_ICON}"></i> ${behavior.label}`;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const hashString = (str = '') => {
|
|
110
|
+
let hash = 0;
|
|
111
|
+
for (let i = 0; i < str.length; i++) {
|
|
112
|
+
hash = (Math.imul(31, hash) + str.charCodeAt(i)) | 0;
|
|
113
|
+
}
|
|
114
|
+
return hash;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const clampNumber = (value, min, max) => (value < min ? min : value > max ? max : value);
|
|
118
|
+
const lerp = (start, end, factor) => start + (end - start) * factor;
|
|
119
|
+
const smoothstep = (value) => value * value * (3 - 2 * value);
|
|
120
|
+
const normalizedHash = (seed, x, y) => ((hashString(`${seed}:${x}:${y}`) >>> 0) / 4294967295) * 2 - 1;
|
|
121
|
+
|
|
122
|
+
const sampleSmoothNoise = (seed, x, y) => {
|
|
123
|
+
const x0 = Math.floor(x);
|
|
124
|
+
const y0 = Math.floor(y);
|
|
125
|
+
const x1 = x0 + 1;
|
|
126
|
+
const y1 = y0 + 1;
|
|
127
|
+
|
|
128
|
+
const sx = smoothstep(x - x0);
|
|
129
|
+
const sy = smoothstep(y - y0);
|
|
130
|
+
const n00 = normalizedHash(seed, x0, y0);
|
|
131
|
+
const n10 = normalizedHash(seed, x1, y0);
|
|
132
|
+
const n01 = normalizedHash(seed, x0, y1);
|
|
133
|
+
const n11 = normalizedHash(seed, x1, y1);
|
|
134
|
+
|
|
135
|
+
return lerp(lerp(n00, n10, sx), lerp(n01, n11, sx), sy);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const isVisibleCell = (cell) => Array.isArray(cell) && (cell[3] || 0) > 0;
|
|
139
|
+
const cloneMatrix = (matrix = []) => matrix.map((row) => row.map((cell) => cell.slice()));
|
|
140
|
+
const modulo = (value, divisor) => {
|
|
141
|
+
if (!divisor) return 0;
|
|
142
|
+
return ((value % divisor) + divisor) % divisor;
|
|
143
|
+
};
|
|
144
|
+
const normalizeColorCell = (cell = [255, 0, 0, 255]) => [
|
|
145
|
+
clampNumber(Math.round(cell[0] || 0), 0, 255),
|
|
146
|
+
clampNumber(Math.round(cell[1] || 0), 0, 255),
|
|
147
|
+
clampNumber(Math.round(cell[2] || 0), 0, 255),
|
|
148
|
+
clampNumber(Math.round(cell[3] ?? 255), 0, 255),
|
|
149
|
+
];
|
|
150
|
+
const getRenderedInputNode = (id = '') => s(`.${id}`) || s(`#${id}-name`) || s(`#${id}`);
|
|
151
|
+
|
|
152
|
+
const countChangedCells = (baseMatrix = [], nextMatrix = []) => {
|
|
153
|
+
const height = Math.max(baseMatrix.length, nextMatrix.length);
|
|
154
|
+
const width = Math.max(baseMatrix[0]?.length || 0, nextMatrix[0]?.length || 0);
|
|
155
|
+
let changedCells = 0;
|
|
156
|
+
|
|
157
|
+
for (let y = 0; y < height; y++) {
|
|
158
|
+
for (let x = 0; x < width; x++) {
|
|
159
|
+
const baseCell = baseMatrix[y]?.[x] || [0, 0, 0, 0];
|
|
160
|
+
const nextCell = nextMatrix[y]?.[x] || [0, 0, 0, 0];
|
|
161
|
+
if (
|
|
162
|
+
baseCell[0] !== nextCell[0] ||
|
|
163
|
+
baseCell[1] !== nextCell[1] ||
|
|
164
|
+
baseCell[2] !== nextCell[2] ||
|
|
165
|
+
baseCell[3] !== nextCell[3]
|
|
166
|
+
) {
|
|
167
|
+
changedCells++;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return changedCells;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const deriveMatrixLayerSeed = (matrix = []) => {
|
|
176
|
+
const signature = [];
|
|
177
|
+
for (let y = 0; y < matrix.length; y++) {
|
|
178
|
+
for (let x = 0; x < (matrix[y]?.length || 0); x++) {
|
|
179
|
+
const cell = matrix[y][x];
|
|
180
|
+
if (!isVisibleCell(cell)) continue;
|
|
181
|
+
signature.push(`${x}:${y}:${cell.join(',')}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return hashString(`${matrix[0]?.length || 0}x${matrix.length}:${signature.join('|')}`);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const colorDistance = (left = [0, 0, 0, 0], right = [0, 0, 0, 0]) => {
|
|
188
|
+
const deltaRed = (left[0] - right[0]) / 255;
|
|
189
|
+
const deltaGreen = (left[1] - right[1]) / 255;
|
|
190
|
+
const deltaBlue = (left[2] - right[2]) / 255;
|
|
191
|
+
const deltaAlpha = ((left[3] || 0) - (right[3] || 0)) / 255;
|
|
192
|
+
return (
|
|
193
|
+
Math.sqrt(deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue + deltaAlpha * deltaAlpha * 0.35) /
|
|
194
|
+
1.83
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const getNeighborEntries = (matrix, x, y) => {
|
|
199
|
+
const neighbors = [];
|
|
200
|
+
const sourceCell = matrix[y]?.[x] || [0, 0, 0, 0];
|
|
201
|
+
|
|
202
|
+
for (let offsetY = -1; offsetY <= 1; offsetY++) {
|
|
203
|
+
for (let offsetX = -1; offsetX <= 1; offsetX++) {
|
|
204
|
+
if (offsetX === 0 && offsetY === 0) continue;
|
|
205
|
+
|
|
206
|
+
const neighborX = x + offsetX;
|
|
207
|
+
const neighborY = y + offsetY;
|
|
208
|
+
if (
|
|
209
|
+
neighborY < 0 ||
|
|
210
|
+
neighborX < 0 ||
|
|
211
|
+
neighborY >= matrix.length ||
|
|
212
|
+
neighborX >= (matrix[neighborY]?.length || 0)
|
|
213
|
+
) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const neighborCell = matrix[neighborY][neighborX];
|
|
218
|
+
const visible = isVisibleCell(neighborCell);
|
|
219
|
+
neighbors.push({
|
|
220
|
+
x: neighborX,
|
|
221
|
+
y: neighborY,
|
|
222
|
+
dx: offsetX,
|
|
223
|
+
dy: offsetY,
|
|
224
|
+
cell: neighborCell.slice(),
|
|
225
|
+
visible,
|
|
226
|
+
distance: visible ? colorDistance(sourceCell, neighborCell) : 1,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return neighbors;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const getDistortionTime = (distortionSeed = 0) => (Math.abs(Number(distortionSeed) || 0) % 4096) / 128 + 1;
|
|
235
|
+
|
|
236
|
+
const getDirectionalVector = ({ x, y, width, height, distortionType, frameSeed, distortionSeed }) => {
|
|
237
|
+
const distortionTime = getDistortionTime(distortionSeed);
|
|
238
|
+
const noiseX = sampleSmoothNoise(frameSeed + 211, x * 0.26 + distortionTime * 0.14, y * 0.26 + 1.9);
|
|
239
|
+
const noiseY = sampleSmoothNoise(frameSeed + 263, x * 0.26 + 7.1, y * 0.26 + distortionTime * 0.14);
|
|
240
|
+
const centerX = (width - 1) / 2;
|
|
241
|
+
const centerY = (height - 1) / 2;
|
|
242
|
+
const deltaX = x - centerX;
|
|
243
|
+
const deltaY = y - centerY;
|
|
244
|
+
const radialX = deltaX === 0 ? 0 : deltaX / Math.max(1, Math.abs(deltaX) + Math.abs(deltaY));
|
|
245
|
+
const radialY = deltaY === 0 ? 0 : deltaY / Math.max(1, Math.abs(deltaX) + Math.abs(deltaY));
|
|
246
|
+
|
|
247
|
+
if (distortionType === 'position-jitter') {
|
|
248
|
+
return { dx: noiseX, dy: noiseY };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (distortionType === 'rotation-drift') {
|
|
252
|
+
const tangentDirection = sampleSmoothNoise(frameSeed + 307, distortionTime * 0.24, 3.7) >= 0 ? 1 : -1;
|
|
253
|
+
return {
|
|
254
|
+
dx: tangentDirection * -radialY + noiseX * 0.3,
|
|
255
|
+
dy: tangentDirection * radialX + noiseY * 0.3,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (distortionType === 'scale-wobble') {
|
|
260
|
+
const radialDirection = sampleSmoothNoise(frameSeed + 359, distortionTime * 0.18, 4.6) >= 0 ? 1 : -1;
|
|
261
|
+
return {
|
|
262
|
+
dx: radialX * radialDirection + noiseX * 0.2,
|
|
263
|
+
dy: radialY * radialDirection + noiseY * 0.2,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
dx: (noiseX >= 0 ? 0.6 : -0.6) + noiseX * 0.6,
|
|
269
|
+
dy: (noiseY >= 0 ? 0.6 : -0.6) + noiseY * 0.6,
|
|
270
|
+
};
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const collectVisibleCells = (matrix = [], layerSeed, frameSeed, distortionType, distortionSeed) => {
|
|
274
|
+
const distortionTime = getDistortionTime(distortionSeed);
|
|
275
|
+
const visibleCells = [];
|
|
276
|
+
|
|
277
|
+
for (let y = 0; y < matrix.length; y++) {
|
|
278
|
+
for (let x = 0; x < (matrix[y]?.length || 0); x++) {
|
|
279
|
+
const cell = matrix[y][x];
|
|
280
|
+
if (!isVisibleCell(cell)) continue;
|
|
281
|
+
|
|
282
|
+
const neighbors = getNeighborEntries(matrix, x, y);
|
|
283
|
+
const visibleNeighbors = neighbors.filter((neighbor) => neighbor.visible);
|
|
284
|
+
const edgeScore = neighbors.some((neighbor) => !neighbor.visible) ? 1 : 0;
|
|
285
|
+
const variationScore = visibleNeighbors.length
|
|
286
|
+
? visibleNeighbors.reduce((sum, neighbor) => {
|
|
287
|
+
if (neighbor.distance < 0.01) return sum + 0.04;
|
|
288
|
+
if (neighbor.distance <= 0.35) return sum + (1 - Math.abs(neighbor.distance - 0.14) / 0.21);
|
|
289
|
+
if (neighbor.distance <= 0.55) return sum + 0.18;
|
|
290
|
+
return sum + 0.04;
|
|
291
|
+
}, 0) / visibleNeighbors.length
|
|
292
|
+
: 0;
|
|
293
|
+
|
|
294
|
+
const activity = (sampleSmoothNoise(frameSeed + 401, x * 0.24 + distortionTime * 0.1, y * 0.24 + 2.7) + 1) / 2;
|
|
295
|
+
const stabilityBias = 1 - (hashString(`${layerSeed}:${distortionType}:${x}:${y}`) >>> 0) / 4294967295;
|
|
296
|
+
|
|
297
|
+
visibleCells.push({
|
|
298
|
+
x,
|
|
299
|
+
y,
|
|
300
|
+
cell: cell.slice(),
|
|
301
|
+
neighbors,
|
|
302
|
+
edgeScore,
|
|
303
|
+
variationScore,
|
|
304
|
+
score: variationScore * 0.58 + edgeScore * 0.2 + activity * 0.18 + stabilityBias * 0.04,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return visibleCells.sort((left, right) => right.score - left.score);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const chooseDistortionTarget = ({ entry, matrix, distortionType, frameSeed, distortionSeed, reservedCells }) => {
|
|
313
|
+
const width = matrix[0]?.length || 0;
|
|
314
|
+
const height = matrix.length;
|
|
315
|
+
const vector = getDirectionalVector({
|
|
316
|
+
x: entry.x,
|
|
317
|
+
y: entry.y,
|
|
318
|
+
width,
|
|
319
|
+
height,
|
|
320
|
+
distortionType,
|
|
321
|
+
frameSeed,
|
|
322
|
+
distortionSeed,
|
|
323
|
+
});
|
|
324
|
+
const vectorLength = Math.hypot(vector.dx, vector.dy) || 1;
|
|
325
|
+
|
|
326
|
+
return [...entry.neighbors]
|
|
327
|
+
.map((neighbor) => {
|
|
328
|
+
const alignment =
|
|
329
|
+
(neighbor.dx * vector.dx + neighbor.dy * vector.dy) /
|
|
330
|
+
((Math.hypot(neighbor.dx, neighbor.dy) || 1) * vectorLength);
|
|
331
|
+
let score = alignment * 0.55;
|
|
332
|
+
|
|
333
|
+
if (!neighbor.visible) {
|
|
334
|
+
score += 0.22 + entry.edgeScore * 0.16;
|
|
335
|
+
} else if (neighbor.distance >= 0.01 && neighbor.distance <= 0.38) {
|
|
336
|
+
score += 0.34 + (0.38 - neighbor.distance) * 0.45;
|
|
337
|
+
} else {
|
|
338
|
+
score -= 0.2;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (distortionType === 'particle-drift' && Math.abs(neighbor.dx) === 1 && Math.abs(neighbor.dy) === 1) {
|
|
342
|
+
score += 0.16;
|
|
343
|
+
}
|
|
344
|
+
if (distortionType === 'rotation-drift' && Math.abs(neighbor.dx) + Math.abs(neighbor.dy) === 1) {
|
|
345
|
+
score += 0.06;
|
|
346
|
+
}
|
|
347
|
+
if (distortionType === 'scale-wobble' && !neighbor.visible) {
|
|
348
|
+
score += 0.08;
|
|
349
|
+
}
|
|
350
|
+
if (reservedCells.has(`${neighbor.x}:${neighbor.y}`)) {
|
|
351
|
+
score = -Infinity;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return { ...neighbor, score };
|
|
355
|
+
})
|
|
356
|
+
.sort((left, right) => right.score - left.score)
|
|
357
|
+
.find((candidate) => candidate.score > 0.02);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const buildDistortedMatrix = (
|
|
361
|
+
baseMatrix,
|
|
362
|
+
distortionType,
|
|
363
|
+
factorA = DEFAULT_DISTORTION_FACTOR_A,
|
|
364
|
+
distortionSeed = Date.now(),
|
|
365
|
+
) => {
|
|
366
|
+
const layerSeed = deriveMatrixLayerSeed(baseMatrix);
|
|
367
|
+
const normalizedSeed = Number.isFinite(distortionSeed) ? distortionSeed : hashString(String(distortionSeed));
|
|
368
|
+
const frameSeed = hashString(`${layerSeed}:${distortionType}:${normalizedSeed}`);
|
|
369
|
+
const visibleCells = collectVisibleCells(baseMatrix, layerSeed, frameSeed, distortionType, normalizedSeed);
|
|
370
|
+
const result = cloneMatrix(baseMatrix);
|
|
371
|
+
|
|
372
|
+
if (!visibleCells.length) {
|
|
373
|
+
return { matrix: result, changedCells: 0, appliedDistortions: 0, layerSeed, frameSeed };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const densityFactor = clampNumber(Number.isFinite(factorA) ? factorA : DEFAULT_DISTORTION_FACTOR_A, 0.01, 1);
|
|
377
|
+
const maxBudget = Math.max(1, Math.round(visibleCells.length * 0.35));
|
|
378
|
+
const distortionBudget = clampNumber(Math.round(visibleCells.length * densityFactor), 1, maxBudget);
|
|
379
|
+
const reservedCells = new Set();
|
|
380
|
+
let appliedDistortions = 0;
|
|
381
|
+
|
|
382
|
+
for (const entry of visibleCells) {
|
|
383
|
+
if (appliedDistortions >= distortionBudget) break;
|
|
384
|
+
|
|
385
|
+
const sourceKey = `${entry.x}:${entry.y}`;
|
|
386
|
+
if (reservedCells.has(sourceKey)) continue;
|
|
387
|
+
|
|
388
|
+
const target = chooseDistortionTarget({
|
|
389
|
+
entry,
|
|
390
|
+
matrix: baseMatrix,
|
|
391
|
+
distortionType,
|
|
392
|
+
frameSeed,
|
|
393
|
+
distortionSeed: normalizedSeed,
|
|
394
|
+
reservedCells,
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
if (!target) continue;
|
|
398
|
+
|
|
399
|
+
if (target.visible) {
|
|
400
|
+
const nextCell = result[target.y][target.x].slice();
|
|
401
|
+
result[target.y][target.x] = entry.cell.slice();
|
|
402
|
+
result[entry.y][entry.x] = nextCell;
|
|
403
|
+
} else {
|
|
404
|
+
result[target.y][target.x] = entry.cell.slice();
|
|
405
|
+
result[entry.y][entry.x] = [0, 0, 0, 0];
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
reservedCells.add(sourceKey);
|
|
409
|
+
reservedCells.add(`${target.x}:${target.y}`);
|
|
410
|
+
appliedDistortions++;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
let changedCells = countChangedCells(baseMatrix, result);
|
|
414
|
+
|
|
415
|
+
if (changedCells === 0) {
|
|
416
|
+
for (const entry of visibleCells) {
|
|
417
|
+
const transparentTarget = entry.neighbors.find((neighbor) => !neighbor.visible);
|
|
418
|
+
if (!transparentTarget) continue;
|
|
419
|
+
result[transparentTarget.y][transparentTarget.x] = entry.cell.slice();
|
|
420
|
+
result[entry.y][entry.x] = [0, 0, 0, 0];
|
|
421
|
+
appliedDistortions = 1;
|
|
422
|
+
changedCells = countChangedCells(baseMatrix, result);
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
matrix: result,
|
|
429
|
+
changedCells,
|
|
430
|
+
appliedDistortions,
|
|
431
|
+
densityFactor,
|
|
432
|
+
layerSeed,
|
|
433
|
+
frameSeed,
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const getMosaicTileSize = (width, height, factorA = DEFAULT_DISTORTION_FACTOR_A) => {
|
|
438
|
+
const minDimension = Math.max(1, Math.min(width, height));
|
|
439
|
+
const normalizedFactor = clampNumber(Number.isFinite(factorA) ? factorA : DEFAULT_DISTORTION_FACTOR_A, 0.01, 1);
|
|
440
|
+
return clampNumber(
|
|
441
|
+
Math.round(1 + normalizedFactor * Math.max(2, Math.min(10, Math.floor(minDimension / 2)))),
|
|
442
|
+
1,
|
|
443
|
+
minDimension,
|
|
444
|
+
);
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const buildMosaicMatrix = (
|
|
448
|
+
baseMatrix,
|
|
449
|
+
mosaicType,
|
|
450
|
+
factorA = DEFAULT_DISTORTION_FACTOR_A,
|
|
451
|
+
brushCell = [255, 0, 0, 255],
|
|
452
|
+
) => {
|
|
453
|
+
const height = baseMatrix.length;
|
|
454
|
+
const width = baseMatrix[0]?.length || 0;
|
|
455
|
+
const result = cloneMatrix(baseMatrix);
|
|
456
|
+
|
|
457
|
+
if (!height || !width) {
|
|
458
|
+
return { matrix: result, changedCells: 0, paintedCells: 0, tileSize: 1 };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const tileSize = getMosaicTileSize(width, height, factorA);
|
|
462
|
+
const gap = Math.max(1, Math.floor(tileSize / 2));
|
|
463
|
+
const thickness = Math.max(1, Math.ceil(tileSize / 3));
|
|
464
|
+
const paintCell = normalizeColorCell(brushCell);
|
|
465
|
+
let paintedCells = 0;
|
|
466
|
+
|
|
467
|
+
const shouldPaint = (x, y) => {
|
|
468
|
+
switch (mosaicType) {
|
|
469
|
+
case 'mosaic-diamond-checker': {
|
|
470
|
+
const span = tileSize * 2 + gap;
|
|
471
|
+
const tileX = Math.floor(x / span);
|
|
472
|
+
const tileY = Math.floor(y / span);
|
|
473
|
+
if ((tileX + tileY) % 2 !== 0) return false;
|
|
474
|
+
const localX = modulo(x, span) - tileSize;
|
|
475
|
+
const localY = modulo(y, span) - tileSize;
|
|
476
|
+
return Math.abs(localX) + Math.abs(localY) <= tileSize - 1;
|
|
477
|
+
}
|
|
478
|
+
case 'mosaic-rhombus-lattice': {
|
|
479
|
+
const period = tileSize * 2 + gap;
|
|
480
|
+
const diagonalA = modulo(x + y, period);
|
|
481
|
+
const diagonalB = modulo(x - y, period);
|
|
482
|
+
return diagonalA < thickness || diagonalB < thickness;
|
|
483
|
+
}
|
|
484
|
+
case 'mosaic-zigzag-rows': {
|
|
485
|
+
const zigzagWidth = Math.max(2, tileSize * 2 + gap);
|
|
486
|
+
const bandHeight = Math.max(1, tileSize);
|
|
487
|
+
const rowIndex = Math.floor(y / bandHeight);
|
|
488
|
+
const localX = modulo(x + (rowIndex % 2) * tileSize, zigzagWidth);
|
|
489
|
+
const ridge = modulo(y, bandHeight);
|
|
490
|
+
return Math.abs(localX - ridge) < thickness || Math.abs(localX - (zigzagWidth - ridge - 1)) < thickness;
|
|
491
|
+
}
|
|
492
|
+
case 'mosaic-staggered-tiles': {
|
|
493
|
+
const step = tileSize + gap;
|
|
494
|
+
const rowIndex = Math.floor(y / step);
|
|
495
|
+
const localX = modulo(x + (rowIndex % 2) * Math.floor(step / 2), step);
|
|
496
|
+
const localY = modulo(y, step);
|
|
497
|
+
return localX < tileSize && localY < tileSize;
|
|
498
|
+
}
|
|
499
|
+
case 'mosaic-brick-offset': {
|
|
500
|
+
const brickWidth = tileSize * 2 + gap;
|
|
501
|
+
const brickHeight = tileSize + gap;
|
|
502
|
+
const rowIndex = Math.floor(y / brickHeight);
|
|
503
|
+
const localX = modulo(x + (rowIndex % 2) * Math.floor(brickWidth / 2), brickWidth);
|
|
504
|
+
const localY = modulo(y, brickHeight);
|
|
505
|
+
return localX < brickWidth - gap && localY < tileSize;
|
|
506
|
+
}
|
|
507
|
+
default:
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
for (let y = 0; y < height; y++) {
|
|
513
|
+
for (let x = 0; x < width; x++) {
|
|
514
|
+
if (!shouldPaint(x, y)) continue;
|
|
515
|
+
paintedCells++;
|
|
516
|
+
result[y][x] = paintCell.slice();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return {
|
|
521
|
+
matrix: result,
|
|
522
|
+
changedCells: countChangedCells(baseMatrix, result),
|
|
523
|
+
paintedCells,
|
|
524
|
+
tileSize,
|
|
525
|
+
};
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
class ObjectLayerEngineModal {
|
|
529
|
+
static selectItemType = 'skin';
|
|
530
|
+
static itemActivable = false;
|
|
531
|
+
static renderFrameDuration = 100;
|
|
532
|
+
static existingObjectLayerId = null;
|
|
533
|
+
static originalDirectionCodes = [];
|
|
534
|
+
static selectedDistortionType = DEFAULT_DISTORTION_TYPE;
|
|
535
|
+
static distortionFactorA = DEFAULT_DISTORTION_FACTOR_A;
|
|
536
|
+
static uniformOpacityEnabled = false;
|
|
537
|
+
static templates = [
|
|
538
|
+
{
|
|
539
|
+
label: 'empty',
|
|
540
|
+
id: 'empty',
|
|
541
|
+
data: [],
|
|
542
|
+
},
|
|
543
|
+
];
|
|
544
|
+
static statDescriptions = {
|
|
545
|
+
effect: {
|
|
546
|
+
title: 'Effect',
|
|
547
|
+
icon: 'stat-effect.png',
|
|
548
|
+
description: 'Amount of life removed when an entity collides or deals an impact.',
|
|
549
|
+
detail: 'Measured in life points.',
|
|
550
|
+
},
|
|
551
|
+
resistance: {
|
|
552
|
+
title: 'Resistance',
|
|
553
|
+
icon: 'stat-resistance.png',
|
|
554
|
+
description: "Adds to the owner's maximum life (survivability cap).",
|
|
555
|
+
detail:
|
|
556
|
+
"This value is summed with the entity's base max life. It also increases the amount of life restored when a regeneration event occurs (adds directly to current life).",
|
|
557
|
+
},
|
|
558
|
+
agility: {
|
|
559
|
+
title: 'Agility',
|
|
560
|
+
icon: 'stat-agility.png',
|
|
561
|
+
description: 'Increases the movement speed of entities.',
|
|
562
|
+
detail: 'Higher values result in faster movement.',
|
|
563
|
+
},
|
|
564
|
+
range: {
|
|
565
|
+
title: 'Range',
|
|
566
|
+
icon: 'stat-range.png',
|
|
567
|
+
description: 'Increases the lifetime of a cast/summoned entity.',
|
|
568
|
+
detail: 'Measured in milliseconds.',
|
|
569
|
+
},
|
|
570
|
+
intelligence: {
|
|
571
|
+
title: 'Intelligence',
|
|
572
|
+
icon: 'stat-intelligence.png',
|
|
573
|
+
description: 'Probability-based stat that increases the chance to spawn/trigger a summoned entity.',
|
|
574
|
+
detail: 'Higher values increase summoning success rate.',
|
|
575
|
+
},
|
|
576
|
+
utility: {
|
|
577
|
+
title: 'Utility',
|
|
578
|
+
icon: 'stat-utility.png',
|
|
579
|
+
description: 'Reduces the cooldown time between actions, allowing for more frequent actions.',
|
|
580
|
+
detail: 'It also increases the chance to trigger life-regeneration events.',
|
|
581
|
+
},
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
static RenderTemplate = (colorTemplate) => {
|
|
585
|
+
const ole = s('object-layer-engine');
|
|
586
|
+
if (!ole) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (colorTemplate.length === 0) {
|
|
591
|
+
ole.clear();
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const matrix = colorTemplate.map((row) => row.map((hex) => [...hexToRgbA(hex), 255]));
|
|
596
|
+
ole.loadMatrix(matrix);
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
static ObjectLayerData = {};
|
|
600
|
+
|
|
601
|
+
static clearData() {
|
|
602
|
+
this.ObjectLayerData = {};
|
|
603
|
+
this.selectItemType = 'skin';
|
|
604
|
+
this.itemActivable = false;
|
|
605
|
+
this.renderFrameDuration = 100;
|
|
606
|
+
this.existingObjectLayerId = null;
|
|
607
|
+
this.originalDirectionCodes = [];
|
|
608
|
+
this.selectedDistortionType = DEFAULT_DISTORTION_TYPE;
|
|
609
|
+
this.distortionFactorA = DEFAULT_DISTORTION_FACTOR_A;
|
|
610
|
+
this.uniformOpacityEnabled = false;
|
|
611
|
+
this.templates = [
|
|
612
|
+
{
|
|
613
|
+
label: 'empty',
|
|
614
|
+
id: 'empty',
|
|
615
|
+
data: [],
|
|
616
|
+
},
|
|
617
|
+
];
|
|
618
|
+
|
|
619
|
+
const ole = s('object-layer-engine');
|
|
620
|
+
if (ole && typeof ole.clear === 'function') {
|
|
621
|
+
ole.clear();
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
for (const directionCode of OBJECT_LAYER_DIRECTION_CODES) {
|
|
625
|
+
const framesContainer = s(`.frames-${directionCode}`);
|
|
626
|
+
if (framesContainer) {
|
|
627
|
+
framesContainer.innerHTML = '';
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Clear form inputs with correct IDs
|
|
632
|
+
const itemIdInput = s('#ol-input-item-id');
|
|
633
|
+
if (itemIdInput) itemIdInput.value = '';
|
|
634
|
+
|
|
635
|
+
const itemDescInput = s('#ol-input-item-description');
|
|
636
|
+
if (itemDescInput) itemDescInput.value = '';
|
|
637
|
+
|
|
638
|
+
const frameDurationInput = s('#ol-input-render-frame-duration');
|
|
639
|
+
if (frameDurationInput) frameDurationInput.value = '100';
|
|
640
|
+
|
|
641
|
+
// Reset toggle switches with correct IDs
|
|
642
|
+
const activableCheckbox = s('#ol-toggle-item-activable');
|
|
643
|
+
if (activableCheckbox) activableCheckbox.checked = false;
|
|
644
|
+
|
|
645
|
+
// Clear stat inputs with correct IDs
|
|
646
|
+
for (const stat of STAT_TYPES) {
|
|
647
|
+
const statInput = getRenderedInputNode(`ol-input-item-stats-${stat}`);
|
|
648
|
+
if (statInput) statInput.value = '0';
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const statRandomMinInput = getRenderedInputNode('ol-input-stats-random-min');
|
|
652
|
+
if (statRandomMinInput) statRandomMinInput.value = String(DEFAULT_STAT_RANDOM_MIN);
|
|
653
|
+
|
|
654
|
+
const statRandomMaxInput = getRenderedInputNode('ol-input-stats-random-max');
|
|
655
|
+
if (statRandomMaxInput) statRandomMaxInput.value = String(DEFAULT_STAT_RANDOM_MAX);
|
|
656
|
+
|
|
657
|
+
// Clear DropDown displays
|
|
658
|
+
const templateDropdownCurrent = s(`.dropdown-current-ol-dropdown-template`);
|
|
659
|
+
if (templateDropdownCurrent) templateDropdownCurrent.innerHTML = '';
|
|
660
|
+
|
|
661
|
+
const itemTypeDropdownCurrent = s(`.dropdown-current-ol-dropdown-item-type`);
|
|
662
|
+
if (itemTypeDropdownCurrent) itemTypeDropdownCurrent.innerHTML = 'skin';
|
|
663
|
+
|
|
664
|
+
const distortionDropdownCurrent = s(`.dropdown-current-ol-dropdown-distortion-type`);
|
|
665
|
+
if (distortionDropdownCurrent) {
|
|
666
|
+
distortionDropdownCurrent.innerHTML = getCanvasBehaviorDisplay(DEFAULT_DISTORTION_TYPE);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const distortionFactorInput = s('#ol-input-distortion-factor-a') || s('.ol-input-distortion-factor-a');
|
|
670
|
+
if (distortionFactorInput) distortionFactorInput.value = String(DEFAULT_DISTORTION_FACTOR_A);
|
|
671
|
+
|
|
672
|
+
const distortionStatusNode = s(`.ol-distortion-status`);
|
|
673
|
+
if (distortionStatusNode) {
|
|
674
|
+
distortionStatusNode.style.color = '#888';
|
|
675
|
+
distortionStatusNode.innerHTML = DEFAULT_DISTORTION_STATUS;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
static loadFromDatabase = async (objectLayerId) => {
|
|
680
|
+
try {
|
|
681
|
+
// Load metadata first (lightweight)
|
|
682
|
+
const { status: metaStatus, data: metadata } = await ObjectLayerService.getMetadata({ id: objectLayerId });
|
|
683
|
+
|
|
684
|
+
if (metaStatus !== 'success' || !metadata) {
|
|
685
|
+
NotificationManager.Push({
|
|
686
|
+
html: `Failed to load object layer metadata`,
|
|
687
|
+
status: 'error',
|
|
688
|
+
});
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Load render data separately (heavy)
|
|
693
|
+
const { status: renderStatus, data: objectLayerRenderFramesData } = await ObjectLayerService.getRender({
|
|
694
|
+
id: objectLayerId,
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
if (renderStatus !== 'success' || !objectLayerRenderFramesData) {
|
|
698
|
+
NotificationManager.Push({
|
|
699
|
+
html: `Failed to load object layer render data`,
|
|
700
|
+
status: 'error',
|
|
701
|
+
});
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return { metadata, objectLayerRenderFramesId: objectLayerRenderFramesData.objectLayerRenderFramesId };
|
|
706
|
+
} catch (error) {
|
|
707
|
+
console.error('Error loading object layer from database:', error);
|
|
708
|
+
NotificationManager.Push({
|
|
709
|
+
html: `Error loading object layer: ${error.message}`,
|
|
710
|
+
status: 'error',
|
|
711
|
+
});
|
|
712
|
+
return null;
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
static instance = async (options = { idModal: '', appStore: {} }) => {
|
|
717
|
+
// Clear all cached data at the start of each render to prevent contamination
|
|
718
|
+
ObjectLayerEngineModal.clearData();
|
|
719
|
+
|
|
720
|
+
const { appStore } = options;
|
|
721
|
+
const canMutate = commonModeratorGuard(appStore?.Data?.user?.main?.model?.user?.role || 'guest');
|
|
722
|
+
|
|
723
|
+
const directionCodes = OBJECT_LAYER_DIRECTION_CODES;
|
|
724
|
+
const directionCodeLabels = OBJECT_LAYER_DIRECTION_LABELS;
|
|
725
|
+
const statTypes = STAT_TYPES;
|
|
726
|
+
|
|
727
|
+
// Canonical authorable item types (includes `static`). A per-render copy so a
|
|
728
|
+
// loaded layer's custom type can be appended without mutating the shared enum.
|
|
729
|
+
const itemTypes = Object.values(ITEM_TYPES);
|
|
730
|
+
|
|
731
|
+
const distortionDropdownId = 'ol-dropdown-distortion-type';
|
|
732
|
+
const distortionApplyBtnClass = 'ol-btn-apply-distortion';
|
|
733
|
+
const distortionStatusClass = 'ol-distortion-status';
|
|
734
|
+
const statsRandomizeBtnClass = 'ol-btn-randomize-stats';
|
|
735
|
+
const statsRandomMinInputId = 'ol-input-stats-random-min';
|
|
736
|
+
const statsRandomMaxInputId = 'ol-input-stats-random-max';
|
|
737
|
+
|
|
738
|
+
// Check if we have an 'id' query parameter to load existing object layer
|
|
739
|
+
const queryParams = getQueryParams();
|
|
740
|
+
let loadedData = null;
|
|
741
|
+
|
|
742
|
+
// Track frame editing state
|
|
743
|
+
let editingFrameId = null;
|
|
744
|
+
let editingDirectionCode = null;
|
|
745
|
+
|
|
746
|
+
const readDistortionFactorA = () => {
|
|
747
|
+
const factorInput = s('.ol-input-distortion-factor-a') || s('#ol-input-distortion-factor-a');
|
|
748
|
+
const parsedFactor = Number.parseFloat(factorInput?.value);
|
|
749
|
+
const normalizedFactor = clampNumber(
|
|
750
|
+
Number.isFinite(parsedFactor)
|
|
751
|
+
? parsedFactor
|
|
752
|
+
: ObjectLayerEngineModal.distortionFactorA || DEFAULT_DISTORTION_FACTOR_A,
|
|
753
|
+
0.01,
|
|
754
|
+
1,
|
|
755
|
+
);
|
|
756
|
+
|
|
757
|
+
ObjectLayerEngineModal.distortionFactorA = normalizedFactor;
|
|
758
|
+
if (factorInput) {
|
|
759
|
+
factorInput.value = String(Math.round(normalizedFactor * 100) / 100);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
return normalizedFactor;
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
const readRandomStatBounds = () => {
|
|
766
|
+
const minInput = getRenderedInputNode(statsRandomMinInputId);
|
|
767
|
+
const maxInput = getRenderedInputNode(statsRandomMaxInputId);
|
|
768
|
+
let minValue = Number.parseInt(minInput?.value, 10);
|
|
769
|
+
let maxValue = Number.parseInt(maxInput?.value, 10);
|
|
770
|
+
|
|
771
|
+
minValue = clampNumber(Number.isFinite(minValue) ? minValue : DEFAULT_STAT_RANDOM_MIN, 0, 10);
|
|
772
|
+
maxValue = clampNumber(Number.isFinite(maxValue) ? maxValue : DEFAULT_STAT_RANDOM_MAX, 0, 10);
|
|
773
|
+
|
|
774
|
+
if (minValue > maxValue) {
|
|
775
|
+
const nextMin = maxValue;
|
|
776
|
+
maxValue = minValue;
|
|
777
|
+
minValue = nextMin;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
if (minInput) minInput.value = String(minValue);
|
|
781
|
+
if (maxInput) maxInput.value = String(maxValue);
|
|
782
|
+
|
|
783
|
+
return { minValue, maxValue };
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
const randomizeStatInputs = () => {
|
|
787
|
+
const { minValue, maxValue } = readRandomStatBounds();
|
|
788
|
+
|
|
789
|
+
for (const statType of statTypes) {
|
|
790
|
+
const statInput = getRenderedInputNode(`ol-input-item-stats-${statType}`);
|
|
791
|
+
if (!statInput) continue;
|
|
792
|
+
|
|
793
|
+
const randomValue = Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
|
|
794
|
+
statInput.value = String(randomValue);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
NotificationManager.Push({
|
|
798
|
+
html: `Stats randomized between ${minValue} and ${maxValue}.`,
|
|
799
|
+
status: 'success',
|
|
800
|
+
});
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
let uniformOpacitySyncInProgress = false;
|
|
804
|
+
|
|
805
|
+
const buildUniformOpacityMatrix = (matrix = [], targetAlpha = 255) => {
|
|
806
|
+
const clampedAlpha = clampNumber(Number(targetAlpha) || 0, 0, 255);
|
|
807
|
+
let changedCells = 0;
|
|
808
|
+
const nextMatrix = matrix.map((row) =>
|
|
809
|
+
row.map((cell) => {
|
|
810
|
+
const nextCell = cell.slice();
|
|
811
|
+
if (isVisibleCell(nextCell) && nextCell[3] !== clampedAlpha) {
|
|
812
|
+
nextCell[3] = clampedAlpha;
|
|
813
|
+
changedCells++;
|
|
814
|
+
}
|
|
815
|
+
return nextCell;
|
|
816
|
+
}),
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
return { matrix: nextMatrix, changedCells, alpha: clampedAlpha };
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
const applyUniformOpacityToEditor = ({ captureUndo = false } = {}) => {
|
|
823
|
+
const ole = s('object-layer-engine');
|
|
824
|
+
if (!ole || !ObjectLayerEngineModal.uniformOpacityEnabled || uniformOpacitySyncInProgress) return false;
|
|
825
|
+
|
|
826
|
+
let currentFrame = null;
|
|
827
|
+
try {
|
|
828
|
+
const exportedMatrix = ole.exportMatrixJSON();
|
|
829
|
+
currentFrame = typeof exportedMatrix === 'string' ? JSON.parse(exportedMatrix) : exportedMatrix;
|
|
830
|
+
} catch (error) {
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const currentMatrix = currentFrame?.matrix;
|
|
835
|
+
if (!Array.isArray(currentMatrix) || !currentMatrix.length || !currentMatrix[0]?.length) {
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const targetAlpha = clampNumber(ole.getBrushAlpha?.() ?? ole.getBrushColor?.()?.[3] ?? 255, 0, 255);
|
|
840
|
+
const nextFrame = buildUniformOpacityMatrix(currentMatrix, targetAlpha);
|
|
841
|
+
if (!nextFrame.changedCells) return false;
|
|
842
|
+
|
|
843
|
+
const nextSnapshot = {
|
|
844
|
+
width: currentFrame.width || currentMatrix[0].length,
|
|
845
|
+
height: currentFrame.height || currentMatrix.length,
|
|
846
|
+
matrix: nextFrame.matrix,
|
|
847
|
+
};
|
|
848
|
+
const beforeSnapshot = captureUndo && typeof ole._snapshot === 'function' ? ole._snapshot() : null;
|
|
849
|
+
|
|
850
|
+
if (
|
|
851
|
+
captureUndo &&
|
|
852
|
+
beforeSnapshot &&
|
|
853
|
+
typeof ole._pushUndo === 'function' &&
|
|
854
|
+
typeof ole._matricesEqual === 'function' &&
|
|
855
|
+
!ole._matricesEqual(beforeSnapshot, nextSnapshot)
|
|
856
|
+
) {
|
|
857
|
+
ole._pushUndo(beforeSnapshot);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
uniformOpacitySyncInProgress = true;
|
|
861
|
+
try {
|
|
862
|
+
ole.loadMatrix(nextFrame.matrix);
|
|
863
|
+
} finally {
|
|
864
|
+
uniformOpacitySyncInProgress = false;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return true;
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
// Helper function to update UI when entering edit mode
|
|
871
|
+
const enterEditMode = (frameId, directionCode) => {
|
|
872
|
+
editingFrameId = frameId;
|
|
873
|
+
editingDirectionCode = directionCode;
|
|
874
|
+
|
|
875
|
+
// Hide/disable all "Add Frame" buttons except the one for the editing direction
|
|
876
|
+
directionCodes.forEach((code) => {
|
|
877
|
+
const addButton = s(`.direction-code-bar-frames-btn-${code}`);
|
|
878
|
+
const addButtonParent = addButton?.parentElement;
|
|
879
|
+
if (addButton && addButtonParent) {
|
|
880
|
+
if (code === directionCode) {
|
|
881
|
+
// Keep the button for the editing direction visible and highlighted with animation
|
|
882
|
+
addButton.style.opacity = '1';
|
|
883
|
+
addButton.style.pointerEvents = 'auto';
|
|
884
|
+
addButton.style.border = '2px solid #4CAF50';
|
|
885
|
+
addButton.style.boxShadow = '0 0 15px rgba(76, 175, 80, 0.6)';
|
|
886
|
+
addButtonParent.classList.add('edit-mode-active');
|
|
887
|
+
} else {
|
|
888
|
+
// Hide/disable buttons for other directions
|
|
889
|
+
addButton.style.opacity = '0.3';
|
|
890
|
+
addButton.style.pointerEvents = 'none';
|
|
891
|
+
addButton.style.filter = 'grayscale(100%)';
|
|
892
|
+
addButton.style.cursor = 'not-allowed';
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
// Change the edit button to close button for the frame being edited
|
|
898
|
+
const editBtn = s(`.direction-code-bar-edit-btn-${frameId}`);
|
|
899
|
+
if (editBtn) {
|
|
900
|
+
editBtn.innerHTML = '<i class="fa-solid fa-times"></i>';
|
|
901
|
+
editBtn.classList.add('edit-mode-active');
|
|
902
|
+
editBtn.title = 'Cancel editing (Esc)';
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Highlight the frame being edited
|
|
906
|
+
document.querySelectorAll('.direction-code-bar-frames-img').forEach((img) => {
|
|
907
|
+
img.style.border = '';
|
|
908
|
+
img.style.boxShadow = '';
|
|
909
|
+
});
|
|
910
|
+
const frameImg = s(`.direction-code-bar-frames-img-${frameId}`);
|
|
911
|
+
if (frameImg) {
|
|
912
|
+
frameImg.style.border = '3px solid #4CAF50';
|
|
913
|
+
frameImg.style.boxShadow = '0 0 10px rgba(76, 175, 80, 0.5)';
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Show notification with better instructions
|
|
917
|
+
NotificationManager.Push({
|
|
918
|
+
html: `<strong>Edit Mode Active</strong><br/>Click the glowing <i class="fa-solid fa-edit"></i> button for direction <strong>${directionCode}</strong> to save, or click <i class="fa-solid fa-times"></i> to cancel.`,
|
|
919
|
+
status: 'info',
|
|
920
|
+
});
|
|
921
|
+
s(`.direction-code-bar-frames-btn-icon-add-${directionCode}`).classList.add('hide');
|
|
922
|
+
s(`.direction-code-bar-frames-btn-icon-edit-${directionCode}`).classList.remove('hide');
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// Helper function to exit edit mode and restore UI
|
|
926
|
+
const exitEditMode = () => {
|
|
927
|
+
const previousEditingFrameId = editingFrameId;
|
|
928
|
+
|
|
929
|
+
s(`.direction-code-bar-frames-btn-icon-add-${editingDirectionCode}`).classList.remove('hide');
|
|
930
|
+
s(`.direction-code-bar-frames-btn-icon-edit-${editingDirectionCode}`).classList.add('hide');
|
|
931
|
+
|
|
932
|
+
editingFrameId = null;
|
|
933
|
+
editingDirectionCode = null;
|
|
934
|
+
|
|
935
|
+
// Restore all "Add Frame" buttons
|
|
936
|
+
directionCodes.forEach((code) => {
|
|
937
|
+
const addButton = s(`.direction-code-bar-frames-btn-${code}`);
|
|
938
|
+
const addButtonParent = addButton?.parentElement;
|
|
939
|
+
if (addButton) {
|
|
940
|
+
addButton.style.opacity = '1';
|
|
941
|
+
addButton.style.pointerEvents = 'auto';
|
|
942
|
+
addButton.style.border = '';
|
|
943
|
+
addButton.style.filter = 'none';
|
|
944
|
+
addButton.style.cursor = 'pointer';
|
|
945
|
+
addButton.style.boxShadow = '';
|
|
946
|
+
if (addButtonParent) {
|
|
947
|
+
addButtonParent.classList.remove('edit-mode-active');
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
// Restore edit button icon if it exists
|
|
953
|
+
if (previousEditingFrameId) {
|
|
954
|
+
const editBtn = s(`.direction-code-bar-edit-btn-${previousEditingFrameId}`);
|
|
955
|
+
if (editBtn) {
|
|
956
|
+
editBtn.innerHTML = '<i class="fa-solid fa-edit"></i>';
|
|
957
|
+
editBtn.classList.remove('edit-mode-active');
|
|
958
|
+
editBtn.title = 'Edit frame';
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// Remove all frame borders and shadows
|
|
963
|
+
document.querySelectorAll('.direction-code-bar-frames-img').forEach((img) => {
|
|
964
|
+
img.style.border = '';
|
|
965
|
+
img.style.boxShadow = '';
|
|
966
|
+
});
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
if (queryParams.id) {
|
|
970
|
+
ObjectLayerEngineModal.existingObjectLayerId = queryParams.id;
|
|
971
|
+
loadedData = await ObjectLayerEngineModal.loadFromDatabase(queryParams.id);
|
|
972
|
+
|
|
973
|
+
if (loadedData) {
|
|
974
|
+
const { metadata, objectLayerRenderFramesId } = loadedData;
|
|
975
|
+
|
|
976
|
+
// Set form values from metadata
|
|
977
|
+
if (metadata.data) {
|
|
978
|
+
if (metadata.data.item) {
|
|
979
|
+
ObjectLayerEngineModal.selectItemType = metadata.data.item.type || itemTypes[0];
|
|
980
|
+
ObjectLayerEngineModal.itemActivable = metadata.data.item.activable || false;
|
|
981
|
+
|
|
982
|
+
// Add loaded item type to itemTypes array if it doesn't exist
|
|
983
|
+
if (ObjectLayerEngineModal.selectItemType && !itemTypes.includes(ObjectLayerEngineModal.selectItemType)) {
|
|
984
|
+
itemTypes.push(ObjectLayerEngineModal.selectItemType);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (objectLayerRenderFramesId) {
|
|
988
|
+
ObjectLayerEngineModal.renderFrameDuration = objectLayerRenderFramesId.frame_duration || 100;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (ObjectLayerEngineModal.templates.length === 1) {
|
|
995
|
+
for (const url of [
|
|
996
|
+
`${getProxyPath()}assets/templates/item-skin-08.json`,
|
|
997
|
+
`${getProxyPath()}assets/templates/item-skin-06.json`,
|
|
998
|
+
]) {
|
|
999
|
+
const id = url.split('/').pop().replace('.json', '');
|
|
1000
|
+
ObjectLayerEngineModal.templates.push({
|
|
1001
|
+
label: id,
|
|
1002
|
+
id,
|
|
1003
|
+
data: JSON.parse(await CoreService.getRaw({ url })).color,
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
let cellsW = 16;
|
|
1009
|
+
let cellsH = 16;
|
|
1010
|
+
if (loadedData && loadedData.objectLayerRenderFramesId && loadedData.objectLayerRenderFramesId.frames) {
|
|
1011
|
+
const frames = loadedData.objectLayerRenderFramesId.frames;
|
|
1012
|
+
for (const direction of Object.keys(frames)) {
|
|
1013
|
+
if (frames[direction] && frames[direction].length > 0 && frames[direction][0].length > 0) {
|
|
1014
|
+
cellsH = frames[direction][0].length;
|
|
1015
|
+
cellsW = frames[direction][0][0].length;
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
// const pixelSize = parseInt(320 / Math.max(cellsW, cellsH));
|
|
1021
|
+
const pixelSize = 30;
|
|
1022
|
+
const idSectionA = 'template-section-a';
|
|
1023
|
+
const idSectionB = 'template-section-b';
|
|
1024
|
+
const colorPaletteClass = 'ol-color-palette';
|
|
1025
|
+
let directionPreviewRuntime = null;
|
|
1026
|
+
|
|
1027
|
+
const cleanupDirectionPreviewRuntime = () => {
|
|
1028
|
+
if (!directionPreviewRuntime) return;
|
|
1029
|
+
if (directionPreviewRuntime.intervalId) {
|
|
1030
|
+
clearInterval(directionPreviewRuntime.intervalId);
|
|
1031
|
+
}
|
|
1032
|
+
for (const frameUrl of directionPreviewRuntime.frameUrls || []) {
|
|
1033
|
+
URL.revokeObjectURL(frameUrl);
|
|
1034
|
+
}
|
|
1035
|
+
directionPreviewRuntime = null;
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
const cleanupDirectionPreviewModal = () => {
|
|
1039
|
+
cleanupDirectionPreviewRuntime();
|
|
1040
|
+
if (s(`.${DIRECTION_PREVIEW_MODAL_ID}`)) {
|
|
1041
|
+
Modal.removeModal(DIRECTION_PREVIEW_MODAL_ID);
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
if (Modal.Data[options.idModal]) {
|
|
1046
|
+
Modal.Data[options.idModal].onCloseListener[`${options.idModal}-direction-preview-cleanup`] = () => {
|
|
1047
|
+
cleanupDirectionPreviewModal();
|
|
1048
|
+
delete Modal.Data[options.idModal]?.onCloseListener?.[`${options.idModal}-direction-preview-cleanup`];
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
const getCurrentFrameDuration = () => {
|
|
1053
|
+
const durationInput = s('.ol-input-render-frame-duration') || s('#ol-input-render-frame-duration');
|
|
1054
|
+
const parsedDuration = Number.parseInt(durationInput?.value, 10);
|
|
1055
|
+
return Math.max(
|
|
1056
|
+
100,
|
|
1057
|
+
Number.isFinite(parsedDuration) ? parsedDuration : ObjectLayerEngineModal.renderFrameDuration || 100,
|
|
1058
|
+
);
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
const openDirectionPreviewModal = async (directionCode) => {
|
|
1062
|
+
const frames = ObjectLayerEngineModal.ObjectLayerData[directionCode] || [];
|
|
1063
|
+
if (!frames.length) {
|
|
1064
|
+
NotificationManager.Push({
|
|
1065
|
+
html: `No frames available yet for ${directionCodeLabels[directionCode] || directionCode}.`,
|
|
1066
|
+
status: 'warning',
|
|
1067
|
+
});
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
const frameUrls = frames
|
|
1072
|
+
.map((frame) => {
|
|
1073
|
+
if (!frame?.image) return null;
|
|
1074
|
+
return URL.createObjectURL(frame.image);
|
|
1075
|
+
})
|
|
1076
|
+
.filter(Boolean);
|
|
1077
|
+
|
|
1078
|
+
if (!frameUrls.length) {
|
|
1079
|
+
NotificationManager.Push({
|
|
1080
|
+
html: `Could not build a local preview for ${directionCodeLabels[directionCode] || directionCode}.`,
|
|
1081
|
+
status: 'error',
|
|
1082
|
+
});
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
cleanupDirectionPreviewModal();
|
|
1087
|
+
|
|
1088
|
+
const { barConfig } = await Themes[Css.currentTheme]();
|
|
1089
|
+
const frameDuration = getCurrentFrameDuration();
|
|
1090
|
+
const previewWidth = Math.max(180, cellsW * pixelSize);
|
|
1091
|
+
const previewHeight = Math.max(180, cellsH * pixelSize);
|
|
1092
|
+
|
|
1093
|
+
await Modal.instance({
|
|
1094
|
+
id: DIRECTION_PREVIEW_MODAL_ID,
|
|
1095
|
+
barConfig,
|
|
1096
|
+
title: `${directionCodeLabels[directionCode] || directionCode} Preview`,
|
|
1097
|
+
html: () => html`
|
|
1098
|
+
<div class="in section-mp" style="text-align: center; min-width: ${previewWidth}px;">
|
|
1099
|
+
<div class="in" style="font-size: 12px; color: #999; margin-bottom: 8px;">
|
|
1100
|
+
${frames.length} frame${frames.length === 1 ? '' : 's'} at ${frameDuration}ms
|
|
1101
|
+
</div>
|
|
1102
|
+
<div
|
|
1103
|
+
class="in direction-preview-stage"
|
|
1104
|
+
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);"
|
|
1105
|
+
>
|
|
1106
|
+
<img
|
|
1107
|
+
class="direction-preview-image"
|
|
1108
|
+
src="${frameUrls[0]}"
|
|
1109
|
+
style="image-rendering: pixelated; width: ${previewWidth}px; height: ${previewHeight}px; object-fit: contain;"
|
|
1110
|
+
/>
|
|
1111
|
+
</div>
|
|
1112
|
+
<div class="fl" style="justify-content: center; gap: 6px; flex-wrap: wrap; margin-top: 10px;">
|
|
1113
|
+
${frameUrls.map(
|
|
1114
|
+
(frameUrl, frameIndex) => html`
|
|
1115
|
+
<img
|
|
1116
|
+
src="${frameUrl}"
|
|
1117
|
+
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);"
|
|
1118
|
+
title="Frame ${frameIndex + 1}"
|
|
1119
|
+
/>
|
|
1120
|
+
`,
|
|
1121
|
+
)}
|
|
1122
|
+
</div>
|
|
1123
|
+
</div>
|
|
1124
|
+
`,
|
|
1125
|
+
style: {
|
|
1126
|
+
width: `${Math.max(300, previewWidth + 40)}px`,
|
|
1127
|
+
height: `${Math.max(260, previewHeight + 150)}px`,
|
|
1128
|
+
border: '1px solid rgba(255,255,255,0.15)',
|
|
1129
|
+
'z-index': 10,
|
|
1130
|
+
},
|
|
1131
|
+
slideMenu: 'modal-menu',
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
const previewImage = s(`.${DIRECTION_PREVIEW_MODAL_ID} .direction-preview-image`);
|
|
1135
|
+
if (!previewImage) {
|
|
1136
|
+
cleanupDirectionPreviewRuntime();
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
let currentFrameIndex = 0;
|
|
1141
|
+
const advancePreviewFrame = () => {
|
|
1142
|
+
if (!previewImage) return;
|
|
1143
|
+
currentFrameIndex = (currentFrameIndex + 1) % frameUrls.length;
|
|
1144
|
+
previewImage.src = frameUrls[currentFrameIndex];
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
directionPreviewRuntime = {
|
|
1148
|
+
frameUrls,
|
|
1149
|
+
intervalId: frameUrls.length > 1 ? setInterval(advancePreviewFrame, frameDuration) : null,
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
if (Modal.Data[DIRECTION_PREVIEW_MODAL_ID]) {
|
|
1153
|
+
Modal.Data[DIRECTION_PREVIEW_MODAL_ID].onCloseListener[DIRECTION_PREVIEW_MODAL_ID] = () => {
|
|
1154
|
+
cleanupDirectionPreviewRuntime();
|
|
1155
|
+
delete Modal.Data[DIRECTION_PREVIEW_MODAL_ID]?.onCloseListener?.[DIRECTION_PREVIEW_MODAL_ID];
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
|
|
1160
|
+
const rgbaToHex = (rgba = [0, 0, 0]) => {
|
|
1161
|
+
const red = Math.max(0, Math.min(255, rgba[0] || 0))
|
|
1162
|
+
.toString(16)
|
|
1163
|
+
.padStart(2, '0');
|
|
1164
|
+
const green = Math.max(0, Math.min(255, rgba[1] || 0))
|
|
1165
|
+
.toString(16)
|
|
1166
|
+
.padStart(2, '0');
|
|
1167
|
+
const blue = Math.max(0, Math.min(255, rgba[2] || 0))
|
|
1168
|
+
.toString(16)
|
|
1169
|
+
.padStart(2, '0');
|
|
1170
|
+
return `#${red}${green}${blue}`.toUpperCase();
|
|
1171
|
+
};
|
|
1172
|
+
|
|
1173
|
+
let directionsCodeBarRender = '';
|
|
1174
|
+
|
|
1175
|
+
// Helper function to add a frame to the direction bar
|
|
1176
|
+
const addFrameToBar = async (directionCode, id, image, json) => {
|
|
1177
|
+
// Capture directionCode in a local variable to ensure proper closure
|
|
1178
|
+
const capturedDirectionCode = directionCode;
|
|
1179
|
+
|
|
1180
|
+
if (!s(`.frames-${capturedDirectionCode}`)) {
|
|
1181
|
+
console.warn(`Frames container for direction code ${capturedDirectionCode} not found`);
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
append(
|
|
1186
|
+
`.frames-${capturedDirectionCode}`,
|
|
1187
|
+
html`
|
|
1188
|
+
<div class="in fll ${id}">
|
|
1189
|
+
<img
|
|
1190
|
+
class="in fll direction-code-bar-frames-img direction-code-bar-frames-img-${id}"
|
|
1191
|
+
src="${URL.createObjectURL(image)}"
|
|
1192
|
+
data-direction-code="${capturedDirectionCode}"
|
|
1193
|
+
/>
|
|
1194
|
+
${await BtnIcon.instance({
|
|
1195
|
+
label: html`<i class="fa-solid fa-edit"></i>`,
|
|
1196
|
+
class: `abs direction-code-bar-edit-btn direction-code-bar-edit-btn-${id}`,
|
|
1197
|
+
})}
|
|
1198
|
+
${await BtnIcon.instance({
|
|
1199
|
+
label: html`<i class="fa-solid fa-trash"></i>`,
|
|
1200
|
+
class: `abs direction-code-bar-trash-btn direction-code-bar-trash-btn-${id}`,
|
|
1201
|
+
})}
|
|
1202
|
+
</div>
|
|
1203
|
+
`,
|
|
1204
|
+
);
|
|
1205
|
+
|
|
1206
|
+
EventsUI.onClick(`.direction-code-bar-frames-img-${id}`, async (e) => {
|
|
1207
|
+
// Get direction code from data attribute to ensure we're using the correct one
|
|
1208
|
+
const clickedDirectionCode = e.target.getAttribute('data-direction-code') || capturedDirectionCode;
|
|
1209
|
+
console.log(`Clicked frame ${id} from direction code: ${clickedDirectionCode}`);
|
|
1210
|
+
const frameData = ObjectLayerEngineModal.ObjectLayerData[clickedDirectionCode]?.find(
|
|
1211
|
+
(frame) => frame.id === id,
|
|
1212
|
+
);
|
|
1213
|
+
if (frameData && frameData.json) {
|
|
1214
|
+
// console.log(`Loading frame data for direction code ${clickedDirectionCode}:`, frameData.json);
|
|
1215
|
+
s('object-layer-engine').importMatrixJSON(frameData.json);
|
|
1216
|
+
} else {
|
|
1217
|
+
console.error(`Frame data not found for id ${id} in direction code ${clickedDirectionCode}`);
|
|
1218
|
+
}
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1221
|
+
EventsUI.onClick(`.direction-code-bar-trash-btn-${id}`, async () => {
|
|
1222
|
+
s(`.${id}`).remove();
|
|
1223
|
+
ObjectLayerEngineModal.ObjectLayerData[capturedDirectionCode] = ObjectLayerEngineModal.ObjectLayerData[
|
|
1224
|
+
capturedDirectionCode
|
|
1225
|
+
].filter((frame) => frame.id !== id);
|
|
1226
|
+
|
|
1227
|
+
// Clear edit mode if deleting the frame being edited
|
|
1228
|
+
if (editingFrameId === id && editingDirectionCode === capturedDirectionCode) {
|
|
1229
|
+
exitEditMode();
|
|
1230
|
+
}
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
EventsUI.onClick(`.direction-code-bar-edit-btn-${id}`, async () => {
|
|
1234
|
+
// Check if this is the frame being edited (close button behavior)
|
|
1235
|
+
if (editingFrameId === id && editingDirectionCode === capturedDirectionCode) {
|
|
1236
|
+
console.log(`Canceling edit mode for frame ${id}`);
|
|
1237
|
+
exitEditMode();
|
|
1238
|
+
// Clear the editor
|
|
1239
|
+
s('object-layer-engine').clear();
|
|
1240
|
+
NotificationManager.Push({
|
|
1241
|
+
html: `<i class="fa-solid fa-times-circle"></i> Edit canceled`,
|
|
1242
|
+
status: 'info',
|
|
1243
|
+
});
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
s(`.direction-code-bar-frames-btn-icon-add-${capturedDirectionCode}`).classList.add('hide');
|
|
1248
|
+
s(`.direction-code-bar-frames-btn-icon-edit-${capturedDirectionCode}`).classList.remove('hide');
|
|
1249
|
+
|
|
1250
|
+
console.log(`Edit button clicked for frame ${id} in direction code ${capturedDirectionCode}`);
|
|
1251
|
+
|
|
1252
|
+
// If another frame is being edited, exit that edit mode first
|
|
1253
|
+
if (editingFrameId && editingFrameId !== id) {
|
|
1254
|
+
exitEditMode();
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// Find the frame data
|
|
1258
|
+
const frameData = ObjectLayerEngineModal.ObjectLayerData[capturedDirectionCode]?.find(
|
|
1259
|
+
(frame) => frame.id === id,
|
|
1260
|
+
);
|
|
1261
|
+
|
|
1262
|
+
if (frameData && frameData.json) {
|
|
1263
|
+
// Load the frame into the editor
|
|
1264
|
+
s('object-layer-engine').importMatrixJSON(frameData.json);
|
|
1265
|
+
|
|
1266
|
+
// Enter edit mode with UI updates
|
|
1267
|
+
enterEditMode(id, capturedDirectionCode);
|
|
1268
|
+
|
|
1269
|
+
console.log(`Entering edit mode for frame ${id} in direction ${capturedDirectionCode}`);
|
|
1270
|
+
} else {
|
|
1271
|
+
console.error(`Frame data not found for id ${id} in direction code ${capturedDirectionCode}`);
|
|
1272
|
+
NotificationManager.Push({
|
|
1273
|
+
html: `<i class="fa-solid fa-exclamation-triangle"></i> Error: Frame data not found`,
|
|
1274
|
+
status: 'error',
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
};
|
|
1279
|
+
|
|
1280
|
+
// Helper function to show loading animation
|
|
1281
|
+
const showFrameLoading = () => {
|
|
1282
|
+
if (!s(`.frame-editor-container`) || s(`.frame-editor-container`).classList.contains('hide')) return;
|
|
1283
|
+
LoadingAnimation.spinner.play(`.frame-editor-container-loading`, 'dual-ring-mini', {
|
|
1284
|
+
prepend: html`<span class="inl loading-text">Loading </span><br /><br /> ` + '<div style="color: gray;">',
|
|
1285
|
+
append: '</div>',
|
|
1286
|
+
});
|
|
1287
|
+
s(`.frame-editor-container`).classList.add('hide');
|
|
1288
|
+
s(`.frame-editor-container-loading`).classList.remove('hide');
|
|
1289
|
+
};
|
|
1290
|
+
|
|
1291
|
+
// Helper function to hide loading animation
|
|
1292
|
+
const hideFrameLoading = () => {
|
|
1293
|
+
if (!s(`.frame-editor-container-loading`) || s(`.frame-editor-container-loading`).classList.contains('hide'))
|
|
1294
|
+
return;
|
|
1295
|
+
LoadingAnimation.spinner.stop(`.frame-editor-container-loading`);
|
|
1296
|
+
s(`.frame-editor-container-loading`).classList.add('hide');
|
|
1297
|
+
s(`.frame-editor-container`).classList.remove('hide');
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
// Helper function to process and add frame from PNG URL using ObjectLayerPngLoader
|
|
1301
|
+
const processAndAddFrameFromPngUrl = async (directionCode, pngUrl) => {
|
|
1302
|
+
// Wait for components to be available with retry logic
|
|
1303
|
+
let ole = s('object-layer-engine');
|
|
1304
|
+
let loader = s('object-layer-png-loader');
|
|
1305
|
+
|
|
1306
|
+
if (!ole || !loader) {
|
|
1307
|
+
console.warn('object-layer-engine or object-layer-png-loader component not found after retries');
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
try {
|
|
1312
|
+
// Load PNG using the loader component - it will automatically load into the editor
|
|
1313
|
+
await loader.loadPngUrl(pngUrl);
|
|
1314
|
+
|
|
1315
|
+
// Export as blob and JSON from component after loading
|
|
1316
|
+
const image = await ole.toBlob();
|
|
1317
|
+
const json = ole.exportMatrixJSON();
|
|
1318
|
+
const id = `frame-loaded-${s4()}-${s4()}`;
|
|
1319
|
+
|
|
1320
|
+
// Add to ObjectLayerData
|
|
1321
|
+
if (!ObjectLayerEngineModal.ObjectLayerData[directionCode]) {
|
|
1322
|
+
ObjectLayerEngineModal.ObjectLayerData[directionCode] = [];
|
|
1323
|
+
}
|
|
1324
|
+
ObjectLayerEngineModal.ObjectLayerData[directionCode].push({ id, image, json });
|
|
1325
|
+
console.log(
|
|
1326
|
+
`Stored frame ${id} in direction code ${directionCode}. Total frames:`,
|
|
1327
|
+
ObjectLayerEngineModal.ObjectLayerData[directionCode].length,
|
|
1328
|
+
);
|
|
1329
|
+
|
|
1330
|
+
// Add to UI
|
|
1331
|
+
await addFrameToBar(directionCode, id, image, json);
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
console.error('Error loading frame from PNG URL:', error);
|
|
1334
|
+
}
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
for (const directionCode of directionCodes) {
|
|
1338
|
+
directionsCodeBarRender += html`
|
|
1339
|
+
<div class="in section-mp-border">
|
|
1340
|
+
<div class="fl">
|
|
1341
|
+
<div class="in fll">
|
|
1342
|
+
<div class="in direction-code-bar-frames-title">${directionCodeLabels[directionCode]}</div>
|
|
1343
|
+
<div class="fl direction-code-bar-btn-row" style="gap: 6px;">
|
|
1344
|
+
${await BtnIcon.instance({
|
|
1345
|
+
label: html`
|
|
1346
|
+
<i class="fa-solid fa-plus direction-code-bar-frames-btn-icon-add-${directionCode}"></i>
|
|
1347
|
+
<i class="fa-solid fa-edit direction-code-bar-frames-btn-icon-edit-${directionCode} hide"></i>
|
|
1348
|
+
`,
|
|
1349
|
+
class: `direction-code-bar-frames-btn-add direction-code-bar-frames-btn-${directionCode}`,
|
|
1350
|
+
})}
|
|
1351
|
+
${await BtnIcon.instance({
|
|
1352
|
+
label: html`<i class="fa-solid fa-play"></i>`,
|
|
1353
|
+
class: `direction-code-bar-preview-btn direction-code-bar-preview-btn-${directionCode}`,
|
|
1354
|
+
})}
|
|
1355
|
+
</div>
|
|
1356
|
+
</div>
|
|
1357
|
+
<div class="frames-${directionCode}"></div>
|
|
1358
|
+
</div>
|
|
1359
|
+
</div>
|
|
1360
|
+
`;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
let statsInputsRender = '';
|
|
1364
|
+
for (const statType of statTypes) {
|
|
1365
|
+
const statInfo = ObjectLayerEngineModal.statDescriptions[statType];
|
|
1366
|
+
const statValue = loadedData?.metadata?.data?.stats?.[statType] || 0;
|
|
1367
|
+
statsInputsRender += html`
|
|
1368
|
+
<div class="inl" style="margin-bottom: 10px; position: relative;">
|
|
1369
|
+
${await Input.instance({
|
|
1370
|
+
id: `ol-input-item-stats-${statType}`,
|
|
1371
|
+
label: html`<div
|
|
1372
|
+
title="${statInfo.description} ${statInfo.detail}"
|
|
1373
|
+
class="inl stat-label-container stat-info-icon"
|
|
1374
|
+
style="width: 120px; font-size: 16px; overflow: visible; position: relative;"
|
|
1375
|
+
>
|
|
1376
|
+
<img
|
|
1377
|
+
src="${getProxyPath()}assets/ui-icons/${statInfo.icon}"
|
|
1378
|
+
style="width: 32px; height: 32px; margin-right: 5px; image-rendering: pixelated; vertical-align: middle;"
|
|
1379
|
+
/>
|
|
1380
|
+
${statInfo.title}
|
|
1381
|
+
</div>`,
|
|
1382
|
+
containerClass: 'inl',
|
|
1383
|
+
type: 'number',
|
|
1384
|
+
min: 0,
|
|
1385
|
+
max: 10,
|
|
1386
|
+
placeholder: true,
|
|
1387
|
+
value: statValue,
|
|
1388
|
+
})}
|
|
1389
|
+
<div class="in stat-description">
|
|
1390
|
+
${statInfo.description}<br />
|
|
1391
|
+
<span style="color: #888; font-style: italic;">${statInfo.detail}</span>
|
|
1392
|
+
</div>
|
|
1393
|
+
</div>
|
|
1394
|
+
`;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
setTimeout(async () => {
|
|
1398
|
+
let loadFramesInProgress = false;
|
|
1399
|
+
const loadFrames = async () => {
|
|
1400
|
+
// Concurrency guard: skip if already loading to prevent duplicate frames
|
|
1401
|
+
if (loadFramesInProgress) {
|
|
1402
|
+
console.warn('loadFrames already in progress, skipping duplicate call');
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
loadFramesInProgress = true;
|
|
1406
|
+
|
|
1407
|
+
try {
|
|
1408
|
+
showFrameLoading();
|
|
1409
|
+
|
|
1410
|
+
// Clear all frames and data at the start to prevent duplication from multiple calls
|
|
1411
|
+
// This must happen BEFORE any async operations to avoid race conditions
|
|
1412
|
+
for (const directionCode of directionCodes) {
|
|
1413
|
+
// Clear DOM frames for this direction code
|
|
1414
|
+
const framesContainer = s(`.frames-${directionCode}`);
|
|
1415
|
+
if (framesContainer) {
|
|
1416
|
+
framesContainer.innerHTML = '';
|
|
1417
|
+
}
|
|
1418
|
+
// Clear data for this direction code
|
|
1419
|
+
ObjectLayerEngineModal.ObjectLayerData[directionCode] = [];
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
for (const directionCode of directionCodes) {
|
|
1423
|
+
// Use IIFE to properly capture directionCode and handle async operations
|
|
1424
|
+
await (async (currentDirectionCode) => {
|
|
1425
|
+
// Register frame add button handler after DOM is ready
|
|
1426
|
+
// Wait longer to ensure all direction bars are rendered
|
|
1427
|
+
|
|
1428
|
+
if (loadedData && loadedData.metadata && loadedData.metadata.data && currentDirectionCode) {
|
|
1429
|
+
// Show loading animation only once on first direction that has frames
|
|
1430
|
+
|
|
1431
|
+
const { type, id } = loadedData.metadata.data.item;
|
|
1432
|
+
const directions = ObjectLayerEngineModal.getDirectionsFromDirectionCode(currentDirectionCode);
|
|
1433
|
+
|
|
1434
|
+
console.log(`Loading frames for direction code: ${currentDirectionCode}, directions:`, directions);
|
|
1435
|
+
|
|
1436
|
+
// Check if frames exist for any direction mapped to this direction code.
|
|
1437
|
+
// Object layers with an empty render (no render-frames doc yet) load
|
|
1438
|
+
// with zero frames so the user can author them from scratch.
|
|
1439
|
+
const frames = loadedData.objectLayerRenderFramesId?.frames;
|
|
1440
|
+
for (const direction of directions) {
|
|
1441
|
+
if (frames && frames[direction] && frames[direction].length > 0) {
|
|
1442
|
+
// Track this direction code as having original data
|
|
1443
|
+
if (!ObjectLayerEngineModal.originalDirectionCodes.includes(currentDirectionCode)) {
|
|
1444
|
+
ObjectLayerEngineModal.originalDirectionCodes.push(currentDirectionCode);
|
|
1445
|
+
}
|
|
1446
|
+
// Load frames from static PNG URLs sequentially to avoid race conditions
|
|
1447
|
+
const frameCount = frames[direction].length;
|
|
1448
|
+
console.log(
|
|
1449
|
+
`Found ${frameCount} frames for direction: ${direction} (code: ${currentDirectionCode})`,
|
|
1450
|
+
);
|
|
1451
|
+
for (let frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
1452
|
+
const pngUrl = `${getProxyPath()}assets/${type}/${id}/${currentDirectionCode}/${frameIndex}.png`;
|
|
1453
|
+
console.log(
|
|
1454
|
+
`Loading frame ${frameIndex} for direction code ${currentDirectionCode} from: ${pngUrl}`,
|
|
1455
|
+
);
|
|
1456
|
+
await processAndAddFrameFromPngUrl(currentDirectionCode, pngUrl);
|
|
1457
|
+
}
|
|
1458
|
+
console.log(`Completed loading ${frameCount} frames for direction code: ${currentDirectionCode}`);
|
|
1459
|
+
// Once we found frames for this direction code, we can break to avoid duplicates
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
const buttonSelector = `.direction-code-bar-frames-btn-${currentDirectionCode}`;
|
|
1466
|
+
const previewButtonSelector = `.direction-code-bar-preview-btn-${currentDirectionCode}`;
|
|
1467
|
+
console.log(`Registering click handler for: ${buttonSelector}`);
|
|
1468
|
+
|
|
1469
|
+
EventsUI.onClick(previewButtonSelector, async () => {
|
|
1470
|
+
await openDirectionPreviewModal(currentDirectionCode);
|
|
1471
|
+
});
|
|
1472
|
+
|
|
1473
|
+
EventsUI.onClick(buttonSelector, async () => {
|
|
1474
|
+
console.log(`Add frame button clicked for direction: ${currentDirectionCode}`);
|
|
1475
|
+
const ole = s('object-layer-engine');
|
|
1476
|
+
if (!ole) {
|
|
1477
|
+
console.error('object-layer-engine not found');
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
const image = await ole.toBlob();
|
|
1481
|
+
const json = ole.exportMatrixJSON();
|
|
1482
|
+
|
|
1483
|
+
// Check if we're in edit mode
|
|
1484
|
+
if (editingFrameId && editingDirectionCode) {
|
|
1485
|
+
// Ensure we're clicking the add button for the same direction being edited
|
|
1486
|
+
if (currentDirectionCode !== editingDirectionCode) {
|
|
1487
|
+
NotificationManager.Push({
|
|
1488
|
+
html: `<i class="fa-solid fa-exclamation-circle"></i> Please click the glowing <i class="fa-solid fa-edit"></i> button for direction <strong>${editingDirectionCode}</strong> to save changes, or click <i class="fa-solid fa-times"></i> to cancel.`,
|
|
1489
|
+
status: 'warning',
|
|
1490
|
+
});
|
|
1491
|
+
return; // Don't add a new frame
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// UPDATE existing frame
|
|
1495
|
+
console.log(`Updating frame ${editingFrameId} in direction ${editingDirectionCode}`);
|
|
1496
|
+
|
|
1497
|
+
// Find the frame in the data array
|
|
1498
|
+
const frameArray = ObjectLayerEngineModal.ObjectLayerData[editingDirectionCode];
|
|
1499
|
+
const frameIndex = frameArray?.findIndex((frame) => frame.id === editingFrameId);
|
|
1500
|
+
|
|
1501
|
+
if (frameIndex !== undefined && frameIndex >= 0) {
|
|
1502
|
+
// Update the frame data while preserving the ID and index
|
|
1503
|
+
frameArray[frameIndex] = {
|
|
1504
|
+
id: editingFrameId,
|
|
1505
|
+
image,
|
|
1506
|
+
json,
|
|
1507
|
+
};
|
|
1508
|
+
|
|
1509
|
+
// Update the visual representation
|
|
1510
|
+
const imgElement = s(`.direction-code-bar-frames-img-${editingFrameId}`);
|
|
1511
|
+
if (imgElement) {
|
|
1512
|
+
imgElement.src = URL.createObjectURL(image);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
console.log(`Frame ${editingFrameId} updated successfully at index ${frameIndex}`);
|
|
1516
|
+
NotificationManager.Push({
|
|
1517
|
+
html: `<i class="fa-solid fa-check-circle"></i> Frame updated successfully at position ${frameIndex + 1}!`,
|
|
1518
|
+
status: 'success',
|
|
1519
|
+
});
|
|
1520
|
+
} else {
|
|
1521
|
+
console.error(`Could not find frame ${editingFrameId} in direction ${editingDirectionCode}`);
|
|
1522
|
+
NotificationManager.Push({
|
|
1523
|
+
html: `<i class="fa-solid fa-exclamation-triangle"></i> Error: Could not find frame to update`,
|
|
1524
|
+
status: 'error',
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// Exit edit mode and restore UI
|
|
1529
|
+
exitEditMode();
|
|
1530
|
+
} else {
|
|
1531
|
+
// ADD new frame (existing behavior)
|
|
1532
|
+
const id = `frame-capture-${s4()}-${s4()}`;
|
|
1533
|
+
console.log(`Creating new frame ${id} for direction ${currentDirectionCode}`);
|
|
1534
|
+
|
|
1535
|
+
if (!ObjectLayerEngineModal.ObjectLayerData[currentDirectionCode])
|
|
1536
|
+
ObjectLayerEngineModal.ObjectLayerData[currentDirectionCode] = [];
|
|
1537
|
+
ObjectLayerEngineModal.ObjectLayerData[currentDirectionCode].push({ id, image, json });
|
|
1538
|
+
console.log(
|
|
1539
|
+
`Stored frame ${id} in direction code ${currentDirectionCode}. Total frames:`,
|
|
1540
|
+
ObjectLayerEngineModal.ObjectLayerData[currentDirectionCode].length,
|
|
1541
|
+
);
|
|
1542
|
+
|
|
1543
|
+
await addFrameToBar(currentDirectionCode, id, image, json);
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
})(directionCode);
|
|
1547
|
+
}
|
|
1548
|
+
hideFrameLoading();
|
|
1549
|
+
} finally {
|
|
1550
|
+
loadFramesInProgress = false;
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
RouterEvents[`router-${options.idModal}`] = loadFrames;
|
|
1554
|
+
|
|
1555
|
+
await loadFrames();
|
|
1556
|
+
s('object-layer-engine').clear();
|
|
1557
|
+
|
|
1558
|
+
const editor = s('object-layer-engine');
|
|
1559
|
+
const colorPalette = s(`.${colorPaletteClass}`);
|
|
1560
|
+
|
|
1561
|
+
const syncPaletteFromEditor = (event = null) => {
|
|
1562
|
+
if (!colorPalette || !editor) {
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
const nextHex = event?.detail?.hex || rgbaToHex(editor.getBrushColor?.());
|
|
1566
|
+
if (nextHex && colorPalette.value !== nextHex) {
|
|
1567
|
+
colorPalette.value = nextHex;
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
const syncEditorFromPalette = (event) => {
|
|
1572
|
+
if (!editor) {
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
const nextHex = event.detail?.value || event.detail?.hex;
|
|
1576
|
+
if (!nextHex) {
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
const [red, green, blue] = hexToRgbA(nextHex);
|
|
1580
|
+
const alpha = editor.getBrushAlpha?.() ?? editor.getBrushColor?.()?.[3] ?? 255;
|
|
1581
|
+
editor.setBrushColor([red, green, blue, alpha]);
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
if (colorPalette) {
|
|
1585
|
+
colorPalette.addEventListener('colorchange', syncEditorFromPalette);
|
|
1586
|
+
}
|
|
1587
|
+
if (editor) {
|
|
1588
|
+
editor.addEventListener('brushcolorchange', syncPaletteFromEditor);
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
const syncUniformOpacityFromEditor = () => {
|
|
1592
|
+
applyUniformOpacityToEditor();
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
if (editor) {
|
|
1596
|
+
editor.addEventListener('brushcolorchange', syncUniformOpacityFromEditor);
|
|
1597
|
+
editor.addEventListener('matrixload', syncUniformOpacityFromEditor);
|
|
1598
|
+
}
|
|
1599
|
+
syncPaletteFromEditor();
|
|
1600
|
+
|
|
1601
|
+
const setDistortionStatus = (message, tone = 'muted') => {
|
|
1602
|
+
const statusNode = s(`.${distortionStatusClass}`);
|
|
1603
|
+
if (!statusNode) return;
|
|
1604
|
+
statusNode.style.color = tone === 'success' ? '#8fd18c' : tone === 'error' ? '#ff8a8a' : '#888';
|
|
1605
|
+
statusNode.innerHTML = message;
|
|
1606
|
+
};
|
|
1607
|
+
|
|
1608
|
+
const applyDistortionToCurrentFrame = async () => {
|
|
1609
|
+
const ole = s('object-layer-engine');
|
|
1610
|
+
if (!ole || typeof ole.exportMatrixJSON !== 'function' || typeof ole.loadMatrix !== 'function') return;
|
|
1611
|
+
|
|
1612
|
+
let currentJson = null;
|
|
1613
|
+
let currentFrame = null;
|
|
1614
|
+
|
|
1615
|
+
try {
|
|
1616
|
+
currentJson = ole.exportMatrixJSON();
|
|
1617
|
+
currentFrame = typeof currentJson === 'string' ? JSON.parse(currentJson) : currentJson;
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
setDistortionStatus('Could not read the current frame from the editor.', 'error');
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
const currentMatrix = currentFrame?.matrix;
|
|
1624
|
+
if (!Array.isArray(currentMatrix) || !currentMatrix.length || !currentMatrix[0]?.length) {
|
|
1625
|
+
setDistortionStatus('The current frame has no editable matrix data.', 'error');
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
const selectedDistortionType = ObjectLayerEngineModal.selectedDistortionType || DEFAULT_DISTORTION_TYPE;
|
|
1629
|
+
const selectedBehavior =
|
|
1630
|
+
CANVAS_BEHAVIOR_BY_VALUE[selectedDistortionType] || CANVAS_BEHAVIOR_BY_VALUE[DEFAULT_DISTORTION_TYPE];
|
|
1631
|
+
const distortionFactorA = readDistortionFactorA();
|
|
1632
|
+
const isMosaicMode = isMosaicBehavior(selectedDistortionType);
|
|
1633
|
+
|
|
1634
|
+
if (!isMosaicMode && !currentMatrix.some((row) => row.some((cell) => isVisibleCell(cell)))) {
|
|
1635
|
+
setDistortionStatus('Paint something on the current frame before applying a distortion.', 'error');
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
const baseFrame = currentFrame;
|
|
1640
|
+
let transformationResult = null;
|
|
1641
|
+
|
|
1642
|
+
if (isMosaicMode) {
|
|
1643
|
+
const activeBrushColor = normalizeColorCell(ole.getBrushColor?.() || [255, 0, 0, 255]);
|
|
1644
|
+
transformationResult = buildMosaicMatrix(
|
|
1645
|
+
baseFrame.matrix,
|
|
1646
|
+
selectedDistortionType,
|
|
1647
|
+
distortionFactorA,
|
|
1648
|
+
activeBrushColor,
|
|
1649
|
+
);
|
|
1650
|
+
} else {
|
|
1651
|
+
const seedBase = Date.now() + hashString(currentJson);
|
|
1652
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
1653
|
+
const distortionSeed = seedBase + attempt * 977;
|
|
1654
|
+
transformationResult = buildDistortedMatrix(
|
|
1655
|
+
baseFrame.matrix,
|
|
1656
|
+
selectedDistortionType,
|
|
1657
|
+
distortionFactorA,
|
|
1658
|
+
distortionSeed,
|
|
1659
|
+
);
|
|
1660
|
+
if (transformationResult.changedCells > 0) break;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
if (!transformationResult || transformationResult.changedCells === 0) {
|
|
1665
|
+
setDistortionStatus(
|
|
1666
|
+
isMosaicMode
|
|
1667
|
+
? 'No visible mosaic was painted on the current frame. Try another factorA value or a different active color.'
|
|
1668
|
+
: 'No visible distortion was produced for the current frame. Try applying again or edit the frame shape first.',
|
|
1669
|
+
'error',
|
|
1670
|
+
);
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
const nextSnapshot = {
|
|
1675
|
+
width: baseFrame.width,
|
|
1676
|
+
height: baseFrame.height,
|
|
1677
|
+
matrix: transformationResult.matrix,
|
|
1678
|
+
};
|
|
1679
|
+
const beforeSnapshot = typeof ole._snapshot === 'function' ? ole._snapshot() : null;
|
|
1680
|
+
|
|
1681
|
+
if (
|
|
1682
|
+
beforeSnapshot &&
|
|
1683
|
+
typeof ole._pushUndo === 'function' &&
|
|
1684
|
+
typeof ole._matricesEqual === 'function' &&
|
|
1685
|
+
!ole._matricesEqual(beforeSnapshot, nextSnapshot)
|
|
1686
|
+
) {
|
|
1687
|
+
ole._pushUndo(beforeSnapshot);
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
ole.loadMatrix(transformationResult.matrix);
|
|
1691
|
+
|
|
1692
|
+
if (isMosaicMode) {
|
|
1693
|
+
setDistortionStatus(
|
|
1694
|
+
`${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)}.`,
|
|
1695
|
+
'success',
|
|
1696
|
+
);
|
|
1697
|
+
} else {
|
|
1698
|
+
setDistortionStatus(
|
|
1699
|
+
`${selectedBehavior.label} applied to the current frame. ${transformationResult.appliedDistortions || 0} local shifts, ${transformationResult.changedCells} cells changed, factorA=${distortionFactorA.toFixed(2)}.`,
|
|
1700
|
+
'success',
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
|
|
1705
|
+
EventsUI.onClick(`.${distortionApplyBtnClass}`, async () => {
|
|
1706
|
+
await applyDistortionToCurrentFrame();
|
|
1707
|
+
});
|
|
1708
|
+
setDistortionStatus(DEFAULT_DISTORTION_STATUS);
|
|
1709
|
+
|
|
1710
|
+
EventsUI.onClick(`.${statsRandomizeBtnClass}`, async () => {
|
|
1711
|
+
randomizeStatInputs();
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
const persistObjectLayer = async ({ clone = false } = {}) => {
|
|
1715
|
+
const isUpdateMode = Boolean(ObjectLayerEngineModal.existingObjectLayerId) && !clone;
|
|
1716
|
+
|
|
1717
|
+
// Validate minimum frame_duration 100ms
|
|
1718
|
+
const frameDuration = parseInt(s(`.ol-input-render-frame-duration`).value);
|
|
1719
|
+
if (!frameDuration || frameDuration < 100) {
|
|
1720
|
+
NotificationManager.Push({
|
|
1721
|
+
html: 'Frame duration must be at least 100ms',
|
|
1722
|
+
status: 'error',
|
|
1723
|
+
});
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
// Validate that item.id is not empty
|
|
1728
|
+
const itemId = s(`.ol-input-item-id`).value;
|
|
1729
|
+
if (!itemId || itemId.trim() === '') {
|
|
1730
|
+
NotificationManager.Push({
|
|
1731
|
+
html: 'Item ID is required',
|
|
1732
|
+
status: 'error',
|
|
1733
|
+
});
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// Validate that direction 08 (down idle) has at least 1 frame (frame index 0)
|
|
1738
|
+
if (
|
|
1739
|
+
!ObjectLayerEngineModal.ObjectLayerData['08'] ||
|
|
1740
|
+
ObjectLayerEngineModal.ObjectLayerData['08'].length === 0
|
|
1741
|
+
) {
|
|
1742
|
+
NotificationManager.Push({
|
|
1743
|
+
html: 'Direction 08 (down idle) must have at least 1 frame (frame index 0)',
|
|
1744
|
+
status: 'error',
|
|
1745
|
+
});
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
// Separate render frames data from objectLayer.data
|
|
1750
|
+
const objectLayerRenderFramesData = {
|
|
1751
|
+
frames: {},
|
|
1752
|
+
colors: [],
|
|
1753
|
+
frame_duration: ObjectLayerEngineModal.renderFrameDuration,
|
|
1754
|
+
};
|
|
1755
|
+
|
|
1756
|
+
const objectLayer = {
|
|
1757
|
+
data: {
|
|
1758
|
+
stats: {},
|
|
1759
|
+
item: {},
|
|
1760
|
+
ledger: { type: 'OFF_CHAIN' },
|
|
1761
|
+
},
|
|
1762
|
+
};
|
|
1763
|
+
for (const directionCode of directionCodes) {
|
|
1764
|
+
const directions = ObjectLayerEngineModal.getDirectionsFromDirectionCode(directionCode);
|
|
1765
|
+
for (const direction of directions) {
|
|
1766
|
+
if (!objectLayerRenderFramesData.frames[direction]) objectLayerRenderFramesData.frames[direction] = [];
|
|
1767
|
+
|
|
1768
|
+
if (!(directionCode in ObjectLayerEngineModal.ObjectLayerData)) {
|
|
1769
|
+
console.warn('No set directionCodeBarFrameData for directionCode', directionCode);
|
|
1770
|
+
continue;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
for (const frameData of ObjectLayerEngineModal.ObjectLayerData[directionCode]) {
|
|
1774
|
+
const { matrix } = JSON.parse(frameData.json);
|
|
1775
|
+
const frameIndexColorMatrix = [];
|
|
1776
|
+
let indexRow = -1;
|
|
1777
|
+
for (const row of matrix) {
|
|
1778
|
+
indexRow++;
|
|
1779
|
+
frameIndexColorMatrix[indexRow] = [];
|
|
1780
|
+
let indexCol = -1;
|
|
1781
|
+
for (const value of row) {
|
|
1782
|
+
indexCol++;
|
|
1783
|
+
let colorIndex = objectLayerRenderFramesData.colors.findIndex(
|
|
1784
|
+
(color) =>
|
|
1785
|
+
color[0] === value[0] && color[1] === value[1] && color[2] === value[2] && color[3] === value[3],
|
|
1786
|
+
);
|
|
1787
|
+
if (colorIndex === -1) {
|
|
1788
|
+
objectLayerRenderFramesData.colors.push(value);
|
|
1789
|
+
colorIndex = objectLayerRenderFramesData.colors.length - 1;
|
|
1790
|
+
}
|
|
1791
|
+
frameIndexColorMatrix[indexRow][indexCol] = colorIndex;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
objectLayerRenderFramesData.frames[direction].push(frameIndexColorMatrix);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
objectLayerRenderFramesData.frame_duration = parseInt(s(`.ol-input-render-frame-duration`).value);
|
|
1799
|
+
objectLayer.data.stats = {
|
|
1800
|
+
effect: parseInt(s(`.ol-input-item-stats-effect`).value),
|
|
1801
|
+
resistance: parseInt(s(`.ol-input-item-stats-resistance`).value),
|
|
1802
|
+
agility: parseInt(s(`.ol-input-item-stats-agility`).value),
|
|
1803
|
+
range: parseInt(s(`.ol-input-item-stats-range`).value),
|
|
1804
|
+
intelligence: parseInt(s(`.ol-input-item-stats-intelligence`).value),
|
|
1805
|
+
utility: parseInt(s(`.ol-input-item-stats-utility`).value),
|
|
1806
|
+
};
|
|
1807
|
+
objectLayer.data.item = {
|
|
1808
|
+
type: ObjectLayerEngineModal.selectItemType,
|
|
1809
|
+
activable: ObjectLayerEngineModal.itemActivable,
|
|
1810
|
+
id: s(`.ol-input-item-id`).value,
|
|
1811
|
+
description: s(`.ol-input-item-description`).value,
|
|
1812
|
+
};
|
|
1813
|
+
|
|
1814
|
+
// Add _id only when updating the existing object layer.
|
|
1815
|
+
if (isUpdateMode) {
|
|
1816
|
+
objectLayer._id = ObjectLayerEngineModal.existingObjectLayerId;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
console.warn(
|
|
1820
|
+
'objectLayer',
|
|
1821
|
+
objectLayer,
|
|
1822
|
+
clone ? '(CLONE MODE)' : isUpdateMode ? '(UPDATE MODE)' : '(CREATE MODE)',
|
|
1823
|
+
);
|
|
1824
|
+
|
|
1825
|
+
if (!commonModeratorGuard(appStore.Data.user.main.model.user.role)) {
|
|
1826
|
+
NotificationManager.Push({
|
|
1827
|
+
html: 'Only moderators and admins can create or edit object layers.',
|
|
1828
|
+
status: 'warning',
|
|
1829
|
+
});
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
// Upload images
|
|
1834
|
+
{
|
|
1835
|
+
// Get all direction codes that currently have frames
|
|
1836
|
+
const directionCodesToUpload = Object.keys(ObjectLayerEngineModal.ObjectLayerData);
|
|
1837
|
+
|
|
1838
|
+
// In UPDATE mode, also include original direction codes that may have been cleared
|
|
1839
|
+
const allDirectionCodes = isUpdateMode
|
|
1840
|
+
? [...new Set([...directionCodesToUpload, ...ObjectLayerEngineModal.originalDirectionCodes])]
|
|
1841
|
+
: directionCodesToUpload;
|
|
1842
|
+
|
|
1843
|
+
console.warn(
|
|
1844
|
+
`Uploading frames for ${allDirectionCodes.length} directions:`,
|
|
1845
|
+
allDirectionCodes,
|
|
1846
|
+
clone ? '(CLONE MODE)' : isUpdateMode ? '(UPDATE MODE)' : '(CREATE MODE)',
|
|
1847
|
+
);
|
|
1848
|
+
|
|
1849
|
+
for (const directionCode of allDirectionCodes) {
|
|
1850
|
+
const frames = ObjectLayerEngineModal.ObjectLayerData[directionCode] || [];
|
|
1851
|
+
console.warn(`Direction ${directionCode}: ${frames.length} frames`);
|
|
1852
|
+
|
|
1853
|
+
// Create FormData with ALL frames for this direction
|
|
1854
|
+
const form = new FormData();
|
|
1855
|
+
let frameIndex = -1;
|
|
1856
|
+
for (const frame of frames) {
|
|
1857
|
+
frameIndex++;
|
|
1858
|
+
const pngBlob = frame.image;
|
|
1859
|
+
|
|
1860
|
+
if (!pngBlob) {
|
|
1861
|
+
console.error(`Frame ${frameIndex} in direction ${directionCode} has no image blob!`);
|
|
1862
|
+
continue;
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
// Append all frames to the same FormData
|
|
1866
|
+
form.append(directionCode, pngBlob, `${frameIndex}.png`);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// Send all frames for this direction in one request (even if empty, to remove frames)
|
|
1870
|
+
try {
|
|
1871
|
+
if (isUpdateMode) {
|
|
1872
|
+
// UPDATE: use PUT endpoint with object layer ID
|
|
1873
|
+
const { status, data } = await ObjectLayerService.put({
|
|
1874
|
+
id: `${ObjectLayerEngineModal.existingObjectLayerId}/frame-image/${objectLayer.data.item.type}/${objectLayer.data.item.id}/${directionCode}`,
|
|
1875
|
+
body: form,
|
|
1876
|
+
headerId: 'file',
|
|
1877
|
+
});
|
|
1878
|
+
console.warn(`Updated ${frames.length} frames for direction ${directionCode}`);
|
|
1879
|
+
} else {
|
|
1880
|
+
// CREATE: use POST endpoint (only if frames exist)
|
|
1881
|
+
if (frames.length > 0) {
|
|
1882
|
+
const { status, data } = await ObjectLayerService.post({
|
|
1883
|
+
id: `frame-image/${objectLayer.data.item.type}/${objectLayer.data.item.id}/${directionCode}`,
|
|
1884
|
+
body: form,
|
|
1885
|
+
headerId: 'file',
|
|
1886
|
+
});
|
|
1887
|
+
console.warn(`Created ${frames.length} frames for direction ${directionCode}`);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
} catch (error) {
|
|
1891
|
+
console.error(`Error uploading frames for direction ${directionCode}:`, error);
|
|
1892
|
+
NotificationManager.Push({
|
|
1893
|
+
html: `Error uploading frames for direction ${directionCode}: ${error.message}`,
|
|
1894
|
+
status: 'error',
|
|
1895
|
+
});
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
console.warn('All frames uploaded successfully');
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
// Upload metadata
|
|
1904
|
+
{
|
|
1905
|
+
// Send objectLayerRenderFramesData as top-level field (not in data)
|
|
1906
|
+
const requestBody = {
|
|
1907
|
+
data: objectLayer.data,
|
|
1908
|
+
objectLayerRenderFramesData: objectLayerRenderFramesData,
|
|
1909
|
+
};
|
|
1910
|
+
|
|
1911
|
+
let response;
|
|
1912
|
+
if (isUpdateMode) {
|
|
1913
|
+
// UPDATE existing object layer
|
|
1914
|
+
console.warn(
|
|
1915
|
+
'PUT path:',
|
|
1916
|
+
`${ObjectLayerEngineModal.existingObjectLayerId}/metadata/${objectLayer.data.item.type}/${objectLayer.data.item.id}`,
|
|
1917
|
+
);
|
|
1918
|
+
response = await ObjectLayerService.put({
|
|
1919
|
+
id: `${ObjectLayerEngineModal.existingObjectLayerId}/metadata/${objectLayer.data.item.type}/${objectLayer.data.item.id}`,
|
|
1920
|
+
body: requestBody,
|
|
1921
|
+
});
|
|
1922
|
+
} else {
|
|
1923
|
+
// CREATE new object layer
|
|
1924
|
+
response = await ObjectLayerService.post({
|
|
1925
|
+
id: `metadata/${objectLayer.data.item.type}/${objectLayer.data.item.id}`,
|
|
1926
|
+
body: requestBody,
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
const { status, data, message } = response;
|
|
1931
|
+
|
|
1932
|
+
if (status === 'success') {
|
|
1933
|
+
const successAction = clone ? 'cloned' : isUpdateMode ? 'updated' : 'created';
|
|
1934
|
+
NotificationManager.Push({
|
|
1935
|
+
html: `Object layer "${objectLayer.data.item.id}" ${successAction} successfully!`,
|
|
1936
|
+
status: 'success',
|
|
1937
|
+
});
|
|
1938
|
+
ObjectLayerEngineModal.toManagement(data?._id || ObjectLayerEngineModal.existingObjectLayerId);
|
|
1939
|
+
} else {
|
|
1940
|
+
const errorAction = clone ? 'cloning' : isUpdateMode ? 'updating' : 'creating';
|
|
1941
|
+
NotificationManager.Push({
|
|
1942
|
+
html: `Error ${errorAction} object layer: ${message}`,
|
|
1943
|
+
status: 'error',
|
|
1944
|
+
});
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
};
|
|
1948
|
+
|
|
1949
|
+
EventsUI.onClick(`.ol-btn-save`, async () => {
|
|
1950
|
+
await persistObjectLayer();
|
|
1951
|
+
});
|
|
1952
|
+
|
|
1953
|
+
EventsUI.onClick(`.ol-btn-clone`, async () => {
|
|
1954
|
+
await persistObjectLayer({ clone: true });
|
|
1955
|
+
});
|
|
1956
|
+
|
|
1957
|
+
// Add reset button event listener
|
|
1958
|
+
EventsUI.onClick(`.ol-btn-reset`, async () => {
|
|
1959
|
+
const confirmResult = await Modal.RenderConfirm({
|
|
1960
|
+
html: async () => {
|
|
1961
|
+
return html`
|
|
1962
|
+
<div class="in section-mp" style="text-align: center">
|
|
1963
|
+
Are you sure you want to reset the form? All unsaved data will be lost.
|
|
1964
|
+
</div>
|
|
1965
|
+
`;
|
|
1966
|
+
},
|
|
1967
|
+
id: `reset-ol-modal-confirm`,
|
|
1968
|
+
});
|
|
1969
|
+
|
|
1970
|
+
if (confirmResult.status === 'confirm') {
|
|
1971
|
+
NotificationManager.Push({
|
|
1972
|
+
html: 'Resetting form to create new object layer...',
|
|
1973
|
+
status: 'info',
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1976
|
+
// Clear all data
|
|
1977
|
+
ObjectLayerEngineModal.clearData();
|
|
1978
|
+
|
|
1979
|
+
setPath(`${getProxyPath()}object-layer-engine`);
|
|
1980
|
+
|
|
1981
|
+
// Reload the modal
|
|
1982
|
+
await ObjectLayerEngineModal.Reload();
|
|
1983
|
+
|
|
1984
|
+
NotificationManager.Push({
|
|
1985
|
+
html: 'Form reset! Ready to create new object layer.',
|
|
1986
|
+
status: 'success',
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
});
|
|
1990
|
+
});
|
|
1991
|
+
|
|
1992
|
+
return html`
|
|
1993
|
+
<style>
|
|
1994
|
+
.direction-code-bar-frames-title {
|
|
1995
|
+
font-weight: bold;
|
|
1996
|
+
font-size: 1.2rem;
|
|
1997
|
+
padding: 0.5rem;
|
|
1998
|
+
width: 70px;
|
|
1999
|
+
}
|
|
2000
|
+
.direction-code-bar-frames-img {
|
|
2001
|
+
width: 100px;
|
|
2002
|
+
height: auto;
|
|
2003
|
+
margin: 3px;
|
|
2004
|
+
cursor: pointer;
|
|
2005
|
+
}
|
|
2006
|
+
.direction-code-bar-trash-btn {
|
|
2007
|
+
top: 3px;
|
|
2008
|
+
left: 30px;
|
|
2009
|
+
color: white;
|
|
2010
|
+
border: none !important;
|
|
2011
|
+
}
|
|
2012
|
+
.direction-code-bar-edit-btn {
|
|
2013
|
+
top: 3px;
|
|
2014
|
+
left: 3px;
|
|
2015
|
+
color: white;
|
|
2016
|
+
border: none !important;
|
|
2017
|
+
}
|
|
2018
|
+
.direction-code-bar-frames-btn-add {
|
|
2019
|
+
color: white;
|
|
2020
|
+
border: none !important;
|
|
2021
|
+
}
|
|
2022
|
+
.direction-code-bar-preview-btn {
|
|
2023
|
+
color: white;
|
|
2024
|
+
border: none !important;
|
|
2025
|
+
}
|
|
2026
|
+
.direction-code-bar-trash-btn:hover {
|
|
2027
|
+
background: none !important;
|
|
2028
|
+
color: red;
|
|
2029
|
+
}
|
|
2030
|
+
.direction-code-bar-edit-btn:hover {
|
|
2031
|
+
background: none !important;
|
|
2032
|
+
color: yellow;
|
|
2033
|
+
}
|
|
2034
|
+
.direction-code-bar-frames-btn-add:hover {
|
|
2035
|
+
background: none !important;
|
|
2036
|
+
color: #c7ff58;
|
|
2037
|
+
}
|
|
2038
|
+
.direction-code-bar-preview-btn:hover {
|
|
2039
|
+
background: none !important;
|
|
2040
|
+
color: #5ee6ff;
|
|
2041
|
+
}
|
|
2042
|
+
.ol-btn-save {
|
|
2043
|
+
width: 120px;
|
|
2044
|
+
padding: 0.5rem;
|
|
2045
|
+
font-size: 20px;
|
|
2046
|
+
min-height: 50px;
|
|
2047
|
+
}
|
|
2048
|
+
.ol-btn-reset {
|
|
2049
|
+
width: 120px;
|
|
2050
|
+
padding: 0.5rem;
|
|
2051
|
+
font-size: 20px;
|
|
2052
|
+
min-height: 50px;
|
|
2053
|
+
}
|
|
2054
|
+
.ol-btn-clone {
|
|
2055
|
+
width: 120px;
|
|
2056
|
+
padding: 0.5rem;
|
|
2057
|
+
font-size: 20px;
|
|
2058
|
+
min-height: 50px;
|
|
2059
|
+
}
|
|
2060
|
+
.ol-btn-randomize-stats {
|
|
2061
|
+
min-height: 50px;
|
|
2062
|
+
padding: 0.5rem 0.75rem;
|
|
2063
|
+
}
|
|
2064
|
+
.ol-number-label {
|
|
2065
|
+
width: 120px;
|
|
2066
|
+
font-size: 16px;
|
|
2067
|
+
overflow: hidden;
|
|
2068
|
+
font-family: 'retro-font';
|
|
2069
|
+
}
|
|
2070
|
+
.sub-title-modal {
|
|
2071
|
+
color: #ffcc00;
|
|
2072
|
+
}
|
|
2073
|
+
.stat-label-container {
|
|
2074
|
+
display: flex;
|
|
2075
|
+
align-items: center;
|
|
2076
|
+
}
|
|
2077
|
+
.stat-info-icon {
|
|
2078
|
+
cursor: default;
|
|
2079
|
+
}
|
|
2080
|
+
.stat-description {
|
|
2081
|
+
padding: 2px 5px;
|
|
2082
|
+
border-left: 2px solid #444;
|
|
2083
|
+
margin-bottom: 5px;
|
|
2084
|
+
max-width: 200px;
|
|
2085
|
+
}
|
|
2086
|
+
.frame-editor-container-loading {
|
|
2087
|
+
width: 100%;
|
|
2088
|
+
height: 150px;
|
|
2089
|
+
color: #ffcc00;
|
|
2090
|
+
}
|
|
2091
|
+
.loading-text {
|
|
2092
|
+
font-family: 'retro-font';
|
|
2093
|
+
font-size: 26px;
|
|
2094
|
+
}
|
|
2095
|
+
</style>
|
|
2096
|
+
${borderChar(2, 'black', [
|
|
2097
|
+
'.sub-title-modal',
|
|
2098
|
+
'.frame-editor-container-loading',
|
|
2099
|
+
'.direction-code-bar-edit-btn',
|
|
2100
|
+
'.direction-code-bar-trash-btn',
|
|
2101
|
+
'.direction-code-bar-frames-btn-add',
|
|
2102
|
+
'.direction-code-bar-preview-btn',
|
|
2103
|
+
])}
|
|
2104
|
+
<div class="in frame-editor-container-loading">
|
|
2105
|
+
<div class="abs center frame-editor-container-loading-center"></div>
|
|
2106
|
+
</div>
|
|
2107
|
+
<div class="in section-mp section-mp-border frame-editor-container">
|
|
2108
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-table-cells-large"></i> Frame editor</div>
|
|
2109
|
+
|
|
2110
|
+
<object-layer-engine id="ole" width="${cellsW}" height="${cellsH}" pixel-size="${pixelSize}">
|
|
2111
|
+
</object-layer-engine>
|
|
2112
|
+
<div class="in section-mp-border" style="margin-top: 10px;">
|
|
2113
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-palette"></i> Brush palette</div>
|
|
2114
|
+
<color-palette class="${colorPaletteClass}" value="#FF0000"></color-palette>
|
|
2115
|
+
<div class="fl" style="align-items: center; gap: 8px; margin-top: 8px;">
|
|
2116
|
+
${await ToggleSwitch.instance({
|
|
2117
|
+
id: UNIFORM_OPACITY_TOGGLE_ID,
|
|
2118
|
+
type: 'checkbox',
|
|
2119
|
+
displayMode: 'checkbox',
|
|
2120
|
+
containerClass: 'in fll',
|
|
2121
|
+
checked: ObjectLayerEngineModal.uniformOpacityEnabled,
|
|
2122
|
+
on: {
|
|
2123
|
+
checked: () => {
|
|
2124
|
+
ObjectLayerEngineModal.uniformOpacityEnabled = true;
|
|
2125
|
+
applyUniformOpacityToEditor({ captureUndo: true });
|
|
2126
|
+
},
|
|
2127
|
+
unchecked: () => {
|
|
2128
|
+
ObjectLayerEngineModal.uniformOpacityEnabled = false;
|
|
2129
|
+
},
|
|
2130
|
+
},
|
|
2131
|
+
})}
|
|
2132
|
+
<div class="section-mp" style="font-size: 14px;">
|
|
2133
|
+
Keep all visible cells at the current opacity bar value
|
|
2134
|
+
</div>
|
|
2135
|
+
</div>
|
|
2136
|
+
</div>
|
|
2137
|
+
<div class="in section-mp-border" style="margin-top: 10px;">
|
|
2138
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-wand-magic-sparkles"></i> Canvas macro</div>
|
|
2139
|
+
<div class="fl" style="align-items: flex-start; gap: 8px; flex-wrap: wrap;">
|
|
2140
|
+
<div class="in fll" style="min-width: 240px;">
|
|
2141
|
+
${await DropDown.instance({
|
|
2142
|
+
id: distortionDropdownId,
|
|
2143
|
+
value: ObjectLayerEngineModal.selectedDistortionType,
|
|
2144
|
+
label: html`Select behavior`,
|
|
2145
|
+
disableSearchBox: true,
|
|
2146
|
+
data: [
|
|
2147
|
+
{
|
|
2148
|
+
kind: 'group',
|
|
2149
|
+
value: 'group-distortion-behaviors',
|
|
2150
|
+
display: html`<div style="padding: 0 6px; color: #9d9d9d;">Distortion behaviors</div>`,
|
|
2151
|
+
},
|
|
2152
|
+
...DISTORTION_TYPES.map((distortion) => ({
|
|
2153
|
+
value: distortion.value,
|
|
2154
|
+
display: html`<i class="${CANVAS_BEHAVIOR_ICON}"></i> ${distortion.label}`,
|
|
2155
|
+
onClick: async () => {
|
|
2156
|
+
ObjectLayerEngineModal.selectedDistortionType = distortion.value;
|
|
2157
|
+
readDistortionFactorA();
|
|
2158
|
+
const statusNode = s(`.${distortionStatusClass}`);
|
|
2159
|
+
if (statusNode) {
|
|
2160
|
+
statusNode.style.color = '#888';
|
|
2161
|
+
statusNode.innerHTML = `${distortion.label} ready for direct canvas apply. factorA controls local distortion density.`;
|
|
2162
|
+
}
|
|
2163
|
+
},
|
|
2164
|
+
})),
|
|
2165
|
+
{
|
|
2166
|
+
kind: 'group',
|
|
2167
|
+
value: 'group-mosaic-behaviors',
|
|
2168
|
+
display: html`<div style="padding: 0 6px; color: #9d9d9d;">Mosaic drawing behaviors</div>`,
|
|
2169
|
+
},
|
|
2170
|
+
...MOSAIC_TYPES.map((mosaic) => ({
|
|
2171
|
+
value: mosaic.value,
|
|
2172
|
+
display: html`<i class="${CANVAS_BEHAVIOR_ICON}"></i> ${mosaic.label}`,
|
|
2173
|
+
onClick: async () => {
|
|
2174
|
+
ObjectLayerEngineModal.selectedDistortionType = mosaic.value;
|
|
2175
|
+
readDistortionFactorA();
|
|
2176
|
+
const statusNode = s(`.${distortionStatusClass}`);
|
|
2177
|
+
if (statusNode) {
|
|
2178
|
+
statusNode.style.color = '#888';
|
|
2179
|
+
statusNode.innerHTML = `${mosaic.label} ready for direct canvas apply. factorA controls tile size and density.`;
|
|
2180
|
+
}
|
|
2181
|
+
},
|
|
2182
|
+
})),
|
|
2183
|
+
],
|
|
2184
|
+
})}
|
|
2185
|
+
</div>
|
|
2186
|
+
<div class="in fll" style="width: 120px;">
|
|
2187
|
+
${await Input.instance({
|
|
2188
|
+
id: `ol-input-distortion-factor-a`,
|
|
2189
|
+
label: html`factorA`,
|
|
2190
|
+
containerClass: 'inl',
|
|
2191
|
+
type: 'number',
|
|
2192
|
+
min: 0.01,
|
|
2193
|
+
max: 1,
|
|
2194
|
+
step: 0.01,
|
|
2195
|
+
value: ObjectLayerEngineModal.distortionFactorA,
|
|
2196
|
+
})}
|
|
2197
|
+
</div>
|
|
2198
|
+
<div class="in fll">
|
|
2199
|
+
${await BtnIcon.instance({
|
|
2200
|
+
class: distortionApplyBtnClass,
|
|
2201
|
+
label: html`<i class="fa-solid fa-bolt"></i> Apply To Frame`,
|
|
2202
|
+
})}
|
|
2203
|
+
</div>
|
|
2204
|
+
</div>
|
|
2205
|
+
<div class="in ${distortionStatusClass}" style="margin-top: 6px; font-size: 12px; color: #888;">
|
|
2206
|
+
${DEFAULT_DISTORTION_STATUS}
|
|
2207
|
+
</div>
|
|
2208
|
+
</div>
|
|
2209
|
+
<object-layer-png-loader id="loader" editor-selector="#ole"></object-layer-png-loader>
|
|
2210
|
+
</div>
|
|
2211
|
+
|
|
2212
|
+
<div class="in section-mp section-mp-border">
|
|
2213
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-database"></i> render data</div>
|
|
2214
|
+
${dynamicCol({ containerSelector: options.idModal, id: idSectionA })}
|
|
2215
|
+
|
|
2216
|
+
<div class="fl">
|
|
2217
|
+
<div class="in fll ${idSectionA}-col-a">
|
|
2218
|
+
<div class="in section-mp">
|
|
2219
|
+
${await DropDown.instance({
|
|
2220
|
+
id: 'ol-dropdown-template',
|
|
2221
|
+
value: ObjectLayerEngineModal.templates[0].id,
|
|
2222
|
+
label: html`${Translate.instance('select-template')}`,
|
|
2223
|
+
data: ObjectLayerEngineModal.templates.map((template) => {
|
|
2224
|
+
return {
|
|
2225
|
+
value: template.id,
|
|
2226
|
+
display: html`<i class="fa-solid fa-paint-roller"></i> ${template.label}`,
|
|
2227
|
+
onClick: async () => {
|
|
2228
|
+
ObjectLayerEngineModal.RenderTemplate(template.data);
|
|
2229
|
+
},
|
|
2230
|
+
};
|
|
2231
|
+
}),
|
|
2232
|
+
})}
|
|
2233
|
+
</div>
|
|
2234
|
+
</div>
|
|
2235
|
+
<div class="in fll ${idSectionA}-col-b">
|
|
2236
|
+
<div class="in section-mp-border" style="width: 135px;">
|
|
2237
|
+
${await Input.instance({
|
|
2238
|
+
id: `ol-input-render-frame-duration`,
|
|
2239
|
+
label: html`<div class="inl ol-number-label">
|
|
2240
|
+
<i class="fa-solid fa-chart-simple"></i> Frame duration
|
|
2241
|
+
</div>`,
|
|
2242
|
+
containerClass: 'inl',
|
|
2243
|
+
type: 'number',
|
|
2244
|
+
min: 100,
|
|
2245
|
+
max: 1000,
|
|
2246
|
+
placeholder: true,
|
|
2247
|
+
value: ObjectLayerEngineModal.renderFrameDuration,
|
|
2248
|
+
})}
|
|
2249
|
+
</div>
|
|
2250
|
+
</div>
|
|
2251
|
+
</div>
|
|
2252
|
+
${directionsCodeBarRender}
|
|
2253
|
+
</div>
|
|
2254
|
+
${dynamicCol({ containerSelector: options.idModal, id: idSectionB, type: 'a-50-b-50' })}
|
|
2255
|
+
|
|
2256
|
+
<div class="fl">
|
|
2257
|
+
<div class="in fll ${idSectionB}-col-a">
|
|
2258
|
+
<div class="in section-mp section-mp-border">
|
|
2259
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-database"></i> Item data</div>
|
|
2260
|
+
${await Input.instance({
|
|
2261
|
+
id: `ol-input-item-id`,
|
|
2262
|
+
label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.instance('item-id')}`,
|
|
2263
|
+
containerClass: '',
|
|
2264
|
+
placeholder: true,
|
|
2265
|
+
value: loadedData?.metadata?.data?.item?.id || '',
|
|
2266
|
+
})}
|
|
2267
|
+
${await Input.instance({
|
|
2268
|
+
id: `ol-input-item-description`,
|
|
2269
|
+
label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.instance('item-description')}`,
|
|
2270
|
+
containerClass: '',
|
|
2271
|
+
placeholder: true,
|
|
2272
|
+
value: loadedData?.metadata?.data?.item?.description || '',
|
|
2273
|
+
})}
|
|
2274
|
+
<div class="in section-mp">
|
|
2275
|
+
${await DropDown.instance({
|
|
2276
|
+
id: 'ol-dropdown-item-type',
|
|
2277
|
+
value: ObjectLayerEngineModal.selectItemType,
|
|
2278
|
+
label: html`${Translate.instance('select-item-type')}`,
|
|
2279
|
+
data: itemTypes.map((itemType) => {
|
|
2280
|
+
return {
|
|
2281
|
+
value: itemType,
|
|
2282
|
+
display: html`${itemType}`,
|
|
2283
|
+
onClick: async () => {
|
|
2284
|
+
console.warn('itemType click', itemType);
|
|
2285
|
+
ObjectLayerEngineModal.selectItemType = itemType;
|
|
2286
|
+
},
|
|
2287
|
+
};
|
|
2288
|
+
}),
|
|
2289
|
+
})}
|
|
2290
|
+
</div>
|
|
2291
|
+
<div class="in section-mp">
|
|
2292
|
+
${await ToggleSwitch.instance({
|
|
2293
|
+
id: 'ol-toggle-item-activable',
|
|
2294
|
+
wrapper: true,
|
|
2295
|
+
wrapperLabel: html`${Translate.instance('item-activable')}`,
|
|
2296
|
+
disabledOnClick: true,
|
|
2297
|
+
checked: ObjectLayerEngineModal.itemActivable,
|
|
2298
|
+
on: {
|
|
2299
|
+
unchecked: () => {
|
|
2300
|
+
ObjectLayerEngineModal.itemActivable = false;
|
|
2301
|
+
console.warn('itemActivable', ObjectLayerEngineModal.itemActivable);
|
|
2302
|
+
},
|
|
2303
|
+
checked: () => {
|
|
2304
|
+
ObjectLayerEngineModal.itemActivable = true;
|
|
2305
|
+
console.warn('itemActivable', ObjectLayerEngineModal.itemActivable);
|
|
2306
|
+
},
|
|
2307
|
+
},
|
|
2308
|
+
})}
|
|
2309
|
+
</div>
|
|
2310
|
+
</div>
|
|
2311
|
+
</div>
|
|
2312
|
+
<div class="in fll ${idSectionB}-col-b">
|
|
2313
|
+
<div class="in section-mp section-mp-border">
|
|
2314
|
+
<div class="in sub-title-modal"><i class="fa-solid fa-database"></i> Stats data</div>
|
|
2315
|
+
<div class="fl" style="align-items: flex-end; gap: 8px; flex-wrap: wrap; margin-bottom: 10px;">
|
|
2316
|
+
<div class="in fll" style="width: 110px;">
|
|
2317
|
+
${await Input.instance({
|
|
2318
|
+
id: statsRandomMinInputId,
|
|
2319
|
+
label: html`Random min`,
|
|
2320
|
+
containerClass: 'inl',
|
|
2321
|
+
type: 'number',
|
|
2322
|
+
min: 0,
|
|
2323
|
+
max: 10,
|
|
2324
|
+
placeholder: true,
|
|
2325
|
+
value: DEFAULT_STAT_RANDOM_MIN,
|
|
2326
|
+
})}
|
|
2327
|
+
</div>
|
|
2328
|
+
<div class="in fll" style="width: 110px;">
|
|
2329
|
+
${await Input.instance({
|
|
2330
|
+
id: statsRandomMaxInputId,
|
|
2331
|
+
label: html`Random max`,
|
|
2332
|
+
containerClass: 'inl',
|
|
2333
|
+
type: 'number',
|
|
2334
|
+
min: 0,
|
|
2335
|
+
max: 10,
|
|
2336
|
+
placeholder: true,
|
|
2337
|
+
value: DEFAULT_STAT_RANDOM_MAX,
|
|
2338
|
+
})}
|
|
2339
|
+
</div>
|
|
2340
|
+
<div class="in fll">
|
|
2341
|
+
${await BtnIcon.instance({
|
|
2342
|
+
label: html`<i class="fa-solid fa-dice"></i> Randomize`,
|
|
2343
|
+
class: statsRandomizeBtnClass,
|
|
2344
|
+
})}
|
|
2345
|
+
</div>
|
|
2346
|
+
</div>
|
|
2347
|
+
${statsInputsRender}
|
|
2348
|
+
</div>
|
|
2349
|
+
</div>
|
|
2350
|
+
</div>
|
|
2351
|
+
|
|
2352
|
+
<div class="fl section-mp">
|
|
2353
|
+
${canMutate
|
|
2354
|
+
? await BtnIcon.instance({
|
|
2355
|
+
label: html`<i class="submit-btn-icon fa-solid fa-folder-open"></i>
|
|
2356
|
+
${ObjectLayerEngineModal.existingObjectLayerId ? 'Update' : Translate.instance('save')}`,
|
|
2357
|
+
class: `in flr ol-btn-save`,
|
|
2358
|
+
})
|
|
2359
|
+
: ''}
|
|
2360
|
+
${canMutate && ObjectLayerEngineModal.existingObjectLayerId
|
|
2361
|
+
? await BtnIcon.instance({
|
|
2362
|
+
label: html`<i class="submit-btn-icon fa-solid fa-clone"></i> Clone`,
|
|
2363
|
+
class: `in flr ol-btn-clone`,
|
|
2364
|
+
})
|
|
2365
|
+
: ''}
|
|
2366
|
+
${await BtnIcon.instance({
|
|
2367
|
+
label: html`<i class="submit-btn-icon fa-solid fa-broom"></i> ${Translate.instance('reset')}`,
|
|
2368
|
+
class: `in flr ol-btn-reset`,
|
|
2369
|
+
})}
|
|
2370
|
+
</div>
|
|
2371
|
+
<div class="in section-mp"></div>
|
|
2372
|
+
`;
|
|
2373
|
+
};
|
|
2374
|
+
|
|
2375
|
+
static getDirectionsFromDirectionCode(directionCode = '08') {
|
|
2376
|
+
return getKeyframeDirectionsByCode(directionCode);
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
static toManagement = async (id = null) => {
|
|
2380
|
+
await ObjectLayerEngineModal.clearData();
|
|
2381
|
+
const subModalId = 'management';
|
|
2382
|
+
const modalId = `modal-object-layer-engine-${subModalId}`;
|
|
2383
|
+
await DefaultManagement.runIsolated(modalId, async () => {
|
|
2384
|
+
setPath(`${getProxyPath()}object-layer-engine-management`);
|
|
2385
|
+
const queryParams = getQueryParams();
|
|
2386
|
+
queryParams.id = id ? id : '';
|
|
2387
|
+
queryParams.page = 1;
|
|
2388
|
+
setQueryParams(queryParams, { replace: true });
|
|
2389
|
+
|
|
2390
|
+
if (id) {
|
|
2391
|
+
DefaultManagement.setIdFilter(modalId, id);
|
|
2392
|
+
} else {
|
|
2393
|
+
DefaultManagement.clearIdFilter(modalId);
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
const managerComponent = DefaultManagement.Tokens[modalId];
|
|
2397
|
+
if (managerComponent) {
|
|
2398
|
+
managerComponent.page = 1;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
s(`.main-btn-object-layer-engine-${subModalId}`).click();
|
|
2402
|
+
|
|
2403
|
+
await DefaultManagement.waitGridReady(modalId);
|
|
2404
|
+
await DefaultManagement.loadTable(modalId, { force: true, reload: true });
|
|
2405
|
+
});
|
|
2406
|
+
};
|
|
2407
|
+
|
|
2408
|
+
static async Reload() {
|
|
2409
|
+
// Clear data before reload to prevent contamination
|
|
2410
|
+
ObjectLayerEngineModal.clearData();
|
|
2411
|
+
const idModal = 'modal-object-layer-engine';
|
|
2412
|
+
if (s(`.modal-object-layer-engine`))
|
|
2413
|
+
Modal.writeHTML({
|
|
2414
|
+
idModal,
|
|
2415
|
+
html: await Modal.Data[idModal].options.html(),
|
|
2416
|
+
});
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
export { ObjectLayerEngineModal };
|