diff --git a/.docs/index.html b/.docs/index.html index 7a2c6ca..8146003 100644 --- a/.docs/index.html +++ b/.docs/index.html @@ -100,7 +100,10 @@ date: 2000-01-01
cd path/to/worldmods;
 git clone https://github.com/Uberi/Minetest-WorldEdit.git worldedit;
-git clone https://github.com/sbrl/Minetest-WorldEditAdditions.git worldeditadditions;
+git clone https://github.com/sbrl/Minetest-WorldEditAdditions.git worldeditadditions; +cd worldeditadditions; +git checkout "$(git describe --tags --abbrev=0)"; +

Source code on GitHub

diff --git a/.docs/package-lock.json b/.docs/package-lock.json index 1755dfc..94d2e16 100644 --- a/.docs/package-lock.json +++ b/.docs/package-lock.json @@ -9,12 +9,12 @@ "version": "1.0.0", "license": "MPL-2.0", "dependencies": { - "@11ty/eleventy": "^2.0.0", + "@11ty/eleventy": "^2.0.1", "chroma-js": "^2.4.2", "clean-css": "^5.3.2", "columnify": "^1.6.0", "debug": "^4.3.4", - "html-entities": "^2.3.3", + "html-entities": "^2.4.0", "html-minifier-terser": "^7.0.0-beta.0", "imagickal": "^5.0.1", "markdown-it-prism": "^2.3.0", @@ -30,13 +30,14 @@ "integrity": "sha512-5R+DsT9LJ9tXiSQ4y+KLFppCkQyXhzAm1AIuBWE/sbU0hSXY5pkhoqQYEcPJQFg/nglL+wD55iv2j+7O96UAvg==" }, "node_modules/@11ty/eleventy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-2.0.0.tgz", - "integrity": "sha512-heNLjt1FD2nx7fvidIgA4zrIvxuslgBK0w5/Ckr5iape1CoLzmDx1uIxPa66Atr1M6YzwG9hcOxoZUYV7PfLXw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-2.0.1.tgz", + "integrity": "sha512-t8XVUbCJByhVEa1RzO0zS2QzbL3wPY8ot1yUw9noqiSHxJWUwv6jiwm1/MZDPTYtkZH2ZHvdQIRQ5/SjG9XmLw==", "dependencies": { "@11ty/dependency-tree": "^2.0.1", - "@11ty/eleventy-dev-server": "^1.0.3", + "@11ty/eleventy-dev-server": "^1.0.4", "@11ty/eleventy-utils": "^1.0.1", + "@11ty/lodash-custom": "^4.17.21", "@iarna/toml": "^2.2.5", "@sindresorhus/slugify": "^1.1.2", "bcp-47-normalize": "^1.1.1", @@ -44,23 +45,20 @@ "cross-spawn": "^7.0.3", "debug": "^4.3.4", "dependency-graph": "^0.11.0", - "ejs": "^3.1.8", + "ejs": "^3.1.9", "fast-glob": "^3.2.12", - "graceful-fs": "^4.2.10", + "graceful-fs": "^4.2.11", "gray-matter": "^4.0.3", "hamljs": "^0.6.2", "handlebars": "^4.7.7", "is-glob": "^4.0.3", "iso-639-1": "^2.1.15", "kleur": "^4.1.5", - "liquidjs": "^10.4.0", - "lodash.chunk": "^4.2.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "luxon": "^3.2.1", + "liquidjs": "^10.7.0", + "luxon": "^3.3.0", "markdown-it": "^13.0.1", "micromatch": "^4.0.5", - "minimist": "^1.2.7", + "minimist": "^1.2.8", "moo": "^0.5.2", "multimatch": "^5.0.0", "mustache": "^4.2.0", @@ -73,7 +71,7 @@ "pug": "^3.0.2", "recursive-copy": "^2.0.14", "semver": "^7.3.8", - "slugify": "^1.6.5" + "slugify": "^1.6.6" }, "bin": { "eleventy": "cmd.js" @@ -87,9 +85,9 @@ } }, "node_modules/@11ty/eleventy-dev-server": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-1.0.3.tgz", - "integrity": "sha512-SjYQewOO0Oo2jUI5h0Lk87pRJllDBzbdcHGZTYEf00gz966kidP1Hyd3ySaHqL4lFqW2I6jIxNVKPlhwYhp6yA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-1.0.4.tgz", + "integrity": "sha512-qVBmV2G1KF/0o5B/3fITlrrDHy4bONUI2YuN3/WJ3BNw4NU1d/we8XhKrlgq13nNvHoBx5czYp3LZt8qRG53Fg==", "dependencies": { "@11ty/eleventy-utils": "^1.0.1", "chokidar": "^3.5.3", @@ -97,11 +95,11 @@ "dev-ip": "^1.0.1", "finalhandler": "^1.2.0", "mime": "^3.0.0", - "minimist": "^1.2.7", - "morphdom": "^2.6.1", + "minimist": "^1.2.8", + "morphdom": "^2.7.0", "please-upgrade-node": "^3.2.0", "ssri": "^8.0.1", - "ws": "^8.12.0" + "ws": "^8.13.0" }, "bin": { "eleventy-dev-server": "cmd.js" @@ -129,6 +127,18 @@ "url": "https://opencollective.com/11ty" } }, + "node_modules/@11ty/lodash-custom": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@11ty/lodash-custom/-/lodash-custom-4.17.21.tgz", + "integrity": "sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", @@ -773,9 +783,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", - "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", "dependencies": { "jake": "^10.8.5" }, @@ -1018,9 +1028,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/gray-matter": { "version": "4.0.3", @@ -1092,9 +1102,19 @@ } }, "node_modules/html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] }, "node_modules/html-minifier-terser": { "version": "7.0.0-beta.0", @@ -1342,14 +1362,14 @@ } }, "node_modules/jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" + "filelist": "^1.0.4", + "minimatch": "^3.1.2" }, "bin": { "jake": "bin/cli.js" @@ -1417,9 +1437,9 @@ } }, "node_modules/liquidjs": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.5.0.tgz", - "integrity": "sha512-qs1lbzfeSx5ICegKFrdYvxtKz8VXaw0Rfbu0zaCgC/M5aR62h89aR3wmL1W5C908y5yq+PBRPRFZZisS/gTPyA==", + "version": "10.8.3", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.8.3.tgz", + "integrity": "sha512-LqHLYtH3vrkT3LyfOhPU0FJX5KPO4aB6SzGa4HRI29yz8pS0ZxqIe/fWtic8qiust1+qrHI92J67tdt92V4WOA==", "dependencies": { "commander": "^10.0.0" }, @@ -1436,9 +1456,9 @@ } }, "node_modules/liquidjs/node_modules/commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "engines": { "node": ">=14" } @@ -1448,26 +1468,11 @@ "resolved": "https://registry.npmjs.org/list-to-array/-/list-to-array-1.1.0.tgz", "integrity": "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==" }, - "node_modules/lodash.chunk": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", - "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" - }, "node_modules/lodash.deburr": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", "integrity": "sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=" }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "node_modules/lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==" - }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -1488,9 +1493,9 @@ } }, "node_modules/luxon": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz", - "integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", + "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==", "engines": { "node": ">=12" } @@ -1708,9 +1713,9 @@ } }, "node_modules/nunjucks": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz", - "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", "dependencies": { "a-sync-waterfall": "^1.0.0", "asap": "^2.0.3", @@ -2237,9 +2242,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2253,7 +2258,7 @@ "node_modules/semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" }, "node_modules/shebang-command": { "version": "2.0.0", @@ -2283,9 +2288,9 @@ } }, "node_modules/slugify": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.5.tgz", - "integrity": "sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", "engines": { "node": ">=8.0.0" } @@ -2514,9 +2519,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/ws": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", - "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "engines": { "node": ">=10.0.0" }, @@ -2546,13 +2551,14 @@ "integrity": "sha512-5R+DsT9LJ9tXiSQ4y+KLFppCkQyXhzAm1AIuBWE/sbU0hSXY5pkhoqQYEcPJQFg/nglL+wD55iv2j+7O96UAvg==" }, "@11ty/eleventy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-2.0.0.tgz", - "integrity": "sha512-heNLjt1FD2nx7fvidIgA4zrIvxuslgBK0w5/Ckr5iape1CoLzmDx1uIxPa66Atr1M6YzwG9hcOxoZUYV7PfLXw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-2.0.1.tgz", + "integrity": "sha512-t8XVUbCJByhVEa1RzO0zS2QzbL3wPY8ot1yUw9noqiSHxJWUwv6jiwm1/MZDPTYtkZH2ZHvdQIRQ5/SjG9XmLw==", "requires": { "@11ty/dependency-tree": "^2.0.1", - "@11ty/eleventy-dev-server": "^1.0.3", + "@11ty/eleventy-dev-server": "^1.0.4", "@11ty/eleventy-utils": "^1.0.1", + "@11ty/lodash-custom": "^4.17.21", "@iarna/toml": "^2.2.5", "@sindresorhus/slugify": "^1.1.2", "bcp-47-normalize": "^1.1.1", @@ -2560,23 +2566,20 @@ "cross-spawn": "^7.0.3", "debug": "^4.3.4", "dependency-graph": "^0.11.0", - "ejs": "^3.1.8", + "ejs": "^3.1.9", "fast-glob": "^3.2.12", - "graceful-fs": "^4.2.10", + "graceful-fs": "^4.2.11", "gray-matter": "^4.0.3", "hamljs": "^0.6.2", "handlebars": "^4.7.7", "is-glob": "^4.0.3", "iso-639-1": "^2.1.15", "kleur": "^4.1.5", - "liquidjs": "^10.4.0", - "lodash.chunk": "^4.2.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "luxon": "^3.2.1", + "liquidjs": "^10.7.0", + "luxon": "^3.3.0", "markdown-it": "^13.0.1", "micromatch": "^4.0.5", - "minimist": "^1.2.7", + "minimist": "^1.2.8", "moo": "^0.5.2", "multimatch": "^5.0.0", "mustache": "^4.2.0", @@ -2589,13 +2592,13 @@ "pug": "^3.0.2", "recursive-copy": "^2.0.14", "semver": "^7.3.8", - "slugify": "^1.6.5" + "slugify": "^1.6.6" } }, "@11ty/eleventy-dev-server": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-1.0.3.tgz", - "integrity": "sha512-SjYQewOO0Oo2jUI5h0Lk87pRJllDBzbdcHGZTYEf00gz966kidP1Hyd3ySaHqL4lFqW2I6jIxNVKPlhwYhp6yA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-1.0.4.tgz", + "integrity": "sha512-qVBmV2G1KF/0o5B/3fITlrrDHy4bONUI2YuN3/WJ3BNw4NU1d/we8XhKrlgq13nNvHoBx5czYp3LZt8qRG53Fg==", "requires": { "@11ty/eleventy-utils": "^1.0.1", "chokidar": "^3.5.3", @@ -2603,11 +2606,11 @@ "dev-ip": "^1.0.1", "finalhandler": "^1.2.0", "mime": "^3.0.0", - "minimist": "^1.2.7", - "morphdom": "^2.6.1", + "minimist": "^1.2.8", + "morphdom": "^2.7.0", "please-upgrade-node": "^3.2.0", "ssri": "^8.0.1", - "ws": "^8.12.0" + "ws": "^8.13.0" } }, "@11ty/eleventy-utils": { @@ -2618,6 +2621,11 @@ "normalize-path": "^3.0.0" } }, + "@11ty/lodash-custom": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@11ty/lodash-custom/-/lodash-custom-4.17.21.tgz", + "integrity": "sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw==" + }, "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", @@ -3097,9 +3105,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "ejs": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", - "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", "requires": { "jake": "^10.8.5" } @@ -3281,9 +3289,9 @@ } }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "gray-matter": { "version": "4.0.3", @@ -3332,9 +3340,9 @@ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, "html-entities": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", - "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==" }, "html-minifier-terser": { "version": "7.0.0-beta.0", @@ -3516,14 +3524,14 @@ "integrity": "sha512-7c7mBznZu2ktfvyT582E2msM+Udc1EjOyhVRE/0ZsjD9LBtWSm23h3PtiRh2a35XoUsTQQjJXaJzuLjXsOdFDg==" }, "jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", "requires": { "async": "^3.2.3", "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" + "filelist": "^1.0.4", + "minimatch": "^3.1.2" } }, "js-stringify": { @@ -3573,17 +3581,17 @@ } }, "liquidjs": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.5.0.tgz", - "integrity": "sha512-qs1lbzfeSx5ICegKFrdYvxtKz8VXaw0Rfbu0zaCgC/M5aR62h89aR3wmL1W5C908y5yq+PBRPRFZZisS/gTPyA==", + "version": "10.8.3", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.8.3.tgz", + "integrity": "sha512-LqHLYtH3vrkT3LyfOhPU0FJX5KPO4aB6SzGa4HRI29yz8pS0ZxqIe/fWtic8qiust1+qrHI92J67tdt92V4WOA==", "requires": { "commander": "^10.0.0" }, "dependencies": { "commander": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", - "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==" + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" } } }, @@ -3592,26 +3600,11 @@ "resolved": "https://registry.npmjs.org/list-to-array/-/list-to-array-1.1.0.tgz", "integrity": "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==" }, - "lodash.chunk": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", - "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" - }, "lodash.deburr": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", "integrity": "sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=" }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==" - }, "lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -3629,9 +3622,9 @@ } }, "luxon": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz", - "integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", + "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==" }, "markdown-it": { "version": "13.0.1", @@ -3793,9 +3786,9 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "nunjucks": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz", - "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", "requires": { "a-sync-waterfall": "^1.0.0", "asap": "^2.0.3", @@ -4191,9 +4184,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "requires": { "lru-cache": "^6.0.0" } @@ -4201,7 +4194,7 @@ "semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" }, "shebang-command": { "version": "2.0.0", @@ -4222,9 +4215,9 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, "slugify": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.5.tgz", - "integrity": "sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ==" + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==" }, "source-map": { "version": "0.6.1", @@ -4389,9 +4382,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", - "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "requires": {} }, "yallist": { diff --git a/.docs/package.json b/.docs/package.json index 063abd8..7db12a1 100644 --- a/.docs/package.json +++ b/.docs/package.json @@ -20,12 +20,12 @@ }, "homepage": "https://github.com/sbrl/Minetest-WorldEditAdditions#readme", "dependencies": { - "@11ty/eleventy": "^2.0.0", + "@11ty/eleventy": "^2.0.1", "chroma-js": "^2.4.2", "clean-css": "^5.3.2", "columnify": "^1.6.0", "debug": "^4.3.4", - "html-entities": "^2.3.3", + "html-entities": "^2.4.0", "html-minifier-terser": "^7.0.0-beta.0", "imagickal": "^5.0.1", "markdown-it-prism": "^2.3.0", diff --git a/.tests/strings/split_shell.test.lua b/.tests/strings/split_shell.test.lua new file mode 100644 index 0000000..f876cf5 --- /dev/null +++ b/.tests/strings/split_shell.test.lua @@ -0,0 +1,178 @@ +local split_shell = require("worldeditadditions_core.utils.strings.split_shell") + +describe("split_shell", function() + it("should handle a single case x3", function() + assert.are.same( + { "yay", "yay", "yay" }, + split_shell("yay yay yay") + ) + end) + + it("should handle double quotes simple", function() + assert.are.same( + { "dirt", "snow block" }, + split_shell("dirt \"snow block\"") + ) + end) + + it("should handle an escaped double quote inside double quotes", function() + assert.are.same( + { "yay", "yay\" yay", "yay" }, + split_shell("yay \"yay\\\" yay\" yay") + ) + end) + + it("should handle single quotes", function() + assert.are.same( + { "yay", "yay", "yay" }, + split_shell("yay 'yay' yay") + ) + end) + + it("should handle single quotes again", function() + assert.are.same( + { "yay", "inside quotes", "another" }, + split_shell("yay 'inside quotes' another") + ) + end) + + it("should handle single quotes inside double quotes", function() + assert.are.same( + { "yay", "yay 'inside quotes' yay", "yay" }, + split_shell("yay \"yay 'inside quotes' yay\" yay") + ) + end) + + it("should handle single quotes and an escaped double quote inside double quotes", function() + assert.are.same( + { "yay", "yay 'inside quotes' yay\"", "yay" }, + split_shell("yay \"yay 'inside quotes' yay\\\"\" yay") + ) + end) + + it("should handle a complex case", function() + assert.are.same( + { "y\"ay", "yay 'in\"side quotes' yay", "y\"ay" }, + split_shell("y\"ay \"yay 'in\\\"side quotes' yay\" y\\\"ay") + ) + end) + it("should handle a subtly different complex case", function() + assert.are.same( + { "y\"ay", "yay", "in\"side quotes", "yay", "y\"ay" }, + split_shell("y\"ay yay 'in\\\"side quotes' yay y\\\"ay") + ) + end) + it("should handle redundant double quotes", function() + assert.are.same( + { "cake" }, + split_shell("\"cake\"") + ) + end) + it("should handle redundant double quotes multi", function() + assert.are.same( + { "cake", "cake", "cake" }, + split_shell("\"cake\" \"cake\" \"cake\"") + ) + end) + it("should handle redundant single quotes", function() + assert.are.same( + { "cake" }, + split_shell("'cake'") + ) + end) + it("should handle redundant single quotes multi", function() + assert.are.same( + { "cake", "cake", "cake" }, + split_shell("'cake' 'cake' 'cake'") + ) + end) + it("should handle redundant double and single quotes", function() + assert.are.same( + { "cake", "cake", "cake" }, + split_shell("'cake' \"cake\" 'cake'") + ) + end) + + it("should handle redundant double and single quotes opposite", function() + assert.are.same( + { "cake", "cake", "cake" }, + split_shell("\"cake\" 'cake' \"cake\"") + ) + end) + it("should handle a random backslash single quotes", function() + assert.are.same( + { "cake", "ca\\ke" }, + split_shell("\"cake\" 'ca\\ke'") + ) + end) + it("should handle a random backslash double quotes", function() + assert.are.same( + { "cake", "ca\\ke" }, + split_shell("\"cake\" \"ca\\ke\"") + ) + end) + it("should handle a backslash after double quotes", function() + assert.are.same( + { "\\cake", "cake" }, + split_shell("\"\\cake\" \"cake\"") + ) + end) + it("should handle a double backslash before double quotes", function() + assert.are.same( + { "\\\"cake\"", "cake" }, + split_shell("\\\\\"cake\" \"cake\"") + ) + end) + it("should handle a single backslash before double quotes", function() + assert.are.same( + { "\"cake\"", "cake" }, + split_shell("\\\"cake\" \"cake\"") + ) + end) + it("should handle a double backslash before single quotes", function() + assert.are.same( + { "\\'cake'", "cake" }, + split_shell("\\\\'cake' 'cake'") + ) + end) + it("should handle a single backslash before single quotes", function() + assert.are.same( + { "\"cake\"", "cake" }, + split_shell("\\\"cake\" \"cake\"") + ) + end) + it("should handle redundant double and single quotes again", function() + assert.are.same( + { "cake", "cake", "cake", "is", "a", "li\\e" }, + split_shell("\"cake\" 'cake' \"cake\" is a \"li\\e\"") + ) + end) + + -- Unclosed quotes are currently considered to last until the end of the string. + + it("should handle an unclosed double quote", function() + assert.are.same( + { "the", "cake is a lie" }, + split_shell("the \"cake is a lie") + ) + end) + it("should handle an unclosed single quote", function() + assert.are.same( + { "the", "cake is a lie" }, + split_shell("the 'cake is a lie") + ) + end) + it("should handle an unclosed single quote at the end", function() + assert.are.same( + { "the", "cake is a lie'" }, + split_shell("the \"cake is a lie'") + ) + end) + it("should handle an unclosed single and double quote", function() + assert.are.same( + { "the", "cake is \"a lie" }, + split_shell("the 'cake is \"a lie") + ) + end) + +end) \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f87f193..d9375fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,20 +4,26 @@ It's about time I started a changelog! This will serve from now on as the main c Note to self: See the bottom of this file for the release template text. -## v1.14: The untitled update (unreleased) +## v1.14: The multipoint update (unreleased) - Add `//dome+`, which allows you to change the direction the dome is pointing in, and also create multiple domes at once - Add `//metaball`, which renders 2 or more [metaballs](https://en.wikipedia.org/wiki/Metaballs) in Minetest - - Add `//revolve`, which makes multiple evenly-spaced rotated copies of the defined region - - Migrate from `depends.txt` to `mod.conf` - - `//sculpt`: Fix undefined `default` brush - - Commands that modify the terrain now ignore liquids - - `//hollow`: Fix safe region bug - Significant backend refactoring to tidy things up - - Add new multi-point selection wand ![A picture of the multi-point wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_multiwand.png) to select many points at once. **Not currently compatible with other wands**, as it's a work-in-progress (commands that support/require more than 2 points are hopefully coming soon) - - Add `//spline`, for drawing curved lines with an arbitrary number of points **(uses the new multi-point wand)** + - Add new multi-point selection wand ![A picture of the multi-point wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_multiwand.png) to select many points at once. + - Implement custom region boxing UI, which replaces the WorldEdit region box when using WorldEditAdditions wands. + - Is backwards compatible with regular WorldEdit wands and tools, as WorldEditAdditions keeps the new positioning system in sync with WorldEdit's. + - Add [`//spline`](https://worldeditadditions.mooncarrot.space/Reference/#spline), for drawing curved lines with an arbitrary number of points **(uses the new multi-point wand)** + - Add [`//revolve`](https://worldeditadditions.mooncarrot.space/Reference/#revolve), which makes multiple evenly-spaced rotated copies of the defined region **(uses the new multi-point wand)** + - [`//copy+`](https://worldeditadditions.mooncarrot.space/Reference/#copy), [`//move+`](https://worldeditadditions.mooncarrot.space/Reference/#move): Added support for integrated `airapply` mode, which replaces nodes at the target only if they are air - append `airapply`/`aa` to the command to use -### Bugfixes +### Bugfixes and changes + - Migrate from `depends.txt` to `mod.conf` - Cloud wand: fix typo in item description. + - Commands that modify the terrain now ignore liquids + - `//sculpt`: + - Fix undefined `default` brush + - Change defaults to `circle`, `height=1`, and `brushsize=8`. + - Change argument ordering to put `height` after `brushsize` instead of the other way around + - `//hollow`: Fix safe region bug ## v1.13: The transformational update (2nd January 2022) @@ -36,10 +42,10 @@ Note to self: See the bottom of this file for the release template text. - Add [`//sculpt`](https://worldeditadditions.mooncarrot.space/Reference/#sculpt) and [`//sculptlist`](https://worldeditadditions.mooncarrot.space/Reference/#sculptlist) for sculpting terrain using a number of custom brushes. - Use [luacheck](https://github.com/mpeterv/luacheck) to find and fix a large number of bugs and other issues [code quality from now on will be significantly improved] - Multiple commands: Allow using quotes (`"thing"`, `'thing'`) to quote values when splitting - - `//layers`: Add optional slope constraint (inspired by [WorldPainter](https://worldpainter.net/)) - - `//bonemeal`: Add optional node list constraint - - `//walls`: Add optional thickness argument - - `//sstack`: Add human-readable approx volumes of regions in the selection stack + - [`//layers`](https://worldeditadditions.mooncarrot.space/Reference/#layers): Add optional slope constraint (inspired by [WorldPainter](https://worldpainter.net/)) + - [`//bonemeal`](https://worldeditadditions.mooncarrot.space/Reference/#bonemeal): Add optional node list constraint + - [`//walls`](https://worldeditadditions.mooncarrot.space/Reference/#walls): Add optional thickness argument + - [`//sstack`](https://worldeditadditions.mooncarrot.space/Reference/#sstack): Add human-readable approx volumes of regions in the selection stack ### Bugfixes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4b6ebc3..446ba96 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,8 @@ When actually implementing stuff, here are a few guidelines that I recommend to -- ██ ██ ██ ██ ██ ██ ██ ██ ██ -- ██ ████ ██ ██ ██ ██ ███████ local wea = worldeditadditions -local wea_c = worldeditadditions_core +local weac = worldeditadditions_core +local Vector3 = weac.Vector3 worldeditadditions_core.register_command("{name}", { params = " [ ...] | [ []]", description = "A **brief** description of what this command does", @@ -48,18 +49,18 @@ worldeditadditions_core.register_command("{name}", { return true, param1, param2 end, nodes_needed = function(name) --Optional - return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) + return Vector3.volume(weac.pos.get1(name), weac.pos.get2(name)) end, func = function(name, param1, param2) -- Start a timer - local start_time = wea_c.get_ms_time() + local start_time = weac.get_ms_time() -- Do stuff -- Finish timer - local time_taken = wea_c.get_ms_time() - start_time + local time_taken = weac.get_ms_time() - start_time minetest.log("This is a logged message!") - return true, "Completed command in " .. wea_c.format.human_time(time_taken) + return true, "Completed command in " .. weac.format.human_time(time_taken) end }) ``` diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index e9c53e5..757290f 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -227,6 +227,8 @@ Floods all connected nodes of the same type starting at _pos1_ with `` Sets the edges of the current selection to ``to create an outline of a rectangular prism. Useful for roughing in walls. +In other words, creates a wireframe of a box defined by the current selection. + ```weacmd //wbox silver_sandstone //wbox dirt @@ -331,7 +333,7 @@ By adding 3 extra numbers for the x, y, and z axes respectively, we can control So in the above example, we scale in the positive x and z directions, and the negative y direction. -### `//copy+ [ [...]]` +### `//copy+ [ [...]] [aa|airapply]` Fully backwards-compatible with `//copy` from regular WorldEdit, but allows you to specify multiple axes at once in a single copy operation. Each successive axis in the list is specified in the form ` `, where: - `` is the name of the axis to move the defined region along @@ -354,6 +356,8 @@ All of the following values are valid axes: Additionally all the absolute axis names (`x`/`y`/`z`/`-x`/`-y`/`-z`) may also be specified multiple times under the same count - e.g. `xy-z 6`. +Finally, if the word `airapply` (or `aa` for short) is present at the end of the command invocation it enables the integrated airapply mode, which replaces target nodes only if they are air-like. + ``` //copy+ x 6 //copy+ y 10 z 4 @@ -362,12 +366,17 @@ Additionally all the absolute axis names (`x`/`y`/`z`/`-x`/`-y`/`-z`) may also b //copy+ xz 50 front 22 //copy+ yx 25 //copy+ -xz-y 10 +//copy+ y 45 aa +//copy+ -y 15 z 5 airapply ``` -### `//move+ [ [...]]` +### `//move+ [ [...]] [aa|airapply]` Identical to [`//copy+`](#copy), but instead moves the defined region instead of copying it. +Note that the integrated `airapply` (`aa` for short) also works as in [`//copy+`](#copy), but remember that if a given target node is not *not* air-like and the integrated `airapply` mode is enabled, the source node is still moved from the source, but destroyed because it is can't be set at the target. + + ``` //move+ x 6 //move+ y 10 z 4 @@ -376,6 +385,8 @@ Identical to [`//copy+`](#copy), but instead moves the defined region instead of //move+ xz 50 front 22 //move+ yx 25 //move+ -xz-y 10 +//move+ back 20 aa +//move+ -z 45 y 3 airapply ``` @@ -668,7 +679,7 @@ Lists all the available sculpting brushes for use with `//sculpt`. If the `previ ``` -### `//sculpt [ [ []]]` +### `//sculpt [ [ []]]` Applies a specified brush to the terrain at position 1 with a given height and a given size. Multiple brushes exist (see [`//sculptlist`](#sculptlist)) - and are represented as a 2D grid of values between 0 and 1, which are then scaled to the specified height. The terrain around position 1 is first converted to a 2D heightmap (as in [`//convolve`](#convolve) before the brush "heightmap" is applied to it. Similar to [`//sphere`](https://github.com/Uberi/Minetest-WorldEdit/blob/master/ChatCommands.md#sphere-radius-node), [`//cubeapply 10 set`](https://github.com/Uberi/Minetest-WorldEdit/blob/master/ChatCommands.md#cubeapply-sizesizex-sizey-sizez-command-parameters), or [`//cylinder y 5 10 10 dirt`](https://github.com/Uberi/Minetest-WorldEdit/blob/master/ChatCommands.md#cylinder-xyz-length-radius1-radius2-node) (all from [WorldEdit](https://content.minetest.net/packages/sfan5/worldedit/)), but has a number of added advantages: @@ -684,9 +695,9 @@ The selection of available brushes is limited at the moment, but see below on ho ``` //sculpt -//sculpt default 10 25 +//sculpt default 25 3 //sculpt ellipse -//sculpt circle 5 50 +//sculpt circle 50 3 ``` #### Create your own brushes diff --git a/README.md b/README.md index 1a3c098..825a5f6 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,8 @@ cd WorldEditAdditions git checkout "$(git describe --tags --abbrev=0)"; ``` +If you do not checkout the latest release, you will be using the development version of WorldEditAdditions. While every effort is made to ensure that the development version is stable at all times, this is not a guarantee. + Windows users, you'll need to check the [releases page](https://github.com/sbrl/Minetest-WorldEditAdditions/releases) and find the name of the latest release, then do this instead of the `git checkout` above: ```bash @@ -159,7 +161,18 @@ Contributions are welcome! Please state in your pull request(s) that you release Please also make sure that the logic for every new command has it's own file. For example, the logic for `//floodfill` goes in `worldeditadditions/floodfill.lua`, the logic for `//overlay` goes in `worldeditadditions/overlay.lua`, etc. More contributing help can be found in [the contributing guide](CONTRIBUTING.md). -I, Starbeamrainbowlabs (@sbrl), have the ultimate final say. +### Inspiration +Want to contribute, but finding it tough to search for inspiration of what to implement? Here are some great places to look: + +- [**Our issue tracker:**](https://github.com/sbrl/Minetest-WorldEditAdditions/issues) There are always a bunch of issues open with cool commands and features that have yet to be implemented. +- **Other software:** Software for Minecraft is often far more mature than that available for Minetest. As a result, it's full of cool ideas. A lot of the existing commands in WorldEditAdditions were sourced from here. + - WorldEdit for Minecraft + - VoxelSniper(-Reimagined) for Minecraft + - WorldPainter for Minecraft +- **Do some building:** When you put WorldEditAdditions to use in building projects of your own, things will absolutely stand out to you what you want in the creative building process that WorldEditAdditions doesn't yet have. +- **Watch others build stuff:** Doesn't even have to be Minetest! There are lots of talented Minecraft builders with videos and series on e.g. YouTube. From their creative building processes, many ideas can be derived. + +The ultimate goal is for WorldEditAdditions to support the creative building process in a way that enables builders of all backgrounds to create incredible things. ## WorldEditAdditions around the web diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua index e8ce070..c8ef8b6 100644 --- a/worldeditadditions/init.lua +++ b/worldeditadditions/init.lua @@ -1,7 +1,7 @@ --- WorldEditAdditions --- @module worldeditadditions --- @release 0.1 --- @copyright 2018 Starbeamrainbowlabs +-- @namespace worldeditadditions +-- @release 1.13 +-- @copyright 2023 Starbeamrainbowlabs -- @license Mozilla Public License, 2.0 -- @author Starbeamrainbowlabs diff --git a/worldeditadditions/lib/airapply.lua b/worldeditadditions/lib/airapply.lua index 1de83fa..b526204 100644 --- a/worldeditadditions/lib/airapply.lua +++ b/worldeditadditions/lib/airapply.lua @@ -13,7 +13,7 @@ local Vector3 = wea_c.Vector3 -- ██ ██ ██ ██ ██ ██ -- ██ ██ ██ ██ ███████ ██ ---- Similar to cubeapply, except that it takes 2 positions and only keeps an ellipsoid-shaped area defined by the boundaries of the defined region. +--- Like ellipsoidapply, but only keeps changes that replace airlike nodes, and discards any other changes made. -- Takes a backup copy of the defined region, runs the given function, and then -- restores the bits around the edge that aren't inside the largest ellipsoid that will fit inside the defined region. -- @param {Position} pos1 The 1st position defining the region boundary diff --git a/worldeditadditions/lib/bonemeal.lua b/worldeditadditions/lib/bonemeal.lua index 86f4c36..0a179c2 100644 --- a/worldeditadditions/lib/bonemeal.lua +++ b/worldeditadditions/lib/bonemeal.lua @@ -2,11 +2,12 @@ local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 --- Bonemeal command. --- Applies bonemeal to all notes --- @module worldeditadditions.overlay - --- strength The strength to apply - see bonemeal:on_use --- chance Positive integer that represents the chance bonemealing will occur +-- Applies bonemeal to all nodes with an air bloc above then. +-- @param strength The strength to apply - see bonemeal:on_use +-- @param chance Positive integer that represents the chance bonemealing will occur +-- @returns bool,number,number 1. Whether the command succeeded or not. +-- 2. The number of nodes actually bonemealed +-- 3. The number of possible candidates we could have bonemealed function worldeditadditions.bonemeal(pos1, pos2, strength, chance, nodename_list) if not nodename_list then nodename_list = {} end pos1, pos2 = Vector3.sort(pos1, pos2) diff --git a/worldeditadditions/lib/copy.lua b/worldeditadditions/lib/copy.lua index 366f1a0..030b76f 100644 --- a/worldeditadditions/lib/copy.lua +++ b/worldeditadditions/lib/copy.lua @@ -1,8 +1,6 @@ local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 ---- Copies a region to another location, potentially overwriting the exiting region. --- @module worldeditadditions.copy -- ██████ ██████ ██████ ██ ██ -- ██ ██ ██ ██ ██ ██ ██ @@ -10,7 +8,16 @@ local Vector3 = wea_c.Vector3 -- ██ ██ ██ ██ ██ -- ██████ ██████ ██ ██ -function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_pos2) +--- Copies a region to another location, potentially overwriting the exiting region. +-- @param source_pos1 Vector3 pos1 of the source region to copy. +-- @param source_pos2 Vector3 pos2 of the source region to copy. +-- @param target_pos1 Vector3 pos1 of the target region to copy to. +-- @param target_pos2 Vector3 pos2 of the target region to copy to. +-- @param airapply=false bool Whether to only replace target nodes that are air-like, leaving those that are not air-like. If false, then all target nodes are replaced regardless of whether they are air-like nodes or not. +-- @returns bool,numbers 1. Whether the copy operation was successful or not +-- 2. The total number of nodes copied. +function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_pos2, airapply) + if airapply == nil then airapply = false end source_pos1, source_pos2 = Vector3.sort(source_pos1, source_pos2) target_pos1, target_pos2 = Vector3.sort(target_pos1, target_pos2) @@ -26,7 +33,7 @@ function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_p local data_target = manip_target:get_data() -- z y x is the preferred loop order (because CPU cache, since then we're iterating linearly through the data array backwards. This only holds true for little-endian machines however) - + local total_replaced = 0 for z = source_pos2.z, source_pos1.z, -1 do for y = source_pos2.y, source_pos1.y, -1 do for x = source_pos2.x, source_pos1.x, -1 do @@ -35,7 +42,14 @@ function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_p local target = source - offset local target_i = area_target:index(target.x, target.y, target.z) - data_target[target_i] = data_source[source_i] + local should_replace = true + if airapply then + should_replace = wea_c.is_airlike(data_target[target_i]) + end + if should_replace then + data_target[target_i] = data_source[source_i] + total_replaced = total_replaced + 1 + end end end end @@ -43,5 +57,5 @@ function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_p -- Save the modified nodes back to disk & return worldedit.manip_helpers.finish(manip_target, data_target) - return true, worldedit.volume(target_pos1, target_pos2) + return true, total_replaced end diff --git a/worldeditadditions/lib/count.lua b/worldeditadditions/lib/count.lua index 6901b62..5d05886 100644 --- a/worldeditadditions/lib/count.lua +++ b/worldeditadditions/lib/count.lua @@ -1,14 +1,19 @@ local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 ---- Counts the nodes in a given area. --- @module worldeditadditions.count - -- ██████ ██████ ██ ██ ███ ██ ████████ -- ██ ██ ██ ██ ██ ████ ██ ██ -- ██ ██ ██ ██ ██ ██ ██ ██ ██ -- ██ ██ ██ ██ ██ ██ ██ ██ ██ -- ██████ ██████ ██████ ██ ████ ██ + +--- Counts the nodes in a given area. +-- @param pos1 Vector3 pos1 of the defined region to count nodes in. +-- @param pos2 Vector3 pos2 of the defined region to count nodes in. +-- @param do_human_counts bool Whether to return human-readable counts (as a string) instead of the raw numbers. +-- @returns bool,table,number 1. Whether the operation was successful or not. +-- 2. A table mapping node ids to the number of that node id seen. +-- 3. The total number of nodes counted. function worldeditadditions.count(pos1, pos2, do_human_counts) pos1, pos2 = Vector3.sort(pos1, pos2) -- pos2 will always have the highest co-ordinates now diff --git a/worldeditadditions/lib/move.lua b/worldeditadditions/lib/move.lua index 9bbf767..8f81f9e 100644 --- a/worldeditadditions/lib/move.lua +++ b/worldeditadditions/lib/move.lua @@ -10,11 +10,12 @@ local Vector3 = wea_c.Vector3 -- ██ ██ ██ ██ ██ ██ ██ ██ -- ██ ██ ██████ ████ ███████ -function worldeditadditions.move(source_pos1, source_pos2, target_pos1, target_pos2) +function worldeditadditions.move(source_pos1, source_pos2, target_pos1, target_pos2, airapply) --- -- 0: Preamble --- + if airapply == nil then airapply = false end source_pos1, source_pos2 = Vector3.sort(source_pos1, source_pos2) target_pos1, target_pos2 = Vector3.sort(target_pos1, target_pos2) @@ -45,9 +46,13 @@ function worldeditadditions.move(source_pos1, source_pos2, target_pos1, target_p local target = source:subtract(offset) local target_i = area_target:index(target.x, target.y, target.z) - - data_target[target_i] = data_source[source_i] - + local should_replace = true + if airapply then + should_replace = wea_c.is_airlike(data_target[target_i]) + end + if should_replace then + data_target[target_i] = data_source[source_i] + end end end end diff --git a/worldeditadditions/lib/noise/engines/perlin.lua b/worldeditadditions/lib/noise/engines/perlin.lua index a46717a..d81bd6b 100644 --- a/worldeditadditions/lib/noise/engines/perlin.lua +++ b/worldeditadditions/lib/noise/engines/perlin.lua @@ -5,7 +5,7 @@ local Vector3 = wea_c.Vector3 --- Perlin noise generation engine. -- Original code by Ken Perlin: http://mrl.nyu.edu/~perlin/noise/ -- Port from this StackOverflow answer: https://stackoverflow.com/a/33425812/1460422 --- @class +-- @class worldeditadditions.noise.engines.Perlin local Perlin = {} Perlin.__index = Perlin diff --git a/worldeditadditions/lib/replacemix.lua b/worldeditadditions/lib/replacemix.lua index 67c8dbe..fa31f2c 100644 --- a/worldeditadditions/lib/replacemix.lua +++ b/worldeditadditions/lib/replacemix.lua @@ -3,12 +3,14 @@ local Vector3 = wea_c.Vector3 --- Like //mix, but replaces a given node instead. -- @module worldeditadditions.replacemix +-- TODO: Implement //replacesplat, which picks seeder nodes with a percentage chance, and then some growth passes with e.g. cellular automata? We should probably be pushing towards a release though round about now -- ██████ ███████ ██████ ██ █████ ██████ ███████ ███ ███ ██ ██ ██ -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ -- ██████ █████ ██████ ██ ███████ ██ █████ ██ ████ ██ ██ ███ -- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -- ██ ██ ███████ ██ ███████ ██ ██ ██████ ███████ ██ ██ ██ ██ ██ + function worldeditadditions.replacemix(pos1, pos2, target_node, target_node_chance, replacements) pos1, pos2 = Vector3.sort(pos1, pos2) -- pos2 will always have the highest co-ordinates now diff --git a/worldeditadditions/lib/sculpt/apply.lua b/worldeditadditions/lib/sculpt/apply.lua index 8af9a5d..e9eaf6b 100644 --- a/worldeditadditions/lib/sculpt/apply.lua +++ b/worldeditadditions/lib/sculpt/apply.lua @@ -5,10 +5,10 @@ local Vector3 = wea_c.Vector3 --- Applies the given brush with the given height and size to the given position. -- @param pos1 Vector3 The position at which to apply the brush. -- @param brush_name string The name of the brush to apply. --- @param height number The height of the brush application. -- @param brush_size Vector3 The size of the brush application. Values are interpreted on the X/Y coordinates, and NOT X/Z! +-- @param height number The height of the brush application. -- @returns bool, string|{ added: number, removed: number } A bool indicating whether the operation was successful or not, followed by either an error message as a string (if it was not successful) or a table of statistics (if it was successful). -local function apply(pos1, brush_name, height, brush_size) +local function apply(pos1, brush_name, brush_size, height) -- 1: Get & validate brush local success, brush, brush_size_actual = wea.sculpt.make_brush(brush_name, brush_size) if not success then return success, brush end diff --git a/worldeditadditions/lib/sculpt/brushes/__gaussian.lua b/worldeditadditions/lib/sculpt/brushes/__gaussian.lua index b3b7c93..2c41ef9 100644 --- a/worldeditadditions/lib/sculpt/brushes/__gaussian.lua +++ b/worldeditadditions/lib/sculpt/brushes/__gaussian.lua @@ -3,6 +3,8 @@ local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 --- Returns a smooth gaussian brush. +-- @name make_gaussian +-- @internal -- @param size Vector3 The target size of the brush. Note that the actual size of the brush will be different, as the gaussian function has some limitations. -- @param sigma=2 number The 'smoothness' of the brush. Higher values are more smooth. return function(size, sigma) diff --git a/worldeditadditions/lib/sculpt/brushes/circle.lua b/worldeditadditions/lib/sculpt/brushes/circle.lua index 2f3aa48..2e678e3 100644 --- a/worldeditadditions/lib/sculpt/brushes/circle.lua +++ b/worldeditadditions/lib/sculpt/brushes/circle.lua @@ -2,6 +2,7 @@ local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 --- Makes a circle brush of a given size. +-- @name circle -- @param size Vector3 The desired sizez of the brush (only X and Y are considered; Z is ignored). -- @returns bool,brush,Vector3 Success bool, then the brush, then finally the actual size of the brush generated. return function(size) diff --git a/worldeditadditions/lib/sculpt/brushes/square.lua b/worldeditadditions/lib/sculpt/brushes/square.lua index cd78045..85c82c6 100644 --- a/worldeditadditions/lib/sculpt/brushes/square.lua +++ b/worldeditadditions/lib/sculpt/brushes/square.lua @@ -1,5 +1,8 @@ --- Returns a simple square brush with 100% weight for every pixel. +-- @name square +-- @param size Vector3 The desired size of the brush. Only the x and y components are used; the z component is ignored. +-- @returns bool,number[],Vector3 1: true, as this function always succeeds. 2: A simple square brush as a zero-indexed flat array. 3: The size of the resulting brush as a Vector3, using the x and y components. return function(size) local result = {} for y=0, size.y do diff --git a/worldeditadditions/lib/sculpt/import_static.lua b/worldeditadditions/lib/sculpt/import_static.lua index 0d28984..8842c29 100644 --- a/worldeditadditions/lib/sculpt/import_static.lua +++ b/worldeditadditions/lib/sculpt/import_static.lua @@ -3,6 +3,8 @@ local wea = worldeditadditions local parse_static = dofile(wea.modpath.."/lib/sculpt/parse_static.lua") --- Reads and parses the brush stored in the specified file. +-- @name import_static +-- @internal -- @param filepath string The path to file that contains the static brush to read in. -- @returns true,table,Vector3|false,string A success boolean, followed either by an error message as a string or the brush (as a table) and it's size (as an X/Y Vector3) return function(filepath) diff --git a/worldeditadditions/lib/sculpt/parse_static.lua b/worldeditadditions/lib/sculpt/parse_static.lua index a1a8a29..7b1208b 100644 --- a/worldeditadditions/lib/sculpt/parse_static.lua +++ b/worldeditadditions/lib/sculpt/parse_static.lua @@ -3,6 +3,8 @@ local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 --- Parses a static brush definition. +-- @name parse_static +-- @internal -- @param source string The source string that contains the static brush, formatted as TSV. -- @returns true,table,Vector3|false,string A success boolean, followed either by an error message as a string or the brush (as a table) and it's size (as an X/Y Vector3) return function(source) diff --git a/worldeditadditions/lib/sculpt/scan_static.lua b/worldeditadditions/lib/sculpt/scan_static.lua index 5f455dd..960cf6f 100644 --- a/worldeditadditions/lib/sculpt/scan_static.lua +++ b/worldeditadditions/lib/sculpt/scan_static.lua @@ -22,6 +22,8 @@ end --- Scans the given directory and imports all static brushes found. -- Static brushes have the file extension ".brush.tsv" (without quotes). +-- @name scan_static +-- @internal -- @param dirpath string The path to directory that contains the static brushs to import. -- @returns bool,loaded,errors A success boolean, followed by the number of brushes loaded, followed by the number of errors encountered while loading brushes (errors are logged as warnings with Minetest) return function(dirpath, overwrite_existing) diff --git a/worldeditadditions/lib/selection/selection.lua b/worldeditadditions/lib/selection/selection.lua index fbf0d4d..02032e0 100644 --- a/worldeditadditions/lib/selection/selection.lua +++ b/worldeditadditions/lib/selection/selection.lua @@ -9,28 +9,39 @@ local Vector3 = wea_c.Vector3 ---Selection helpers and modifiers local selection = {} ---- Additively adds a point to the current selection or +--- Additively adds a point to the current selection defined by pos1..pos2 or -- makes a selection from the provided point. -- @param name string Player name. -- @param pos vector The position to include. -function selection.add_point(name, pos) - if pos ~= nil then - local created_new = not worldedit.pos1[name] or not worldedit.pos2[name] - -- print("[set_pos1]", name, "("..pos.x..", "..pos.y..", "..pos.z..")") - if not worldedit.pos1[name] then worldedit.pos1[name] = Vector3.clone(pos) end - if not worldedit.pos2[name] then worldedit.pos2[name] = Vector3.clone(pos) end +function selection.add_point(name, newpos) + if newpos ~= nil then + -- print("DEBUG:selection.add_point newpos", newpos) + local has_pos1 = not not wea_c.pos.get1(name) + local has_pos2 = not not wea_c.pos.get2(name) + local created_new = not has_pos1 or not has_pos2 + if not has_pos1 then wea_c.pos.set1(name, Vector3.clone(newpos)) end + if not has_pos2 then wea_c.pos.set2(name, Vector3.clone(newpos)) end + - worldedit.marker_update(name) + -- Now no longer needed, given that the new sysstem uses an event listener to push updates to the selected region automatically + -- worldedit.marker_update(name) - local volume_before = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) + local pos1, pos2 = wea_c.pos.get1(name), wea_c.pos.get2(name) - worldedit.pos1[name], worldedit.pos2[name] = Vector3.expand_region( - Vector3.clone(worldedit.pos1[name]), - Vector3.clone(worldedit.pos2[name]), - pos + local volume_before = worldedit.volume(pos1, pos2) + + + local new_pos1, new_pos2 = Vector3.expand_region( + Vector3.clone(pos1), + Vector3.clone(pos2), + newpos ) - local volume_after = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name]) + wea_c.pos.set1(name, new_pos1) + wea_c.pos.set2(name, new_pos2) + + + local volume_after = worldedit.volume(new_pos1, new_pos2) local volume_difference = volume_after - volume_before if volume_difference == 0 and created_new then @@ -42,21 +53,20 @@ function selection.add_point(name, pos) msg = msg..volume_difference.." node" if volume_difference ~= 1 then msg = msg.."s" end - worldedit.marker_update(name) + -- Done automatically + -- worldedit.marker_update(name) worldedit.player_notify(name, msg) else - worldedit.player_notify(name, "Error: Too far away (try raising your maxdist with //farwand maxdist )") + worldedit.player_notify(name, "Error. Too far away (try raising your maxdist with //farwand maxdist )") -- print("[set_pos1]", name, "nil") end end ---- Clears current selection. +--- Clears current selection, *but only pos1 and pos2! -- @param name string Player name. function selection.clear_points(name) - worldedit.pos1[name] = nil - worldedit.pos2[name] = nil - worldedit.marker_update(name) - worldedit.set_pos[name] = nil + wea_c.pos.clear(name) + -- worldedit.marker_update(name) worldedit.player_notify(name, "Region cleared") end diff --git a/worldeditadditions_commands/commands/copy.lua b/worldeditadditions_commands/commands/copy.lua index e8e8d8e..f7e67c3 100644 --- a/worldeditadditions_commands/commands/copy.lua +++ b/worldeditadditions_commands/commands/copy.lua @@ -3,6 +3,12 @@ local wea = worldeditadditions local Vector3 = wea_c.Vector3 local function parse_stage2(name, parts) + local do_airapply = false + if parts[#parts] == "aa" or parts[#parts] == "airapply" then + do_airapply = true + table.remove(parts, #parts) + end + local success, vpos1, vpos2 = wea_c.parse.axes( parts, wea_c.player_dir(name) @@ -17,7 +23,7 @@ local function parse_stage2(name, parts) return false, "Refusing to copy region a distance of 0 nodes" end - return true, offset:floor() + return true, offset:floor(), do_airapply end -- ██████ ██████ ██████ ██ ██ @@ -26,7 +32,7 @@ end -- ██ ██ ██ ██ ██ -- ██████ ██████ ██ ██ worldeditadditions_core.register_command("copy+", { -- TODO: Make this an override - params = " [ [...]]", + params = " [ [...]] [aa|airapply]", description = "Copies the defined region to another location - potentially across multiple axes at once.", privs = { worldedit = true }, require_pos = 2, @@ -43,7 +49,7 @@ worldeditadditions_core.register_command("copy+", { -- TODO: Make this an overri func = function(name, parts) local start_time = wea_c.get_ms_time() - local success_a, copy_offset = parse_stage2(name, parts) + local success_a, copy_offset, do_airapply = parse_stage2(name, parts) if not success_a then return success_a, copy_offset end local source_pos1 = Vector3.clone(worldedit.pos1[name]) @@ -54,7 +60,8 @@ worldeditadditions_core.register_command("copy+", { -- TODO: Make this an overri local success_b, nodes_modified = wea.copy( source_pos1, source_pos2, - target_pos1, target_pos2 + target_pos1, target_pos2, + do_airapply ) if not success_b then return success_b, nodes_modified end diff --git a/worldeditadditions_commands/commands/count.lua b/worldeditadditions_commands/commands/count.lua index d5c7b29..db620d2 100644 --- a/worldeditadditions_commands/commands/count.lua +++ b/worldeditadditions_commands/commands/count.lua @@ -29,7 +29,7 @@ worldeditadditions_core.register_command("count", { ) if not success then return success, counts end - local result = wea_c.format.make_ascii_table(counts).."\n".. + local result = "\n"..wea_c.format.make_ascii_table(counts).."\n".. string.rep("=", 6 + #tostring(total) + 6).."\n".. "Total "..total.." nodes\n" diff --git a/worldeditadditions_commands/commands/meta/subdivide.lua b/worldeditadditions_commands/commands/meta/subdivide.lua index e027455..a033650 100644 --- a/worldeditadditions_commands/commands/meta/subdivide.lua +++ b/worldeditadditions_commands/commands/meta/subdivide.lua @@ -116,9 +116,11 @@ worldeditadditions_core.register_command("subdivide", { end worldedit.player_notify_suppress(name) - worldedit.pos1[name] = cpos1 - worldedit.pos2[name] = cpos2 - worldedit.marker_update(name) + wea_c.pos.set1(name, cpos1) + wea_c.pos.set2(name, cpos2) + -- worldedit.pos1[name] = cpos1 + -- worldedit.pos2[name] = cpos2 + -- worldedit.marker_update(name) cmd.func(name, wea_c.table.unpack(cmd_args_parsed)) if will_trigger_saferegion(name, cmd_name, args) then minetest.chatcommands["/y"].func(name) @@ -141,9 +143,12 @@ worldeditadditions_core.register_command("subdivide", { time_last_msg = wea_c.get_ms_time() end end, function(_, _, stats) - worldedit.pos1[name] = pos1 - worldedit.pos2[name] = pos2 - worldedit.marker_update(name) + + wea_c.pos.set1(name, pos1) + wea_c.pos.set2(name, pos2) + -- worldedit.pos1[name] = pos1 + -- worldedit.pos2[name] = pos2 + -- worldedit.marker_update(name) -- Called on completion minetest.log("action", string.format("%s used //subdivide at %s - %s, with %d chunks and %d total nodes in %s", diff --git a/worldeditadditions_commands/commands/move.lua b/worldeditadditions_commands/commands/move.lua index 54320f0..fe895ac 100644 --- a/worldeditadditions_commands/commands/move.lua +++ b/worldeditadditions_commands/commands/move.lua @@ -3,6 +3,12 @@ local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 local function parse_stage2(name, parts) + local do_airapply = false + if parts[#parts] == "aa" or parts[#parts] == "airapply" then + do_airapply = true + table.remove(parts, #parts) + end + local success, vpos1, vpos2 = wea_c.parse.axes( parts, wea_c.player_dir(name) @@ -17,7 +23,7 @@ local function parse_stage2(name, parts) return false, "Refusing to move region a distance of 0 nodes" end - return true, offset:floor() + return true, offset:floor(), do_airapply end -- ███ ███ ██████ ██ ██ ███████ @@ -26,7 +32,7 @@ end -- ██ ██ ██ ██ ██ ██ ██ ██ -- ██ ██ ██████ ████ ███████ worldeditadditions_core.register_command("move+", { -- TODO: Make this an override - params = " [ [...]]", + params = " [ [...]] [aa|airapply]", description = "Moves the defined region to another location - potentially across multiple axes at once.", privs = { worldedit = true }, require_pos = 2, @@ -43,7 +49,7 @@ worldeditadditions_core.register_command("move+", { -- TODO: Make this an overri func = function(name, parts) local start_time = wea_c.get_ms_time() - local success_a, copy_offset = parse_stage2(name, parts) + local success_a, copy_offset, do_airapply = parse_stage2(name, parts) if not success_a then return success_a, copy_offset end --- 1: Calculate the source & target regions @@ -58,15 +64,18 @@ worldeditadditions_core.register_command("move+", { -- TODO: Make this an overri ----------------------------------------------------------------------- local success_b, nodes_modified = wea.move( source_pos1, source_pos2, - target_pos1, target_pos2 + target_pos1, target_pos2, + do_airapply ) if not success_b then return success_b, nodes_modified end -- 3: Update the defined region ----------------------------------------------------------------------- - worldedit.pos1[name] = target_pos1 - worldedit.pos2[name] = target_pos2 - worldedit.marker_update(name) + wea_c.pos.set1(name, target_pos1) + wea_c.pos.set2(name, target_pos2) + -- worldedit.pos1[name] = target_pos1 + -- worldedit.pos2[name] = target_pos2 + -- worldedit.marker_update(name) local time_taken = wea_c.get_ms_time() - start_time diff --git a/worldeditadditions_commands/commands/scale.lua b/worldeditadditions_commands/commands/scale.lua index 1b7b194..a70db16 100644 --- a/worldeditadditions_commands/commands/scale.lua +++ b/worldeditadditions_commands/commands/scale.lua @@ -117,9 +117,11 @@ wea_c.register_command("scale", { ) if not success then return success, stats end - worldedit.pos1[name] = stats.pos1 - worldedit.pos2[name] = stats.pos2 - worldedit.marker_update(name) + wea_c.pos.set1(name, stats.pos1) + wea_c.pos.set2(name, stats.pos2) + -- worldedit.pos1[name] = stats.pos1 + -- worldedit.pos2[name] = stats.pos2 + -- worldedit.marker_update(name) local time_taken = wea_c.get_ms_time() - start_time diff --git a/worldeditadditions_commands/commands/sculpt.lua b/worldeditadditions_commands/commands/sculpt.lua index f84ac80..f25fe37 100644 --- a/worldeditadditions_commands/commands/sculpt.lua +++ b/worldeditadditions_commands/commands/sculpt.lua @@ -9,20 +9,20 @@ local Vector3 = wea_c.Vector3 -- ██ ██ ██ ██ ██ ██ ██ -- ███████ ██████ ██████ ███████ ██ ██ worldeditadditions_core.register_command("sculpt", { - params = "[ [ []]]", + params = "[ [ []]]", description = "Applies a sculpting brush to the terrain with a given height. See //sculptlist to list all available brushes. Note that while the brush size is configurable, the actual brush size you end up with may be slightly different to that which you request due to brush size restrictions.", privs = { worldedit = true }, require_pos = 1, parse = function(params_text) if not params_text or params_text == "" then - params_text = "circle_soft1" + params_text = "circle" end local parts = wea_c.split_shell(params_text) - local brush_name = "circle_soft1" - local height = 5 - local brush_size = 10 + local brush_name = "circle" + local brush_size = 8 + local height = 1 if #parts >= 1 then brush_name = table.remove(parts, 1) @@ -30,24 +30,25 @@ worldeditadditions_core.register_command("sculpt", { return false, "A brush with the name '"..brush_name.."' doesn't exist. Try using //sculptlist to list all available brushes." end end - if #parts >= 1 then - height = tonumber(table.remove(parts, 1)) - if not height then - return false, "Invalid height value (must be an integer - negative values lower terrain instead of raising it)" - end - end if #parts >= 1 then brush_size = tonumber(table.remove(parts, 1)) if not brush_size or brush_size < 1 then return false, "Invalid brush size. Brush sizes must be a positive integer." end end + if #parts >= 1 then + height = tonumber(table.remove(parts, 1)) + if not height then + return false, + "Invalid height value (must be an integer - negative values lower terrain instead of raising it)" + end + end brush_size = Vector3.new(brush_size, brush_size, 0):floor() - return true, brush_name, math.floor(height), brush_size + return true, brush_name, brush_size, math.floor(height) end, - nodes_needed = function(name, brush_name, height, brush_size) + nodes_needed = function(name, brush_name, brush_size, height) local success, brush, size_actual = wea.sculpt.make_brush(brush_name, brush_size) if not success then return 0 end @@ -60,13 +61,13 @@ worldeditadditions_core.register_command("sculpt", { return size_actual.x * size_actual.y * range_nodes end, - func = function(name, brush_name, height, brush_size) + func = function(name, brush_name, brush_size, height) local start_time = wea_c.get_ms_time() local pos1 = wea_c.Vector3.clone(worldedit.pos1[name]) local success, stats = wea.sculpt.apply( pos1, - brush_name, height, brush_size + brush_name, brush_size, height ) if not success then return success, stats.added end diff --git a/worldeditadditions_commands/commands/selectors/spop.lua b/worldeditadditions_commands/commands/selectors/spop.lua index 231a5b4..ba20664 100644 --- a/worldeditadditions_commands/commands/selectors/spop.lua +++ b/worldeditadditions_commands/commands/selectors/spop.lua @@ -1,4 +1,5 @@ local wea = worldeditadditions +local weac = worldeditadditions_core -- ███████ ██████ ██████ ██████ @@ -20,9 +21,11 @@ worldeditadditions_core.register_command("spop", { local success, pos1, pos2 = wea.spop(name) if not success then return success, pos1 end - worldedit.pos1[name] = pos1 - worldedit.pos2[name] = pos2 - worldedit.marker_update(name) + weac.pos.set1(name, pos1) + weac.pos.set2(name, pos2) + -- worldedit.pos1[name] = pos1 + -- worldedit.pos2[name] = pos2 + -- worldedit.marker_update(name) local new_count = wea.scount(name) local plural = "s are" diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua index 7ca4c5e..67a7054 100644 --- a/worldeditadditions_commands/init.lua +++ b/worldeditadditions_commands/init.lua @@ -1,5 +1,5 @@ --- WorldEditAdditions-ChatCommands --- @module worldeditadditions_commands +-- @namespace worldeditadditions_commands -- @release 0.1 -- @copyright 2018 Starbeamrainbowlabs -- @license Mozilla Public License, 2.0 diff --git a/worldeditadditions_core/core/entities/init.lua b/worldeditadditions_core/core/entities/init.lua index f673be1..6068dba 100644 --- a/worldeditadditions_core/core/entities/init.lua +++ b/worldeditadditions_core/core/entities/init.lua @@ -11,4 +11,5 @@ local wea_c = worldeditadditions_core return { pos_marker = dofile(wea_c.modpath.."/core/entities/pos_marker.lua"), + pos_marker_wall = dofile(wea_c.modpath.."/core/entities/pos_marker_wall.lua") } \ No newline at end of file diff --git a/worldeditadditions_core/core/entities/pos_marker.lua b/worldeditadditions_core/core/entities/pos_marker.lua index 26d2d19..c12b129 100644 --- a/worldeditadditions_core/core/entities/pos_marker.lua +++ b/worldeditadditions_core/core/entities/pos_marker.lua @@ -14,12 +14,12 @@ local WEAPositionMarker = { static_save = false, textures = { - "worldeditadditions_bg.png", - "worldeditadditions_bg.png", - "worldeditadditions_bg.png", - "worldeditadditions_bg.png", - "worldeditadditions_bg.png", - "worldeditadditions_bg.png", + "worldeditadditions_core_bg.png", + "worldeditadditions_core_bg.png", + "worldeditadditions_core_bg.png", + "worldeditadditions_core_bg.png", + "worldeditadditions_core_bg.png", + "worldeditadditions_core_bg.png", } }, @@ -89,17 +89,17 @@ local function set_number(entity, display_number) if display_number < 100 then local number_right = display_number % 10 local number_left = (display_number - number_right) / 10 - texture_name = texture_name.."worldeditadditions_l"..number_left..".png" - texture_name = texture_name.."^worldeditadditions_r"..number_right..".png" + texture_name = texture_name .. "worldeditadditions_core_l" .. number_left .. ".png" + texture_name = texture_name .. "^worldeditadditions_core_r" .. number_right .. ".png" -- print("DEBUG:set_number number_left", number_left, "number_right", number_right) local colour_id = ((display_number - 1) % 12) + 1 -- Lua starts from 1, not 0 :-/ texture_name = "("..texture_name..")^[colorize:"..number_colours[colour_id]..":255" end if #texture_name > 0 then - texture_name = "worldeditadditions_bg.png^("..texture_name..")" + texture_name = "worldeditadditions_core_bg.png^(" .. texture_name .. ")" else - texture_name = "worldeditadditions_bg.png" + texture_name = "worldeditadditions_core_bg.png" end -- print("DEBUG:set_number texture_name", texture_name) diff --git a/worldeditadditions_core/core/entities/pos_marker_wall.lua b/worldeditadditions_core/core/entities/pos_marker_wall.lua new file mode 100644 index 0000000..4fdbcaf --- /dev/null +++ b/worldeditadditions_core/core/entities/pos_marker_wall.lua @@ -0,0 +1,456 @@ +local wea_c = worldeditadditions_core +local EventEmitter = worldeditadditions_core.EventEmitter +local Vector3 = wea_c.Vector3 + +local anchor + +local entity_wall_size = 10 +local collision_thickness = 0.2 + +local last_reset = tostring(wea_c.get_ms_time()) + +local WEAPositionMarkerWall = { + initial_properties = { + visual = "cube", + visual_size = { x = 1, y = 1, z = 1 }, + collisionbox = { -0.55, -0.55, -0.55, 0.55, 0.55, 0.55 }, + -- ^^ { xmin, ymin, zmin, xmax, ymax, zmax } relative to obj pos + physical = false, + collide_with_objects = false, + static_save = false, + + textures = { + "worldeditadditions_core_marker_wall.png", + "worldeditadditions_core_marker_wall.png", + "worldeditadditions_core_marker_wall.png", + "worldeditadditions_core_marker_wall.png", + "worldeditadditions_core_marker_wall.png", + "worldeditadditions_core_marker_wall.png", + } + }, + + on_activate = function(self, staticdata) + if staticdata ~= last_reset then + -- print("DEBUG:marker_wall/remove staticdata", staticdata, "last_reset", last_reset) + self.object:remove() + -- else + -- print("DEBUG:marker_wall/ok staticdata", staticdata, "type", type(staticdata), "last_reset", last_reset, "type", type(last_reset)) + end + end, + on_punch = function(self, _) + anchor.delete(self) + end, + on_blast = function(self, damage) + return false, false, {} -- Do not damage or knockback the player + end +} + +minetest.register_entity( + ":worldeditadditions:marker_wall", + WEAPositionMarkerWall +) + + +--- Updates the properties of a single wall to match it's side and size +local function single_setup(entity, size, side) + local new_props = { + visual_size = Vector3.min( + Vector3.new(10, 10, 10), + size:abs() + ) + -- x = math.min(10, math.abs(size.x)), + -- y = math.min(10, math.abs(size.y)), + -- z = math.min(10, math.abs(size.z)) + } + + local cthick = Vector3.new( + collision_thickness, + collision_thickness, + collision_thickness + ) + local cpos1 = Vector3.clone(new_props.visual_size):multiply(-1):divide(2):add(cthick) + local cpos2 = Vector3.clone(new_props.visual_size):divide(2):subtract(cthick) + + if side == "x" or side == "-x" then + new_props.visual_size = new_props.visual_size + Vector3.new( + collision_thickness - 0.1 + ) + cpos1.x = -collision_thickness + cpos2.x = collision_thickness + end + if side == "y" or side == "-y" then + new_props.visual_size.y = collision_thickness - 0.1 + cpos1.y = -collision_thickness + cpos2.y = collision_thickness + end + if side == "z" or side == "-z" then + new_props.visual_size.z = collision_thickness - 0.1 + cpos1.z = -collision_thickness + cpos2.z = collision_thickness + end + + new_props.collisionbox = { + cpos1.x, cpos1.y, cpos1.z, + cpos2.x, cpos2.y, cpos2.z + } + + -- print("DEBUG:setup_single size", size, "side", side, "new_props", wea_c.inspect(new_props)) + + entity:set_properties(new_props) +end + +--- Creates a single marker wall entity. +-- @param player_name string The name of the player it should belong to. +-- @param pos1 Vector3 The pos1 corner of the area the SINGLE marker should cover. +-- @param pos2 Vector3 The pos2 corner of the area the SINGLE marker should cover. +-- @param side string The side that this wall is on. Valid values: x, -x, y, -y, z, -z. +-- @returns Entity +local function create_single(player_name, pos1, pos2, side) + + + local pos_centre = ((pos2 - pos1) / 2) + pos1 + local entity = minetest.add_entity(pos_centre, "worldeditadditions:marker_wall", last_reset) + -- print("DEBUG:marker_wall create_single --> START player_name", player_name, "pos1", pos1, "pos2", pos2, "side", side, "SPAWN", pos_centre, "last_reset", last_reset) + + entity:get_luaentity().player_name = player_name + + single_setup(entity, pos2 - pos1, side) + + return entity +end + + +--- Creates a marker wall around the defined region. +-- @param player_name string The name of the player that the wall belongs to. +-- @param pos1 Vector3 pos1 of the defined region. +-- @param pos2 Vector3 pos2 of the defined region. +-- @param sides_to_display string The sides of the marker wall that should actually be displayed, squished together into a single string. Defaults to "+x-x+z-z". Use "+x-x+z-z+y-y" to display all sides; add and remove sides as desired. +-- @returns table A list of all created entities. +local function create_wall(player_name, pos1, pos2, sides_to_display) + if not sides_to_display then + sides_to_display = "+x-x+z-z" -- this matches WorldEdit + -- To display all of them: + -- sides_to_display = "+x-x+z-z+y-y" + end + -- print("DEBUG:marker_wall create_wall --> START player_name", player_name, "pos1", pos1, "pos2", pos2) + local pos1s, pos2s = Vector3.sort(pos1, pos2) + + local entities = {} + -- local dim1, dim2 + -- if side == "x" or side == "-x" then dim1, dim2 = size.z, size.y + -- elseif side == "z" or size == "-z" then dim1, dim2 = size.x, size.y + -- elseif side == "y" or size == "-y" then dim1, dim2 = size.x, size.z + -- end + + -- x → z, y + -- z → x, y + -- y → x, z + + -- ██ ██ + -- ██ ██ ██ + -- ██████ ███ + -- ██ ██ ██ + -- ██ ██ + -- First, do positive x + if string.find(sides_to_display, "+x") then + local posx_pos1 = Vector3.new( + math.max(pos1s.x, pos2s.x) + 0.5, + math.min(pos1s.y, pos2s.y) - 0.5, + math.min(pos1s.z, pos2s.z) - 0.5 + ) + local posx_pos2 = Vector3.new( + math.max(pos1s.x, pos2s.x) + 0.5, + math.max(pos1s.y, pos2s.y) + 0.5, + math.max(pos1s.z, pos2s.z) + 0.5 + ) + + -- print("DEBUG ************ +X pos1", posx_pos1, "pos2", posx_pos2) + + for z = posx_pos2.z, posx_pos1.z, -entity_wall_size do + for y = posx_pos2.y, posx_pos1.y, -entity_wall_size do + local single_pos1 = Vector3.new( + posx_pos1.x, + y, + z + ) + local single_pos2 = Vector3.new( + posx_pos1.x, + math.max(y - entity_wall_size, posx_pos1.y), + math.max(z - entity_wall_size, posx_pos1.z) + ) + + local entity = create_single(player_name, + single_pos1, single_pos2, + "x" + ) + table.insert(entities, entity) + end + end + + end + + + -- ██ ██ + -- ██ ██ + -- ██████ ███ + -- ██ ██ + -- ██ ██ + -- Now, do negative x + if string.find(sides_to_display, "-x") then + local negx_pos1 = Vector3.new( + math.min(pos1s.x, pos2s.x) - 0.5, + math.min(pos1s.y, pos2s.y) - 0.5, + math.min(pos1s.z, pos2s.z) - 0.5 + ) + local negx_pos2 = Vector3.new( + math.min(pos1s.x, pos2s.x) - 0.5, + math.max(pos1s.y, pos2s.y) + 0.5, + math.max(pos1s.z, pos2s.z) + 0.5 + ) + -- print("DEBUG ************ -X pos1", negx_pos1, "pos2", negx_pos2) + + for z = negx_pos2.z, negx_pos1.z, -entity_wall_size do + for y = negx_pos2.y, negx_pos1.y, -entity_wall_size do + local single_pos1 = Vector3.new( + negx_pos1.x, + y, + z + ) + local single_pos2 = Vector3.new( + negx_pos1.x, + math.max(y - entity_wall_size, negx_pos1.y), + math.max(z - entity_wall_size, negx_pos1.z) + ) + + local entity = create_single(player_name, + single_pos1, single_pos2, + "-x" + ) + table.insert(entities, entity) + end + end + + end + + + -- ██ ██ + -- ██ ██ ██ + -- ██████ ████ + -- ██ ██ + -- ██ + -- Now, positive y + if string.find(sides_to_display, "+y") then + local posy_pos1 = Vector3.new( + math.min(pos1s.x, pos2s.x) - 0.5, + math.max(pos1s.y, pos2s.y) + 0.5, + math.min(pos1s.z, pos2s.z) - 0.5 + ) + local posy_pos2 = Vector3.new( + math.max(pos1s.x, pos2s.x) + 0.5, + math.max(pos1s.y, pos2s.y) + 0.5, + math.max(pos1s.z, pos2s.z) + 0.5 + ) + + -- print("DEBUG ************ +Y pos1", posy_pos1, "pos2", posy_pos2) + + for z = posy_pos2.z, posy_pos1.z, -entity_wall_size do + for x = posy_pos2.x, posy_pos1.x, -entity_wall_size do + local single_pos1 = Vector3.new( + x, + posy_pos1.y, + z + ) + local single_pos2 = Vector3.new( + math.max(x - entity_wall_size, posy_pos1.x), + posy_pos1.y, + math.max(z - entity_wall_size, posy_pos1.z) + ) + + local entity = create_single(player_name, + single_pos1, single_pos2, + "y" + ) + table.insert(entities, entity) + end + end + + end + + -- ██ ██ + -- ██ ██ + -- ██████ ████ + -- ██ + -- ██ + -- Now, negative y + if string.find(sides_to_display, "-y") then + local negy_pos1 = Vector3.new( + math.min(pos1s.x, pos2s.x) - 0.5, + math.min(pos1s.y, pos2s.y) - 0.5, + math.min(pos1s.z, pos2s.z) - 0.5 + ) + local negy_pos2 = Vector3.new( + math.max(pos1s.x, pos2s.x) + 0.5, + math.min(pos1s.y, pos2s.y) - 0.5, + math.max(pos1s.z, pos2s.z) + 0.5 + ) + + -- print("DEBUG ************ -Y pos1", negy_pos1, "pos2", negy_pos2) + + for z = negy_pos2.z, negy_pos1.z, -entity_wall_size do + for x = negy_pos2.x, negy_pos1.x, -entity_wall_size do + local single_pos1 = Vector3.new( + x, + negy_pos1.y, + z + ) + local single_pos2 = Vector3.new( + math.max(x - entity_wall_size, negy_pos1.x), + negy_pos1.y, + math.max(z - entity_wall_size, negy_pos1.z) + ) + + local entity = create_single(player_name, + single_pos1, single_pos2, + "-y" + ) + table.insert(entities, entity) + end + end + + end + + -- ███████ + -- ██ ███ + -- ██████ ███ + -- ██ ███ + -- ███████ + -- Now, positive z. Almost there! + if string.find(sides_to_display, "+z") then + local posz_pos1 = Vector3.new( + math.min(pos1s.x, pos2s.x) - 0.5, + math.min(pos1s.y, pos2s.y) - 0.5, + math.max(pos1s.z, pos2s.z) + 0.5 + ) + local posz_pos2 = Vector3.new( + math.max(pos1s.x, pos2s.x) + 0.5, + math.max(pos1s.y, pos2s.y) + 0.5, + math.max(pos1s.z, pos2s.z) + 0.5 + ) + + -- print("DEBUG ************ +Z pos1", posz_pos1, "pos2", posz_pos2) + + for x = posz_pos2.x, posz_pos1.x, -entity_wall_size do + for y = posz_pos2.y, posz_pos1.y, -entity_wall_size do + local single_pos1 = Vector3.new( + x, + y, + posz_pos1.z + ) + local single_pos2 = Vector3.new( + math.max(x - entity_wall_size, posz_pos1.x), + math.max(y - entity_wall_size, posz_pos1.y), + posz_pos1.z + ) + + local entity = create_single(player_name, + single_pos1, single_pos2, + "z" + ) + table.insert(entities, entity) + end + end + + end + + + -- ███████ + -- ███ + -- ██████ ███ + -- ███ + -- ███████ + -- Finally, negative z. Last one! + if string.find(sides_to_display, "-z") then + local negz_pos1 = Vector3.new( + math.min(pos1s.x, pos2s.x) - 0.5, + math.min(pos1s.y, pos2s.y) - 0.5, + math.min(pos1s.z, pos2s.z) - 0.5 + ) + local negz_pos2 = Vector3.new( + math.max(pos1s.x, pos2s.x) + 0.5, + math.max(pos1s.y, pos2s.y) + 0.5, + math.min(pos1s.z, pos2s.z) - 0.5 + ) + + -- print("DEBUG ************ -Z pos1", negz_pos1, "pos2", negz_pos2) + + for x = negz_pos2.x, negz_pos1.x, -entity_wall_size do + for y = negz_pos2.y, negz_pos1.y, -entity_wall_size do + local single_pos1 = Vector3.new( + x, + y, + negz_pos1.z + ) + local single_pos2 = Vector3.new( + math.max(x - entity_wall_size, negz_pos1.x), + math.max(y - entity_wall_size, negz_pos1.y), + negz_pos1.z + ) + + local entity = create_single(player_name, + single_pos1, single_pos2, + "-z" + ) + table.insert(entities, entity) + end + end + + end + + + -- TODO: All the other sides. For testing we're doing 1 side for now, so we can vaoid having to do everything all over again if we make a mistake. + + + + -- for z = pos2.z, pos1.z, -entity_wall_size do + -- for y = pos2.y, pos1.y, -entity_wall_size do + -- for x = pos2.x, pos1.x, -entity_wall_size do + + -- end + -- end + -- end + + return entities +end + + +--- Deletes all entities in the given entity list +-- @param entitylist table A list of wall entities that make up the wall to delete. +local function delete(entitylist) + -- print("DEBUG:marker_wall delete --> START with "..#entitylist.." entities") + local player_name + for _, entity in ipairs(entitylist) do + if not entity.get_luaentity or not entity:get_luaentity() then return end -- Ensure the entity is still valid + + if not player_name then + player_name = entity:get_luaentity().player_name + end + + entity:remove() + end + + last_reset = tostring(wea_c.get_ms_time()) + -- print("DEBUG:marker_wall delete --> LAST_RESET is now", last_reset, "type", type(last_reset)) + + anchor:emit("delete", { + player_name = player_name + }) + + +end + +anchor = EventEmitter.new({ + create = create_wall, + delete = delete +}) + +return anchor \ No newline at end of file diff --git a/worldeditadditions_core/core/pos.lua b/worldeditadditions_core/core/pos.lua index 924e2ed..ea0bdfe 100644 --- a/worldeditadditions_core/core/pos.lua +++ b/worldeditadditions_core/core/pos.lua @@ -5,12 +5,32 @@ local positions_count_limit = 999 local positions = {} --- Position manager. --- @event set { player_name: string, i: number, pos: Vector3 } A new position has been set in a player's list at a specific position. --- @event push { player_name: string, i: number, pos: Vector3 } A new position has been pushed onto a player's stack. --- @event pop { player_name: string, i: number, pos: Vector3 } A new position has been pushed onto a player's stack. --- @event clear { player_name: string } The positions for a player have been cleared. +-- @namespace worldeditadditions_core.pos local anchor = nil + +--- A new position has been set in a player's list at a specific position. +-- @event set +-- @format { player_name: string, i: number, pos: Vector3 } +-- @example +-- { +-- player_name = "some_player_name", +-- i = 3, +-- pos = { x = 456, y = 64, z = 9045 } +-- } + +--- A new position has been pushed onto a player's stack. +-- @event push +-- @format { player_name: string, i: number, pos: Vector3 } + +--- A new position has been pushed onto a player's stack. +-- @event pop +-- @format { player_name: string, i: number, pos: Vector3 } + +--- The positions for a player have been cleared. +-- @event clear +-- @format { player_name: string } + --- Ensures that a table exists for the given player. -- @param player_name string The name of the player to check. local function ensure_player(player_name) @@ -146,6 +166,7 @@ end -- @param pos Vector3 The position to set. -- @returns bool Whether the operation was successful or not (players aren't allowed more than positions_count_limit number of positions at a time). local function set(player_name, i, pos) + -- It's a shame that Lua doesn't have a throw/raise, 'cause we could sure use it here if i > positions_count_limit then return false end ensure_player(player_name) @@ -196,6 +217,7 @@ local function clear(player_name) if worldedit then if worldedit.pos1 then worldedit.pos1[player_name] = nil end if worldedit.pos2 then worldedit.pos2[player_name] = nil end + if worldedit.set_pos then worldedit.set_pos[player_name] = nil end end anchor:emit("clear", { player_name = player_name }) end @@ -245,6 +267,6 @@ anchor = wea_c.EventEmitter.new({ set_all = set_all, compat_worldedit_get = compat_worldedit_get }) -anchor.debug = true +anchor.debug = false return anchor diff --git a/worldeditadditions_core/core/pos_marker_manage.lua b/worldeditadditions_core/core/pos_marker_manage.lua index 8b553ae..e9412d0 100644 --- a/worldeditadditions_core/core/pos_marker_manage.lua +++ b/worldeditadditions_core/core/pos_marker_manage.lua @@ -77,5 +77,9 @@ wea_c.pos:addEventListener("clear", function(event) wea_c.entities.pos_marker.delete(entity) end end + -- For compatibility, ensure that we also clear the legacy worldedit region too + if worldedit and worldedit.marker_update then + worldedit.marker_update(event.player_name) + end position_entities[event.player_name] = nil end) \ No newline at end of file diff --git a/worldeditadditions_core/core/pos_marker_wall_manage.lua b/worldeditadditions_core/core/pos_marker_wall_manage.lua new file mode 100644 index 0000000..7a4ac84 --- /dev/null +++ b/worldeditadditions_core/core/pos_marker_wall_manage.lua @@ -0,0 +1,72 @@ +local weac = worldeditadditions_core + +local wall_entity_lists = {} + +--- Ensures that a table exists for the given player. +-- @param player_name string The name of the player to check. +local function ensure_player(player_name) + if player_name == nil then + minetest.log("error", "[wea core:pos_manage:ensure_player] player_name is nil") + end + if not wall_entity_lists[player_name] then + wall_entity_lists[player_name] = {} + end +end + +--- Deletes the currently displayed marker wall. +-- @param event EventArgs The event args for the set, push, pop, or clear events on wea_c.pos. +-- @returns void +local function do_delete(event) + if not wall_entity_lists[event.player_name] then return end + -- print("DEBUG:marker_wall_manage do_delete --> deleting pre-existing wall with "..tostring(#wall_entity_lists[event.player_name]).." entities") + if #wall_entity_lists[event.player_name] > 0 then + weac.entities.pos_marker_wall.delete(wall_entity_lists[event.player_name]) + end + + wall_entity_lists[event.player_name] = nil +end + +--- Updates the marker wall as appropriate. +-- @param event EventArgs The event args for the set, push, or pop events on wea_c.pos. +-- @returns void +local function do_update(event) + -- print("DEBUG:marker_wall_manage do_update --> START") + -- We don't dynamically update, as that'd be too much work. + -- Instead, we just delete & recreate each time. + if wall_entity_lists[event.player_name] then + -- print("DEBUG:marker_wall_manage do_update --> do_delete") + do_delete(event) + end + + local pos1 = weac.pos.get1(event.player_name) + local pos2 = weac.pos.get2(event.player_name) + -- print("DEBUG:marker_wall_manage do_update --> pos1", pos1, "pos2", pos2) + + if not pos1 or not pos2 then return end + + wall_entity_lists[event.player_name] = weac.entities.pos_marker_wall.create( + event.player_name, + pos1, + pos2 + ) + -- print("DEBUG:marker_wall_manage do_update --> entitylist", weac.inspect(wall_entity_lists[event.player_name])) +end + + + +local function needs_update(event) + if event.i > 2 then + return false + end + return true +end + +local function handle_event(event) + if needs_update(event) then do_update(event) end +end + + +weac.pos:addEventListener("set", handle_event) +weac.pos:addEventListener("pop", handle_event) +weac.pos:addEventListener("push", handle_event) +weac.pos:addEventListener("clear", do_delete) \ No newline at end of file diff --git a/worldeditadditions_core/init.lua b/worldeditadditions_core/init.lua index 454ad44..f9aca2b 100644 --- a/worldeditadditions_core/init.lua +++ b/worldeditadditions_core/init.lua @@ -1,14 +1,10 @@ --- WorldEditAdditions-Core --- @module worldeditadditions_core +-- @namespace worldeditadditions_core -- @release 1.13 -- @copyright 2021 Starbeamrainbowlabs and VorTechnix -- @license Mozilla Public License, 2.0 -- @author Starbeamrainbowlabs and VorTechnix --- local temp = true --- if temp then return end --- This mod isn't finished yet, so it will not be executed for now. - local modpath = minetest.get_modpath("worldeditadditions_core") @@ -67,6 +63,7 @@ wea_c.fetch_command_def = dofile(modpath.."/core/fetch_command_def.lua") wea_c.register_alias = dofile(modpath.."/core/register_alias.lua") wea_c.entities = dofile(modpath.."/core/entities/init.lua") -- AFTER pos dofile(modpath.."/core/pos_marker_manage.lua") -- AFTER pos, entities +dofile(modpath.."/core/pos_marker_wall_manage.lua") -- AFTER pos, entities -- Initialise WorldEdit stuff if the WorldEdit mod is not present if minetest.global_exists("worldedit") then diff --git a/worldeditadditions_farwand/textures/worldeditadditions_bg.png b/worldeditadditions_core/textures/worldeditadditions_core_bg.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_bg.png rename to worldeditadditions_core/textures/worldeditadditions_core_bg.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l0.png b/worldeditadditions_core/textures/worldeditadditions_core_l0.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l0.png rename to worldeditadditions_core/textures/worldeditadditions_core_l0.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l1.png b/worldeditadditions_core/textures/worldeditadditions_core_l1.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l1.png rename to worldeditadditions_core/textures/worldeditadditions_core_l1.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l2.png b/worldeditadditions_core/textures/worldeditadditions_core_l2.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l2.png rename to worldeditadditions_core/textures/worldeditadditions_core_l2.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l3.png b/worldeditadditions_core/textures/worldeditadditions_core_l3.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l3.png rename to worldeditadditions_core/textures/worldeditadditions_core_l3.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l4.png b/worldeditadditions_core/textures/worldeditadditions_core_l4.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l4.png rename to worldeditadditions_core/textures/worldeditadditions_core_l4.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l5.png b/worldeditadditions_core/textures/worldeditadditions_core_l5.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l5.png rename to worldeditadditions_core/textures/worldeditadditions_core_l5.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l6.png b/worldeditadditions_core/textures/worldeditadditions_core_l6.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l6.png rename to worldeditadditions_core/textures/worldeditadditions_core_l6.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l7.png b/worldeditadditions_core/textures/worldeditadditions_core_l7.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l7.png rename to worldeditadditions_core/textures/worldeditadditions_core_l7.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l8.png b/worldeditadditions_core/textures/worldeditadditions_core_l8.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l8.png rename to worldeditadditions_core/textures/worldeditadditions_core_l8.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_l9.png b/worldeditadditions_core/textures/worldeditadditions_core_l9.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_l9.png rename to worldeditadditions_core/textures/worldeditadditions_core_l9.png diff --git a/worldeditadditions_core/textures/worldeditadditions_core_marker_wall.png b/worldeditadditions_core/textures/worldeditadditions_core_marker_wall.png new file mode 100644 index 0000000..f80279e Binary files /dev/null and b/worldeditadditions_core/textures/worldeditadditions_core_marker_wall.png differ diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r0.png b/worldeditadditions_core/textures/worldeditadditions_core_r0.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r0.png rename to worldeditadditions_core/textures/worldeditadditions_core_r0.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r1.png b/worldeditadditions_core/textures/worldeditadditions_core_r1.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r1.png rename to worldeditadditions_core/textures/worldeditadditions_core_r1.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r2.png b/worldeditadditions_core/textures/worldeditadditions_core_r2.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r2.png rename to worldeditadditions_core/textures/worldeditadditions_core_r2.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r3.png b/worldeditadditions_core/textures/worldeditadditions_core_r3.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r3.png rename to worldeditadditions_core/textures/worldeditadditions_core_r3.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r4.png b/worldeditadditions_core/textures/worldeditadditions_core_r4.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r4.png rename to worldeditadditions_core/textures/worldeditadditions_core_r4.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r5.png b/worldeditadditions_core/textures/worldeditadditions_core_r5.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r5.png rename to worldeditadditions_core/textures/worldeditadditions_core_r5.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r6.png b/worldeditadditions_core/textures/worldeditadditions_core_r6.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r6.png rename to worldeditadditions_core/textures/worldeditadditions_core_r6.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r7.png b/worldeditadditions_core/textures/worldeditadditions_core_r7.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r7.png rename to worldeditadditions_core/textures/worldeditadditions_core_r7.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r8.png b/worldeditadditions_core/textures/worldeditadditions_core_r8.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r8.png rename to worldeditadditions_core/textures/worldeditadditions_core_r8.png diff --git a/worldeditadditions_farwand/textures/worldeditadditions_r9.png b/worldeditadditions_core/textures/worldeditadditions_core_r9.png similarity index 100% rename from worldeditadditions_farwand/textures/worldeditadditions_r9.png rename to worldeditadditions_core/textures/worldeditadditions_core_r9.png diff --git a/worldeditadditions_core/utils/lru.lua b/worldeditadditions_core/utils/lru.lua index 139ea6f..e2fb0e2 100644 --- a/worldeditadditions_core/utils/lru.lua +++ b/worldeditadditions_core/utils/lru.lua @@ -6,7 +6,7 @@ else end --- A least-recently-used cache implementation. --- @class +-- @class worldeditadditions_core.LRU local LRU = {} LRU.__index = LRU diff --git a/worldeditadditions_core/utils/mesh.lua b/worldeditadditions_core/utils/mesh.lua index 28271fd..9815bab 100644 --- a/worldeditadditions_core/utils/mesh.lua +++ b/worldeditadditions_core/utils/mesh.lua @@ -8,7 +8,7 @@ local wea_c = worldeditadditions_core -- ██ ██ ██ ██████ ███████ --- A single face of a Mesh. --- @class +-- @class worldeditadditions_core.Face local Face = {} Face.__index = Face @@ -42,7 +42,7 @@ function Face.__eq(a, b) return Face.equal(a, b) end -- ██ ██ ███████ ███████ ██ ██ --- A mesh of faces. --- @class +-- @class worldeditadditions_core.Mesh local Mesh = {} Mesh.__index = Mesh diff --git a/worldeditadditions_core/utils/parse/key_instance.lua b/worldeditadditions_core/utils/parse/key_instance.lua index 1cec51d..727fa43 100644 --- a/worldeditadditions_core/utils/parse/key_instance.lua +++ b/worldeditadditions_core/utils/parse/key_instance.lua @@ -1,6 +1,7 @@ --- A container for transmitting (axis table, sign) or (dir, sign) pairs -- and other data within parsing functions. --- @class +-- @internal +-- @class worldeditadditions_core.parse.key_instance local key_instance = {} key_instance.__index = key_instance key_instance.__name = "Key Instance" diff --git a/worldeditadditions_core/utils/queue.lua b/worldeditadditions_core/utils/queue.lua index 197ff2e..9bda947 100644 --- a/worldeditadditions_core/utils/queue.lua +++ b/worldeditadditions_core/utils/queue.lua @@ -1,8 +1,7 @@ ------------------------------------------------------------------------------- --- A Queue implementation -- Taken & adapted from https://www.lua.org/pil/11.4.html --- @submodule worldeditadditions.utils.queue --- @class +-- @class worldeditadditions_core.Queue local Queue = {} Queue.__index = Queue diff --git a/worldeditadditions_core/utils/setting_handler.lua b/worldeditadditions_core/utils/setting_handler.lua index 11c5106..25d0081 100644 --- a/worldeditadditions_core/utils/setting_handler.lua +++ b/worldeditadditions_core/utils/setting_handler.lua @@ -1,4 +1,3 @@ ---- A wrapper to simultaniously handle global and world settings. -- Initialize settings container local wea_c = worldeditadditions_core @@ -8,7 +7,8 @@ wea_c.settings = {} local path = minetest.get_worldpath() .. "/worldeditadditions" minetest.mkdir(path) --- @class +--- A wrapper to simultaniously handle global and world settings. +-- @namespace worldeditadditions_core.setting_handler local setting_handler = {} --- Reads world settings into WEA core settings object diff --git a/worldeditadditions_core/utils/strings/split_shell.lua b/worldeditadditions_core/utils/strings/split_shell.lua index ac0ea4a..ac1d858 100644 --- a/worldeditadditions_core/utils/strings/split_shell.lua +++ b/worldeditadditions_core/utils/strings/split_shell.lua @@ -1,7 +1,16 @@ -- worldeditadditions_core = { modpath="/home/sbrl/.minetest/worlds/Mod-Sandbox/worldmods/WorldEditAdditions/worldeditadditions_core/" } -local wea_c = worldeditadditions_core -local table_map = dofile(wea_c.modpath.."/utils/table/table_map.lua") +local table_map, polyfill + +if minetest then + local wea_c = worldeditadditions_core + table_map = dofile(wea_c.modpath.."/utils/table/table_map.lua") + polyfill = wea_c +else + table_map = require("worldeditadditions_core.utils.table.table_map") + polyfill = require("worldeditadditions_core.utils.strings.polyfill") +end + local function is_whitespace(char) return char:match("%s") end @@ -13,6 +22,7 @@ local function split_shell(text, autotrim) local acc = {} local mode = "NORMAL" -- NORMAL, INSIDE_QUOTES_SINGLE, INSIDE_QUOTES_DOUBLE + -- print("\n\n\n\n\nDEBUG:split_shell START text", text, "autotrim", autotrim) for i=1,text_length do local prevchar = "" @@ -27,7 +37,7 @@ local function split_shell(text, autotrim) if mode == "NORMAL" then if is_whitespace(curchar) and #acc > 0 then - local nextval = wea_c.trim(table.concat(acc, "")) + local nextval = polyfill.trim(table.concat(acc, "")) if #nextval > 0 then table.insert(result, table.concat(acc, "")) end @@ -54,7 +64,7 @@ local function split_shell(text, autotrim) table.insert(acc, curchar) end elseif mode == "INSIDE_QUOTES_SINGLE" then - if curchar == "'" and prevchar ~= "\\" and is_whitespace(nextchar) then + if curchar == "'" and prevchar ~= "\\" and (is_whitespace(nextchar) or nextchar == "") then -- It's the end of a quote! mode = "NORMAL" elseif (curchar == "\\" and ( diff --git a/worldeditadditions_core/utils/vector3.lua b/worldeditadditions_core/utils/vector3.lua index be0c92f..8bb7093 100644 --- a/worldeditadditions_core/utils/vector3.lua +++ b/worldeditadditions_core/utils/vector3.lua @@ -1,5 +1,5 @@ --- A 3-dimensional vector. --- @class +-- @class worldeditadditions_core.Vector3 local Vector3 = {} Vector3.__index = Vector3 Vector3.__name = "Vector3" -- A hack to allow identification in wea.inspect @@ -126,7 +126,6 @@ function Vector3.round(a) end --- Rounds the components of this vector to the specified number of decimal places. --- TODO: Document this. -- @param a Vector3 The vector to round. -- @param dp number The number of decimal places to round to. -- @returns Vector3 A new instance with the components rounded to the specified number of decimal places. @@ -174,7 +173,7 @@ function Vector3.length(a) return math.sqrt(a:length_squared()) end ---- Calculates the volume of the region bounded by 1 points. +--- Calculates the volume of the region bounded by 2 points. -- @param a Vector3 The first point bounding the target region. -- @param b Vector3 The second point bounding the target region. -- @returns number The volume of the defined region. @@ -419,13 +418,13 @@ end -- function. Either that, or Blender 3 (https://blender.org/) is quite useful to visualise what's going on. -- @source GitHub Copilot, generated 2023-01-17 -- @warning Not completely tested! Pending a thorough evaluation. Seems to basically work, after some tweaks to the fluff around the edges? --- @param {Vector3} origin The origin point to rotate around --- @param {Vector3} point The point to rotate. --- @param {Vector3} rotate Rotate this much around the 3 different axes, x, y, and z. Axial rotations are handled in this order: X→Y→Z. --- @param {Number} x Rotate this much around the X axis (yz plane), in radians. --- @param {Number} y Rotate this much around the Y axis (xz plane), in radians. --- @param {Number} z Rotate this much around the Z axis (xy plane), in radians. --- @return {Vector3} The rotated point. +-- @param origin Vector3 The origin point to rotate around +-- @param point Vector3 The point to rotate. +-- @param rotate Vector3 Rotate this much around the 3 different axes, x, y, and z. Axial rotations are handled in this order: X→Y→Z. +-- @param x number Rotate this much around the X axis (yz plane), in radians. +-- @param y number Rotate this much around the Y axis (xz plane), in radians. +-- @param z number Rotate this much around the Z axis (xy plane), in radians. +-- @return Vector3 The rotated point. function Vector3.rotate3d(origin, point, rotate) local point_norm = point - origin diff --git a/worldeditadditions_farwand/edit/brush.piskel b/worldeditadditions_farwand/edit/brush.piskel new file mode 100644 index 0000000..e8a58c1 --- /dev/null +++ b/worldeditadditions_farwand/edit/brush.piskel @@ -0,0 +1 @@ +{"modelVersion":2,"piskel":{"name":"New Piskel","description":"","fps":0,"height":16,"width":16,"layers":["{\"name\":\"bg\",\"opacity\":1,\"frameCount\":2,\"chunks\":[{\"layout\":[[0],[1]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAArklEQVRIS2NkGGDAOMD2M4w6YDQERkNg+ITAz9df/4PKFHZRbpI8RZJifIUWyAHTWo8xFE5wJclMkhTjc0BVyIb/AqJcDGXT3cBm2m9z+i/EK8Sw3nYNXjuo4gCQ5SBLQQ4AgbVmDWCaQ5wDTB/02ofTHqo4INtz7n9+bmF4AIEcgu4IXA6h2AGx9h3/+bhEwZbDHIEcFebzrcChAwInE49h2EexA0ipTWGOQXYIAGP4KxGpw5fjAAAAAElFTkSuQmCC\"}]}","{\"name\":\"main\",\"opacity\":1,\"frameCount\":2,\"chunks\":[{\"layout\":[[0],[1]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAABJ0lEQVRIS2PcWav7n4GBgcG9+TIjiCYVUKqfcUGOOtgBkoJsZDmCUv1gX7dHK/4HOYBch1CiHx7sIENgDiAnNMjVD3dAnpc0igNIdQS5+lESHrIhsNBImHKT6MRJjn4Mw2GGwBxgpMRDUuIkVT9W34VaioITJTImJZuSoh9n8JJiCLayg1j9eOOXWENwFV7E6CeYwDwMhf6rSXLCo4OURAlyGCH9BB0AMiTBUeI/HyczQ0q6EQOPmAHYw0qWzUTpJaSfaEPOLDP9z8YtAbYc5AhSHADSg0s/0Q7YOlnvv7gwO9gBIIeQ6ghk/dk/WRk4xDkYDnrtYyTaASCLQYaAaJBDQI7Q899Msv6ie3/AloPwycRjpDkAltphviHHESAz1Au1/sMcAQADxIMgEWtmUwAAAABJRU5ErkJggg==\"}]}","{\"name\":\"overlay\",\"opacity\":1,\"frameCount\":2,\"chunks\":[{\"layout\":[[0],[1]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAIklEQVRIS2NkGGDAOMD2M4w6YDQERkNgNARGQ2A0BEZDAABMmAARhe0y0gAAAABJRU5ErkJggg==\"}]}"]}} \ No newline at end of file diff --git a/worldeditadditions_farwand/edit/worldedit_wand.piskel b/worldeditadditions_farwand/edit/worldedit_wand.piskel index e2e7ee9..9a5e7b7 100644 --- a/worldeditadditions_farwand/edit/worldedit_wand.piskel +++ b/worldeditadditions_farwand/edit/worldedit_wand.piskel @@ -1 +1 @@ -{"modelVersion":2,"piskel":{"name":"worldedit_wand","description":"","fps":0,"height":16,"width":16,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":5,\"chunks\":[{\"layout\":[[0],[1],[2],[3],[4]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAQCAYAAACBSfjBAAADRElEQVRYR+3YW0hTcRwH8O9Jp25uml1kupBIG+tqF60gVIoigi7kQwhBdK/Hoig1JMJuFtjlwUh6CYkuVHQhCSoqSypbdhlFZo7M1mYtnTu7uO3MX5zFxErr/18PDek87eF8f+e3z/9y/ptQI4A0BuChX4uKFpuACK6eW+kkmEUE3SJit4CrhnZjPKlGxWGo+h4crgKYy0SufLhdIiJruwtuj4SxY1K4aySfT6LAIwmeSg9XVqidJNCjJsKUxfkovFjHFZabp6saCnYFEONVhADhB2J3sCMuqmkhh+gKOXh8QTRumcbdwyebSElJSjidXnQ4vJhoSGWuYZ87lxwmE6aWeCEDfpxlhL+pC+knZjPVEIqz0ijbkIGX9x9DP2M0Vt98zxTsHflqDYU/RwrY/HU6AmIQMYrbWHktH2X13Vw9NJs7KVEVG9Hs+6zX02u7HQWHlDC3WqCJeYZuox0Z1+Yz9dB70/E8LVltNqjG56D4ipEpLMNJh9ELKM++/VcTuACmnk0lnxhA0E3w289hzZ2lXHl56b5q+oL4OAUsVjscjk6Y9rEPwoYrrWS0eNHgM6DODNQ38vX/A9TRojwyN97HuNxsbDr9gh2x4juijJeTFgej1c+FIGfLZyeEavDm79Y3ky5tBHz+AN61vA8BtlWxD4K8hbxta8eSY1VIzrzA/fxfkHbP05Kzyw5V1nSUn3nMjBhexjIEL0Lf9xZv/vL1BpLRVq1YIEQ6CJUZm+mp+w1Of70RqsHTf79A2wqzSTvECUGpxtYaU9Qj/nxw4EX4m/yAOCUL0yhJqUDPsEzsPHnnP+IAx7vfwuxdN4cUHWZIggKlF99FhKhNVsLW5eXeE8P7YrTn/4hStTaHPrW2QKGbgF2nHvzx/v6Wg4zQ/MWLg0/4jid9EaM1zwRSWpRL6bEutHc4UV5rYcr0hdyem0BjR0aOGM15Zow9y8aQSiHgg5SII5deMufCkNGMwPLrdaD+uSA2F04mXZwIl9SD3RdaubJyk4MRkRthxxItpQ5XwyKpUVnznDs/2BC5AeSZVLJuJvmsJuh1w7Gpuo27xmBC5P7y4f3iwHINpUgiNl5i/+elvxfL+trOiHoID8K/zn8DbQVu1uI+550AAAAASUVORK5CYII=\"}]}"]}} \ No newline at end of file +{"modelVersion":2,"piskel":{"name":"worldedit_wand","description":"","fps":0,"height":16,"width":16,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":5,\"chunks\":[{\"layout\":[[0],[1],[2],[3],[4]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAQCAYAAACBSfjBAAADB0lEQVRYR+2WXUhTYRjH/wd1btacgZmaeZFpRgrZF4GQIEQE9gERCEKF9HWpN1oXIlIkGRgUCHVVlGBlUErRRdEHDEqXXZiRLUdipubMsx2348623niPvGsz3c57CmTgA7s4O/yf53l/z8d5BQD49SybCA4JQY+ExFoI9D+tlnk6maTkGJC28hXEmTI4GiQuPYtDCCFjEzPweAPIX7+K24flXirxvwnA2+rl1oaftbLqGKHPHe23NPkRSJeZBF1+JMhJKkAoQGK9dogVt4eIKM2oOXh9QfTVbtUUODzp7+MSSU01we2W8VOUUVSYodmHs7yciP39KDkngwL8tssGZdCF7Oulmn2wXJoaW1R4zBqb6mL6EMgNc0ikF6B9ahv8UhAJSc9xtHs3GqyzMQOHJ2p3TJMVKYm6uu9HQQH56HSi7LIJjuFRmBPeY9bmRG73Hq4cGLz6szURw2c0GSL80A7dtGEzNhbl4VDFfgiBK/hDXQGau4xcAEo6MohP8iPoIVCcd1H94iCXno7uwOAkkg1JGB1zQhSn0X9RexFOPRomtlEZPb5CvHYA1j6+/CmtWVkJMbjZficEMM1iQeWRw1ELob4MXJqDSOFtzzLANqZwQaDa86VG1Qev/qXVTtZmpcOn+PFl6KsKcKRNexHoCvk8MoEDV9tgyevkjt9x/4Gat+hygQKjNvhhKKILo43yX3QpCF4I4dF49Q8f9xAK7XjVXkFvEVpza8g7zye0Tz1VffDmP3/30fOsWZceOtaZE9WLduGCL/Qk8S8Q53/xlyI+7UTahcy2FBerXUl/0cZ4UbJLcYilLgKFyMb4rbVPTWfnwAUkZ7lRfm3hm0nUBUkhZlpMGHfJ3DuR7cV41LORzu5tViHmpAQXhRjzU88g2idltPTyXU/CIcajvm6HkeSvNkWFGBMgVTNHeiHEsz4WRE0AlyEaidkA0HVEx5navk63yk4zwGWIcxDZXVcXwGWIkZ1IIXJ1ILtmxPNO+59NcPLJtD6A4UlQJ/MvwlqeWRHiVc/O+Bv+1GgX7gdMgAAAAABJRU5ErkJggg==\"}]}"]}} \ No newline at end of file diff --git a/worldeditadditions_farwand/textures/worldeditadditions_chisel.png b/worldeditadditions_farwand/textures/worldeditadditions_chisel.png new file mode 100644 index 0000000..d742fb2 Binary files /dev/null and b/worldeditadditions_farwand/textures/worldeditadditions_chisel.png differ