mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-11-26 09:03:01 +00:00
Add //layers command
Also add aliases //naturalise and //naturalize
This commit is contained in:
parent
905ccc2d50
commit
75a17ed64f
9 changed files with 134 additions and 12 deletions
|
@ -210,7 +210,7 @@ Here are all the above examples together:
|
||||||
```
|
```
|
||||||
|
|
||||||
### `//convolve <kernel> [<width>[,<height>]] [<sigma>]`
|
### `//convolve <kernel> [<width>[,<height>]] [<sigma>]`
|
||||||
Advanced version of `//smooth` from we_env, and so far the _only_ WorldEditAdditions command to have any aliases (`//smoothadv` and `//conv`).
|
Advanced version of `//smooth` from we_env, and one of the few WorldEditAdditions commands to have any aliases (`//smoothadv` and `//conv`).
|
||||||
|
|
||||||
Extracts a heightmap from the defined region and then proceeds to [convolve](https://en.wikipedia.org/wiki/Kernel_(image_processing)) over it with the specified kernel. The kernel can be thought of as the filter that will be applied to the heightmap. Once done, the newly convolved heightmap is applied to the terrain.
|
Extracts a heightmap from the defined region and then proceeds to [convolve](https://en.wikipedia.org/wiki/Kernel_(image_processing)) over it with the specified kernel. The kernel can be thought of as the filter that will be applied to the heightmap. Once done, the newly convolved heightmap is applied to the terrain.
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ dofile(worldeditadditions.modpath.."/utils/tables.lua")
|
||||||
dofile(worldeditadditions.modpath.."/utils.lua")
|
dofile(worldeditadditions.modpath.."/utils.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/floodfill.lua")
|
dofile(worldeditadditions.modpath.."/lib/floodfill.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/overlay.lua")
|
dofile(worldeditadditions.modpath.."/lib/overlay.lua")
|
||||||
|
dofile(worldeditadditions.modpath.."/lib/layers.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/ellipsoid.lua")
|
dofile(worldeditadditions.modpath.."/lib/ellipsoid.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/torus.lua")
|
dofile(worldeditadditions.modpath.."/lib/torus.lua")
|
||||||
dofile(worldeditadditions.modpath.."/lib/walls.lua")
|
dofile(worldeditadditions.modpath.."/lib/walls.lua")
|
||||||
|
|
58
worldeditadditions/lib/layers.lua
Normal file
58
worldeditadditions/lib/layers.lua
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
--- Overlap command. Places a specified node on top of each column.
|
||||||
|
-- @module worldeditadditions.overlay
|
||||||
|
|
||||||
|
function worldeditadditions.layers(pos1, pos2, node_weights)
|
||||||
|
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 node_id_ignore = minetest.get_content_id("ignore")
|
||||||
|
|
||||||
|
local node_ids, node_ids_count = worldeditadditions.unwind_node_list(node_weights)
|
||||||
|
|
||||||
|
-- minetest.log("action", "pos1: " .. worldeditadditions.vector.tostring(pos1))
|
||||||
|
-- minetest.log("action", "pos2: " .. worldeditadditions.vector.tostring(pos2))
|
||||||
|
for i,v in ipairs(node_ids) do
|
||||||
|
print("[layer] i", i, "node id", v)
|
||||||
|
end
|
||||||
|
-- z y x is the preferred loop order, but that isn't really possible here
|
||||||
|
|
||||||
|
local changes = { replaced = 0, skipped_columns = 0 }
|
||||||
|
for z = pos2.z, pos1.z, -1 do
|
||||||
|
for x = pos2.x, pos1.x, -1 do
|
||||||
|
local next_index = 1 -- We use table.insert() in make_weighted
|
||||||
|
local placed_node = false
|
||||||
|
|
||||||
|
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_ignore = data[i] == node_id_ignore
|
||||||
|
|
||||||
|
if not is_air and not is_ignore then
|
||||||
|
-- It's not an airlike node or something else odd
|
||||||
|
data[i] = node_ids[next_index]
|
||||||
|
next_index = next_index + 1
|
||||||
|
changes.replaced = changes.replaced + 1
|
||||||
|
|
||||||
|
-- If we're done replacing nodes in this column, move to the next one
|
||||||
|
if next_index > #node_ids then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not placed_node then
|
||||||
|
changes.skipped_columns = changes.skipped_columns + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save the modified nodes back to disk & return
|
||||||
|
worldedit.manip_helpers.finish(manip, data)
|
||||||
|
|
||||||
|
return changes
|
||||||
|
end
|
|
@ -9,7 +9,6 @@ function worldeditadditions.overlay(pos1, pos2, node_weights)
|
||||||
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
|
local manip, area = worldedit.manip_helpers.init(pos1, pos2)
|
||||||
local data = manip:get_data()
|
local data = manip:get_data()
|
||||||
|
|
||||||
local node_id_air = minetest.get_content_id("air")
|
|
||||||
local node_id_ignore = minetest.get_content_id("ignore")
|
local node_id_ignore = minetest.get_content_id("ignore")
|
||||||
|
|
||||||
local node_ids, node_ids_count = worldeditadditions.make_weighted(node_weights)
|
local node_ids, node_ids_count = worldeditadditions.make_weighted(node_weights)
|
||||||
|
@ -28,7 +27,7 @@ function worldeditadditions.overlay(pos1, pos2, node_weights)
|
||||||
for y = pos2.y, pos1.y, -1 do
|
for y = pos2.y, pos1.y, -1 do
|
||||||
local i = area:index(x, y, z)
|
local i = area:index(x, y, z)
|
||||||
|
|
||||||
local is_air = data[i] == node_id_air
|
local is_air = worldeditadditions.is_airlike(data[i])
|
||||||
if not is_air then -- wielded_light nodes are airlike too
|
if not is_air then -- wielded_light nodes are airlike too
|
||||||
local this_node_name = minetest.get_name_from_content_id(data[i])
|
local this_node_name = minetest.get_name_from_content_id(data[i])
|
||||||
is_air = is_air or worldeditadditions.string_starts(this_node_name, "wielded_light")
|
is_air = is_air or worldeditadditions.string_starts(this_node_name, "wielded_light")
|
||||||
|
|
|
@ -6,10 +6,23 @@ function worldeditadditions.make_weighted(tbl)
|
||||||
local next_id = minetest.get_content_id(node_name)
|
local next_id = minetest.get_content_id(node_name)
|
||||||
print("[make_weighted] seen "..node_name.." @ weight "..weight.." → id "..next_id)
|
print("[make_weighted] seen "..node_name.." @ weight "..weight.." → id "..next_id)
|
||||||
for i = 1, weight do
|
for i = 1, weight do
|
||||||
table.insert(
|
table.insert(result, next_id)
|
||||||
result,
|
end
|
||||||
next_id
|
end
|
||||||
)
|
return result, #result
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Unwinds a list of { node = string, weight = number } tables into a list of node ids.
|
||||||
|
-- The node ids will be repeated multiple times according to their weights
|
||||||
|
-- (e.g. an entry with a weight of 2 will be repeated twice).
|
||||||
|
-- @param list table[] The list to unwind.
|
||||||
|
-- @return number[],number The unwound list of node ids, follows by the number of node ids in total.
|
||||||
|
function worldeditadditions.unwind_node_list(list)
|
||||||
|
local result = {}
|
||||||
|
for i,item in ipairs(list) do
|
||||||
|
local node_id = minetest.get_content_id(item.node)
|
||||||
|
for i = 1, item.weight do
|
||||||
|
table.insert(result, node_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return result, #result
|
return result, #result
|
||||||
|
@ -41,6 +54,10 @@ function worldeditadditions.is_airlike(id)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
-- Just in case
|
-- Just in case
|
||||||
|
if worldeditadditions.string_starts(this_node_name, "wielded_light") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
-- Just in case
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -155,8 +155,10 @@ end
|
||||||
|
|
||||||
--- Parses a list of strings as a list of weighted nodes - e.g. like in the //mix command.
|
--- Parses a list of strings as a list of weighted nodes - e.g. like in the //mix command.
|
||||||
-- @param parts string[] The list of strings to parse (try worldeditadditions.split)
|
-- @param parts string[] The list of strings to parse (try worldeditadditions.split)
|
||||||
|
-- @param as_list bool If true, then table.insert() successive { node = string, weight = number } subtables when parsing instead of populating as an associative array.
|
||||||
-- @returns table A table in the form node_name => weight.
|
-- @returns table A table in the form node_name => weight.
|
||||||
function worldeditadditions.parse_weighted_nodes(parts)
|
function worldeditadditions.parse_weighted_nodes(parts, as_list)
|
||||||
|
if as_list == nil then as_list = false end
|
||||||
local MODE_EITHER = 1
|
local MODE_EITHER = 1
|
||||||
local MODE_NODE = 2
|
local MODE_NODE = 2
|
||||||
|
|
||||||
|
@ -177,23 +179,31 @@ function worldeditadditions.parse_weighted_nodes(parts)
|
||||||
print("mode: either");
|
print("mode: either");
|
||||||
local chance = tonumber(part)
|
local chance = tonumber(part)
|
||||||
if not chance then
|
if not chance then
|
||||||
|
print("not a chance, trying a node name")
|
||||||
local node_name = worldedit.normalize_nodename(part)
|
local node_name = worldedit.normalize_nodename(part)
|
||||||
if not node_name then
|
if not node_name then
|
||||||
return false, "Error: Invalid number '"..chance.."'"
|
return false, "Error: Invalid number '"..chance.."'"
|
||||||
end
|
end
|
||||||
if last_node_name then
|
if last_node_name then
|
||||||
result[last_node_name] = 1
|
if as_list then table.insert(result, { node = last_node_name, weight = 1 })
|
||||||
|
else result[last_node_name] = 1 end
|
||||||
end
|
end
|
||||||
last_node_name = node_name
|
last_node_name = node_name
|
||||||
mode = MODE_EITHER
|
mode = MODE_EITHER
|
||||||
else
|
else
|
||||||
result[last_node_name] = math.floor(chance)
|
print("it's a chance: ", chance, "for", last_node_name)
|
||||||
|
chance = math.floor(chance)
|
||||||
|
if as_list then table.insert(result, { node = last_node_name, weight = chance })
|
||||||
|
else result[last_node_name] = chance end
|
||||||
|
last_node_name = nil
|
||||||
mode = MODE_NODE
|
mode = MODE_NODE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if last_node_name then
|
if last_node_name then
|
||||||
result[last_node_name] = 1
|
print("caught trailing node name: ", last_node_name)
|
||||||
|
if as_list then table.insert(result, { node = last_node_name, weight = 1 })
|
||||||
|
else result[last_node_name] = 1 end
|
||||||
end
|
end
|
||||||
|
|
||||||
return true, result
|
return true, result
|
||||||
|
|
|
@ -69,7 +69,7 @@ worldedit.register_command("convolve", {
|
||||||
|
|
||||||
|
|
||||||
minetest.log("action", name.." used //convolve at "..worldeditadditions.vector.tostring(worldedit.pos1[name]).." - "..worldeditadditions.vector.tostring(worldedit.pos2[name])..", adding "..stats.added.." nodes and removing "..stats.removed.." nodes in "..time_taken.."s")
|
minetest.log("action", name.." used //convolve at "..worldeditadditions.vector.tostring(worldedit.pos1[name]).." - "..worldeditadditions.vector.tostring(worldedit.pos2[name])..", adding "..stats.added.." nodes and removing "..stats.removed.." nodes in "..time_taken.."s")
|
||||||
return true, "Added "..stats.added.." and removed "..stats.removed.." nodes"
|
return true, "Added "..stats.added.." and removed "..stats.removed.." nodes in " .. time_taken .. "s"
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
36
worldeditadditions_commands/commands/layers.lua
Normal file
36
worldeditadditions_commands/commands/layers.lua
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
-- ██████ ██ ██ ███████ ██████ ██ █████ ██ ██
|
||||||
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
-- ██ ██ ██ ██ █████ ██████ ██ ███████ ████
|
||||||
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||||
|
-- ██████ ████ ███████ ██ ██ ███████ ██ ██ ██
|
||||||
|
worldedit.register_command("layers", {
|
||||||
|
params = "[<node_name_1> [<layer_count_1>]] [<node_name_2> [<layer_count_2>]] ...",
|
||||||
|
description = "Replaces the topmost non-airlike nodes with layers of the given nodes from top to bottom. Like WorldEdit for MC's //naturalize command. Default: dirt_with_grass dirt 3",
|
||||||
|
privs = { worldedit = true },
|
||||||
|
require_pos = 2,
|
||||||
|
parse = function(params_text)
|
||||||
|
if not params_text or params_text == "" then
|
||||||
|
params_text = "dirt_with_grass dirt 3"
|
||||||
|
end
|
||||||
|
|
||||||
|
local success, node_list = worldeditadditions.parse_weighted_nodes(
|
||||||
|
worldeditadditions.split(params_text, "%s+", false),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
return success, node_list
|
||||||
|
end,
|
||||||
|
nodes_needed = function(name)
|
||||||
|
return worldedit.volume(worldedit.pos1[name], worldedit.pos2[name])
|
||||||
|
end,
|
||||||
|
func = function(name, node_list)
|
||||||
|
local start_time = os.clock()
|
||||||
|
local changes = worldeditadditions.layers(worldedit.pos1[name], worldedit.pos2[name], node_list)
|
||||||
|
local time_taken = os.clock() - start_time
|
||||||
|
|
||||||
|
minetest.log("action", name .. " used //layers at " .. worldeditadditions.vector.tostring(worldedit.pos1[name]) .. ", replacing " .. changes.replaced .. " nodes and skipping " .. changes.skipped_columns .. " columns in " .. time_taken .. "s")
|
||||||
|
return true, changes.replaced .. " nodes replaced and " .. changes.skipped_columns .. " columns skipped in " .. time_taken .. "s"
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
worldedit.alias_command("naturalise", "layers")
|
||||||
|
worldedit.alias_command("naturalize", "layers")
|
|
@ -19,6 +19,7 @@ dofile(we_c.modpath.."/multi.lua")
|
||||||
|
|
||||||
dofile(we_c.modpath.."/commands/floodfill.lua")
|
dofile(we_c.modpath.."/commands/floodfill.lua")
|
||||||
dofile(we_c.modpath.."/commands/overlay.lua")
|
dofile(we_c.modpath.."/commands/overlay.lua")
|
||||||
|
dofile(we_c.modpath.."/commands/layers.lua")
|
||||||
dofile(we_c.modpath.."/commands/ellipsoid.lua")
|
dofile(we_c.modpath.."/commands/ellipsoid.lua")
|
||||||
dofile(we_c.modpath.."/commands/torus.lua")
|
dofile(we_c.modpath.."/commands/torus.lua")
|
||||||
dofile(we_c.modpath.."/commands/walls.lua")
|
dofile(we_c.modpath.."/commands/walls.lua")
|
||||||
|
|
Loading…
Reference in a new issue