diff --git a/.docs/Tutorial.md b/.docs/Tutorial.md index 4982348..e8c6d41 100644 --- a/.docs/Tutorial.md +++ b/.docs/Tutorial.md @@ -27,10 +27,10 @@ Explaining core WorldEdit commands is out of scope of this tutorial, but you can The purpose of _WorldEditAdditions_ is to extend _WorldEdit_ by adding additional commands. Example commands that have been implemented that are not present in core _WorldEdit_ include (but certainly aren't limited to): - - [`//maze`](/Reference/#maze-replace_node-path_length-path_width-seed): Create instant mazes - - [`//forest`](/Reference/#forest-density-sapling_a-chance_a-sapling_b-chance_b-sapling_n-chance_n-): Plant forests - - [`//torus`](http://localhost:8080/Reference/#torus-major_radius-minor_radius-node_name-axesxy-hollow): Generate [torus](https://en.wikipedia.org/wiki/Torus) shapes - - [`//scale`](/Reference/#scale-axis-scale_factor-factor_x-factor_y-factor_z-anchor_x-anchor_y-anchor_z): Scale things up and down - even both at the same time! + - [`//maze`](/Reference/#maze): Create instant mazes + - [`//forest`](/Reference/#forest): Plant forests + - [`//torus`](http://localhost:8080/Reference/#torus): Generate [torus](https://en.wikipedia.org/wiki/Torus) shapes + - [`//scale`](/Reference/#scale): Scale things up and down - even both at the same time! See a full list with complete explanations in the [chat command reference](/Reference). @@ -98,9 +98,9 @@ A number of additional concepts that are not required to use WorldEditAdditions ### Meta commands WorldEditAdditions provides a number of *meta commands*. Such commands don't do anything on their own, but call other commands in various different ways. Examples of meta commands include: - - [`//subdivide`](/Reference#subdivide-size_x-size_y-size_z-cmd_name-args): split a region into chunks, and execute the command once for each chunk - - [`//many`](/Reference#many-times-command): Execute a command multiple times - - [`//multi`](/Reference#multi-command_a-command_b-command_c-): Execute multiple commands in sequence + - [`//subdivide`](/Reference#subdivide): split a region into chunks, and execute the command once for each chunk + - [`//many`](/Reference#many): Execute a command multiple times + - [`//multi`](/!node_modules, !_sitemulti): Execute multiple commands in sequence Of course, this isn't an exhaustive list - check the [reference](/Reference) for a full list. @@ -109,7 +109,7 @@ Memory (or RAM - Random Access Memory) is used by all the processes running on a Depending on your system, Minetest and your system can slow to a crawl or even crash if you execute a command on a region that's too big. -To work around this, the [`//subdivide`](/Reference#subdivide-size_x-size_y-size_z-cmd_name-args) command was implemented. It splits the defined region into chunks, and calls the specified command over and over again for each chunk. +To work around this, the [`//subdivide`](/Reference#subdivide) command was implemented. It splits the defined region into chunks, and calls the specified command over and over again for each chunk. It's not suitable for all commands (since it requires that said command takes 2 points) though, but because it splits the defined region into multiple chunks, it can be executed on *enormous* regions that can't fit into memory all at the same time. diff --git a/.docs/lib/parse_sections.js b/.docs/lib/parse_sections.js index d9e4678..eaf807c 100644 --- a/.docs/lib/parse_sections.js +++ b/.docs/lib/parse_sections.js @@ -15,7 +15,8 @@ module.exports = function parse_sections(source) { result.push({ title: htmlentities.encode(title), slug: title.toLowerCase().replace(/[^a-z0-9-_\s]+/gi, "") - .replace(/\s+/g, "-"), + .replace(/\s+/g, "-") + .replace(/-.*$/, ""), content: markdown.render(acc.slice(1).join("\n")) }); } diff --git a/.tests/Vector3/abs.test.lua b/.tests/Vector3/abs.test.lua new file mode 100644 index 0000000..9803c57 --- /dev/null +++ b/.tests/Vector3/abs.test.lua @@ -0,0 +1,35 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.abs", function() + it("should work with a positive vector", function() + local a = Vector3.new(16, 64, 16) + assert.are.same( + Vector3.new(16, 64, 16), + a:abs() + ) + end) + it("should abs another positive vector", function() + local a = Vector3.new(9, 16, 25) + assert.are.same( + Vector3.new(9, 16, 25), + a:abs() + ) + end) + it("should abs a negative vector", function() + local a = Vector3.new(-9, -16, -25) + assert.are.same( + Vector3.new(9, 16, 25), + a:abs() + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(9, -16, 25) + + local result = a:abs() + assert.are.same( + Vector3.new(9, 16, 25), + result + ) + assert.are_not.equal(result, a) + end) +end) diff --git a/.tests/Vector3/add.test.lua b/.tests/Vector3/add.test.lua new file mode 100644 index 0000000..cba5a2a --- /dev/null +++ b/.tests/Vector3/add.test.lua @@ -0,0 +1,80 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.add", function() + it("should add 2 positive vectors", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(1, 1, 1) + assert.are.same( + Vector3.new(4, 5, 6), + a:add(b) + ) + end) + it("should support the add operator", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(1, 1, 1) + assert.are.same( + Vector3.new(4, 5, 6), + a + b + ) + end) + it("should work with floats", function() + local a = Vector3.new(3.5, 4.5, 5.5) + local b = Vector3.new(1.1, 1.1, 1.1) + assert.are.same( + Vector3.new(4.6, 5.6, 6.6), + a + b + ) + end) + it("should work with scalar a", function() + local a = 2 + local b = Vector3.new(6, 7, 8) + assert.are.same( + Vector3.new(8, 9, 10), + a + b + ) + end) + it("should work with scalar b", function() + local a = Vector3.new(6, 7, 8) + local b = 2 + assert.are.same( + Vector3.new(8, 9, 10), + a + b + ) + end) + it("should handle negative b", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(-1, -1, -1) + assert.are.same( + Vector3.new(2, 3, 4), + a + b + ) + end) + it("should handle negative a", function() + local a = Vector3.new(-3, -4, -5) + local b = Vector3.new(1, 1, 1) + assert.are.same( + Vector3.new(-2, -3, -4), + a + b + ) + end) + it("should handle negative a and b", function() + local a = Vector3.new(-3, -4, -5) + local b = Vector3.new(-1, -1, -1) + assert.are.same( + Vector3.new(-4, -5, -6), + a + b + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(1, 1, 1) + + local result = a + b + assert.are.same( + Vector3.new(4, 5, 6), + result + ) + assert.are_not.equal(result, a) + assert.are_not.equal(result, b) + end) +end) diff --git a/.tests/Vector3/area.test.lua b/.tests/Vector3/area.test.lua new file mode 100644 index 0000000..d7fc97f --- /dev/null +++ b/.tests/Vector3/area.test.lua @@ -0,0 +1,25 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.area", function() + it("should work with a positive vector", function() + local a = Vector3.new(3, 3, 3) + assert.are.equal( + 27, + a:area() + ) + end) + it("should work with a negative vector", function() + local a = Vector3.new(-4, -4, -4) + assert.are.equal( + -64, + a:area() + ) + end) + it("should work with a mixed vector", function() + local a = Vector3.new(-3, 3, -3) + assert.are.equal( + 27, + a:area() + ) + end) +end) diff --git a/.tests/Vector3/ceil.test.lua b/.tests/Vector3/ceil.test.lua new file mode 100644 index 0000000..449d89d --- /dev/null +++ b/.tests/Vector3/ceil.test.lua @@ -0,0 +1,35 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.ceil", function() + it("should ceil a positive vector", function() + local a = Vector3.new(3.1, 4.2, 5.8) + assert.are.same( + Vector3.new(4, 5, 6), + a:ceil() + ) + end) + it("should ceil a negative vector", function() + local a = Vector3.new(-3.1, -4.2, -5.3) + assert.are.same( + Vector3.new(-3, -4, -5), + a:ceil() + ) + end) + it("should work with integers", function() + local a = Vector3.new(3, 4, 5) + assert.are.same( + a:ceil(), + Vector3.new(3, 4, 5) + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(3.1, 4.7, 5.99999) + + local result = a:ceil() + assert.are.same( + Vector3.new(4, 5, 6), + result + ) + assert.are_not.equal(result, a) + end) +end) diff --git a/.tests/Vector3/clone.test.lua b/.tests/Vector3/clone.test.lua new file mode 100644 index 0000000..a6b4804 --- /dev/null +++ b/.tests/Vector3/clone.test.lua @@ -0,0 +1,20 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.clone", function() + it("should return a new Vector3 instance", function() + local a = Vector3.new(3, 4, 5) + + local result = a:clone() + result.x = 4 + assert.are.same(Vector3.new(3, 4, 5), a) + assert.are.same(Vector3.new(4, 4, 5), result) + end) + it("should return a new Vector3 instance for a different vector", function() + local a = Vector3.new(-99, 66, 88) + + local result = a:clone() + result.y = -44 + assert.are.same(Vector3.new(-99, 66, 88), a) + assert.are.same(Vector3.new(-99, -44, 88), result) + end) +end) diff --git a/.tests/Vector3/divide.test.lua b/.tests/Vector3/divide.test.lua new file mode 100644 index 0000000..18c728f --- /dev/null +++ b/.tests/Vector3/divide.test.lua @@ -0,0 +1,80 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.divide", function() + it("should divide 2 positive vectors", function() + local a = Vector3.new(30, 40, 50) + local b = Vector3.new(2, 2, 2) + assert.are.same( + Vector3.new(15, 20, 25), + a:divide(b) + ) + end) + it("should work with the div alias", function() + local a = Vector3.new(30, 40, 50) + local b = Vector3.new(2, 2, 2) + assert.are.same( + Vector3.new(15, 20, 25), + a:div(b) + ) + end) + it("should work with scalar a", function() + local a = 2 + local b = Vector3.new(12, 14, 16) + assert.are.same( + Vector3.new(6, 7, 8), + a / b + ) + end) + it("should work with scalar b", function() + local a = Vector3.new(6, 8, 10) + local b = 2 + assert.are.same( + Vector3.new(3, 4, 5), + a / b + ) + end) + it("should support the divide operator", function() + local a = Vector3.new(10, 12, 14) + local b = Vector3.new(2, 3, 2) + assert.are.same( + Vector3.new(5, 4, 7), + a / b + ) + end) + it("should handle negative b", function() + local a = Vector3.new(30, 40, 50) + local b = Vector3.new(-2, -2, -2) + assert.are.same( + Vector3.new(-15, -20, -25), + a / b + ) + end) + it("should handle negative a", function() + local a = Vector3.new(-30, -40, -50) + local b = Vector3.new(2, 4, 2) + assert.are.same( + Vector3.new(-15, -10, -25), + a / b + ) + end) + it("should handle negative a and b", function() + local a = Vector3.new(-30, -40, -50) + local b = Vector3.new(-2, -2, -2) + assert.are.same( + Vector3.new(15, 20, 25), + a / b + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(9, 12, 15) + local b = Vector3.new(3, 3, 3) + + local result = a / b + assert.are.same( + Vector3.new(3, 4, 5), + result + ) + assert.are_not.equal(result, a) + assert.are_not.equal(result, b) + end) +end) diff --git a/.tests/Vector3/dot.test.lua b/.tests/Vector3/dot.test.lua new file mode 100644 index 0000000..3f6f6b3 --- /dev/null +++ b/.tests/Vector3/dot.test.lua @@ -0,0 +1,36 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.dot", function() + it("should work with a positive vector", function() + local a = Vector3.new(3, 3, 3) + local b = Vector3.new(4, 5, 6) + assert.are.equal( + 45, + a:dot(b) + ) + end) + it("should work with a negative vector", function() + local a = Vector3.new(-4, -4, -4) + local b = Vector3.new(4, 5, 6) + assert.are.equal( + -60, + a:dot(b) + ) + end) + it("should work with a mixed vector", function() + local a = Vector3.new(-3, 3, -3) + local b = Vector3.new(7, 8, 9) + assert.are.equal( + -24, + a:dot(b) + ) + end) + it("should work with the dot_product alias", function() + local a = Vector3.new(-3, 3, -3) + local b = Vector3.new(7, 8, 9) + assert.are.equal( + -24, + a:dot_product(b) + ) + end) +end) diff --git a/.tests/Vector3/equal.test.lua b/.tests/Vector3/equal.test.lua new file mode 100644 index 0000000..25ee004 --- /dev/null +++ b/.tests/Vector3/equal.test.lua @@ -0,0 +1,40 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.equals", function() + it("should return true when identical", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(3, 4, 5) + + assert.are.same( + true, + a:equals(b) + ) + end) + it("should return false when not identical", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(6, 7, 8) + + assert.are.same( + false, + a:equals(b) + ) + end) + it("should return false when not identical x", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(4, 4, 5) + + assert.are.same( + false, + a:equals(b) + ) + end) + it("should return false when not identical y", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(3, 5, 5) + + assert.are.same( + false, + a:equals(b) + ) + end) +end) diff --git a/.tests/Vector3/expand_region.test.lua b/.tests/Vector3/expand_region.test.lua new file mode 100644 index 0000000..2847464 --- /dev/null +++ b/.tests/Vector3/expand_region.test.lua @@ -0,0 +1,48 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.expand_region", function() + it("should work with positive vectors", function() + local a = Vector3.new(16, 64, 16) + local b = Vector3.new(1, 4, 6) + local target = Vector3.new(99, 99, 99) + + local result_a, result_b = target:expand_region(a, b) + assert.are.same(Vector3.new(1, 4, 6), result_a) + assert.are.same(Vector3.new(99, 99, 99), result_b) + end) + it("should work with mixed components", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + local target = Vector3.new(-99, -99, -99) + + local result_a, result_b = target:expand_region(a, b) + assert.are.same(Vector3.new(-99, -99, -99), result_a) + assert.are.same(Vector3.new(16, 4, 60), result_b) + end) + it("should work with negative vectors", function() + local a = Vector3.new(-9, -16, -25) + local b = Vector3.new(-3, -6, -2) + local target = Vector3.new(-99, -99, -99) + + local result_a, result_b = target:expand_region(a, b) + assert.are.same(Vector3.new(-99, -99, -99), result_a) + assert.are.same(Vector3.new(-3, -6, -2), result_b) + end) + it("should return new Vector3 instances", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + local target = Vector3.new(99, 99, 99) + + local result_a, result_b = target:expand_region(a, b) + assert.are.same(Vector3.new(1, 1, 16), result_a) + assert.are.same(Vector3.new(99, 99, 99), result_b) + + result_a.y = 999 + result_b.y = 999 + + assert.are.same(Vector3.new(16, 1, 16), a) + assert.are.same(Vector3.new(1, 4, 60), b) + assert.are.same(Vector3.new(1, 999, 16), result_a) + assert.are.same(Vector3.new(99, 999, 99), result_b) + end) +end) diff --git a/.tests/Vector3/floor.test.lua b/.tests/Vector3/floor.test.lua new file mode 100644 index 0000000..c29b56d --- /dev/null +++ b/.tests/Vector3/floor.test.lua @@ -0,0 +1,35 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.floor", function() + it("should floor a positive vector", function() + local a = Vector3.new(3.1, 4.75, 5.9) + assert.are.same( + Vector3.new(3, 4, 5), + a:floor() + ) + end) + it("should floor a negative vector", function() + local a = Vector3.new(-3.1, -4.2, -5.3) + assert.are.same( + Vector3.new(-4, -5, -6), + a:floor() + ) + end) + it("should work with integers", function() + local a = Vector3.new(3, 4, 5) + assert.are.same( + Vector3.new(3, 4, 5), + a:floor() + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(3.1, 4.7, 5.99999) + + local result = a:floor() + assert.are.same( + Vector3.new(3, 4, 5), + result + ) + assert.are_not.equal(result, a) + end) +end) diff --git a/.tests/Vector3/is_contained.test.lua b/.tests/Vector3/is_contained.test.lua new file mode 100644 index 0000000..9c245ee --- /dev/null +++ b/.tests/Vector3/is_contained.test.lua @@ -0,0 +1,44 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.is_contained", function() + it("should return true when inside", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(30, 40, 50) + local target = Vector3.new(6, 6, 6) + + assert.are.same( + true, + target:is_contained(a, b) + ) + end) + it("should return false when outside x", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(30, 40, 50) + local target = Vector3.new(60, 6, 6) + + assert.are.same( + false, + target:is_contained(a, b) + ) + end) + it("should return false when outside y", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(30, 40, 50) + local target = Vector3.new(6, 60, 6) + + assert.are.same( + false, + target:is_contained(a, b) + ) + end) + it("should return false when outside z", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(30, 40, 50) + local target = Vector3.new(6, 6, 60) + + assert.are.same( + false, + target:is_contained(a, b) + ) + end) +end) diff --git a/.tests/Vector3/length.test.lua b/.tests/Vector3/length.test.lua new file mode 100644 index 0000000..3c8924b --- /dev/null +++ b/.tests/Vector3/length.test.lua @@ -0,0 +1,30 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +-- To find these numbers, in Javascript: +-- function t(x) { return Math.sqrt((x*x)*3); } +-- for(let i = 0; i < 1000000000; i++) { let r = t(i); if(Math.floor(r) === r) console.log(`i ${i}, r ${r}`); } + + +describe("Vector3.length", function() + it("should work with a positive vector", function() + local a = Vector3.new(80198051, 80198051, 80198051) + assert.are.equal( + 138907099, + a:length() + ) + end) + it("should work with a negative vector", function() + local a = Vector3.new(-189750626, -189750626, -189750626) + assert.are.equal( + 328657725, + a:length() + ) + end) + it("should work with a mixed vector", function() + local a = Vector3.new(-371635731, 371635731, -371635731) + assert.are.equal( + 643691968, + a:length() + ) + end) +end) diff --git a/.tests/Vector3/length_squared.test.lua b/.tests/Vector3/length_squared.test.lua new file mode 100644 index 0000000..3e049c9 --- /dev/null +++ b/.tests/Vector3/length_squared.test.lua @@ -0,0 +1,25 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.length_squared", function() + it("should work with a positive vector", function() + local a = Vector3.new(3, 3, 3) + assert.are.equal( + 27, + a:length_squared() + ) + end) + it("should work with a negative vector", function() + local a = Vector3.new(-4, -4, -4) + assert.are.equal( + 48, + a:length_squared() + ) + end) + it("should work with a mixed vector", function() + local a = Vector3.new(-3, 3, -3) + assert.are.equal( + 27, + a:length_squared() + ) + end) +end) diff --git a/.tests/Vector3/limit_to.test.lua b/.tests/Vector3/limit_to.test.lua new file mode 100644 index 0000000..0847fc9 --- /dev/null +++ b/.tests/Vector3/limit_to.test.lua @@ -0,0 +1,56 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.limit_to", function() + it("should limit_to a positive vector", function() + local a = Vector3.new(801980510, 801980510, 801980510) + assert.are.same( + Vector3.new(80198051, 80198051, 80198051), + a:limit_to(138907099) + ) + end) + it("should limit_to a negative vector", function() + local a = Vector3.new(-1897506260, -1897506260, -1897506260) + assert.are.same( + Vector3.new(-189750626, -189750626, -189750626), + a:limit_to(328657725) + ) + end) + it("should work if the length is borderline", function() + local a = Vector3.new(80198051, 80198051, 80198051) + assert.are.same( + Vector3.new(80198051, 80198051, 80198051), + a:limit_to(138907099) + ) + end) + it("should not change anything if the length is smaller", function() + local a = Vector3.new(3, 4, 5) + assert.are.same( + Vector3.new(3, 4, 5), + a:limit_to(100) + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(801980510, 801980510, 801980510) + + local result = a:limit_to(138907099) + assert.are.same( + Vector3.new(80198051, 80198051, 80198051), + result + ) + a.x = 4 + assert.are.same(Vector3.new(4, 801980510, 801980510), a) + assert.are.same(Vector3.new(80198051, 80198051, 80198051), result) + end) + it("should return a new Vector3 instance if the length is smaller", function() + local a = Vector3.new(3, 4, 5) + + local result = a:limit_to(101) + assert.are.same( + Vector3.new(3, 4, 5), + result + ) + a.x = 40 + assert.are.same(Vector3.new(40, 4, 5), a) + assert.are.same(Vector3.new(3, 4, 5), result) + end) +end) diff --git a/.tests/Vector3/max.test.lua b/.tests/Vector3/max.test.lua new file mode 100644 index 0000000..f8d3d2a --- /dev/null +++ b/.tests/Vector3/max.test.lua @@ -0,0 +1,44 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.max", function() + it("should work with positive vectors", function() + local a = Vector3.new(16, 64, 16) + local b = Vector3.new(1, 4, 6) + + assert.are.same( + Vector3.new(16, 64, 16), + Vector3.max(a, b) + ) + end) + it("should work with mixed components", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + + assert.are.same( + Vector3.new(16, 4, 60), + Vector3.max(a, b) + ) + end) + it("should work with negative vectors", function() + local a = Vector3.new(-9, -16, -25) + local b = Vector3.new(-3, -6, -2) + + assert.are.same( + Vector3.new(-3, -6, -2), + Vector3.max(a, b) + ) + end) + it("should return new Vector3 instances", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + + local result = Vector3.max(a, b) + assert.are.same(Vector3.new(16, 4, 60), result) + + result.y = 999 + + assert.are.same(Vector3.new(16, 1, 16), a) + assert.are.same(Vector3.new(1, 4, 60), b) + assert.are.same(Vector3.new(16, 999, 60), result) + end) +end) diff --git a/.tests/Vector3/max_component.test.lua b/.tests/Vector3/max_component.test.lua new file mode 100644 index 0000000..3c74bab --- /dev/null +++ b/.tests/Vector3/max_component.test.lua @@ -0,0 +1,39 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.max_component", function() + it("should work with a positive vector x", function() + local a = Vector3.new(30, 4, 5) + assert.are.equal( + 30, + a:max_component() + ) + end) + it("should work with a positive vector y", function() + local a = Vector3.new(3, 10, 5) + assert.are.equal( + 10, + a:max_component() + ) + end) + it("should work with a positive vector z", function() + local a = Vector3.new(3, 1, 50.5) + assert.are.equal( + 50.5, + a:max_component() + ) + end) + it("should work with a negative vector", function() + local a = Vector3.new(-4, -5, -1) + assert.are.equal( + -1, + a:max_component() + ) + end) + it("should work with a mixed vector", function() + local a = Vector3.new(-30, 3, -3) + assert.are.equal( + 3, + a:max_component() + ) + end) +end) diff --git a/.tests/Vector3/mean.test.lua b/.tests/Vector3/mean.test.lua new file mode 100644 index 0000000..0604d68 --- /dev/null +++ b/.tests/Vector3/mean.test.lua @@ -0,0 +1,47 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.mean", function() + it("should work with a positive vector", function() + local a = Vector3.new(2, 2, 2) + local b = Vector3.new(4, 4, 4) + assert.are.same( + Vector3.new(3, 3, 3), + a:mean(b) + ) + end) + it("should work with a positive vector the other way around", function() + local a = Vector3.new(2, 2, 2) + local b = Vector3.new(4, 4, 4) + assert.are.same( + Vector3.new(3, 3, 3), + b:mean(a) + ) + end) + it("should mean another positive vector", function() + local a = Vector3.new(6, 6, 6) + local b = Vector3.new(10, 10, 10) + assert.are.same( + Vector3.new(8, 8, 8), + a:mean(b) + ) + end) + it("should mean a negative vector", function() + local a = Vector3.new(-2, -2, -2) + local b = Vector3.new(0, 0, 0) + assert.are.same( + Vector3.new(-1, -1, -1), + a:mean(b) + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(6, 6, 6) + local b = Vector3.new(10, 10, 10) + assert.are.same( + Vector3.new(8, 8, 8), + a:mean(b) + ) + + assert.are.same(Vector3.new(6, 6, 6), a) + assert.are.same(Vector3.new(10, 10, 10), b) + end) +end) diff --git a/.tests/Vector3/min.test.lua b/.tests/Vector3/min.test.lua new file mode 100644 index 0000000..332d74d --- /dev/null +++ b/.tests/Vector3/min.test.lua @@ -0,0 +1,44 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.min", function() + it("should work with positive vectors", function() + local a = Vector3.new(16, 64, 16) + local b = Vector3.new(1, 4, 6) + + assert.are.same( + Vector3.new(1, 4, 6), + Vector3.min(a, b) + ) + end) + it("should work with mixed components", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + + assert.are.same( + Vector3.new(1, 1, 16), + Vector3.min(a, b) + ) + end) + it("should work with negative vectors", function() + local a = Vector3.new(-9, -16, -25) + local b = Vector3.new(-3, -6, -2) + + assert.are.same( + Vector3.new(-9, -16, -25), + Vector3.min(a, b) + ) + end) + it("should return new Vector3 instances", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + + local result = Vector3.min(a, b) + assert.are.same(Vector3.new(1, 1, 16), result) + + result.y = 999 + + assert.are.same(Vector3.new(16, 1, 16), a) + assert.are.same(Vector3.new(1, 4, 60), b) + assert.are.same(Vector3.new(1, 999, 16), result) + end) +end) diff --git a/.tests/Vector3/min_component.test.lua b/.tests/Vector3/min_component.test.lua new file mode 100644 index 0000000..d1e8fc4 --- /dev/null +++ b/.tests/Vector3/min_component.test.lua @@ -0,0 +1,39 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.min_component", function() + it("should work with a positive vector x", function() + local a = Vector3.new(3, 4, 5) + assert.are.equal( + 3, + a:min_component() + ) + end) + it("should work with a positive vector y", function() + local a = Vector3.new(3, 1, 5) + assert.are.equal( + 1, + a:min_component() + ) + end) + it("should work with a positive vector z", function() + local a = Vector3.new(3, 1, 0.5) + assert.are.equal( + 0.5, + a:min_component() + ) + end) + it("should work with a negative vector", function() + local a = Vector3.new(-4, -5, -46) + assert.are.equal( + -46, + a:min_component() + ) + end) + it("should work with a mixed vector", function() + local a = Vector3.new(-30, 3, -3) + assert.are.equal( + -30, + a:min_component() + ) + end) +end) diff --git a/.tests/Vector3/move_towards.test.lua b/.tests/Vector3/move_towards.test.lua new file mode 100644 index 0000000..c48ba82 --- /dev/null +++ b/.tests/Vector3/move_towards.test.lua @@ -0,0 +1,17 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +-- To find these numbers, in Javascript: +-- function t(x) { return Math.sqrt((x*x)*3); } +-- for(let i = 0; i < 1000000000; i++) { let r = t(i); if(Math.floor(r) === r) console.log(`i ${i}, r ${r}`); } + + +describe("Vector3.move_towards", function() + it("should work with a positive vector", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(10, 10, 10) + assert.are.same( + Vector3.new(5.0022714374157439821, 5.7162326606420661435, 6.4301938838683883048), + a:move_towards(b, 3) + ) + end) +end) diff --git a/.tests/Vector3/multiply.test.lua b/.tests/Vector3/multiply.test.lua new file mode 100644 index 0000000..f133135 --- /dev/null +++ b/.tests/Vector3/multiply.test.lua @@ -0,0 +1,80 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.multiply", function() + it("should multiply 2 positive vectors", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(2, 2, 2) + assert.are.same( + Vector3.new(6, 8, 10), + a:multiply(b) + ) + end) + it("should work with the mul alias", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(2, 2, 2) + assert.are.same( + Vector3.new(6, 8, 10), + a:mul(b) + ) + end) + it("should work with scalar a", function() + local a = 2 + local b = Vector3.new(6, 7, 8) + assert.are.same( + Vector3.new(12, 14, 16), + a * b + ) + end) + it("should work with scalar b", function() + local a = Vector3.new(6, 7, 8) + local b = 2 + assert.are.same( + Vector3.new(12, 14, 16), + a * b + ) + end) + it("should support the multiply operator", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(2, 2, 2) + assert.are.same( + Vector3.new(6, 8, 10), + a * b + ) + end) + it("should handle negative b", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(-1, -1, -1) + assert.are.same( + Vector3.new(-3, -4, -5), + a * b + ) + end) + it("should handle negative a", function() + local a = Vector3.new(-3, -4, -5) + local b = Vector3.new(2, 2, 2) + assert.are.same( + Vector3.new(-6, -8, -10), + a * b + ) + end) + it("should handle negative a and b", function() + local a = Vector3.new(-3, -4, -5) + local b = Vector3.new(-2, -2, -2) + assert.are.same( + Vector3.new(6, 8, 10), + a * b + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(3, 3, 3) + + local result = a * b + assert.are.same( + Vector3.new(9, 12, 15), + result + ) + assert.are_not.equal(result, a) + assert.are_not.equal(result, b) + end) +end) diff --git a/.tests/Vector3/new.test.lua b/.tests/Vector3/new.test.lua new file mode 100644 index 0000000..b74e5b1 --- /dev/null +++ b/.tests/Vector3/new.test.lua @@ -0,0 +1,25 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.add", function() + it("should create a new Vector3", function() + assert.are.same( + { x = 3, y = 4, z = 5 }, + Vector3.new(3, 4, 5) + ) + end) + it("should throw an error on invalid x", function() + assert.has.errors(function() + Vector3.new("cheese", 4, 5) + end) + end) + it("should throw an error on invalid y", function() + assert.has.errors(function() + Vector3.new(4, "cheese", 5) + end) + end) + it("should throw an error on invalid z", function() + assert.has.errors(function() + Vector3.new(66, 2, "cheese") + end) + end) +end) diff --git a/.tests/Vector3/round.test.lua b/.tests/Vector3/round.test.lua new file mode 100644 index 0000000..6107381 --- /dev/null +++ b/.tests/Vector3/round.test.lua @@ -0,0 +1,35 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.round", function() + it("should round a positive vector", function() + local a = Vector3.new(3.1, 4.75, 5.9) + assert.are.same( + Vector3.new(3, 5, 6), + a:round() + ) + end) + it("should round a negative vector", function() + local a = Vector3.new(-3.1, -4.2, -5.3) + assert.are.same( + Vector3.new(-3, -4, -5), + a:round() + ) + end) + it("should work with integers", function() + local a = Vector3.new(3, 4, 5) + assert.are.same( + Vector3.new(3, 4, 5), + a:round() + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(3.1, 4.7, 5.99999) + + local result = a:round() + assert.are.same( + Vector3.new(3, 5, 6), + result + ) + assert.are_not.equal(result, a) + end) +end) diff --git a/.tests/Vector3/set_to.test.lua b/.tests/Vector3/set_to.test.lua new file mode 100644 index 0000000..99eedab --- /dev/null +++ b/.tests/Vector3/set_to.test.lua @@ -0,0 +1,52 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.set_to", function() + it("should set_to a positive vector", function() + local a = Vector3.new(801980510, 801980510, 801980510) + assert.are.same( + Vector3.new(80198051, 80198051, 80198051), + a:set_to(138907099) + ) + end) + it("should set_to a negative vector", function() + local a = Vector3.new(-1897506260, -1897506260, -1897506260) + assert.are.same( + Vector3.new(-189750626, -189750626, -189750626), + a:set_to(328657725) + ) + end) + it("should work if the length is borderline", function() + local a = Vector3.new(80198051, 80198051, 80198051) + assert.are.same( + Vector3.new(80198051, 80198051, 80198051), + a:set_to(138907099) + ) + end) + it("should work if the length is smaller", function() + local a = Vector3.new(80198051, 80198051, 80198051) + assert.are.same( + Vector3.new(109552575, 109552575, 109552575), + a:set_to(189750626):floor() -- Hack to ignore flating-point errors. In theory we should really use epsilon here instead + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(801980510, 801980510, 801980510) + + local result = a:set_to(138907099) + assert.are.same( + Vector3.new(80198051, 80198051, 80198051), + result + ) + assert.are_not.equal(result, a) + end) + it("should return a new Vector3 instance if the length is smaller", function() + local a = Vector3.new(80198051, 80198051, 80198051) + + local result = a:set_to(189750626):floor() + assert.are.same( + Vector3.new(109552575, 109552575, 109552575), + result + ) + assert.are_not.equal(result, a) + end) +end) diff --git a/.tests/Vector3/snap_to.test.lua b/.tests/Vector3/snap_to.test.lua new file mode 100644 index 0000000..389de35 --- /dev/null +++ b/.tests/Vector3/snap_to.test.lua @@ -0,0 +1,35 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.snap_to", function() + it("should snap_to a positive vector", function() + local a = Vector3.new(3.1, 4.75, 5.9) + assert.are.same( + Vector3.new(0, 0, 10), + a:snap_to(10) + ) + end) + it("should snap_to a negative vector", function() + local a = Vector3.new(-2.5, -4.2, -5.3) + assert.are.same( + Vector3.new(0, -6, -6), + a:snap_to(6) + ) + end) + it("should work with integers", function() + local a = Vector3.new(3, 4, 5) + assert.are.same( + Vector3.new(3, 3, 6), + a:snap_to(3) + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(3.1, 4.7, 5.99999) + + local result = a:snap_to(3) + assert.are.same( + Vector3.new(3, 6, 6), + result + ) + assert.are_not.equal(result, a) + end) +end) diff --git a/.tests/Vector3/sort_pos.test.lua b/.tests/Vector3/sort_pos.test.lua new file mode 100644 index 0000000..df8a89f --- /dev/null +++ b/.tests/Vector3/sort_pos.test.lua @@ -0,0 +1,44 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.sort", function() + it("should work with positive vectors", function() + local a = Vector3.new(16, 64, 16) + local b = Vector3.new(1, 4, 6) + + local result_a, result_b = Vector3.sort(a, b) + assert.are.same(Vector3.new(1, 4, 6), result_a) + assert.are.same(Vector3.new(16, 64, 16), result_b) + end) + it("should work with mixed components", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + + local result_a, result_b = Vector3.sort(a, b) + assert.are.same(Vector3.new(1, 1, 16), result_a) + assert.are.same(Vector3.new(16, 4, 60), result_b) + end) + it("should work with negative vectors", function() + local a = Vector3.new(-9, -16, -25) + local b = Vector3.new(-3, -6, -2) + + local result_a, result_b = Vector3.sort(a, b) + assert.are.same(Vector3.new(-9, -16, -25), result_a) + assert.are.same(Vector3.new(-3, -6, -2), result_b) + end) + it("should return new Vector3 instances", function() + local a = Vector3.new(16, 1, 16) + local b = Vector3.new(1, 4, 60) + + local result_a, result_b = Vector3.sort(a, b) + assert.are.same(Vector3.new(1, 1, 16), result_a) + assert.are.same(Vector3.new(16, 4, 60), result_b) + + result_a.y = 999 + result_b.y = 999 + + assert.are.same(Vector3.new(16, 1, 16), a) + assert.are.same(Vector3.new(1, 4, 60), b) + assert.are.same(Vector3.new(1, 999, 16), result_a) + assert.are.same(Vector3.new(16, 999, 60), result_b) + end) +end) diff --git a/.tests/Vector3/sqrt.test.lua b/.tests/Vector3/sqrt.test.lua new file mode 100644 index 0000000..dbd84ca --- /dev/null +++ b/.tests/Vector3/sqrt.test.lua @@ -0,0 +1,28 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.sqrt", function() + it("should sqrt a positive vector", function() + local a = Vector3.new(16, 64, 16) + assert.are.same( + Vector3.new(4, 8, 4), + a:sqrt() + ) + end) + it("should sqrt another positive vector", function() + local a = Vector3.new(9, 16, 25) + assert.are.same( + Vector3.new(3, 4, 5), + a:sqrt() + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(9, 16, 25) + + local result = a:sqrt() + assert.are.same( + Vector3.new(3, 4, 5), + result + ) + assert.are_not.equal(result, a) + end) +end) diff --git a/.tests/Vector3/subtract.test.lua b/.tests/Vector3/subtract.test.lua new file mode 100644 index 0000000..c447c71 --- /dev/null +++ b/.tests/Vector3/subtract.test.lua @@ -0,0 +1,80 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.subtract", function() + it("should subtract 2 positive vectors", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(1, 1, 1) + assert.are.same( + Vector3.new(2, 3, 4), + a:subtract(b) + ) + end) + it("should work with the sub alias", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(1, 1, 1) + assert.are.same( + Vector3.new(2, 3, 4), + a:sub(b) + ) + end) + it("should work with scalar a", function() + local a = 2 + local b = Vector3.new(6, 7, 8) + assert.are.same( + Vector3.new(4, 5, 6), + a - b + ) + end) + it("should work with scalar b", function() + local a = Vector3.new(6, 7, 8) + local b = 2 + assert.are.same( + Vector3.new(4, 5, 6), + a - b + ) + end) + it("should support the subtract operator", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(1, 1, 1) + assert.are.same( + Vector3.new(2, 3, 4), + a - b + ) + end) + it("should handle negative b", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(-1, -1, -1) + assert.are.same( + Vector3.new(4, 5, 6), + a - b + ) + end) + it("should handle negative a", function() + local a = Vector3.new(-3, -4, -5) + local b = Vector3.new(1, 1, 1) + assert.are.same( + Vector3.new(-4, -5, -6), + a - b + ) + end) + it("should handle negative a and b", function() + local a = Vector3.new(-3, -4, -5) + local b = Vector3.new(-1, -1, -1) + assert.are.same( + Vector3.new(-2, -3, -4), + a - b + ) + end) + it("should return a new Vector3 instance", function() + local a = Vector3.new(3, 4, 5) + local b = Vector3.new(1, 1, 1) + + local result = a - b + assert.are.same( + Vector3.new(2, 3, 4), + result + ) + assert.are_not.equal(result, a) + assert.are_not.equal(result, b) + end) +end) diff --git a/.tests/Vector3/tostring.test.lua b/.tests/Vector3/tostring.test.lua new file mode 100644 index 0000000..56f3dac --- /dev/null +++ b/.tests/Vector3/tostring.test.lua @@ -0,0 +1,39 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +describe("Vector3.__tostring", function() + it("should stringify a Vector3", function() + local a = Vector3.new(3, 4, 5) + assert.are.same( + "(3, 4, 5)", + a:__tostring() + ) + end) + it("should implicitly stringify a Vector3", function() + local a = Vector3.new(3, 4, 5) + assert.are.same( + "(3, 4, 5)", + tostring(a) + ) + end) + it("should implicitly stringify another Vector3", function() + local a = Vector3.new(55, 77, 22) + assert.are.same( + "(55, 77, 22)", + tostring(a) + ) + end) + it("should handle negative numbers", function() + local a = Vector3.new(-1, -2, -3) + assert.are.same( + "(-1, -2, -3)", + tostring(a) + ) + end) + it("should handle a mix of positive and negative numbers", function() + local a = Vector3.new(-7, 2, -99) + assert.are.same( + "(-7, 2, -99)", + tostring(a) + ) + end) +end) diff --git a/.tests/Vector3/unit.test.lua b/.tests/Vector3/unit.test.lua new file mode 100644 index 0000000..3d3b01d --- /dev/null +++ b/.tests/Vector3/unit.test.lua @@ -0,0 +1,37 @@ +local Vector3 = require("worldeditadditions.utils.vector3") + +-- To find these numbers, in Javascript: +-- function t(x) { return Math.sqrt((x*x)*3); } +-- for(let i = 0; i < 1000000000; i++) { let r = t(i); if(Math.floor(r) === r) console.log(`i ${i}, r ${r}`); } + + +describe("Vector3.unit", function() + it("should work with a positive vector", function() + local a = Vector3.new(10, 10, 10) + assert.are.same( + Vector3.new(57735, 57735, 57735), + a:unit():multiply(100000):floor() + ) + end) + it("should work with a the normalise alias", function() + local a = Vector3.new(10, 10, 10) + assert.are.same( + Vector3.new(57735, 57735, 57735), + a:normalise():multiply(100000):floor() + ) + end) + it("should work with a negative vector", function() + local a = Vector3.new(10, 10, 10) + assert.are.same( + Vector3.new(57735, 57735, 57735), + a:unit():multiply(100000):floor() + ) + end) + it("should work with a mixed vector", function() + local a = Vector3.new(-371635731, 371635731, -371635731) + assert.are.same( + Vector3.new(-57736, 57735, -57736), + a:unit():multiply(100000):floor() + ) + end) +end) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b1813d..d4fe01c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,12 @@ 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.12: The selection tools update (unreleased) +## v1.12: The selection tools update (26th June 2021) - Add `//spush`, `//spop`, and `//sstack` - Add `//srect` (_select rectangle_), `//scol` (_select column_), `//scube` (_select cube_) - thanks, @VorTechnix! - Add `//scloud` (_select point cloud_), `//scentre` (_select centre node(s)_), `//srel` (_select relative_) - thanks, @VorTechnix! - Add `//smake` (_selection make_) - thanks, @VorTechnix! - Significantly refactored backend utility functions (more to come in future updates) - - `//bonemeal`: Try bonemealing everything that isn't an air block (#49) - Add new universal chance parsing - Any `` can now either be a 1-in-N number (e.g. `4`, `10`), or a percentage chance (e.g. `50%`, `10%`). - Caveat: Percentages are converted to a 1-in-N chance, but additionally that number is rounded down in some places @@ -19,6 +18,7 @@ Note to self: See the bottom of this file for the release template text. - `//erode`: Add new `river` erosion algorithm for filling in potholes and removing pillars ### Bugfixes + - `//bonemeal`: Try bonemealing everything that isn't an air block (#49) - `//overlay`: Don't place nodes above water - `//multi`: Improve resilience by handling some edge cases - `//layers`: Fix crash due to outdated debug code diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index 3629ed5..9200ec0 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -505,6 +505,7 @@ While other server commands can be executed while a `//subdivide` is running, `/ //subdivice 25 25 25 fixlight ``` + ## `//multi .....` Executes multi chat commands in sequence. Intended for _WorldEdit_ commands, but does work with others too. Don't forget a space between commands! @@ -528,6 +529,7 @@ In addition, this also allows for including a double forward slash in the argume //multi /time 7:00 //1 //outset h 20 //outset v 5 //overlay dirt_with_grass //1 //2 //sphere 8 air //shift down 1 //floodfill //reset ``` + ## `//many ` Executes a single chat command many times in a row. Uses `minetest.after()` to yield to the main server thread to allow other things to happen at the same time, so technically you could have multiple `//many` calls going at once (but multithreading support is out of reach, so only a single one will be executing at the same time). @@ -538,6 +540,7 @@ Note that this isn't necessarily limited to executing WorldEdit / WorldEditAddit //many 100 //multi //1 //2 //outset 20 //set dirt ``` + ## `//ellipsoidapply ` Executes the given command, and then clips the result to the largest ellipsoid that will fit inside the defined region. The specified command must obviously take 2 positions - so for example `//set`, `//replacemix`, and `//maze3d` will work, but `//sphere`, `//torus`, and `//floodfill` won't. @@ -549,6 +552,7 @@ Executes the given command, and then clips the result to the largest ellipsoid t //ellipsoidapply layers desert_sand sand 2 desert_sandstone 4 sandstone 10 ``` + ## `//scol [ ] ` Short for _select column_. Sets the pos2 at a set distance along 1 axis from pos1. If the axis isn't specified, defaults the direction you are facing. Implementation thanks to @VorTechnix. @@ -557,6 +561,7 @@ Short for _select column_. Sets the pos2 at a set distance along 1 axis from pos //scol x 3 ``` + ## `//srect [ []] ` Short for _select rectangle_. Sets the pos2 at a set distance along 2 axes from pos1. If the axes aren't specified, defaults to positive y and the direction you are facing. Implementation thanks to @VorTechnix. @@ -566,6 +571,7 @@ Short for _select rectangle_. Sets the pos2 at a set distance along 2 axes from //srect -z y 25 ``` + ## `//scube [ [ []]] ` Short for _select cube_. Sets the pos2 at a set distance along 3 axes from pos1. If the axes aren't specified, defaults to positive y, the direction you are facing and the axis to the left of facing. Implementation thanks to @VorTechnix. @@ -576,6 +582,7 @@ Short for _select cube_. Sets the pos2 at a set distance along 3 axes from pos1. //scube -z 12 ``` + ## `//scloud <0-6|stop|reset>` Short for _select point cloud_. Sets pos1 and pos2 to include the nodes you punch. Numbers 1-6 designate how many nodes you want to punch before the operation ends. 0 or stop terminate the operation so that any further nodes you punch won't be added to selection. Reset terminates operation if one is running and resets the selection area. @@ -585,6 +592,7 @@ Short for _select point cloud_. Sets pos1 and pos2 to include the nodes you punc //scloud stop ``` + ## `//scentre` Short for _select center_. Sets pos1 and pos2 to the centre point(s) of the current selection area. 1, 2, 4 or 8 nodes may be selected depending on what parts of the original selection are even in distance. Implementation thanks to @VorTechnix. @@ -592,6 +600,7 @@ Short for _select center_. Sets pos1 and pos2 to the centre point(s) of the curr //scentre ``` + ## `//srel [ [ ]]` Short for _select relative_. Sets the pos2 at set distances along 3 axes relative to pos1. If pos1 is not set it will default to the node directly under the player. The axis arguments accept `x, y, z` as well as `up, down, left, right, front, back`. Left, right, front and back are relative to player facing direction. Negative (`-`) can be applied to the axis, the length or both. Implementation thanks to @VorTechnix. @@ -602,7 +611,8 @@ Short for _select relative_. Sets the pos2 at set distances along 3 axes relativ //scube -z 12 -y -2 x -2 ``` -## `//smake [ []]` + +## `//smake [ []]` Short for _selection make_. Modifies existing selection by moving pos2. Allows you to make the selection an odd or even length on one or more axes or set two or more axes equal to each other or the longest, shortest or average of them. Implementation thanks to @VorTechnix. Usage examples: @@ -615,41 +625,41 @@ Usage examples: //smake equal zy x ``` -### ``: odd/even/equal/factor +### ``: odd|even|equal -|Value | Description | -| --- | --- | -odd: | round up or down, based on mode, all axes specified in `` to the nearest odd length relative to pos1 -even: | round up or down, based on mode, all axes specified in `` to the nearest even length relative to pos1 -equal: | set `` axes length equal to the length of `` axis if specified or to the length of the largest, smallest or average of the `` axes based on mode. +Value | Description +--------|--------------- +`odd` | Round up or down, based on mode, all axes specified in `` to the nearest odd length relative to pos1 +`even` | Round up or down, based on mode, all axes specified in `` to the nearest even length relative to pos1 +`equal` | Set `` axes length equal to the length of `` axis if specified or to the length of the largest, smallest or average of the `` axes based on mode. -### `:` grow/shrink/average +### ``: grow|shrink|average #### *If `` == odd or even:* -|Value | Description | -| --- | --- | -grow: | grow each axis specified in `` to the nearest odd/even number to itself -shrink: | shrink each axis specified in `` to the nearest odd/even number to itself -average/avg: | take the average of all axes specified in `` and then for each specified axis grow or shrink it, depending on weather it is less than or greater than the average, to the nearest odd/even number to itself +Value | Description +----------------|-------------- +`grow` | Grow each axis specified in `` to the nearest odd/even number to itself +`shrink` | Shrink each axis specified in `` to the nearest odd/even number to itself +`average`|`avg` | Take the average of all axes specified in `` and then for each specified axis grow or shrink it, depending on weather it is less than or greater than the average, to the nearest odd/even number to itself -#### *If `` == equal:* ^[1] +#### *If `` == equal:* +The `` argument can be omitted and will not be parsed if present if `` is specified -|Value | Description | -| --- | --- | -grow: | grow each axis specified in `` to the length of the longest specified axis -shrink: | shrink each axis specified in `` to the length of the shortest specified axis -average/avg: | set each axis specified in `` to the average length of all the specified axes +Value | Description +----------------|--------------- +`grow` | Grow each axis specified in `` to the length of the longest specified axis +`shrink` | Shrink each axis specified in `` to the length of the shortest specified axis +`average`|`avg` | Set each axis specified in `` to the average length of all the specified axes ### Additional arguments: -|Name | Description | -| --- | --- | -``: | Specify axes to perform operation on (default= xz)| -``: If `` == odd or even: | Does nothing -``: If `` == equal: | Overrides ``^[1] and sets all `` axes equal to itself - -^[1]: `` argument can be omitted and will not be parsed if present if `` is specified +Name | Description +------------|------------------ +`` | Specify axes to perform operation on (default= xz)| +``: If `` == odd or even | Does nothing +``: If `` == equal | Overrides ``^[1] and sets all `` axes equal to itself + ## `//sstack` Displays the contents of your per-user selection stack. This stack can be pushed to and popped from rather like a stack of plates. See also `//spush` (for pushing to the selection stack) and `//spop` (for popping from the selection stack). @@ -658,6 +668,7 @@ Displays the contents of your per-user selection stack. This stack can be pushed //sstack ``` + ## `//spush` Pushes the currently defined region onto your per-user selection stack. Does not otherwise alter the defined region. diff --git a/README.md b/README.md index f55fb03..0db3fd5 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ The detailed explanations have moved! Check them out [here](https://github.com/s - [`//scloud <0-6|stop|reset>`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#scloud-0-6stopreset) - [`//scentre`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#scentre) - [`//srel [ [ ]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#srel-axis1-length1-axis2-length2-axis3-length3) + - [`//smake [ []]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#smake-operationoddevenequal-modegrowshrinkaverage-targetxz-base) - [`//sstack`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#sstack) - [`//spush`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#spush) - [`//spop`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#spop) @@ -81,6 +82,7 @@ The detailed explanations have moved! Check them out [here](https://github.com/s ### Tools - [WorldEditAdditions Far Wand](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#far-wand) + - [WorldEditAdditions Cloud Wand](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#cloud-wand) - [`//farwand skip_liquid (true|false) | maxdist `](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/main/Chat-Command-Reference.md#farwand-skip_liquid-truefalse--maxdist-number) diff --git a/tests.sh b/tests.sh index 35bac85..d355f72 100755 --- a/tests.sh +++ b/tests.sh @@ -27,7 +27,7 @@ luarocks_root="${PWD}/.luarocks"; # Setup the lua module path eval "$(luarocks --tree "${luarocks_root}" path)"; -mode="${1}"; shift; +mode="${1}"; if [[ "$#" -gt 0 ]]; then shift; fi run_setup() { log_msg "Installing busted"; diff --git a/worldeditadditions/init.lua b/worldeditadditions/init.lua index 08c03e0..4a1e1cb 100644 --- a/worldeditadditions/init.lua +++ b/worldeditadditions/init.lua @@ -8,6 +8,8 @@ worldeditadditions = {} worldeditadditions.modpath = minetest.get_modpath("worldeditadditions") dofile(worldeditadditions.modpath.."/utils/vector.lua") +dofile(worldeditadditions.modpath.."/utils/vector3.lua") +dofile(worldeditadditions.modpath.."/utils/mesh.lua") dofile(worldeditadditions.modpath.."/utils/strings/init.lua") dofile(worldeditadditions.modpath.."/utils/format/init.lua") diff --git a/worldeditadditions/utils/mesh.lua b/worldeditadditions/utils/mesh.lua new file mode 100644 index 0000000..e496f8f --- /dev/null +++ b/worldeditadditions/utils/mesh.lua @@ -0,0 +1,99 @@ +local wea = worldeditadditions + + +-- ███████ █████ ██████ ███████ +-- ██ ██ ██ ██ ██ +-- █████ ███████ ██ █████ +-- ██ ██ ██ ██ ██ +-- ██ ██ ██ ██████ ███████ + +--- A single face of a Mesh. +local Face = {} +Face.__index = Face + +--- Creates a new face from a list of vertices. +-- The list of vertices should be anti-clockwise. +-- @param vertices Vector3[] A list of Vector3 vertices that define the face. +function Face.new(vertices) + local result = { vertices = vertices } + setmetatable(result, Face) + return result +end + +--- Determines whether this face is equal to another face or not. +-- @param a Face The first face to compare. +-- @param b Face The second face to compare. +-- @returns bool Whether the 2 faces are equal or not. +function Face.equal(a, b) + if #a.vertices ~= #b.vertices then return false end + for i,vertex in ipairs(a) do + if vertex ~= b.vertices[i] then return false end + end + return true +end +function Face.__eq(a, b) return Face.equal(a, b) end + + +-- ███ ███ ███████ ███████ ██ ██ +-- ████ ████ ██ ██ ██ ██ +-- ██ ████ ██ █████ ███████ ███████ +-- ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ███████ ███████ ██ ██ + +--- A mesh of faces. +local Mesh = {} +Mesh.__index = Mesh + +--- Creates a new empty mesh object container. +-- @returns Mesh +function Mesh.new() + local result = { faces = {} } + setmetatable(result, Mesh) +end + +--- Adds a face to this mesh. +-- @param self Mesh The mesh instance to operate on. +-- @param face Face The face to add. +-- @returns void +function Mesh.add_face(self, face) + table.insert(self.faces, face) +end + +--- Deduplicate the list of faces in this Mesh. +-- Removes all faces that are exactly equal to one another. This reduces the +-- filesize. +-- @returns number The number of faces removed. +function Mesh.dedupe(self) + -- Find the faces to remove + local toremove = {} + for i,face_check in ipairs(self.faces) do + for j,face_next in ipairs(self.faces) do + if i ~= j -- If we're not comparing a face to itself... + and face_check == face_next -- ....and the 2 faces are equal.... + and not wea.table_contains(toremove, j) then -- ...and we haven't already marked it for removal... + -- Mark it for removal + table.insert(toremove, j) + end + end + end + -- Sort the list of indexes marked for removal from largest to smallest + -- This way, removing smaller items doesn't alter the index of larger ones + table.sort(toremove, function(a, b) return a > b end) + + -- Remove the faces marked for removal + for i, remove_index in ipairs(toremove) do + table.remove(self.faces, remove_index) + end + return #toremove +end + + +if worldeditadditions then + worldeditadditions.Face = Face + worldeditadditions.Mesh = Mesh +else + return { + Face = Face, + Mesh = Mesh + } +end diff --git a/worldeditadditions/utils/tables/init.lua b/worldeditadditions/utils/tables/init.lua index 2536672..2ccf93b 100644 --- a/worldeditadditions/utils/tables/init.lua +++ b/worldeditadditions/utils/tables/init.lua @@ -20,3 +20,4 @@ dofile(worldeditadditions.modpath.."/utils/tables/table_map.lua") dofile(worldeditadditions.modpath.."/utils/tables/table_tostring.lua") dofile(worldeditadditions.modpath.."/utils/tables/table_unique.lua") dofile(worldeditadditions.modpath.."/utils/tables/table_unpack.lua") +dofile(worldeditadditions.modpath.."/utils/tables/table_contains.lua") diff --git a/worldeditadditions/utils/tables/table_contains.lua b/worldeditadditions/utils/tables/table_contains.lua new file mode 100644 index 0000000..c65fdfe --- /dev/null +++ b/worldeditadditions/utils/tables/table_contains.lua @@ -0,0 +1,18 @@ + +--- Looks to see whether a given table contains a given value. +-- @param tbl table The table to look in. +-- @param target any The target to look for. +-- @returns bool Whether the table contains the given target or not. +local function table_contains(tbl, target) + for key, value in ipairs(tbl) do + if value == target then return true end + end + return false +end + + +if worldeditadditions then + worldeditadditions.table_contains = table_contains +else + return table_contains +end diff --git a/worldeditadditions/utils/vector.lua b/worldeditadditions/utils/vector.lua index 4c767b4..7f330da 100644 --- a/worldeditadditions/utils/vector.lua +++ b/worldeditadditions/utils/vector.lua @@ -110,7 +110,7 @@ end -- @param pos2 Vector pos2 of the defined region. -- @return Vector Min values from input vectors. function worldeditadditions.vector.min(pos1, pos2) - return vector.new(math.min(pos1.x + pos2.x), math.min(pos1.y + pos2.y), math.min(pos1.z + pos2.z)) + return vector.new(math.min(pos1.x, pos2.x), math.min(pos1.y, pos2.y), math.min(pos1.z, pos2.z)) end --- Returns a vector of the max values of 2 positions. @@ -118,5 +118,5 @@ end -- @param pos2 Vector pos2 of the defined region. -- @return Vector Max values from input vectors. function worldeditadditions.vector.max(pos1, pos2) - return vector.new(math.max(pos1.x + pos2.x), math.max(pos1.y + pos2.y), math.max(pos1.z + pos2.z)) + return vector.new(math.max(pos1.x, pos2.x), math.max(pos1.y, pos2.y), math.max(pos1.z, pos2.z)) end diff --git a/worldeditadditions/utils/vector3.lua b/worldeditadditions/utils/vector3.lua new file mode 100644 index 0000000..095c3d8 --- /dev/null +++ b/worldeditadditions/utils/vector3.lua @@ -0,0 +1,399 @@ +--- A 3-dimensional vector. +local Vector3 = {} +Vector3.__index = Vector3 + +function Vector3.new(x, y, z) + if type(x) ~= "number" then + error("Error: Expected number for the value of x, but received argument of type "..type(x)..".") + end + if type(y) ~= "number" then + error("Error: Expected number for the value of y, but received argument of type "..type(y)..".") + end + if type(z) ~= "number" then + error("Error: Expected number for the value of z, but received argument of type "..type(z)..".") + end + + local result = { + x = x, + y = y, + z = z + } + setmetatable(result, Vector3) + return result +end + +--- Returns a new instance of this vector. +-- @param a Vector3 The vector to clone. +-- @returns Vector3 A new vector whose values are identical to those of the original vector. +function Vector3.clone(a) + return Vector3.new(a.x, a.y, a.z) +end + +--- Adds the specified vectors or numbers together. +-- Returns the result as a new vector. +-- If 1 of the inputs is a number and the other a vector, then the number will +-- be added to each of the components of the vector. +-- @param a Vector3|number The first item to add. +-- @param a Vector3|number The second item to add. +-- @returns Vector3 The result as a new Vector3 object. +function Vector3.add(a, b) + if type(a) == "number" then + return Vector3.new(b.x + a, b.y + a, b.z + a) + elseif type(b) == "number" then + return Vector3.new(a.x + b, a.y + b, a.z + b) + end + return Vector3.new(a.x + b.x, a.y + b.y, a.z + b.z) +end + +--- Subtracts the specified vectors or numbers together. +-- Returns the result as a new vector. +-- If 1 of the inputs is a number and the other a vector, then the number will +-- be subtracted to each of the components of the vector. +-- @param a Vector3|number The first item to subtract. +-- @param a Vector3|number The second item to subtract. +-- @returns Vector3 The result as a new Vector3 object. +function Vector3.subtract(a, b) + if type(a) == "number" then + return Vector3.new(b.x - a, b.y - a, b.z - a) + elseif type(b) == "number" then + return Vector3.new(a.x - b, a.y - b, a.z - b) + end + return Vector3.new(a.x - b.x, a.y - b.y, a.z - b.z) +end +--- Alias for Vector3.subtract. +function Vector3.sub(a, b) return Vector3.subtract(a, b) end + +--- Multiplies the specified vectors or numbers together. +-- Returns the result as a new vector. +-- If 1 of the inputs is a number and the other a vector, then the number will +-- be multiplied to each of the components of the vector. +-- +-- If both of the inputs are vectors, then the components are multiplied +-- by each other (NOT the cross product). In other words: +-- a.x * b.x, a.y * b.y, a.z * b.z +-- +-- @param a Vector3|number The first item to multiply. +-- @param a Vector3|number The second item to multiply. +-- @returns Vector3 The result as a new Vector3 object. +function Vector3.multiply(a, b) + if type(a) == "number" then + return Vector3.new(b.x * a, b.y * a, b.z * a) + elseif type(b) == "number" then + return Vector3.new(a.x * b, a.y * b, a.z * b) + end + return Vector3.new(a.x * b.x, a.y * b.y, a.z * b.z) +end +--- Alias for Vector3.multiply. +function Vector3.mul(a, b) return Vector3.multiply(a, b) end + +--- Divides the specified vectors or numbers together. +-- Returns the result as a new vector. +-- If 1 of the inputs is a number and the other a vector, then the number will +-- be divided to each of the components of the vector. +-- @param a Vector3|number The first item to divide. +-- @param a Vector3|number The second item to divide. +-- @returns Vector3 The result as a new Vector3 object. +function Vector3.divide(a, b) + if type(a) == "number" then + return Vector3.new(b.x / a, b.y / a, b.z / a) + elseif type(b) == "number" then + return Vector3.new(a.x / b, a.y / b, a.z / b) + end + return Vector3.new(a.x / b.x, a.y / b.y, a.z / b.z) +end +--- Alias for Vector3.divide. +function Vector3.div(a, b) return Vector3.divide(a, b) end + + +--- Rounds the components of this vector down. +-- @param a Vector3 The vector to operate on. +-- @returns Vector3 A new instance with the x/y/z components rounded down. +function Vector3.floor(a) + return Vector3.new(math.floor(a.x), math.floor(a.y), math.floor(a.z)) +end +--- Rounds the components of this vector up. +-- @param a Vector3 The vector to operate on. +-- @returns Vector3 A new instance with the x/y/z components rounded up. +function Vector3.ceil(a) + return Vector3.new(math.ceil(a.x), math.ceil(a.y), math.ceil(a.z)) +end +--- Rounds the components of this vector. +-- @param a Vector3 The vector to operate on. +-- @returns Vector3 A new instance with the x/y/z components rounded. +function Vector3.round(a) + return Vector3.new(math.floor(a.x+0.5), math.floor(a.y+0.5), math.floor(a.z+0.5)) +end + + +--- Snaps this Vector3 to an imaginary square grid with the specified sized +-- squares. +-- @param a Vector3 The vector to operate on. +-- @param number grid_size The size of the squares on the imaginary grid to which to snap. +-- @returns Vector3 A new Vector3 instance snapped to an imaginary grid of the specified size. +function Vector3.snap_to(a, grid_size) + return (a / grid_size):round() * grid_size +end + +--- Returns the area of this vector. +-- In other words, multiplies all the components together and returns a scalar value. +-- @param a Vector3 The vector to return the area of. +-- @returns number The area of this vector. +function Vector3.area(a) + return a.x * a.y * a.z +end + +--- Returns the scalar length of this vector squared. +-- @param a Vector3 The vector to operate on. +-- @returns number The length squared of this vector as a scalar value. +function Vector3.length_squared(a) + return a.x * a.x + a.y * a.y + a.z * a.z +end + +--- Square roots each component of this vector. +-- @param a Vector3 The vector to operate on. +-- @returns number A new vector with each component square rooted. +function Vector3.sqrt(a) + return Vector3.new(math.sqrt(a.x), math.sqrt(a.y), math.sqrt(a.z)) +end + +--- Calculates the scalar length of this vector. +-- @param a Vector3 The vector to operate on. +-- @returns number The length of this vector as a scalar value. +function Vector3.length(a) + return math.sqrt(a:length_squared()) +end + +--- Calculates the dot product of this vector and another vector. +-- @param a Vector3 The first vector to operate on. +-- @param a Vector3 The second vector to operate on. +-- @returns number The dot product of this vector as a scalar value. +function Vector3.dot(a, b) + return a.x * b.x + a.y * b.y + a.z * b.z; +end +--- Alias of Vector3.dot. +function Vector3.dot_product(a, b) + return Vector3.dot(a, b) +end + +--- Determines if 2 vectors are equal to each other. +-- 2 vectors are equal if their values are identical. +-- @param a Vector3 The first vector to test. +-- @param a Vector3 The second vector to test. +-- @returns bool Whether the 2 vectors are equal or not. +function Vector3.equals(a, b) + return a.x == b.x + and a.y == b.y + and a.z == b.z +end + +--- Returns a new vector whose length clamped to the given length. +-- The direction in which the vector is pointing is not changed. +-- @param a Vector3 The vector to operate on. +-- @returns Vector3 A new Vector3 instance limited to the specified length. +function Vector3.limit_to(a, length) + if type(length) ~= "number" then error("Error: Expected number, but found "..type(length)..".") end + + if a:length() > length then + return (a / a:length()) * length + end + return a:clone() +end + +--- Returns a new vector whose length clamped to the given length. +-- The direction in which the vector is pointing is not changed. +-- @param a Vector3 The vector to operate on. +-- @returns Vector3 A new Vector3 instance limited to the specified length. +function Vector3.set_to(a, length) + if type(length) ~= "number" then error("Error: Expected number, but found "..type(length)..".") end + + return (a / a:length()) * length +end + +--- Returns the unit vector of this vector. +-- The unit vector is a vector with a length of 1. +-- Returns a new vector. +-- Does not change the direction of the vector. +-- @param a Vector3 The vector to operate on. +-- @returns Vector3 The unit vector of this vector. +function Vector3.unit(a) + return a / a:length() +end +--- Alias of Vector3.unit. +function Vector3.normalise(a) return a:unit() end + + +--- Return a vector that is amount distance towards b from a. +-- @param a Vector3 The vector to move from. +-- @param b Vector3 The vector to move towards. +-- @param amount number The amount to move. +function Vector3.move_towards(a, b, amount) + return a + (b - a):limit_to(amount) +end + +--- Returns the value of the minimum component of the vector. +-- Returns a scalar value. +-- @param a Vector3 The vector to operate on. +-- @returns number The value of the minimum component of the vector. +function Vector3.min_component(a) + return math.min(a.x, a.y, a.z) +end + +--- Returns the value of the maximum component of the vector. +-- Returns a scalar value. +-- @param a Vector3 The vector to operate on. +-- @returns number The value of the maximum component of the vector. +function Vector3.max_component(a) + return math.max(a.x, a.y, a.z) +end + +--- Returns the absolute form of this vector. +-- In other words, it removes the minus sign from all components of the vector. +-- @param a Vector3 The vector to operate on. +-- @returns Vector3 The absolute form of the given vector. +function Vector3.abs(a) + return Vector3.new(math.abs(a.x), math.abs(a.y), math.abs(a.z)) +end + +--- Sorts the components of the given vectors. +-- pos1 will contain the minimum values, and pos2 the maximum values. +-- Returns 2 new vectors. +-- Note that the vectors provided do not *have* to be instances of Vector3. +-- It is only required that they have the keys x, y, and z. +-- Vector3 instances are always returned. +-- This enables convenient ingesting of positions from outside. +-- @param pos1 Vector3 The first vector to operate on. +-- @param pos2 Vector3 The second vector to operate on. +-- @returns Vector3,Vector3 The 2 sorted vectors. +function Vector3.sort(pos1, pos2) + local pos1_new = Vector3.clone(pos1) -- This way we can accept non-Vector3 instances + local pos2_new = Vector3.clone(pos2) -- This way we can accept non-Vector3 instances + if pos1_new.x > pos2_new.x then + pos1_new.x, pos2_new.x = pos2_new.x, pos1_new.x + end + if pos1_new.y > pos2_new.y then + pos1_new.y, pos2_new.y = pos2_new.y, pos1_new.y + end + if pos1_new.z > pos2_new.z then + pos1_new.z, pos2_new.z = pos2_new.z, pos1_new.z + end + return pos1_new, pos2_new +end + +--- Determines if this vector is contained within the region defined by the given vectors. +-- @param a Vector3 The target vector to check. +-- @param pos1 Vector3 pos1 of the defined region. +-- @param pos2 Vector3 pos2 of the defined region. +-- @return boolean Whether the given target is contained within the defined worldedit region. +function Vector3.is_contained(target, pos1, pos2) + local pos1, pos2 = Vector3.sort(pos1, pos2) + + return pos1.x <= target.x + and pos1.y <= target.y + and pos1.z <= target.z + and pos2.x >= target.x + and pos2.y >= target.y + and pos2.z >= target.z +end + + +--- Expands the defined region to include the given point. +-- @param target Vector3 The target vector to include. +-- @param pos1 Vector3 pos1 of the defined region. +-- @param pos2 Vector3 pos2 of the defined region. +-- @returns Vector3,Vector3 2 vectors that represent the expand_region. +function Vector3.expand_region(target, pos1, pos2) + local pos1, pos2 = Vector3.sort(pos1, pos2) + + if target.x < pos1.x then pos1.x = target.x end + if target.y < pos1.y then pos1.y = target.y end + if target.z < pos1.z then pos1.z = target.z end + + if target.x > pos2.x then pos2.x = target.x end + if target.y > pos2.y then pos2.y = target.y end + if target.z > pos2.z then pos2.z = target.z end + + return pos1, pos2 +end + +--- Returns the mean (average) of 2 positions. +-- In other words, returns the centre of 2 points. +-- @param pos1 Vector3 pos1 of the defined region. +-- @param pos2 Vector3 pos2 of the defined region. +-- @param target Vector3 Centre coordinates. +function Vector3.mean(pos1, pos2) + return (pos1 + pos2) / 2 +end + + +--- Returns a vector of the min components of 2 vectors. +-- @param pos1 Vector3 The first vector to operate on. +-- @param pos2 Vector3 The second vector to operate on. +-- @return Vector3 The minimum values from the input vectors +function Vector3.min(pos1, pos2) + return Vector3.new( + math.min(pos1.x, pos2.x), + math.min(pos1.y, pos2.y), + math.min(pos1.z, pos2.z) + ) +end + +--- Returns a vector of the max values of 2 vectors. +-- @param pos1 Vector3 The first vector to operate on. +-- @param pos2 Vector3 The second vector to operate on. +-- @return Vector3 The maximum values from the input vectors. +function Vector3.max(pos1, pos2) + return Vector3.new( + math.max(pos1.x, pos2.x), + math.max(pos1.y, pos2.y), + math.max(pos1.z, pos2.z) + ) +end + + + +-- ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ██████ █████ ██████ ███████ ██ ██ ██ ██████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██████ ██ ███████ ██ ██ ██ ██ ██ ██████ ██ ██ +-- +-- ██████ ██ ██ ███████ ██████ ██████ ██ ██████ ███████ ███████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ██ ██ █████ ██████ ██████ ██ ██ ██ █████ ███████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██████ ████ ███████ ██ ██ ██ ██ ██ ██████ ███████ ███████ + +function Vector3.__call(x, y, z) return Vector3.new(x, y, z) end + +function Vector3.__add(a, b) + return Vector3.add(a, b) +end + +function Vector3.__sub(a, b) + return Vector3.sub(a, b) +end + +function Vector3.__mul(a, b) + return Vector3.mul(a, b) +end + +function Vector3.__div(a, b) + return Vector3.divide(a, b) +end + +function Vector3.__eq(a, b) + return Vector3.equals(a, b) +end + +--- Returns the current Vector3 as a string. +function Vector3.__tostring(a) + return "("..a.x..", "..a.y..", "..a.z..")" +end + + + +if worldeditadditions then + worldeditadditions.Vector3 = Vector3 +else + return Vector3 +end diff --git a/worldeditadditions_commands/commands/selectors/smake.lua b/worldeditadditions_commands/commands/selectors/smake.lua index d9cb22a..13b0b02 100644 --- a/worldeditadditions_commands/commands/selectors/smake.lua +++ b/worldeditadditions_commands/commands/selectors/smake.lua @@ -5,7 +5,7 @@ -- ███████ ██ ██ ██ ██ ██ ██ ███████ local wea = worldeditadditions worldedit.register_command("smake", { - params = " [ []]", + params = " [ []]", description = "Make one or more axes of the current selection odd, even, or equal to another.", privs = { worldedit = true }, require_pos = 2,