Compare commits

...

30 Commits

Author SHA1 Message Date
4042808d4e Socket event enum enhancement 2025-02-17 01:20:16 +01:00
a6d6d894a9 #363 : Moved socket logic into socketManager and removed it from Pinia store 2025-02-17 01:17:02 +01:00
0c61fe77de Paint tool fixes 2025-02-16 21:36:31 +01:00
bfb2bcb939 Map editor teleport enhancements 2025-02-16 21:18:06 +01:00
af5a97f66d Removed debug console log 2025-02-16 19:04:35 +01:00
79fa54b1bb Cache improvement 2025-02-16 19:03:58 +01:00
dbb4cae154 Only update value if is self 2025-02-16 18:21:53 +01:00
9a8220e4e0 Teleport walk fix 2025-02-16 18:16:35 +01:00
bc0db8b32b Receive new location as array instead of object 2025-02-16 17:29:21 +01:00
ad611ef593 Send new location as array instead of object 2025-02-16 17:19:19 +01:00
d819a84a37 npm update 2025-02-16 17:15:28 +01:00
15dc331a43 Improved movement logic 2025-02-16 17:14:24 +01:00
920baaebde Updated interval value 2025-02-16 01:55:04 +01:00
b569888682 Set selectedPlacedObject null when exiting map editor 2025-02-15 20:46:00 +01:00
94eab073e6 Max 2. pivot points 2025-02-15 17:57:30 +01:00
d843b954ab TS 2025-02-15 17:42:01 +01:00
337446497b Simple 2025-02-15 16:51:58 +01:00
d8805dd775 Added pivot point logic 2025-02-15 16:40:17 +01:00
4c040c21d6 npm update 2025-02-15 15:37:05 +01:00
d0af83ec60 N/A 2025-02-14 23:15:35 +01:00
2de34d2034 Package updates 2025-02-14 22:56:33 +01:00
132121c082 ToggleGmPanel > set false 2025-02-14 16:22:21 +01:00
201f628bfa Saving teleports works again 2025-02-14 03:16:22 +01:00
af99d66595 Add if check to quick login 2025-02-14 03:06:49 +01:00
56f30093f6 Teleport fix WIP 2025-02-14 03:04:42 +01:00
8f26a40a0e 11 for fast login 2025-02-14 03:03:57 +01:00
110fd4e608 TS improvements 2025-02-14 02:49:14 +01:00
c1edf31ca0 TS fix 2025-02-14 02:44:14 +01:00
90c0ed3141 Open teleport modal fix 2025-02-14 02:42:01 +01:00
bcf0d2832d Feedback Shilo
the placement of map objects sometimes placed in a tile that the mouse wasnt over. but i didnt try reproducing the issue.
opening map editor doesnt close the gm window (nor show the map editor). not obvious.
side panels like map objects doesnt have a close button. so i was only able to close it by switching to "move" tool.
2025-02-14 02:34:56 +01:00
47 changed files with 754 additions and 402 deletions

468
package-lock.json generated
View File

@ -10,16 +10,18 @@
"dependencies": { "dependencies": {
"@vueuse/core": "^10.5.0", "@vueuse/core": "^10.5.0",
"@vueuse/integrations": "^10.5.0", "@vueuse/integrations": "^10.5.0",
"axios": "^1.7.7", "axios": "^1.7.9",
"dexie": "^4.0.8", "dexie": "^4.0.11",
"phaser": "3.87.0", "phaser": "^3.88.2",
"pinia": "^2.1.6", "phaser3-rex-plugins": "^1.80.13",
"phavuer": "^0.16.5",
"pinia": "^2.3.1",
"sharp": "^0.33.5", "sharp": "^0.33.5",
"socket.io-client": "^4.8.0", "socket.io-client": "^4.8.1",
"universal-cookie": "^6.1.3", "universal-cookie": "^6.1.3",
"vite-plugin-image-optimizer": "^1.1.8", "vite-plugin-image-optimizer": "^1.1.8",
"vue": "^3.5.12", "vue": "^3.5.13",
"zod": "^3.22.2" "zod": "^3.24.2"
}, },
"devDependencies": { "devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@ianvs/prettier-plugin-sort-imports": "^4.4.0",
@ -32,8 +34,6 @@
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"jsdom": "^24.1.1", "jsdom": "^24.1.1",
"npm-run-all2": "^6.2.3", "npm-run-all2": "^6.2.3",
"phaser3-rex-plugins": "^1.80.8",
"phavuer": "^0.16.1",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"sass": "^1.79.4", "sass": "^1.79.4",
@ -88,14 +88,14 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz",
"integrity": "sha512-ef383X5++iZHWAXX0SXQR6ZyQhw/0KtTkrTz61WXRhFM6dhpHulO/RJz79L8S6ugZHJkOOkUrUdxgdF2YiPFnA==", "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.26.8", "@babel/parser": "^7.26.9",
"@babel/types": "^7.26.8", "@babel/types": "^7.26.9",
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25", "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
@ -123,12 +123,12 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
"integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==", "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.8" "@babel/types": "^7.26.9"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@ -138,10 +138,9 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.26.7", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
"integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
@ -151,32 +150,32 @@
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==", "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.8", "@babel/parser": "^7.26.9",
"@babel/types": "^7.26.8" "@babel/types": "^7.26.9"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz",
"integrity": "sha512-nic9tRkjYH0oB2dzr/JoGIm+4Q6SuYeLEiIiZDwBscRMYFJ+tMAz98fuel9ZnbXViA2I0HVSSRRK8DW5fjXStA==", "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.26.2", "@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.8", "@babel/generator": "^7.26.9",
"@babel/parser": "^7.26.8", "@babel/parser": "^7.26.9",
"@babel/template": "^7.26.8", "@babel/template": "^7.26.9",
"@babel/types": "^7.26.8", "@babel/types": "^7.26.9",
"debug": "^4.3.1", "debug": "^4.3.1",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@ -185,9 +184,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.8", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
"integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==", "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.25.9",
@ -1497,9 +1496,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz",
"integrity": "sha512-+GcCXtOQoWuC7hhX1P00LqjjIiS/iOouHXhMdiDSnq/1DGTox4SpUvO52Xm+div6+106r+TcvOeo/cxvyEyTgg==", "integrity": "sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -1510,9 +1509,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.7.tgz",
"integrity": "sha512-E8+2qCIjciYUnCa1AiVF1BkRgqIGW9KzJeesQqVfyRITGQN+dFuoivO0hnro1DjT74wXLRZ7QF8MIbz+luGaJA==", "integrity": "sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1523,9 +1522,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.7.tgz",
"integrity": "sha512-z9Ib+OzqN3DZEjX7PDQMHEhtF+t6Mi2z/ueChQPLS/qUMKY7Ybn5A2ggFoKRNRh1q1T03YTQfBTQCJZiepESAg==", "integrity": "sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1536,9 +1535,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.7.tgz",
"integrity": "sha512-PShKVY4u0FDAR7jskyFIYVyHEPCPnIQY8s5OcXkdU8mz3Y7eXDJPdyM/ZWjkYdR2m0izD9HHWA8sGcXn+Qrsyg==", "integrity": "sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1549,9 +1548,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.7.tgz",
"integrity": "sha512-YSwyOqlDAdKqs0iKuqvRHLN4SrD2TiswfoLfvYXseKbL47ht1grQpq46MSiQAx6rQEN8o8URtpXARCpqabqxGQ==", "integrity": "sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1562,9 +1561,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.7.tgz",
"integrity": "sha512-HEP4CgPAY1RxXwwL5sPFv6BBM3tVeLnshF03HMhJYCNc6kvSqBgTMmsEjb72RkZBAWIqiPUyF1JpEBv5XT9wKQ==", "integrity": "sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1575,9 +1574,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.7.tgz",
"integrity": "sha512-88fSzjC5xeH9S2Vg3rPgXJULkHcLYMkh8faix8DX4h4TIAL65ekwuQMA/g2CXq8W+NJC43V6fUpYZNjaX3+IIg==", "integrity": "sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -1588,9 +1587,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.7.tgz",
"integrity": "sha512-wM4ztnutBqYFyvNeR7Av+reWI/enK9tDOTKNF+6Kk2Q96k9bwhDDOlnCUNRPvromlVXo04riSliMBs/Z7RteEg==", "integrity": "sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -1601,9 +1600,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.7.tgz",
"integrity": "sha512-9RyprECbRa9zEjXLtvvshhw4CMrRa3K+0wcp3KME0zmBe1ILmvcVHnypZ/aIDXpRyfhSYSuN4EPdCCj5Du8FIA==", "integrity": "sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1614,9 +1613,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.7.tgz",
"integrity": "sha512-qTmklhCTyaJSB05S+iSovfo++EwnIEZxHkzv5dep4qoszUMX5Ca4WM4zAVUMbfdviLgCSQOu5oU8YoGk1s6M9Q==", "integrity": "sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1627,9 +1626,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.7.tgz",
"integrity": "sha512-4Qmkaps9yqmpjY5pvpkfOerYgKNUGzQpFxV6rnS7c/JfYbDSU0y6WpbbredB5cCpLFGJEqYX40WUmxMkwhWCjw==", "integrity": "sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -1640,9 +1639,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.7.tgz",
"integrity": "sha512-Zsrtux3PuaxuBTX/zHdLaFmcofWGzaWW1scwLU3ZbW/X+hSsFbz9wDIp6XvnT7pzYRl9MezWqEqKy7ssmDEnuQ==", "integrity": "sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -1653,9 +1652,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.7.tgz",
"integrity": "sha512-aK+Zp+CRM55iPrlyKiU3/zyhgzWBxLVrw2mwiQSYJRobCURb781+XstzvA8Gkjg/hbdQFuDw44aUOxVQFycrAg==", "integrity": "sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -1666,9 +1665,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.7.tgz",
"integrity": "sha512-WoKLVrY9ogmaYPXwTH326+ErlCIgMmsoRSx6bO+l68YgJnlOXhygDYSZe/qbUJCSiCiZAQ+tKm88NcWuUXqOzw==", "integrity": "sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -1679,9 +1678,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.7.tgz",
"integrity": "sha512-Sht4aFvmA4ToHd2vFzwMFaQCiYm2lDFho5rPcvPBT5pCdC+GwHG6CMch4GQfmWTQ1SwRKS0dhDYb54khSrjDWw==", "integrity": "sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1692,9 +1691,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.7.tgz",
"integrity": "sha512-zmmpOQh8vXc2QITsnCiODCDGXFC8LMi64+/oPpPx5qz3pqv0s6x46ps4xoycfUiVZps5PFn1gksZzo4RGTKT+A==", "integrity": "sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1705,9 +1704,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.7.tgz",
"integrity": "sha512-3/q1qUsO/tLqGBaD4uXsB6coVGB3usxw3qyeVb59aArCgedSF66MPdgRStUd7vbZOsko/CgVaY5fo2vkvPLWiA==", "integrity": "sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1718,9 +1717,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.7.tgz",
"integrity": "sha512-oLHxuyywc6efdKVTxvc0135zPrRdtYVjtVD5GUm55I3ODxhU/PwkQFD97z16Xzxa1Fz0AEe4W/2hzRtd+IfpOA==", "integrity": "sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -1731,9 +1730,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.6.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.7.tgz",
"integrity": "sha512-0PVwmgzZ8+TZ9oGBmdZoQVXflbvuwzN/HRclujpl4N/q3i+y0lqLw8n1bXA8ru3sApDjlmONaNAuYr38y1Kr9w==", "integrity": "sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1781,9 +1780,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.17.18", "version": "20.17.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.18.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz",
"integrity": "sha512-9kS0opXVV3dJ+C7HPhXfDlOdMu4cjJSZhlSxlDK39IxVRxBbuiYjCkLYSO9d5UYqTd4DApxRK9T1xJiTAkfA0w==", "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2328,7 +2327,6 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0" "license": "Python-2.0"
}, },
"node_modules/assertion-error": { "node_modules/assertion-error": {
@ -2482,6 +2480,19 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/camelcase-css": { "node_modules/camelcase-css": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
@ -2514,9 +2525,9 @@
"license": "CC-BY-4.0" "license": "CC-BY-4.0"
}, },
"node_modules/chai": { "node_modules/chai": {
"version": "5.1.2", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
"integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2683,7 +2694,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
"integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"node-fetch": "^2.6.12" "node-fetch": "^2.6.12"
@ -2748,7 +2758,6 @@
"version": "0.8.5", "version": "0.8.5",
"resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
"integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"graphlib": "^2.1.8", "graphlib": "^2.1.8",
@ -2853,6 +2862,20 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/eastasianwidth": { "node_modules/eastasianwidth": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@ -2880,9 +2903,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.98", "version": "1.5.101",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.98.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.101.tgz",
"integrity": "sha512-bI/LbtRBxU2GzK7KK5xxFd2y9Lf9XguHooPYbcXWy6wUoT8NMnffsvRhPmSeUHLSDKAEtKuTaEtK4Ms15zkIEA==", "integrity": "sha512-L0ISiQrP/56Acgu4/i/kfPwWSgrzYZUnQrC0+QPFuhqlLP1Ir7qzPPDVS9BcKIyWTRU8+o6CC8dKw38tSWhYIA==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -2965,6 +2988,24 @@
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
}, },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-module-lexer": { "node_modules/es-module-lexer": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
@ -2972,6 +3013,33 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
@ -3040,7 +3108,6 @@
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.8.x" "node": ">=0.8.x"
@ -3147,13 +3214,14 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.1", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"mime-types": "^2.1.12" "mime-types": "^2.1.12"
}, },
"engines": { "engines": {
@ -3217,12 +3285,48 @@
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/get-intrinsic": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"function-bind": "^1.1.2",
"get-proto": "^1.0.0",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/glob": { "node_modules/glob": {
"version": "10.4.5", "version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@ -3283,6 +3387,18 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@ -3294,7 +3410,6 @@
"version": "2.1.8", "version": "2.1.8",
"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
"integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"lodash": "^4.17.15" "lodash": "^4.17.15"
@ -3304,7 +3419,6 @@
"version": "0.25.4", "version": "0.25.4",
"resolved": "https://registry.npmjs.org/graphology/-/graphology-0.25.4.tgz", "resolved": "https://registry.npmjs.org/graphology/-/graphology-0.25.4.tgz",
"integrity": "sha512-33g0Ol9nkWdD6ulw687viS8YJQBxqG5LWII6FI6nul0pq6iM2t5EKquOTFDbyTblRB3O9I+7KX4xI8u5ffekAQ==", "integrity": "sha512-33g0Ol9nkWdD6ulw687viS8YJQBxqG5LWII6FI6nul0pq6iM2t5EKquOTFDbyTblRB3O9I+7KX4xI8u5ffekAQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"events": "^3.3.0", "events": "^3.3.0",
@ -3318,7 +3432,6 @@
"version": "0.24.8", "version": "0.24.8",
"resolved": "https://registry.npmjs.org/graphology-types/-/graphology-types-0.24.8.tgz", "resolved": "https://registry.npmjs.org/graphology-types/-/graphology-types-0.24.8.tgz",
"integrity": "sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q==", "integrity": "sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q==",
"dev": true,
"license": "MIT", "license": "MIT",
"peer": true "peer": true
}, },
@ -3332,11 +3445,37 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
@ -3400,7 +3539,6 @@
"version": "22.5.1", "version": "22.5.1",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz", "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz",
"integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==", "integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==",
"dev": true,
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -3424,7 +3562,6 @@
"version": "2.7.3", "version": "2.7.3",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.7.3.tgz", "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.7.3.tgz",
"integrity": "sha512-FgZxrXdRA5u44xfYsJlEBL4/KH3f2IluBpgV/7riW0YW2VEyM8FzVt2XHAOi6id0Ppj7vZvCZVpp5LrGXnc8Ig==", "integrity": "sha512-FgZxrXdRA5u44xfYsJlEBL4/KH3f2IluBpgV/7riW0YW2VEyM8FzVt2XHAOi6id0Ppj7vZvCZVpp5LrGXnc8Ig==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cross-fetch": "4.0.0" "cross-fetch": "4.0.0"
@ -3618,7 +3755,6 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1" "argparse": "^2.0.1"
@ -3738,7 +3874,6 @@
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/loupe": { "node_modules/loupe": {
@ -3764,6 +3899,15 @@
"@jridgewell/sourcemap-codec": "^1.5.0" "@jridgewell/sourcemap-codec": "^1.5.0"
} }
}, },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/memorystream": { "node_modules/memorystream": {
"version": "0.3.1", "version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
@ -3861,7 +4005,6 @@
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
"integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
"mustache": "bin/mustache" "mustache": "bin/mustache"
@ -3908,7 +4051,6 @@
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"whatwg-url": "^5.0.0" "whatwg-url": "^5.0.0"
@ -3929,21 +4071,18 @@
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/node-fetch/node_modules/webidl-conversions": { "node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"dev": true,
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/node-fetch/node_modules/whatwg-url": { "node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tr46": "~0.0.3", "tr46": "~0.0.3",
@ -4077,7 +4216,6 @@
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz",
"integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/package-json-from-dist": { "node_modules/package-json-from-dist": {
@ -4091,7 +4229,6 @@
"version": "5.5.2", "version": "5.5.2",
"resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.2.tgz", "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.2.tgz",
"integrity": "sha512-PZXg8UuAc4PcVwLosEEDYjPyfWnTEhOrUfdv+3Bx+NuAb+5NhDmXzg5fHWmdCh1mP5p7JAZfFr3IMQfcntNAdA==", "integrity": "sha512-PZXg8UuAc4PcVwLosEEDYjPyfWnTEhOrUfdv+3Bx+NuAb+5NhDmXzg5fHWmdCh1mP5p7JAZfFr3IMQfcntNAdA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/parse5": { "node_modules/parse5": {
@ -4165,9 +4302,9 @@
} }
}, },
"node_modules/phaser": { "node_modules/phaser": {
"version": "3.87.0", "version": "3.88.2",
"resolved": "https://registry.npmjs.org/phaser/-/phaser-3.87.0.tgz", "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.88.2.tgz",
"integrity": "sha512-AyI1b3T5fp05gzf6WUmu2FNqaZL+Y7w88yBRLf7YZXF9bncUSHpnDrupnTGoPqy/RKHRLBcay7zWeqQ2wiMWcw==", "integrity": "sha512-UBgd2sAFuRJbF2xKaQ5jpMWB8oETncChLnymLGHcrnT53vaqiGrQWbUKUDBawKLm24sghjKo4Bf+/xfv8espZQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"eventemitter3": "^5.0.1" "eventemitter3": "^5.0.1"
@ -4177,7 +4314,6 @@
"version": "1.80.13", "version": "1.80.13",
"resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.13.tgz", "resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.13.tgz",
"integrity": "sha512-d2P3c+0r7h/GXtOZIjB6DLjBQ2rSEeZ+AOG1D6jgGGn/Txb+PiDmFMhBF3qJ6YoPlVarSE8lw6V8Jy7K7xPnLg==", "integrity": "sha512-d2P3c+0r7h/GXtOZIjB6DLjBQ2rSEeZ+AOG1D6jgGGn/Txb+PiDmFMhBF3qJ6YoPlVarSE8lw6V8Jy7K7xPnLg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"dagre": "^0.8.5", "dagre": "^0.8.5",
@ -4195,14 +4331,12 @@
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/phavuer": { "node_modules/phavuer": {
"version": "0.16.5", "version": "0.16.5",
"resolved": "https://registry.npmjs.org/phavuer/-/phavuer-0.16.5.tgz", "resolved": "https://registry.npmjs.org/phavuer/-/phavuer-0.16.5.tgz",
"integrity": "sha512-NuUghQU1cZ8ePGJ9rt9czahtzPiJb7H5wALuP2ZDn8W4ELYuBk5Fz/nMzyxBFFme78Px7q38YTY3nW7xQMu1Ww==", "integrity": "sha512-NuUghQU1cZ8ePGJ9rt9czahtzPiJb7H5wALuP2ZDn8W4ELYuBk5Fz/nMzyxBFFme78Px7q38YTY3nW7xQMu1Ww==",
"dev": true,
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"phaser": "^3.70.0", "phaser": "^3.70.0",
@ -4433,9 +4567,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.5.0", "version": "3.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz",
"integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==", "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@ -4537,9 +4671,9 @@
} }
}, },
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "4.1.1", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -4554,7 +4688,6 @@
"version": "0.14.1", "version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/requires-port": { "node_modules/requires-port": {
@ -4597,9 +4730,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.34.6", "version": "4.34.7",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.6.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.7.tgz",
"integrity": "sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ==", "integrity": "sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/estree": "1.0.6" "@types/estree": "1.0.6"
@ -4612,25 +4745,25 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.34.6", "@rollup/rollup-android-arm-eabi": "4.34.7",
"@rollup/rollup-android-arm64": "4.34.6", "@rollup/rollup-android-arm64": "4.34.7",
"@rollup/rollup-darwin-arm64": "4.34.6", "@rollup/rollup-darwin-arm64": "4.34.7",
"@rollup/rollup-darwin-x64": "4.34.6", "@rollup/rollup-darwin-x64": "4.34.7",
"@rollup/rollup-freebsd-arm64": "4.34.6", "@rollup/rollup-freebsd-arm64": "4.34.7",
"@rollup/rollup-freebsd-x64": "4.34.6", "@rollup/rollup-freebsd-x64": "4.34.7",
"@rollup/rollup-linux-arm-gnueabihf": "4.34.6", "@rollup/rollup-linux-arm-gnueabihf": "4.34.7",
"@rollup/rollup-linux-arm-musleabihf": "4.34.6", "@rollup/rollup-linux-arm-musleabihf": "4.34.7",
"@rollup/rollup-linux-arm64-gnu": "4.34.6", "@rollup/rollup-linux-arm64-gnu": "4.34.7",
"@rollup/rollup-linux-arm64-musl": "4.34.6", "@rollup/rollup-linux-arm64-musl": "4.34.7",
"@rollup/rollup-linux-loongarch64-gnu": "4.34.6", "@rollup/rollup-linux-loongarch64-gnu": "4.34.7",
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.6", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.7",
"@rollup/rollup-linux-riscv64-gnu": "4.34.6", "@rollup/rollup-linux-riscv64-gnu": "4.34.7",
"@rollup/rollup-linux-s390x-gnu": "4.34.6", "@rollup/rollup-linux-s390x-gnu": "4.34.7",
"@rollup/rollup-linux-x64-gnu": "4.34.6", "@rollup/rollup-linux-x64-gnu": "4.34.7",
"@rollup/rollup-linux-x64-musl": "4.34.6", "@rollup/rollup-linux-x64-musl": "4.34.7",
"@rollup/rollup-win32-arm64-msvc": "4.34.6", "@rollup/rollup-win32-arm64-msvc": "4.34.7",
"@rollup/rollup-win32-ia32-msvc": "4.34.6", "@rollup/rollup-win32-ia32-msvc": "4.34.7",
"@rollup/rollup-win32-x64-msvc": "4.34.6", "@rollup/rollup-win32-x64-msvc": "4.34.7",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@ -4673,9 +4806,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.84.0", "version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.84.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.0.tgz",
"integrity": "sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg==", "integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -5589,9 +5722,9 @@
} }
}, },
"node_modules/vue-component-type-helpers": { "node_modules/vue-component-type-helpers": {
"version": "2.2.0", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.0.tgz", "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.2.tgz",
"integrity": "sha512-cYrAnv2me7bPDcg9kIcGwjJiSB6Qyi08+jLDo9yuvoFQjzHiPTzML7RnkJB1+3P6KMsX/KbCD4QE3Tv/knEllw==", "integrity": "sha512-6lLY+n2xz2kCYshl59mL6gy8OUUTmkscmDFMO8i7Lj+QKwgnIFUZmM1i/iTYObtrczZVdw7UakPqDTGwVSGaRg==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@ -5667,7 +5800,6 @@
"version": "1.6.28", "version": "1.6.28",
"resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz", "resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz",
"integrity": "sha512-Egb0oFEga6f+nSgasH3E0M405Pzn6y3/9tOVanv/DLfa1YBIgcv90L18YyWnvXkRbIM17v5Kv6IT2N6g1x5tvQ==", "integrity": "sha512-Egb0oFEga6f+nSgasH3E0M405Pzn6y3/9tOVanv/DLfa1YBIgcv90L18YyWnvXkRbIM17v5Kv6IT2N6g1x5tvQ==",
"dev": true,
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/webidl-conversions": { "node_modules/webidl-conversions": {

View File

@ -16,16 +16,18 @@
"dependencies": { "dependencies": {
"@vueuse/core": "^10.5.0", "@vueuse/core": "^10.5.0",
"@vueuse/integrations": "^10.5.0", "@vueuse/integrations": "^10.5.0",
"axios": "^1.7.7", "axios": "^1.7.9",
"dexie": "^4.0.8", "dexie": "^4.0.11",
"phaser": "3.87.0", "phaser": "^3.88.2",
"pinia": "^2.1.6", "phavuer": "^0.16.5",
"phaser3-rex-plugins": "^1.80.13",
"pinia": "^2.3.1",
"sharp": "^0.33.5", "sharp": "^0.33.5",
"socket.io-client": "^4.8.0", "socket.io-client": "^4.8.1",
"universal-cookie": "^6.1.3", "universal-cookie": "^6.1.3",
"vite-plugin-image-optimizer": "^1.1.8", "vite-plugin-image-optimizer": "^1.1.8",
"vue": "^3.5.12", "vue": "^3.5.13",
"zod": "^3.22.2" "zod": "^3.24.2"
}, },
"devDependencies": { "devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@ianvs/prettier-plugin-sort-imports": "^4.4.0",
@ -38,8 +40,6 @@
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"jsdom": "^24.1.1", "jsdom": "^24.1.1",
"npm-run-all2": "^6.2.3", "npm-run-all2": "^6.2.3",
"phaser3-rex-plugins": "^1.80.8",
"phavuer": "^0.16.1",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"sass": "^1.79.4", "sass": "^1.79.4",

View File

@ -16,6 +16,7 @@ import Debug from '@/components/utilities/Debug.vue'
import Notifications from '@/components/utilities/Notifications.vue' import Notifications from '@/components/utilities/Notifications.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useSoundComposable } from '@/composables/useSoundComposable' import { useSoundComposable } from '@/composables/useSoundComposable'
import { socketManager } from '@/managers/SocketManager'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { computed, watch } from 'vue' import { computed, watch } from 'vue'
@ -26,8 +27,8 @@ const { playSound } = useSoundComposable()
const currentScreen = computed(() => { const currentScreen = computed(() => {
if (!gameStore.game.isLoaded) return Loading if (!gameStore.game.isLoaded) return Loading
if (!gameStore.connection) return Login if (!socketManager.connection) return Login
if (!gameStore.token) return Login if (!socketManager.token) return Login
if (!gameStore.character) return Characters if (!gameStore.character) return Characters
if (mapEditor.active.value) return MapEditor if (mapEditor.active.value) return MapEditor
return Game return Game

View File

@ -5,6 +5,8 @@ export enum Direction {
} }
export enum SocketEvent { export enum SocketEvent {
CONNECT_ERROR = 'connect_error',
RECONNECT_FAILED = 'reconnect_failed',
CLOSE = '52', CLOSE = '52',
DATA = '51', DATA = '51',
CHARACTER_CONNECT = '50', CHARACTER_CONNECT = '50',
@ -41,7 +43,7 @@ export enum SocketEvent {
GM_MAP_REQUEST = '19', GM_MAP_REQUEST = '19',
GM_MAP_UPDATE = '18', GM_MAP_UPDATE = '18',
MAP_CHARACTER_MOVEERROR = '17', MAP_CHARACTER_MOVEERROR = '17',
DISCONNECT = '16', DISCONNECT = 'disconnect',
USER_DISCONNECT = '15', USER_DISCONNECT = '15',
LOGIN = '14', LOGIN = '14',
LOGGED_IN = '13', LOGGED_IN = '13',
@ -49,7 +51,7 @@ export enum SocketEvent {
DATE = '11', DATE = '11',
FAILED = '10', FAILED = '10',
COMPLETED = '9', COMPLETED = '9',
CONNECTION = '8', CONNECTION = 'connection',
WEATHER = '7', WEATHER = '7',
CHARACTER_DISCONNECT = '6', CHARACTER_DISCONNECT = '6',
MAP_CHARACTER_ATTACK = '5', MAP_CHARACTER_ATTACK = '5',

View File

@ -36,7 +36,8 @@ export type Tile = {
export type MapObject = { export type MapObject = {
id: string id: string
name: string name: string
tags: any | null tags: string[]
pivotPoints: { x: number; y: number }[]
originX: number originX: number
originY: number originY: number
frameRate: number frameRate: number
@ -100,7 +101,7 @@ export enum MapEventTileType {
export type MapEventTile = { export type MapEventTile = {
id: string id: string
mapid: string map: string
type: MapEventTileType type: MapEventTileType
positionX: number positionX: number
positionY: number positionY: number

View File

@ -21,7 +21,17 @@ export async function downloadCache<T extends { id: string; updatedAt: Date }>(e
} }
const items = response.data ?? [] const items = response.data ?? []
const serverItemIds = new Set(items.map((item) => item.id))
// Remove items that don't exist on server
const existingItems = await storage.getAll()
for (const existingItem of existingItems) {
if (!serverItemIds.has(existingItem.id)) {
await storage.delete(existingItem.id)
}
}
// Update or add new items
for (const item of items) { for (const item of items) {
let overwrite = false let overwrite = false
const existingItem = await storage.getById(item.id) const existingItem = await storage.getById(item.id)

View File

@ -22,6 +22,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import { socketManager } from '@/managers/SocketManager'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { onClickOutside, useFocus } from '@vueuse/core' import { onClickOutside, useFocus } from '@vueuse/core'
@ -30,7 +31,6 @@ import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
const scene = useScene() const scene = useScene()
const gameStore = useGameStore() const gameStore = useGameStore()
const mapStore = useMapStore()
const message = ref('') const message = ref('')
const chats = ref<{ character: string; message: string }[]>([]) const chats = ref<{ character: string; message: string }[]>([])
@ -55,7 +55,7 @@ function unfocusChat(event: Event, targetElement: HTMLElement) {
const sendMessage = () => { const sendMessage = () => {
if (!message.value.trim()) return if (!message.value.trim()) return
gameStore.connection?.emit(SocketEvent.CHAT_MESSAGE, { message: message.value }, (response: boolean) => {}) socketManager.emit(SocketEvent.CHAT_MESSAGE, { message: message.value }, (response: boolean) => {})
message.value = '' message.value = ''
} }
@ -79,7 +79,7 @@ const scrollToBottom = () => {
}) })
} }
gameStore.connection?.on(SocketEvent.CHAT_MESSAGE, (data: { character: string; message: string }) => { socketManager.on(SocketEvent.CHAT_MESSAGE, (data: { character: string; message: string }) => {
if (!data.character || !data.message) return if (!data.character || !data.message) return
chats.value.push({ character: data.character, message: data.message }) chats.value.push({ character: data.character, message: data.message })
@ -153,7 +153,7 @@ onMounted(() => {
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
gameStore.connection?.off(SocketEvent.CHAT_MESSAGE) socketManager.off(SocketEvent.CHAT_MESSAGE)
removeEventListener('keydown', focusChat) removeEventListener('keydown', focusChat)
}) })
</script> </script>

View File

@ -8,6 +8,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import { socketManager } from '@/managers/SocketManager'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useDateFormat } from '@vueuse/core' import { useDateFormat } from '@vueuse/core'
import { onUnmounted } from 'vue' import { onUnmounted } from 'vue'
@ -15,6 +16,6 @@ import { onUnmounted } from 'vue'
const gameStore = useGameStore() const gameStore = useGameStore()
onUnmounted(() => { onUnmounted(() => {
gameStore.connection?.off(SocketEvent.DATE) socketManager.off(SocketEvent.DATE)
}) })
</script> </script>

View File

@ -6,6 +6,7 @@
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { MapCharacter, UUID } from '@/application/types' import type { MapCharacter, UUID } from '@/application/types'
import Character from '@/components/game/character/Character.vue' import Character from '@/components/game/character/Character.vue'
import { socketManager } from '@/managers/SocketManager'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore' import { useMapStore } from '@/stores/mapStore'
import { onUnmounted } from 'vue' import { onUnmounted } from 'vue'
@ -17,32 +18,32 @@ const props = defineProps<{
tileMap: Phaser.Tilemaps.Tilemap tileMap: Phaser.Tilemaps.Tilemap
}>() }>()
gameStore.connection?.on(SocketEvent.MAP_CHARACTER_JOIN, (data: MapCharacter) => { socketManager.on(SocketEvent.MAP_CHARACTER_JOIN, (data: MapCharacter) => {
mapStore.addCharacter(data) mapStore.addCharacter(data)
}) })
gameStore.connection?.on(SocketEvent.MAP_CHARACTER_LEAVE, (characterId: UUID) => { socketManager.on(SocketEvent.MAP_CHARACTER_LEAVE, (characterId: UUID) => {
mapStore.removeCharacter(characterId) mapStore.removeCharacter(characterId)
}) })
gameStore.connection?.on(SocketEvent.MAP_CHARACTER_MOVE, (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => { socketManager.on(SocketEvent.MAP_CHARACTER_MOVE, ([characterId, posX, posY, rot, isMoving]: [UUID, number, number, number, boolean]) => {
mapStore.updateCharacterPosition(data) mapStore.updateCharacterPosition([characterId, posX, posY, rot, isMoving])
// @TODO: Replace with universal class, composable or store
if (data.characterId === gameStore.character?.id) { if (characterId === gameStore.character?.id) {
gameStore.character!.positionX = data.positionX gameStore.character!.positionX = posX
gameStore.character!.positionY = data.positionY gameStore.character!.positionY = posY
gameStore.character!.rotation = data.rotation gameStore.character!.rotation = rot
} }
}) })
gameStore.connection?.on(SocketEvent.MAP_CHARACTER_ATTACK, (characterId: UUID) => { socketManager.on(SocketEvent.MAP_CHARACTER_ATTACK, (characterId: UUID) => {
mapStore.updateCharacterProperty(characterId, 'isAttacking', true) mapStore.updateCharacterProperty(characterId, 'isAttacking', true)
}) })
onUnmounted(() => { onUnmounted(() => {
gameStore.connection?.off(SocketEvent.MAP_CHARACTER_ATTACK) socketManager.off(SocketEvent.MAP_CHARACTER_ATTACK)
gameStore.connection?.off(SocketEvent.MAP_CHARACTER_MOVE) socketManager.off(SocketEvent.MAP_CHARACTER_MOVE)
gameStore.connection?.off(SocketEvent.MAP_CHARACTER_JOIN) socketManager.off(SocketEvent.MAP_CHARACTER_JOIN)
gameStore.connection?.off(SocketEvent.MAP_CHARACTER_LEAVE) socketManager.off(SocketEvent.MAP_CHARACTER_LEAVE)
}) })
</script> </script>

View File

@ -11,6 +11,7 @@ import { unduplicateArray } from '@/application/utilities'
import Characters from '@/components/game/map/Characters.vue' import Characters from '@/components/game/map/Characters.vue'
import MapTiles from '@/components/game/map/MapTiles.vue' import MapTiles from '@/components/game/map/MapTiles.vue'
import PlacedMapObjects from '@/components/game/map/PlacedMapObjects.vue' import PlacedMapObjects from '@/components/game/map/PlacedMapObjects.vue'
import { socketManager } from '@/managers/SocketManager'
import { createTileLayer, createTileMap, loadTileTexturesFromMapTileArray } from '@/services/mapService' import { createTileLayer, createTileMap, loadTileTexturesFromMapTileArray } from '@/services/mapService'
import { MapStorage } from '@/storage/storages' import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
@ -29,7 +30,7 @@ const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const tileMapLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>() const tileMapLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
// Event listeners // Event listeners
gameStore.connection?.on(SocketEvent.MAP_CHARACTER_TELEPORT, (data: mapLoadData) => { socketManager.on(SocketEvent.MAP_CHARACTER_TELEPORT, (data: mapLoadData) => {
mapStore.setMapId(data.mapId) mapStore.setMapId(data.mapId)
mapStore.setCharacters(data.characters) mapStore.setCharacters(data.characters)
}) })
@ -65,6 +66,6 @@ onUnmounted(() => {
tileMap.value.destroy() tileMap.value.destroy()
} }
gameStore.connection?.off(SocketEvent.MAP_CHARACTER_TELEPORT) socketManager.off(SocketEvent.MAP_CHARACTER_TELEPORT)
}) })
</script> </script>

View File

@ -61,7 +61,7 @@ function calculateObjectPlacement(mapObj: PlacedMapObject): { x: number; y: numb
const imageProps = computed(() => ({ const imageProps = computed(() => ({
alpha: mapEditor.movingPlacedObject.value?.id == props.placedMapObject.id || mapEditor.selectedMapObject.value?.id == props.placedMapObject.id ? 0.5 : 1, alpha: mapEditor.movingPlacedObject.value?.id == props.placedMapObject.id || mapEditor.selectedMapObject.value?.id == props.placedMapObject.id ? 0.5 : 1,
tint: mapEditor.selectedPlacedObject.value?.id == props.placedMapObject.id ? 0x00ff00 : 0xffffff, tint: mapEditor.selectedPlacedObject.value?.id == props.placedMapObject.id ? 0x00ff00 : 0xffffff,
depth: calculateIsometricDepth(props.placedMapObject.positionX, props.placedMapObject.positionY, mapObject.value!.frameWidth, mapObject.value!.frameHeight, mapObject.value!.originX, mapObject.value!.originY), depth: calculateIsometricDepth(props.placedMapObject.positionX, props.placedMapObject.positionY),
...calculateObjectPlacement(props.placedMapObject), ...calculateObjectPlacement(props.placedMapObject),
flipX: props.placedMapObject.isRotated, flipX: props.placedMapObject.isRotated,
texture: mapObject.value!.id, texture: mapObject.value!.id,

View File

@ -36,6 +36,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { CharacterGender, CharacterHair, Sprite } from '@/application/types' import type { CharacterGender, CharacterHair, Sprite } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -66,7 +67,7 @@ if (selectedCharacterHair.value) {
function removeCharacterHair() { function removeCharacterHair() {
if (!selectedCharacterHair.value) return if (!selectedCharacterHair.value) return
gameStore.connection?.emit(SocketEvent.GM_CHARACTERHAIR_REMOVE, { id: selectedCharacterHair.value.id }, (response: boolean) => { socketManager.emit(SocketEvent.GM_CHARACTERHAIR_REMOVE, { id: selectedCharacterHair.value.id }, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to remove character hair') console.error('Failed to remove character hair')
return return
@ -76,7 +77,7 @@ function removeCharacterHair() {
} }
function refreshCharacterHairList(unsetSelectedCharacterHair = true) { function refreshCharacterHairList(unsetSelectedCharacterHair = true) {
gameStore.connection?.emit(SocketEvent.GM_CHARACTERHAIR_LIST, {}, (response: CharacterHair[]) => { socketManager.emit(SocketEvent.GM_CHARACTERHAIR_LIST, {}, (response: CharacterHair[]) => {
assetManagerStore.setCharacterHairList(response) assetManagerStore.setCharacterHairList(response)
if (unsetSelectedCharacterHair) { if (unsetSelectedCharacterHair) {
@ -94,7 +95,7 @@ function saveCharacterHair() {
spriteId: characterSpriteId.value spriteId: characterSpriteId.value
} }
gameStore.connection?.emit(SocketEvent.GM_CHARACTERHAIR_UPDATE, characterHairData, (response: boolean) => { socketManager.emit(SocketEvent.GM_CHARACTERHAIR_UPDATE, characterHairData, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to save character type') console.error('Failed to save character type')
return return
@ -114,7 +115,7 @@ watch(selectedCharacterHair, (characterHair: CharacterHair | null) => {
onMounted(() => { onMounted(() => {
if (!selectedCharacterHair.value) return if (!selectedCharacterHair.value) return
gameStore.connection?.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => { socketManager.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
assetManagerStore.setSpriteList(response) assetManagerStore.setSpriteList(response)
}) })
}) })

View File

@ -34,6 +34,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { CharacterHair } from '@/application/types' import type { CharacterHair } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useVirtualList } from '@vueuse/core' import { useVirtualList } from '@vueuse/core'
@ -53,13 +54,13 @@ const handleSearch = () => {
} }
const createNewCharacterHair = () => { const createNewCharacterHair = () => {
gameStore.connection?.emit(SocketEvent.GM_CHARACTERHAIR_CREATE, {}, (response: boolean) => { socketManager.emit(SocketEvent.GM_CHARACTERHAIR_CREATE, {}, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to create new character type') console.error('Failed to create new character type')
return return
} }
gameStore.connection?.emit(SocketEvent.GM_CHARACTERHAIR_LIST, {}, (response: CharacterHair[]) => { socketManager.emit(SocketEvent.GM_CHARACTERHAIR_LIST, {}, (response: CharacterHair[]) => {
assetManagerStore.setCharacterHairList(response) assetManagerStore.setCharacterHairList(response)
}) })
}) })
@ -93,7 +94,7 @@ function toTop() {
} }
onMounted(() => { onMounted(() => {
gameStore.connection?.emit(SocketEvent.GM_CHARACTERHAIR_LIST, {}, (response: CharacterHair[]) => { socketManager.emit(SocketEvent.GM_CHARACTERHAIR_LIST, {}, (response: CharacterHair[]) => {
assetManagerStore.setCharacterHairList(response) assetManagerStore.setCharacterHairList(response)
}) })
}) })

View File

@ -42,6 +42,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { CharacterGender, CharacterRace, CharacterType, Sprite } from '@/application/types' import type { CharacterGender, CharacterRace, CharacterType, Sprite } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -75,7 +76,7 @@ if (selectedCharacterType.value) {
function removeCharacterType() { function removeCharacterType() {
if (!selectedCharacterType.value) return if (!selectedCharacterType.value) return
gameStore.connection?.emit(SocketEvent.GM_CHARACTERTYPE_REMOVE, { id: selectedCharacterType.value.id }, (response: boolean) => { socketManager.emit(SocketEvent.GM_CHARACTERTYPE_REMOVE, { id: selectedCharacterType.value.id }, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to remove character type') console.error('Failed to remove character type')
return return
@ -85,7 +86,7 @@ function removeCharacterType() {
} }
function refreshCharacterTypeList(unsetSelectedCharacterType = true) { function refreshCharacterTypeList(unsetSelectedCharacterType = true) {
gameStore.connection?.emit(SocketEvent.GM_CHARACTERTYPE_LIST, {}, (response: CharacterType[]) => { socketManager.emit(SocketEvent.GM_CHARACTERTYPE_LIST, {}, (response: CharacterType[]) => {
assetManagerStore.setCharacterTypeList(response) assetManagerStore.setCharacterTypeList(response)
if (unsetSelectedCharacterType) { if (unsetSelectedCharacterType) {
@ -104,7 +105,7 @@ function saveCharacterType() {
spriteId: characterSpriteId.value spriteId: characterSpriteId.value
} }
gameStore.connection?.emit(SocketEvent.GM_CHARACTERTYPE_UPDATE, characterTypeData, (response: boolean) => { socketManager.emit(SocketEvent.GM_CHARACTERTYPE_UPDATE, characterTypeData, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to save character type') console.error('Failed to save character type')
return return
@ -125,7 +126,7 @@ watch(selectedCharacterType, (characterType: CharacterType | null) => {
onMounted(() => { onMounted(() => {
if (!selectedCharacterType.value) return if (!selectedCharacterType.value) return
gameStore.connection?.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => { socketManager.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
assetManagerStore.setSpriteList(response) assetManagerStore.setSpriteList(response)
}) })
}) })

View File

@ -34,6 +34,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { CharacterType } from '@/application/types' import type { CharacterType } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useVirtualList } from '@vueuse/core' import { useVirtualList } from '@vueuse/core'
@ -53,13 +54,13 @@ const handleSearch = () => {
} }
const createNewCharacterType = () => { const createNewCharacterType = () => {
gameStore.connection?.emit(SocketEvent.GM_CHARACTERTYPE_CREATE, {}, (response: boolean) => { socketManager.emit(SocketEvent.GM_CHARACTERTYPE_CREATE, {}, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to create new character type') console.error('Failed to create new character type')
return return
} }
gameStore.connection?.emit(SocketEvent.GM_CHARACTERTYPE_LIST, {}, (response: CharacterType[]) => { socketManager.emit(SocketEvent.GM_CHARACTERTYPE_LIST, {}, (response: CharacterType[]) => {
assetManagerStore.setCharacterTypeList(response) assetManagerStore.setCharacterTypeList(response)
}) })
}) })
@ -93,7 +94,7 @@ function toTop() {
} }
onMounted(() => { onMounted(() => {
gameStore.connection?.emit(SocketEvent.GM_CHARACTERTYPE_LIST, {}, (response: CharacterType[]) => { socketManager.emit(SocketEvent.GM_CHARACTERTYPE_LIST, {}, (response: CharacterType[]) => {
assetManagerStore.setCharacterTypeList(response) assetManagerStore.setCharacterTypeList(response)
}) })
}) })

View File

@ -46,6 +46,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { Item, ItemRarity, ItemType, Sprite } from '@/application/types' import type { Item, ItemRarity, ItemType, Sprite } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -81,7 +82,7 @@ if (selectedItem.value) {
function removeItem() { function removeItem() {
if (!selectedItem.value) return if (!selectedItem.value) return
gameStore.connection?.emit(SocketEvent.GM_ITEM_REMOVE, { id: selectedItem.value.id }, (response: boolean) => { socketManager.emit(SocketEvent.GM_ITEM_REMOVE, { id: selectedItem.value.id }, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to remove item') console.error('Failed to remove item')
return return
@ -91,7 +92,7 @@ function removeItem() {
} }
function refreshItemList(unsetSelectedItem = true) { function refreshItemList(unsetSelectedItem = true) {
gameStore.connection?.emit(SocketEvent.GM_ITEM_LIST, {}, (response: Item[]) => { socketManager.emit(SocketEvent.GM_ITEM_LIST, {}, (response: Item[]) => {
assetManagerStore.setItemList(response) assetManagerStore.setItemList(response)
if (unsetSelectedItem) { if (unsetSelectedItem) {
@ -111,7 +112,7 @@ function saveItem() {
spriteId: itemSpriteId.value spriteId: itemSpriteId.value
} }
gameStore.connection?.emit(SocketEvent.GM_ITEM_UPDATE, itemData, (response: boolean) => { socketManager.emit(SocketEvent.GM_ITEM_UPDATE, itemData, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to save item') console.error('Failed to save item')
return return
@ -133,7 +134,7 @@ watch(selectedItem, (item: Item | null) => {
onMounted(() => { onMounted(() => {
if (!selectedItem.value) return if (!selectedItem.value) return
gameStore.connection?.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => { socketManager.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
assetManagerStore.setSpriteList(response) assetManagerStore.setSpriteList(response)
}) })
}) })

View File

@ -31,6 +31,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { Item } from '@/application/types' import type { Item } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useVirtualList } from '@vueuse/core' import { useVirtualList } from '@vueuse/core'
@ -49,13 +50,13 @@ const handleSearch = () => {
} }
const createNewItem = () => { const createNewItem = () => {
gameStore.connection?.emit(SocketEvent.GM_ITEM_CREATE, {}, (response: boolean) => { socketManager.emit(SocketEvent.GM_ITEM_CREATE, {}, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to create new item') console.error('Failed to create new item')
return return
} }
gameStore.connection?.emit(SocketEvent.GM_ITEM_LIST, {}, (response: Item[]) => { socketManager.emit(SocketEvent.GM_ITEM_LIST, {}, (response: Item[]) => {
assetManagerStore.setItemList(response) assetManagerStore.setItemList(response)
}) })
}) })
@ -89,7 +90,7 @@ function toTop() {
} }
onMounted(() => { onMounted(() => {
gameStore.connection?.emit(SocketEvent.GM_ITEM_LIST, {}, (response: Item[]) => { socketManager.emit(SocketEvent.GM_ITEM_LIST, {}, (response: Item[]) => {
assetManagerStore.setItemList(response) assetManagerStore.setItemList(response)
}) })
}) })

View File

@ -1,7 +1,20 @@
<template> <template>
<div class="h-full overflow-auto"> <div class="h-full overflow-auto">
<div class="relative p-2.5 flex flex-col items-center justify-center h-72 rounded-md default-border bg-gray"> <div class="relative p-2.5 flex flex-col items-center justify-center h-72 rounded-md default-border bg-gray">
<img class="max-h-56" :src="`${config.server_endpoint}/textures/map_objects/${selectedMapObject?.id}.png`" :alt="'Object ' + selectedMapObject?.id" /> <div class="relative">
<img class="max-h-56" :src="`${config.server_endpoint}/textures/map_objects/${selectedMapObject?.id}.png`" :alt="'Object ' + selectedMapObject?.id" @click="addPivotPoint" ref="imageRef" />
<svg class="absolute bottom-1 left-0 w-full h-full pointer-events-none">
<line v-for="(_, index) in mapObjectPivotPoints.slice(0, -1)" :key="index" :x1="mapObjectPivotPoints[index].x" :y1="mapObjectPivotPoints[index].y" :x2="mapObjectPivotPoints[index + 1].x" :y2="mapObjectPivotPoints[index + 1].y" stroke="white" stroke-width="2" />
</svg>
<div
v-for="(point, index) in mapObjectPivotPoints"
:key="index"
class="absolute w-2 h-2 bg-white rounded-full cursor-move -translate-x-1.5 -translate-y-1.5 ring-2 ring-black"
:style="{ left: point.x + 'px', top: point.y + 'px' }"
@mousedown="startDragging(index, $event)"
@contextmenu.prevent="removePivotPoint(index)"
/>
</div>
</div> </div>
<div class="mt-5 block"> <div class="mt-5 block">
<form class="flex gap-2.5 flex-wrap" @submit.prevent="saveObject"> <form class="flex gap-2.5 flex-wrap" @submit.prevent="saveObject">
@ -47,6 +60,7 @@ import config from '@/application/config'
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { MapObject } from '@/application/types' import type { MapObject } from '@/application/types'
import ChipsInput from '@/components/forms/ChipsInput.vue' import ChipsInput from '@/components/forms/ChipsInput.vue'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -58,11 +72,15 @@ const selectedMapObject = computed(() => assetManagerStore.selectedMapObject)
const mapObjectName = ref('') const mapObjectName = ref('')
const mapObjectTags = ref<string[]>([]) const mapObjectTags = ref<string[]>([])
const mapObjectPivotPoints = ref<Array<{ x: number; y: number }>>([])
const mapObjectOriginX = ref(0) const mapObjectOriginX = ref(0)
const mapObjectOriginY = ref(0) const mapObjectOriginY = ref(0)
const mapObjectFrameRate = ref(0) const mapObjectFrameRate = ref(0)
const mapObjectFrameWidth = ref(0) const mapObjectFrameWidth = ref(0)
const mapObjectFrameHeight = ref(0) const mapObjectFrameHeight = ref(0)
const imageRef = ref<HTMLImageElement | null>(null)
const isDragging = ref(false)
const draggedPointIndex = ref(-1)
if (!selectedMapObject.value) { if (!selectedMapObject.value) {
console.error('No map mapObject selected') console.error('No map mapObject selected')
@ -71,6 +89,7 @@ if (!selectedMapObject.value) {
if (selectedMapObject.value) { if (selectedMapObject.value) {
mapObjectName.value = selectedMapObject.value.name mapObjectName.value = selectedMapObject.value.name
mapObjectTags.value = selectedMapObject.value.tags mapObjectTags.value = selectedMapObject.value.tags
mapObjectPivotPoints.value = selectedMapObject.value.pivotPoints
mapObjectOriginX.value = selectedMapObject.value.originX mapObjectOriginX.value = selectedMapObject.value.originX
mapObjectOriginY.value = selectedMapObject.value.originY mapObjectOriginY.value = selectedMapObject.value.originY
mapObjectFrameRate.value = selectedMapObject.value.frameRate mapObjectFrameRate.value = selectedMapObject.value.frameRate
@ -79,7 +98,7 @@ if (selectedMapObject.value) {
} }
function removeObject() { function removeObject() {
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_REMOVE, { mapObject: selectedMapObject.value?.id }, (response: boolean) => { socketManager.emit(SocketEvent.GM_MAPOBJECT_REMOVE, { mapObject: selectedMapObject.value?.id }, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to remove mapObject') console.error('Failed to remove mapObject')
return return
@ -89,7 +108,7 @@ function removeObject() {
} }
function refreshObjectList(unsetSelectedMapObject = true) { function refreshObjectList(unsetSelectedMapObject = true) {
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => { socketManager.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
assetManagerStore.setMapObjectList(response) assetManagerStore.setMapObjectList(response)
if (unsetSelectedMapObject) { if (unsetSelectedMapObject) {
@ -104,12 +123,13 @@ function saveObject() {
return return
} }
gameStore.connection?.emit( socketManager.emit(
'gm:mapObject:update', SocketEvent.GM_MAPOBJECT_UPDATE,
{ {
id: selectedMapObject.value.id, id: selectedMapObject.value.id,
name: mapObjectName.value, name: mapObjectName.value,
tags: mapObjectTags.value, tags: mapObjectTags.value,
pivotPoints: mapObjectPivotPoints.value,
originX: mapObjectOriginX.value, originX: mapObjectOriginX.value,
originY: mapObjectOriginY.value, originY: mapObjectOriginY.value,
frameRate: mapObjectFrameRate.value, frameRate: mapObjectFrameRate.value,
@ -130,6 +150,7 @@ watch(selectedMapObject, (mapObject: MapObject | null) => {
if (!mapObject) return if (!mapObject) return
mapObjectName.value = mapObject.name mapObjectName.value = mapObject.name
mapObjectTags.value = mapObject.tags mapObjectTags.value = mapObject.tags
mapObjectPivotPoints.value = mapObject.pivotPoints
mapObjectOriginX.value = mapObject.originX mapObjectOriginX.value = mapObject.originX
mapObjectOriginY.value = mapObject.originY mapObjectOriginY.value = mapObject.originY
mapObjectFrameRate.value = mapObject.frameRate mapObjectFrameRate.value = mapObject.frameRate
@ -141,7 +162,51 @@ onMounted(() => {
if (!selectedMapObject.value) return if (!selectedMapObject.value) return
}) })
function addPivotPoint(event: MouseEvent) {
if (!imageRef.value) return
// Max 2
if (mapObjectPivotPoints.value.length >= 2) return
const rect = imageRef.value.getBoundingClientRect()
const x = event.clientX - rect.left
const y = event.clientY - rect.top
mapObjectPivotPoints.value.push({ x, y })
}
function startDragging(index: number, event: MouseEvent) {
isDragging.value = true
draggedPointIndex.value = index
const moveHandler = (e: MouseEvent) => {
if (!isDragging.value || !imageRef.value) return
const rect = imageRef.value.getBoundingClientRect()
mapObjectPivotPoints.value[draggedPointIndex.value] = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
}
}
const upHandler = () => {
isDragging.value = false
draggedPointIndex.value = -1
window.removeEventListener('mousemove', moveHandler)
window.removeEventListener('mouseup', upHandler)
}
window.addEventListener('mousemove', moveHandler)
window.addEventListener('mouseup', upHandler)
}
function removePivotPoint(index: number) {
mapObjectPivotPoints.value.splice(index, 1)
}
onBeforeUnmount(() => { onBeforeUnmount(() => {
assetManagerStore.setSelectedMapObject(null) assetManagerStore.setSelectedMapObject(null)
}) })
</script> </script>
<style scoped>
.pointer-events-none {
pointer-events: none;
}
</style>

View File

@ -31,6 +31,7 @@
import config from '@/application/config' import config from '@/application/config'
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { MapObject } from '@/application/types' import type { MapObject } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useVirtualList } from '@vueuse/core' import { useVirtualList } from '@vueuse/core'
@ -48,13 +49,13 @@ const elementToScroll = ref()
const handleFileUpload = (e: Event) => { const handleFileUpload = (e: Event) => {
const files = (e.target as HTMLInputElement).files const files = (e.target as HTMLInputElement).files
if (!files) return if (!files) return
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_UPLOAD, files, (response: boolean) => { socketManager.emit(SocketEvent.GM_MAPOBJECT_UPLOAD, files, (response: boolean) => {
if (!response) { if (!response) {
if (config.environment === 'development') console.error('Failed to upload map object') if (config.environment === 'development') console.error('Failed to upload map object')
return return
} }
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => { socketManager.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
assetManagerStore.setMapObjectList(response) assetManagerStore.setMapObjectList(response)
}) })
}) })
@ -93,7 +94,7 @@ function toTop() {
} }
onMounted(() => { onMounted(() => {
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => { socketManager.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
assetManagerStore.setMapObjectList(response) assetManagerStore.setMapObjectList(response)
}) })
}) })

View File

@ -74,6 +74,7 @@ import { uuidv4 } from '@/application/utilities'
import SpriteActionsInput from '@/components/gameMaster/assetManager/partials/sprite/partials/SpriteImagesInput.vue' import SpriteActionsInput from '@/components/gameMaster/assetManager/partials/sprite/partials/SpriteImagesInput.vue'
import SpritePreview from '@/components/gameMaster/assetManager/partials/sprite/partials/SpritePreview.vue' import SpritePreview from '@/components/gameMaster/assetManager/partials/sprite/partials/SpritePreview.vue'
import Accordion from '@/components/utilities/Accordion.vue' import Accordion from '@/components/utilities/Accordion.vue'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -98,7 +99,7 @@ if (selectedSprite.value) {
} }
function deleteSprite() { function deleteSprite() {
gameStore.connection?.emit(SocketEvent.GM_SPRITE_DELETE, { id: selectedSprite.value?.id }, (response: boolean) => { socketManager.emit(SocketEvent.GM_SPRITE_DELETE, { id: selectedSprite.value?.id }, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to delete sprite') console.error('Failed to delete sprite')
return return
@ -108,7 +109,7 @@ function deleteSprite() {
} }
function copySprite() { function copySprite() {
gameStore.connection?.emit(SocketEvent.GM_SPRITE_COPY, { id: selectedSprite.value?.id }, (response: boolean) => { socketManager.emit(SocketEvent.GM_SPRITE_COPY, { id: selectedSprite.value?.id }, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to copy sprite') console.error('Failed to copy sprite')
return return
@ -118,7 +119,7 @@ function copySprite() {
} }
function refreshSpriteList(unsetSelectedSprite = true) { function refreshSpriteList(unsetSelectedSprite = true) {
gameStore.connection?.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => { socketManager.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
assetManagerStore.setSpriteList(response) assetManagerStore.setSpriteList(response)
if (unsetSelectedSprite) { if (unsetSelectedSprite) {
@ -150,7 +151,7 @@ function saveSprite() {
}) ?? [] }) ?? []
} }
gameStore.connection?.emit(SocketEvent.GM_SPRITE_UPDATE, updatedSprite, (response: boolean) => { socketManager.emit(SocketEvent.GM_SPRITE_UPDATE, updatedSprite, (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to save sprite') console.error('Failed to save sprite')
return return

View File

@ -27,6 +27,7 @@
import config from '@/application/config' import config from '@/application/config'
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { Sprite } from '@/application/types' import type { Sprite } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useVirtualList } from '@vueuse/core' import { useVirtualList } from '@vueuse/core'
@ -41,13 +42,13 @@ const hasScrolled = ref(false)
const elementToScroll = ref() const elementToScroll = ref()
function newButtonClickHandler() { function newButtonClickHandler() {
gameStore.connection?.emit(SocketEvent.GM_SPRITE_CREATE, {}, (response: boolean) => { socketManager.emit(SocketEvent.GM_SPRITE_CREATE, {}, (response: boolean) => {
if (!response) { if (!response) {
if (config.environment === 'development') console.error('Failed to create new sprite') if (config.environment === 'development') console.error('Failed to create new sprite')
return return
} }
gameStore.connection?.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => { socketManager.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
assetManagerStore.setSpriteList(response) assetManagerStore.setSpriteList(response)
}) })
}) })
@ -86,7 +87,7 @@ function toTop() {
} }
onMounted(() => { onMounted(() => {
gameStore.connection?.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => { socketManager.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
assetManagerStore.setSpriteList(response) assetManagerStore.setSpriteList(response)
}) })
}) })

View File

@ -27,6 +27,7 @@ import config from '@/application/config'
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { Tile } from '@/application/types' import type { Tile } from '@/application/types'
import ChipsInput from '@/components/forms/ChipsInput.vue' import ChipsInput from '@/components/forms/ChipsInput.vue'
import { socketManager } from '@/managers/SocketManager'
import { TileStorage } from '@/storage/storages' import { TileStorage } from '@/storage/storages'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
@ -57,7 +58,7 @@ watch(selectedTile, (tile: Tile | null) => {
}) })
async function deleteTile() { async function deleteTile() {
gameStore.connection?.emit(SocketEvent.GM_TILE_DELETE, { id: selectedTile.value?.id }, async (response: boolean) => { socketManager.emit(SocketEvent.GM_TILE_DELETE, { id: selectedTile.value?.id }, async (response: boolean) => {
if (!response) { if (!response) {
console.error('Failed to delete tile') console.error('Failed to delete tile')
return return
@ -68,7 +69,7 @@ async function deleteTile() {
} }
function refreshTileList(unsetSelectedTile = true) { function refreshTileList(unsetSelectedTile = true) {
gameStore.connection?.emit(SocketEvent.GM_TILE_LIST, {}, (response: Tile[]) => { socketManager.emit(SocketEvent.GM_TILE_LIST, {}, (response: Tile[]) => {
assetManagerStore.setTileList(response) assetManagerStore.setTileList(response)
if (unsetSelectedTile) { if (unsetSelectedTile) {
@ -83,7 +84,7 @@ function saveTile() {
return return
} }
gameStore.connection?.emit( socketManager.emit(
'gm:tile:update', 'gm:tile:update',
{ {
id: selectedTile.value.id, id: selectedTile.value.id,

View File

@ -31,6 +31,7 @@
import config from '@/application/config' import config from '@/application/config'
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { Tile } from '@/application/types' import type { Tile } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore' import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useVirtualList } from '@vueuse/core' import { useVirtualList } from '@vueuse/core'
@ -48,13 +49,13 @@ const elementToScroll = ref()
const handleFileUpload = (e: Event) => { const handleFileUpload = (e: Event) => {
const files = (e.target as HTMLInputElement).files const files = (e.target as HTMLInputElement).files
if (!files) return if (!files) return
gameStore.connection?.emit(SocketEvent.GM_TILE_UPLOAD, files, (response: boolean) => { socketManager.emit(SocketEvent.GM_TILE_UPLOAD, files, (response: boolean) => {
if (!response) { if (!response) {
if (config.environment === 'development') console.error('Failed to upload tile') if (config.environment === 'development') console.error('Failed to upload tile')
return return
} }
gameStore.connection?.emit(SocketEvent.GM_TILE_LIST, {}, (response: Tile[]) => { socketManager.emit(SocketEvent.GM_TILE_LIST, {}, (response: Tile[]) => {
assetManagerStore.setTileList(response) assetManagerStore.setTileList(response)
}) })
}) })
@ -93,7 +94,7 @@ function toTop() {
} }
onMounted(() => { onMounted(() => {
gameStore.connection?.emit(SocketEvent.GM_TILE_LIST, {}, (response: Tile[]) => { socketManager.emit(SocketEvent.GM_TILE_LIST, {}, (response: Tile[]) => {
assetManagerStore.setTileList(response) assetManagerStore.setTileList(response)
}) })
}) })

View File

@ -32,7 +32,7 @@ let commandIndex = ref(0)
let originTiles: string[][] = [] let originTiles: string[][] = []
let originEventTiles: MapEventTile[] = [] let originEventTiles: MapEventTile[] = []
let originObjects = ref<PlacedMapObjectT[]>(mapEditor.currentMap.value.placedMapObjects) let originObjects = ref<PlacedMapObjectT[]>(mapEditor.currentMap.value?.placedMapObjects ?? [])
const { undo, redo, commit, pause, resume, canUndo, canRedo } = useRefHistory(originObjects, { deep: true, capacity: 9 }) const { undo, redo, commit, pause, resume, canUndo, canRedo } = useRefHistory(originObjects, { deep: true, capacity: 9 })

View File

@ -46,7 +46,9 @@ class EventTileCommand implements EditorCommand {
} }
} }
function createCommandUpdate(tile?: MapEventTile, operation: 'draw' | 'erase' | 'clear') { function createCommandUpdate(tile?: MapEventTile | null, operation: 'draw' | 'erase' | 'clear' = 'draw') {
if (!tile) return
if (!currentCommand) { if (!currentCommand) {
currentCommand = new EventTileCommand(operation) currentCommand = new EventTileCommand(operation)
} }
@ -86,19 +88,17 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
if (existingEventTile) return if (existingEventTile) return
// If teleport, check if there is a selected map // If teleport, check if there is a selected map
if (mapEditor.drawMode.value === 'teleport' && !mapEditor.teleportSettings.value.toMapId) return if (mapEditor.drawMode.value === 'teleport' && !mapEditor.teleportSettings.value.toMap) return
const newEventTile = { const newEventTile = {
id: uuidv4() as UUID, id: uuidv4() as UUID,
mapId: map.id,
map: map,
type: mapEditor.drawMode.value === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT, type: mapEditor.drawMode.value === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT,
positionX: tile.x, positionX: tile.x,
positionY: tile.y, positionY: tile.y,
teleport: teleport:
mapEditor.drawMode.value === 'teleport' mapEditor.drawMode.value === 'teleport'
? { ? {
toMap: mapEditor.teleportSettings.value.toMapId, toMap: mapEditor.teleportSettings.value.toMap,
toPositionX: mapEditor.teleportSettings.value.toPositionX, toPositionX: mapEditor.teleportSettings.value.toPositionX,
toPositionY: mapEditor.teleportSettings.value.toPositionY, toPositionY: mapEditor.teleportSettings.value.toPositionY,
toRotation: mapEditor.teleportSettings.value.toRotation toRotation: mapEditor.teleportSettings.value.toRotation
@ -106,9 +106,9 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
: undefined : undefined
} }
createCommandUpdate(newEventTile, 'draw') createCommandUpdate(newEventTile as MapEventTile, 'draw')
map.mapEventTiles.push(newEventTile) map.mapEventTiles.push(newEventTile as MapEventTile)
} }
function erase(pointer: Phaser.Input.Pointer, map: MapT) { function erase(pointer: Phaser.Input.Pointer, map: MapT) {
@ -149,7 +149,7 @@ function handlePointer(pointer: Phaser.Input.Pointer) {
} }
function clearTiles() { function clearTiles() {
if (mapEditor.currentMap.value.mapEventTiles.length === 0) return if (mapEditor.currentMap.value?.mapEventTiles.length === 0) return
createCommandUpdate(null, 'clear') createCommandUpdate(null, 'clear')
finalizeCommand() finalizeCommand()
} }

View File

@ -18,7 +18,7 @@ import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { getTile } from '@/services/mapService' import { getTile } from '@/services/mapService'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import {computed, onMounted, onUnmounted, ref, watch} from 'vue' import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import Tilemap = Phaser.Tilemaps.Tilemap import Tilemap = Phaser.Tilemaps.Tilemap
import TilemapLayer = Phaser.Tilemaps.TilemapLayer import TilemapLayer = Phaser.Tilemaps.TilemapLayer
@ -129,7 +129,7 @@ function moveMapObject(id: string, map: MapT) {
const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY) const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY)
if (!tile) return if (!tile) return
console.log(id)
map.placedMapObjects.map((placed) => { map.placedMapObjects.map((placed) => {
if (placed.id === id) { if (placed.id === id) {
placed.positionX = tile.x placed.positionX = tile.x

View File

@ -39,6 +39,7 @@ import { SocketEvent } from '@/application/enums'
import type { Map } from '@/application/types' import type { Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { socketManager } from '@/managers/SocketManager'
import { MapStorage } from '@/storage/storages' import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { ref, useTemplateRef } from 'vue' import { ref, useTemplateRef } from 'vue'
@ -57,7 +58,7 @@ const pvp = ref(false)
defineExpose({ open: () => modalRef.value?.open() }) defineExpose({ open: () => modalRef.value?.open() })
async function submit() { async function submit() {
gameStore.connection?.emit(SocketEvent.GM_MAP_CREATE, { name: name.value, width: width.value, height: height.value }, async (response: Map | false) => { socketManager.emit(SocketEvent.GM_MAP_CREATE, { name: name.value, width: width.value, height: height.value }, async (response: Map | false) => {
if (!response) { if (!response) {
return return
} }

View File

@ -34,6 +34,7 @@ import type { Map } from '@/application/types'
import CreateMap from '@/components/gameMaster/mapEditor/partials/CreateMap.vue' import CreateMap from '@/components/gameMaster/mapEditor/partials/CreateMap.vue'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { socketManager } from '@/managers/SocketManager'
import { MapStorage } from '@/storage/storages' import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { onMounted, ref, useTemplateRef } from 'vue' import { onMounted, ref, useTemplateRef } from 'vue'
@ -61,14 +62,14 @@ async function fetchMaps() {
} }
function loadMap(id: string) { function loadMap(id: string) {
gameStore.connection?.emit(SocketEvent.GM_MAP_REQUEST, { mapId: id }, (response: Map) => { socketManager.emit(SocketEvent.GM_MAP_REQUEST, { mapId: id }, (response: Map) => {
mapEditor.loadMap(response) mapEditor.loadMap(response)
}) })
modalRef.value?.close() modalRef.value?.close()
} }
async function deleteMap(id: string) { async function deleteMap(id: string) {
gameStore.connection?.emit(SocketEvent.GM_MAP_DELETE, { mapId: id }, async (response: boolean) => { socketManager.emit(SocketEvent.GM_MAP_DELETE, { mapId: id }, async (response: boolean) => {
if (!response) { if (!response) {
gameStore.addNotification({ gameStore.addNotification({
title: 'Error', title: 'Error',

View File

@ -1,10 +1,15 @@
<template> <template>
<div class="absolute border-0 border-l-2 border-solid border-gray-500 w-1/4 min-w-80 flex flex-col top-0 right-0 z-10 h-dvh bg-gray-800" v-if="mapEditor.tool.value === 'pencil' && mapEditor.drawMode.value === 'map_object'"> <div class="absolute border-0 border-l-2 border-solid border-gray-500 w-1/4 min-w-80 flex flex-col top-0 right-0 z-10 h-dvh bg-gray-800" v-if="mapEditor.tool.value === 'pencil' && mapEditor.drawMode.value === 'map_object'">
<div class="flex flex-col gap-2.5 p-2.5"> <div class="flex flex-col gap-2.5 p-2.5">
<div class="relative flex"> <div class="flex justify-between items-center">
<img src="/assets/icons/mapEditor/search.svg" class="w-4 h-4 py-0.5 absolute top-1/2 -translate-y-1/2 left-2.5" alt="Search icon" /> <div class="flex-grow">
<label class="mb-1.5 font-titles hidden" for="search">Search</label> <div class="relative flex">
<input @mousedown.stop class="!pl-7 input-field w-full" type="text" name="search" placeholder="Search" v-model="searchQuery" /> <img src="/assets/icons/mapEditor/search.svg" class="w-4 h-4 py-0.5 absolute top-1/2 -translate-y-1/2 left-2.5" alt="Search icon" />
<label class="mb-1.5 font-titles hidden" for="search">Search</label>
<input @mousedown.stop class="!pl-7 input-field w-full" type="text" name="search" placeholder="Search" v-model="searchQuery" />
</div>
</div>
<img src="/assets/icons/mapEditor/dropdown-chevron.svg" class="w-12 h-12 ml-2 cursor-pointer hover:opacity-80 -rotate-90" alt="Close" @click="mapEditor.setTool('move')" />
</div> </div>
<div class="flex"> <div class="flex">
<select class="input-field w-full" name="lists" v-model="mapEditor.drawMode.value" @change="(event: any) => mapEditor.setDrawMode(event.target.value)"> <select class="input-field w-full" name="lists" v-model="mapEditor.drawMode.value" @change="(event: any) => mapEditor.setDrawMode(event.target.value)">

View File

@ -45,6 +45,7 @@ import { SocketEvent } from '@/application/enums'
import type { MapObject, Map as MapT, PlacedMapObject } from '@/application/types' import type { MapObject, Map as MapT, PlacedMapObject } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { socketManager } from '@/managers/SocketManager'
import { MapObjectStorage } from '@/storage/storages' import { MapObjectStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
@ -81,7 +82,7 @@ const handleDelete = () => {
async function handleUpdate() { async function handleUpdate() {
if (!mapObject.value) return if (!mapObject.value) return
gameStore.connection?.emit( socketManager.emit(
SocketEvent.GM_MAPOBJECT_UPDATE, SocketEvent.GM_MAPOBJECT_UPDATE,
{ {
id: props.placedMapObject.mapObject as string, id: props.placedMapObject.mapObject as string,

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal ref="modalRef" @modal:close="() => mapEditorStore.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false" bg-style="none"> <Modal v-if="showTeleportModal" ref="modalRef" @modal:close="() => mapEditor.setTool('move')" :modal-width="300" :modal-height="350" :is-resizable="false" bg-style="none">
<template #modalHeader> <template #modalHeader>
<h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3> <h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3>
</template> </template>
@ -28,7 +28,7 @@
<label for="toMap">Map to teleport to</label> <label for="toMap">Map to teleport to</label>
<select v-model="toMap" class="input-field" name="toMap" id="toMap"> <select v-model="toMap" class="input-field" name="toMap" id="toMap">
<option :value="null">Select map</option> <option :value="null">Select map</option>
<option v-for="map in mapList" :key="map.id" :value="map">{{ map.name }}</option> <option v-for="map in mapList" :key="map.id" :value="map.id">{{ map.name }}</option>
</select> </select>
</div> </div>
</div> </div>
@ -39,51 +39,50 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums'
import type { Map } from '@/application/types' import type { Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore' import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useMapEditorStore } from '@/stores/mapEditorStore' import { MapStorage } from '@/storage/storages'
import { computed, onMounted, ref, useTemplateRef, watch } from 'vue' import { computed, onMounted, ref, useTemplateRef, watch } from 'vue'
const showTeleportModal = computed(() => mapEditorStore.tool === 'pencil' && mapEditorStore.drawMode === 'teleport') const showTeleportModal = computed(() => mapEditor.tool.value === 'pencil' && mapEditor.drawMode.value === 'teleport')
const mapEditorStore = useMapEditorStore() const mapStorage = new MapStorage()
const gameStore = useGameStore() const mapEditor = useMapEditorComposable()
const mapList = ref<Map[]>([])
const modalRef = useTemplateRef('modalRef') const modalRef = useTemplateRef('modalRef')
const mapList = ref<Map[]>([])
defineExpose({ defineExpose({
open: () => modalRef.value?.open() open: () => modalRef.value?.open()
}) })
onMounted(fetchMaps)
function fetchMaps() {
// gameStore.connection?.emit(SocketEvent.GM_MAP_LIST, {}, (response: Map[]) => {
// mapList.value = response
// })
}
const { toPositionX, toPositionY, toRotation, toMap } = useRefTeleportSettings() const { toPositionX, toPositionY, toRotation, toMap } = useRefTeleportSettings()
function useRefTeleportSettings() { function useRefTeleportSettings() {
const settings = mapEditorStore.teleportSettings const settings = mapEditor.teleportSettings.value
return { return {
toPositionX: ref(settings.toPositionX), toPositionX: ref(settings.toPositionX),
toPositionY: ref(settings.toPositionY), toPositionY: ref(settings.toPositionY),
toRotation: ref(settings.toRotation), toRotation: ref(settings.toRotation),
toMap: ref(settings.toMapId) toMap: ref(settings.toMap)
} }
} }
watch([toPositionX, toPositionY, toRotation, toMap], updateTeleportSettings) watch([toPositionX, toPositionY, toRotation, toMap], updateTeleportSettings)
function updateTeleportSettings() { function updateTeleportSettings() {
mapEditorStore.setTeleportSettings({ mapEditor.setTeleportSettings({
toPositionX: toPositionX.value, toPositionX: toPositionX.value,
toPositionY: toPositionY.value, toPositionY: toPositionY.value,
toRotation: toRotation.value, toRotation: toRotation.value,
toMapId: toMap.value toMap: toMap.value
}) })
} }
async function fetchMaps() {
mapList.value = await mapStorage.getAll()
}
onMounted(async () => {
await fetchMaps()
})
</script> </script>

View File

@ -1,10 +1,15 @@
<template> <template>
<div class="absolute border-0 border-l-2 border-solid border-gray-500 w-1/4 min-w-80 flex flex-col top-0 right-0 z-10 h-dvh bg-gray-800" v-if="(mapEditor.tool.value === 'pencil' && mapEditor.drawMode.value === 'tile') || mapEditor.tool.value === 'paint'"> <div class="absolute border-0 border-l-2 border-solid border-gray-500 w-1/4 min-w-80 flex flex-col top-0 right-0 z-10 h-dvh bg-gray-800" v-if="(mapEditor.tool.value === 'pencil' && mapEditor.drawMode.value === 'tile') || mapEditor.tool.value === 'paint'">
<div class="flex flex-col gap-2.5 p-2.5"> <div class="flex flex-col gap-2.5 p-2.5">
<div class="relative flex"> <div class="flex justify-between items-center">
<img src="/assets/icons/mapEditor/search.svg" class="w-4 h-4 py-0.5 absolute top-1/2 -translate-y-1/2 left-2.5" alt="Search icon" /> <div class="flex-grow">
<label class="mb-1.5 font-titles hidden" for="search">Search</label> <div class="relative flex">
<input @mousedown.stop class="!pl-7 input-field w-full" type="text" name="search" placeholder="Search" v-model="searchQuery" /> <img src="/assets/icons/mapEditor/search.svg" class="w-4 h-4 py-0.5 absolute top-1/2 -translate-y-1/2 left-2.5" alt="Search icon" />
<label class="mb-1.5 font-titles hidden" for="search">Search</label>
<input @mousedown.stop class="!pl-7 input-field w-full" type="text" name="search" placeholder="Search" v-model="searchQuery" />
</div>
</div>
<img src="/assets/icons/mapEditor/dropdown-chevron.svg" class="w-12 h-12 ml-2 cursor-pointer hover:opacity-80 -rotate-90" alt="Close" @click="mapEditor.setTool('move')" />
</div> </div>
<div class="flex"> <div class="flex">
<select class="input-field w-full" name="lists" v-model="mapEditor.drawMode.value" @change="(event: any) => mapEditor.setDrawMode(event.target.value)"> <select class="input-field w-full" name="lists" v-model="mapEditor.drawMode.value" @change="(event: any) => mapEditor.setDrawMode(event.target.value)">

View File

@ -117,7 +117,7 @@ const selectPencilOpen = ref(false)
const selectEraserOpen = ref(false) const selectEraserOpen = ref(false)
const isContinuousDrawingEnabled = ref<Boolean>(false) const isContinuousDrawingEnabled = ref<Boolean>(false)
const isShowPlacedMapObjectPreviewEnabled = ref<Boolean>(mapEditor.isPlacedMapObjectPreviewEnabled.value) const isShowPlacedMapObjectPreviewEnabled = ref<Boolean>(mapEditor.isPlacedMapObjectPreviewEnabled.value)
const listOpen = computed(() => mapEditor.tool.value === 'pencil' && (mapEditor.drawMode.value === 'tile' || mapEditor.drawMode.value === 'map_object')) const listOpen = computed(() => (mapEditor.tool.value === 'pencil' && (mapEditor.drawMode.value === 'tile' || mapEditor.drawMode.value === 'map_object')) || mapEditor.tool.value === 'paint')
// drawMode // drawMode
function setDrawMode(value: string) { function setDrawMode(value: string) {
@ -148,6 +148,7 @@ function handleModeClick(mode: string, type: 'pencil' | 'eraser') {
function handleClick(tool: string) { function handleClick(tool: string) {
mapEditor.setTool(tool) mapEditor.setTool(tool)
if (tool === 'paint') mapEditor.setDrawMode('tile')
selectPencilOpen.value = tool === 'pencil' ? !selectPencilOpen.value : false selectPencilOpen.value = tool === 'pencil' ? !selectPencilOpen.value : false
selectEraserOpen.value = tool === 'eraser' ? !selectEraserOpen.value : false selectEraserOpen.value = tool === 'eraser' ? !selectEraserOpen.value : false
if (mapEditor.drawMode.value === 'teleport') emit('open-teleport') if (mapEditor.drawMode.value === 'teleport') emit('open-teleport')

View File

@ -26,6 +26,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { socketManager } from '@/managers/SocketManager'
import { login } from '@/services/authenticationService' import { login } from '@/services/authenticationService'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useCookies } from '@vueuse/integrations/useCookies' import { useCookies } from '@vueuse/integrations/useCookies'
@ -53,7 +54,7 @@ async function submit() {
formError.value = response.error formError.value = response.error
return return
} }
gameStore.setToken(response.token) socketManager.setToken(response.token)
gameStore.initConnection() gameStore.initConnection()
return true // Indicate success return true // Indicate success
} }

View File

@ -26,6 +26,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { socketManager } from '@/managers/SocketManager'
import { login, register } from '@/services/authenticationService' import { login, register } from '@/services/authenticationService'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { useCookies } from '@vueuse/integrations/useCookies' import { useCookies } from '@vueuse/integrations/useCookies'
@ -67,7 +68,7 @@ async function submit() {
return return
} }
gameStore.setToken(loginResponse.token) socketManager.setToken(loginResponse.token)
gameStore.initConnection() gameStore.initConnection()
} }
</script> </script>

View File

@ -126,6 +126,7 @@ import { SocketEvent } from '@/application/enums'
import { type CharacterHair, type Character as CharacterT, type Map } from '@/application/types' import { type CharacterHair, type Character as CharacterT, type Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useSoundComposable } from '@/composables/useSoundComposable' import { useSoundComposable } from '@/composables/useSoundComposable'
import { socketManager } from '@/managers/SocketManager'
import { CharacterHairStorage } from '@/storage/storages' import { CharacterHairStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue' import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -142,11 +143,10 @@ const selectedHairId = ref<string | null>(null)
// Fetch characters // Fetch characters
setTimeout(() => { setTimeout(() => {
console.log(SocketEvent.CHARACTER_LIST) socketManager.emit(SocketEvent.CHARACTER_LIST)
gameStore.connection?.emit(SocketEvent.CHARACTER_LIST)
}, 750) }, 750)
gameStore.connection?.on(SocketEvent.CHARACTER_LIST, (data: any) => { socketManager.on(SocketEvent.CHARACTER_LIST, (data: any) => {
characters.value = data characters.value = data
isLoading.value = false isLoading.value = false
}) })
@ -155,7 +155,7 @@ gameStore.connection?.on(SocketEvent.CHARACTER_LIST, (data: any) => {
function loginWithCharacter() { function loginWithCharacter() {
if (!selectedCharacterId.value) return if (!selectedCharacterId.value) return
gameStore.connection?.emit( socketManager.emit(
SocketEvent.CHARACTER_CONNECT, SocketEvent.CHARACTER_CONNECT,
{ {
characterId: selectedCharacterId.value, characterId: selectedCharacterId.value,
@ -169,7 +169,7 @@ function loginWithCharacter() {
// Create character logics // Create character logics
function createCharacter() { function createCharacter() {
gameStore.connection?.emit(SocketEvent.CHARACTER_CREATE, { name: newCharacterName.value }, (success: boolean) => { socketManager.emit(SocketEvent.CHARACTER_CREATE, { name: newCharacterName.value }, (success: boolean) => {
if (success) return if (success) return
isCreateNewCharacterModalOpen.value = false isCreateNewCharacterModalOpen.value = false
}) })
@ -188,8 +188,8 @@ onMounted(async () => {
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
gameStore.connection?.off(SocketEvent.CHARACTER_LIST) socketManager.off(SocketEvent.CHARACTER_LIST)
gameStore.connection?.off(SocketEvent.CHARACTER_CONNECT) socketManager.off(SocketEvent.CHARACTER_CONNECT)
gameStore.connection?.off(SocketEvent.CHARACTER_CREATE) socketManager.off(SocketEvent.CHARACTER_CREATE)
}) })
</script> </script>

View File

@ -20,6 +20,7 @@
<script setup lang="ts"> <script setup lang="ts">
import config from '@/application/config' import config from '@/application/config'
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import { socketManager } from '@/managers/SocketManager'
import 'phaser' import 'phaser'
import type { Map as MapT } from '@/application/types' import type { Map as MapT } from '@/application/types'
import Map from '@/components/gameMaster/mapEditor/Map.vue' import Map from '@/components/gameMaster/mapEditor/Map.vue'
@ -92,7 +93,7 @@ function save() {
mapId: currentMap.id mapId: currentMap.id
} }
gameStore.connection?.emit(SocketEvent.GM_MAP_UPDATE, data, (response: MapT) => { socketManager.emit(SocketEvent.GM_MAP_UPDATE, data, (response: MapT) => {
mapStorage.update(response.id, response) mapStorage.update(response.id, response)
}) })
} }

View File

@ -1,10 +1,14 @@
<template></template> <template></template>
<script setup lang="ts"> <script setup lang="ts">
import { socketManager } from '@/managers/SocketManager'
import { login } from '@/services/authenticationService'
import { CharacterHairStorage, CharacterTypeStorage, MapObjectStorage, MapStorage, SoundStorage, SpriteStorage, TileStorage } from '@/storage/storages' import { CharacterHairStorage, CharacterTypeStorage, MapObjectStorage, MapStorage, SoundStorage, SpriteStorage, TileStorage } from '@/storage/storages'
import { TextureStorage } from '@/storage/textureStorage' import { TextureStorage } from '@/storage/textureStorage'
import { useGameStore } from '@/stores/gameStore'
import { onMounted, onUnmounted } from 'vue' import { onMounted, onUnmounted } from 'vue'
const gameStore = useGameStore()
const mapStorage = new MapStorage() const mapStorage = new MapStorage()
const tileStorage = new TileStorage() const tileStorage = new TileStorage()
const mapObjectStorage = new MapObjectStorage() const mapObjectStorage = new MapObjectStorage()
@ -37,6 +41,17 @@ async function handleKeyPress(event: KeyboardEvent) {
currentString = '' // Reset currentString = '' // Reset
} }
if (currentString.includes('11')) {
if (socketManager.token) return
const response = await login('root', 'password')
if (response.success === undefined) {
return
}
socketManager.setToken(response.token)
gameStore.initConnection()
}
// Reset string after a certain amount of time // Reset string after a certain amount of time
setTimeout(() => { setTimeout(() => {
currentString = '' currentString = ''

View File

@ -12,6 +12,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { socketManager } from '@/managers/SocketManager'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import { onBeforeMount, onBeforeUnmount, onMounted, onUnmounted, watch } from 'vue' import { onBeforeMount, onBeforeUnmount, onMounted, onUnmounted, watch } from 'vue'

View File

@ -1,4 +1,5 @@
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import { socketManager } from '@/managers/SocketManager'
import { getTile } from '@/services/mapService' import { getTile } from '@/services/mapService'
import { useGameStore } from '@/stores/gameStore' import { useGameStore } from '@/stores/gameStore'
import type { Ref } from 'vue' import type { Ref } from 'vue'
@ -7,7 +8,77 @@ import { useBaseControlsComposable } from './useBaseControlsComposable'
export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) { export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore() const gameStore = useGameStore()
const baseHandlers = useBaseControlsComposable(scene, layer, waypoint, camera) const baseHandlers = useBaseControlsComposable(scene, layer, waypoint, camera)
const pressedKeys = new Set<string>()
let moveTimeout: NodeJS.Timeout | null = null
let currentPosition = {
x: 0,
y: 0
}
// Movement constants
const MOVEMENT_DELAY = 110 // Milliseconds between moves
const ARROW_KEYS = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'] as const
function updateCurrentPosition() {
if (!gameStore.character) return
currentPosition = {
x: gameStore.character.positionX,
y: gameStore.character.positionY
}
}
function calculateNewPosition() {
let newX = currentPosition.x
let newY = currentPosition.y
if (pressedKeys.has('ArrowLeft')) newX--
if (pressedKeys.has('ArrowRight')) newX++
if (pressedKeys.has('ArrowUp')) newY--
if (pressedKeys.has('ArrowDown')) newY++
return { newX, newY }
}
function emitMovement(x: number, y: number) {
if (x === currentPosition.x && y === currentPosition.y) return
socketManager.emit(SocketEvent.MAP_CHARACTER_MOVE, [x, y])
socketManager.on(SocketEvent.MAP_CHARACTER_MOVE, ([characterId, posX, posY, rot, isMoving]: [string, number, number, number, boolean]) => {
if (characterId !== gameStore.character?.id) return
currentPosition = { x: posX, y: posY }
})
currentPosition = { x, y }
}
function startMovementLoop() {
if (moveTimeout) return
const move = () => {
if (pressedKeys.size === 0) {
stopMovementLoop()
return
}
updateCurrentPosition()
const { newX, newY } = calculateNewPosition()
emitMovement(newX, newY)
moveTimeout = setTimeout(move, MOVEMENT_DELAY)
}
move()
}
function stopMovementLoop() {
if (moveTimeout) {
clearTimeout(moveTimeout)
moveTimeout = null
}
}
// Pointer Handlers
function handlePointerDown(pointer: Phaser.Input.Pointer) { function handlePointerDown(pointer: Phaser.Input.Pointer) {
baseHandlers.startDragging(pointer) baseHandlers.startDragging(pointer)
} }
@ -23,70 +94,37 @@ export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Til
const pointerTile = getTile(layer, pointer.worldX, pointer.worldY) const pointerTile = getTile(layer, pointer.worldX, pointer.worldY)
if (!pointerTile) return if (!pointerTile) return
gameStore.connection?.emit(SocketEvent.MAP_CHARACTER_MOVE, { emitMovement(pointerTile.x, pointerTile.y)
positionX: pointerTile.x,
positionY: pointerTile.y
})
} }
const pressedKeys = new Set<string>() // Keyboard Handlers
let moveInterval: number | null = null
function handleKeyDown(event: KeyboardEvent) { function handleKeyDown(event: KeyboardEvent) {
if (!gameStore.character) return if (!gameStore.character) return
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)) { if (ARROW_KEYS.includes(event.key as (typeof ARROW_KEYS)[number])) {
// Prevent key repeat events
if (event.repeat) return if (event.repeat) return
pressedKeys.add(event.key) pressedKeys.add(event.key)
updateCurrentPosition()
// Start movement loop if not already running startMovementLoop()
if (!moveInterval) {
moveInterval = window.setInterval(moveCharacter, 80) // Increased interval to match server throttle `MOVEMENT_THROTTLE`
moveCharacter() // Move immediately on first press
}
} }
// Attack on CTRL
if (event.key === 'Control') { if (event.key === 'Control') {
gameStore.connection?.emit(SocketEvent.MAP_CHARACTER_ATTACK) socketManager.emit(SocketEvent.MAP_CHARACTER_ATTACK)
} }
} }
function handleKeyUp(event: KeyboardEvent) { function handleKeyUp(event: KeyboardEvent) {
pressedKeys.delete(event.key) pressedKeys.delete(event.key)
// If no movement keys are pressed, clear the interval if (pressedKeys.size === 0) {
if (pressedKeys.size === 0 && moveInterval) { stopMovementLoop()
clearInterval(moveInterval)
moveInterval = null
}
}
function moveCharacter() {
if (!gameStore.character) return
const { positionX, positionY } = gameStore.character
let newX = positionX
let newY = positionY
// Calculate new position based on pressed keys
if (pressedKeys.has('ArrowLeft')) newX--
if (pressedKeys.has('ArrowRight')) newX++
if (pressedKeys.has('ArrowUp')) newY--
if (pressedKeys.has('ArrowDown')) newY++
// Only emit if position changed
if (newX !== positionX || newY !== positionY) {
gameStore.connection?.emit(SocketEvent.MAP_CHARACTER_MOVE, {
positionX: newX,
positionY: newY
})
} }
} }
const setupControls = () => { const setupControls = () => {
updateCurrentPosition() // Initialize position
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown) scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp) scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
@ -96,6 +134,9 @@ export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Til
} }
const cleanupControls = () => { const cleanupControls = () => {
stopMovementLoop()
pressedKeys.clear()
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown) scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove) scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp) scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)

View File

@ -18,7 +18,7 @@ export function useCharacterSpriteComposable(scene: Phaser.Scene, tilemap: Phase
const tween = ref<Phaser.Tweens.Tween | null>(null) const tween = ref<Phaser.Tweens.Tween | null>(null)
const updateIsometricDepth = (positionX: number, positionY: number) => { const updateIsometricDepth = (positionX: number, positionY: number) => {
isometricDepth.value = calculateIsometricDepth(positionX, positionY, 30, 95) isometricDepth.value = calculateIsometricDepth(positionX, positionY)
} }
const updatePosition = (positionX: number, positionY: number) => { const updatePosition = (positionX: number, positionY: number) => {

View File

@ -1,8 +1,9 @@
import type { Map, MapObject, PlacedMapObject, UUID } from '@/application/types' import type { Map, MapObject, PlacedMapObject, UUID } from '@/application/types'
import { useGameStore } from '@/stores/gameStore'
import { ref } from 'vue' import { ref } from 'vue'
export type TeleportSettings = { export type TeleportSettings = {
toMapId: string toMap: string
toPositionX: number toPositionX: number
toPositionY: number toPositionY: number
toRotation: number toRotation: number
@ -20,7 +21,7 @@ const movingPlacedObject = ref<PlacedMapObject | null>(null)
const selectedPlacedObject = ref<PlacedMapObject | null>(null) const selectedPlacedObject = ref<PlacedMapObject | null>(null)
const shouldClearTiles = ref(false) const shouldClearTiles = ref(false)
const teleportSettings = ref<TeleportSettings>({ const teleportSettings = ref<TeleportSettings>({
toMapId: '1000', toMap: '1000',
toPositionX: 0, toPositionX: 0,
toPositionY: 0, toPositionY: 0,
toRotation: 0 toRotation: 0
@ -46,6 +47,8 @@ export function useMapEditorComposable() {
const toggleActive = () => { const toggleActive = () => {
if (active.value) reset() if (active.value) reset()
active.value = !active.value active.value = !active.value
const gameStore = useGameStore()
gameStore.uiSettings.isGmPanelOpen = false
} }
const togglePlacedMapObjectPreview = () => { const togglePlacedMapObjectPreview = () => {
@ -95,6 +98,7 @@ export function useMapEditorComposable() {
selectedTile.value = '' selectedTile.value = ''
isPlacedMapObjectPreviewEnabled.value = false isPlacedMapObjectPreviewEnabled.value = false
selectedMapObject.value = null selectedMapObject.value = null
selectedPlacedObject.value = null
shouldClearTiles.value = false shouldClearTiles.value = false
refreshMapObject.value = 0 refreshMapObject.value = 0
} }

View File

@ -0,0 +1,76 @@
import config from '@/application/config'
import { SocketEvent } from '@/application/enums'
import { useCookies } from '@vueuse/integrations/useCookies'
import { io, Socket } from 'socket.io-client'
import { ref, shallowRef } from 'vue'
class SocketManager {
private static instance: SocketManager
private _connection = shallowRef<Socket | null>(null)
private _token = ref('')
private constructor() {}
public static getInstance(): SocketManager {
if (!SocketManager.instance) {
SocketManager.instance = new SocketManager()
}
return SocketManager.instance
}
public get connection() {
return this._connection.value
}
public get token() {
return this._token.value
}
public setToken(token: string) {
this._token.value = token
}
public initConnection(): Socket {
if (this._connection.value) return this._connection.value
const socket = io(config.server_endpoint, {
secure: config.environment === 'production',
withCredentials: true,
transports: ['websocket'],
reconnectionAttempts: 5
})
this._connection.value = socket
return socket
}
public disconnect(): void {
if (!this._connection.value) return
this._connection.value.off(SocketEvent.CONNECT_ERROR)
this._connection.value.off(SocketEvent.RECONNECT_FAILED)
this._connection.value.off(SocketEvent.DATE)
this._connection.value.disconnect()
useCookies().remove('token', {
domain: config.domain
})
this._connection.value = null
this._token.value = ''
}
public emit(event: string, ...args: any[]): void {
this._connection.value?.emit(event, ...args)
}
public on(event: string, callback: (...args: any[]) => void): void {
this._connection.value?.on(event, callback)
}
public off(event: string, callback?: (...args: any[]) => void): void {
this._connection.value?.off(event, callback)
}
}
export const socketManager = SocketManager.getInstance()

View File

@ -62,12 +62,8 @@ export function createTileArray(width: number, height: number, tile: string = 'b
return Array.from({ length: height }, () => Array.from({ length: width }, () => tile)) return Array.from({ length: height }, () => Array.from({ length: width }, () => tile))
} }
export const calculateIsometricDepth = (positionX: number, positionY: number, width: number = 0, height: number = 0, isCharacter: boolean = false) => { export const calculateIsometricDepth = (positionX: number, positionY: number, pivotPoints: { x: number; y: number }[] = []) => {
const baseDepth = positionX + positionY return Math.max(positionX + positionY)
if (isCharacter) {
return baseDepth
}
return baseDepth + (width + height) / (2 * config.tile_size.width)
} }
async function loadTileTextures(tiles: TileT[], scene: Phaser.Scene) { async function loadTileTextures(tiles: TileT[], scene: Phaser.Scene) {
@ -155,4 +151,4 @@ export function createTileLayer(tileMap: Phaser.Tilemaps.Tilemap, tilesArray: st
//Recursive Array Clone //Recursive Array Clone
export function cloneArray(arr: any[]): any[] { export function cloneArray(arr: any[]): any[] {
return arr.map((item) => (item instanceof Array ? cloneArray(item) : item)) return arr.map((item) => (item instanceof Array ? cloneArray(item) : item))
} }

View File

@ -1,16 +1,12 @@
import config from '@/application/config'
import { SocketEvent } from '@/application/enums' import { SocketEvent } from '@/application/enums'
import type { Character, Notification, User, WorldSettings } from '@/application/types' import type { Character, Notification, User, WorldSettings } from '@/application/types'
import { useCookies } from '@vueuse/integrations/useCookies' import { socketManager } from '@/managers/SocketManager'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { io, Socket } from 'socket.io-client'
export const useGameStore = defineStore('game', { export const useGameStore = defineStore('game', {
state: () => { state: () => {
return { return {
notifications: [] as Notification[], notifications: [] as Notification[],
token: '',
connection: null as Socket | null,
user: null as User | null, user: null as User | null,
character: null as Character | null, character: null as Character | null,
world: { world: {
@ -51,9 +47,6 @@ export const useGameStore = defineStore('game', {
removeNotification(id: string) { removeNotification(id: string) {
this.notifications = this.notifications.filter((notification: Notification) => notification.id !== id) this.notifications = this.notifications.filter((notification: Notification) => notification.id !== id)
}, },
setToken(token: string) {
this.token = token
},
setUser(user: User | null) { setUser(user: User | null) {
this.user = user this.user = user
}, },
@ -73,49 +66,34 @@ export const useGameStore = defineStore('game', {
this.uiSettings.isCharacterProfileOpen = !this.uiSettings.isCharacterProfileOpen this.uiSettings.isCharacterProfileOpen = !this.uiSettings.isCharacterProfileOpen
}, },
initConnection() { initConnection() {
this.connection = io(config.server_endpoint, { const socket = socketManager.initConnection()
secure: config.environment === 'production',
withCredentials: true,
transports: ['websocket'],
reconnectionAttempts: 5
})
// #99 - If we can't connect, disconnect // Handle connect error
this.connection.on('connect_error', () => { socket.on(SocketEvent.CONNECT_ERROR, () => {
this.disconnectSocket() this.disconnectSocket()
}) })
// Let the server know the user is logged in // Handle failed reconnection
this.connection.emit(SocketEvent.LOGIN) socket.on(SocketEvent.RECONNECT_FAILED, () => {
this.disconnectSocket()
})
// set user // Emit login event
this.connection.on(SocketEvent.LOGGED_IN, (user: User) => { socketManager.emit(SocketEvent.LOGIN)
// Handle logged in event
socketManager.on(SocketEvent.LOGGED_IN, (user: User) => {
this.setUser(user) this.setUser(user)
}) })
// When we can't reconnect, disconnect // Handle date updates
this.connection.on('reconnect_failed', () => { socketManager.on(SocketEvent.DATE, (data: Date) => {
this.disconnectSocket()
})
// Listen for new date from socket
this.connection.on(SocketEvent.DATE, (data: Date) => {
this.world.date = new Date(data) this.world.date = new Date(data)
}) })
}, },
disconnectSocket() { disconnectSocket() {
// Remove event listeners socketManager.disconnect()
this.connection?.off('connect_error')
this.connection?.off('reconnect_failed')
this.connection?.off(SocketEvent.DATE)
this.connection?.disconnect()
useCookies().remove('token', {
domain: config.domain
})
this.connection = null
this.token = ''
this.user = null this.user = null
this.character = null this.character = null

View File

@ -2,7 +2,7 @@ import type { MapObject, Map as MapT } from '@/application/types'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export type TeleportSettings = { export type TeleportSettings = {
toMapId: string toMap: string
toPositionX: number toPositionX: number
toPositionY: number toPositionY: number
toRotation: number toRotation: number
@ -18,7 +18,7 @@ export const useMapEditorStore = defineStore('mapEditor', {
selectedMapObject: null as MapObject | null, selectedMapObject: null as MapObject | null,
shouldClearTiles: false, shouldClearTiles: false,
teleportSettings: { teleportSettings: {
toMapId: '', toMap: '',
toPositionX: 0, toPositionX: 0,
toPositionY: 0, toPositionY: 0,
toRotation: 0 toRotation: 0

View File

@ -35,13 +35,13 @@ export const useMapStore = defineStore('map', {
removeCharacter(characterId: UUID) { removeCharacter(characterId: UUID) {
this.characters = this.characters.filter((char) => char.character.id !== characterId) this.characters = this.characters.filter((char) => char.character.id !== characterId)
}, },
updateCharacterPosition(data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) { updateCharacterPosition([characterId, posX, posY, rot, isMoving]: [UUID, number, number, number, boolean]) {
const character = this.characters.find((char) => char.character.id === data.characterId) const character = this.characters.find((char) => char.character.id === characterId)
if (character) { if (character) {
character.character.positionX = data.positionX character.character.positionX = posX
character.character.positionY = data.positionY character.character.positionY = posY
character.character.rotation = data.rotation character.character.rotation = rot
character.isMoving = data.isMoving character.isMoving = isMoving
} }
}, },
reset() { reset() {