diff --git a/LICENSE.txt b/LICENSE.txt index bc0b1db..151369c 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1 +1 @@ -WTFPL +CC0, except for code copied from e.g. minetest's builtin diff --git a/fill_3d.lua b/fill_3d.lua new file mode 100644 index 0000000..eaa7142 --- /dev/null +++ b/fill_3d.lua @@ -0,0 +1,53 @@ +-- Algorithm created by sofar and changed by others: +-- https://github.com/minetest/minetest/commit/d7908ee49480caaab63d05c8a53d93103579d7a9 + +local function search(go, p, apply_move, moves) + local num_moves = #moves + + -- We make a stack, and manually maintain size for performance. + -- Stored in the stack, we will maintain tables with pos, and + -- last neighbor visited. This way, when we get back to each + -- node, we know which directions we have already walked, and + -- which direction is the next to walk. + local s = {} + local n = 0 + -- The neighbor order we will visit from our table. + local v = 1 + + while true do + -- Push current pos onto the stack. + n = n + 1 + s[n] = {p = p, v = v} + -- Select next node from neighbor list. + p = apply_move(p, moves[v]) + -- Now we check out the node. If it is in need of an update, + -- it will let us know in the return value (true = updated). + if not go(p) then + -- If we don't need to "recurse" (walk) to it then pop + -- our previous pos off the stack and continue from there, + -- with the v value we were at when we last were at that + -- node + repeat + local pop = s[n] + p = pop.p + v = pop.v + s[n] = nil + n = n - 1 + -- If there's nothing left on the stack, and no + -- more sides to walk to, we're done and can exit + if n == 0 and v == num_moves then + return + end + until v < num_moves + -- The next round walk the next neighbor in list. + v = v + 1 + else + -- If we did need to walk the neighbor, then + -- start walking it from the walk order start (1), + -- and not the order we just pushed up the stack. + v = 1 + end + end +end + +return search diff --git a/init.lua b/init.lua index 1303e3a..52dcd89 100644 --- a/init.lua +++ b/init.lua @@ -414,6 +414,51 @@ function funcs.search_2d(go_test, x0, y0, allow_revisit, give_map) return l end +local fallings_search = dofile(path .. "/fill_3d.lua") +local moves_touch = { + {x = -1, y = 0, z = 0}, + {x = 0, y = 0, z = 0}, + {x = 1, y = 0, z = 0}, + {x = 0, y = -1, z = 0}, + {x = 0, y = 1, z = 0}, + {x = 0, y = 0, z = -1}, + {x = 0, y = 0, z = 1}, +} +local moves_near = {} +for z = -1,1 do + for y = -1,1 do + for x = -1,1 do + moves_near[#moves_near+1] = {x = x, y = y, z = z} + end + end +end + +function funcs.search_3d(can_go, startpos, apply_move, moves) + local visited = {} + local found = {} + local function on_visit(pos) + local vi = minetest.hash_node_position(pos) + if visited[vi] then + return false + end + visited[vi] = true + local valid_pos = can_go(pos) + if valid_pos then + found[#found+1] = pos + end + return valid_pos + end + if apply_move == "touch" then + apply_move = vector.add + moves = moves_touch + elseif apply_move == "near" then + apply_move = vector.add + moves = moves_near + end + fallings_search(on_visit, startpos, apply_move, moves) +end + + local explosion_tables = {} function funcs.explosion_table(r) local table = explosion_tables[r]