2022-09-18 23:18:03 +00:00
local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3
2024-01-02 16:59:51 +00:00
---
-- @module worldeditadditions
2021-02-07 23:39:09 +00:00
-- ███████ ██████ █████ ██ ███████ ██████ ██████ ██ ██ ███ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██
-- ███████ ██ ███████ ██ █████ ██ ██ ██ ██ ██ █ ██ ██ ██ ██
-- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██
-- ███████ ██████ ██ ██ ███████ ███████ ███████ ██████ ██████ ███ ███ ██ ████
--- Scales the defined region down by the given scale factor in the given directions.
2024-01-02 16:59:51 +00:00
-- You probably want worldeditadditions.scale, which scales in both directions.
2021-02-07 23:39:09 +00:00
-- @param pos1 Vector Position 1 of the defined region,
-- @param pos2 Vector Position 2 of the defined region.
-- @param scale Vector The scale factor - as a vector - by which to scale down.
2021-02-18 00:30:24 +00:00
-- @param anchor Vector The direction to scale in - as a vector. e.g. { x = -1, y = 1, z = -1 } would mean scale in the negative x, positive y, and nevative z directions.
2021-02-07 23:39:09 +00:00
-- @return boolean, string|table Whether the operation was successful or not. If not, then an error messagea as a string is also passed. If it was, then a statistics object is returned instead.
2021-02-18 00:30:24 +00:00
function worldeditadditions . scale_down ( pos1 , pos2 , scale , anchor )
2022-09-18 23:18:03 +00:00
pos1 , pos2 = Vector3.sort ( pos1 , pos2 )
scale = Vector3.clone ( scale )
2021-02-07 23:39:09 +00:00
if scale.x > 1 or scale.y > 1 or scale.z > 1 or scale.x < - 1 or scale.y < - 1 or scale.z < - 1 then
return false , " Error: Scale factor vectors may not mix values -1 < factor < 1 and (1 < factor or factor < -1) - in other words, you can't scale both up and down at the same time (try worldeditadditions.scale, which automatically applies such scale factor vectors as 2 successive operations) "
end
2021-02-18 00:30:24 +00:00
if anchor.x == 0 or anchor.y == 0 or anchor.z == 0 then
return false , " Error: One of the components of the anchor vector was 0 (anchor components should either be greater than or less than 0 to indicate the anchor to scale in.) "
2021-02-07 23:39:09 +00:00
end
2022-09-18 23:18:03 +00:00
local scale_down = ( 1 / scale ) : floor ( )
local size = pos2 - pos1
2021-02-18 02:18:34 +00:00
if size.x < scale_down.x or size.y < scale_down.y or size.z < scale.z then
2022-09-18 23:18:03 +00:00
return false , " Error: Area isn't big enough to apply scale down by " .. scale .. " . "
2021-02-18 02:18:34 +00:00
end
2022-09-18 23:18:03 +00:00
local size_small = ( size / scale_down ) : floor ( )
2021-02-07 23:39:09 +00:00
2021-02-17 23:09:25 +00:00
local manip , area = worldedit.manip_helpers . init ( pos1 , pos2 )
2021-02-07 23:39:09 +00:00
local data = manip : get_data ( )
2022-09-18 23:18:03 +00:00
local data_copy = wea_c.table . shallowcopy ( data )
2021-02-07 23:39:09 +00:00
local node_id_air = minetest.get_content_id ( " air " )
2022-09-18 23:18:03 +00:00
local pos1_small = pos1 : clone ( )
local pos2_small = pos2 : clone ( )
2021-02-07 23:39:09 +00:00
2021-02-18 02:33:26 +00:00
if anchor.x < 1 then pos1_small.x = pos2_small.x - size_small.x
else pos2_small.x = pos1_small.x + size_small.x end
if anchor.y < 1 then pos1_small.y = pos2_small.y - size_small.y
else pos2_small.y = pos1_small.y + size_small.y end
if anchor.z < 1 then pos1_small.z = pos2_small.z - size_small.z
else pos2_small.z = pos1_small.z + size_small.z end
local stats = { updated = 0 , scale = scale_down , pos1 = pos1_small , pos2 = pos2_small }
2021-02-07 23:39:09 +00:00
-- Zero out the area we're scaling down into
for i in area : iterp ( pos1 , pos2 ) do
data_copy [ i ] = node_id_air
-- We update the entire area, even though we're scaling down
-- ....because we fill in the area we left behind with air
stats.updated = stats.updated + 1
end
for z = pos2.z , pos1.z , - 1 do
for y = pos2.y , pos1.y , - 1 do
for x = pos2.x , pos1.x , - 1 do
2022-09-18 23:18:03 +00:00
local posi_rel = Vector3.new ( x , y , z ) - pos1
2021-02-07 23:39:09 +00:00
2022-09-18 23:18:03 +00:00
local posi_copy = posi_rel / scale_down
2021-02-07 23:39:09 +00:00
2021-02-18 00:30:24 +00:00
if anchor.x < 0 then posi_copy.x = size.x - posi_copy.x end
if anchor.y < 0 then posi_copy.y = size.y - posi_copy.y end
if anchor.z < 0 then posi_copy.z = size.z - posi_copy.z end
2021-02-07 23:39:09 +00:00
2022-09-18 23:18:03 +00:00
posi_copy = pos1 + posi_copy
2021-02-07 23:39:09 +00:00
local i_source = area : index ( x , y , z )
local i_target = area : index ( posi_copy.x , posi_copy.y , posi_copy.z )
-- Technically we could save some operations here by not setting
-- the target multiple times per copy, but the calculations
-- above are probably a lot more taxing
-- TODO Be more intelligent about deciding what node to replace with here
data_copy [ i_target ] = data [ i_source ]
end
end
end
-- Save the modified nodes back to disk & return
worldedit.manip_helpers . finish ( manip , data_copy )
2021-02-18 02:18:34 +00:00
return true , stats
2021-02-07 23:39:09 +00:00
end