diff --git a/.gitignore b/.gitignore index 546dc51..76541c0 100644 --- a/.gitignore +++ b/.gitignore @@ -242,6 +242,7 @@ temp/ # VorTechnix stuff .vdev/ +*.old.lua # Created by https://www.toptal.com/developers/gitignore/api/archives # Edit at https://www.toptal.com/developers/gitignore?templates=archives diff --git a/.tests/parse/axes/axes_parser.test.lua b/.tests/parse/axes/axes_parser.test.lua index 00546cd..a698438 100644 --- a/.tests/parse/axes/axes_parser.test.lua +++ b/.tests/parse/axes/axes_parser.test.lua @@ -96,6 +96,15 @@ describe("parse_axes", function() assert.are.same(Vector3.new(40, 77, 99), maxv) end) + it("should infer that directions before a value are connected to that value", function() + local minv, maxv = parse_axes({ + "xy", "-x", "5" + }, facing_dirs.z_neg) + assert.is.truthy(minv) + assert.are.same(Vector3.new(-5, 0, 0), minv) + assert.are.same(Vector3.new(5, 5, 0), maxv) + end) + it("should return 2 0,0,0 vectors if no input", function() local minv, maxv = parse_axes({ -- No input diff --git a/CHANGELOG.md b/CHANGELOG.md index 116b30b..66ee766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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.15: The untitled update (unreleased) +## v1.15: The direction update (unreleased) - Added the optional argument `all` to [`//unmark`](https://worldeditadditions.mooncarrot.space/Reference/#unmark) - Added a (rather nuclear) fix (attempt 4) at finally exterminating all zombie region marker walls forever - This is not a hotfix to avoid endless small releases fixing the bug, as it's clear it's much more difficult to fix on all systems than initially expected @@ -16,11 +16,21 @@ Note to self: See the bottom of this file for the release template text. - Added [`//set+`](https://worldeditadditions.mooncarrot.space/Reference/#set) for setting nodes and param2/light levels quickly. - NOTE TO SELF: Setting light values doesn't appear to be working very well for some reason - Added [`//ndef`](https://worldeditadditions.mooncarrot.space/Reference/#ndef) to print a given node's definition table. This is for debugging and development purposes. +- Added `//sgrow` and `//sshrink` commands to enlarge and shrink selection regions and aliased them over WorldEdit equivalents (`//expand`, `//outset` and `//contract`, `//inset` respectively). +- Added Unified Axis Syntax (UAS) parser. - Implementation by @VorTechnix + - See [UAS System reference] for details. (Note to self hook up hyperlink) +- Added `//uasparse` command to show the vectors produced by a given UAS expression. - Implementation by @VorTechnix ### Bugfixes and changes - Don't warn on failed registration of `//flora` → [`//bonemeal`](https://worldeditadditions.mooncarrot.space/Reference/#bonemeal) if the `bonemeal` mod isn't installed (e.g. in MineClone2) - thanks @VorTechnix in #106 - Improve documentation of [`//noise2d`](https://worldeditadditions.mooncarrot.space/Reference/#noise2d). If it still doesn't make sense, please let me know. It's a complicated command that needs reworking a bit to be easier to use. - Alias `//napply` to [`//nodeapply`](https://worldeditadditions.mooncarrot.space/Reference/#nodeapply) +- Re-factored selection tools to all use WEA position system and UAS Parser if applicable. - Re-factor by @VorTechnix +- `//sshift` now overrides `//shift` from WorldEdit. - Re-factor by @VorTechnix + +### Deprecations +- Deprecated `//scol`, `//srect` and `//scube`. Now that `//srel` is using UAS parser there is no need for them. - Deprecated by @VorTechnix +- Deprecated `//sfactor`. Now that `//sgrow` and `//sshrink` exist it is no longer needed. - Deprecated by @VorTechnix ### Lua API changes diff --git a/Chat-Command-Reference.md b/Chat-Command-Reference.md index 5bc1981..d608396 100644 --- a/Chat-Command-Reference.md +++ b/Chat-Command-Reference.md @@ -1201,6 +1201,16 @@ This command is intended for debugging and development purposes, but if you're i //ndef glass ``` +### `//uasparse ` +Short for *Unified Axis Syntax Parse*. Parses the given UAS expression and prints the resulting vectors to the chat window. + +```weacmd +//uasparse front right 5 +//uasparse y 12 h -2 +//uasparse left 3 up 5 -front 7 +//uasparse -z 12 -y -2 x -2 +``` + ## Selection @@ -1212,6 +1222,58 @@ This command is intended for debugging and development purposes, but if you're i ███████ ███████ ███████ ███████ ██████ ██ ██ ██████ ██ ████ --> +### Unified Axis Syntax (UAS) +The Unified Axis Syntax system allows users to input direction and distance information in three dimensions using "natural" measurement syntax. The key features include axis clumping, double negatives, relative directions, mirroring and compass directions (more information below). + +*Note: negatives can be applied to axes, directions **AND** distances* + +#### Relative Directions +|Key Words | Interpretation| +|----------|---------------| +|`f[ront]\|facing\|?` | The direction the player is facing most toward in the world +|`b[ack]\|behind\|rear` | The opposite of the direction the player is facing most toward in the world +|`l[eft]` | The direction to the left of the player +|`r[ight]` | The direction to the right of the player + +```weacmd +back 1 +f r 4 +-facing 13 +``` + +#### Compass Directions +|Key Words | Interpretation| +|----------|---------------| +|`n[orth]` | z +|`s[outh]` | -z +|`e[ast]` | x +|`w[est]` | -x +|`u[p]` | y +|`d[own]` | -y + +```weacmd +south 3 +north west 5 +e d -2 +``` + +#### Axis Clumping +Supported axes are `x`, `y`, `z`, `h`, `v`. All horizontal axes are covered by `h` and both vertical ones are covered by `v`. + +- `h 5` == `xz -xz 5` == `x 5 z 5 x -5 z -5` +- `v 5` == `up down 5` == `y -y 5` +- `vxz 5` == `xyz -y 5` == `xyz 5 y -5` + +#### Inference and Omnidirectionality +The UAS parser takes command input that is split by whitespace and interprets it as a series of numbers preceded by directional cues. If a number is preceded by another number or nothing it assumes that the number is to be applied on all axes in both positive and negative directions. + +- `10` == `hv 10` == `xyz -xyz 10` +- `x 3 6` == `x 3 hv 6` + +From the above examples you can also see the principle of inference. All direction modifiers before a value are interpreted as belonging to that value. So `x v 5` is equivalent to `x 5 v 5` and `xv 5`. + +Because UAS parses "natural" measurement syntax, there are many ways to express the same direction and distance. This caters to users with different ways of thinking and different play styles which will hopefully make the tools easier to use. + ### `//unmark` > First overridden in v1.14 @@ -1310,7 +1372,6 @@ Short for _select column_. Sets the pos2 at a set distance along 1 axis from pos //scol x 3 ``` - ### `//srect [ []] ` > Added in v1.12; deprecated in favour of [`//srel`](#srel) in v1.15 @@ -1365,17 +1426,43 @@ Short for _select center_. Sets pos1 and pos2 to the centre point(s) of the curr //scentre ``` -### `//srel [ [ ]]` +### `//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. ```weacmd //srel front 5 -//srel y 12 right -2 +//srel y 12 right -2 //srel left 3 up 5 -front 7 //srel -z 12 -y -2 x -2 ``` -### `//sshift [ [ ]]` +### `//sgrow ` +> Added in v1.15 + +Short for _selection grow_. Grows the current selection along specified axes/directions. +Aliases: `//extend`, `//outset`. + +```weacmd +//sgrow back 4 +//sgrow left -2 v r 2 +//sgrow h 4 +//sgrow -zy -2 x -2 +``` + +### `//sshrink ` +> Added in v1.15 + +Short for _selection shrink_. Shrinks the current selection along specified axes/directions. +Aliases: `//contract`, `//inset`. + +```weacmd +//sshrink left 4 +//sshrink right -2 up 2 +//sshrink v 4 +//sshrink -hy 2 x -3 true +``` + +### `//sshift ` > Added in v1.13 Short for _selection shift_. Shifts the WorldEdit region along 3 axes. 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. diff --git a/README.md b/README.md index 2902c3a..1cc24af 100644 --- a/README.md +++ b/README.md @@ -80,20 +80,23 @@ The detailed explanations have moved! Check them out [here](https://worldeditadd - [`//basename `](https://worldeditadditions.mooncarrot.space/Reference/#basename) - [`//ngroups [v[erbose]]`](https://worldeditadditions.mooncarrot.space/Reference/#ngroups) _(new in v1.15)_ - [`//ndef `](https://worldeditadditions.mooncarrot.space/Reference/#ndef) _(new in v1.15)_ + - [`//uasparse `](https://worldeditadditions.mooncarrot.space/Reference/#uasparse) _(new in v1.15)_ ### Selection - - [`//scol [ ] `](https://worldeditadditions.mooncarrot.space/Reference/#scol) - - [`//srect [ []] `](https://worldeditadditions.mooncarrot.space/Reference/#srect) - - [`//scube [ [ []]] `](https://worldeditadditions.mooncarrot.space/Reference/#scube) + - [~~`//scol [ ] `~~](https://worldeditadditions.mooncarrot.space/Reference/#scol) (REMOVED in v1.15) + - [~~`//srect [ []] `~~](https://worldeditadditions.mooncarrot.space/Reference/#srect) (REMOVED in v1.15) + - [~~`//scube [ [ []]] `~~](https://worldeditadditions.mooncarrot.space/Reference/#scube) (REMOVED in v1.15) - [`//scloud <0-6|stop|reset>`](https://worldeditadditions.mooncarrot.space/Reference/#scloud) - [`//scentre`](https://worldeditadditions.mooncarrot.space/Reference/#scentre) - - [`//srel [ [ ]]`](https://worldeditadditions.mooncarrot.space/Reference/#srel) + - [`//sgrow `](https://worldeditadditions.mooncarrot.space/Reference/#sgrow) _(new in v1.15)_ + - [`//srel `](https://worldeditadditions.mooncarrot.space/Reference/#srel) - [`//smake [ []]`](https://worldeditadditions.mooncarrot.space/Reference/#smake) + - [`//sshrink `](https://worldeditadditions.mooncarrot.space/Reference/#sshrink) _(new in v1.15)_ - [`//sstack`](https://worldeditadditions.mooncarrot.space/Reference/#sstack) - [`//spush`](https://worldeditadditions.mooncarrot.space/Reference/#spush) - [`//spop`](https://worldeditadditions.mooncarrot.space/Reference/#spop) - - [`//sshift [ [ ]]`](https://worldeditadditions.mooncarrot.space/Reference/#sshift) - - [`//sfactor []`](https://worldeditadditions.mooncarrot.space/Reference/#sfactor) + - [`//sshift `](https://worldeditadditions.mooncarrot.space/Reference/#sshift) + - [~~`//sfactor []`~~](https://worldeditadditions.mooncarrot.space/Reference/#sfactor) (REMOVED in v1.15) - [`//pos `](https://worldeditadditions.mooncarrot.space/Reference/#pos) - [`//pos1`](https://worldeditadditions.mooncarrot.space/Reference/#pos1) - [`//pos2`](https://worldeditadditions.mooncarrot.space/Reference/#pos2) diff --git a/worldeditadditions_commands/commands/selectors/init.lua b/worldeditadditions_commands/commands/selectors/init.lua index 00d5685..f5b4f95 100644 --- a/worldeditadditions_commands/commands/selectors/init.lua +++ b/worldeditadditions_commands/commands/selectors/init.lua @@ -1,34 +1,46 @@ --- ███████ ███████ ██ ███████ ██████ ████████ ██████ ██████ ███████ --- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ --- ███████ █████ ██ █████ ██ ██ ██ ██ ██████ ███████ --- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ --- ███████ ███████ ███████ ███████ ██████ ██ ██████ ██ ██ ███████ - --- Chat commands that operate on selections. - -local wea_cmdpath = worldeditadditions_commands.modpath .. "/commands/selectors/" -local weac = worldeditadditions_core - -dofile(wea_cmdpath.."srel.lua") -dofile(wea_cmdpath.."scentre.lua") -dofile(wea_cmdpath.."scloud.lua") -dofile(wea_cmdpath.."scol.lua") -dofile(wea_cmdpath.."scube.lua") -dofile(wea_cmdpath.."sfactor.lua") -dofile(wea_cmdpath.."smake.lua") -dofile(wea_cmdpath.."spop.lua") -dofile(wea_cmdpath.."spush.lua") -dofile(wea_cmdpath.."srect.lua") -dofile(wea_cmdpath.."sshift.lua") -dofile(wea_cmdpath.."sstack.lua") - -dofile(wea_cmdpath.."unmark.lua") -dofile(wea_cmdpath.."mark.lua") -dofile(wea_cmdpath.."pos1-2.lua") -dofile(wea_cmdpath.."reset.lua") - --- Aliases -weac.register_alias("sfac", "sfactor") - -weac.register_alias("1", "pos1", true) -- true = override target -weac.register_alias("2", "pos2", true) -- true = override target +-- ███████ ███████ ██ ███████ ██████ ████████ ██████ ██████ ███████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ █████ ██ █████ ██ ██ ██ ██ ██████ ███████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ███████ ███████ ███████ ██████ ██ ██████ ██ ██ ███████ + +-- Chat commands that operate on selections. + +local wea_cmdpath = worldeditadditions_commands.modpath .. "/commands/selectors/" +local weac = worldeditadditions_core + +dofile(wea_cmdpath.."scentre.lua") +dofile(wea_cmdpath.."scloud.lua") +dofile(wea_cmdpath.."sgrow.lua") +dofile(wea_cmdpath.."smake.lua") +dofile(wea_cmdpath.."spop.lua") +dofile(wea_cmdpath.."spush.lua") +dofile(wea_cmdpath.."srel.lua") +dofile(wea_cmdpath.."sshift.lua") +dofile(wea_cmdpath.."sshrink.lua") +dofile(wea_cmdpath.."sstack.lua") + +--- DEPRECATED --- +dofile(wea_cmdpath.."scol.lua") +dofile(wea_cmdpath.."scube.lua") +dofile(wea_cmdpath.."srect.lua") +dofile(wea_cmdpath.."sfactor.lua") +--- END DEPRECATED --- + +dofile(wea_cmdpath.."unmark.lua") +dofile(wea_cmdpath.."mark.lua") +dofile(wea_cmdpath.."pos1-2.lua") +dofile(wea_cmdpath.."reset.lua") + +-- Aliases +weac.register_alias("sfac", "sfactor") + +weac.register_alias("sgrow", "expand", true) -- true = override target +weac.register_alias("sgrow", "outset", true) -- true = override target +weac.register_alias("sshrink", "contract", true) -- true = override target +weac.register_alias("sshrink", "inset", true) -- true = override target + +weac.register_alias("sshift", "shift", true) -- true = override target + +weac.register_alias("1", "pos1", true) -- true = override target +weac.register_alias("2", "pos2", true) -- true = override target diff --git a/worldeditadditions_commands/commands/selectors/scentre.lua b/worldeditadditions_commands/commands/selectors/scentre.lua index af589ff..ec8c31e 100644 --- a/worldeditadditions_commands/commands/selectors/scentre.lua +++ b/worldeditadditions_commands/commands/selectors/scentre.lua @@ -1,35 +1,33 @@ -local wea_c = worldeditadditions_core -local Vector3 = wea_c.Vector3 - --- ███████ ██████ ███████ ███ ██ ████████ ███████ ██████ --- ██ ██ ██ ████ ██ ██ ██ ██ ██ --- ███████ ██ █████ ██ ██ ██ ██ █████ ██████ --- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ --- ███████ ██████ ███████ ██ ████ ██ ███████ ██ ██ -worldeditadditions_core.register_command("scentre", { - params = "", - description = "Set WorldEdit region positions 1 and 2 to the centre of the current selection.", - privs = {worldedit=true}, - require_pos = 2, - parse = function(params_text) - return true - end, - func = function(name) - local mean = Vector3.mean( - Vector3.clone(worldedit.pos1[name]), - Vector3.clone(worldedit.pos2[name]) - ) - local pos1, pos2 = Vector3.clone(mean), Vector3.clone(mean) - - pos1 = pos1:floor() - pos2 = pos2:ceil() - - worldedit.pos1[name], worldedit.pos2[name] = pos1, pos2 - worldedit.mark_pos1(name) - worldedit.mark_pos2(name) - - return true, "position 1 set to "..pos1..", position 2 set to "..pos2 - end, -}) - --- lua print(vecs.mean.x..", "..vecs.mean.y..", "..vecs.mean.z) +local wea_c = worldeditadditions_core +local Vector3 = wea_c.Vector3 + +-- ███████ ██████ ███████ ███ ██ ████████ ███████ ██████ +-- ██ ██ ██ ████ ██ ██ ██ ██ ██ +-- ███████ ██ █████ ██ ██ ██ ██ █████ ██████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██████ ███████ ██ ████ ██ ███████ ██ ██ +worldeditadditions_core.register_command("scentre", { + params = "", + description = "Set WorldEdit region positions 1 and 2 to the centre of the current selection.", + privs = {worldedit=true}, + require_pos = 2, + parse = function(params_text) + return true + end, + func = function(name) + local mean = Vector3.mean( + Vector3.clone(wea_c.pos.get(name, 1)), + Vector3.clone(wea_c.pos.get(name, 2)) + ) + local pos1, pos2 = Vector3.clone(mean), Vector3.clone(mean) + + pos1 = pos1:floor() + pos2 = pos2:ceil() + + wea_c.pos.set_all(name, {pos1, pos2}) + + return true, "Position 1 to "..pos1..", Position 2 to "..pos2 + end, +}) + +-- lua print(vecs.mean.x..", "..vecs.mean.y..", "..vecs.mean.z) diff --git a/worldeditadditions_commands/commands/selectors/scol.lua b/worldeditadditions_commands/commands/selectors/scol.lua index 1ada5ac..bc57bfc 100644 --- a/worldeditadditions_commands/commands/selectors/scol.lua +++ b/worldeditadditions_commands/commands/selectors/scol.lua @@ -7,37 +7,15 @@ local Vector3 = wea_c.Vector3 -- ██ ██ ██ ██ ██ -- ███████ ██████ ██████ ███████ worldeditadditions_core.register_command("scol", { - params = "[] ", - description = "Set WorldEdit region position 2 at a set distance along 1 axis.", - privs = {worldedit=true}, + params = "None", + description = "DEPRECATED: please use //srel instead.", + privs = { worldedit = true }, require_pos = 1, parse = function(params_text) - local vec, tmp = Vector3.new(0, 0, 0), {} - local find = wea_c.split(params_text, "%s", false) - local ax1, sn1, len = (tostring(find[1]):match('[xyz]') or "g"):sub(1,1), wea_c.getsign(find[1]), find[table.maxn(find)] - - tmp.len = tonumber(len) - -- If len == nil cancel the operation - if not tmp.len then return false, "No length specified." end - -- If ax1 is bad send "get" order - if ax1 == "g" then tmp.get = true - else vec[ax1] = sn1 * tmp.len end - - return true, vec, tmp - -- tmp carries: - -- The length (len) arguement to the main function for use if "get" is invoked there - -- The bool value "get" to tell the main function if it needs to populate missing information in vec + return params_text end, - func = function(name, vec, tmp) - if tmp.get then - local ax, dir = wea_c.player_axis2d(name) - vec[ax] = tmp.len * dir - end - - local pos2 = vec + Vector3.clone(worldedit.pos1[name]) - worldedit.pos2[name] = pos2 - worldedit.mark_pos2(name) - return true, "position 2 set to "..pos2 + func = function(name, paramtext) + return false, "DEPRECATED: please use //srel instead..." end, }) diff --git a/worldeditadditions_commands/commands/selectors/scube.lua b/worldeditadditions_commands/commands/selectors/scube.lua index 0c7df3e..f65ab02 100644 --- a/worldeditadditions_commands/commands/selectors/scube.lua +++ b/worldeditadditions_commands/commands/selectors/scube.lua @@ -7,48 +7,15 @@ local Vector3 = wea_c.Vector3 -- ██ ██ ██ ██ ██ ██ ██ -- ███████ ██████ ██████ ██████ ███████ worldeditadditions_core.register_command("scube", { - params = "[ [ []]] ", - description = "Set WorldEdit region position 2 at a set distance along 3 axes.", + params = "None", + description = "DEPRECATED: please use //srel instead.", privs = { worldedit = true }, require_pos = 1, parse = function(params_text) - local vec, tmp = Vector3.new(0, 0, 0), {} - local find = wea_c.split(params_text, "%s", false) - local ax1, ax2, ax3 = (tostring(find[1]):match('[xyz]') or "g"):sub(1,1), (tostring(find[2]):match('[xyz]') or "g"):sub(1,1), - (tostring(find[3]):match('[xyz]') or "g"):sub(1,1) - local sn1, sn2, sn3, len = wea_c.getsign(find[1]), wea_c.getsign(find[2]), wea_c.getsign(find[3]), find[table.maxn(find)] - - tmp.len = tonumber(len) - -- If len is nill cancel the operation - if not tmp.len then return false, "No length specified." end - -- If axis is bad send "get" order - if ax1 == "g" then tmp.get = true - else vec[ax1] = sn1 * tmp.len end - if ax2 == "g" then tmp.get = true - else vec[ax2] = sn2 * tmp.len end - if ax3 == "g" then tmp.get = true - else vec[ax3] = sn3 * tmp.len end - - tmp.axes = ax1..","..ax2..","..ax3 - return true, vec, tmp - -- tmp carries: - -- The length (len) arguement to the main function for use if "get" is invoked there - -- The bool value "get" to tell the main function if it needs to populate missing information in vec - -- The string "axes" to tell the main function what axes are and/or need to be populated if "get" is invoked + return params_text end, - func = function(name, vec, tmp) - if tmp.get then - local ax, dir = wea_c.player_axis2d(name) - local _, left, sn = wea_c.axis_left(ax,dir) - if not tmp.axes:find("x") then vec.x = tmp.len * (ax == "x" and dir or sn) end - if not tmp.axes:find("z") then vec.z = tmp.len * (ax == "z" and dir or sn) end - if not tmp.axes:find("y") then vec.y = tmp.len end - end - - local pos2 = vec + Vector3.clone(worldedit.pos1[name]) - worldedit.pos2[name] = pos2 - worldedit.mark_pos2(name) - return true, "position 2 set to "..pos2 + func = function(name, paramtext) + return false, "DEPRECATED: please use //srel instead..." end, }) diff --git a/worldeditadditions_commands/commands/selectors/sfactor.lua b/worldeditadditions_commands/commands/selectors/sfactor.lua index 4c86408..ef78473 100644 --- a/worldeditadditions_commands/commands/selectors/sfactor.lua +++ b/worldeditadditions_commands/commands/selectors/sfactor.lua @@ -1,87 +1,22 @@ -local wea = worldeditadditions -local wea_c = worldeditadditions_core -local Vector3 = wea_c.Vector3 - - --- ███████ ███████ █████ ██████ ████████ ██████ ██████ --- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ --- ███████ █████ ███████ ██ ██ ██ ██ ██████ --- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ --- ███████ ██ ██ ██ ██████ ██ ██████ ██ ██ -worldeditadditions_core.register_command("sfactor", { - params = " []", - description = "Make the length of one or more target axes of the current selection to be multiple(s) of .", - privs = { worldedit = true }, - require_pos = 2, - parse = function(params_text) - local parts = wea_c.split(params_text, "%s+", false) - - if #parts < 2 then - return false, "Error: Not enough arguments. Expected \" []\"." - end - local mode, fac, targ = wea_c.table.unpack(parts) - local modeSet = wea_c.table.makeset {"grow", "shrink", "avg"} - - -- Mode parsing - if mode == "average" then -- If mode is average set to avg - mode = "avg" - elseif not modeSet[mode] then -- If mode is invalid throw error - return false, "Error: Invalid \""..mode.."\". Expected \"grow\", \"shrink\", or \"average\"/\"avg\"." - end - - -- Factor parsing - local factest = tonumber(fac) - if not factest then - return false, "Error: Invalid \""..fac.."\". Expected a number." - elseif factest < 2 then - return false, "Error: is too low. Expected a number equal to or greater than 2." - else - fac = math.floor(factest+0.5) - end - - -- Target parsing - if not targ then -- If no target set to default (xz) - targ = "xz" - elseif targ:match("[xyz]+") then -- ensure correct target syntax - targ = table.concat(wea_c.tochars(targ:match("[xyz]+"),true,true)) - else - return false, "Error: Invalid \""..targ.."\". Expected \"x\" and or \"y\" and or \"z\"." - end - - return true, mode, fac, targ - end, - func = function(name, mode, fac, targ) - local pos1, pos2 = Vector3.clone(worldedit.pos1[name]), Vector3.clone(worldedit.pos2[name]) - local delta = pos2 - pos1 -- local delta equation: Vd(a) = V2(a) - V1(a) - local _tl = #targ -- Get targ length as a variable incase mode is "average"/"avg" - local targ = wea_c.tocharset(targ) -- Break up targ string into set table - local _m = 0 -- _m is the container to hold the average of the axes in targ - - -- set _m to the max, min or mean of the target axes depending on mode (_tl is the length of targ) or base if it exists - if mode == "avg" then - for k,v in pairs(targ) do _m = _m + math.abs(delta[k]) end - _m = _m / _tl - end - - -- Equation: round(delta[] / factor) * factor - local eval = function(int,fac_inner) - local tmp, abs, neg = int / fac_inner, math.abs(int), int < 0 - - if mode == "avg" then - if int > _m then int = math.floor(abs / fac_inner) * fac_inner - else int = math.ceil(abs / fac_inner) * fac_inner end - elseif mode == "shrink" then int = math.floor(abs / fac_inner) * fac_inner - else int = math.ceil(abs / fac_inner) * fac_inner end - - if int < fac_inner then int = fac_inner end -- Ensure selection doesn't collapse to 0 - if neg then int = int * -1 end -- Ensure correct facing direction - return int - end - - for k,v in pairs(targ) do delta[k] = eval(delta[k],fac) end - - worldedit.pos2[name] = pos1 + delta - worldedit.mark_pos2(name) - return true, "position 2 set to "..pos2 - end -}) +local wea = worldeditadditions +local wea_c = worldeditadditions_core +local Vector3 = wea_c.Vector3 + + +-- ███████ ███████ █████ ██████ ████████ ██████ ██████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ █████ ███████ ██ ██ ██ ██ ██████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██ ██ ██ ██████ ██ ██████ ██ ██ +worldeditadditions_core.register_command("sfactor", { + params = "None", + description = "DEPRECATED: please use //grow or //shrink instead.", + + privs = { worldedit = true }, + parse = function(params_text) + return params_text + end, + func = function(name, paramtext) + return false, "DEPRECATED: please use //grow or //shrink instead..." + end +}) diff --git a/worldeditadditions_commands/commands/selectors/sgrow.lua b/worldeditadditions_commands/commands/selectors/sgrow.lua new file mode 100644 index 0000000..9ede412 --- /dev/null +++ b/worldeditadditions_commands/commands/selectors/sgrow.lua @@ -0,0 +1,42 @@ +-- local wea = worldeditadditions +local wea_c = worldeditadditions_core +local Vector3 = wea_c.Vector3 + + +-- ███████ ██████ ██████ ██████ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██ ███ ██████ ██ ██ ██ █ ██ +-- ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ +-- ███████ ██████ ██ ██ ██████ ███ ███ + + +worldeditadditions_core.register_command("sgrow", { + params = "", + description = "Grow selection region", + privs = { worldedit = true }, + require_pos = 0, + parse = function(params_text) + local ret = wea_c.split(params_text) + if #ret < 1 then return false, "SGROW: No params found!" + else return true, ret end + end, + func = function(name, params_text) + local facing = wea_c.player_dir(name) + local min, max = wea_c.parse.directions(params_text, facing) + if not min then return false, max end + + local pos1 = wea_c.pos.get(name, 1) + local pos2 = wea_c.pos.get(name, 2) + + if not pos2 then wea_c.pos.set(name, 2, pos1) + else pos1, pos2 = Vector3.sort(pos1, pos2) end + + pos1, pos2 = pos1:add(min), pos2:add(max) + + wea_c.pos.set_all(name, {pos1, pos2}) + return true, "Position 1 to "..pos1..", Position 2 to "..pos2 + end, +}) + +-- Tests +-- //srel front 5 left 3 y 2 diff --git a/worldeditadditions_commands/commands/selectors/smake.lua b/worldeditadditions_commands/commands/selectors/smake.lua index 91ba3e0..78309bb 100644 --- a/worldeditadditions_commands/commands/selectors/smake.lua +++ b/worldeditadditions_commands/commands/selectors/smake.lua @@ -1,133 +1,131 @@ -local wea = worldeditadditions -local wea_c = worldeditadditions_core -local Vector3 = wea_c.Vector3 - - --- ███████ ███ ███ █████ ██ ██ ███████ --- ██ ████ ████ ██ ██ ██ ██ ██ --- ███████ ██ ████ ██ ███████ █████ █████ --- ██ ██ ██ ██ ██ ██ ██ ██ ██ --- ███████ ██ ██ ██ ██ ██ ██ ███████ -worldeditadditions_core.register_command("smake", { - params = " [ []]", - description = "Make one or more axes of the current selection odd, even, or equal to another.", - privs = { worldedit = true }, - require_pos = 2, - parse = function(params_text) - -- Split params_text, check for missing arguments and fill in empty spots - local parts = wea_c.split(params_text, "%s+", false) - if #parts < 2 then - return false, "Error: Not enough arguments. Expected \" [ []]\"." - else - for i=3,4 do if not parts[i] then parts[i] = false end end - end - - -- Initialize local variables and sets - local oper, mode, targ, base = wea_c.table.unpack(parts) - local operSet, modeSet = wea_c.table.makeset {"equal", "odd", "even"}, wea_c.table.makeset {"grow", "shrink", "avg"} - - -- Main Logic - -- Check base if base is present and if so valid. - if base then - if base:match("[xyz]") then -- ensure correct base syntax - base = base:match("[xyz]") - else - return false, "Error: Invalid base \""..base.."\". Expected \"x\", \"y\" or \"z\"." - end - end - - -- Resolve target then mode (in that order incase mode is target). - if not targ then -- If no target set to default (xz) - targ = "xz" - elseif targ:match("[xyz]+") then -- ensure correct target syntax - targ = table.concat(wea_c.tochars(targ:match("[xyz]+"),true,true)) - else - return false, "Error: Invalid \""..targ.."\". Expected \"x\" and or \"y\" and or \"z\"." - end - - if mode == "average" then -- If mode is average set to avg - mode = "avg" - elseif mode:match("[xyz]+") then -- If target is actually base set vars to correct values. - base, targ, mode = targ:sub(1,1), table.concat(wea_c.tochars(mode:match("[xyz]+"),true,true)), false - elseif not modeSet[mode] and not base then -- If mode is invalid and base isn't present throw error - return false, "Error: Invalid \""..mode.."\". Expected \"grow\", \"shrink\", or \"average\"/\"avg\"." - end - - if base then - if oper ~= "equal" then base = false -- If operation isn't equalize we don't need - elseif targ:match(base) then -- Else check that base is not in target and return error if it is - return false, "Error: ("..base..") cannot be included in ("..targ..")." - end - end - - -- Check if operator is valid - if not operSet[oper] then - return false, "Error: Invalid operator \""..oper.."\". Expected \"odd\", \"even\" or \"equal\"." - end - - return true, oper, mode, targ, base - end, - func = function(name, oper, mode, targ, base) - local pos1, pos2 = Vector3.clone(worldedit.pos1[name]), Vector3.clone(worldedit.pos2[name]) - local eval -- Declare eval placeholder function to edit later - - local delta = pos2 - pos1 -- local delta equation: Vd(a) = V2(a) - V1(a) - local _tl = #targ -- Get targ length as a variable incase mode is "average"/"avg" - local targ = wea_c.tocharset(targ) -- Break up targ string into set table - local _m = 0 -- _m is the container to hold the max, min or average (depending on the mode) of the axes in targ - - -- set _m to the max, min or mean of the target axes depending on mode or base if it exists - if base then _m = delta[base] - elseif mode == "avg" then - for k,v in pairs(targ) do _m = _m + math.abs(delta[k]) end - _m = _m / _tl - elseif mode == "grow" then - for k,v in pairs(targ) do if math.abs(delta[k]) > _m then _m = math.abs(delta[k]) end end - else - -- Take output of next(targ), put it in a table, wrap the table in brackets to force evlauation so that - -- we can call the first element of that table to serve as the key for a call to delta. - _m = delta[({next(targ)})[1]] - for k,v in pairs(targ) do if math.abs(delta[k]) < _m then _m = math.abs(delta[k]) end end - end - - if oper == "even" then - eval = function(int) - local tmp, abs, neg = int / 2, math.abs(int), int < 0 - if math.floor(tmp) ~= tmp then - if mode == "avg" then - if int > _m then int = abs - 1 - else int = abs + 1 end - elseif mode == "shrink" and abs > 0 then int = abs - 1 - else int = abs + 1 end - end - if neg then int = int * -1 end -- Ensure correct facing direction - return int - end - elseif oper == "odd" then - eval = function(int) - local tmp, abs, neg = int / 2, math.abs(int), int < 0 - if math.floor(tmp) == tmp then - if mode == "avg" then - if int > _m then int = abs - 1 - else int = abs + 1 end - elseif mode == "shrink" and abs > 0 then int = abs - 1 - else int = abs + 1 end - end - if neg then int = int * -1 end - return int - end - else -- Case: oper == "equal" - eval = function(int) - -- Bug: shrink sets pos2 to pos1 - if int < 0 then return _m * -1 - else return _m end - end - end - - for k,v in pairs(targ) do delta[k] = eval(delta[k]) end - - worldedit.pos2[name] = pos1 + delta - worldedit.mark_pos2(name) - return true, "position 2 set to "..pos2 - end -}) +local wea_c = worldeditadditions_core +local Vector3 = wea_c.Vector3 + + +-- ███████ ███ ███ █████ ██ ██ ███████ +-- ██ ████ ████ ██ ██ ██ ██ ██ +-- ███████ ██ ████ ██ ███████ █████ █████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ██ ██ ██ ██ ██ ██ ███████ +worldeditadditions_core.register_command("smake", { + params = " [ []]", + description = "Make one or more axes of the current selection odd, even, or equal to another.", + privs = { worldedit = true }, + require_pos = 2, + parse = function(params_text) + -- Split params_text, check for missing arguments and fill in empty spots + local parts = wea_c.split(params_text, "%s+", false) + if #parts < 2 then + return false, "Error: Not enough arguments. Expected \" [ []]\"." + else + for i=3,4 do if not parts[i] then parts[i] = false end end + end + + -- Initialize local variables and sets + local oper, mode, targ, base = wea_c.table.unpack(parts) + local operSet, modeSet = wea_c.table.makeset {"equal", "odd", "even"}, wea_c.table.makeset {"grow", "shrink", "avg"} + + -- Main Logic + -- Check base if base is present and if so valid. + if base then + if base:match("[xyz]") then -- ensure correct base syntax + base = base:match("[xyz]") + else + return false, "Error: Invalid base \""..base.."\". Expected \"x\", \"y\" or \"z\"." + end + end + + -- Resolve target then mode (in that order incase mode is target). + if not targ then -- If no target set to default (xz) + targ = "xz" + elseif targ:match("[xyz]+") then -- ensure correct target syntax + targ = table.concat(wea_c.tochars(targ:match("[xyz]+"),true,true)) + else + return false, "Error: Invalid \""..targ.."\". Expected \"x\" and or \"y\" and or \"z\"." + end + + if mode == "average" then -- If mode is average set to avg + mode = "avg" + elseif mode:match("[xyz]+") then -- If target is actually base set vars to correct values. + base, targ, mode = targ:sub(1,1), table.concat(wea_c.tochars(mode:match("[xyz]+"),true,true)), false + elseif not modeSet[mode] and not base then -- If mode is invalid and base isn't present throw error + return false, "Error: Invalid \""..mode.."\". Expected \"grow\", \"shrink\", or \"average\"/\"avg\"." + end + + if base then + if oper ~= "equal" then base = false -- If operation isn't equalize we don't need + elseif targ:match(base) then -- Else check that base is not in target and return error if it is + return false, "Error: ("..base..") cannot be included in ("..targ..")." + end + end + + -- Check if operator is valid + if not operSet[oper] then + return false, "Error: Invalid operator \""..oper.."\". Expected \"odd\", \"even\" or \"equal\"." + end + + return true, oper, mode, targ, base + end, + func = function(name, oper, mode, targ, base) + local pos1, pos2 = Vector3.clone(wea_c.pos.get(name, 1)), Vector3.clone(wea_c.pos.get(name, 2)) + local eval -- Declare eval placeholder function to edit later + + local delta = pos2 - pos1 -- local delta equation: Vd(a) = V2(a) - V1(a) + local _tl = #targ -- Get targ length as a variable incase mode is "average"/"avg" + local targ = wea_c.tocharset(targ) -- Break up targ string into set table + local _m = 0 -- _m is the container to hold the max, min or average (depending on the mode) of the axes in targ + + -- set _m to the max, min or mean of the target axes depending on mode or base if it exists + if base then _m = delta[base] + elseif mode == "avg" then + for k,v in pairs(targ) do _m = _m + math.abs(delta[k]) end + _m = _m / _tl + elseif mode == "grow" then + for k,v in pairs(targ) do if math.abs(delta[k]) > _m then _m = math.abs(delta[k]) end end + else + -- Take output of next(targ), put it in a table, wrap the table in brackets to force evlauation so that + -- we can call the first element of that table to serve as the key for a call to delta. + _m = delta[({next(targ)})[1]] + for k,v in pairs(targ) do if math.abs(delta[k]) < _m then _m = math.abs(delta[k]) end end + end + + if oper == "even" then + eval = function(int) + local tmp, abs, neg = int / 2, math.abs(int), int < 0 + if math.floor(tmp) ~= tmp then + if mode == "avg" then + if int > _m then int = abs - 1 + else int = abs + 1 end + elseif mode == "shrink" and abs > 0 then int = abs - 1 + else int = abs + 1 end + end + if neg then int = int * -1 end -- Ensure correct facing direction + return int + end + elseif oper == "odd" then + eval = function(int) + local tmp, abs, neg = int / 2, math.abs(int), int < 0 + if math.floor(tmp) == tmp then + if mode == "avg" then + if int > _m then int = abs - 1 + else int = abs + 1 end + elseif mode == "shrink" and abs > 0 then int = abs - 1 + else int = abs + 1 end + end + if neg then int = int * -1 end + return int + end + else -- Case: oper == "equal" + eval = function(int) + -- Bug: shrink sets pos2 to pos1 + if int < 0 then return _m * -1 + else return _m end + end + end + + for k,_ in pairs(targ) do delta[k] = eval(delta[k]) end + + wea_c.pos.set(name, 2, pos1 + delta) + return true, "Position 2 to "..pos2 + end +}) diff --git a/worldeditadditions_commands/commands/selectors/srect.lua b/worldeditadditions_commands/commands/selectors/srect.lua index b0cb190..fcb0f8c 100644 --- a/worldeditadditions_commands/commands/selectors/srect.lua +++ b/worldeditadditions_commands/commands/selectors/srect.lua @@ -1,4 +1,3 @@ -local wea = worldeditadditions local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 @@ -8,43 +7,15 @@ local Vector3 = wea_c.Vector3 -- ██ ██ ██ ██ ██ ██ -- ███████ ██ ██ ███████ ██████ ██ worldeditadditions_core.register_command("srect", { - params = "[ []] ", - description = "Set WorldEdit region position 2 at a set distance along 2 axes.", + params = "None", + description = "DEPRECATED: please use //srel instead.", privs = { worldedit = true }, require_pos = 1, parse = function(params_text) - local vec, tmp = Vector3.new(0, 0, 0), {} - local find = wea_c.split(params_text, "%s", false) - local ax1, ax2 = (tostring(find[1]):match('[xyz]') or "g"):sub(1,1), (tostring(find[2]):match('[xyz]') or "g"):sub(1,1) - local sn1, sn2, len = wea_c.getsign(find[1]), wea_c.getsign(find[2]), find[table.maxn(find)] - - tmp.len = tonumber(len) - -- If len == nill cancel the operation - if not tmp.len then return false, "No length specified." end - -- If axis is bad send "get" order - if ax1 == "g" then tmp.get = true - else vec[ax1] = sn1 * tmp.len end - if ax2 == "g" then tmp.get = true - else vec[ax2] = sn2 * tmp.len end - - tmp.axes = ax1..","..ax2 - return true, vec, tmp - -- tmp carries: - -- The length (len) arguement to the main function for use if "get" is invoked there - -- The bool value "get" to tell the main function if it needs to populate missing information in vec - -- The string "axes" to tell the main function what axes are and/or need to be populated if "get" is invoked + return params_text end, - func = function(name, vec, tmp) - if tmp.get then - local ax, dir = wea_c.player_axis2d(name) - if not tmp.axes:find("[xz]") then vec[ax] = tmp.len * dir end - if not tmp.axes:find("y") then vec.y = tmp.len end - end - - local p2 = vec + Vector3.clone(worldedit.pos1[name]) - worldedit.pos2[name] = p2 - worldedit.mark_pos2(name) - return true, "position 2 set to "..p2 + func = function(name, paramtext) + return false, "DEPRECATED: please use //srel instead..." end, }) diff --git a/worldeditadditions_commands/commands/selectors/srel.lua b/worldeditadditions_commands/commands/selectors/srel.lua index 75d30d3..b0af141 100644 --- a/worldeditadditions_commands/commands/selectors/srel.lua +++ b/worldeditadditions_commands/commands/selectors/srel.lua @@ -1,58 +1,37 @@ -local wea = worldeditadditions -local wea_c = worldeditadditions_core -local Vector3 = wea_c.Vector3 - - --- ███████ ██████ ███████ ██ --- ██ ██ ██ ██ ██ --- ███████ ██████ █████ ██ --- ██ ██ ██ ██ ██ --- ███████ ██ ██ ███████ ███████ -local function parse_with_name(name,args) - local vec, tmp = Vector3.new(0, 0, 0), {} - local find, _, i = {}, 0, 0 - repeat - _, i, tmp.proc = args:find("([%l%s+-]+%d+)%s*", i) - if tmp.proc:match("[xyz]") then - tmp.ax = tmp.proc:match("[xyz]") - tmp.dir = tonumber(tmp.proc:match("[+-]?%d+")) * (tmp.proc:match("-%l+") and -1 or 1) - else - tmp.ax, _ = wea_c.dir_to_xyz(name, tmp.proc:match("%l+")) - if not tmp.ax then return false, _ end - tmp.dir = tonumber(tmp.proc:match("[+-]?%d+")) * (tmp.proc:match("-%l+") and -1 or 1) * _ - end - vec[tmp.ax] = tmp.dir - until not args:find("([%l%s+-]+%d+)%s*", i) - return true, vec -end -worldeditadditions_core.register_command("srel", { - params = " [ [ ]]", - description = "Set WorldEdit region position 2 at set distances along 3 axes.", - privs = { worldedit = true }, - require_pos = 0, - parse = function(params_text) - if params_text:match("([%l%s+-]+%d+)") then return true, params_text - else return false, "No acceptable params found" end - end, - func = function(name, params_text) - local ret = "" - local _, vec = parse_with_name(name,params_text) - if not _ then return false, vec end - - if not worldedit.pos1[name] then - local pos = wea_c.player_vector(name) + Vector3.new(0.5, -0.5, 0.5) - pos = pos:floor() - worldedit.pos1[name] = pos - worldedit.mark_pos1(name) - ret = "position 1 set to "..pos..", " - end - - local p2 = vec + Vector3.clone(worldedit.pos1[name]) - worldedit.pos2[name] = p2 - worldedit.mark_pos2(name) - return true, ret.."position 2 set to "..p2 - end, -}) - --- Tests --- //srel front 5 left 3 y 2 +-- local wea = worldeditadditions +local wea_c = worldeditadditions_core +local Vector3 = wea_c.Vector3 + + +-- ███████ ██████ ███████ ██ +-- ██ ██ ██ ██ ██ +-- ███████ ██████ █████ ██ +-- ██ ██ ██ ██ ██ +-- ███████ ██ ██ ███████ ███████ + + +worldeditadditions_core.register_command("srel", { + params = "", + description = "Set WorldEdit region position 2 relative to position 1 and player facing.", + privs = { worldedit = true }, + require_pos = 0, + parse = function(params_text) + local ret = wea_c.split(params_text) + if #ret < 1 then return false, "SREL: No params found!" + else return true, ret end + end, + func = function(name, params_text) + local facing = wea_c.player_dir(name) + local vec, err = wea_c.parse.directions(params_text, facing, true) + if not vec then return false, err end + + local pos1 = wea_c.pos.get(name, 1) + local pos2 = pos1:add(vec) + + wea_c.pos.set_all(name, {pos1, pos2}) + return true, "Position 1 to "..pos1..", Position 2 to "..pos2 + end, +}) + +-- Tests +-- //srel front 5 left 3 y 2 diff --git a/worldeditadditions_commands/commands/selectors/sshift.lua b/worldeditadditions_commands/commands/selectors/sshift.lua index 5ce1b54..c115a65 100644 --- a/worldeditadditions_commands/commands/selectors/sshift.lua +++ b/worldeditadditions_commands/commands/selectors/sshift.lua @@ -1,4 +1,3 @@ -local wea = worldeditadditions local wea_c = worldeditadditions_core local Vector3 = worldeditadditions.Vector3 @@ -8,46 +7,26 @@ local Vector3 = worldeditadditions.Vector3 -- ██ ██ ██ ██ ██ ██ ██ -- ███████ ███████ ██ ██ ██ ██ ██ -local function parse_with_name(name,args) - local vec, tmp = Vector3.new(0, 0, 0), {} - local find, _, i = {}, 0, 0 - repeat - _, i, tmp.proc = args:find("([%l%s+-]+%d+)%s*", i) - if tmp.proc:match("[xyz]") then - tmp.ax = tmp.proc:match("[xyz]") - tmp.dir = tonumber(tmp.proc:match("[+-]?%d+")) * (tmp.proc:match("-%l+") and -1 or 1) - else - tmp.ax, _ = wea_c.dir_to_xyz(name, tmp.proc:match("%l+")) - if not tmp.ax then return false, _ end - tmp.dir = tonumber(tmp.proc:match("[+-]?%d+")) * (tmp.proc:match("-%l+") and -1 or 1) * _ - end - vec[tmp.ax] = tmp.dir - until not args:find("([%l%s+-]+%d+)%s*", i) - return true, vec -end - worldeditadditions_core.register_command("sshift", { - params = " [ [ ]]", + params = "", description = "Shift the WorldEdit region in 3 dimensions.", privs = { worldedit = true }, require_pos = 2, parse = function(params_text) - if params_text:match("([%l%s+-]+%d+)") then return true, params_text - else return false, "No acceptable params found" end + local ret = wea_c.split(params_text) + if #ret < 1 then return false, "Error: No params found!" + else return true, ret end end, func = function(name, params_text) - local _, vec = parse_with_name(name,params_text) - if not _ then return false, vec end + local facing = wea_c.player_dir(name) + local vec, err = wea_c.parse.directions(params_text, facing, true) + if not vec then return false, err end - local pos1 = vec:add(worldedit.pos1[name]) - worldedit.pos1[name] = pos1 - worldedit.mark_pos1(name) + local pos1 = vec:add(wea_c.pos.get(name, 1)) + local pos2 = vec:add(wea_c.pos.get(name, 2)) - local pos2 = vec:add(worldedit.pos2[name]) - worldedit.pos2[name] = pos2 - worldedit.mark_pos2(name) - - return true, "Region shifted by " .. (vec.x + vec.y + vec.z) .. " nodes." + wea_c.pos.set_all(name, {pos1, pos2}) + return true, "Position 1 to "..pos1..", Position 2 to "..pos2 end, }) diff --git a/worldeditadditions_commands/commands/selectors/sshrink.lua b/worldeditadditions_commands/commands/selectors/sshrink.lua new file mode 100644 index 0000000..e46ec67 --- /dev/null +++ b/worldeditadditions_commands/commands/selectors/sshrink.lua @@ -0,0 +1,42 @@ +-- local wea = worldeditadditions +local wea_c = worldeditadditions_core +local Vector3 = wea_c.Vector3 + + +-- ███████ ███████ ██ ██ ██████ ██ ███ ██ ██ ██ +-- ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ +-- ███████ ███████ ███████ ██████ ██ ██ ██ ██ █████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ███████ ███████ ██ ██ ██ ██ ██ ██ ████ ██ ██ + + +worldeditadditions_core.register_command("sshrink", { + params = "", + description = "Shrink selection region", + privs = { worldedit = true }, + require_pos = 0, + parse = function(params_text) + local ret = wea_c.split(params_text) + if #ret < 1 then return false, "Error: No params found!" + else return true, ret end + end, + func = function(name, params_text) + local facing = wea_c.player_dir(name) + local min, max = wea_c.parse.directions(params_text, facing) + if not min then return false, max end + + local pos1 = wea_c.pos.get(name, 1) + local pos2 = wea_c.pos.get(name, 2) + + if not pos2 then wea_c.pos.set(name, 2, pos1) + else pos1, pos2 = Vector3.sort(pos1, pos2) end + + pos1, pos2 = pos1:add(max), pos2:add(min) + + wea_c.pos.set_all(name, {pos1, pos2}) + return true, "Position 1 to "..pos1..", Position 2 to "..pos2 + end, +}) + +-- Tests +-- //srel front 5 left 3 y 2 diff --git a/worldeditadditions_commands/commands/uasparse.lua b/worldeditadditions_commands/commands/uasparse.lua new file mode 100644 index 0000000..bf072f4 --- /dev/null +++ b/worldeditadditions_commands/commands/uasparse.lua @@ -0,0 +1,29 @@ +local wea_c = worldeditadditions_core +-- local Vector3 = wea_c.Vector3 + +-- ██ ██ █████ ███████ ██████ █████ ██████ ███████ ███████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██ ██ ███████ ███████ ██████ ███████ ██████ ███████ █████ +-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +-- ██████ ██ ██ ███████ ██ ██ ██ ██ ██ ███████ ███████ + +worldeditadditions_core.register_command("uasparse", { + params = "", + description = "Debug command. Returns min and max vectors for given inputs", + privs = { worldedit = true }, + -- require_pos = 2, + parse = function(params_text) + local ret = wea_c.split(params_text) + if #ret < 1 then return false, "Error: No params found!" + else return true, ret end + end, + func = function(name, params_text) + local facing = wea_c.player_dir(name) + local min, max = wea_c.parse.directions(params_text, facing) + if not min then + return false, max + else + return true, "Min: "..min.." Max: "..max + end + end +}) diff --git a/worldeditadditions_commands/init.lua b/worldeditadditions_commands/init.lua index c9b2095..d0a9273 100644 --- a/worldeditadditions_commands/init.lua +++ b/worldeditadditions_commands/init.lua @@ -41,6 +41,7 @@ dofile(wea_cmd.modpath.."/commands/revolve.lua") dofile(wea_cmd.modpath.."/commands/rotate.lua") dofile(wea_cmd.modpath.."/commands/orient.lua") dofile(wea_cmd.modpath.."/commands/set.lua") +dofile(wea_cmd.modpath.."/commands/uasparse.lua") -- Meta Commands dofile(wea_cmd.modpath .. "/commands/meta/init.lua") diff --git a/worldeditadditions_core/utils/parse/axes_parser.lua b/worldeditadditions_core/utils/parse/axes_parser.lua index 678a050..d966256 100644 --- a/worldeditadditions_core/utils/parse/axes_parser.lua +++ b/worldeditadditions_core/utils/parse/axes_parser.lua @@ -23,7 +23,7 @@ else end ---- Unified Axis Keywords banks +--- Unified Axis Syntax banks local keywords = { -- Compass keywords compass = { @@ -36,7 +36,9 @@ local keywords = { ["w"] = "-x", ["west"] = "-x", ["-w"] = "x", ["-west"] = "x", ["u"] = "y", ["up"] = "y", + ["-u"] = "-y", ["-up"] = "-y", ["d"] = "-y", ["down"] = "-y", + ["-d"] = "y", ["-down"] = "y", }, -- Direction keywords @@ -90,9 +92,9 @@ function parse.num(str) else return false end end ---- Checks if a string is a valid Unified Axis Keyword. (Supports axis clumping) --- @param: str: String: Keyword instance to parse --- @returns: Key Instance: returns keyword type, processed keyword content and signed number (or nil) +--- Checks if a string is a valid Unified Axis Syntax. (Supports axis clumping) +-- @param: str: String: Keyword to parse +-- @returns: keyword type, processed keyword content and signed number (or nil) function parse.keyword(str) if type(str) ~= "string" then return "err", "Error: \""..tostring(str).."\" is not a string.", 404 @@ -135,68 +137,65 @@ end ---- Converts Unified Axis Keyword table into Vector3 instances. +--- Converts Unified Axis Syntax table into Vector3 instances. -- @param: tbl: Table: Keyword table to parse -- @param: facing: Table: Output from worldeditadditions_core.player_dir(name) -- @param: sum: Bool | String | nil: Return a single vector by summing the 2 output vectors together -- @returns: Vector3, [Vector3]: returns min, max Vector3 or sum Vector3 (if @param: sum ~= nil) -- if error: @returns: false, String: error message function parse.keytable(tbl, facing, sum) - local min, max = Vector3.new(), Vector3.new() - local expected = 1 - local tmp = {axes = {}, num = 0, sign = 1, mirror = false} + local min, max, mir= Vector3.new(), Vector3.new(), false + local neg, pos, v0 = Vector3.new(), Vector3.new(), Vector3.new() - --- Processes a number and adds it to the min and max vectors. - -- @param num The number to process. - -- @param axes The axes to apply the number to. - -- @param sign The sign of the number. - local function parseNumber(num, axes, sign) - if axes.rev then parseNumber(num, axes.rev, -sign) end - if num * sign >= 0 then - max = max:add(parse.vectorize(axes, num, sign)) + local function update(num) -- Update "min" and "max" + if num < 0 then + min, max = min:add(pos:mul(num)), max:add(neg:mul(num)) else - min = min:add(parse.vectorize(axes, num, sign)) + min, max = min:add(neg:mul(num)), max:add(pos:mul(num)) + end + neg, pos = v0:clone(), v0:clone() + end + + local function udir(axes, sign) -- Update "neg" and "pos" + if axes.rev then udir(axes.rev, -sign) end + for _, v in ipairs(axes) do + if sign < 0 then neg[v] = -1 + else pos[v] = 1 end end end - for i, v in ipairs(tbl) do + for i,v in ipairs(tbl) do if v:sub(1, 1) == "+" then v = v:sub(2) end - tmp.num = parse.num(v) + local num = parse.num(v) - if expected == 1 then - if tmp.num then - parseNumber(tmp.num, {"x", "y", "z", rev={"x", "y", "z"}}, tmp.sign) - else - local key_type, key_entry, key_sign = parse.keyword(v) + -- If we have a dimension add it to output + -- Else gather direction statements + if num then + -- Check for direction vectors + if neg == v0 and pos == v0 then + neg, pos = v0:add(-1), v0:add(1) + end + update(num) + else + local key_type, key_entry, key_sign = parse.keyword(v) if key_type == "axis" then - tmp.axes = key_entry - tmp.sign = key_sign + udir(key_entry, key_sign) elseif key_type == "dir" then - tmp.axes = {facing[key_entry].axis} - tmp.sign = facing[key_entry].sign * key_sign + udir({facing[key_entry].axis}, + facing[key_entry].sign * key_sign) elseif key_type == "rev" then - tmp.mirror = true + mir = true else return false, key_entry end - - expected = 2 - end - else - if tmp.num then - parseNumber(tmp.num, tmp.axes, tmp.sign) - expected = 1 - else - return false, "Error: Expected number after \""..tostring(tbl[i-1]).."\". Got \""..tostring(v).."\"." - end end end - if tmp.mirror and not sum then + if mir and not sum then max = max:max(min:abs()) min = max:multiply(-1) end @@ -209,6 +208,7 @@ function parse.keytable(tbl, facing, sum) end + return { keyword = parse.keyword, keytable = parse.keytable, diff --git a/worldeditadditions_core/utils/strings/split.lua b/worldeditadditions_core/utils/strings/split.lua index dbdaa74..2436a74 100644 --- a/worldeditadditions_core/utils/strings/split.lua +++ b/worldeditadditions_core/utils/strings/split.lua @@ -1,89 +1,90 @@ --- Licence: GPLv2 (MPL-2.0 is compatible, so we can use this here) --- Source: https://stackoverflow.com/a/43582076/1460422 - --- gsplit: iterate over substrings in a string separated by a pattern --- --- Parameters: --- text (string) - the string to iterate over --- pattern (string) - the separator pattern --- plain (boolean) - if true (or truthy), pattern is interpreted as a plain --- string, not a Lua pattern --- --- Returns: iterator --- --- Usage: --- for substr in gsplit(text, pattern, plain) do --- doSomething(substr) --- end -local function gsplit(text, pattern, plain) - local splitStart, length = 1, #text - return function () - if splitStart then - local sepStart, sepEnd = string.find(text, pattern, splitStart, plain) - local ret - if not sepStart then - ret = string.sub(text, splitStart) - splitStart = nil - elseif sepEnd < sepStart then - -- Empty separator! - ret = string.sub(text, splitStart, sepStart) - if sepStart < length then - splitStart = sepStart + 1 - else - splitStart = nil - end - else - ret = sepStart > splitStart and string.sub(text, splitStart, sepStart - 1) or '' - splitStart = sepEnd + 1 - end - return ret - end - end -end - - ---- Split a string into substrings separated by a pattern. -- Deprecated --- @param text string The string to iterate over --- @param pattern string The separator pattern --- @param plain boolean If true (or truthy), pattern is interpreted as a --- plain string, not a Lua pattern --- @returns table A sequence table containing the substrings -local function dsplit(text, pattern, plain) - local ret = {} - for match in gsplit(text, pattern, plain) do - table.insert(ret, match) - end - return ret -end - ---- Split a string into substrings separated by a pattern. --- @param str string The string to iterate over --- @param dlm string The delimiter (separator) pattern --- @param plain boolean If true (or truthy), pattern is interpreted as a --- plain string, not a Lua pattern --- @returns table A sequence table containing the substrings -local function split(str,dlm,plain) - local pos, ret = 0, {} - local ins, i = str:find(dlm,pos,plain) - -- "if plain" shaves off some time in the while statement - if plain then - while ins do - table.insert(ret,str:sub(pos,ins - 1)) - pos = ins + #dlm - ins = str:find(dlm,pos,true) - end - else - while ins do - table.insert(ret,str:sub(pos,ins - 1)) - pos = i + 1 - ins, i = str:find(dlm,pos) - end - end - -- print(pos..","..#str) - if str:sub(pos,#str) ~= "" then - table.insert(ret,str:sub(pos,#str)) - end - return ret -end - +-- Licence: GPLv2 (MPL-2.0 is compatible, so we can use this here) +-- Source: https://stackoverflow.com/a/43582076/1460422 + +-- gsplit: iterate over substrings in a string separated by a pattern +-- +-- Parameters: +-- text (string) - the string to iterate over +-- pattern (string) - the separator pattern +-- plain (boolean) - if true (or truthy), pattern is interpreted as a plain +-- string, not a Lua pattern +-- +-- Returns: iterator +-- +-- Usage: +-- for substr in gsplit(text, pattern, plain) do +-- doSomething(substr) +-- end +local function gsplit(text, pattern, plain) + local splitStart, length = 1, #text + return function () + if splitStart then + local sepStart, sepEnd = string.find(text, pattern, splitStart, plain) + local ret + if not sepStart then + ret = string.sub(text, splitStart) + splitStart = nil + elseif sepEnd < sepStart then + -- Empty separator! + ret = string.sub(text, splitStart, sepStart) + if sepStart < length then + splitStart = sepStart + 1 + else + splitStart = nil + end + else + ret = sepStart > splitStart and string.sub(text, splitStart, sepStart - 1) or '' + splitStart = sepEnd + 1 + end + return ret + end + end +end + + +--- Split a string into substrings separated by a pattern. -- Deprecated +-- @param text string The string to iterate over +-- @param pattern string The separator pattern +-- @param plain boolean If true (or truthy), pattern is interpreted as a +-- plain string, not a Lua pattern +-- @returns table A sequence table containing the substrings +local function dsplit(text, pattern, plain) + local ret = {} + for match in gsplit(text, pattern, plain) do + table.insert(ret, match) + end + return ret +end + +--- Split a string into substrings separated by a pattern. +-- @param str string The string to iterate over +-- @param dlm="%s+" string The delimiter (separator) pattern. If a falsey value is passed, then the default value is used. +-- @param plain boolean If true (or truthy), pattern is interpreted as a +-- plain string, not a Lua pattern +-- @returns table A sequence table containing the substrings +local function split(str,dlm,plain) + if not dlm then dlm = "%s+" end + local pos, ret = 0, {} + local ins, i = str:find(dlm,pos,plain) + -- "if plain" shaves off some time in the while statement + if plain then + while ins do + table.insert(ret,str:sub(pos,ins - 1)) + pos = ins + #dlm + ins = str:find(dlm,pos,true) + end + else + while ins do + table.insert(ret,str:sub(pos,ins - 1)) + pos = i + 1 + ins, i = str:find(dlm,pos) + end + end + -- print(pos..","..#str) + if str:sub(pos,#str) ~= "" then + table.insert(ret,str:sub(pos,#str)) + end + return ret +end + return split \ No newline at end of file