i dont even remember, something, something, zone editor

This commit is contained in:
Dennis Postma 2024-06-13 20:28:34 +02:00
parent 12445db7f1
commit 4bc076d55d
17 changed files with 479 additions and 207 deletions

210
package-lock.json generated
View File

@ -743,9 +743,9 @@
} }
}, },
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
"integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -760,9 +760,9 @@
} }
}, },
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
"integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -777,9 +777,9 @@
} }
}, },
"node_modules/@esbuild/android-arm64": { "node_modules/@esbuild/android-arm64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
"integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -794,9 +794,9 @@
} }
}, },
"node_modules/@esbuild/android-x64": { "node_modules/@esbuild/android-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
"integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -811,9 +811,9 @@
} }
}, },
"node_modules/@esbuild/darwin-arm64": { "node_modules/@esbuild/darwin-arm64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
"integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -828,9 +828,9 @@
} }
}, },
"node_modules/@esbuild/darwin-x64": { "node_modules/@esbuild/darwin-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -845,9 +845,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-arm64": { "node_modules/@esbuild/freebsd-arm64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
"integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -862,9 +862,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-x64": { "node_modules/@esbuild/freebsd-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
"integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -879,9 +879,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm": { "node_modules/@esbuild/linux-arm": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
"integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -896,9 +896,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm64": { "node_modules/@esbuild/linux-arm64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
"integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -913,9 +913,9 @@
} }
}, },
"node_modules/@esbuild/linux-ia32": { "node_modules/@esbuild/linux-ia32": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
"integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -930,9 +930,9 @@
} }
}, },
"node_modules/@esbuild/linux-loong64": { "node_modules/@esbuild/linux-loong64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
"integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -947,9 +947,9 @@
} }
}, },
"node_modules/@esbuild/linux-mips64el": { "node_modules/@esbuild/linux-mips64el": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
"integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@ -964,9 +964,9 @@
} }
}, },
"node_modules/@esbuild/linux-ppc64": { "node_modules/@esbuild/linux-ppc64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
"integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -981,9 +981,9 @@
} }
}, },
"node_modules/@esbuild/linux-riscv64": { "node_modules/@esbuild/linux-riscv64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
"integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -998,9 +998,9 @@
} }
}, },
"node_modules/@esbuild/linux-s390x": { "node_modules/@esbuild/linux-s390x": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
"integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -1015,9 +1015,9 @@
} }
}, },
"node_modules/@esbuild/linux-x64": { "node_modules/@esbuild/linux-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
"integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1032,9 +1032,9 @@
} }
}, },
"node_modules/@esbuild/netbsd-x64": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
"integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1049,9 +1049,9 @@
} }
}, },
"node_modules/@esbuild/openbsd-x64": { "node_modules/@esbuild/openbsd-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
"integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1066,9 +1066,9 @@
} }
}, },
"node_modules/@esbuild/sunos-x64": { "node_modules/@esbuild/sunos-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
"integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1083,9 +1083,9 @@
} }
}, },
"node_modules/@esbuild/win32-arm64": { "node_modules/@esbuild/win32-arm64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
"integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1100,9 +1100,9 @@
} }
}, },
"node_modules/@esbuild/win32-ia32": { "node_modules/@esbuild/win32-ia32": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
"integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -1117,9 +1117,9 @@
} }
}, },
"node_modules/@esbuild/win32-x64": { "node_modules/@esbuild/win32-x64": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
"integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2944,9 +2944,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001632", "version": "1.0.30001633",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001632.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz",
"integrity": "sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==", "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -3411,9 +3411,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.799", "version": "1.4.802",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.799.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz",
"integrity": "sha512-3D3DwWkRTzrdEpntY0hMLYwj7SeBk1138CkPE8sBDSj3WzrzOiG2rHm3luw8jucpf+WiyLBCZyU9lMHyQI9M9Q==", "integrity": "sha512-TnTMUATbgNdPXVSHsxvNVSG0uEd6cSZsANjm8c9HbvflZVVn1yTRcmVXYT1Ma95/ssB/Dcd30AHweH2TE+dNpA==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -3490,9 +3490,9 @@
} }
}, },
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.20.2", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
"integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
@ -3503,29 +3503,29 @@
"node": ">=12" "node": ">=12"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/aix-ppc64": "0.20.2", "@esbuild/aix-ppc64": "0.21.5",
"@esbuild/android-arm": "0.20.2", "@esbuild/android-arm": "0.21.5",
"@esbuild/android-arm64": "0.20.2", "@esbuild/android-arm64": "0.21.5",
"@esbuild/android-x64": "0.20.2", "@esbuild/android-x64": "0.21.5",
"@esbuild/darwin-arm64": "0.20.2", "@esbuild/darwin-arm64": "0.21.5",
"@esbuild/darwin-x64": "0.20.2", "@esbuild/darwin-x64": "0.21.5",
"@esbuild/freebsd-arm64": "0.20.2", "@esbuild/freebsd-arm64": "0.21.5",
"@esbuild/freebsd-x64": "0.20.2", "@esbuild/freebsd-x64": "0.21.5",
"@esbuild/linux-arm": "0.20.2", "@esbuild/linux-arm": "0.21.5",
"@esbuild/linux-arm64": "0.20.2", "@esbuild/linux-arm64": "0.21.5",
"@esbuild/linux-ia32": "0.20.2", "@esbuild/linux-ia32": "0.21.5",
"@esbuild/linux-loong64": "0.20.2", "@esbuild/linux-loong64": "0.21.5",
"@esbuild/linux-mips64el": "0.20.2", "@esbuild/linux-mips64el": "0.21.5",
"@esbuild/linux-ppc64": "0.20.2", "@esbuild/linux-ppc64": "0.21.5",
"@esbuild/linux-riscv64": "0.20.2", "@esbuild/linux-riscv64": "0.21.5",
"@esbuild/linux-s390x": "0.20.2", "@esbuild/linux-s390x": "0.21.5",
"@esbuild/linux-x64": "0.20.2", "@esbuild/linux-x64": "0.21.5",
"@esbuild/netbsd-x64": "0.20.2", "@esbuild/netbsd-x64": "0.21.5",
"@esbuild/openbsd-x64": "0.20.2", "@esbuild/openbsd-x64": "0.21.5",
"@esbuild/sunos-x64": "0.20.2", "@esbuild/sunos-x64": "0.21.5",
"@esbuild/win32-arm64": "0.20.2", "@esbuild/win32-arm64": "0.21.5",
"@esbuild/win32-ia32": "0.20.2", "@esbuild/win32-ia32": "0.21.5",
"@esbuild/win32-x64": "0.20.2" "@esbuild/win32-x64": "0.21.5"
} }
}, },
"node_modules/escalade": { "node_modules/escalade": {
@ -6594,13 +6594,13 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.2.13", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.0.tgz",
"integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==", "integrity": "sha512-hA6vAVK977NyW1Qw+fLvqSo7xDPej7von7C3DwwqPRmnnnK36XEBC/J3j1V5lP8fbt7y0TgTKJbpNGSwM+Bdeg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "^0.20.1", "esbuild": "^0.21.3",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"rollup": "^4.13.0" "rollup": "^4.13.0"
}, },

