Merge pull request #1 from sbrl/master

Update 2.2
This commit is contained in:
VorTechnix 2021-03-01 13:27:35 -08:00 committed by GitHub
commit 7f4ebb8b8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 305 additions and 78 deletions

@ -2,7 +2,10 @@
It's about time I started a changelog! This will serve from now on as the main changelog for WorldEditAdditions.
## v1.11 (unreleased)
## v1.12 (unreleased)
- Add `//srect` (_select rectangle_) - thanks, @VorTechnix!
## v1.11: The big data update (25th January 2021)
- Add `//scale` (currently **experimental**)
- Scale operations that scale up and down at the same time are split into 2 separate operations automatically (scaling up is always performed first)
- `//count`: Make numbers human-readable
@ -15,8 +18,12 @@ It's about time I started a changelog! This will serve from now on as the main c
- If you encounter any other issues with it over large areas (particularly 2000x150x2000 and larger), please let me know
- Bugfix: Fix obscure crash in calls to `human_size` ("unknown" will now be returned if passed junk)
- `//many` can now be used with commands with no arguments.
- `//conv`, `//erode`, `//fillcaves`: Treat liquids as air
- Add new [cloud wand](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#cloud-wand)
- `//conv`, `//erode`: Minor refactoring to improve code clarity
## v1.10 (16th January 2021)
## v1.10: The tidyup update (16th January 2021)
- `//maze`: Fix some parts of generated mazes staying solid
- `//maze`, `//maze3d`: Allow non-number seeds (existing seeds aren't affected - they will still produce identical output)
- `//many`: Improve format of progress messages, add ETA

@ -482,6 +482,15 @@ Executes the given command, and then clips the result to the largest ellipsoid t
//ellipsoidapply layers desert_sand sand 2 desert_sandstone 4 sandstone 10
```
## `//srect [<axis1> [<axis2>]] <length>`
Short for _select rectangle_. Sets the pos2 at a set distance along 2 axes from pos1. If the axes aren't specified, defaults to positive y and the direction you are facing. Implementation thanks to @VorTechnix.
```
//srect x z 10
//srect 3
//srect -z y 25
```
## `//y`
Confirms the execution of a command if it could potentially affect a large number of nodes and take a while. This is a regular WorldEdit command.
@ -530,3 +539,10 @@ You can change the maximum range with the `maxdist` subcommand:
```
Note that the number there isn't in blocks (because hard maths). It is however proportional to the distance the wand will raycast looks for nodes, so a higher value will result in it raycasting further.
## Cloud Wand
The cloud wand (`worldeditadditions:cloudwand`) is a another variant the above _Far Wand_. It looks like this: ![A picture of the far wand](https://raw.githubusercontent.com/sbrl/Minetest-WorldEditAdditions/master/worldeditadditions_farwand/textures/worldeditadditions_cloudwand.png)
Unlike the other 2 wands, this wand functions in an additive manner. Left-click on a node to expand the currently defined region (creating a new one if one isn't defined already) to include that node. Right click to clear the currently defined region.
It has the range of the _Far Wand_ mentioned above too, so you can select nodes from a great distance. It also abides by preferences set via the `//farwand` chat command.

@ -42,3 +42,29 @@ Clearing large amounts of foliage is easy!
```
Adjust the numbers (and direction in the `//shift` command) to match your scenario.
## Flower Field
Make a flower field with no grass.
```
//overlay air 20 flowers:geranium 1
```
Adjust the air value to change flower density.
```
//overlay air 80 flowers:rose 1 flowers:tulip 1 flowers:dandelion_yellow 1 flowers:chrysanthemum_green 1 flowers:geranium 1 flowers:viola 1 flowers:dandelion_white 1 flowers:tulip_black 1
```
When working with many types of flowers the air values need to be higher to compensate. The best equation for the air value that I've found is `<desired spacing> * <sum of flower probabilities>`.
## Grass Field
Make a grass field
```
//overlay air 36 default:grass_2 2 default:grass_3 2 default:grass_4 1 default:grass_5 1
```
Adjust the air value to change grass density. As with flower field the best equation for the air value is `<desired spacing> * <sum of flower probabilities>`.

@ -13,6 +13,7 @@ _(Do you have a cool build that you used WorldEditAdditions to build? [Get in to
## Table of Contents
- [Quick Command Reference](#quick-command-reference) (including links to detailed explanations)
- [Using the Far Wand](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#far-wand)
- [Using the Cloud Wand](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#cloud-wand)
- [Detailed Chat Command Explanations](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md)
- [Chat Command Cookbook](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Cookbook.md)
- [Troubleshooting](#troubleshooting)
@ -38,7 +39,8 @@ The detailed explanations have moved! Check them out [here](https://github.com/s
### Misc
- [`//replacemix <target_node> [<chance>] <replace_node_a> [<chance_a>] [<replace_node_b> [<chance_b>]] [<replace_node_N> [<chance_N>]] ....`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#replacemix-target_node-chance-replace_node_a-chance_a-replace_node_b-chance_b-replace_node_n-chance_n-)
- [`//floodfill [<replace_node> [<radius>]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#floodfill-replace_node-radius-floodfill)
- [`//scale <axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#scale-axis-scale_factor--factor_x-factor_y-factor_z-anchor_x-anchor_y-anchor_z)
- [`//scale <axis> <scale_factor> | <factor_x> [<factor_y> <factor_z> [<anchor_x> <anchor_y> <anchor_z>]]`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#scale-axis-scale_factor--factor_x-factor_y-factor_z-anchor_x-anchor_y-anchor_z) **experimental**
- [`//srect [<axis1> [<axis2>]] <length>`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#srect-axis1-axis2-length)
### Terrain
- [`//overlay <node_name_a> [<chance_a>] <node_name_b> [<chance_b>] [<node_name_N> [<chance_N>]] ...`](https://github.com/sbrl/Minetest-WorldEditAdditions/blob/master/Chat-Command-Reference.md#overlay-node_name_a-chance_a-node_name_b-chance_b-node_name_n-chance_n-)

@ -57,13 +57,9 @@ function worldeditadditions.convolve(pos1, pos2, kernel, kernel_size)
local node_id_air = minetest.get_content_id("air")
local heightmap = worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
local heightmap, heightmap_size = worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
local heightmap_conv = worldeditadditions.shallowcopy(heightmap)
local heightmap_size = {}
heightmap_size[0] = (pos2.z - pos1.z) + 1
heightmap_size[1] = (pos2.x - pos1.x) + 1
worldeditadditions.conv.convolve(
heightmap_conv,
heightmap_size,

@ -18,18 +18,18 @@ function worldeditadditions.conv.convolve(heightmap, heightmap_size, matrix, mat
border_size[1] = (matrix_size[1]-1) / 2 -- width
-- print("[convolve] matrix_size", matrix_size[0], matrix_size[1])
-- print("[convolve] border_size", border_size[0], border_size[1])
-- print("[convolve] heightmap_size: ", heightmap_size[0], heightmap_size[1])
-- print("[convolve] heightmap_size: ", heightmap_size.z, heightmap_size.x)
--
-- print("[convolve] z: from", (heightmap_size[0]-border_size[0]) - 1, "to", border_size[0], "step", -1)
-- print("[convolve] x: from", (heightmap_size[1]-border_size[1]) - 1, "to", border_size[1], "step", -1)
-- print("[convolve] z: from", (heightmap_size.z-border_size[0]) - 1, "to", border_size[0], "step", -1)
-- print("[convolve] x: from", (heightmap_size.x-border_size[1]) - 1, "to", border_size[1], "step", -1)
-- Convolve over only the bit that allows us to use the full convolution matrix
for z = (heightmap_size[0]-border_size[0]) - 1, border_size[0], -1 do
for x = (heightmap_size[1]-border_size[1]) - 1, border_size[1], -1 do
for z = (heightmap_size.z-border_size[0]) - 1, border_size[0], -1 do
for x = (heightmap_size.x-border_size[1]) - 1, border_size[1], -1 do
local total = 0
local hi = (z * heightmap_size[1]) + x
local hi = (z * heightmap_size.x) + x
-- print("[convolve/internal] z", z, "x", x, "hi", hi)
-- No continue statement in Lua :-/
@ -40,7 +40,7 @@ function worldeditadditions.conv.convolve(heightmap, heightmap_size, matrix, mat
local cz = z + (mz - border_size[0])
local cx = x + (mx - border_size[1])
local i = (cz * heightmap_size[1]) + cx
local i = (cz * heightmap_size.x) + cx
-- A value of -1 = nothing in this column (so we should ignore it)
if heightmap[i] ~= -1 then

@ -9,9 +9,10 @@ function worldeditadditions.erode.run(pos1, pos2, algorithm, params)
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data()
local heightmap_size = {}
heightmap_size[0] = (pos2.z - pos1.z) + 1
heightmap_size[1] = (pos2.x - pos1.x) + 1
local heightmap_size = {
z = (pos2.z - pos1.z) + 1,
x = (pos2.x - pos1.x) + 1
}
local region_height = (pos2.y - pos1.y) + 1
@ -20,7 +21,7 @@ function worldeditadditions.erode.run(pos1, pos2, algorithm, params)
-- print("[erode.run] algorithm: "..algorithm..", params:");
-- print(worldeditadditions.map_stringify(params))
-- worldeditadditions.print_2d(heightmap, heightmap_size[1])
-- worldeditadditions.print_2d(heightmap, heightmap_size.x)
local success, msg, stats
if algorithm == "snowballs" then
success, msg = worldeditadditions.erode.snowballs(heightmap, heightmap_eroded, heightmap_size, region_height, params)

@ -18,11 +18,11 @@ local function snowball(heightmap, normalmap, heightmap_size, startpos, params)
for i = 1, params.max_steps do
local x = pos.x
local z = pos.z
local hi = math.floor(z+0.5)*heightmap_size[1] + math.floor(x+0.5)
local hi = math.floor(z+0.5)*heightmap_size.x + math.floor(x+0.5)
-- Stop if we go out of bounds
if x < 0 or z < 0
or x >= heightmap_size[1]-1 or z >= heightmap_size[0]-1 then
-- print("[snowball] hit edge; stopping at ("..x..", "..z.."), (bounds @ "..(heightmap_size[1]-1)..", "..(heightmap_size[0]-1)..")", "x", x, "/", heightmap_size[1]-1, "z", z, "/", heightmap_size[0]-1)
or x >= heightmap_size.x-1 or z >= heightmap_size.z-1 then
-- print("[snowball] hit edge; stopping at ("..x..", "..z.."), (bounds @ "..(heightmap_size.x-1)..", "..(heightmap_size.z-1)..")", "x", x, "/", heightmap_size.x-1, "z", z, "/", heightmap_size.z-1)
return true, i
end
@ -100,8 +100,8 @@ function worldeditadditions.erode.snowballs(heightmap_initial, heightmap, height
local success, steps = snowball(
heightmap, normals, heightmap_size,
{
x = math.random() * (heightmap_size[1] - 1),
z = math.random() * (heightmap_size[0] - 1)
x = math.random() * (heightmap_size.x - 1),
z = math.random() * (heightmap_size.z - 1)
},
params
)

@ -27,7 +27,7 @@ function worldeditadditions.fillcaves(pos1, pos2, node_name)
for y = pos2.y, pos1.y, -1 do
local i = area:index(x, y, z)
local is_air = worldeditadditions.is_airlike(data[i])
local is_air = worldeditadditions.is_airlike(data[i]) or worldeditadditions.is_liquidlike(data[i])
local is_ignore = data[i] == node_id_ignore
-- If the previous node was air and this one isn't, then we've found the top level

@ -0,0 +1,3 @@
function worldeditadditions.noise.engine_perlin_2d(x, y)
end

@ -0,0 +1,9 @@
-- ███ ███ █████ ██ ██ ███████ ██████ ██████
-- ████ ████ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ████ ██ ███████ █████ █████ █████ ██ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██ ██ ██ ██ ██ ███████ ███████ ███████ ██████
function worldeditadditions.noise.make_2d(size, noise_func)
-- TODO: Follow https://www.redblobgames.com/maps/terrain-from-noise/
end

@ -0,0 +1,3 @@
worldeditadditions.noise = {}
dofile(worldeditadditions.modpath.."/lib/noise/alg_perlin.lua")

@ -0,0 +1,38 @@
--- Applies a layer of 2D noise over the terrain in the defined region.
-- @module worldeditadditions.noise2d
-- ███ ██ ██████ ██ ███████ ███████ ██████ ██████
-- ████ ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ██ ██ ██ ██ ██ ███████ █████ █████ ██ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
-- ██ ████ ██████ ██ ███████ ███████ ███████ ██████
--- Applies a layer of 2d noise over the terrain in the defined region.
-- @param pos1 Vector pos1 of the defined region
-- @param pos2 Vector pos2 of the defined region
-- @param noise_params table A noise parameters table. Will be passed unmodified to PerlinNoise() from the Minetest API.
function worldeditadditions.noise2d(pos1, pos2, noise_params)
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
-- pos2 will always have the highest co-ordinates now
-- Fetch the nodes in the specified area
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
local data = manip:get_data()
local heightmap_old, heightmap_size = worldeditadditions.make_heightmap(
pos1, pos2,
manip, area,
data
)
local heightmap_new = worldeditadditions.shallowcopy(heightmap_old)
local perlin_map = PerlinNoiseMap(noise_params, heightmap_size)
local stats = { added = 0, removed = 0 }
-- Save the modified nodes back to disk & return
-- No need to save - this function doesn't actually change anything
worldedit.manip_helpers.finish(manip, data)
return true, stats
end

@ -7,7 +7,7 @@
-- @param manip VoxelManip The VoxelManip object.
-- @param area area The associated area object.
-- @param data table The associated data object.
-- @return table The ZERO-indexed heightmap data (as 1 single flat array).
-- @return table,table The ZERO-indexed heightmap data (as 1 single flat array), followed by the size of the heightmap in the form { 0 = size_z, 1 = size_x }.
function worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
-- z y x (in reverse for little-endian machines) is the preferred loop order, but that isn't really possible here
@ -20,7 +20,7 @@ function worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
-- Scan each column top to bottom
for y = pos2.y+1, pos1.y, -1 do
local i = area:index(x, y, z)
if not worldeditadditions.is_airlike(data[i]) then
if not (worldeditadditions.is_airlike(data[i]) or worldeditadditions.is_liquidlike(data[i])) then
-- It's the first non-airlike node in this column
-- Start heightmap values from 1 (i.e. there's at least 1 node in the column)
heightmap[hi] = (y - pos1.y) + 1
@ -34,7 +34,12 @@ function worldeditadditions.make_heightmap(pos1, pos2, manip, area, data)
end
end
return heightmap
local heightmap_size = {
z = (pos2.z - pos1.z) + 1,
x = (pos2.x - pos1.x) + 1
}
return heightmap, heightmap_size
end
--- Calculates a normal map for the given heightmap.
@ -45,27 +50,27 @@ end
-- @param heightmap_size int[] The size of the heightmap in the form [ z, x ]
-- @return Vector[] The calculated normal map, in the same form as the input heightmap. Each element of the array is a 3D Vector (i.e. { x, y, z }) representing a normal.
function worldeditadditions.calculate_normals(heightmap, heightmap_size)
-- print("heightmap_size: "..heightmap_size[1].."x"..heightmap_size[0])
-- print("heightmap_size: "..heightmap_size.x.."x"..heightmap_size.z)
local result = {}
for z = heightmap_size[0]-1, 0, -1 do
for x = heightmap_size[1]-1, 0, -1 do
for z = heightmap_size.z-1, 0, -1 do
for x = heightmap_size.x-1, 0, -1 do
-- Algorithm ref https://stackoverflow.com/a/13983431/1460422
-- Also ref Vector.mjs, which I implemented myself (available upon request)
local hi = z*heightmap_size[1] + x
local hi = z*heightmap_size.x + x
-- Default to this pixel's height
local up = heightmap[hi]
local down = heightmap[hi]
local left = heightmap[hi]
local right = heightmap[hi]
if z - 1 > 0 then up = heightmap[(z-1)*heightmap_size[1] + x] end
if z + 1 < heightmap_size[0]-1 then down = heightmap[(z+1)*heightmap_size[1] + x] end
if x - 1 > 0 then left = heightmap[z*heightmap_size[1] + (x-1)] end
if x + 1 < heightmap_size[1]-1 then right = heightmap[z*heightmap_size[1] + (x+1)] end
if z - 1 > 0 then up = heightmap[(z-1)*heightmap_size.x + x] end
if z + 1 < heightmap_size.z-1 then down = heightmap[(z+1)*heightmap_size.x + x] end
if x - 1 > 0 then left = heightmap[z*heightmap_size.x + (x-1)] end
if x + 1 < heightmap_size.x-1 then right = heightmap[z*heightmap_size.x + (x+1)] end
-- print("[normals] UP | index", (z-1)*heightmap_size[1] + x, "z", z, "z-1", z - 1, "up", up, "limit", 0)
-- print("[normals] DOWN | index", (z+1)*heightmap_size[1] + x, "z", z, "z+1", z + 1, "down", down, "limit", heightmap_size[1]-1)
-- print("[normals] LEFT | index", z*heightmap_size[1] + (x-1), "x", x, "x-1", x - 1, "left", left, "limit", 0)
-- print("[normals] RIGHT | index", z*heightmap_size[1] + (x+1), "x", x, "x+1", x + 1, "right", right, "limit", heightmap_size[1]-1)
-- print("[normals] UP | index", (z-1)*heightmap_size.x + x, "z", z, "z-1", z - 1, "up", up, "limit", 0)
-- print("[normals] DOWN | index", (z+1)*heightmap_size.x + x, "z", z, "z+1", z + 1, "down", down, "limit", heightmap_size.x-1)
-- print("[normals] LEFT | index", z*heightmap_size.x + (x-1), "x", x, "x-1", x - 1, "left", left, "limit", 0)
-- print("[normals] RIGHT | index", z*heightmap_size.x + (x+1), "x", x, "x+1", x + 1, "right", right, "limit", heightmap_size.x-1)
result[hi] = worldeditadditions.vector.normalize({
x = left - right,
@ -82,10 +87,11 @@ end
function worldeditadditions.apply_heightmap_changes(pos1, pos2, area, data, heightmap_old, heightmap_new, heightmap_size)
local stats = { added = 0, removed = 0 }
local node_id_air = minetest.get_content_id("air")
local node_id_ignore = minetest.get_content_id("ignore")
for z = heightmap_size[0], 0, -1 do
for x = heightmap_size[1], 0, -1 do
local hi = z*heightmap_size[1] + x
for z = heightmap_size.z, 0, -1 do
for x = heightmap_size.x, 0, -1 do
local hi = z*heightmap_size.x + x
local height_old = heightmap_old[hi]
local height_new = heightmap_new[hi]
@ -95,12 +101,23 @@ function worldeditadditions.apply_heightmap_changes(pos1, pos2, area, data, heig
if height_old == height_new then
-- noop
elseif height_new < height_old then
local node_id_replace = data[area:index(
pos1.x + x,
pos1.y + height_old + 1,
pos1.z + z
)]
-- Unlikely, but if it can happen, it *will* happen.....
if node_id_replace == node_id_ignore then
node_id_replace = node_id_air
end
stats.removed = stats.removed + (height_old - height_new)
local y = height_new
while y < height_old do
local ci = area:index(pos1.x + x, pos1.y + y, pos1.z + z)
-- print("[conv/save] remove at y", y, "→", pos1.y + y, "current:", minetest.get_name_from_content_id(data[ci]))
data[ci] = node_id_air
if data[ci] ~= node_id_ignore then
data[ci] = node_id_replace
end
y = y + 1
end
else -- height_new > height_old
@ -113,7 +130,9 @@ function worldeditadditions.apply_heightmap_changes(pos1, pos2, area, data, heig
while y < height_new do
local ci = area:index(pos1.x + x, pos1.y + y, pos1.z + z)
-- print("[conv/save] add at y", y, "→", pos1.y + y, "current:", minetest.get_name_from_content_id(data[ci]))
data[ci] = node_id
if data[ci] ~= node_id_ignore then
data[ci] = node_id
end
y = y + 1
end
end

@ -40,3 +40,36 @@ function worldeditadditions.vector.floor(v)
-- Some vectors are 2d
if v.z then v.z = math.floor(v.z) end
end
--- Determines if the target point is contained within the defined worldedit region.
-- @param pos1 Vector pos1 of the defined region.
-- @param pos2 Vector pos2 of the defined region.
-- @param target Vector The target vector to check.
-- @return boolean Whether the given target is contained within the defined worldedit region.
function worldeditadditions.vector.is_contained(pos1, pos2, target)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
return pos1.x >= target.x
and pos1.y >= target.y
and pos1.z >= target.z
and pos2.x <= target.x
and pos2.y <= target.y
and pos2.z <= target.z
end
--- Expands the defined region to include the given point.
-- @param pos1 Vector pos1 of the defined region.
-- @param pos2 Vector pos2 of the defined region.
-- @param target Vector The target vector to include.
function worldeditadditions.vector.expand_region(pos1, pos2, target)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
if target.x < pos1.x then pos1.x = target.x end
if target.y < pos1.y then pos1.y = target.y end
if target.z < pos1.z then pos1.z = target.z end
if target.x > pos2.x then pos2.x = target.x end
if target.y > pos2.y then pos2.y = target.y end
if target.z > pos2.z then pos2.z = target.z end
return pos1, pos2
end

@ -28,7 +28,6 @@ worldedit.register_command("scale", {
privs = { worldedit = true },
require_pos = 2,
parse = function(params_text)
print("[DEBUG//scale] got params_text '"..params_text.."'")
if not params_text then params_text = "" end
local parts = worldeditadditions.split(params_text, "%s+", false)

@ -3,42 +3,36 @@
-- ███████ ██████ █████ ██ ██
-- ██ ██ ██ ██ ██ ██
-- ███████ ██ ██ ███████ ██████ ██
-- local -- TODO: set this to local once development is finished
function parse_params_srect(params_text)
local wea = worldeditadditions
local find = wea.split(params_text, "%s", false)
local ax1, ax2, len = find[1], find[2], find[table.maxn(find)]
-- If ax1 is bad set to player facing dir
if ax1 == len or not ax1:match('[xyz]') then ax1 = "get"
else
local success, value = wea.getsign(ax1, "int")
if not success then return success, value
else ax1 = { value, ax1:gsub('[^xyz]',''):sub(1,1) }
end
end
-- If ax2 is bad set to +y
if not ax2 or ax2 == len or not ax2:match('[xyz]') then ax2 = "y" end
local success, value = wea.getsign(ax2, "int")
if not success then return success, value end
ax2 = { value, ax2:gsub('[^xyz]',''):sub(1,1) }
len = tonumber(len)
-- If len == nill cancel the operation
if len == nil then
return false, "No length specified."
end
return true, ax1, ax2, len
end
worldedit.register_command("srect", {
params = "[<axis1> [<axis2>]] <length>",
description = "Set WorldEdit region position 2 at a set distance along 2 axes.",
privs = {worldedit=true},
privs = { worldedit = true },
require_pos = 1,
parse = function(params_text)
local values = {parse_params_srect(params_text)}
return unpack(values)
local wea = worldeditadditions
local find = wea.split(params_text, "%s", false)
local ax1, ax2, len = find[1], find[2], find[table.maxn(find)]
-- If ax1 is bad set to player facing dir
if ax1 == len or not ax1:match('[xyz]') then ax1 = "get"
else
local success, value = wea.getsign(ax1, "int")
if not success then return success, value
else ax1 = { value, ax1:gsub('[^xyz]', ''):sub(1, 1) } end
end
-- If ax2 is bad set to +y
if not ax2 or ax2 == len or not ax2:match('[xyz]') then ax2 = "y" end
local success, value = wea.getsign(ax2, "int")
if not success then return success, value end
ax2 = { value, ax2:gsub('[^xyz]', ''):sub(1, 1) }
len = tonumber(len)
-- If len == nill cancel the operation
if len == nil then
return false, "No length specified."
end
return true, ax1, ax2, len
end,
func = function(name, axis1, axis2, len)
if axis1 == "get" then axis1 = worldeditadditions.player_axis2d(name) end

@ -1 +1 @@
{"modelVersion":2,"piskel":{"name":"worldedit_wand","description":"","fps":0,"height":16,"width":16,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":3,\"chunks\":[{\"layout\":[[0],[1],[2]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAQCAYAAABQrvyxAAACWklEQVRIS82WXUhTYRjH/yd31ra2viQ5cxFRJlbUKre6CI2gm6AP2kV4FVSGXiZFfoSErCi76OOmQLqJERWkkMFuKqQsShIxvQrbyMK2yMztzNa2sz1xFkdW2fa+BwXP9ft/zu/3vO/zniP4BJCtAniVlNAeCAvQ8WSelJIQlJGekmFoAFcNqW4hWVYasdT6DJOxXQi2ylx5wb9JoNfvCFv2V8PT+ZwrrLpSt43SkRSK4mJWAEnA0Mgusc8XoEk5lm3bj0QaAw3buBiEpjI7OStWYai3D+XbV+Po4w9cBajDRtqm6RUY+VaJlJxGkfgURx5Vo/XlT2aG6YU3qyQKhcOwbHCh6WE/cwHlKqYF1O5f7DZxAWy9V0IJOYX0FCE5fh/Heg5y5f8AvV5TRcGBXqx3O1F/5y27RPtvCRXeZTeiP5TkglCz3p2mbA3e/D+QbXskikbGYSmrhPduH7OEdoxUEF6I3HuDNz8j4GmPk6QFUQhmK075hue1xH/hmvfaabFZRGb5Wpy91TNvJfKCXajdTeJEEIogoqXzvS4JaYkZ4Uiceya0uSiULwh147iLPo8GIDo24tztFwXX//0dVM+0CjHyNY7Lb9ivx9yZypdnAmqpcVOpIYYvE1F4/WNMmVyRM24TrVuhXyJfnhnm/KE1ZBEFfFQW4VrXEHNOE5krCS6Qk57N5DDKiCkZtD0Y5cqqInMhwQ3ReECikmIrxhQrrvgGufOzLcENoHayuXYHJULDKHcUo77jE3eN2ZTgfrl2pi8dttEyRUZdF/uf50yDfcL/XReD1oRfxpVUxz8/zhUAAAAASUVORK5CYII=\"}]}"]}}
{"modelVersion":2,"piskel":{"name":"worldedit_wand","description":"","fps":0,"height":16,"width":16,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":4,\"chunks\":[{\"layout\":[[0],[1],[2],[3]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAQCAYAAACm53kpAAACy0lEQVRYR92XXUhTYRzGn5M7083NMks2FxGmYp9Wal2ERhBE0Ad5EUIQfRh6mRT5ERJiX3bRx42BdBMjKkgpI28qLE3KEimlC5kbmugmms6d6dqX/ziLI1aa77sYjM71nv/7/H7vOe/ZEcwCSJ8JvPMZUGt1CAjjmnmZQoJNQnBKgqoUXDMMxbGkXaXGMt0bON27YKuSuPJKXSIi+4gbU9MBpKcmMs8QmjcJ9L6XsOVAPgoaWpmDsws36Sk46UeMRwwJgA9QlbFL2G+2klNyh8ZNe4PoKt3G3WHYIVFCggYulwfjTg82ZiYzzxDK04yUlbka3W0dyNi+Bide9DOH5dJUrydFRrgCLN+y4ZeCiBFf4dizfFS1f+fqYLFNULxWxb37cu/Zhe7kGcjucEC7PgflTzuZCwRuYlaAvPtXm+K4ALY+TCav5EdwiuAbe4STLYe48vKt/6V3FLFqEUP2MTidE+i5wi7xF9DbhXlk62rDutwslNz/zC6h9qcEGT7HqEan3ccFIWdrdsaFZvDmX7dbyGRcAa/Pjz5rf0jAYB27xD8gq/cYyDU5Bm1aNmoedDBLUB4DGYQXYu65y5t/8vwDydDHj+4VwpE4L+C5giwyLHFB0Ohw1twT9RJ+f3HxSFwQrmKfkRI0ImaWr8WFuy3/rYS/gl0u2k3iuA0BQURlQ19YEgxLNXBMerjPBOVciHR+Uai6Uzk0PGCFaNqAi/feLvr7+W5HGcIy6sH1j3yvt7kSIpVnAqoszKUUlRsj4y7UNA8xZeaKOJ8bR+krw5cQyTwzzKXDqaQVBXwNxONWYzdzThERSQiWf+8Lrc8FcqZgM5nUEtyBGVQ/HuDKyiWjUQI3RNlBAyUn6TAU0OGG+RN3PtokcAPIO1lRtIO89h5kmJJQUj/IPSOaJHCXV563a0f0lBiQUNzI/uU338F4unkirA6KxH/N/wCTFeDHmzMoJgAAAABJRU5ErkJggg==\"}]}"]}}

@ -4,6 +4,8 @@ worldeditadditions.farwand = {
local modpath = minetest.get_modpath("worldeditadditions_farwand")
dofile(modpath.."/lib/do_raycast.lua")
dofile(modpath.."/lib/farwand.lua")
dofile(modpath.."/lib/cloudwand.lua")
dofile(modpath.."/lib/chatcommand.lua")
dofile(modpath.."/lib/settings.lua")

@ -0,0 +1,60 @@
local function 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
local function clear_points(name, pos)
worldedit.pos1[name] = nil
worldedit.pos2[name] = nil
worldedit.marker_update(name)
worldedit.set_pos[name] = nil
worldedit.player_notify(name, "Region cleared")
end
minetest.register_tool(":worldeditadditions:cloudwand", {
description = "WorldEditAdditions far-reaching point cloud wand",
inventory_image = "worldeditadditions_cloudwand.png",
on_place = function(itemstack, player, pointed_thing)
local name = player:get_player_name()
-- print("[farwand] on_place", name)
-- Right click when pointing at something
-- Pointed thing: https://rubenwardy.com/minetest_modding_book/lua_api.html#pointed_thing
clear_points(name)
end,
on_use = function(itemstack, player, pointed_thing)
local name = player:get_player_name()
-- print("[farwand] on_use", name)
local looking_pos, node_id = worldeditadditions.farwand.do_raycast(player)
add_point(name, looking_pos)
-- Left click when pointing at something or nothing
end,
on_secondary_use = function(itemstack, player, pointed_thing)
local name = player:get_player_name()
-- Right click when pointing at nothing
-- print("[farwand] on_secondary_use", name)
clear_points(name)
end
})

@ -0,0 +1,17 @@
--- worldeditadditions.raycast() wrapper
function worldeditadditions.farwand.do_raycast(player)
if player == nil then return nil end
local player_name = player:get_player_name()
if worldeditadditions.farwand.player_data[player_name] == nil then
worldeditadditions.farwand.player_data[player_name] = { maxdist = 1000, skip_liquid = true }
end
local looking_pos, node_id = worldeditadditions.raycast(
player,
worldeditadditions.farwand.player_data[player_name].maxdist,
worldeditadditions.farwand.player_data[player_name].skip_liquid
)
return looking_pos, node_id
end

@ -5,6 +5,7 @@ local function set_pos1(name, pos)
worldedit.mark_pos1(name)
worldedit.player_notify(name, "pos1 set to "..worldeditadditions.vector.tostring(pos))
else
worldedit.player_notify(name, "Error: Too far away (try raising your maxdist with //farwand maxdist <number>)")
-- print("[set_pos1]", name, "nil")
end
end
@ -15,6 +16,7 @@ local function set_pos2(name, pos)
worldedit.mark_pos2(name)
worldedit.player_notify(name, "pos2 set to "..worldeditadditions.vector.tostring(pos))
else
worldedit.player_notify(name, "Error: Too far away (try raising your maxdist with //farwand maxdist <number>)")
-- print("[set_pos2]", name, "nil")
end
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B