add block post processing support, start adding L2/L3/L4 node count indexing, add simple shim for vl_scheduler functionality

This commit is contained in:
teknomunk 2024-05-01 07:33:01 +00:00
parent 6e5c47ac59
commit 66854baf47
3 changed files with 199 additions and 53 deletions

View File

@ -3,11 +3,16 @@ local modpath = minetest.get_modpath(modname)
-- Make sure the API is available everywhere
dofile(modpath.."/api.lua")
if not minetest.get_modpath("vl_scheduler") then
dofile(modpath.."/scheduler.lua")
end
local mod = vl_map_index
mod.indexer_dofile(modpath.."/node_counter.lua")
-- Imports
local call_async = minetest.handle_async or function(a,b,...) b(a(...)) end
local scheduler = mod.scheduler
-- Constants
local DIRTY_BLOCK_HOLDOFF = 2
@ -17,9 +22,11 @@ local MINETEST_BLOCK_SIZE = 16
local storage = minetest.get_mod_storage()
local dirty_blocks = minetest.deserialize(storage:get_string("dirty_blocks")) or {}
local processing_block = minetest.deserialize(storage:get_string("processing_block")) or false
local post_process_blocks = minetest.deserialize(storage:get_string("post_process_blocks")) or {}
minetest.register_on_shutdown(function()
storage:set_string("dirty_blocks", minetest.serialize(dirty_blocks))
storage:set_string("processing_block",minetest.serialize(processing_block))
storage:set_string("pos_process_blocks",minetest.serialize(post_process_blocks))
end)
-- Map block processor
@ -76,6 +83,11 @@ local function process_dirty_block()
storage:set_string(mod.indexers[indexer].name..vector.to_string(minetest.get_position_from_hash(map_block_hash)),tostring(result))
index_in_process = false
decompress_queue[#decompress_queue + 1] = {map_block_hash, indexer, result}
-- Flag the map block for post processing
if mod.indexers[indexer].post_process then
post_process_blocks[map_block_hash] = true
end
end
-- Run the indexer
@ -114,7 +126,8 @@ end
-- Returns true if all indexes have been generated for map_block
function mod.has_index(map_block)
for i = 1,#mod.indexers do
if not storage:contains(mod.indexers[i].name..vector.to_string(map_block)) then
local idx = mod.indexers[i].name..vector.to_string(map_block)
if not storage:contains(idx) then
return false
end
end
@ -131,7 +144,7 @@ function mod.index_around_entity(pos, distance)
local blocks = math.ceil(distance / MINETEST_BLOCK_SIZE)
for z = -blocks,blocks do
for y = -blocks,blocks do
for y = -2,1 do
for x = -blocks,blocks do
mod.ensure_indexed(vector.add(center, vector.new(x,y,z)))
end
@ -170,7 +183,7 @@ local function run_indexer()
local last_player_block = last_player_blocks[player_name]
if not last_player_block or last_player_block ~= map_block then
print("Indexing around "..player_name)
--print("Indexing around "..player_name)
mod.index_around_entity(player_pos, 128)
end
last_player_blocks[player_name] = map_block
@ -194,14 +207,16 @@ local function run_indexer()
local item = decompress_queue[idx]
decompress_queue[idx] = nil
if item then
mod.cache_map_index(item[1], item[2], mod.unpack_index(item[3]))
local map_block_hash = item[1]
local indexer = item[2]
mod.cache_map_index(map_block_hash, indexer, mod.unpack_index(item[3]))
if post_process_blocks[item[1]] then
mod.indexers[indexer].post_process(map_block_hash)
post_process_blocks[item[1]] = nil
end
end
end
if minetest.get_modpath("vl_scheduler") then
-- Run the indexer
vl_scheduler.register_periodic_task("vl_map_index:indexer", 0.25, 4, run_indexer)
else
-- Globalstep to handle reindexing map blocks
minetest.register_globalstep(run_indexer)
end
-- Run the indexer
scheduler.register_periodic_task("vl_map_index:indexer", 0.25, 4, run_indexer)

View File

@ -1,5 +1,6 @@
-- Imports
local vl_map_index = vl_map_index
local mod = vl_map_index
local scheduler = mod.scheduler
-- Constants
local MIN_SEARCH_SIZE = 1000
@ -15,7 +16,11 @@ local function block_pos_hash(min, x, y, z)
(z - min.z)
end
vl_map_index.register_indexer("node_counter",{
local l2_tasks = {}
local l3_tasks = {}
local l4_task = nil
mod.register_indexer("node_counter",{
index = function(data)
local min = data.map_block.min
local max = data.map_block.max
@ -79,51 +84,93 @@ vl_map_index.register_indexer("node_counter",{
--print(dump(index))
return index
end,
post_process = function(map_block_hash)
local pos = minetest.get_position_from_hash(map_block_hash)
---- Schedule tasks for updating heirarchial indexes
-- L2 index (256x256x256 blocks)
local l2_block = mod.map_block(pos)
local l2_block_hash = minetest.hash_node_position(l2_block)
if l2_tasks[l2_block_hash] then
l2_tasks[l2_block_hash]:cancel()
end
l2_tasks[l2_block_hash] = scheduler.add_cancelable_task("vl_map_index:node_counter_l2_index", 2, 4, {l2_block_hash})
-- L3 index (4096*4096*4096 blocks)
local l3_block = mod.map_block(l2_block)
local l3_block_hash = minetest.hash_node_position(l3_block)
if l3_tasks[l3_block_hash] then
l3_tasks[l3_block_hash]:cancel()
end
l3_tasks[l3_block_hash] = scheduler.add_cancelable_task("vl_map_index:node_counter_l3_index", 2, 4, {l3_block_hash})
print("L3 block = "..vector.to_string(l3_block))
-- L4 (whole world, 65536x65536x65536 block)
if l4_task then
l4_task:cancel()
end
l4_task = scheduler.add_cancelable_task("vl_map_index:node_counter_l4_index", 2, 4, {})
end,
})
if not mod.main_thread then return end
-- Scheduler tasks
scheduler.register_function("vl_map_index:node_counter_l2_index",function(l2_block_hash)
print("TODO: update L2 index")
l2_tasks[l2_block_hash] = nil
end)
scheduler.register_function("vl_map_index:node_counter_l3_index",function(l3_block_hash)
print("TODO: update L3 index")
l3_tasks[l3_block_hash] = nil
end)
scheduler.register_function("vl_map_index:node_counter_l4_index",function()
print("TODO: update L4 index")
l4_task = nil
end)
-- Public-facing API
if vl_map_index.main_thread then
function vl_map_index.find_nodes_in_area(pos1, pos2, nodenames, grouped)
local size = math.abs(pos1.x - pos2.x) * math.abs(pos1.y - pos2.y) * math.abs(pos1.z - pos2.z)
if size >= MIN_SEARCH_SIZE then
local indexes = vl_map_index.get_indexes_for_area(pos1, pos2, "node_counter")
if indexes then
for i=1,#indexes do
-- TODO: find nodes in area
end
function mod.find_nodes_in_area(pos1, pos2, nodenames, grouped)
local size = math.abs(pos1.x - pos2.x) * math.abs(pos1.y - pos2.y) * math.abs(pos1.z - pos2.z)
if size >= MIN_SEARCH_SIZE then
local indexes = mod.get_indexes_for_area(pos1, pos2, "node_counter")
if indexes then
for i=1,#indexes do
-- TODO: find nodes in area
end
end
-- Otherwize, fallback onto minetest builtin function
return minetest.find_nodes_in_area(pos1, pos2, nodenames, grouped)
end
function vl_map_index.find_node_near(pos, radius, nodenames, search_center)
local size = radius * radius * radius
if size >= MIN_SEARCH_SIZE then
local indexes = vl_map_index.get_indexes_near(pos, radius, "node_counter")
if indexes then
for i=1,#indexes do
-- TODO: find nodes in area
end
end
return nil
end
-- Otherwize, fallback onto minetest builtin function
return minetest.find_node_near(pos, radius, nodenames, search_center)
end
function vl_map_index.find_nodes_in_area_under_air(pos1, pos2, nodenames)
local size = math.abs(pos1.x - pos2.x) * math.abs(pos1.y - pos2.y) * math.abs(pos1.z - pos2.z)
if size >= MIN_SEARCH_SIZE then
local indexes = vl_map_index.get_indexes_for_area(pos1, pos2, "node_counter")
if indexes then
for i=1,#indexes do
-- TODO: find nodes under air in area
end
end
end
-- Otherwize, fallback onto minetest builtin function
return minetest.find_nodes_in_area_under_air(pos1, pos2, nodenames)
end
-- Otherwize, fallback onto minetest builtin function
return minetest.find_nodes_in_area(pos1, pos2, nodenames, grouped)
end
function mod.find_node_near(pos, radius, nodenames, search_center)
local size = radius * radius * radius
if size >= MIN_SEARCH_SIZE then
local indexes = mod.get_indexes_near(pos, radius, "node_counter")
if indexes then
for i=1,#indexes do
-- TODO: find nodes in area
end
end
return nil
end
-- Otherwize, fallback onto minetest builtin function
return minetest.find_node_near(pos, radius, nodenames, search_center)
end
function mod.find_nodes_in_area_under_air(pos1, pos2, nodenames)
local size = math.abs(pos1.x - pos2.x) * math.abs(pos1.y - pos2.y) * math.abs(pos1.z - pos2.z)
if size >= MIN_SEARCH_SIZE then
local indexes = mod.get_indexes_for_area(pos1, pos2, "node_counter")
if indexes then
for i=1,#indexes do
-- TODO: find nodes under air in area
end
end
end
-- Otherwize, fallback onto minetest builtin function
return minetest.find_nodes_in_area_under_air(pos1, pos2, nodenames)
end

View File

@ -0,0 +1,84 @@
local mod = vl_map_index
-- Adapter for when no vl_scheduler is not available
local periodic = {}
local tasks = {}
local functions = {}
local scheduler = {
register_periodic_task = function(name,period,priority,func)
periodic[#periodic + 1] = {
func = func,
period = period,
time = 0
}
local time = 0
minetest.register_globalstep(function(dtime)
time = time + dtime
if time >= period then
func()
time = time - period
end
end)
end,
register_function = function(name, func, default_time, default_priority)
functions[name] = func
end,
add_task = function(name, time, priority, args)
local func = functions[name]
if not func then return end
local task = {
func = func,
time = time,
args = args,
}
tasks[#tasks + 1] = task
end,
add_cancelable_task = function(name, time, priority, args)
local func = functions[name]
if not func then return end
local task = {
func = func,
time = time,
args = args,
}
function task:cancel()
task.canceled = true
end
tasks[#tasks + 1] = task
end
}
mod.scheduler = scheduler
minetest.register_globalstep(function(dtime)
-- Run periodic tasks
for i = 1,#periodic do
local task = periodic[i]
local time,period = task.time,task.period
time = time + dtime
if time >= period then
time = time - period
task.func()
end
task.time = time
end
-- Run tasks
local new_tasks = {}
for i = 1,#tasks do
local task = tasks[i]
local time = task.time
time = time - dtime
if time <= 0 then
if not task.canceled then
task.func(unpack(task.args))
end
else
task.time = time
new_tasks[#new_tasks + 1] = task
end
end
tasks = new_tasks
end)