mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-12-22 19:45:02 +00:00
commit
f569358229
33 changed files with 960 additions and 158 deletions
|
@ -7,6 +7,9 @@ Note to self: See the bottom of this file for the release template text.
|
|||
- Add `//sfactor` (_selection factor_) - Selection Tools by @VorTechnix are finished for now.
|
||||
- Add `//mface` (_measure facing_), `//midpos` (_measure middle position_), `//msize` (_measure size_), `//mtrig` (_measure trigonometry_) - Measuring Tools implemented by @VorTechnix.
|
||||
- Add `//airapply` for applying commands only to air nodes in the defined region
|
||||
- Add `//wcorner` (_wireframe corners_), `//wbox` (_wireframe box_), `//compass` (_wireframe compass_) - Wireframes implemented by @VorTechnix.
|
||||
- Add `//for` for executing commands while changing their arguments - Implemented by @VorTechnix.
|
||||
- Add `//sshift` (_selection shift_) - WorldEdit cuboid manipulator replacements implemented by @VorTechnix.
|
||||
- Add `//noise2d` for perturbing terrain with multiple different noise functions
|
||||
- Add `//noiseapply2d` for running commands on columns where a noise value is over a threshold
|
||||
- Add `//ellipsoid2` which creates an ellipsoid that fills the defined region
|
||||
|
|
|
@ -193,7 +193,32 @@ Floods all connected nodes of the same type starting at _pos1_ with `<replace_no
|
|||
```
|
||||
|
||||
|
||||
### `//scale <axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>`
|
||||
## `//wbox <replace_node>`
|
||||
Sets the edges of the current selection to `<replace_node>`to create an outline of a rectangular prism. Useful for roughing in walls.
|
||||
|
||||
```weacmd
|
||||
//wbox silver_sandstone
|
||||
//wbox dirt
|
||||
```
|
||||
|
||||
## `//wcompass <replace_node> [<bead_node>]`
|
||||
Creates a compass around pos1 with a single node bead pointing north (+Z).
|
||||
|
||||
```weacmd
|
||||
//wcompass meselamp
|
||||
//wcompass desert_cobble torch
|
||||
//wcompass gold diamond
|
||||
```
|
||||
|
||||
## `//wcorner <replace_node>`
|
||||
Set the corners of the current selection to `<replace_node>`. Useful for outlining building sites and setting boundaries.
|
||||
|
||||
```weacmd
|
||||
//wcorner glass
|
||||
//wcorner stone_with_iron
|
||||
```
|
||||
|
||||
## `//scale <axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>`
|
||||
Advanced version of [`//stretch` from WorldEdit](https://github.com/Uberi/Minetest-WorldEdit/blob/master/ChatCommands.md#stretch-stretchx-stretchy-stretchz) that can scale both up and down at the same time by transparently splitting it into 2 different operations. Scaling up is *always* done before scaling down.
|
||||
|
||||
Although the syntax looks complicated, it's really quite simple. The key concept to understand is that of the scale factor. It refers to how much the defined region should be scaled up or down by, and can be specified in multiple different ways:
|
||||
|
@ -286,6 +311,8 @@ This command is best explained with examples:
|
|||
|
||||
The above functions just like `//replace` - nothing special going on here. It replaces all `dirt` nodes with `stone`.
|
||||
|
||||
|
||||
|
||||
Let's make it more interesting:
|
||||
|
||||
```weacmd
|
||||
|
@ -728,17 +755,25 @@ Short for _select center_. Sets pos1 and pos2 to the centre point(s) of the curr
|
|||
//scentre
|
||||
```
|
||||
|
||||
|
||||
### `//srel <axis1> <length1> [<axis2> <length2> [<axis3> <length3>]]`
|
||||
## `//srel <axis1> <length1> [<axis2> <length2> [<axis3> <length3>]]`
|
||||
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 left 3 up 5 -front 7
|
||||
//scube -z 12 -y -2 x -2
|
||||
//srel -z 12 -y -2 x -2
|
||||
```
|
||||
|
||||
## `//sshift <axis1> <length1> [<axis2> <length2> [<axis3> <length3>]]`
|
||||
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.
|
||||
|
||||
```weacmd
|
||||
//sshift back 4
|
||||
//sshift right -2 up 2
|
||||
//sshift -left 2 z -7 -y -4
|
||||
//sshift -z 12 -y -2 x -2
|
||||
```
|
||||
|
||||
### `//smake <operation:odd|even|equal> <mode:grow|shrink|average> [<target=xz> [<base>]]`
|
||||
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.
|
||||
|
@ -786,7 +821,7 @@ If `<base>` | `<mode>` becomes optional. If present it will be ignored.
|
|||
Name | Description
|
||||
------------|------------------
|
||||
`<target>` | Specify axes to perform operation on (default= xz)|
|
||||
`<base>`: If `<operation>` == odd or even | Does nothing
|
||||
`<base>`: If `<operation>` == odd or even | Does nothing
|
||||
`<base>`: If `<operation>` == equal | Overrides `<mode>` and sets all `<target>` axes equal to itself
|
||||
|
||||
### `//sfactor <mode:grow|shrink|average> <factor> [<target=xz>]`
|
||||
|
|
|
@ -9,6 +9,8 @@ worldeditadditions = {}
|
|||
local wea = worldeditadditions
|
||||
wea.modpath = minetest.get_modpath("worldeditadditions")
|
||||
|
||||
wea.Set = dofile(wea.modpath.."/utils/set.lua")
|
||||
|
||||
wea.Vector3 = dofile(wea.modpath.."/utils/vector3.lua")
|
||||
wea.Mesh, wea.Face = dofile(wea.modpath.."/utils/mesh.lua")
|
||||
|
||||
|
@ -30,7 +32,7 @@ dofile(wea.modpath.."/utils/nodes.lua")
|
|||
dofile(wea.modpath.."/utils/node_identification.lua")
|
||||
dofile(wea.modpath.."/utils/terrain.lua")
|
||||
dofile(wea.modpath.."/utils/raycast_adv.lua") -- For the farwand
|
||||
dofile(wea.modpath.."/utils/axes.lua")
|
||||
dofile(wea.modpath.."/utils/player.lua") -- Player info functions
|
||||
|
||||
dofile(wea.modpath.."/lib/compat/saplingnames.lua")
|
||||
|
||||
|
@ -68,5 +70,9 @@ dofile(wea.modpath.."/lib/airapply.lua")
|
|||
dofile(wea.modpath.."/lib/noiseapply2d.lua")
|
||||
|
||||
dofile(wea.modpath.."/lib/subdivide.lua")
|
||||
dofile(wea.modpath.."/lib/selection/stack.lua")
|
||||
dofile(wea.modpath.."/lib/selection/cloud.lua")
|
||||
|
||||
dofile(wea.modpath.."/lib/selection/init.lua") -- Helpers for selections
|
||||
|
||||
dofile(wea.modpath.."/lib/wireframe/corner_set.lua")
|
||||
dofile(wea.modpath.."/lib/wireframe/make_compass.lua")
|
||||
dofile(wea.modpath.."/lib/wireframe/wire_box.lua")
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
-- ██████ ██ ██████ ██ ██ ██████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██████ ███████ ██████ ██████ ██████
|
||||
worldeditadditions.add_pos = {}
|
||||
worldeditadditions.selection = {}
|
||||
function worldeditadditions.selection.add_point(name, pos)
|
||||
if pos ~= nil then
|
||||
local is_new = not worldedit.pos1[name] and not worldedit.pos2[name]
|
||||
-- print("[set_pos1]", name, "("..pos.x..", "..pos.y..", "..pos.z..")")
|
||||
if not worldedit.pos1[name] then worldedit.pos1[name] = vector.new(pos) end
|
||||
if not worldedit.pos2[name] then worldedit.pos2[name] = vector.new(pos) end
|
||||
|
||||
worldedit.marker_update(name)
|
||||
|
||||
local volume_before = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||
|
||||
worldedit.pos1[name], worldedit.pos2[name] = worldeditadditions.vector.expand_region(worldedit.pos1[name], worldedit.pos2[name], pos)
|
||||
|
||||
local volume_after = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||
|
||||
local volume_difference = volume_after - volume_before
|
||||
|
||||
worldedit.marker_update(name)
|
||||
print("DEBUG volume_before", volume_before, "volume_after", volume_after)
|
||||
if is_new then
|
||||
local msg = "Created new region of "..volume_after.." node"
|
||||
if volume_after ~= 1 then msg = msg.."s" end
|
||||
worldedit.player_notify(name, msg)
|
||||
else
|
||||
local msg = "Expanded region by "..volume_difference.." node"
|
||||
if volume_difference ~= 1 then msg = msg.."s" end
|
||||
worldedit.player_notify(name, msg)
|
||||
end
|
||||
else
|
||||
worldedit.player_notify(name, "Error: Too far away (try raising your maxdist with //farwand maxdist <number>)")
|
||||
-- print("[set_pos1]", name, "nil")
|
||||
end
|
||||
end
|
||||
function worldeditadditions.selection.clear_points(name)
|
||||
worldedit.pos1[name] = nil
|
||||
worldedit.pos2[name] = nil
|
||||
worldedit.marker_update(name)
|
||||
worldedit.set_pos[name] = nil
|
||||
|
||||
worldedit.player_notify(name, "Region cleared")
|
||||
end
|
7
worldeditadditions/lib/selection/init.lua
Normal file
7
worldeditadditions/lib/selection/init.lua
Normal file
|
@ -0,0 +1,7 @@
|
|||
local wea = worldeditadditions
|
||||
local wea_m = wea.modpath .. "/lib/selection/"
|
||||
|
||||
wea.add_pos = {}
|
||||
|
||||
wea.selection = dofile(wea_m.."selection.lua")
|
||||
dofile(wea_m.."stack.lua")
|
68
worldeditadditions/lib/selection/selection.lua
Normal file
68
worldeditadditions/lib/selection/selection.lua
Normal file
|
@ -0,0 +1,68 @@
|
|||
-- ███████ ███████ ██ ███████ ██████ ████████ ██ ██████ ███ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
|
||||
-- ███████ █████ ██ █████ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███████ ███████ ███████ ███████ ██████ ██ ██ ██████ ██ ████
|
||||
|
||||
---Selection helpers and modifiers
|
||||
local selection = {}
|
||||
|
||||
--- Additively adds a point to the current selection or
|
||||
-- makes a selection from the provided point.
|
||||
-- @param name string Player name.
|
||||
-- @param pos vector The position to include.
|
||||
function selection.add_point(name, pos)
|
||||
if pos ~= nil then
|
||||
-- print("[set_pos1]", name, "("..pos.x..", "..pos.y..", "..pos.z..")")
|
||||
if not worldedit.pos1[name] then worldedit.pos1[name] = vector.new(pos) end
|
||||
if not worldedit.pos2[name] then worldedit.pos2[name] = vector.new(pos) end
|
||||
|
||||
worldedit.marker_update(name)
|
||||
|
||||
local volume_before = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||
|
||||
worldedit.pos1[name], worldedit.pos2[name] = worldeditadditions.vector.expand_region(worldedit.pos1[name], worldedit.pos2[name], pos)
|
||||
|
||||
local volume_after = worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||
|
||||
local volume_difference = volume_after - volume_before
|
||||
|
||||
worldedit.marker_update(name)
|
||||
worldedit.player_notify(name, "Expanded region by "..volume_difference.." nodes")
|
||||
else
|
||||
worldedit.player_notify(name, "Error: Too far away (try raising your maxdist with //farwand maxdist <number>)")
|
||||
-- print("[set_pos1]", name, "nil")
|
||||
end
|
||||
end
|
||||
|
||||
--- Clears current selection.
|
||||
-- @param name string Player name.
|
||||
function selection.clear_points(name)
|
||||
worldedit.pos1[name] = nil
|
||||
worldedit.pos2[name] = nil
|
||||
worldedit.marker_update(name)
|
||||
worldedit.set_pos[name] = nil
|
||||
|
||||
worldedit.player_notify(name, "Region cleared")
|
||||
end
|
||||
|
||||
--- Checks if a string is a valid axis.
|
||||
-- @param str string String to check (be sure to remove any + or -).
|
||||
-- @param hv bool Include "h" (general horizontal) and "v" (general vertical).
|
||||
-- @return bool If string is a valid axis then true.
|
||||
function selection.check_axis(str,hv)
|
||||
if hv then
|
||||
return (str == "x" or str == "y" or str == "z" or str == "h" or str == "v")
|
||||
else
|
||||
return (str == "x" or str == "y" or str == "z")
|
||||
end
|
||||
end
|
||||
|
||||
--- Checks if a string is a valid dir.
|
||||
-- @param str string String to check (be sure to remove any + or -).
|
||||
-- @return bool If string is a valid dir then true.
|
||||
function selection.check_dir(str)
|
||||
return (str == "front" or str == "back" or str == "left" or str == "right" or str == "up" or str == "down")
|
||||
end
|
||||
|
||||
return selection
|
25
worldeditadditions/lib/wireframe/corner_set.lua
Normal file
25
worldeditadditions/lib/wireframe/corner_set.lua
Normal file
|
@ -0,0 +1,25 @@
|
|||
-- ██████ ██████ ██████ ███ ██ ███████ ██████ ███████ ███████ ████████
|
||||
-- ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██████ ██ ██ ██ █████ ██████ ███████ █████ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██████ ██████ ██ ██ ██ ████ ███████ ██ ██ ███████ ███████ ██
|
||||
|
||||
--- Puts a node at each corner of selection box.
|
||||
-- @param {Position} pos1 The 1st position defining the WorldEdit selection
|
||||
-- @param {Position} pos2 The 2nd positioon defining the WorldEdit selection
|
||||
-- @param {string} node Name of the node to place
|
||||
function worldeditadditions.corner_set(pos1,pos2,node)
|
||||
|
||||
-- z y x is the preferred loop order (because CPU cache I'd guess, since then we're iterating linearly through the data array)
|
||||
local counts = { replaced = 0 }
|
||||
for k,z in pairs({pos1.z,pos2.z}) do
|
||||
for k,y in pairs({pos1.y,pos2.y}) do
|
||||
for k,x in pairs({pos1.x,pos2.x}) do
|
||||
minetest.set_node(vector.new(x,y,z), {name=node})
|
||||
counts.replaced = counts.replaced + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true, counts.replaced
|
||||
end
|
32
worldeditadditions/lib/wireframe/make_compass.lua
Normal file
32
worldeditadditions/lib/wireframe/make_compass.lua
Normal file
|
@ -0,0 +1,32 @@
|
|||
-- ███ ███ █████ ██ ██ ███████ ██████ ██████ ███ ███ ██████ █████ ███████ ███████
|
||||
-- ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ████ ██ ███████ █████ █████ ██ ██ ██ ██ ████ ██ ██████ ███████ ███████ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ███████ ██████ ██████ ██ ██ ██ ██ ██ ███████ ███████
|
||||
|
||||
--- Makes a compass with a bead pointing north (+Z).
|
||||
-- @param {Position} pos1 The 1st position defining the WorldEdit selection
|
||||
-- @param {string} node1 Name of the node to place
|
||||
-- @param {string} node2 Name of the node of the bead
|
||||
function worldeditadditions.make_compass(pos1,node1,node2)
|
||||
|
||||
minetest.set_node(vector.add(pos1,vector.new(0,1,3)), {name=node2})
|
||||
local counts = { replaced = 1 }
|
||||
|
||||
-- z y x is the preferred loop order (because CPU cache I'd guess, since then we're iterating linearly through the data array)
|
||||
for z = -3,3 do
|
||||
if z ~= 0 then
|
||||
for k,x in pairs({math.floor(-3/math.abs(z)),0,math.ceil(3/math.abs(z))}) do
|
||||
minetest.set_node(vector.new(pos1.x+x,pos1.y,pos1.z+z), {name=node1})
|
||||
counts.replaced = counts.replaced + 1
|
||||
end
|
||||
else
|
||||
for x = -3,3 do
|
||||
minetest.set_node(vector.new(pos1.x+x,pos1.y,pos1.z), {name=node1})
|
||||
counts.replaced = counts.replaced + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true, counts.replaced
|
||||
end
|
55
worldeditadditions/lib/wireframe/wire_box.lua
Normal file
55
worldeditadditions/lib/wireframe/wire_box.lua
Normal file
|
@ -0,0 +1,55 @@
|
|||
-- ██ ██ ██ ██████ ███████ ██████ ██████ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ █ ██ ██ ██████ █████ ██████ ██ ██ ███
|
||||
-- ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███ ███ ██ ██ ██ ███████ ██████ ██████ ██ ██
|
||||
|
||||
--- Fills the edges of the selection box with nodes.
|
||||
-- @param {Position} pos1 The 1st position defining the WorldEdit selection
|
||||
-- @param {Position} pos2 The 2nd positioon defining the WorldEdit selection
|
||||
-- @param {string} node Name of the node to place
|
||||
local v3 = worldeditadditions.Vector3
|
||||
function worldeditadditions.wire_box(pos1,pos2,node)
|
||||
local node_id_replace = minetest.get_content_id(node)
|
||||
local ps1, ps2 = v3.sort(pos1,pos2)
|
||||
|
||||
-- Fetch the nodes in the specified area
|
||||
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
|
||||
local data = manip:get_data()
|
||||
|
||||
-- Using three loops to reduce the number of nodes processed
|
||||
local counts = { replaced = 0 }
|
||||
|
||||
for z = ps1.z,ps2.z do
|
||||
for _j,y in pairs({pos1.y,pos2.y}) do
|
||||
for _k,x in pairs({pos1.x,pos2.x}) do
|
||||
data[area:index(x, y, z)] = node_id_replace
|
||||
counts.replaced = counts.replaced + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if math.abs(ps2.y-ps1.y) > 1 then
|
||||
for _j,z in pairs({pos1.z,pos2.z}) do
|
||||
for y = pos1.y+1,pos2.y-1 do
|
||||
for _k,x in pairs({pos1.x,pos2.x}) do
|
||||
data[area:index(x, y, z)] = node_id_replace
|
||||
counts.replaced = counts.replaced + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if math.abs(ps2.x-ps1.x) > 1 then
|
||||
for _j,z in pairs({pos1.z,pos2.z}) do
|
||||
for _k,y in pairs({pos1.y,pos2.y}) do
|
||||
for x = pos1.x+1,pos2.x-1 do
|
||||
data[area:index(x, y, z)] = node_id_replace
|
||||
counts.replaced = counts.replaced + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Save the modified nodes back to disk & return
|
||||
worldedit.manip_helpers.finish(manip, data)
|
||||
|
||||
return true, counts.replaced
|
||||
end
|
|
@ -1,39 +0,0 @@
|
|||
-- Returns the player's facing direction on the horizontal axes only.
|
||||
-- @param name string The name of the player to return facing direction of.
|
||||
-- @return Returns axis name and sign multiplier.
|
||||
function worldeditadditions.player_axis2d(name)
|
||||
-- minetest.get_player_by_name("singleplayer"):
|
||||
local dir = minetest.get_player_by_name(name):get_look_dir()
|
||||
local x, z= math.abs(dir.x), math.abs(dir.z)
|
||||
if x > z then return "x", dir.x > 0 and 1 or -1
|
||||
else return "z", dir.z > 0 and 1 or -1 end
|
||||
end
|
||||
|
||||
-- Returns the axis and sign of the axis to the left of the input axis.
|
||||
-- @param axis string x or z.
|
||||
-- @param sign int Sign multiplier.
|
||||
-- @return Returns axis name and sign multiplier.
|
||||
function worldeditadditions.axis_left(axis,sign)
|
||||
if not axis:match("[xz]") then return false, "Error: Not a horizontal axis!"
|
||||
elseif axis == "x" then return true, "z", sign
|
||||
else return true, "x", -sign end
|
||||
end
|
||||
|
||||
--- Dehumanize Direction: translates up, down, left, right, front, into xyz based on player orientation.
|
||||
-- @param name string The name of the player to return facing direction of.
|
||||
-- @param dir string Relative direction to translate.
|
||||
-- @return Returns axis name and sign multiplier.
|
||||
function worldeditadditions.dir_to_xyz(name, dir)
|
||||
local axfac, drfac = worldeditadditions.player_axis2d(name)
|
||||
local _, axlft, drlft = worldeditadditions.axis_left(axfac,drfac)
|
||||
if dir:match("front") or dir:match("back") then
|
||||
return axfac, dir:match("front") and drfac or -drfac
|
||||
elseif dir:match("left") or dir:match("right") then
|
||||
return axlft, dir:match("left") and drlft or -drlft
|
||||
elseif dir:match("up") or dir:match("down") then
|
||||
return "y", dir == "down" and -1 or 1
|
||||
else return false, "\"" .. dir .. "\" not a recognized direction! Try: (up | down | left | right | front | back)" end
|
||||
end
|
||||
|
||||
-- Tests
|
||||
-- /lua print(worldeditadditions.table.unpack(worldeditadditions.player_axis2d(myname)))
|
|
@ -82,9 +82,12 @@ end
|
|||
-- @param src string|int Input string.
|
||||
-- @return string|int Returns the signed multiplier (1|-1).
|
||||
function worldeditadditions.getsign(src)
|
||||
if type(src) == "number" then return src < 0 and -1 or 1
|
||||
if type(src) == "number" then
|
||||
if src < 0 then return -1 else return 1 end
|
||||
elseif type(src) ~= "string" then return 1
|
||||
else return src:match('-') and -1 or 1 end
|
||||
else
|
||||
if src:match('-') then return -1 else return 1 end
|
||||
end
|
||||
end
|
||||
|
||||
--- Clamp a number to ensure it falls within a given range.
|
||||
|
|
72
worldeditadditions/utils/player.lua
Normal file
72
worldeditadditions/utils/player.lua
Normal file
|
@ -0,0 +1,72 @@
|
|||
local wea = worldeditadditions
|
||||
local v3 = worldeditadditions.Vector3
|
||||
--- Returns the player's position (at leg level).
|
||||
-- @param name string The name of the player to return facing direction of.
|
||||
-- @return vector Returns position.
|
||||
function worldeditadditions.player_vector(name)
|
||||
return minetest.get_player_by_name(name):get_pos()
|
||||
end
|
||||
|
||||
--- Returns the player's facing info including relative DIRs.
|
||||
-- @param name string The name of the player to return facing direction of.
|
||||
-- @return table (vector3+) xyz raw values and {axis,sign} tables for facing direction and
|
||||
-- relative direction keys (front, back, left, right, up, down).
|
||||
function worldeditadditions.player_dir(name)
|
||||
local dir = v3.clone(minetest.get_player_by_name(name):get_look_dir())
|
||||
local abs = dir:abs()
|
||||
-- Facing info
|
||||
if abs.x > abs.z then dir.facing = {axis="x",sign=wea.getsign(dir.x)}
|
||||
else dir.facing = {axis="z",sign=wea.getsign(dir.z)} end
|
||||
-- Set front and back
|
||||
dir.front = dir.facing
|
||||
dir.back = {axis=dir.facing.axis,sign=dir.facing.sign*-1}
|
||||
-- Set left and right
|
||||
if dir.facing.axis == "x" then dir.left = {axis="z", sign=dir.facing.sign}
|
||||
else dir.left = {axis="x", sign=dir.facing.sign*-1} end
|
||||
dir.right = {axis=dir.left.axis,sign=dir.left.sign*-1}
|
||||
-- Set up and down
|
||||
dir.up = {axis="y",sign=1}
|
||||
dir.down = {axis="y",sign=-1}
|
||||
return dir
|
||||
end
|
||||
-- /lua print(worldeditadditions.vector.tostring(minetest.get_player_by_name(myname):get_look_dir()))
|
||||
|
||||
--- DEPRICATED =================================================================
|
||||
-- TODO: Refactor commands that use the following functions to use player_dir then delete these functions
|
||||
|
||||
--- Returns the player's facing direction on the horizontal axes only.
|
||||
-- @param name string The name of the player to return facing direction of.
|
||||
-- @return string,int Returns axis name and sign multiplier.
|
||||
function worldeditadditions.player_axis2d(name)
|
||||
-- minetest.get_player_by_name("singleplayer"):
|
||||
local dir = minetest.get_player_by_name(name):get_look_dir()
|
||||
local x, z= math.abs(dir.x), math.abs(dir.z)
|
||||
if x > z then return "x", dir.x > 0 and 1 or -1
|
||||
else return "z", dir.z > 0 and 1 or -1 end
|
||||
end
|
||||
|
||||
--- Returns the axis and sign of the axis to the left of the input axis.
|
||||
-- @param axis string x or z.
|
||||
-- @param sign int Sign multiplier.
|
||||
-- @return string,int Returns axis name and sign multiplier.
|
||||
function worldeditadditions.axis_left(axis,sign)
|
||||
if not axis:match("[xz]") then return false, "Error: Not a horizontal axis!"
|
||||
elseif axis == "x" then return true, "z", sign
|
||||
else return true, "x", -sign end
|
||||
end
|
||||
|
||||
--- Dehumanize Direction: translates up, down, left, right, front, into xyz based on player orientation.
|
||||
-- @param name string The name of the player to return facing direction of.
|
||||
-- @param dir string Relative direction to translate.
|
||||
-- @return string Returns axis name and sign multiplier.
|
||||
function worldeditadditions.dir_to_xyz(name, dir)
|
||||
local axfac, drfac = worldeditadditions.player_axis2d(name)
|
||||
local _, axlft, drlft = worldeditadditions.axis_left(axfac,drfac)
|
||||
if dir:match("front") or dir:match("back") then
|
||||
return axfac, dir:match("front") and drfac or -drfac
|
||||
elseif dir:match("left") or dir:match("right") then
|
||||
return axlft, dir:match("left") and drlft or -drlft
|
||||
elseif dir:match("up") or dir:match("down") then
|
||||
return "y", dir == "down" and -1 or 1
|
||||
else return false, "\"" .. dir .. "\" not a recognized direction! Try: (up | down | left | right | front | back)" end
|
||||
end
|
101
worldeditadditions/utils/set.lua
Normal file
101
worldeditadditions/utils/set.lua
Normal file
|
@ -0,0 +1,101 @@
|
|||
--- Sets for lua!
|
||||
-- local Set = {}
|
||||
--- Option 1:
|
||||
-- Set.__index = Set
|
||||
-- Set.__newindex = function(tbl, key, value)
|
||||
-- if not tbl.__protected[key] then
|
||||
-- rawset(tbl,key,value)
|
||||
-- else
|
||||
-- error("Protected!")
|
||||
-- end
|
||||
-- end
|
||||
-- Set.__protected = {
|
||||
-- __protected=true,
|
||||
-- new=true,
|
||||
-- add=true,
|
||||
-- delete=true,
|
||||
-- has=true
|
||||
-- }
|
||||
|
||||
--- Option 2:
|
||||
local Set = {}
|
||||
Set.__index = Set
|
||||
Set.__newindex = function(tbl, key, value)
|
||||
rawset(tbl.set,key,value)
|
||||
end
|
||||
|
||||
--- Creates a new set.
|
||||
-- @param i any Initial values(s) of the set.
|
||||
-- @returns Set A table of keys equal to true.
|
||||
function Set.new(i)
|
||||
local result = {set={}}
|
||||
setmetatable(result, Set)
|
||||
if type(i) == "table" then
|
||||
for k,v in pairs(i) do result[v] = true end
|
||||
elseif i then
|
||||
result[i] = true
|
||||
end
|
||||
return result
|
||||
end
|
||||
-- a = Set.new({"add","new","thing"})
|
||||
|
||||
--- Adds item(s) to set.
|
||||
-- @param a set Set to manipulate.
|
||||
-- @param i not nil Values(s) to add.
|
||||
-- @returns bool Success of operation.
|
||||
function Set.add(a,i)
|
||||
if type(i) == "table" then
|
||||
for k,v in pairs(i) do a[v] = true end
|
||||
else
|
||||
a[i] = true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Deletes item(s) from set.
|
||||
-- @param a set Set to manipulate.
|
||||
-- @param i not nil Values(s) to delete.
|
||||
-- @returns bool Success of operation.
|
||||
function Set.delete(a,i)
|
||||
if type(i) == "table" then
|
||||
for k,v in pairs(i) do a[v] = nil end
|
||||
else
|
||||
a[i] = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Checks if value(s) are present in set.
|
||||
-- @param a set Set to inspect.
|
||||
-- @param i not nil Values(s) to check.
|
||||
-- @returns bool Value(s) are present?
|
||||
function Set.has(a,i)
|
||||
if type(i) == "table" then
|
||||
for k,v in pairs(i) do
|
||||
if not a[k] then return false end
|
||||
end
|
||||
return true
|
||||
else
|
||||
return a[i] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██████ █████ ██████ ███████ ██ ██ ██ ██████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██████ ██ ███████ ██ ██ ██ ██ ██ ██████ ██ ██
|
||||
--
|
||||
-- ██████ ██ ██ ███████ ██████ ██████ ██ ██████ ███████ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ █████ ██████ ██████ ██ ██ ██ █████ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██████ ████ ███████ ██ ██ ██ ██ ██ ██████ ███████ ███████
|
||||
|
||||
function Set.__call(i) return Set.new(i) end
|
||||
|
||||
|
||||
-- Main Return:
|
||||
return Set
|
|
@ -4,3 +4,4 @@ dofile(wea.modpath.."/utils/strings/split.lua")
|
|||
dofile(wea.modpath.."/utils/strings/polyfill.lua")
|
||||
dofile(wea.modpath.."/utils/strings/tochars.lua")
|
||||
wea.split_shell = dofile(wea.modpath.."/utils/strings/split_shell.lua")
|
||||
wea.to_boolean = dofile(wea.modpath.."/utils/strings/to_boolean.lua")
|
||||
|
|
|
@ -42,16 +42,46 @@ function worldeditadditions.gsplit(text, pattern, plain)
|
|||
end
|
||||
|
||||
|
||||
-- Split a string into substrings separated by a pattern.
|
||||
--- 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
|
||||
function worldeditadditions.split(text, pattern, plain)
|
||||
function worldeditadditions.dsplit(text, pattern, plain)
|
||||
local ret = {}
|
||||
for match in worldeditadditions.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
|
||||
function worldeditadditions.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
|
||||
|
|
12
worldeditadditions/utils/strings/to_boolean.lua
Normal file
12
worldeditadditions/utils/strings/to_boolean.lua
Normal file
|
@ -0,0 +1,12 @@
|
|||
--- Converts input to a value of type Boolean.
|
||||
-- @param arg any Input to convert
|
||||
-- @returns boolean
|
||||
local function to_boolean(arg)
|
||||
local typ = type(arg)
|
||||
if typ == "boolean" then return arg
|
||||
elseif typ == "number" and arg > 0 then return true
|
||||
elseif arg == "false" or arg == "no" then return false
|
||||
elseif typ ~= "nil" then return true
|
||||
else return false end
|
||||
end
|
||||
return to_boolean
|
|
@ -2,16 +2,27 @@
|
|||
-- @param tbl table input table
|
||||
-- @param sep string key value seperator
|
||||
-- @param new_line string key value pair delimiter
|
||||
-- @param max_depth number max recursion depth (optional)
|
||||
-- @return string concatenated table pairs
|
||||
local function table_tostring(tbl, sep, new_line)
|
||||
local function table_tostring(tbl, sep, new_line, max_depth)
|
||||
if type(sep) ~= "string" then sep = ": " end
|
||||
if type(new_line) ~= "string" then new_line = ", " end
|
||||
if type(max_depth) == "number" then max_depth = {depth=0,max=max_depth}
|
||||
elseif type(max_depth) ~= "table" then max_depth = {depth=0,max=5} end
|
||||
local ret = {}
|
||||
if type(tbl) ~= "table" then return "Error: input not table!" end
|
||||
for key,value in pairs(tbl) do
|
||||
table.insert(ret,tostring(key) .. sep .. tostring(value) .. new_line)
|
||||
if type(value) == "table" and max_depth.depth < max_depth.max then
|
||||
table.insert(ret,tostring(key) .. sep ..
|
||||
"{" .. table_tostring(value,sep,new_line,{max_depth.depth+1,max_depth.max}) .. "}")
|
||||
else
|
||||
table.insert(ret,tostring(key) .. sep .. tostring(value))
|
||||
end
|
||||
end
|
||||
return table.concat(ret,"")
|
||||
return table.concat(ret,new_line)
|
||||
end
|
||||
|
||||
-- Test:
|
||||
-- /lua v1 = { x= 0.335, facing= { axis= "z", sign= -1 } }; print(worldeditadditions.table.tostring(v1))
|
||||
|
||||
return table_tostring
|
||||
|
|
|
@ -66,11 +66,11 @@ function Vector3.sub(a, b) return Vector3.subtract(a, b) end
|
|||
-- 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.
|
||||
|
@ -263,7 +263,7 @@ end
|
|||
-- 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.
|
||||
-- @returns Vector3,Vector3 The 2 sorted vectors (min, max).
|
||||
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
|
||||
|
@ -384,7 +384,7 @@ end
|
|||
-- ██ ██ ██████ █████ ██████ ███████ ██ ██ ██ ██████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██████ ██ ███████ ██ ██ ██ ██ ██ ██████ ██ ██
|
||||
--
|
||||
--
|
||||
-- ██████ ██ ██ ███████ ██████ ██████ ██ ██████ ███████ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ █████ ██████ ██████ ██ ██ ██ █████ ███████
|
||||
|
|
|
@ -15,6 +15,6 @@ worldedit.register_command("basename", {
|
|||
end,
|
||||
func = function(name, params_text)
|
||||
if name == nil then return end
|
||||
worldedit.player_notify(name, worldedit.normalize_nodename(params_text) or 'Error 404: "'..params_text..'" not found!')
|
||||
return true, worldedit.normalize_nodename(params_text) or 'Error 404: "'..params_text..'" not found!'
|
||||
end
|
||||
})
|
||||
|
|
88
worldeditadditions_commands/commands/meta/for.lua
Normal file
88
worldeditadditions_commands/commands/meta/for.lua
Normal file
|
@ -0,0 +1,88 @@
|
|||
-- ███████ ██████ ██████
|
||||
-- ██ ██ ██ ██ ██
|
||||
-- █████ ██ ██ ██████
|
||||
-- ██ ██ ██ ██ ██
|
||||
-- ██ ██████ ██ ██
|
||||
-- Process:
|
||||
-- 1: Split `params_text` into two vars with unpack(wea.split(params_text,"%sdo%s"))
|
||||
-- 2: Further split the two vars into two tables, one of values and the other of {command, args} sub tables
|
||||
-- 3: For each entry in the values table execute each {command, args} sub table using gsub to replace "%%" in the args with the current value
|
||||
|
||||
-- Specs:
|
||||
-- Command cluster support using ()
|
||||
-- ?Basename support for values
|
||||
-- ?Comma deliniation support for values
|
||||
|
||||
local wea = worldeditadditions
|
||||
local function step(params)
|
||||
-- Initialize additional params on first call
|
||||
if not params.first then
|
||||
params.i = 1 -- Iteration number
|
||||
params.time = 0 -- Total execution time
|
||||
params.first = true
|
||||
end
|
||||
|
||||
-- Load current value to use
|
||||
local v = params.values[params.i]
|
||||
|
||||
-- Start a timer
|
||||
local start_time = wea.get_ms_time()
|
||||
-- Execute command
|
||||
params.cmd.func(params.player_name, params.args:gsub("%%+",v))
|
||||
-- Finish timer and add to total
|
||||
params.time = params.time + wea.get_ms_time() - start_time
|
||||
-- Increment iteration state
|
||||
params.i = params.i + 1
|
||||
|
||||
if params.i <= #params.values then
|
||||
-- If we haven't run out of values call function again
|
||||
minetest.after(0, step, params)
|
||||
else
|
||||
worldedit.player_notify(params.player_name, "For "..
|
||||
table.concat(params.values,", ")..
|
||||
", /"..params.cmd_name.." completed in " ..
|
||||
wea.format.human_time(params.time))
|
||||
end
|
||||
end
|
||||
|
||||
worldedit.register_command("for", {
|
||||
params = "<value1> <value2> <value3>... do //<command> <arg> %% <arg>",
|
||||
description = "Executes a chat command for each value before \" do \" replacing any instances of \"%%\" with those values. The forward slashes at the beginning of the chat command must be the same as if you were executing it normally.",
|
||||
privs = { worldedit = true },
|
||||
parse = function(params_text)
|
||||
if not params_text:match("%sdo%s") then
|
||||
return false, "Error: \"do\" argument is not present."
|
||||
end
|
||||
local parts = wea.split(params_text,"%sdo%s")
|
||||
if not parts[1] == "" then
|
||||
return false, "Error: No values specified."
|
||||
end
|
||||
if not parts[2] then
|
||||
return false, "Error: No command specified."
|
||||
end
|
||||
local values = wea.split(parts[1],"%s")
|
||||
local command, args = parts[2]:match("/([^%s]+)%s*(.*)$")
|
||||
if not args then args = ""
|
||||
else args = wea.trim(args) end
|
||||
|
||||
return true, values, command, args
|
||||
end,
|
||||
func = function(name, values, command, args)
|
||||
local cmd = minetest.chatcommands[command]
|
||||
if not cmd then
|
||||
return false, "Error: "..command.." isn't a valid command."
|
||||
end
|
||||
if not minetest.check_player_privs(name, cmd.privs) then
|
||||
return false, "Your privileges are insufficient to run /\""..command.."\"."
|
||||
end
|
||||
|
||||
step({
|
||||
player_name = name,
|
||||
cmd_name = command,
|
||||
values = values,
|
||||
cmd = cmd,
|
||||
args = args
|
||||
})
|
||||
|
||||
end
|
||||
})
|
18
worldeditadditions_commands/commands/meta/init.lua
Normal file
18
worldeditadditions_commands/commands/meta/init.lua
Normal file
|
@ -0,0 +1,18 @@
|
|||
-- ███ ███ ███████ ████████ █████
|
||||
-- ████ ████ ██ ██ ██ ██
|
||||
-- ██ ████ ██ █████ ██ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ███████ ██ ██ ██
|
||||
|
||||
-- Commands that work on other commands.
|
||||
|
||||
local we_cm = worldeditadditions_commands.modpath .. "/commands/meta/"
|
||||
|
||||
dofile(we_cm.."airapply.lua")
|
||||
dofile(we_cm.."ellipsoidapply.lua")
|
||||
dofile(we_cm.."for.lua")
|
||||
-- dofile(we_cm.."macro.lua") -- Async bug
|
||||
dofile(we_cm.."many.lua")
|
||||
dofile(we_cm.."multi.lua")
|
||||
dofile(we_cm.."noiseapply2d.lua")
|
||||
dofile(we_cm.."subdivide.lua")
|
134
worldeditadditions_commands/commands/meta/macro.lua
Normal file
134
worldeditadditions_commands/commands/meta/macro.lua
Normal file
|
@ -0,0 +1,134 @@
|
|||
-- ███ ███ █████ ██████ ██████ ██████
|
||||
-- ████ ████ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ████ ██ ███████ ██ ██████ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ ██ ██ ██ ██████ ██ ██ ██████
|
||||
local wea = worldeditadditions
|
||||
local v3 = worldeditadditions.Vector3
|
||||
local function step(params)
|
||||
-- Initialize additional params on first call
|
||||
if not params.first then
|
||||
params.i = 1 -- Iteration number
|
||||
params.time = 0 -- Total execution time
|
||||
params.first = true
|
||||
end
|
||||
|
||||
-- Load current command string to use
|
||||
local command, args = params.commands[params.i]:match("/([^%s]+)%s*(.*)$")
|
||||
if not args then args = ""
|
||||
else args = args:match("^%s*(.*)%s*$") end
|
||||
-- Get command and test privs
|
||||
local cmd = minetest.chatcommands[command]
|
||||
if not cmd then
|
||||
return false, "Error: "..command.." isn't a valid command."
|
||||
end
|
||||
if not minetest.check_player_privs(params.player_name, cmd.privs) then
|
||||
return false, "Your privileges are insufficient to run /\""..command.."\"."
|
||||
end
|
||||
|
||||
-- Start a timer
|
||||
local start_time = wea.get_ms_time()
|
||||
-- Execute command
|
||||
cmd.func(params.player_name, args)
|
||||
-- Finish timer and add to total
|
||||
params.time = params.time + wea.get_ms_time() - start_time
|
||||
-- Increment iteration state
|
||||
params.i = params.i + 1
|
||||
|
||||
if params.i <= #params.commands then
|
||||
-- If we haven't run out of values call function again
|
||||
minetest.after(params.delay, step, params) -- Time is in seconds
|
||||
else
|
||||
worldedit.player_notify(params.player_name, "The macro \""..
|
||||
params.file.."\" was completed in " ..
|
||||
wea.format.human_time(params.time))
|
||||
end
|
||||
end
|
||||
|
||||
worldedit.register_command("macro", {
|
||||
params = "<file> [<delay=0>]",
|
||||
description = "Load commands from \"(world folder)/macros/<file>[.weamac | .wmac]\" with position 1 of the current WorldEdit region as the origin.",
|
||||
privs = {worldedit=true},
|
||||
require_pos = 0,
|
||||
parse = function(params_text)
|
||||
local parts = wea.split(params_text,"%s")
|
||||
local file_name, delay -- = params_text:match("^(.-)%s*(%d*%.?%d*)$")
|
||||
-- Check for params and delay
|
||||
if not parts[1] then
|
||||
return false, "Error: Insufficient arguments. Expected: \"<file> [<delay=0>]\""
|
||||
elseif not parts[#parts]:match("[^%d%.]") then
|
||||
delay = table.remove(parts,#parts)
|
||||
file_name = table.concat(parts," ")
|
||||
else
|
||||
delay = 0
|
||||
file_name = table.concat(parts," ")
|
||||
end
|
||||
-- Check file name
|
||||
if file_name:match("[!\"#%%&'%(%)%*%+,/:;<=>%?%[\\]%^`{|}]") then
|
||||
return false, "Disallowed file name: " .. params_text
|
||||
end
|
||||
|
||||
return true, file_name, delay
|
||||
end,
|
||||
func = function(name, file_name, delay)
|
||||
if not worldedit.pos1[name] then
|
||||
worldedit.pos1[name] = v3.add(wea.player_vector(name), v3.new(0.5,-0.5,0.5)):floor()
|
||||
worldedit.mark_pos1(name)
|
||||
end
|
||||
worldedit.pos2[name] = worldedit.pos1[name]
|
||||
|
||||
-- Find the file in the world path
|
||||
local testpaths = {
|
||||
minetest.get_worldpath() .. "/macros/" .. file_name,
|
||||
minetest.get_worldpath() .. "/macros/" .. file_name .. ".weamac",
|
||||
minetest.get_worldpath() .. "/macros/" .. file_name .. ".wmac",
|
||||
}
|
||||
local file, err
|
||||
for index, path in ipairs(testpaths) do
|
||||
file, err = io.open(path, "rb")
|
||||
if not err then break end
|
||||
end
|
||||
-- Check if file exists
|
||||
if err then
|
||||
return false, "Error: File \"" .. file_name .. "\" does not exist or is corrupt."
|
||||
end
|
||||
local value = file:read("*a")
|
||||
file:close()
|
||||
|
||||
step({
|
||||
player_name = name,
|
||||
file = file_name:match("^[^%.]+"),
|
||||
delay = delay,
|
||||
commands = wea.split(value,"[\n\r]+")
|
||||
})
|
||||
|
||||
end,
|
||||
})
|
||||
|
||||
-- Make default macro
|
||||
local function default_macro()
|
||||
local path = minetest.get_worldpath() .. "/macros"
|
||||
-- Create directory if it does not already exist
|
||||
minetest.mkdir(path)
|
||||
local writer, err = io.open(path.."/fixlight.weamac", "ab")
|
||||
if not writer then return false end
|
||||
writer:write("//multi //1 //2 //outset 50 //fixlight //y")
|
||||
writer:flush()
|
||||
writer:close()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Check for default macro
|
||||
local function chk_default_macro()
|
||||
local path = minetest.get_worldpath() .. "/macros/fixlight.weamac"
|
||||
local file, err = io.open(path, "rb")
|
||||
if err then return false
|
||||
else
|
||||
file:close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
if not chk_default_macro() then
|
||||
default_macro()
|
||||
end
|
|
@ -18,4 +18,8 @@ dofile(we_cm.."smake.lua")
|
|||
dofile(we_cm.."spop.lua")
|
||||
dofile(we_cm.."spush.lua")
|
||||
dofile(we_cm.."srect.lua")
|
||||
dofile(we_cm.."sshift.lua")
|
||||
dofile(we_cm.."sstack.lua")
|
||||
|
||||
-- Aliases
|
||||
worldedit.alias_command("sfac", "sfactor")
|
||||
|
|
|
@ -36,7 +36,7 @@ worldedit.register_command("srel", {
|
|||
if not _ then return false, vec end
|
||||
|
||||
if not worldedit.pos1[name] then
|
||||
local pos = vector.add(minetest.get_player_by_name(name):get_pos(), vector.new(0.5,-0.5,0.5))
|
||||
local pos = vector.add(wea.player_vector(name), vector.new(0.5,-0.5,0.5))
|
||||
wea.vector.floor(pos)
|
||||
worldedit.pos1[name] = pos
|
||||
worldedit.mark_pos1(name)
|
||||
|
|
51
worldeditadditions_commands/commands/selectors/sshift.lua
Normal file
51
worldeditadditions_commands/commands/selectors/sshift.lua
Normal file
|
@ -0,0 +1,51 @@
|
|||
-- ███████ ███████ ██ ██ ██ ███████ ████████
|
||||
-- ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███████ ███████ ███████ ██ █████ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███████ ███████ ██ ██ ██ ██ ██
|
||||
local wea = worldeditadditions
|
||||
local v3 = worldeditadditions.Vector3
|
||||
local function parse_with_name(name,args)
|
||||
local vec, tmp = v3.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.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
|
||||
worldedit.register_command("sshift", {
|
||||
params = "<axis1> <distance1> [<axis2> <distance2> [<axis3> <distance3>]]",
|
||||
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
|
||||
end,
|
||||
func = function(name, params_text)
|
||||
local _, vec = parse_with_name(name,params_text)
|
||||
if not _ then return false, vec end
|
||||
|
||||
local pos1 = vec:add(worldedit.pos1[name])
|
||||
worldedit.pos1[name] = pos1
|
||||
worldedit.mark_pos1(name)
|
||||
|
||||
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."
|
||||
end,
|
||||
})
|
||||
|
||||
-- Tests
|
||||
-- //srel front 5 left 3 y 2
|
13
worldeditadditions_commands/commands/wireframe/init.lua
Normal file
13
worldeditadditions_commands/commands/wireframe/init.lua
Normal file
|
@ -0,0 +1,13 @@
|
|||
-- ██ ██ ██ ██████ ███████ ███████ ██████ █████ ███ ███ ███████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██
|
||||
-- ██ █ ██ ██ ██████ █████ █████ ██████ ███████ ██ ████ ██ █████
|
||||
-- ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███ ███ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ███████
|
||||
|
||||
-- 2d and 3d outlines of shapes.
|
||||
|
||||
local we_cm = worldeditadditions_commands.modpath .. "/commands/wireframe/"
|
||||
|
||||
dofile(we_cm.."wbox.lua")
|
||||
dofile(we_cm.."wcompass.lua")
|
||||
dofile(we_cm.."wcorner.lua")
|
39
worldeditadditions_commands/commands/wireframe/wbox.lua
Normal file
39
worldeditadditions_commands/commands/wireframe/wbox.lua
Normal file
|
@ -0,0 +1,39 @@
|
|||
-- ██ ██ ██████ ██████ ██ ██
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ██ █ ██ ██████ ██ ██ ███
|
||||
-- ██ ███ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███ ███ ██████ ██████ ██ ██
|
||||
local wea = worldeditadditions
|
||||
local v3 = worldeditadditions.Vector3
|
||||
worldedit.register_command("wbox", {
|
||||
params = "<replace_node>",
|
||||
description = "Sets the edges of the current selection to <replace_node>",
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(params_text)
|
||||
if params_text == "" then
|
||||
return false, "Error: too few arguments! Expected: \"<replace_node>\""
|
||||
end
|
||||
local node = worldedit.normalize_nodename(params_text)
|
||||
if not node then
|
||||
return false, "invalid node name: " .. params_text
|
||||
end
|
||||
return true, node
|
||||
end,
|
||||
nodes_needed = function(name)
|
||||
local delta = v3.subtract(worldedit.pos2[name], worldedit.pos1[name]):abs():add(1)
|
||||
local total, mult, axes = 1, 4, {"x","y","z"}
|
||||
for k,v in pairs(axes) do
|
||||
if worldedit.pos1[name] ~= worldedit.pos2[name] then total = total*2
|
||||
else mult = mult/2 end
|
||||
end
|
||||
for k,v in pairs(axes) do
|
||||
if delta[v] > 2 then total = total + (delta[v] - 2)*mult end
|
||||
end
|
||||
return total
|
||||
end,
|
||||
func = function(name, node)
|
||||
local _, count = wea.wire_box(worldedit.pos1[name], worldedit.pos2[name], node)
|
||||
return _, count .. " nodes set"
|
||||
end,
|
||||
})
|
35
worldeditadditions_commands/commands/wireframe/wcompass.lua
Normal file
35
worldeditadditions_commands/commands/wireframe/wcompass.lua
Normal file
|
@ -0,0 +1,35 @@
|
|||
-- ██ ██ ██████ ██████ ███ ███ ██████ █████ ███████ ███████
|
||||
-- ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██
|
||||
-- ██ █ ██ ██ ██ ██ ██ ████ ██ ██████ ███████ ███████ ███████
|
||||
-- ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███ ███ ██████ ██████ ██ ██ ██ ██ ██ ███████ ███████
|
||||
local wea = worldeditadditions
|
||||
worldedit.register_command("wcompass", {
|
||||
params = "<replace_node> [<bead_node>]",
|
||||
description = "Creates a compass around pos1 with a single node bead pointing north (+Z).",
|
||||
privs = {worldedit=true},
|
||||
require_pos = 1,
|
||||
parse = function(params_text)
|
||||
local parts = wea.split(params_text," ",true)
|
||||
if not parts[1] then
|
||||
return false, "Error: too few arguments! Expected: \"<replace_node> [<bead_node>]\""
|
||||
elseif not parts[2] then
|
||||
parts[2] = parts[1]
|
||||
end
|
||||
local node1 = worldedit.normalize_nodename(parts[1])
|
||||
local node2 = worldedit.normalize_nodename(parts[2])
|
||||
if not node1 then
|
||||
return false, "Invalid <replace_node>: " .. parts[1]
|
||||
elseif not node2 then
|
||||
return false, "Invalid <bead_node>: " .. parts[2]
|
||||
end
|
||||
return true, node1, node2
|
||||
end,
|
||||
nodes_needed = function(name)
|
||||
return 26
|
||||
end,
|
||||
func = function(name, node1, node2)
|
||||
local _, count = wea.make_compass(worldedit.pos1[name], node1, node2)
|
||||
return _, count .. " nodes set"
|
||||
end,
|
||||
})
|
30
worldeditadditions_commands/commands/wireframe/wcorner.lua
Normal file
30
worldeditadditions_commands/commands/wireframe/wcorner.lua
Normal file
|
@ -0,0 +1,30 @@
|
|||
-- ██ ██ ██████ ██████ ██████ ███ ██ ███████ ██████
|
||||
-- ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██
|
||||
-- ██ █ ██ ██ ██ ██ ██████ ██ ██ ██ █████ ██████
|
||||
-- ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
-- ███ ███ ██████ ██████ ██ ██ ██ ████ ███████ ██ ██
|
||||
local wea = worldeditadditions
|
||||
worldedit.register_command("wcorner", {
|
||||
params = "<replace_node>",
|
||||
description = "Set the corners of the current selection to <replace_node>",
|
||||
privs = {worldedit=true},
|
||||
require_pos = 2,
|
||||
parse = function(params_text)
|
||||
local node = worldedit.normalize_nodename(params_text)
|
||||
if not node then
|
||||
return false, "invalid node name: " .. params_text
|
||||
end
|
||||
return true, node
|
||||
end,
|
||||
nodes_needed = function(name)
|
||||
local p1, p2, total = worldedit.pos1[name], worldedit.pos2[name], 1
|
||||
for k,v in pairs({"x","y","z"}) do
|
||||
if p1[v] ~= p2[v] then total = total*2 end
|
||||
end
|
||||
return total
|
||||
end,
|
||||
func = function(name, node)
|
||||
local _, count = wea.corner_set(worldedit.pos1[name], worldedit.pos2[name], node)
|
||||
return _, count .. " nodes set"
|
||||
end,
|
||||
})
|
|
@ -39,12 +39,8 @@ dofile(we_c.modpath.."/commands/spiral2.lua")
|
|||
|
||||
dofile(we_c.modpath.."/commands/count.lua")
|
||||
|
||||
dofile(we_c.modpath.."/commands/meta/multi.lua")
|
||||
dofile(we_c.modpath.."/commands/meta/many.lua")
|
||||
dofile(we_c.modpath.."/commands/meta/subdivide.lua")
|
||||
dofile(we_c.modpath.."/commands/meta/ellipsoidapply.lua")
|
||||
dofile(we_c.modpath.."/commands/meta/airapply.lua")
|
||||
dofile(we_c.modpath.."/commands/meta/noiseapply2d.lua")
|
||||
-- Meta Commands
|
||||
dofile(we_c.modpath.."/commands/meta/init.lua")
|
||||
|
||||
-- Selection Tools
|
||||
dofile(we_c.modpath.."/commands/selectors/init.lua")
|
||||
|
@ -52,6 +48,9 @@ dofile(we_c.modpath.."/commands/selectors/init.lua")
|
|||
-- Measure Tools
|
||||
dofile(we_c.modpath.."/commands/measure/init.lua")
|
||||
|
||||
-- Wireframe
|
||||
dofile(we_c.modpath.."/commands/wireframe/init.lua")
|
||||
|
||||
dofile(we_c.modpath.."/commands/extra/saplingaliases.lua")
|
||||
dofile(we_c.modpath.."/commands/extra/basename.lua")
|
||||
|
||||
|
@ -84,9 +83,6 @@ worldedit.alias_command("naturalize", "layers")
|
|||
|
||||
worldedit.alias_command("flora", "bonemeal")
|
||||
|
||||
-- Selection Tools
|
||||
worldedit.alias_command("sfac", "sfactor")
|
||||
|
||||
-- Measure Tools
|
||||
worldedit.alias_command("mcount", "count")
|
||||
worldedit.alias_command("mfacing", "mface")
|
||||
|
|
|
@ -1,37 +1,26 @@
|
|||
function worldeditadditions_core.register_command(name, def)
|
||||
-- TODO: Implement our own deep copy function here
|
||||
-- Depending on a Minetest-specific addition here makes be very uneasy
|
||||
-- ...especially since it's not obvious at first glance that this isn't a
|
||||
-- core feature provided by Lua itself
|
||||
local def = table.copy(def)
|
||||
|
||||
assert(
|
||||
def.privs,
|
||||
"Error: No privileges specified in definition of command '"..name.."'."
|
||||
)
|
||||
|
||||
def.require_pos = def.require_pos or 0
|
||||
|
||||
assert(def.require_pos >= 0 and def.require_pos < 3)
|
||||
|
||||
if def.params == "" and not def.parse then
|
||||
def.parse = function(params_text) return true end
|
||||
else
|
||||
assert(
|
||||
def.parse,
|
||||
"Error: No parameter parsing function specified, even though parameters were specified in definition of command '"..name.."'."
|
||||
)
|
||||
function worldeditadditions_core.check_command(name, def)
|
||||
if not (name and #name > 0) then
|
||||
return false, "Error: No command name."
|
||||
end
|
||||
|
||||
assert(
|
||||
def.nodes_needed == nil or type(def.nodes_needed) == "function",
|
||||
"Error: nodes_needed must be either not specified or be a function that returns the number of nodes that could potentially be changed for a given set fo parsed parameters in definition of command '"..name.."'"
|
||||
)
|
||||
|
||||
assert(
|
||||
def.func,
|
||||
"Error: 'func' is not defined. It must be defined to the function to call to run the command in definition of command '"..name.."'."
|
||||
)
|
||||
|
||||
return def
|
||||
if not def.privs then
|
||||
return false, "Error: privs is nill. Expected table."
|
||||
end
|
||||
def.require_pos = def.require_pos or 0
|
||||
if not (def.require_pos >= 0 and def.require_pos < 3) then
|
||||
return false, "Error: require_pos must be greater than -1 and less than 3."
|
||||
end
|
||||
if not def.parse then
|
||||
if def.params == "" then
|
||||
def.parse = function(params_text) return true end
|
||||
else
|
||||
return false, "Error: parse function is invalid."
|
||||
end
|
||||
end
|
||||
if not (def.nodes_needed == nil or type(def.nodes_needed) == "function") then
|
||||
return false, "Error: nodes_needed must be nil or function."
|
||||
end
|
||||
if not def.func then
|
||||
return false, "Error: main function is invalid."
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
local we_c = worldeditadditions_core
|
||||
function we_c.override_command(name, def)
|
||||
local success, def = we_c.check(name, def)
|
||||
|
||||
local def = table.copy(def)
|
||||
local success, err = we_c.check_command(name, def)
|
||||
|
||||
if not success then
|
||||
return false, def
|
||||
error(err)
|
||||
return false
|
||||
end
|
||||
|
||||
minetest.override_chatcommand("/" .. name, {
|
||||
|
@ -16,3 +18,18 @@ function we_c.override_command(name, def)
|
|||
})
|
||||
worldedit.registered_commands[name] = def
|
||||
end
|
||||
|
||||
function we_c.alias_override(alias, original)
|
||||
if not worldedit.registered_commands[original] then
|
||||
minetest.log("error", "worldedit_shortcommands: original " .. original .. " does not exist")
|
||||
return
|
||||
end
|
||||
if minetest.chatcommands["/" .. alias] then
|
||||
minetest.override_chatcommand("/" .. alias, minetest.chatcommands["/" .. original])
|
||||
worldedit.registered_commands[alias] = worldedit.registered_commands[original]
|
||||
else
|
||||
minetest.register_chatcommand("/" .. alias, minetest.chatcommands["/" .. original])
|
||||
worldedit.registered_commands[alias] = worldedit.registered_commands[original]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
local we_c = worldeditadditions_core
|
||||
function we_c.register_command(name, def)
|
||||
local success, def = we_c.check(name, def)
|
||||
|
||||
local def = table.copy(def)
|
||||
local success, err = we_c.check_command(name, def)
|
||||
if not success then
|
||||
return false, def
|
||||
return false, err
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("/" .. name, {
|
||||
|
@ -16,3 +16,17 @@ function we_c.register_command(name, def)
|
|||
})
|
||||
worldedit.registered_commands[name] = def
|
||||
end
|
||||
|
||||
function we_c.alias_command(alias, original)
|
||||
if not worldedit.registered_commands[original] then
|
||||
minetest.log("error", "worldedit_shortcommands: original " .. original .. " does not exist")
|
||||
return
|
||||
end
|
||||
if minetest.chatcommands["/" .. alias] then
|
||||
minetest.log("error", "worldedit_shortcommands: alias " .. alias .. " already exists")
|
||||
return
|
||||
end
|
||||
|
||||
minetest.register_chatcommand("/" .. alias, minetest.chatcommands["/" .. original])
|
||||
worldedit.registered_commands[alias] = worldedit.registered_commands[original]
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue