mirror of
				https://github.com/Uberi/Minetest-WorldEdit.git
				synced 2025-11-04 14:45:27 +01:00 
			
		
		
		
	Improved stacking
This stack / copy uses a direction vector, so it's not limited to only along the X/Y/Z axis, and can go diagonally. This enables things like building staircases.
This commit is contained in:
		@@ -172,6 +172,129 @@ worldedit.copy = function(pos1, pos2, axis, amount) --wip: replace the old versi
 | 
			
		||||
	return worldedit.volume(pos1, pos2)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
worldedit.copy2 = function(pos1, pos2, direction, volume)
 | 
			
		||||
    -- 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.
 | 
			
		||||
    
 | 
			
		||||
	local get_node, get_meta, add_node = minetest.get_node, minetest.get_meta, minetest.add_node
 | 
			
		||||
    local somemeta = get_meta(pos1) -- hax lol
 | 
			
		||||
    local to_table = somemeta.to_table
 | 
			
		||||
    local from_table = somemeta.from_table
 | 
			
		||||
    somemeta = nil
 | 
			
		||||
 | 
			
		||||
	local pos1, pos2 = worldedit.sort_pos(pos1, pos2)
 | 
			
		||||
	local manip = minetest.get_voxel_manip()
 | 
			
		||||
	manip:read_from_map(pos1, pos2)
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    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 = ox; pos1.y = oy; pos1.z = oz
 | 
			
		||||
                pos2.x = x; pos2.y = y; pos2.z = z
 | 
			
		||||
                local node = get_node(pos1)
 | 
			
		||||
				local meta = to_table(get_meta(pos1)) --get meta of current node
 | 
			
		||||
                add_node(pos2,node)
 | 
			
		||||
                from_table(get_meta(pos2),meta)
 | 
			
		||||
                oz = oz + sz
 | 
			
		||||
            end
 | 
			
		||||
            oy = oy + sy
 | 
			
		||||
        end
 | 
			
		||||
        ox = ox + sx
 | 
			
		||||
    end
 | 
			
		||||
end            
 | 
			
		||||
 | 
			
		||||
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()
 | 
			
		||||
    return nil
 | 
			
		||||
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)
 | 
			
		||||
 
 | 
			
		||||
@@ -619,6 +619,52 @@ minetest.register_chatcommand("/stack", {
 | 
			
		||||
	end),
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
minetest.register_chatcommand("/stack2", {
 | 
			
		||||
	params = "<count> <x>/<y>/<z>",
 | 
			
		||||
	description = "Stack the current WorldEdit region <count> times translating each time by x, y and z in the respective directions.",
 | 
			
		||||
	privs = {worldedit=true},
 | 
			
		||||
	func = function(name, param)
 | 
			
		||||
		local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name]
 | 
			
		||||
        if pos1 == nil or pos2 == nil then
 | 
			
		||||
            worldedit.player_notify(name, "Select a position first!")
 | 
			
		||||
            return
 | 
			
		||||
        end
 | 
			
		||||
        local repetitions, incs = param:match("([0-9]+)%s*(.+)")
 | 
			
		||||
        repetitions = repetitions and tonumber(repetitions)
 | 
			
		||||
        if repetitions == nil then
 | 
			
		||||
			worldedit.player_notify(name, "invalid count: " .. param)
 | 
			
		||||
            return 
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local x,y,z = incs:match("(.+)/(.+)/(.+)")
 | 
			
		||||
        if x == nil then
 | 
			
		||||
            worldedit.player_notify(name, "invalid increments: " .. param)
 | 
			
		||||
            return
 | 
			
		||||
        end
 | 
			
		||||
        x = tonumber(x)
 | 
			
		||||
        y = tonumber(y)
 | 
			
		||||
        z = tonumber(z)
 | 
			
		||||
        if x == nil or y == nil or z == nil then
 | 
			
		||||
            worldedit.player_notify(name, "increments must be numbers: " .. param)
 | 
			
		||||
            return
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local count = worldedit.volume(pos1,pos2) * repetitions
 | 
			
		||||
 | 
			
		||||
        return safe_region(function()
 | 
			
		||||
   		  worldedit.stack2(pos1, pos2, {x=x,y=y,z=z}, repetitions,
 | 
			
		||||
          function()
 | 
			
		||||
		    worldedit.player_notify(name, count .. " nodes stacked")
 | 
			
		||||
        end)
 | 
			
		||||
 | 
			
		||||
        end,
 | 
			
		||||
        function() 
 | 
			
		||||
            return count
 | 
			
		||||
    	end)(name,param) -- more hax
 | 
			
		||||
	end
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
minetest.register_chatcommand("/stretch", {
 | 
			
		||||
	params = "<stretchx> <stretchy> <stretchz>",
 | 
			
		||||
	description = "Scale the current WorldEdit positions and region by a factor of <stretchx>, <stretchy>, <stretchz> along the X, Y, and Z axes, repectively, with position 1 as the origin",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user