View File

@ -0,0 +1 @@
<svg height="492pt" viewBox="0 0 492.49284 492" width="492pt" xmlns="http://www.w3.org/2000/svg"><path d="m304.140625 82.472656-270.976563 270.996094c-1.363281 1.367188-2.347656 3.09375-2.816406 4.949219l-30.035156 120.554687c-.898438 3.628906.167969 7.488282 2.816406 10.136719 2.003906 2.003906 4.734375 3.113281 7.527344 3.113281.855469 0 1.730469-.105468 2.582031-.320312l120.554688-30.039063c1.878906-.46875 3.585937-1.449219 4.949219-2.8125l271-270.976562zm0 0"/><path d="m476.875 45.523438-30.164062-30.164063c-20.160157-20.160156-55.296876-20.140625-75.433594 0l-36.949219 36.949219 105.597656 105.597656 36.949219-36.949219c10.070312-10.066406 15.617188-23.464843 15.617188-37.714843s-5.546876-27.648438-15.617188-37.71875zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 745 B

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,5 +1,5 @@
<template> <template>
<TilemapLayerC :tilemap="tileMap" :tileset="zoneStore.tiles" ref="tilemapLayer" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" /> <TilemapLayerC :tilemap="tileMap" :tileset="zoneStore.tiles" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" />
<Controls :layer="layer" /> <Controls :layer="layer" />
<Container> <Container>
<Character :layer="layer" v-for="character in zoneStore.characters" :key="character.id" :character="character" /> <Character :layer="layer" v-for="character in zoneStore.characters" :key="character.id" :character="character" />
@ -17,19 +17,13 @@ import { onBeforeMount, onBeforeUnmount, ref, type Ref, watch } from 'vue'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
import { useSocketStore } from '@/stores/socket' import { useSocketStore } from '@/stores/socket'
import { useZoneStore } from '@/stores/zone' import { useZoneStore } from '@/stores/zone'
import { generateTilemap } from '@/services/zone'
// Phavuer logic // Phavuer logic
let scene = useScene() let scene = useScene()
let tilemapLayer = ref() let tilemapLayer = ref()
let zoneData = new Phaser.Tilemaps.MapData({
width: 10, // @TODO : get this from the server const tileMap = generateTilemap(scene, 10, 10);
height: 10, // @TODO : get this from the server
tileWidth: config.tile_size.x,
tileHeight: config.tile_size.y,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
format: Phaser.Tilemaps.Formats.ARRAY_2D
})
let tileMap = new Phaser.Tilemaps.Tilemap(scene, zoneData)
let tileset: Tileset = tileMap.addTilesetImage('default', 'tiles') as Tileset let tileset: Tileset = tileMap.addTilesetImage('default', 'tiles') as Tileset
let layer: TilemapLayer = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) as TilemapLayer let layer: TilemapLayer = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) as TilemapLayer
@ -46,7 +40,7 @@ const socket = useSocketStore()
watch( watch(
() => zoneStore.tiles, () => zoneStore.tiles,
() => { () => {
// @TODO : change to tiles for when loading other maps // @TODO : change to zone for when loading other maps
zoneStore.tiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y))) zoneStore.tiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y)))
}, },
{ deep: true } { deep: true }
@ -54,7 +48,7 @@ watch(
// Load the zone from the server // Load the zone from the server
onBeforeMount(() => { onBeforeMount(() => {
socket.connection.emit('character:zone:load', { zoneId: socket.character.zoneId }) socket.connection.emit('character:zone:request', { zoneId: socket.character.zoneId })
}) })
// Listen for the zone event from the server and load the zone // Listen for the zone event from the server and load the zone
@ -73,7 +67,7 @@ socket.connection.on('zone:character:join', (data: CharacterType) => {
}) })
// Listen for user:disconnect // Listen for user:disconnect
socket.connection.on('user:disconnect', (data: CharacterType) => { socket.connection.on('zone:character:leave', (data: CharacterType) => {
zoneStore.removeCharacter(data) zoneStore.removeCharacter(data)
}) })
@ -83,6 +77,8 @@ socket.connection.on('character:moved', (data: CharacterType) => {
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
zoneStore.reset();
socket.connection.emit('character:zone:leave')
socket.connection.off('character:zone:load') socket.connection.off('character:zone:load')
socket.connection.off('zone:character:join') socket.connection.off('zone:character:join')
socket.connection.off('user:disconnect') socket.connection.off('user:disconnect')

View File

@ -53,7 +53,7 @@ scene.input.on(Phaser.Input.Events.POINTER_MOVE, dragZone)
watch( watch(
() => zoneEditorStore.tool, () => { () => zoneEditorStore.tool, () => {
// @TODO : change to tiles for when loading other maps // @TODO : change to zone for when loading other maps
if (zoneEditorStore.tool === 'move') { if (zoneEditorStore.tool === 'move') {
scene.input.on(Phaser.Input.Events.POINTER_MOVE, dragZone) scene.input.on(Phaser.Input.Events.POINTER_MOVE, dragZone)
} else { } else {

View File

@ -0,0 +1,105 @@
<template>
<Teleport to="body">
<Modal v-if="isModalOpen" :isModalOpen="true" :closable="false" :modal-width="645" :modal-height="260">
<template #modalHeader>
<h3 class="modal-title">Walls</h3>
</template>
<template #modalBody>
<canvas ref="canvas" :width="wallWidth" :height="wallHeight" style="display: none"></canvas>
<div class="walls">
<img v-for="(wall, index) in walls" :key="index" :src="wall" alt="Wall" @click="zoneEditorStore.setSelectedWall(index)" :class="{ selected: zoneEditorStore.selectedWall && zoneEditorStore.selectedWall === index }" />
</div>
</template>
</Modal>
</Teleport>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import config from '@/config'
import Modal from '@/components/utilities/Modal.vue'
import { useZoneEditorStore } from '@/stores/zoneEditor'
const wallWidth = config.wall_size.x
const wallHeight = config.wall_size.y
const walls = ref<string[]>([])
const selectedWall = ref<number | null>(null)
const canvas = ref<HTMLCanvasElement | null>(null)
const isModalOpen = ref(false)
const zoneEditorStore = useZoneEditorStore()
// Hardcoded image path
const imagePath = '/assets/zone/walls.png'
const loadImage = (src: string): Promise<HTMLImageElement> => {
return new Promise((resolve) => {
const img = new Image()
img.onload = () => resolve(img)
img.src = src
})
}
const splitWalls = (img: HTMLImageElement) => {
if (!canvas.value) {
console.error('Canvas not found')
return
}
const ctx = canvas.value.getContext('2d')
if (!ctx) {
console.error('Failed to get canvas context')
return
}
const wallsetWidth = img.width
const wallsetHeight = img.height
const columns = Math.floor(wallsetWidth / wallWidth)
const rows = Math.floor(wallsetHeight / wallHeight)
walls.value = []
selectedWall.value = null
for (let row = 0; row < rows; row++) {
for (let col = 0; col < columns; col++) {
const x = col * wallWidth
const y = row * wallHeight
ctx.clearRect(0, 0, wallWidth, wallHeight)
ctx.drawImage(img, x, y, wallWidth, wallHeight, 0, 0, wallWidth, wallHeight)
const wallDataURL = canvas.value.toDataURL()
walls.value.push(wallDataURL)
}
}
}
const selectWall = (index: number) => {
selectedWall.value = index
}
onMounted(async () => {
isModalOpen.value = true
const img = await loadImage(imagePath)
await nextTick()
splitWalls(img)
})
</script>
<style lang="scss">
.walls {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.walls img {
width: 30px;
height: 130px;
cursor: pointer;
border: 2px solid transparent;
transition: border 0.3s ease;
}
.walls img.selected {
border: 2px solid #ff0000;
}
</style>

View File

@ -29,7 +29,7 @@ const isModalOpen = ref(false)
const zoneEditorStore = useZoneEditorStore() const zoneEditorStore = useZoneEditorStore()
// Hardcoded image path // Hardcoded image path
const imagePath = '/assets/tiles/default.png' const imagePath = '/assets/zone/tiles.png'
const loadImage = (src: string): Promise<HTMLImageElement> => { const loadImage = (src: string): Promise<HTMLImageElement> => {
return new Promise((resolve) => { return new Promise((resolve) => {

View File

@ -6,31 +6,36 @@
<img src="/assets/icons/zoneEditor/move.svg" alt="Move camera" /> <img src="/assets/icons/zoneEditor/move.svg" alt="Move camera" />
</button> </button>
<div class="divider"></div> <div class="divider"></div>
<button :class="{ active: zoneEditorStore.tool === 'tile' }" @click="zoneEditorStore.setTool('tile')"> <button :class="{ active: zoneEditorStore.tool === 'pencil' }" @click="zoneEditorStore.setTool('pencil')">
<img src="/assets/icons/zoneEditor/tiles.svg" alt="Draw tiles" /> <img src="/assets/icons/zoneEditor/pencil.svg" alt="Pencil" />
<select v-model="drawMode" v-if="zoneEditorStore.tool === 'pencil'">
<option value="tile" :selected="zoneEditorStore.drawMode === 'tile'">tile</option>
<option value="wall" :selected="zoneEditorStore.drawMode === 'wall'">wall</option>
<option value="decoration" :selected="zoneEditorStore.drawMode === 'decoration'">decoration</option>
<option value="teleport" :selected="zoneEditorStore.drawMode === 'teleport'">teleport</option>
<option value="blocking_tile" :selected="zoneEditorStore.drawMode === 'blocking_tile'">blocking tile</option>
</select>
</button> </button>
<div class="divider"></div> <div class="divider"></div>
<button :class="{ active: zoneEditorStore.tool === 'eraser' }" @click="zoneEditorStore.setTool('eraser')"> <button :class="{ active: zoneEditorStore.tool === 'eraser' }" @click="zoneEditorStore.setTool('eraser')">
<img src="/assets/icons/zoneEditor/eraser.svg" alt="Eraser" /> <img src="/assets/icons/zoneEditor/eraser.svg" alt="Eraser" />
<select v-model="drawMode" v-if="zoneEditorStore.tool === 'eraser'">
<option value="tile" :selected="zoneEditorStore.drawMode === 'tile'">tile</option>
<option value="wall" :selected="zoneEditorStore.drawMode === 'wall'">wall</option>
<option value="decoration" :selected="zoneEditorStore.drawMode === 'decoration'">decoration</option>
<option value="teleport" :selected="zoneEditorStore.drawMode === 'teleport'">teleport</option>
<option value="blocking_tile" :selected="zoneEditorStore.drawMode === 'blocking_tile'">blocking tile</option>
</select>
</button> </button>
<div class="divider"></div> <div class="divider"></div>
<button> <button @click="() => zoneEditorStore.toggleZoneSettings()">
<img src="/assets/icons/zoneEditor/gear.svg" alt="Zone settings" /> <img src="/assets/icons/zoneEditor/gear.svg" alt="Zone settings" />
</button> </button>
<div class="divider"></div>
<button>
<img src="/assets/icons/zoneEditor/monster.svg" alt="Zone settings" />
</button>
<div class="divider"></div>
<button>
<img src="/assets/icons/zoneEditor/cart.svg" alt="Zone settings" />
</button>
</div> </div>
<div class="buttons"> <div class="buttons">
<button class="btn-cyan">Save as new</button>
<button class="btn-cyan">Save</button> <button class="btn-cyan">Save</button>
<button class="btn-cyan">Load</button> <button class="btn-cyan">Load</button>
<button class="btn-cyan">Clear</button> <button class="btn-cyan" @click="clear">Clear</button>
<button class="btn-cyan" @click="() => zoneEditorStore.toggleActive()">Exit</button> <button class="btn-cyan" @click="() => zoneEditorStore.toggleActive()">Exit</button>
</div> </div>
</div> </div>
@ -38,7 +43,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onBeforeUnmount, ref } from 'vue' import { onBeforeUnmount, ref, watch } from 'vue'
import { useScene } from 'phavuer' import { useScene } from 'phavuer'
import { getTile, tileToWorldXY } from '@/services/zone' import { getTile, tileToWorldXY } from '@/services/zone'
import config from '@/config' import config from '@/config'
@ -51,7 +56,15 @@ const props = defineProps({
layer: Phaser.Tilemaps.TilemapLayer layer: Phaser.Tilemaps.TilemapLayer
}) })
const scene = useScene() const scene = useScene()
const emit = defineEmits(['erase', 'move', 'tile']) const emit = defineEmits(['move', 'eraser', 'pencil'])
// drawMode
const drawMode = ref('tile')
// on change of select
watch(drawMode, (value) => {
zoneEditorStore.setDrawMode(value)
})
function drawTiles(pointer: Phaser.Input.Pointer) { function drawTiles(pointer: Phaser.Input.Pointer) {
if (!pointer.isDown) return if (!pointer.isDown) return
@ -65,11 +78,11 @@ function drawTiles(pointer: Phaser.Input.Pointer) {
} }
if (zoneEditorStore.tool === 'eraser') { if (zoneEditorStore.tool === 'eraser') {
emit('erase', pointer_tile) emit('eraser', pointer_tile)
} }
if (zoneEditorStore.tool === 'tile') { if (zoneEditorStore.tool === 'pencil') {
emit('tile', pointer_tile) emit('pencil', pointer_tile)
} }
} }
@ -78,6 +91,10 @@ scene.input.on(Phaser.Input.Events.POINTER_MOVE, drawTiles)
onBeforeUnmount(() => { onBeforeUnmount(() => {
scene.input.off(Phaser.Input.Events.POINTER_MOVE, drawTiles) scene.input.off(Phaser.Input.Events.POINTER_MOVE, drawTiles)
}) })
function clear() {
zoneEditorStore.setTiles(Array.from({ length: zoneEditorStore.zoneSettings?.width ?? 10 }, () => Array.from({ length: zoneEditorStore.zoneSettings?.height ?? 10 }, () => 0)))
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -0,0 +1,105 @@
<template>
<Teleport to="body">
<Modal v-if="isModalOpen" :isModalOpen="true" :closable="false" :modal-width="645" :modal-height="260">
<template #modalHeader>
<h3 class="modal-title">Walls</h3>
</template>
<template #modalBody>
<canvas ref="canvas" :width="wallWidth" :height="wallHeight" style="display: none"></canvas>
<div class="walls">
<img v-for="(wall, index) in walls" :key="index" :src="wall" alt="Wall" @click="zoneEditorStore.setSelectedWall(index)" :class="{ selected: zoneEditorStore.selectedWall && zoneEditorStore.selectedWall === index }" />
</div>
</template>
</Modal>
</Teleport>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import config from '@/config'
import Modal from '@/components/utilities/Modal.vue'
import { useZoneEditorStore } from '@/stores/zoneEditor'
const wallWidth = config.wall_size.x
const wallHeight = config.wall_size.y
const walls = ref<string[]>([])
const selectedWall = ref<number | null>(null)
const canvas = ref<HTMLCanvasElement | null>(null)
const isModalOpen = ref(false)
const zoneEditorStore = useZoneEditorStore()
// Hardcoded image path
const imagePath = '/assets/zone/walls.png'
const loadImage = (src: string): Promise<HTMLImageElement> => {
return new Promise((resolve) => {
const img = new Image()
img.onload = () => resolve(img)
img.src = src
})
}
const splitWalls = (img: HTMLImageElement) => {
if (!canvas.value) {
console.error('Canvas not found')
return
}
const ctx = canvas.value.getContext('2d')
if (!ctx) {
console.error('Failed to get canvas context')
return
}
const wallsetWidth = img.width
const wallsetHeight = img.height
const columns = Math.floor(wallsetWidth / wallWidth)
const rows = Math.floor(wallsetHeight / wallHeight)
walls.value = []
selectedWall.value = null
for (let row = 0; row < rows; row++) {
for (let col = 0; col < columns; col++) {
const x = col * wallWidth
const y = row * wallHeight
ctx.clearRect(0, 0, wallWidth, wallHeight)
ctx.drawImage(img, x, y, wallWidth, wallHeight, 0, 0, wallWidth, wallHeight)
const wallDataURL = canvas.value.toDataURL()
walls.value.push(wallDataURL)
}
}
}
const selectWall = (index: number) => {
selectedWall.value = index
}
onMounted(async () => {
isModalOpen.value = true
const img = await loadImage(imagePath)
await nextTick()
splitWalls(img)
})
</script>
<style lang="scss">
.walls {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.walls img {
width: 30px;
height: 130px;
cursor: pointer;
border: 2px solid transparent;
transition: border 0.3s ease;
}
.walls img.selected {
border: 2px solid #ff0000;
}
</style>

View File

@ -1,9 +1,10 @@
<template> <template>
<TilemapLayerC :tilemap="tileMap" :tileset="zoneStore.tiles" ref="tilemapLayer" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" /> <TilemapLayerC :tilemap="tileMap" :tileset="zoneEditorStore.tiles" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" />
<Controls :layer="layer" /> <Controls :layer="layer" />
<Toolbar :layer="layer" @erase="erase" @tile="tile" /> <Toolbar :layer="layer" @eraser="eraser" @pencil="pencil" />
<Tiles /> <Tiles v-if="zoneEditorStore.tool === 'pencil' || zoneEditorStore.tool === 'eraser'" />
<ZoneSettings /> <Walls v-if="zoneEditorStore.tool === 'pencil' || zoneEditorStore.tool === 'eraser'" />
<ZoneSettings v-if="zoneEditorStore.zoneSettingsOpen" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -11,27 +12,22 @@ import config from '@/config'
import Tileset = Phaser.Tilemaps.Tileset import Tileset = Phaser.Tilemaps.Tileset
import TilemapLayer = Phaser.Tilemaps.TilemapLayer import TilemapLayer = Phaser.Tilemaps.TilemapLayer
import { Container, TilemapLayer as TilemapLayerC, useScene } from 'phavuer' import { Container, TilemapLayer as TilemapLayerC, useScene } from 'phavuer'
import { onBeforeMount, ref, type Ref, watch } from 'vue' import { onBeforeMount, onBeforeUnmount, ref, type Ref, watch } from 'vue'
import Controls from '@/components/utilities/Controls.vue' import Controls from '@/components/utilities/Controls.vue'
import { useSocketStore } from '@/stores/socket' import { useSocketStore } from '@/stores/socket'
import { useZoneStore } from '@/stores/zone'
import Toolbar from '@/components/utilities/zoneEditor/Toolbar.vue' import Toolbar from '@/components/utilities/zoneEditor/Toolbar.vue'
import Tiles from '@/components/utilities/zoneEditor/Tiles.vue' import Tiles from '@/components/utilities/zoneEditor/Tiles.vue'
import { useZoneEditorStore } from '@/stores/zoneEditor' import { useZoneEditorStore } from '@/stores/zoneEditor'
import ZoneSettings from '@/components/utilities/zoneEditor/ZoneSettings.vue' import ZoneSettings from '@/components/utilities/zoneEditor/ZoneSettings.vue'
import Walls from '@/components/utilities/zoneEditor/Walls.vue'
import { generateTilemap } from '@/services/zone'
// Phavuer logic // Phavuer logic
let scene = useScene() let scene = useScene()
let tilemapLayer = ref() const socket = useSocketStore()
let zoneData = new Phaser.Tilemaps.MapData({ const zoneEditorStore = useZoneEditorStore()
width: 10, // @TODO : get this from the server
height: 10, // @TODO : get this from the server let tileMap = generateTilemap(scene, 10, 10);
tileWidth: config.tile_size.x,
tileHeight: config.tile_size.y,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
format: Phaser.Tilemaps.Formats.ARRAY_2D
})
let tileMap = new Phaser.Tilemaps.Tilemap(scene, zoneData)
let tileset: Tileset = tileMap.addTilesetImage('default', 'tiles') as Tileset let tileset: Tileset = tileMap.addTilesetImage('default', 'tiles') as Tileset
let layer: TilemapLayer = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) as TilemapLayer let layer: TilemapLayer = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) as TilemapLayer
@ -40,41 +36,40 @@ const centerY = (tileMap.height * tileMap.tileHeight) / 2
const centerX = (tileMap.width * tileMap.tileWidth) / 2 const centerX = (tileMap.width * tileMap.tileWidth) / 2
scene.cameras.main.centerOn(centerX, centerY) scene.cameras.main.centerOn(centerX, centerY)
// Multiplayer / server logics onBeforeMount(() => {
const zoneStore = useZoneStore() socket.connection.emit('gm:zone_editor:zone:request', { zoneId: socket.character.zoneId })
const zoneEditorStore = useZoneEditorStore() })
const socket = useSocketStore()
zoneStore.setTiles([ const tiles = Array.from({ length: 10 }, () => Array.from({ length: 10 }, () => 0))
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], zoneEditorStore.setTiles(tiles)
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0], zoneEditorStore.tiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y)))
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
])
zoneStore.tiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y)))
// Watch for changes in the zoneStore and update the layer // Watch for changes in the zoneStore and update the layer
watch( watch(
() => zoneStore.tiles, () => zoneEditorStore.tiles,
() => { () => {
// @TODO : change to tiles for when loading other maps // @TODO : change to zone for when loading other maps
zoneStore.tiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y))) zoneEditorStore.tiles.forEach((row, y) => row.forEach((tile, x) => layer.putTileAt(tile, x, y)))
}, },
{ deep: true } { deep: true }
) )
function erase(tile: Phaser.Tilemaps.Tile) { socket.connection.on('gm:zone_editor:zone:load', (data) => {
tileMap = generateTilemap(scene, data.zone.width, data.zone.height);
zoneEditorStore.setZoneSettings(data.zone)
zoneEditorStore.setTiles(data.zone.tiles)
})
function eraser(tile: Phaser.Tilemaps.Tile) {
layer.putTileAt(0, tile.x, tile.y) layer.putTileAt(0, tile.x, tile.y)
} }
function tile(tile: Phaser.Tilemaps.Tile) { function pencil(tile: Phaser.Tilemaps.Tile) {
if (zoneEditorStore.selectedTile === null) return if (zoneEditorStore.selectedTile === null) return
layer.putTileAt(zoneEditorStore.selectedTile, tile.x, tile.y) layer.putTileAt(zoneEditorStore.selectedTile, tile.x, tile.y)
} }
onBeforeUnmount(() => {
zoneEditorStore.reset();
})
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<Modal :isModalOpen="properties.isModalOpen" @modal:close="() => console.log(1)"> <Modal :isModalOpen="true" @modal:close="() => zoneEditorStore.toggleZoneSettings()">
<template #modalHeader> <template #modalHeader>
<h3 class="modal-title">Zone settings</h3> <h3 class="modal-title">Zone settings</h3>
</template> </template>
@ -9,25 +9,22 @@
<div class="form-fields"> <div class="form-fields">
<div> <div>
<label for="name">Name</label> <label for="name">Name</label>
<input v-model="name" name="name" id="name" /> <input name="name" id="name" />
</div> </div>
<div> <div>
<label for="name">Width</label> <label for="name">Width</label>
<input v-model="name" name="name" id="name" /> <input name="name" id="name" />
</div>
<div>
<label for="name">Height</label> <label for="name">Height</label>
<input v-model="name" name="name" id="name" /> <input name="name" id="name" />
</div> </div>
<div> <div>
<label for="name">PVP enabled</label> <label for="name">PVP enabled</label>
<input v-model="name" name="name" id="name" /> <input name="name" id="name" />
</div> </div>
</div> </div>
<div class="submit">
<button class="btn-cyan" type="submit">Save</button>
</div>
</form> </form>
<button class="btn-cyan" @click="() => console.log(1)">Cancel</button>
</template> </template>
</Modal> </Modal>
</template> </template>
@ -35,8 +32,7 @@
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useZoneEditorStore } from '@/stores/zoneEditor'
const properties = ref({ const zoneEditorStore = useZoneEditorStore()
isModalOpen: true
})
</script> </script>

