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

View File

@ -16,16 +16,18 @@
"dependencies": {
"@vueuse/core": "^10.5.0",
"@vueuse/integrations": "^10.5.0",
"axios": "^1.7.7",
"dexie": "^4.0.8",
"phaser": "3.87.0",
"pinia": "^2.1.6",
"axios": "^1.7.9",
"dexie": "^4.0.11",
"phaser": "^3.88.2",
"phavuer": "^0.16.5",
"phaser3-rex-plugins": "^1.80.13",
"pinia": "^2.3.1",
"sharp": "^0.33.5",
"socket.io-client": "^4.8.0",
"socket.io-client": "^4.8.1",
"universal-cookie": "^6.1.3",
"vite-plugin-image-optimizer": "^1.1.8",
"vue": "^3.5.12",
"zod": "^3.22.2"
"vue": "^3.5.13",
"zod": "^3.24.2"
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.4.0",
@ -38,8 +40,6 @@
"autoprefixer": "^10.4.19",
"jsdom": "^24.1.1",
"npm-run-all2": "^6.2.3",
"phaser3-rex-plugins": "^1.80.8",
"phavuer": "^0.16.1",
"postcss": "^8.4.47",
"prettier": "^3.3.3",
"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 { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useSoundComposable } from '@/composables/useSoundComposable'
import { socketManager } from '@/managers/SocketManager'
import { useGameStore } from '@/stores/gameStore'
import { computed, watch } from 'vue'
@ -26,8 +27,8 @@ const { playSound } = useSoundComposable()
const currentScreen = computed(() => {
if (!gameStore.game.isLoaded) return Loading
if (!gameStore.connection) return Login
if (!gameStore.token) return Login
if (!socketManager.connection) return Login
if (!socketManager.token) return Login
if (!gameStore.character) return Characters
if (mapEditor.active.value) return MapEditor
return Game

View File

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

View File

@ -36,7 +36,8 @@ export type Tile = {
export type MapObject = {
id: string
name: string
tags: any | null
tags: string[]
pivotPoints: { x: number; y: number }[]
originX: number
originY: number
frameRate: number
@ -100,7 +101,7 @@ export enum MapEventTileType {
export type MapEventTile = {
id: string
mapid: string
map: string
type: MapEventTileType
positionX: 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 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) {
let overwrite = false
const existingItem = await storage.getById(item.id)

View File

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

View File

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

View File

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

View File

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

View File

@ -61,7 +61,7 @@ function calculateObjectPlacement(mapObj: PlacedMapObject): { x: number; y: numb
const imageProps = computed(() => ({
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,
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),
flipX: props.placedMapObject.isRotated,
texture: mapObject.value!.id,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,20 @@
<template>
<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">
<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 class="mt-5 block">
<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 type { MapObject } from '@/application/types'
import ChipsInput from '@/components/forms/ChipsInput.vue'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -58,11 +72,15 @@ const selectedMapObject = computed(() => assetManagerStore.selectedMapObject)
const mapObjectName = ref('')
const mapObjectTags = ref<string[]>([])
const mapObjectPivotPoints = ref<Array<{ x: number; y: number }>>([])
const mapObjectOriginX = ref(0)
const mapObjectOriginY = ref(0)
const mapObjectFrameRate = ref(0)
const mapObjectFrameWidth = ref(0)
const mapObjectFrameHeight = ref(0)
const imageRef = ref<HTMLImageElement | null>(null)
const isDragging = ref(false)
const draggedPointIndex = ref(-1)
if (!selectedMapObject.value) {
console.error('No map mapObject selected')
@ -71,6 +89,7 @@ if (!selectedMapObject.value) {
if (selectedMapObject.value) {
mapObjectName.value = selectedMapObject.value.name
mapObjectTags.value = selectedMapObject.value.tags
mapObjectPivotPoints.value = selectedMapObject.value.pivotPoints
mapObjectOriginX.value = selectedMapObject.value.originX
mapObjectOriginY.value = selectedMapObject.value.originY
mapObjectFrameRate.value = selectedMapObject.value.frameRate
@ -79,7 +98,7 @@ if (selectedMapObject.value) {
}
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) {
console.error('Failed to remove mapObject')
return
@ -89,7 +108,7 @@ function removeObject() {
}
function refreshObjectList(unsetSelectedMapObject = true) {
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
socketManager.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
assetManagerStore.setMapObjectList(response)
if (unsetSelectedMapObject) {
@ -104,12 +123,13 @@ function saveObject() {
return
}
gameStore.connection?.emit(
'gm:mapObject:update',
socketManager.emit(
SocketEvent.GM_MAPOBJECT_UPDATE,
{
id: selectedMapObject.value.id,
name: mapObjectName.value,
tags: mapObjectTags.value,
pivotPoints: mapObjectPivotPoints.value,
originX: mapObjectOriginX.value,
originY: mapObjectOriginY.value,
frameRate: mapObjectFrameRate.value,
@ -130,6 +150,7 @@ watch(selectedMapObject, (mapObject: MapObject | null) => {
if (!mapObject) return
mapObjectName.value = mapObject.name
mapObjectTags.value = mapObject.tags
mapObjectPivotPoints.value = mapObject.pivotPoints
mapObjectOriginX.value = mapObject.originX
mapObjectOriginY.value = mapObject.originY
mapObjectFrameRate.value = mapObject.frameRate
@ -141,7 +162,51 @@ onMounted(() => {
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(() => {
assetManagerStore.setSelectedMapObject(null)
})
</script>
<style scoped>
.pointer-events-none {
pointer-events: none;
}
</style>

View File

@ -31,6 +31,7 @@
import config from '@/application/config'
import { SocketEvent } from '@/application/enums'
import type { MapObject } from '@/application/types'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore'
import { useVirtualList } from '@vueuse/core'
@ -48,13 +49,13 @@ const elementToScroll = ref()
const handleFileUpload = (e: Event) => {
const files = (e.target as HTMLInputElement).files
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 (config.environment === 'development') console.error('Failed to upload map object')
return
}
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
socketManager.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
assetManagerStore.setMapObjectList(response)
})
})
@ -93,7 +94,7 @@ function toTop() {
}
onMounted(() => {
gameStore.connection?.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
socketManager.emit(SocketEvent.GM_MAPOBJECT_LIST, {}, (response: MapObject[]) => {
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 SpritePreview from '@/components/gameMaster/assetManager/partials/sprite/partials/SpritePreview.vue'
import Accordion from '@/components/utilities/Accordion.vue'
import { socketManager } from '@/managers/SocketManager'
import { useAssetManagerStore } from '@/stores/assetManagerStore'
import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -98,7 +99,7 @@ if (selectedSprite.value) {
}
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) {
console.error('Failed to delete sprite')
return
@ -108,7 +109,7 @@ function deleteSprite() {
}
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) {
console.error('Failed to copy sprite')
return
@ -118,7 +119,7 @@ function copySprite() {
}
function refreshSpriteList(unsetSelectedSprite = true) {
gameStore.connection?.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
socketManager.emit(SocketEvent.GM_SPRITE_LIST, {}, (response: Sprite[]) => {
assetManagerStore.setSpriteList(response)
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) {
console.error('Failed to save sprite')
return

View File

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

View File

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

View File

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

View File

@ -32,7 +32,7 @@ let commandIndex = ref(0)
let originTiles: string[][] = []
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 })

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) {
currentCommand = new EventTileCommand(operation)
}
@ -86,19 +88,17 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
if (existingEventTile) return
// 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 = {
id: uuidv4() as UUID,
mapId: map.id,
map: map,
type: mapEditor.drawMode.value === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT,
positionX: tile.x,
positionY: tile.y,
teleport:
mapEditor.drawMode.value === 'teleport'
? {
toMap: mapEditor.teleportSettings.value.toMapId,
toMap: mapEditor.teleportSettings.value.toMap,
toPositionX: mapEditor.teleportSettings.value.toPositionX,
toPositionY: mapEditor.teleportSettings.value.toPositionY,
toRotation: mapEditor.teleportSettings.value.toRotation
@ -106,9 +106,9 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
: 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) {
@ -149,7 +149,7 @@ function handlePointer(pointer: Phaser.Input.Pointer) {
}
function clearTiles() {
if (mapEditor.currentMap.value.mapEventTiles.length === 0) return
if (mapEditor.currentMap.value?.mapEventTiles.length === 0) return
createCommandUpdate(null, 'clear')
finalizeCommand()
}

View File

@ -18,7 +18,7 @@ import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { getTile } from '@/services/mapService'
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 TilemapLayer = Phaser.Tilemaps.TilemapLayer
@ -129,7 +129,7 @@ function moveMapObject(id: string, map: MapT) {
const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY)
if (!tile) return
console.log(id)
map.placedMapObjects.map((placed) => {
if (placed.id === id) {
placed.positionX = tile.x

View File

@ -39,6 +39,7 @@ import { SocketEvent } from '@/application/enums'
import type { Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { socketManager } from '@/managers/SocketManager'
import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore'
import { ref, useTemplateRef } from 'vue'
@ -57,7 +58,7 @@ const pvp = ref(false)
defineExpose({ open: () => modalRef.value?.open() })
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) {
return
}

View File

@ -34,6 +34,7 @@ import type { Map } from '@/application/types'
import CreateMap from '@/components/gameMaster/mapEditor/partials/CreateMap.vue'
import Modal from '@/components/utilities/Modal.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { socketManager } from '@/managers/SocketManager'
import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore'
import { onMounted, ref, useTemplateRef } from 'vue'
@ -61,14 +62,14 @@ async function fetchMaps() {
}
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)
})
modalRef.value?.close()
}
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) {
gameStore.addNotification({
title: 'Error',

View File

@ -1,10 +1,15 @@
<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="flex flex-col gap-2.5 p-2.5">
<div class="relative flex">
<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 class="flex justify-between items-center">
<div class="flex-grow">
<div class="relative flex">
<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 class="flex">
<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 Modal from '@/components/utilities/Modal.vue'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { socketManager } from '@/managers/SocketManager'
import { MapObjectStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore'
import { onMounted, ref } from 'vue'
@ -81,7 +82,7 @@ const handleDelete = () => {
async function handleUpdate() {
if (!mapObject.value) return
gameStore.connection?.emit(
socketManager.emit(
SocketEvent.GM_MAPOBJECT_UPDATE,
{
id: props.placedMapObject.mapObject as string,

View File

@ -1,5 +1,5 @@
<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>
<h3 class="m-0 font-medium shrink-0 text-white">Teleport settings</h3>
</template>
@ -28,7 +28,7 @@
<label for="toMap">Map to teleport to</label>
<select v-model="toMap" class="input-field" name="toMap" id="toMap">
<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>
</div>
</div>
@ -39,51 +39,50 @@
</template>
<script setup lang="ts">
import { SocketEvent } from '@/application/enums'
import type { Map } from '@/application/types'
import Modal from '@/components/utilities/Modal.vue'
import { useGameStore } from '@/stores/gameStore'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { MapStorage } from '@/storage/storages'
import { computed, onMounted, ref, useTemplateRef, watch } from 'vue'
const showTeleportModal = computed(() => mapEditorStore.tool === 'pencil' && mapEditorStore.drawMode === 'teleport')
const mapEditorStore = useMapEditorStore()
const gameStore = useGameStore()
const mapList = ref<Map[]>([])
const showTeleportModal = computed(() => mapEditor.tool.value === 'pencil' && mapEditor.drawMode.value === 'teleport')
const mapStorage = new MapStorage()
const mapEditor = useMapEditorComposable()
const modalRef = useTemplateRef('modalRef')
const mapList = ref<Map[]>([])
defineExpose({
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()
function useRefTeleportSettings() {
const settings = mapEditorStore.teleportSettings
const settings = mapEditor.teleportSettings.value
return {
toPositionX: ref(settings.toPositionX),
toPositionY: ref(settings.toPositionY),
toRotation: ref(settings.toRotation),
toMap: ref(settings.toMapId)
toMap: ref(settings.toMap)
}
}
watch([toPositionX, toPositionY, toRotation, toMap], updateTeleportSettings)
function updateTeleportSettings() {
mapEditorStore.setTeleportSettings({
mapEditor.setTeleportSettings({
toPositionX: toPositionX.value,
toPositionY: toPositionY.value,
toRotation: toRotation.value,
toMapId: toMap.value
toMap: toMap.value
})
}
async function fetchMaps() {
mapList.value = await mapStorage.getAll()
}
onMounted(async () => {
await fetchMaps()
})
</script>

View File

@ -1,10 +1,15 @@
<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="flex flex-col gap-2.5 p-2.5">
<div class="relative flex">
<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 class="flex justify-between items-center">
<div class="flex-grow">
<div class="relative flex">
<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 class="flex">
<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 isContinuousDrawingEnabled = ref<Boolean>(false)
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
function setDrawMode(value: string) {
@ -148,6 +148,7 @@ function handleModeClick(mode: string, type: 'pencil' | 'eraser') {
function handleClick(tool: string) {
mapEditor.setTool(tool)
if (tool === 'paint') mapEditor.setDrawMode('tile')
selectPencilOpen.value = tool === 'pencil' ? !selectPencilOpen.value : false
selectEraserOpen.value = tool === 'eraser' ? !selectEraserOpen.value : false
if (mapEditor.drawMode.value === 'teleport') emit('open-teleport')

View File

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

View File

@ -26,6 +26,7 @@
</template>
<script setup lang="ts">
import { socketManager } from '@/managers/SocketManager'
import { login, register } from '@/services/authenticationService'
import { useGameStore } from '@/stores/gameStore'
import { useCookies } from '@vueuse/integrations/useCookies'
@ -67,7 +68,7 @@ async function submit() {
return
}
gameStore.setToken(loginResponse.token)
socketManager.setToken(loginResponse.token)
gameStore.initConnection()
}
</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 Modal from '@/components/utilities/Modal.vue'
import { useSoundComposable } from '@/composables/useSoundComposable'
import { socketManager } from '@/managers/SocketManager'
import { CharacterHairStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
@ -142,11 +143,10 @@ const selectedHairId = ref<string | null>(null)
// Fetch characters
setTimeout(() => {
console.log(SocketEvent.CHARACTER_LIST)
gameStore.connection?.emit(SocketEvent.CHARACTER_LIST)
socketManager.emit(SocketEvent.CHARACTER_LIST)
}, 750)
gameStore.connection?.on(SocketEvent.CHARACTER_LIST, (data: any) => {
socketManager.on(SocketEvent.CHARACTER_LIST, (data: any) => {
characters.value = data
isLoading.value = false
})
@ -155,7 +155,7 @@ gameStore.connection?.on(SocketEvent.CHARACTER_LIST, (data: any) => {
function loginWithCharacter() {
if (!selectedCharacterId.value) return
gameStore.connection?.emit(
socketManager.emit(
SocketEvent.CHARACTER_CONNECT,
{
characterId: selectedCharacterId.value,
@ -169,7 +169,7 @@ function loginWithCharacter() {
// Create character logics
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
isCreateNewCharacterModalOpen.value = false
})
@ -188,8 +188,8 @@ onMounted(async () => {
})
onBeforeUnmount(() => {
gameStore.connection?.off(SocketEvent.CHARACTER_LIST)
gameStore.connection?.off(SocketEvent.CHARACTER_CONNECT)
gameStore.connection?.off(SocketEvent.CHARACTER_CREATE)
socketManager.off(SocketEvent.CHARACTER_LIST)
socketManager.off(SocketEvent.CHARACTER_CONNECT)
socketManager.off(SocketEvent.CHARACTER_CREATE)
})
</script>

View File

@ -20,6 +20,7 @@
<script setup lang="ts">
import config from '@/application/config'
import { SocketEvent } from '@/application/enums'
import { socketManager } from '@/managers/SocketManager'
import 'phaser'
import type { Map as MapT } from '@/application/types'
import Map from '@/components/gameMaster/mapEditor/Map.vue'
@ -92,7 +93,7 @@ function save() {
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)
})
}

View File

@ -1,10 +1,14 @@
<template></template>
<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 { TextureStorage } from '@/storage/textureStorage'
import { useGameStore } from '@/stores/gameStore'
import { onMounted, onUnmounted } from 'vue'
const gameStore = useGameStore()
const mapStorage = new MapStorage()
const tileStorage = new TileStorage()
const mapObjectStorage = new MapObjectStorage()
@ -37,6 +41,17 @@ async function handleKeyPress(event: KeyboardEvent) {
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
setTimeout(() => {
currentString = ''

View File

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

View File

@ -1,4 +1,5 @@
import { SocketEvent } from '@/application/enums'
import { socketManager } from '@/managers/SocketManager'
import { getTile } from '@/services/mapService'
import { useGameStore } from '@/stores/gameStore'
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) {
const gameStore = useGameStore()
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) {
baseHandlers.startDragging(pointer)
}
@ -23,70 +94,37 @@ export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Til
const pointerTile = getTile(layer, pointer.worldX, pointer.worldY)
if (!pointerTile) return
gameStore.connection?.emit(SocketEvent.MAP_CHARACTER_MOVE, {
positionX: pointerTile.x,
positionY: pointerTile.y
})
emitMovement(pointerTile.x, pointerTile.y)
}
const pressedKeys = new Set<string>()
let moveInterval: number | null = null
// Keyboard Handlers
function handleKeyDown(event: KeyboardEvent) {
if (!gameStore.character) return
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
// Prevent key repeat events
if (ARROW_KEYS.includes(event.key as (typeof ARROW_KEYS)[number])) {
if (event.repeat) return
pressedKeys.add(event.key)
// Start movement loop if not already running
if (!moveInterval) {
moveInterval = window.setInterval(moveCharacter, 80) // Increased interval to match server throttle `MOVEMENT_THROTTLE`
moveCharacter() // Move immediately on first press
}
updateCurrentPosition()
startMovementLoop()
}
// Attack on CTRL
if (event.key === 'Control') {
gameStore.connection?.emit(SocketEvent.MAP_CHARACTER_ATTACK)
socketManager.emit(SocketEvent.MAP_CHARACTER_ATTACK)
}
}
function handleKeyUp(event: KeyboardEvent) {
pressedKeys.delete(event.key)
// If no movement keys are pressed, clear the interval
if (pressedKeys.size === 0 && moveInterval) {
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
})
if (pressedKeys.size === 0) {
stopMovementLoop()
}
}
const setupControls = () => {
updateCurrentPosition() // Initialize position
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_UP, handlePointerUp)
@ -96,6 +134,9 @@ export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Til
}
const cleanupControls = () => {
stopMovementLoop()
pressedKeys.clear()
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_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 updateIsometricDepth = (positionX: number, positionY: number) => {
isometricDepth.value = calculateIsometricDepth(positionX, positionY, 30, 95)
isometricDepth.value = calculateIsometricDepth(positionX, positionY)
}
const updatePosition = (positionX: number, positionY: number) => {

View File

@ -1,8 +1,9 @@
import type { Map, MapObject, PlacedMapObject, UUID } from '@/application/types'
import { useGameStore } from '@/stores/gameStore'
import { ref } from 'vue'
export type TeleportSettings = {
toMapId: string
toMap: string
toPositionX: number
toPositionY: number
toRotation: number
@ -20,7 +21,7 @@ const movingPlacedObject = ref<PlacedMapObject | null>(null)
const selectedPlacedObject = ref<PlacedMapObject | null>(null)
const shouldClearTiles = ref(false)
const teleportSettings = ref<TeleportSettings>({
toMapId: '1000',
toMap: '1000',
toPositionX: 0,
toPositionY: 0,
toRotation: 0
@ -46,6 +47,8 @@ export function useMapEditorComposable() {
const toggleActive = () => {
if (active.value) reset()
active.value = !active.value
const gameStore = useGameStore()
gameStore.uiSettings.isGmPanelOpen = false
}
const togglePlacedMapObjectPreview = () => {
@ -95,6 +98,7 @@ export function useMapEditorComposable() {
selectedTile.value = ''
isPlacedMapObjectPreviewEnabled.value = false
selectedMapObject.value = null
selectedPlacedObject.value = null
shouldClearTiles.value = false
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))
}
export const calculateIsometricDepth = (positionX: number, positionY: number, width: number = 0, height: number = 0, isCharacter: boolean = false) => {
const baseDepth = positionX + positionY
if (isCharacter) {
return baseDepth
}
return baseDepth + (width + height) / (2 * config.tile_size.width)
export const calculateIsometricDepth = (positionX: number, positionY: number, pivotPoints: { x: number; y: number }[] = []) => {
return Math.max(positionX + positionY)
}
async function loadTileTextures(tiles: TileT[], scene: Phaser.Scene) {

View File

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

View File

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

View File

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