ShadowNinja
2016-03-22 1475ee6e40b61ba2b604ac6dc3ff285df415450f
Add trace_node_ray_fat and use it for mining lasers

This function includes more nodes, so laser tunnels
aren't always only one node wide.
2 files modified
81 ■■■■■ changed files
technic/helpers.lua 79 ●●●●● patch | view | raw | blame | history
technic/tools/mining_lasers.lua 2 ●●● patch | view | raw | blame | history
technic/helpers.lua
@@ -110,3 +110,82 @@
    end, vector.round(pos)
end
--- Like trace_node_ray, but includes extra positions close to the ray.
function technic.trace_node_ray_fat(pos, dir, range)
    local x_step = dir.x > 0 and 1 or -1
    local y_step = dir.y > 0 and 1 or -1
    local z_step = dir.z > 0 and 1 or -1
    local next_poses = {}
    local i = 1
    return function(p)
        local ni, np = next(next_poses)
        if np then
            next_poses[ni] = nil
            return np
        end
        -- Approximation of where we should be if we weren't rounding
        -- to nodes.  This moves forward a bit faster then we do.
        -- A correction is done below.
        local real_x = pos.x + (dir.x * i)
        local real_y = pos.y + (dir.y * i)
        local real_z = pos.z + (dir.z * i)
        -- How far off we've gotten from where we should be.
        local dx = math.abs(real_x - p.x)
        local dy = math.abs(real_y - p.y)
        local dz = math.abs(real_z - p.z)
        -- If the real position moves ahead too fast, stop it so we
        -- can catch up.  If it gets too far ahead it will smooth
        -- out our movement too much and we won't turn fast enough.
        if dx + dy + dz < 2 then
            i = i + 1
        end
        -- Step in whichever direction we're most off course in.
        local sx, sy, sz  -- Whether we've already stepped along each axis
        if dx > dy then
            if dx > dz then
                sx = true
                p.x = p.x + x_step
            else
                sz = true
                p.z = p.z + z_step
            end
        elseif dy > dz then
            sy = true
            p.y = p.y + y_step
        else
            sz = true
            p.z = p.z + z_step
        end
        if vector.distance(pos, p) > range then
            return nil
        end
        -- Add other positions that we're significantly off on.
        -- We can just use fixed integer keys here because the
        -- table will be completely cleared before we reach this
        -- code block again.
        local dlen = math.sqrt(dx*dx + dy*dy + dz*dz)
        -- Normalized axis deltas
        local dxn, dyn, dzn = dx / dlen, dy / dlen, dz / dlen
        if not sx and dxn > 0.5 then
            next_poses[1] = vector.new(p.x + x_step, p.y, p.z)
        end
        if not sy and dyn > 0.5 then
            next_poses[2] = vector.new(p.x, p.y + y_step, p.z)
        end
        if not sz and dzn > 0.5 then
            next_poses[3] = vector.new(p.x, p.y, p.z + z_step)
        end
        return p
    end, vector.round(pos)
end
technic/tools/mining_lasers.lua
@@ -71,7 +71,7 @@
        texture = particle_texture .. "^[transform" .. math.random(0, 7),
    })
    minetest.sound_play(sound, {pos = player_pos, max_hear_distance = range})
    for pos in technic.trace_node_ray(start_pos, dir, range) do
    for pos in technic.trace_node_ray_fat(start_pos, dir, range) do
        if minetest.is_protected(pos, player_name) then
            minetest.record_protection_violation(pos, player_name)
            break