2012-10-14 03:45:50 +02:00
worldedit = worldedit or { }
2013-07-12 20:22:30 +02:00
local minetest = minetest --local copy of global
2012-10-14 03:45:50 +02:00
--modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions
worldedit.sort_pos = function ( pos1 , pos2 )
pos1 = { x = pos1.x , y = pos1.y , z = pos1.z }
pos2 = { x = pos2.x , y = pos2.y , z = pos2.z }
if pos1.x > pos2.x then
pos2.x , pos1.x = pos1.x , pos2.x
end
if pos1.y > pos2.y then
pos2.y , pos1.y = pos1.y , pos2.y
end
if pos1.z > pos2.z then
pos2.z , pos1.z = pos1.z , pos2.z
end
return pos1 , pos2
end
--determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume
worldedit.volume = function ( pos1 , pos2 )
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
return ( pos2.x - pos1.x + 1 ) * ( pos2.y - pos1.y + 1 ) * ( pos2.z - pos1.z + 1 )
end
--sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled
2014-07-01 01:13:44 +02:00
worldedit.set = function ( pos1 , pos2 , nodenames )
2014-07-10 08:34:27 +02:00
local oneNode
2014-07-01 01:13:44 +02:00
if type ( nodenames ) == ' string ' then
2014-07-10 08:34:27 +02:00
oneNode = true
else
oneNode = false
2014-07-01 01:13:44 +02:00
end
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-07-12 20:22:30 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
2013-07-21 22:54:25 +02:00
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
2013-06-23 02:59:23 +02:00
2013-07-21 22:54:25 +02:00
--fill emerged area with ignore
2013-07-12 20:22:30 +02:00
local nodes = { }
2013-07-21 22:54:25 +02:00
local ignore = minetest.get_content_id ( " ignore " )
for i = 1 , worldedit.volume ( emerged_pos1 , emerged_pos2 ) do
nodes [ i ] = ignore
end
--fill selected area with node
2014-07-01 01:13:44 +02:00
local node_ids = { }
for i , v in ipairs ( nodenames ) do
node_ids [ i ] = minetest.get_content_id ( nodenames [ i ] )
end
2014-07-10 08:34:27 +02:00
if oneNode then --only one type of node
local id = node_ids
2014-07-07 20:06:33 +02:00
for i in area : iterp ( pos1 , pos2 ) do nodes [ i ] = id end --fill area with node
2014-07-10 08:34:27 +02:00
else --several types of nodes specified
2014-07-07 01:42:02 +02:00
local id_count , rand = # node_ids , math.random
2014-07-07 20:06:33 +02:00
for i in area : iterp ( pos1 , pos2 ) do nodes [ i ] = node_ids [ rand ( id_count ) ] end --fill randomly with all types of specified nodes
2012-10-14 03:45:50 +02:00
end
2013-06-23 02:59:23 +02:00
2013-07-12 20:22:30 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2012-10-14 03:45:50 +02:00
return worldedit.volume ( pos1 , pos2 )
end
--replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced
2013-06-23 18:46:59 +02:00
worldedit.replace = function ( pos1 , pos2 , searchnode , replacenode )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-07-21 22:54:25 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
local nodes = manip : get_data ( )
local searchnode_id = minetest.get_content_id ( searchnode )
local replacenode_id = minetest.get_content_id ( replacenode )
local count = 0
for i in area : iterp ( pos1 , pos2 ) do --replace searchnode with replacenode
if nodes [ i ] == searchnode_id then
nodes [ i ] = replacenode_id
count = count + 1
end
2012-10-14 03:45:50 +02:00
end
2013-07-21 22:54:25 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
return count
2012-10-14 03:45:50 +02:00
end
2013-01-13 00:29:57 +01:00
--replaces all nodes other than `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced
2013-07-21 22:54:25 +02:00
worldedit.replaceinverse = function ( pos1 , pos2 , searchnode , replacenode )
2013-01-13 00:29:57 +01:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-07-21 22:54:25 +02:00
--set up voxel manipulator
local manip = minetest.get_voxel_manip ( )
local emerged_pos1 , emerged_pos2 = manip : read_from_map ( pos1 , pos2 )
local area = VoxelArea : new ( { MinEdge = emerged_pos1 , MaxEdge = emerged_pos2 } )
local nodes = manip : get_data ( )
local searchnode_id = minetest.get_content_id ( searchnode )
local replacenode_id = minetest.get_content_id ( replacenode )
2013-01-13 00:29:57 +01:00
local count = 0
2013-07-21 22:54:25 +02:00
for i in area : iterp ( pos1 , pos2 ) do --replace anything that is not searchnode with replacenode
if nodes [ i ] ~= searchnode_id then
nodes [ i ] = replacenode_id
count = count + 1
2013-01-13 00:29:57 +01:00
end
end
2013-07-21 22:54:25 +02:00
--update map nodes
manip : set_data ( nodes )
manip : write_to_map ( )
manip : update_map ( )
2013-01-13 00:29:57 +01:00
return count
end
2014-07-07 01:59:56 +02:00
--copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied
2013-12-21 00:41:13 +01:00
worldedit.copy = function ( pos1 , pos2 , axis , amount ) --wip: replace the old version below
2013-08-01 04:15:08 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
if amount == 0 then
return
end
local other1 , other2
if axis == " x " then
other1 , other2 = " y " , " z "
elseif axis == " y " then
other1 , other2 = " x " , " z "
else --axis == "z"
other1 , other2 = " x " , " y "
end
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
--prepare slice along axis
local extent = {
[ axis ] = 1 ,
[ other1 ] = pos2 [ other1 ] - pos1 [ other1 ] + 1 ,
[ other2 ] = pos2 [ other2 ] - pos1 [ other2 ] + 1 ,
}
local nodes = { }
local schematic = { size = extent , data = nodes }
local currentpos = { x = pos1.x , y = pos1.y , z = pos1.z }
local stride = { x = 1 , y = extent.x , z = extent.x * extent.y }
local get_node = minetest.get_node
for index1 = 1 , extent [ axis ] do --go through each slice
--copy slice into schematic
local newindex1 = ( index1 + offset [ axis ] ) * stride [ axis ] + 1 --offset contributed by axis plus 1 to make it 1-indexed
for index2 = 1 , extent [ other1 ] do
local newindex2 = newindex1 + ( index2 + offset [ other1 ] ) * stride [ other1 ]
for index3 = 1 , extent [ other2 ] do
local i = newindex2 + ( index3 + offset [ other2 ] ) * stride [ other2 ]
2013-08-16 22:57:35 +02:00
local node = get_node ( pos )
node.param1 = 255 --node will always appear
nodes [ i ] = node
2013-08-01 04:15:08 +02:00
end
end
--copy schematic to target
currentpos [ axis ] = currentpos [ axis ] + amount
place_schematic ( currentpos , schematic )
--wip: copy meta
currentpos [ axis ] = currentpos [ axis ] + 1
end
return worldedit.volume ( pos1 , pos2 )
end
2014-07-01 01:14:14 +02:00
worldedit.copy2 = function ( pos1 , pos2 , direction , volume )
2014-07-07 01:42:02 +02:00
-- the overlap shouldn't matter as long as we
-- 1) start at the furthest separated corner
-- 2) complete an edge before moving inward, either edge works
-- 3) complete a face before moving inward, similarly
--
-- to do this I
-- 1) find the furthest destination in the direction, of each axis
-- 2) call those the furthest separated corner
-- 3) make sure to iterate inward from there
-- 4) nested loop to make sure complete edge, complete face, then complete cube.
2014-07-01 01:14:14 +02:00
local get_node , get_meta , add_node = minetest.get_node , minetest.get_meta , minetest.add_node
2014-07-07 01:42:02 +02:00
local somemeta = get_meta ( pos1 ) -- hax lol
local to_table = somemeta.to_table
local from_table = somemeta.from_table
somemeta = nil
2014-07-01 01:14:14 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
2014-07-07 01:42:02 +02:00
local sx , sy , sz -- direction sign
local ix , iy , iz -- initial destination
local ex , ey , ez -- final destination
local originalx , originaly , originalz -- source
-- vim -> :'<,'>s/\<\([ioes]\?\)x\>/\1y/g
if direction.x > 0 then
originalx = pos2.x
ix = originalx + direction.x
ex = pos1.x + direction.x
sx = - 1
elseif direction.x < 0 then
originalx = pos1.x
ix = originalx + direction.x
ex = pos2.x + direction.x
sx = 1
else
originalx = pos1.x
ix = originalx -- whatever
ex = pos2.x
sx = 1
end
2014-07-01 01:14:14 +02:00
2014-07-07 01:42:02 +02:00
if direction.y > 0 then
originaly = pos2.y
iy = originaly + direction.y
ey = pos1.y + direction.y
sy = - 1
elseif direction.y < 0 then
originaly = pos1.y
iy = originaly + direction.y
ey = pos2.y + direction.y
sy = 1
else
originaly = pos1.y
iy = originaly -- whatever
ey = pos2.y
sy = 1
end
2014-07-01 01:14:14 +02:00
2014-07-07 01:42:02 +02:00
if direction.z > 0 then
originalz = pos2.z
iz = originalz + direction.z
ez = pos1.z + direction.z
sz = - 1
elseif direction.z < 0 then
originalz = pos1.z
iz = originalz + direction.z
ez = pos2.z + direction.z
sz = 1
else
originalz = pos1.z
iz = originalz -- whatever
ez = pos2.z
sz = 1
end
-- print('copy',originalx,ix,ex,sx,originaly,iy,ey,sy,originalz,iz,ez,sz)
local ox , oy , oz
ox = originalx
for x = ix , ex , sx do
oy = originaly
for y = iy , ey , sy do
oz = originalz
for z = iz , ez , sz do
-- reusing pos1/pos2 as source/dest here
pos1.x , pos1.y , pos1.z = ox , oy , oz
pos2.x , pos2.y , pos2.z = x , y , z
local node = get_node ( pos1 )
2014-07-01 01:14:14 +02:00
local meta = to_table ( get_meta ( pos1 ) ) --get meta of current node
2014-07-07 01:42:02 +02:00
add_node ( pos2 , node )
from_table ( get_meta ( pos2 ) , meta )
oz = oz + sz
end
oy = oy + sy
end
ox = ox + sx
end
end
2014-07-07 01:59:56 +02:00
--duplicates the region defined by positions `pos1` and `pos2` `amount` times with offset vector `direction`, returning the number of nodes stacked
2014-07-07 01:42:02 +02:00
worldedit.stack2 = function ( pos1 , pos2 , direction , amount , finished )
local i = 0
local translated = { x = 0 , y = 0 , z = 0 }
local function nextone ( )
if i <= amount then
i = i + 1
translated.x = translated.x + direction.x
translated.y = translated.y + direction.y
translated.z = translated.z + direction.z
worldedit.copy2 ( pos1 , pos2 , translated , volume )
minetest.after ( 0 , nextone )
else
if finished then
finished ( )
end
end
end
nextone ( )
2014-07-07 01:59:56 +02:00
return worldedit.volume ( pos1 , pos2 ) * amount
2014-07-01 01:14:14 +02:00
end
2012-10-14 03:45:50 +02:00
--copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied
2013-07-31 06:02:37 +02:00
worldedit.copy = function ( pos1 , pos2 , axis , amount )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-08-01 04:15:08 +02:00
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
2013-07-31 06:02:37 +02:00
local get_node , get_meta , add_node = minetest.get_node , minetest.get_meta , minetest.add_node
2012-10-14 03:45:50 +02:00
if amount < 0 then
local pos = { x = pos1.x , y = 0 , z = 0 }
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
2013-07-31 06:02:37 +02:00
local node = get_node ( pos ) --obtain current node
local meta = get_meta ( pos ) : to_table ( ) --get meta of current node
2012-10-14 03:45:50 +02:00
local value = pos [ axis ] --store current position
pos [ axis ] = value + amount --move along axis
2013-07-31 06:02:37 +02:00
add_node ( pos , node ) --copy node to new position
get_meta ( pos ) : from_table ( meta ) --set metadata of new node
2012-10-14 03:45:50 +02:00
pos [ axis ] = value --restore old position
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
else
local pos = { x = pos2.x , y = 0 , z = 0 }
while pos.x >= pos1.x do
pos.y = pos2.y
while pos.y >= pos1.y do
pos.z = pos2.z
while pos.z >= pos1.z do
2013-07-31 06:02:37 +02:00
local node = get_node ( pos ) --obtain current node
local meta = get_meta ( pos ) : to_table ( ) --get meta of current node
2012-10-14 03:45:50 +02:00
local value = pos [ axis ] --store current position
pos [ axis ] = value + amount --move along axis
2013-07-31 06:02:37 +02:00
add_node ( pos , node ) --copy node to new position
get_meta ( pos ) : from_table ( meta ) --set metadata of new node
2012-10-14 03:45:50 +02:00
pos [ axis ] = value --restore old position
pos.z = pos.z - 1
end
pos.y = pos.y - 1
end
pos.x = pos.x - 1
end
end
return worldedit.volume ( pos1 , pos2 )
end
--moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved
2013-07-31 06:02:37 +02:00
worldedit.move = function ( pos1 , pos2 , axis , amount )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-08-01 04:15:08 +02:00
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
--wip: move slice by slice using schematic method in the move axis and transfer metadata in separate loop (and if the amount is greater than the length in the axis, copy whole thing at a time and erase original after, using schematic method)
2013-07-31 06:02:37 +02:00
local get_node , get_meta , add_node , remove_node = minetest.get_node , minetest.get_meta , minetest.add_node , minetest.remove_node
2012-10-14 03:45:50 +02:00
if amount < 0 then
local pos = { x = pos1.x , y = 0 , z = 0 }
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
2013-07-31 06:02:37 +02:00
local node = get_node ( pos ) --obtain current node
local meta = get_meta ( pos ) : to_table ( ) --get metadata of current node
remove_node ( pos )
2012-10-14 03:45:50 +02:00
local value = pos [ axis ] --store current position
pos [ axis ] = value + amount --move along axis
2013-07-31 06:02:37 +02:00
add_node ( pos , node ) --move node to new position
get_meta ( pos ) : from_table ( meta ) --set metadata of new node
2012-10-14 03:45:50 +02:00
pos [ axis ] = value --restore old position
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
else
local pos = { x = pos2.x , y = 0 , z = 0 }
while pos.x >= pos1.x do
pos.y = pos2.y
while pos.y >= pos1.y do
pos.z = pos2.z
while pos.z >= pos1.z do
2013-07-31 06:02:37 +02:00
local node = get_node ( pos ) --obtain current node
local meta = get_meta ( pos ) : to_table ( ) --get metadata of current node
remove_node ( pos )
2012-10-14 03:45:50 +02:00
local value = pos [ axis ] --store current position
pos [ axis ] = value + amount --move along axis
2013-07-31 06:02:37 +02:00
add_node ( pos , node ) --move node to new position
get_meta ( pos ) : from_table ( meta ) --set metadata of new node
2012-10-14 03:45:50 +02:00
pos [ axis ] = value --restore old position
pos.z = pos.z - 1
end
pos.y = pos.y - 1
end
pos.x = pos.x - 1
end
end
return worldedit.volume ( pos1 , pos2 )
end
--duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked
2013-08-01 04:15:08 +02:00
worldedit.stack = function ( pos1 , pos2 , axis , count )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
local length = pos2 [ axis ] - pos1 [ axis ] + 1
if count < 0 then
count = - count
length = - length
end
local amount = 0
local copy = worldedit.copy
for i = 1 , count do
amount = amount + length
2013-08-01 04:15:08 +02:00
copy ( pos1 , pos2 , axis , amount )
2012-10-14 03:45:50 +02:00
end
2013-07-21 22:54:25 +02:00
return worldedit.volume ( pos1 , pos2 ) * count
2012-10-14 03:45:50 +02:00
end
2013-12-21 00:41:13 +01:00
--stretches the region defined by positions `pos1` and `pos2` by an factor of positive integers `stretchx`, `stretchy`. and `stretchz` along the X, Y, and Z axes, respectively, with `pos1` as the origin, returning the number of nodes scaled, the new scaled position 1, and the new scaled position 2
worldedit.stretch = function ( pos1 , pos2 , stretchx , stretchy , stretchz ) --wip: test this
2013-06-18 21:05:49 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-06-23 02:59:23 +02:00
--prepare schematic of large node
2013-06-23 18:46:59 +02:00
local get_node , get_meta , place_schematic = minetest.get_node , minetest.get_meta , minetest.place_schematic
2013-08-16 22:57:35 +02:00
local placeholder_node = { name = " " , param1 = 255 , param2 = 0 }
2013-06-23 02:59:23 +02:00
local nodes = { }
2013-12-21 00:41:13 +01:00
for i = 1 , stretchx * stretchy * stretchz do
2013-06-23 02:59:23 +02:00
nodes [ i ] = placeholder_node
end
2013-12-21 00:41:13 +01:00
local schematic = { size = { x = stretchx , y = stretchy , z = stretchz } , data = nodes }
2013-07-21 22:54:25 +02:00
2013-12-21 00:41:13 +01:00
local sizex , sizey , sizez = stretchx - 1 , stretchy - 1 , stretchz - 1
2013-07-21 22:54:25 +02:00
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
2013-12-21 00:41:13 +01:00
local new_pos2 = {
x = pos1.x + ( pos2.x - pos1.x ) * stretchx + sizex ,
y = pos1.y + ( pos2.y - pos1.y ) * stretchy + sizey ,
z = pos1.z + ( pos2.z - pos1.z ) * stretchz + sizez ,
}
2013-07-31 06:02:37 +02:00
manip : read_from_map ( pos1 , new_pos2 )
2013-06-23 02:59:23 +02:00
2013-06-18 21:05:49 +02:00
local pos = { x = pos2.x , y = 0 , z = 0 }
local bigpos = { x = 0 , y = 0 , z = 0 }
while pos.x >= pos1.x do
pos.y = pos2.y
while pos.y >= pos1.y do
pos.z = pos2.z
while pos.z >= pos1.z do
2013-06-23 18:46:59 +02:00
local node = get_node ( pos ) --obtain current node
local meta = get_meta ( pos ) : to_table ( ) --get meta of current node
2013-06-23 02:59:23 +02:00
2013-12-21 00:41:13 +01:00
--calculate far corner of the big node
local posx = pos1.x + ( pos.x - pos1.x ) * stretchx
local posy = pos1.y + ( pos.y - pos1.y ) * stretchy
local posz = pos1.z + ( pos.z - pos1.z ) * stretchz
2013-06-23 02:59:23 +02:00
--create large node
2013-07-21 22:54:25 +02:00
placeholder_node.name = node.name
2013-08-16 22:57:35 +02:00
placeholder_node.param2 = node.param2
2013-06-23 02:59:23 +02:00
bigpos.x , bigpos.y , bigpos.z = posx , posy , posz
place_schematic ( bigpos , schematic )
2013-07-21 22:54:25 +02:00
--fill in large node meta
2013-12-21 00:41:13 +01:00
if next ( meta.fields ) ~= nil or next ( meta.inventory ) ~= nil then --node has meta fields
for x = 0 , sizex do
for y = 0 , sizey do
for z = 0 , sizez do
2013-07-21 22:54:25 +02:00
bigpos.x , bigpos.y , bigpos.z = posx + x , posy + y , posz + z
get_meta ( bigpos ) : from_table ( meta ) --set metadata of new node
end
2013-06-18 21:05:49 +02:00
end
end
end
pos.z = pos.z - 1
end
pos.y = pos.y - 1
end
pos.x = pos.x - 1
end
2013-12-21 00:41:13 +01:00
return worldedit.volume ( pos1 , pos2 ) * stretchx * stretchy * stretchz , pos1 , new_pos2
2013-06-18 21:05:49 +02:00
end
--transposes a region defined by the positions `pos1` and `pos2` between the `axis1` and `axis2` axes, returning the number of nodes transposed, the new transposed position 1, and the new transposed position 2
2013-08-01 04:15:08 +02:00
worldedit.transpose = function ( pos1 , pos2 , axis1 , axis2 )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2012-12-12 23:17:56 +01:00
local compare
local extent1 , extent2 = pos2 [ axis1 ] - pos1 [ axis1 ] , pos2 [ axis2 ] - pos1 [ axis2 ]
if extent1 > extent2 then
compare = function ( extent1 , extent2 )
return extent1 > extent2
end
else
compare = function ( extent1 , extent2 )
return extent1 < extent2
end
end
--calculate the new position 2 after transposition
2013-07-21 22:54:25 +02:00
local new_pos2 = { x = pos2.x , y = pos2.y , z = pos2.z }
new_pos2 [ axis1 ] = pos1 [ axis1 ] + extent2
new_pos2 [ axis2 ] = pos1 [ axis2 ] + extent1
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
local upperbound = { x = pos2.x , y = pos2.y , z = pos2.z }
if upperbound [ axis1 ] < new_pos2 [ axis1 ] then upperbound [ axis1 ] = new_pos2 [ axis1 ] end
if upperbound [ axis2 ] < new_pos2 [ axis2 ] then upperbound [ axis2 ] = new_pos2 [ axis2 ] end
manip : read_from_map ( pos1 , upperbound )
2012-12-12 23:17:56 +01:00
2012-10-14 03:45:50 +02:00
local pos = { x = pos1.x , y = 0 , z = 0 }
2013-06-23 18:46:59 +02:00
local get_node , get_meta , add_node = minetest.get_node , minetest.get_meta , minetest.add_node
2012-10-14 03:45:50 +02:00
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
local extent1 , extent2 = pos [ axis1 ] - pos1 [ axis1 ] , pos [ axis2 ] - pos1 [ axis2 ]
2012-12-12 23:17:56 +01:00
if compare ( extent1 , extent2 ) then --transpose only if below the diagonal
2013-06-23 18:46:59 +02:00
local node1 = get_node ( pos )
local meta1 = get_meta ( pos ) : to_table ( )
2012-12-12 23:17:56 +01:00
local value1 , value2 = pos [ axis1 ] , pos [ axis2 ] --save position values
pos [ axis1 ] , pos [ axis2 ] = pos1 [ axis1 ] + extent2 , pos1 [ axis2 ] + extent1 --swap axis extents
2013-06-23 18:46:59 +02:00
local node2 = get_node ( pos )
local meta2 = get_meta ( pos ) : to_table ( )
add_node ( pos , node1 )
get_meta ( pos ) : from_table ( meta1 )
2012-12-12 23:17:56 +01:00
pos [ axis1 ] , pos [ axis2 ] = value1 , value2 --restore position values
2013-06-23 18:46:59 +02:00
add_node ( pos , node2 )
get_meta ( pos ) : from_table ( meta2 )
2012-10-14 03:45:50 +02:00
end
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
2013-07-21 22:54:25 +02:00
return worldedit.volume ( pos1 , pos2 ) , pos1 , new_pos2
2012-10-14 03:45:50 +02:00
end
--flips a region defined by the positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z"), returning the number of nodes flipped
2013-08-01 04:15:08 +02:00
worldedit.flip = function ( pos1 , pos2 , axis )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-07-21 22:54:25 +02:00
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
2013-06-23 02:59:23 +02:00
--wip: flip the region slice by slice along the flip axis using schematic method
2012-10-14 03:45:50 +02:00
local pos = { x = pos1.x , y = 0 , z = 0 }
local start = pos1 [ axis ] + pos2 [ axis ]
pos2 [ axis ] = pos1 [ axis ] + math.floor ( ( pos2 [ axis ] - pos1 [ axis ] ) / 2 )
2013-07-21 22:54:25 +02:00
local get_node , get_meta , add_node = minetest.get_node , minetest.get_meta , minetest.add_node
2012-10-14 03:45:50 +02:00
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
2013-07-21 22:54:25 +02:00
local node1 = get_node ( pos )
local meta1 = get_meta ( pos ) : to_table ( )
2012-10-14 03:45:50 +02:00
local value = pos [ axis ]
pos [ axis ] = start - value
2013-07-21 22:54:25 +02:00
local node2 = get_node ( pos )
local meta2 = get_meta ( pos ) : to_table ( )
add_node ( pos , node1 )
get_meta ( pos ) : from_table ( meta1 )
2012-10-14 03:45:50 +02:00
pos [ axis ] = value
2013-07-21 22:54:25 +02:00
add_node ( pos , node2 )
get_meta ( pos ) : from_table ( meta2 )
2012-10-14 03:45:50 +02:00
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
return worldedit.volume ( pos1 , pos2 )
end
--rotates a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise around axis `axis` (90 degree increment), returning the number of nodes rotated
2013-08-01 04:15:08 +02:00
worldedit.rotate = function ( pos1 , pos2 , axis , angle )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
local axis1 , axis2
if axis == " x " then
axis1 , axis2 = " z " , " y "
elseif axis == " y " then
axis1 , axis2 = " x " , " z "
else --axis == "z"
axis1 , axis2 = " y " , " x "
end
angle = angle % 360
2012-12-12 23:17:56 +01:00
local count
2012-10-14 03:45:50 +02:00
if angle == 90 then
2013-08-01 04:15:08 +02:00
worldedit.flip ( pos1 , pos2 , axis1 )
count , pos1 , pos2 = worldedit.transpose ( pos1 , pos2 , axis1 , axis2 )
2012-10-14 03:45:50 +02:00
elseif angle == 180 then
2013-08-01 04:15:08 +02:00
worldedit.flip ( pos1 , pos2 , axis1 )
count = worldedit.flip ( pos1 , pos2 , axis2 )
2012-10-14 03:45:50 +02:00
elseif angle == 270 then
2013-08-01 04:15:08 +02:00
worldedit.flip ( pos1 , pos2 , axis2 )
count , pos1 , pos2 = worldedit.transpose ( pos1 , pos2 , axis1 , axis2 )
2012-10-14 03:45:50 +02:00
end
2012-12-12 23:17:56 +01:00
return count , pos1 , pos2
2012-10-14 03:45:50 +02:00
end
2013-01-12 22:46:40 +01:00
--rotates all oriented nodes in a region defined by the positions `pos1` and `pos2` by `angle` degrees clockwise (90 degree increment) around the Y axis, returning the number of nodes oriented
2013-08-01 04:15:08 +02:00
worldedit.orient = function ( pos1 , pos2 , angle ) --wip: support 6D facedir rotation along arbitrary axis
2013-01-12 22:46:40 +01:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-06-23 18:46:59 +02:00
local registered_nodes = minetest.registered_nodes
2013-01-12 22:46:40 +01:00
local wallmounted = {
[ 90 ] = { [ 0 ] = 0 , [ 1 ] = 1 , [ 2 ] = 5 , [ 3 ] = 4 , [ 4 ] = 2 , [ 5 ] = 3 } ,
[ 180 ] = { [ 0 ] = 0 , [ 1 ] = 1 , [ 2 ] = 3 , [ 3 ] = 2 , [ 4 ] = 5 , [ 5 ] = 4 } ,
[ 270 ] = { [ 0 ] = 0 , [ 1 ] = 1 , [ 2 ] = 4 , [ 3 ] = 5 , [ 4 ] = 3 , [ 5 ] = 2 }
}
local facedir = {
[ 90 ] = { [ 0 ] = 1 , [ 1 ] = 2 , [ 2 ] = 3 , [ 3 ] = 0 } ,
[ 180 ] = { [ 0 ] = 2 , [ 1 ] = 3 , [ 2 ] = 0 , [ 3 ] = 1 } ,
[ 270 ] = { [ 0 ] = 3 , [ 1 ] = 0 , [ 2 ] = 1 , [ 3 ] = 2 }
}
angle = angle % 360
if angle == 0 then
return 0
end
local wallmounted_substitution = wallmounted [ angle ]
local facedir_substitution = facedir [ angle ]
2013-07-21 22:54:25 +02:00
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
2013-01-12 22:46:40 +01:00
local count = 0
2013-06-23 18:46:59 +02:00
local get_node , get_meta , add_node = minetest.get_node , minetest.get_meta , minetest.add_node
2013-01-12 22:46:40 +01:00
local pos = { x = pos1.x , y = 0 , z = 0 }
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
2013-06-23 18:46:59 +02:00
local node = get_node ( pos )
local def = registered_nodes [ node.name ]
2013-01-12 22:46:40 +01:00
if def then
if def.paramtype2 == " wallmounted " then
node.param2 = wallmounted_substitution [ node.param2 ]
2013-06-23 18:46:59 +02:00
local meta = get_meta ( pos ) : to_table ( )
add_node ( pos , node )
get_meta ( pos ) : from_table ( meta )
2013-01-12 22:46:40 +01:00
count = count + 1
elseif def.paramtype2 == " facedir " then
node.param2 = facedir_substitution [ node.param2 ]
2013-06-23 18:46:59 +02:00
local meta = get_meta ( pos ) : to_table ( )
add_node ( pos , node )
get_meta ( pos ) : from_table ( meta )
2013-01-12 22:46:40 +01:00
count = count + 1
end
end
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
return count
end
2013-01-12 22:02:23 +01:00
--fixes the lighting in a region defined by positions `pos1` and `pos2`, returning the number of nodes updated
2013-08-01 04:15:08 +02:00
worldedit.fixlight = function ( pos1 , pos2 )
2012-10-14 03:45:50 +02:00
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-07-21 22:54:25 +02:00
--make area stay loaded
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
2013-06-23 18:46:59 +02:00
local nodes = minetest.find_nodes_in_area ( pos1 , pos2 , " air " )
local dig_node = minetest.dig_node
for _ , pos in ipairs ( nodes ) do
dig_node ( pos )
2012-10-14 03:45:50 +02:00
end
2013-06-23 18:46:59 +02:00
return # nodes
2013-01-13 00:29:57 +01:00
end
2013-07-29 18:43:24 +02:00
--clears all objects in a region defined by the positions `pos1` and `pos2`, returning the number of objects cleared
worldedit.clearobjects = function ( pos1 , pos2 )
local pos1 , pos2 = worldedit.sort_pos ( pos1 , pos2 )
2013-07-31 06:02:37 +02:00
--make area stay loaded
2013-07-29 18:43:24 +02:00
local manip = minetest.get_voxel_manip ( )
manip : read_from_map ( pos1 , pos2 )
local pos1x , pos1y , pos1z = pos1.x , pos1.y , pos1.z
2013-07-31 06:02:37 +02:00
local pos2x , pos2y , pos2z = pos2.x + 1 , pos2.y + 1 , pos2.z + 1
local center = { x = ( pos1x + pos2x ) / 2 , y = ( pos1y + pos2y ) / 2 , z = ( pos1z + pos2z ) / 2 } --center of region
local radius = ( ( center.x - pos1x + 0.5 ) + ( center.y - pos1y + 0.5 ) + ( center.z - pos1z + 0.5 ) ) ^ 0.5 --bounding sphere radius
2013-07-29 18:43:24 +02:00
local count = 0
2013-07-31 06:02:37 +02:00
for _ , obj in pairs ( minetest.get_objects_inside_radius ( center , radius ) ) do --all objects in bounding sphere
local entity = obj : get_luaentity ( )
if not ( entity and entity.name : find ( " ^worldedit: " ) ) then --avoid WorldEdit entities
local pos = obj : getpos ( )
if pos.x >= pos1x and pos.x <= pos2x
and pos.y >= pos1y and pos.y <= pos2y
and pos.z >= pos1z and pos.z <= pos2z then --inside region
obj : remove ( )
count = count + 1
end
2013-07-29 18:43:24 +02:00
end
end
return count
end