mirror of
https://github.com/sbrl/Minetest-WorldEditAdditions.git
synced 2024-12-23 12:05:01 +00:00
86 lines
3.9 KiB
Lua
86 lines
3.9 KiB
Lua
local wea_c = worldeditadditions_core
|
|
local Vector3 = wea_c.Vector3
|
|
local NodeListMatcher = wea_c.NodeListMatcher
|
|
|
|
---
|
|
-- @module worldeditadditions
|
|
|
|
|
|
-- ███ ██ ██████ ██████ ███████
|
|
-- ████ ██ ██ ██ ██ ██ ██
|
|
-- ██ ██ ██ ██ ██ ██ ██ █████
|
|
-- ██ ██ ██ ██ ██ ██ ██ ██
|
|
-- ██ ████ ██████ ██████ ███████
|
|
--
|
|
-- █████ ██████ ██████ ██ ██ ██
|
|
-- ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
-- ███████ ██████ ██████ ██ ████
|
|
-- ██ ██ ██ ██ ██ ██
|
|
-- ██ ██ ██ ██ ███████ ██
|
|
|
|
--- Like ellipsoidapply and airapply, but much more flexible, allowing custom sets of nodes to filter changes on. Any changes that don't replace nodes that match the given nodelist will be discarded.
|
|
-- Takes a backup copy of the defined region, runs the given function, and then
|
|
-- restores the bits around the edge that aren't inside the largest ellipsoid that will fit inside the defined region.
|
|
-- @param pos1 Vector3 The 1st position defining the region boundary
|
|
-- @param pos2 Vector3 The 2nd positioon defining the region boundary
|
|
-- @param nodelist string[] The nodelist to match changes against. Any changes that don't replace nodes on this list will be discarded. The following special node names are also accepted: liquid, air. Note that all node names MUST be normalised, otherwise they won't be recognised!
|
|
-- @param func function The function to call that performs the action in question. It is expected that the given function will accept no arguments.
|
|
function worldeditadditions.nodeapply(pos1, pos2, nodelist, func)
|
|
local time_taken_all = wea_c.get_ms_time()
|
|
pos1, pos2 = Vector3.sort(pos1, pos2)
|
|
-- pos2 will always have the highest co-ordinates now
|
|
|
|
-- Fetch the nodes in the specified area
|
|
local manip_before, area_before = worldedit.manip_helpers.init(pos1, pos2)
|
|
local data_before = manip_before:get_data()
|
|
|
|
local time_taken_fn = wea_c.get_ms_time()
|
|
func()
|
|
time_taken_fn = wea_c.get_ms_time() - time_taken_fn
|
|
|
|
local manip_after, area_after = worldedit.manip_helpers.init(pos1, pos2)
|
|
local data_after = manip_after:get_data()
|
|
|
|
-- Cache node ids for speed. Even if minetest.get_content_id is efficient, an extra function call is still relatively expensive when called 10K+ times on a large region.
|
|
local success, matcher = NodeListMatcher.new(nodelist)
|
|
if not success then return success, matcher end
|
|
|
|
local allowed_changes = 0
|
|
local denied_changes = 0
|
|
for z = pos2.z, pos1.z, -1 do
|
|
for y = pos2.y, pos1.y, -1 do
|
|
for x = pos2.x, pos1.x, -1 do
|
|
local i_before = area_before:index(x, y, z)
|
|
local i_after = area_after:index(x, y, z)
|
|
|
|
-- Filter on the list of node ids
|
|
local allow_replacement = matcher:match_id(data_before[i_before])
|
|
|
|
-- Roll back any changes that aren't allowed
|
|
-- ...but ensure we only count changed nodes
|
|
if not allow_replacement then
|
|
if data_after[i_after] ~= data_before[i_before] then
|
|
allowed_changes = allowed_changes + 1
|
|
end
|
|
-- Roll back
|
|
data_after[i_after] = data_before[i_before]
|
|
elseif data_after[i_after] ~= data_before[i_before] then
|
|
denied_changes = denied_changes + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Save the modified nodes back to disk & return
|
|
-- No need to save - this function doesn't actually change anything
|
|
worldedit.manip_helpers.finish(manip_after, data_after)
|
|
|
|
|
|
time_taken_all = wea_c.get_ms_time() - time_taken_all
|
|
return true, {
|
|
all = time_taken_all,
|
|
fn = time_taken_fn,
|
|
allowed_changes = allowed_changes,
|
|
denied_changes = denied_changes
|
|
}
|
|
end
|