forked from VoxeLibre/VoxeLibre
Optimize world respawn point reselection by only considering positions within 3 nodes of tree nodes and when validating a position can still pathfind to a tree start checking trees from the closest to the respawn point
This commit is contained in:
parent
3b1c55c234
commit
3ad862c61c
|
@ -146,60 +146,87 @@ local function good_for_respawn(pos, player)
|
|||
local def0 = minetest.registered_nodes[nn0]
|
||||
local def1 = minetest.registered_nodes[nn1]
|
||||
local def2 = minetest.registered_nodes[nn2]
|
||||
|
||||
-- Be safe around undefined nodes
|
||||
if not def0 then return false end
|
||||
if not def1 then return false end
|
||||
if not def2 then return false end
|
||||
|
||||
return def0.walkable and (not def1.walkable) and (not def2.walkable) and
|
||||
(def1.damage_per_second == nil or def2.damage_per_second <= 0) and
|
||||
(def1.damage_per_second == nil or def2.damage_per_second <= 0)
|
||||
end
|
||||
|
||||
local function can_find_tree(pos1, trees)
|
||||
if not emerge_pos1 or not emerge_pos2 then return false end
|
||||
local trees = trees or get_trees(pos1)
|
||||
if not trees then return false end
|
||||
|
||||
if (attempts_to_find_trees * 3 < #trees) then
|
||||
-- random search
|
||||
for i = 1, attempts_to_find_trees do
|
||||
local pos2 = trees[math.random(1,#trees)]
|
||||
if not minetest.is_protected(pos2, "") then
|
||||
if pos2.x < pos1.x then
|
||||
pos2.x = pos2.x + 1
|
||||
elseif pos2.x > pos1.x then
|
||||
pos2.x = pos2.x - 1
|
||||
end
|
||||
if pos2.z < pos1.z then
|
||||
pos2.z = pos2.z + 1
|
||||
elseif pos2.z > pos1.z then
|
||||
pos2.z = pos2.z - 1
|
||||
end
|
||||
local way = minetest.find_path(pos1, pos2, res, 1, 3, "A*_noprefetch")
|
||||
if way then
|
||||
return true
|
||||
end
|
||||
local ADJACENT_OFFSETS = {
|
||||
vector.new( 1,0, 0),
|
||||
vector.new(-1,0, 0),
|
||||
vector.new( 0,0, 1),
|
||||
vector.new( 0,0,-1),
|
||||
vector.new( 0,1, 0),
|
||||
}
|
||||
|
||||
local function pathfind_next_to(target, pos1, distance)
|
||||
local closest_free_pos = nil
|
||||
local closest_free_dist = nil
|
||||
for j=1,4 do
|
||||
local test_pos = vector.add(target, ADJACENT_OFFSETS[j])
|
||||
if minetest.get_node(test_pos).name == "air" and minetest.get_node(vector.offset(test_pos,0,-1,0)).name ~= "air" then
|
||||
local new_dist = vector.distance(pos1, test_pos)
|
||||
if not closest_free_pos or new_dist < closest_free_dist then
|
||||
closest_free_pos = test_pos
|
||||
closest_free_dist = new_dist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local way = false
|
||||
if closest_free_pos then
|
||||
return minetest.find_path(pos1, closest_free_pos, distance, 1, 3, "A*_noprefetch")
|
||||
end
|
||||
end
|
||||
|
||||
local function can_find_tree(pos1, trees)
|
||||
local start_time = minetest.get_us_time()
|
||||
|
||||
if not emerge_pos1 or not emerge_pos2 then
|
||||
minetest.log("verbose", "[mcl_spawn] Missing emerge position in can_find_tree()")
|
||||
return false
|
||||
end
|
||||
local trees = trees or get_trees(pos1)
|
||||
if not trees then
|
||||
minetest.log("verbose", "[mcl_spawn] No trees in area in can_find_tree()")
|
||||
return false
|
||||
end
|
||||
|
||||
for i, pos2 in ipairs(trees) do
|
||||
-- full search
|
||||
if not minetest.is_protected(pos2, "") then
|
||||
if pos2.x < pos1.x then
|
||||
pos2.x = pos2.x + 1
|
||||
elseif pos2.x > pos1.x then
|
||||
pos2.x = pos2.x - 1
|
||||
end
|
||||
if pos2.z < pos1.z then
|
||||
pos2.z = pos2.z + 1
|
||||
elseif pos2.z > pos1.z then
|
||||
pos2.z = pos2.z - 1
|
||||
end
|
||||
local way = minetest.find_path(pos1, pos2, res, 1, 3, "A*_noprefetch")
|
||||
if way then
|
||||
return true
|
||||
-- Search from closest to furthest from pos1
|
||||
for i = 2,#trees do
|
||||
for j = 1,(i-1) do
|
||||
if vector.distance(pos1,trees[j]) > vector.distance(pos1,trees[j+1]) then
|
||||
local tmp = trees[j+1]
|
||||
trees[j] = trees[j+1]
|
||||
trees[j+1] = tmp
|
||||
end
|
||||
end
|
||||
if i > attempts_to_find_trees then return false end
|
||||
end
|
||||
|
||||
for i = 1,#trees do
|
||||
local possible_tree = trees[i]
|
||||
|
||||
local start_pathfind = minetest.get_us_time()
|
||||
local way = pathfind_next_to(possible_tree, pos1, res)
|
||||
local stop_pathfind = minetest.get_us_time()
|
||||
|
||||
if stop_pathfind > start_time + 0.25e6 then
|
||||
minetest.log("info","[mcl_spawn] can_find_tree() timed out")
|
||||
return false;
|
||||
end
|
||||
|
||||
if way then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -285,86 +312,52 @@ local function next_biome()
|
|||
return false
|
||||
end
|
||||
|
||||
local function find_spawn_in_area(pos1, pos2)
|
||||
local nodes = minetest.find_nodes_in_area(pos1, pos2, {"group:tree"})
|
||||
if #nodes <= 0 then return nil end
|
||||
|
||||
for i = 1,#nodes do
|
||||
local pos = nodes[i]
|
||||
|
||||
local candidates = minetest.find_nodes_in_area_under_air(
|
||||
vector.offset(pos,-3,-2,-3),
|
||||
vector.offset(pos, 3, 2, 3),
|
||||
{"group:solid"}
|
||||
)
|
||||
|
||||
for j = 1,#candidates do
|
||||
local candidate = vector.offset(candidates[j],0,1,0)
|
||||
local gfs = good_for_respawn(candidate)
|
||||
local way = false
|
||||
if vector.distance(candidate, pos) <= 1 then
|
||||
way = true
|
||||
else
|
||||
local way = pathfind_next_to(candidate, pos, 5)
|
||||
end
|
||||
if gfs and way then
|
||||
return candidate
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function ecb_search_continue(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining <= 0 then
|
||||
emerge_pos1 = {x = wsp.x-half_res, y = alt_min, z = wsp.z-half_res}
|
||||
emerge_pos2 = {x = wsp.x+half_res, y = alt_max, z = wsp.z+half_res}
|
||||
local nodes = minetest.find_nodes_in_area_under_air(emerge_pos1, emerge_pos2, node_groups_white_list)
|
||||
minetest.log("verbose", "[mcl_spawn] Data emerge callback: "..minetest.pos_to_string(wsp).." - "..tostring(nodes and #nodes) .. " node(s) found under air")
|
||||
if nodes then
|
||||
if no_trees_area_counter >= 0 then
|
||||
local trees = get_trees(emerge_pos1, emerge_pos2)
|
||||
if trees and #trees > 0 then
|
||||
no_trees_area_counter = 0
|
||||
if attempts_to_find_pos * 3 < #nodes then
|
||||
-- random
|
||||
for i=1, attempts_to_find_pos do
|
||||
wsp = nodes[math.random(1,#nodes)]
|
||||
if wsp then
|
||||
wsp.y = wsp.y + 1
|
||||
if good_for_respawn(wsp) and can_find_tree(wsp, trees) then
|
||||
minetest.log("action", "[mcl_spawn] Dynamic world spawn randomly determined to be "..minetest.pos_to_string(wsp))
|
||||
searched = true
|
||||
success = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- in a sequence
|
||||
for i=1, math.min(#nodes, attempts_to_find_pos) do
|
||||
wsp = nodes[i]
|
||||
if wsp then
|
||||
wsp.y = wsp.y + 1
|
||||
if good_for_respawn(wsp) and can_find_tree(wsp, trees) then
|
||||
minetest.log("action", "[mcl_spawn] Dynamic world spawn determined to be "..minetest.pos_to_string(wsp))
|
||||
searched = true
|
||||
success = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
no_trees_area_counter = no_trees_area_counter + 1
|
||||
if no_trees_area_counter > 10 then
|
||||
minetest.log("verbose", "[mcl_spawn] More than 10 times no trees at all! Won't search trees next 200 calls")
|
||||
no_trees_area_counter = -200
|
||||
end
|
||||
end
|
||||
else -- seems there are no trees but we'll check it later, after next 200 calls
|
||||
no_trees_area_counter = no_trees_area_counter + 1
|
||||
if attempts_to_find_pos * 3 < #nodes then
|
||||
-- random
|
||||
for i=1, attempts_to_find_pos do
|
||||
wsp = nodes[math.random(1,#nodes)]
|
||||
if wsp then
|
||||
wsp.y = wsp.y + 1
|
||||
if good_for_respawn(wsp) then
|
||||
minetest.log("action", "[mcl_spawn] Dynamic world spawn randomly determined to be "..minetest.pos_to_string(wsp) .. " (no trees)")
|
||||
searched = true
|
||||
success = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- in a sequence
|
||||
for i=1, math.min(#nodes, attempts_to_find_pos) do
|
||||
wsp = nodes[i]
|
||||
if wsp then
|
||||
wsp.y = wsp.y + 1
|
||||
if good_for_respawn(wsp) then
|
||||
minetest.log("action", "[mcl_spawn] Dynamic world spawn determined to be "..minetest.pos_to_string(wsp) .. " (no trees)")
|
||||
searched = true
|
||||
success = true
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local start_time = minetest.get_us_time()
|
||||
|
||||
local spawn_pos = find_spawn_in_area(emerge_pos1, emerge_pos2)
|
||||
if spawn_pos then
|
||||
wsp = spawn_pos
|
||||
minetest.log("action", "[mcl_spawn] Dynamic world spawn randomly determined to be "..minetest.pos_to_string(wsp))
|
||||
searched = true
|
||||
success = true
|
||||
return
|
||||
end
|
||||
|
||||
next_pos()
|
||||
mcl_spawn.search()
|
||||
end
|
||||
|
@ -565,8 +558,24 @@ function mcl_spawn.shadow_worker()
|
|||
|
||||
if success then
|
||||
local wsp_node = minetest.get_node(wsp)
|
||||
if not (wsp_node and wsp_node.name == "ignore")
|
||||
and ((not good_for_respawn(wsp)) or ((no_trees_area_counter >= 0) and not can_find_tree(wsp))) then
|
||||
local spawn_bad = false
|
||||
|
||||
if not spawn_bad and not wsp_node or wsp_node.name == "ignore" then
|
||||
spawn_bad = true
|
||||
minetest.log("verbose", "[mcl_spawn] World spawn point could not be checked or is 'ignore' wsp_node="..dump(wsp_node))
|
||||
end
|
||||
|
||||
if not spawn_bad and not good_for_respawn(wsp) then
|
||||
spawn_bad = true
|
||||
minetest.log("verbose", "[mcl_spawn] World spawn point is not good for respawn")
|
||||
end
|
||||
|
||||
if not spawn_bad and ( (no_trees_area_counter >= 0) and not can_find_tree(wsp) ) then
|
||||
spawn_bad = true
|
||||
minetest.log("verbose", "[mcl_spawn] No trees near spawn point")
|
||||
end
|
||||
|
||||
if spawn_bad then
|
||||
success = false
|
||||
minetest.log("action", "[mcl_spawn] World spawn position isn't safe anymore: "..minetest.pos_to_string(wsp))
|
||||
mcl_spawn.search()
|
||||
|
|
Loading…
Reference in New Issue