diff options
author | Anthony Zhang <azhang9@gmail.com> | 2013-07-31 22:15:08 -0400 |
---|---|---|
committer | Anthony Zhang <azhang9@gmail.com> | 2013-07-31 22:15:08 -0400 |
commit | b0bf52e9b688713853b1ab3740d8b6522a1ba5ae (patch) | |
tree | a8a29a991a6c6457c276ef0902e2e91f6d29161b | |
parent | 3c51ec8c4a347a6714472c423215243fc538f5f5 (diff) |
Rewrite spirals from scratch and fix upside-down pyramids. Use voxelmanip for markers to ensure area is emerged.
-rw-r--r-- | Chat Commands.md | 4 | ||||
-rw-r--r-- | WorldEdit API.md | 4 | ||||
-rw-r--r-- | worldedit/compatibility.lua | 2 | ||||
-rw-r--r-- | worldedit/manipulations.lua | 92 | ||||
-rw-r--r-- | worldedit/primitives.lua | 145 | ||||
-rw-r--r-- | worldedit/serialization.lua | 2 | ||||
-rw-r--r-- | worldedit_commands/init.lua | 8 | ||||
-rw-r--r-- | worldedit_commands/mark.lua | 28 |
8 files changed, 181 insertions, 104 deletions
diff --git a/Chat Commands.md b/Chat Commands.md index 675532a..f70bf75 100644 --- a/Chat Commands.md +++ b/Chat Commands.md @@ -155,9 +155,9 @@ Add pyramid centered at WorldEdit position 1 along the x/y/z/? axis with height //pyramid 5 glass
//pyramid 2 mesecons:wire_00000000_off
-### //spiral <width> <height> <spacer> <node>
+### //spiral <length> <height> <spacer> <node>
-Add spiral centered at WorldEdit position 1 with width <width>, height <height>, space between walls <spacer>, composed of <node>.
+Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <spacer>, composed of <node>.
//spiral 20 5 3 Diamond Block
//spiral 5 2 1 glass
diff --git a/WorldEdit API.md b/WorldEdit API.md index 5d7e6d9..22441d2 100644 --- a/WorldEdit API.md +++ b/WorldEdit API.md @@ -134,9 +134,9 @@ Adds a pyramid centered at `pos` along the `axis` axis ("x" or "y" or "z") with Returns the number of nodes added.
-### count = worldedit.spiral(pos, width, height, spacer, nodename)
+### count = worldedit.spiral(pos, length, height, spacer, nodename)
-Adds a spiral centered at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`.
+Adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `nodename`.
Returns the number of nodes added.
diff --git a/worldedit/compatibility.lua b/worldedit/compatibility.lua index f6971cc..eb81eea 100644 --- a/worldedit/compatibility.lua +++ b/worldedit/compatibility.lua @@ -17,4 +17,4 @@ worldedit.metaload = function(originpos, filename) if err then return 0 end
local data = file:read("*a")
return worldedit.deserialize(originpos, data)
-end
\ No newline at end of file +end
diff --git a/worldedit/manipulations.lua b/worldedit/manipulations.lua index 54e0d2e..53fea6f 100644 --- a/worldedit/manipulations.lua +++ b/worldedit/manipulations.lua @@ -1,7 +1,6 @@ worldedit = worldedit or {}
local minetest = minetest --local copy of global
---wip: remove env parameter where no longer needed in chat commands module
--wip: fix the queue
--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
@@ -112,11 +111,68 @@ worldedit.replaceinverse = function(pos1, pos2, searchnode, replacenode) return count
end
+worldedit.copy = function(pos1, pos2, axis, amount)
+ 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]
+ nodes[i] = get_node(pos)
+ 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
+
--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
worldedit.copy = function(pos1, pos2, axis, amount)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
- --wip: copy slice by slice using schematic method in the copy 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), use voxelmanip to keep area loaded
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
if amount < 0 then
local pos = {x=pos1.x, y=0, z=0}
@@ -166,7 +222,11 @@ end worldedit.move = function(pos1, pos2, axis, amount)
local pos1, pos2 = worldedit.sort_pos(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), use voxelmanip to keep area loaded
+ --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)
local get_node, get_meta, add_node, remove_node = minetest.get_node, minetest.get_meta, minetest.add_node, minetest.remove_node
if amount < 0 then
local pos = {x=pos1.x, y=0, z=0}
@@ -215,7 +275,7 @@ worldedit.move = function(pos1, pos2, axis, amount) 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
-worldedit.stack = function(pos1, pos2, axis, count, env)
+worldedit.stack = function(pos1, pos2, axis, count)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local length = pos2[axis] - pos1[axis] + 1
if count < 0 then
@@ -226,7 +286,7 @@ worldedit.stack = function(pos1, pos2, axis, count, env) local copy = worldedit.copy
for i = 1, count do
amount = amount + length
- copy(pos1, pos2, axis, amount, env)
+ copy(pos1, pos2, axis, amount)
end
return worldedit.volume(pos1, pos2) * count
end
@@ -291,7 +351,7 @@ worldedit.scale = function(pos1, pos2, factor) 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
-worldedit.transpose = function(pos1, pos2, axis1, axis2, env)
+worldedit.transpose = function(pos1, pos2, axis1, axis2)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local compare
@@ -350,7 +410,7 @@ worldedit.transpose = function(pos1, pos2, axis1, axis2, env) 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
-worldedit.flip = function(pos1, pos2, axis, env)
+worldedit.flip = function(pos1, pos2, axis)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
--make area stay loaded
@@ -388,7 +448,7 @@ worldedit.flip = function(pos1, pos2, axis, env) 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
-worldedit.rotate = function(pos1, pos2, axis, angle, env)
+worldedit.rotate = function(pos1, pos2, axis, angle)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local axis1, axis2
@@ -403,20 +463,20 @@ worldedit.rotate = function(pos1, pos2, axis, angle, env) local count
if angle == 90 then
- worldedit.flip(pos1, pos2, axis1, env)
- count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2, env)
+ worldedit.flip(pos1, pos2, axis1)
+ count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
elseif angle == 180 then
- worldedit.flip(pos1, pos2, axis1, env)
- count = worldedit.flip(pos1, pos2, axis2, env)
+ worldedit.flip(pos1, pos2, axis1)
+ count = worldedit.flip(pos1, pos2, axis2)
elseif angle == 270 then
- worldedit.flip(pos1, pos2, axis2, env)
- count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2, env)
+ worldedit.flip(pos1, pos2, axis2)
+ count, pos1, pos2 = worldedit.transpose(pos1, pos2, axis1, axis2)
end
return count, pos1, pos2
end
--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
-worldedit.orient = function(pos1, pos2, angle, env) --wip: support 6D facedir rotation along arbitrary axis
+worldedit.orient = function(pos1, pos2, angle) --wip: support 6D facedir rotation along arbitrary axis
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
local registered_nodes = minetest.registered_nodes
@@ -477,7 +537,7 @@ worldedit.orient = function(pos1, pos2, angle, env) --wip: support 6D facedir ro end
--fixes the lighting in a region defined by positions `pos1` and `pos2`, returning the number of nodes updated
-worldedit.fixlight = function(pos1, pos2, env)
+worldedit.fixlight = function(pos1, pos2)
local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
--make area stay loaded
diff --git a/worldedit/primitives.lua b/worldedit/primitives.lua index eb4624b..e359baa 100644 --- a/worldedit/primitives.lua +++ b/worldedit/primitives.lua @@ -326,7 +326,7 @@ worldedit.cylinder = function(pos, axis, length, radius, nodename) local newindex3 = newindex2 + (index3 + offset[other2]) * stride[other2]
if index2 * index2 + index3 * index3 <= max_radius then
for index1 = min_slice, max_slice do --add column along axis
- local i = newindex3 + index1 * stride[axis] + 1
+ local i = newindex3 + index1 * stride[axis]
nodes[i] = node_id
end
count = count + length
@@ -358,18 +358,14 @@ worldedit.pyramid = function(pos, axis, height, nodename) --handle inverted pyramids
local startaxis, endaxis, step
- local currentpos = {x=pos.x, y=pos.y, z=pos.z}
if height > 0 then
height = height - 1
- startaxis, endaxis = 0, height
step = 1
pos1[axis] = pos[axis] --upper half of box
else
- height = -height - 1
- startaxis, endaxis = height, 0
+ height = height + 1
step = -1
- pos2[axis] = pos[axis] + 1 --lower half of box
- currentpos[axis] = pos[axis] - height --bottom of box
+ pos2[axis] = pos[axis] --lower half of box
end
--set up voxel manipulator
@@ -387,19 +383,20 @@ worldedit.pyramid = function(pos, axis, height, nodename) --fill selected area with node
local node_id = minetest.get_content_id(nodename)
local stride = {x=1, y=area.ystride, z=area.zstride}
- local offset = {x=currentpos.x - emerged_pos1.x, y=currentpos.y - emerged_pos1.y, z=currentpos.z - emerged_pos1.z}
+ local offset = {x=pos.x - emerged_pos1.x, y=pos.y - emerged_pos1.y, z=pos.z - emerged_pos1.z}
+ local size = height * step
local count = 0
- for index1 = startaxis, endaxis, step do --go through each level of the pyramid
+ for index1 = 0, height, step do --go through each level of the pyramid
local newindex1 = (index1 + offset[axis]) * stride[axis] + 1 --offset contributed by axis plus 1 to make it 1-indexed
- for index2 = -height, height do
+ for index2 = -size, size do
local newindex2 = newindex1 + (index2 + offset[other1]) * stride[other1]
- for index3 = -height, height do
+ for index3 = -size, size do
local i = newindex2 + (index3 + offset[other2]) * stride[other2]
nodes[i] = node_id
end
end
- count = count + (height * 2 + 1) ^ 2
- height = height - 1
+ count = count + (size * 2 + 1) ^ 2
+ size = size - 1
end
--update map nodes
@@ -410,70 +407,72 @@ worldedit.pyramid = function(pos, axis, height, nodename) return count
end
---adds a spiral centered at `pos` with width `width`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
-worldedit.spiral = function(pos, width, height, spacer, nodename, env) --wip: rewrite this whole thing, nobody can understand it anyways
- -- spiral matrix - http://rosettacode.org/wiki/Spiral_matrix#Lua
- local abs = math.abs
- local sign = function(s) return s ~= 0 and s / av(s) or 0 end
- local function sindex(z, x) -- returns the value at (x, z) in a spiral that starts at 1 and goes outwards
- if z == -x and z >= x then return (2*z+1)^2 end
- local longest = math.max(abs(z), abs(x))
- return (2*longest-1)^2 + 4*longest + 2*longest*sign(x+z) + sign(z^2-x^2)*(longest-(abs(z)==longest and sign(z)*x or sign(x)*z)) -- OH GOD WHAT
+--adds a spiral centered at `pos` with side length `length`, height `height`, space between walls `spacer`, composed of `nodename`, returning the number of nodes added
+worldedit.spiral = function(pos, length, height, spacer, nodename)
+ local extent = math.ceil(length / 2)
+ local pos1 = {x=pos.x - extent, y=pos.y, z=pos.z - extent}
+ local pos2 = {x=pos.x + extent, y=pos.y + height, z=pos.z + extent}
+
+ --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})
+
+ --fill emerged area with ignore
+ local nodes = {}
+ local ignore = minetest.get_content_id("ignore")
+ for i = 1, worldedit.volume(emerged_pos1, emerged_pos2) do
+ nodes[i] = ignore
end
- local function spiralt(side)
- local ret, id, start, stop = {}, 0, math.floor((-side+1)/2), math.floor((side-1)/2)
- for i = 1, side do
- for j = 1, side do
- local id = side^2 - sindex(stop - i + 1,start + j - 1)
- ret[id] = {x=i,z=j}
+
+ --
+ local node_id = minetest.get_content_id(nodename)
+ local stride = {x=1, y=area.ystride, z=area.zstride}
+ local offsetx, offsety, offsetz = pos.x - emerged_pos1.x, pos.y - emerged_pos1.y, pos.z - emerged_pos1.z
+ local i = offsetz * stride.z + offsety * stride.y + offsetx + 1
+
+ --add first column
+ local column = i
+ for y = 1, height do
+ nodes[column] = node_id
+ column = column + stride.y
+ end
+
+ --add spiral segments
+ local axis, other = "x", "z"
+ local sign = 1
+ local count = height
+ for segment = 1, length / spacer - 1 do --go through each segment except the last
+ for index = 1, segment * spacer do --fill segment
+ i = i + stride[axis] * sign
+ local column = i
+ for y = 1, height do --add column
+ nodes[column] = node_id
+ column = column + stride.y
end
+ count = count + height
+ end
+ axis, other = other, axis --swap axes
+ if segment % 2 == 1 then --change sign every other turn
+ sign = -sign
end
- return ret
end
- if env == nil then env = minetest.env end
- -- connect the joined parts
- local spiral = spiralt(width)
- height = tonumber(height)
- if height < 1 then height = 1 end
- spacer = tonumber(spacer)-1
- if spacer < 1 then spacer = 1 end
- local count = 0
- local node = {name=nodename}
- local np,lp
- for y=0,height do
- lp = nil
- for _,v in ipairs(spiral) do
- np = {x=pos.x+v.x*spacer, y=pos.y+y, z=pos.z+v.z*spacer}
- if lp~=nil then
- if lp.x~=np.x then
- if lp.x<np.x then
- for i=lp.x+1,np.x do
- env:add_node({x=i, y=np.y, z=np.z}, node)
- count = count + 1
- end
- else
- for i=np.x,lp.x-1 do
- env:add_node({x=i, y=np.y, z=np.z}, node)
- count = count + 1
- end
- end
- end
- if lp.z~=np.z then
- if lp.z<np.z then
- for i=lp.z+1,np.z do
- env:add_node({x=np.x, y=np.y, z=i}, node)
- count = count + 1
- end
- else
- for i=np.z,lp.z-1 do
- env:add_node({x=np.x, y=np.y, z=i}, node)
- count = count + 1
- end
- end
- end
- end
- lp = np
+
+ --add shorter final segment
+ for index = 1, (math.floor(length / spacer) - 2) * spacer do
+ i = i + stride[axis] * sign
+ local column = i
+ for y = 1, height do --add column
+ nodes[column] = node_id
+ column = column + stride.y
end
+ count = count + height
end
+print(minetest.serialize(nodes))
+ --update map nodes
+ manip:set_data(nodes)
+ manip:write_to_map()
+ manip:update_map()
+
return count
-end
+end
\ No newline at end of file diff --git a/worldedit/serialization.lua b/worldedit/serialization.lua index 7b65b25..731b8d4 100644 --- a/worldedit/serialization.lua +++ b/worldedit/serialization.lua @@ -183,7 +183,7 @@ end --loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
worldedit.deserialize = function(originpos, value)
- --make sure the area stays loaded --wip: not very performant
+ --make area stay loaded --wip: not very performant
local pos1, pos2 = worldedit.allocate(originpos, value)
local manip = minetest.get_voxel_manip()
manip:read_from_map(pos1, pos2)
diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index 1a57849..b6c1e79 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -536,8 +536,8 @@ minetest.register_chatcommand("/pyramid", { })
minetest.register_chatcommand("/spiral", {
- params = "<width> <height> <space> <node>",
- description = "Add spiral centered at WorldEdit position 1 with width <width>, height <height>, space between walls <space>, composed of <node>",
+ params = "<length> <height> <space> <node>",
+ description = "Add spiral centered at WorldEdit position 1 with side length <length>, height <height>, space between walls <space>, composed of <node>",
privs = {worldedit=true},
func = function(name, param)
local pos = worldedit.pos1[name]
@@ -546,7 +546,7 @@ minetest.register_chatcommand("/spiral", { return
end
- local found, _, width, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
+ local found, _, length, height, space, nodename = param:find("^(%d+)%s+(%d+)%s+(%d+)%s+(.+)$")
if found == nil then
worldedit.player_notify(name, "invalid usage: " .. param)
return
@@ -557,7 +557,7 @@ minetest.register_chatcommand("/spiral", { return
end
- local count = worldedit.spiral(pos, tonumber(width), tonumber(height), tonumber(space), node)
+ local count = worldedit.spiral(pos, tonumber(length), tonumber(height), tonumber(space), node)
worldedit.player_notify(name, count .. " nodes added")
end,
})
diff --git a/worldedit_commands/mark.lua b/worldedit_commands/mark.lua index c241acb..3295d74 100644 --- a/worldedit_commands/mark.lua +++ b/worldedit_commands/mark.lua @@ -21,16 +21,21 @@ minetest.register_entity(":worldedit:region_cube", { end,
})
---wip: use voxelmanip to put the entity in the correct spot
-
--marks worldedit region position 1
worldedit.mark_pos1 = function(name)
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+
+ if pos1 ~= nil then
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos1) --wip: see if this even works
+ end
if worldedit.marker1[name] ~= nil then --marker already exists
worldedit.marker1[name]:remove() --remove marker
worldedit.marker1[name] = nil
end
- if pos1 ~= nil then --add marker
+ if pos1 ~= nil then
+ --add marker
worldedit.marker1[name] = minetest.add_entity(pos1, "worldedit:pos1")
worldedit.marker1[name]:get_luaentity().active = true
if pos2 ~= nil then --region defined
@@ -42,11 +47,18 @@ end --marks worldedit region position 2
worldedit.mark_pos2 = function(name)
local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
+
+ if pos2 ~= nil then
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos2, pos2) --wip: see if this even works
+ end
if worldedit.marker2[name] ~= nil then --marker already exists
worldedit.marker2[name]:remove() --remove marker
worldedit.marker2[name] = nil
end
- if pos2 ~= nil then --add marker
+ if pos2 ~= nil then
+ --add marker
worldedit.marker2[name] = minetest.add_entity(pos2, "worldedit:pos2")
worldedit.marker2[name]:get_luaentity().active = true
if pos1 ~= nil then --region defined
@@ -56,10 +68,16 @@ worldedit.mark_pos2 = function(name) end
worldedit.mark_region = function(pos1, pos2)
+ --make area stay loaded
+ local manip = minetest.get_voxel_manip()
+ manip:read_from_map(pos1, pos2)
+
if worldedit.marker[name] ~= nil then --marker already exists
--wip: remove markers
end
-
+ if pos1 ~= nil and pos2 ~= nil then
+ --wip: place markers
+ end
end
minetest.register_entity(":worldedit:pos1", {
|