View File

@ -5,6 +5,7 @@ export default {
width: 960, width: 960,
height: 540, height: 540,
tile_size: { x: 64, y: 32, z: 1 }, tile_size: { x: 64, y: 32, z: 1 },
wall_size: { x: 32, y: 128, z: 1 },
depth: { depth: {
ground: 0, // + y ground: 0, // + y
bullet: 5000, bullet: 5000,

View File

@ -1,16 +1,24 @@
<template> <template>
<div class="game-container"> <div class="game-container">
<Game class="game" :config="gameConfig" @create="createGame"> <GmTools />
<Game class="game" :config="gameConfig" @create="createGame" v-if="!zoneEditorStore.active">
<Scene name="main" @preload="preloadScene" @create="createScene"> <Scene name="main" @preload="preloadScene" @create="createScene">
<GmTools /> <div class="top-ui">
<div v-if="!zoneEditorStore.active"> <Hud />
<div class="top-ui"><Hud /></div> </div>
<World /> <div class="center-ui">
<div class="bottom-ui"><Chat /> <Menubar /></div> <World />
</div> </div>
<div v-else> <div class="bottom-ui">
<ZoneEditor /> <Chat />
</div> <Menubar />
</div>
</Scene>
</Game>
<Game class="game" :config="gameConfig" @create="createGame" v-else>
<Scene name="main" @preload="preloadScene" @create="createScene">
<ZoneEditor />
</Scene> </Scene>
</Game> </Game>
</div> </div>
@ -45,7 +53,7 @@ const gameConfig = {
name: 'New Quest', name: 'New Quest',
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight, height: window.innerHeight,
type: Phaser.WEBGL, type: Phaser.CANVAS,
pixelArt: true pixelArt: true
} }
@ -61,7 +69,7 @@ const preloadScene = (scene: Phaser.Scene) => {
* Write logic that downloads all assets from out websocket or http server in base64 format * Write logic that downloads all assets from out websocket or http server in base64 format
* Don't forget to check how intensive that operation is with sockets for performance * Don't forget to check how intensive that operation is with sockets for performance
*/ */
scene.load.image('tiles', '/assets/tiles/default.png') scene.load.image('tiles', '/assets/zone/tiles.png')
scene.load.image('waypoint', '/assets/waypoint.png') scene.load.image('waypoint', '/assets/waypoint.png')
scene.textures.addBase64( scene.textures.addBase64(
'character', 'character',

View File

@ -23,3 +23,15 @@ export function tileToWorldXY(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number
return { position_x, position_y } return { position_x, position_y }
} }
export function generateTilemap(scene: Phaser.Scene, width: number, height: number, ) {
const zoneData = new Phaser.Tilemaps.MapData({
width: width, // @TODO : get this from the server
height: height, // @TODO : get this from the server
tileWidth: config.tile_size.x,
tileHeight: config.tile_size.y,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
format: Phaser.Tilemaps.Formats.ARRAY_2D
})
return new Phaser.Tilemaps.Tilemap(scene, zoneData);
}

View File

@ -1,5 +1,6 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { Character } from '@/types' import type { Character } from '@/types'
import config from '@/config'
export const useZoneStore = defineStore('zone', { export const useZoneStore = defineStore('zone', {
state: () => ({ state: () => ({
@ -23,6 +24,10 @@ export const useZoneStore = defineStore('zone', {
}, },
removeCharacter(character: Character) { removeCharacter(character: Character) {
this.characters = this.characters.filter((c: Character) => c.id !== character.id) this.characters = this.characters.filter((c: Character) => c.id !== character.id)
},
reset() {
this.tiles = []
this.characters = []
} }
} }
}) })

View File

@ -1,25 +1,56 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import config from '@/config' import config from '@/config'
import {type Zone} from '@/types'
export const useZoneEditorStore = defineStore('zoneEditor', { export const useZoneEditorStore = defineStore('zoneEditor', {
state: () => ({ state: () => ({
active: true, active: false,
tiles: [] as number[][],
tool: 'move', tool: 'move',
drawMode: 'tile',
selectedTile: null, selectedTile: null,
selectedWall: null,
selectedDecoration: null,
zoneSettings: null as Zone | null,
zoneSettingsOpen: false
}), }),
actions: { actions: {
toggleActive() { toggleActive() {
this.active = !this.active this.active = !this.active
}, },
setTiles(tiles: number[][]) {
this.tiles = tiles
},
setTool(tool: string) { setTool(tool: string) {
this.tool = tool this.tool = tool
}, },
setDrawMode(mode: string) {
this.drawMode = mode
},
setSelectedTile(tile: any) { setSelectedTile(tile: any) {
this.selectedTile = tile this.selectedTile = tile
}, },
setSelectedWall(wall: any) {
this.selectedWall = wall
},
setSelectedDecoration(decoration: any) {
this.selectedDecoration = decoration
},
setZoneSettings(zone: Zone) {
this.zoneSettings = zone
},
toggleZoneSettings() {
this.zoneSettingsOpen = !this.zoneSettingsOpen
},
reset() {
this.tiles = []
this.tool = 'move'
this.drawMode = 'tile'
this.selectedTile = null
this.selectedWall = null
this.selectedDecoration = null
this.zoneSettings = null
this.zoneSettingsOpen = false
}
} }
}) })
/**
* [[0,0,0,0,0,0,0,0,0,0],[0,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,0],[0,0,0,0,0,0,0,0,0,0]]
*/