Merge branch 'main' of https://github.com/sbrl/Minetest-WorldEditAdditions
|
@ -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
|
@ -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": {
|
||||
|
|
|
@ -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",
|
||||
|
|
178
.tests/strings/split_shell.test.lua
Normal 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)
|
32
CHANGELOG.md
|
@ -4,20 +4,26 @@ It's about time I started a changelog! This will serve from now on as the main c
|
|||
Note to self: See the bottom of this file for the release template text.
|
||||
|
||||
|
||||
## v1.14: The untitled update (unreleased)
|
||||
## v1.14: The multipoint update (unreleased)
|
||||
- Add `//dome+`, which allows you to change the direction the dome is pointing in, and also create multiple domes at once
|
||||
- Add `//metaball`, which renders 2 or more [metaballs](https://en.wikipedia.org/wiki/Metaballs) in Minetest
|
||||
- Add `//revolve`, which makes multiple evenly-spaced rotated copies of the defined region
|
||||
- Migrate from `depends.txt` to `mod.conf`
|
||||
- `//sculpt`: Fix undefined `default` brush
|
||||
- Commands that modify the terrain now ignore liquids
|
||||
- `//hollow`: Fix safe region bug
|
||||
- Significant backend refactoring to tidy things up
|
||||
- Add new multi-point selection wand ![A picture of the multi-point wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_multiwand.png) to select many points at once. **Not currently compatible with other wands**, as it's a work-in-progress (commands that support/require more than 2 points are hopefully coming soon)
|
||||
- Add `//spline`, for drawing curved lines with an arbitrary number of points **(uses the new multi-point wand)**
|
||||
- Add new multi-point selection wand ![A picture of the multi-point wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/main/worldeditadditions_farwand/textures/worldeditadditions_multiwand.png) to select many points at once.
|
||||
- Implement custom region boxing UI, which replaces the WorldEdit region box when using WorldEditAdditions wands.
|
||||
- Is backwards compatible with regular WorldEdit wands and tools, as WorldEditAdditions keeps the new positioning system in sync with WorldEdit's.
|
||||
- Add [`//spline`](https://worldeditadditions.mooncarrot.space/Reference/#spline), for drawing curved lines with an arbitrary number of points **(uses the new multi-point wand)**
|
||||
- Add [`//revolve`](https://worldeditadditions.mooncarrot.space/Reference/#revolve), which makes multiple evenly-spaced rotated copies of the defined region **(uses the new multi-point wand)**
|
||||
- [`//copy+`](https://worldeditadditions.mooncarrot.space/Reference/#copy), [`//move+`](https://worldeditadditions.mooncarrot.space/Reference/#move): Added support for integrated `airapply` mode, which replaces nodes at the target only if they are air - append `airapply`/`aa` to the command to use
|
||||
|
||||
### Bugfixes
|
||||
### Bugfixes and changes
|
||||
- Migrate from `depends.txt` to `mod.conf`
|
||||
- Cloud wand: fix typo in item description.
|
||||
- Commands that modify the terrain now ignore liquids
|
||||
- `//sculpt`:
|
||||
- Fix undefined `default` brush
|
||||
- Change defaults to `circle`, `height=1`, and `brushsize=8`.
|
||||
- Change argument ordering to put `height` after `brushsize` instead of the other way around
|
||||
- `//hollow`: Fix safe region bug
|
||||
|
||||
|
||||
## v1.13: The transformational update (2nd January 2022)
|
||||
|
@ -36,10 +42,10 @@ Note to self: See the bottom of this file for the release template text.
|
|||
- Add [`//sculpt`](https://worldeditadditions.mooncarrot.space/Reference/#sculpt) and [`//sculptlist`](https://worldeditadditions.mooncarrot.space/Reference/#sculptlist) for sculpting terrain using a number of custom brushes.
|
||||
- Use [luacheck](https://github.com/mpeterv/luacheck) to find and fix a large number of bugs and other issues [code quality from now on will be significantly improved]
|
||||
- Multiple commands: Allow using quotes (`"thing"`, `'thing'`) to quote values when splitting
|
||||
- `//layers`: Add optional slope constraint (inspired by [WorldPainter](https://worldpainter.net/))
|
||||
- `//bonemeal`: Add optional node list constraint
|
||||
- `//walls`: Add optional thickness argument
|
||||
- `//sstack`: Add human-readable approx volumes of regions in the selection stack
|
||||
- [`//layers`](https://worldeditadditions.mooncarrot.space/Reference/#layers): Add optional slope constraint (inspired by [WorldPainter](https://worldpainter.net/))
|
||||
- [`//bonemeal`](https://worldeditadditions.mooncarrot.space/Reference/#bonemeal): Add optional node list constraint
|
||||
- [`//walls`](https://worldeditadditions.mooncarrot.space/Reference/#walls): Add optional thickness argument
|
||||
- [`//sstack`](https://worldeditadditions.mooncarrot.space/Reference/#sstack): Add human-readable approx volumes of regions in the selection stack
|
||||
|
||||
|
||||
### Bugfixes
|
||||
|
|
|
@ -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
|
||||
})
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
15
README.md
|
@ -128,6 +128,8 @@ cd WorldEditAdditions
|
|||
git checkout "$(git describe --tags --abbrev=0)";
|
||||
```
|
||||
|
||||
If you do not checkout the latest release, you will be using the development version of WorldEditAdditions. While every effort is made to ensure that the development version is stable at all times, this is not a guarantee.
|
||||
|
||||
Windows users, you'll need to check the [releases page](https://github.com/sbrl/Minetest-WorldEditAdditions/releases) and find the name of the latest release, then do this instead of the `git checkout` above:
|
||||
|
||||
```bash
|
||||
|
@ -159,7 +161,18 @@ Contributions are welcome! Please state in your pull request(s) that you release
|
|||
|
||||
Please also make sure that the logic for every new command has it's own file. For example, the logic for `//floodfill` goes in `worldeditadditions/floodfill.lua`, the logic for `//overlay` goes in `worldeditadditions/overlay.lua`, etc. More contributing help can be found in [the contributing guide](CONTRIBUTING.md).
|
||||
|
||||
I, Starbeamrainbowlabs (@sbrl), have the ultimate final say.
|
||||
### Inspiration
|
||||
Want to contribute, but finding it tough to search for inspiration of what to implement? Here are some great places to look:
|
||||
|
||||
- [**Our issue tracker:**](https://github.com/sbrl/Minetest-WorldEditAdditions/issues) There are always a bunch of issues open with cool commands and features that have yet to be implemented.
|
||||
- **Other software:** Software for Minecraft is often far more mature than that available for Minetest. As a result, it's full of cool ideas. A lot of the existing commands in WorldEditAdditions were sourced from here.
|
||||
- WorldEdit for Minecraft
|
||||
- VoxelSniper(-Reimagined) for Minecraft
|
||||
- WorldPainter for Minecraft
|
||||
- **Do some building:** When you put WorldEditAdditions to use in building projects of your own, things will absolutely stand out to you what you want in the creative building process that WorldEditAdditions doesn't yet have.
|
||||
- **Watch others build stuff:** Doesn't even have to be Minetest! There are lots of talented Minecraft builders with videos and series on e.g. YouTube. From their creative building processes, many ideas can be derived.
|
||||
|
||||
The ultimate goal is for WorldEditAdditions to support the creative building process in a way that enables builders of all backgrounds to create incredible things.
|
||||
|
||||
|
||||
## WorldEditAdditions around the web
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
local wea_c = worldeditadditions_core
|
||||
local Vector3 = wea_c.Vector3
|
||||
|
||||
--- Copies a region to another location, potentially overwriting the exiting region.
|
||||
-- @module worldeditadditions.copy
|
||||
|
||||
-- ██████ ██████ ██████ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██
|
||||
|
@ -10,7 +8,16 @@ local Vector3 = wea_c.Vector3
|
|||
-- ██ ██ ██ ██ ██
|
||||
-- ██████ ██████ ██ ██
|
||||
|
||||
function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_pos2)
|
||||
--- Copies a region to another location, potentially overwriting the exiting region.
|
||||
-- @param source_pos1 Vector3 pos1 of the source region to copy.
|
||||
-- @param source_pos2 Vector3 pos2 of the source region to copy.
|
||||
-- @param target_pos1 Vector3 pos1 of the target region to copy to.
|
||||
-- @param target_pos2 Vector3 pos2 of the target region to copy to.
|
||||
-- @param airapply=false bool Whether to only replace target nodes that are air-like, leaving those that are not air-like. If false, then all target nodes are replaced regardless of whether they are air-like nodes or not.
|
||||
-- @returns bool,numbers 1. Whether the copy operation was successful or not
|
||||
-- 2. The total number of nodes copied.
|
||||
function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_pos2, airapply)
|
||||
if airapply == nil then airapply = false end
|
||||
source_pos1, source_pos2 = Vector3.sort(source_pos1, source_pos2)
|
||||
target_pos1, target_pos2 = Vector3.sort(target_pos1, target_pos2)
|
||||
|
||||
|
@ -26,7 +33,7 @@ function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_p
|
|||
local data_target = manip_target:get_data()
|
||||
|
||||
-- z y x is the preferred loop order (because CPU cache, since then we're iterating linearly through the data array backwards. This only holds true for little-endian machines however)
|
||||
|
||||
local total_replaced = 0
|
||||
for z = source_pos2.z, source_pos1.z, -1 do
|
||||
for y = source_pos2.y, source_pos1.y, -1 do
|
||||
for x = source_pos2.x, source_pos1.x, -1 do
|
||||
|
@ -35,7 +42,14 @@ function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_p
|
|||
local target = source - offset
|
||||
local target_i = area_target:index(target.x, target.y, target.z)
|
||||
|
||||
data_target[target_i] = data_source[source_i]
|
||||
local should_replace = true
|
||||
if airapply then
|
||||
should_replace = wea_c.is_airlike(data_target[target_i])
|
||||
end
|
||||
if should_replace then
|
||||
data_target[target_i] = data_source[source_i]
|
||||
total_replaced = total_replaced + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -43,5 +57,5 @@ function worldeditadditions.copy(source_pos1, source_pos2, target_pos1, target_p
|
|||
-- Save the modified nodes back to disk & return
|
||||
worldedit.manip_helpers.finish(manip_target, data_target)
|
||||
|
||||
return true, worldedit.volume(target_pos1, target_pos2)
|
||||
return true, total_replaced
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,11 +10,12 @@ local Vector3 = wea_c.Vector3
|
|||
-- ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██████ ████ ███████
|
||||
|
||||
function worldeditadditions.move(source_pos1, source_pos2, target_pos1, target_pos2)
|
||||
function worldeditadditions.move(source_pos1, source_pos2, target_pos1, target_pos2, airapply)
|
||||
---
|
||||
-- 0: Preamble
|
||||
---
|
||||
|
||||
if airapply == nil then airapply = false end
|
||||
source_pos1, source_pos2 = Vector3.sort(source_pos1, source_pos2)
|
||||
target_pos1, target_pos2 = Vector3.sort(target_pos1, target_pos2)
|
||||
|
||||
|
@ -45,9 +46,13 @@ function worldeditadditions.move(source_pos1, source_pos2, target_pos1, target_p
|
|||
local target = source:subtract(offset)
|
||||
local target_i = area_target:index(target.x, target.y, target.z)
|
||||
|
||||
|
||||
data_target[target_i] = data_source[source_i]
|
||||
|
||||
local should_replace = true
|
||||
if airapply then
|
||||
should_replace = wea_c.is_airlike(data_target[target_i])
|
||||
end
|
||||
if should_replace then
|
||||
data_target[target_i] = data_source[source_i]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--- WorldEditAdditions-ChatCommands
|
||||
-- @module worldeditadditions_commands
|
||||
-- @namespace worldeditadditions_commands
|
||||
-- @release 0.1
|
||||
-- @copyright 2018 Starbeamrainbowlabs
|
||||
-- @license Mozilla Public License, 2.0
|
||||
|
|
|
@ -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")
|
||||
}
|
|
@ -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)
|
||||
|
|
456
worldeditadditions_core/core/entities/pos_marker_wall.lua
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
72
worldeditadditions_core/core/pos_marker_wall_manage.lua
Normal 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)
|
|
@ -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
|
||||
|
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 506 B |
Before Width: | Height: | Size: 511 B After Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 505 B After Width: | Height: | Size: 505 B |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 522 B After Width: | Height: | Size: 522 B |
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 507 B |
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 506 B |
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
After Width: | Height: | Size: 84 B |
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 506 B |
Before Width: | Height: | Size: 511 B After Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 507 B |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 521 B After Width: | Height: | Size: 521 B |
Before Width: | Height: | Size: 509 B After Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 505 B After Width: | Height: | Size: 505 B |
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
|
@ -6,7 +6,7 @@ else
|
|||
end
|
||||
|
||||
--- A least-recently-used cache implementation.
|
||||
-- @class
|
||||
-- @class worldeditadditions_core.LRU
|
||||
local LRU = {}
|
||||
LRU.__index = LRU
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
1
worldeditadditions_farwand/edit/brush.piskel
Normal 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==\"}]}"]}}
|
|
@ -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==\"}]}"]}}
|
After Width: | Height: | Size: 715 B |