This commit is contained in:
VorTechnix 2023-07-04 14:50:17 -07:00
commit 5cf155772d
71 changed files with 1141 additions and 298 deletions

View file

@ -100,7 +100,10 @@ date: 2000-01-01
<pre><code>cd path/to/worldmods;
git clone https://github.com/Uberi/Minetest-WorldEdit.git worldedit;
git clone https://github.com/sbrl/Minetest-WorldEditAdditions.git worldeditadditions;</code></pre>
git clone https://github.com/sbrl/Minetest-WorldEditAdditions.git worldeditadditions;
cd worldeditadditions;
git checkout "$(git describe --tags --abbrev=0)";</code></pre>
<p><a class="bigbutton" href="https://github.com/sbrl/Minetest-WorldEditAdditions">Source code on GitHub</a></p>
</div>

277
.docs/package-lock.json generated
View file

@ -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": {

View file

@ -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",

View file

@ -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)

View file

@ -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

View file

@ -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 = "<argument> <argument=default> <option1|option2|...> [<optional_argument> <optional_argument2> ...] | [<optional_argument> [<optional_argument2>]]",
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
})
```

View file

@ -227,6 +227,8 @@ Floods all connected nodes of the same type starting at _pos1_ with `<replace_no
### `//wbox <replace_node>`
Sets the edges of the current selection to `<replace_node>`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+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`
### `//copy+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]] [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 `<axis> <count>`, where:
- `<axis>` 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+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]`
### `//move+ <axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]] [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 [<brush_name=default> [<height=5> [<brush_size=10>]]]`
### `//sculpt [<brush_name=default> [<brush_size=8> [<height=1>]]]`
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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)
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

View file

@ -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,number>,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

View file

@ -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)
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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)
local volume_before = worldedit.volume(worldedit.pos1[name], worldedit.pos2[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)
worldedit.pos1[name], worldedit.pos2[name] = Vector3.expand_region(
Vector3.clone(worldedit.pos1[name]),
Vector3.clone(worldedit.pos2[name]),
pos
local pos1, pos2 = wea_c.pos.get1(name), wea_c.pos.get2(name)
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 <number>)")
worldedit.player_notify(name, "Error. Too far away (try raising your maxdist with //farwand maxdist <number>)")
-- 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

View file

@ -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 = "<axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]",
params = "<axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]] [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

View file

@ -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"

View file

@ -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",

View file

@ -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 = "<axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]]",
params = "<axis:x|y|z|-x|-y|-z|?|front|back|left|right|up|down> <count> [<axis> <count> [...]] [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

View file

@ -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

View file

@ -9,20 +9,20 @@ local Vector3 = wea_c.Vector3
-- ██ ██ ██ ██ ██ ██ ██
-- ███████ ██████ ██████ ███████ ██ ██
worldeditadditions_core.register_command("sculpt", {
params = "[<brush_name=default> [<height=5> [<brush_size=10>]]]",
params = "[<brush_name=default> [<brush_size=8> [<height=1>]]]",
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

View file

@ -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"

View file

@ -1,5 +1,5 @@
--- WorldEditAdditions-ChatCommands
-- @module worldeditadditions_commands
-- @namespace worldeditadditions_commands
-- @release 0.1
-- @copyright 2018 Starbeamrainbowlabs
-- @license Mozilla Public License, 2.0

View file

@ -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")
}

View file

@ -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)

View file

@ -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<WEAPositionMarkerWall>
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<entitylist> 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<entity> 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

View file

@ -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 = <Vector3> { 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

View file

@ -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)

View file

@ -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<wea_c.pos.set> 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<wea_c.pos.set> 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)

View file

@ -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

View file

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 512 B

View file

Before

Width:  |  Height:  |  Size: 506 B

After

Width:  |  Height:  |  Size: 506 B

View file

Before

Width:  |  Height:  |  Size: 511 B

After

Width:  |  Height:  |  Size: 511 B

View file

Before

Width:  |  Height:  |  Size: 505 B

After

Width:  |  Height:  |  Size: 505 B

View file

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View file

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View file

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View file

Before

Width:  |  Height:  |  Size: 522 B

After

Width:  |  Height:  |  Size: 522 B

View file

Before

Width:  |  Height:  |  Size: 507 B

After

Width:  |  Height:  |  Size: 507 B

View file

Before

Width:  |  Height:  |  Size: 506 B

After

Width:  |  Height:  |  Size: 506 B

View file

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

View file

Before

Width:  |  Height:  |  Size: 506 B

After

Width:  |  Height:  |  Size: 506 B

View file

Before

Width:  |  Height:  |  Size: 511 B

After

Width:  |  Height:  |  Size: 511 B

View file

Before

Width:  |  Height:  |  Size: 507 B

After

Width:  |  Height:  |  Size: 507 B

View file

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View file

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View file

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View file

Before

Width:  |  Height:  |  Size: 521 B

After

Width:  |  Height:  |  Size: 521 B

View file

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 509 B

View file

Before

Width:  |  Height:  |  Size: 505 B

After

Width:  |  Height:  |  Size: 505 B

View file

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 512 B

View file

@ -6,7 +6,7 @@ else
end
--- A least-recently-used cache implementation.
-- @class
-- @class worldeditadditions_core.LRU
local LRU = {}
LRU.__index = LRU

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -1,6 +1,15 @@
-- 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")
@ -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 (

View file

@ -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

View file

@ -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==\"}]}"]}}

View file

@ -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=\"}]}"]}}
{"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==\"}]}"]}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B