forked from VoxeLibre/VoxeLibre
Add server lag tracking to mcl_player global step, maintain an index of lightning attractors in mod storage for mcl_lightning_rods and use this instead of minetest.find_node_near during lightning strikes, modify node definition to allow for additional lightning attractors
This commit is contained in:
parent
d264ba70d8
commit
b64f7c81b2
|
@ -0,0 +1,194 @@
|
||||||
|
local storage = minetest.get_mod_storage()
|
||||||
|
local mod = mcl_lightning_rods
|
||||||
|
local BLOCK_SIZE = 64
|
||||||
|
|
||||||
|
-- Helper functions
|
||||||
|
function vector_floor(v)
|
||||||
|
return vector.new( math.floor(v.x), math.floor(v.y), math.floor(v.z) )
|
||||||
|
end
|
||||||
|
function vector_min(a,b)
|
||||||
|
return vector.new( math.min(a.x,b.x), math.min(a.y,b.y), math.min(a.z,b.z) )
|
||||||
|
end
|
||||||
|
function vector_max(a,b)
|
||||||
|
return vector.new( math.max(a.x,b.x), math.max(a.y,b.y), math.max(a.z,b.z) )
|
||||||
|
end
|
||||||
|
|
||||||
|
local function read_voxel_area(pos1, pos2)
|
||||||
|
local vm = minetest.get_voxel_manip()
|
||||||
|
local minp, maxp = vm:read_from_map(pos1, pos2)
|
||||||
|
local data = vm:get_data()
|
||||||
|
local area = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
|
||||||
|
|
||||||
|
return vm,data,area
|
||||||
|
end
|
||||||
|
|
||||||
|
local function load_index(x,y,z)
|
||||||
|
local idx_key = string.format("%d-%d,%d,%d",BLOCK_SIZE,x,y,z)
|
||||||
|
local idx_str = storage:get_string(idx_key)
|
||||||
|
if idx_str and idx_str ~= "" then
|
||||||
|
local idx = minetest.deserialize(idx_str)
|
||||||
|
return idx
|
||||||
|
end
|
||||||
|
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
local function load_index_vector(pos)
|
||||||
|
return load_index(pos.x,pos.y,pos.z)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function save_index(x,y,z, idx)
|
||||||
|
local idx_str = minetest.serialize(idx)
|
||||||
|
local idx_key = string.format("%d-%d,%d,%d",BLOCK_SIZE,x,y,z)
|
||||||
|
storage:set_string(idx_key, idx_str)
|
||||||
|
end
|
||||||
|
local function save_index_vector(pos, idx)
|
||||||
|
return save_index(pos.x,pos.y,pos.z, idx)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove duplicates and verify all locations have a lightning attractor present
|
||||||
|
local function clean_index(idx, drop)
|
||||||
|
local new_idx = {}
|
||||||
|
local exists = {}
|
||||||
|
for _,p in ipairs(idx) do
|
||||||
|
local key = string.format("%d,%d,%d",p.x,p.y,p.z)
|
||||||
|
if not exists[key] then
|
||||||
|
exists[key] = true
|
||||||
|
|
||||||
|
local node = minetest.get_node(p)
|
||||||
|
if minetest.get_item_group(node.name, "attracts_lightning") ~= 0 or (drop and vector.distance(p,drop) < 0.1 ) then
|
||||||
|
new_idx[#new_idx + 1] = p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return new_idx
|
||||||
|
end
|
||||||
|
|
||||||
|
function mod.find_attractors_in_area(pos1, pos2)
|
||||||
|
-- Normalize the search area into large, regular blocks
|
||||||
|
local pos1_r = vector_floor(pos1 / BLOCK_SIZE)
|
||||||
|
local pos2_r = vector_floor(pos2 / BLOCK_SIZE)
|
||||||
|
local min = vector_min(pos1_r, pos2_r)
|
||||||
|
local max = vector_max(pos1_r, pos2_r)
|
||||||
|
|
||||||
|
local results = {}
|
||||||
|
for z = min.z,max.z do
|
||||||
|
for y = min.y,max.y do
|
||||||
|
for x = min.x,max.x do
|
||||||
|
local idx = load_index(x,y,z)
|
||||||
|
|
||||||
|
-- Make sure every indexed position actually has a lightning attractor present
|
||||||
|
for _,pos in ipairs(idx) do
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if minetest.get_item_group(node.name, "attracts_lightning") ~= 0 then
|
||||||
|
results[#results + 1] = pos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
local function find_closest_position_in_list(pos, list)
|
||||||
|
local dist = nil
|
||||||
|
local best = nil
|
||||||
|
for _,p in ipairs(list) do
|
||||||
|
local p_dist = vector.distance(p,pos)
|
||||||
|
if not dist or p_dist < dist then
|
||||||
|
dist = p_dist
|
||||||
|
best = p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return best
|
||||||
|
end
|
||||||
|
|
||||||
|
function mod.find_closest_attractor(pos, search_size)
|
||||||
|
local attractor_positions = mod.find_attractors_in_area(
|
||||||
|
vector.offset(pos, -search_size, -search_size, -search_size),
|
||||||
|
vector.offset(pos, search_size, search_size, search_size)
|
||||||
|
)
|
||||||
|
return find_closest_position_in_list(pos, attractor_positions)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mod.unregister_lightning_attractor(pos)
|
||||||
|
-- Verify the node no longer attracts lightning
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if minetest.get_item_group(node.name, "attracts_lightning") ~= 0 then return end
|
||||||
|
|
||||||
|
-- Get the existing index data (if any)
|
||||||
|
local pos_r = vector_floor(pos / BLOCK_SIZE)
|
||||||
|
local idx = load_index_vector(pos_r)
|
||||||
|
|
||||||
|
-- Clean the index and drop this node
|
||||||
|
idx = clean_index(idx, pos)
|
||||||
|
save_index_vector(pos_r, idx)
|
||||||
|
end
|
||||||
|
function mod.register_lightning_attractor(pos)
|
||||||
|
-- Verify the node attracts lightning
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if minetest.get_item_group(node.name, "attracts_lightning") == 0 then return end
|
||||||
|
|
||||||
|
-- Get the existing index data (if any)
|
||||||
|
local pos_r = vector_floor(pos / BLOCK_SIZE)
|
||||||
|
local idx = load_index_vector(pos_r)
|
||||||
|
for _,p in ipairs(idx) do
|
||||||
|
-- Don't need to change anything if the rod is already registered
|
||||||
|
if vector.distance(p,pos) < 0.1 then return end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add and save the rod position
|
||||||
|
idx[#idx + 1] = pos
|
||||||
|
|
||||||
|
-- Clean and save the index data
|
||||||
|
clean_index(idx)
|
||||||
|
save_index_vector(pos_r, idx)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Constants used for content id index
|
||||||
|
local IS_ATTRACTOR = {}
|
||||||
|
local IS_NOT_ATTRACTOR = {}
|
||||||
|
function mod.index_block(pos)
|
||||||
|
local pos_r = vector_floor(pos1 / BLOCK_SIZE)
|
||||||
|
local pos1 = vector.multiply(pos_r,BLOCK_SIZE)
|
||||||
|
local pos2 = vector.offset(pos,BLOCK_SIZE - 1,BLOCK_SIZE - 1,BLOCK_SIZE - 1)
|
||||||
|
|
||||||
|
-- We are completely rebuilding the index data so there is no nead to load
|
||||||
|
-- the existing data
|
||||||
|
local idx = {}
|
||||||
|
|
||||||
|
-- Setup voxel manipulator
|
||||||
|
local vm,data,area = read_voxel_area()
|
||||||
|
|
||||||
|
-- Indexes to speed things up
|
||||||
|
local cid_attractors = {}
|
||||||
|
|
||||||
|
-- Iterate over the area and look for lightning attractors
|
||||||
|
local minx = pos1.x
|
||||||
|
local maxx = pos1.x
|
||||||
|
for z = pos1.z,pos2.z do
|
||||||
|
for y = pos1.y,pos2.y do
|
||||||
|
for x = minx,maxx do
|
||||||
|
local vi = area:index(x,y,z)
|
||||||
|
local cid = data[vi]
|
||||||
|
local attr = cid_attractors[cid]
|
||||||
|
if attr then
|
||||||
|
if attr == IS_ATTRACTOR then
|
||||||
|
idx[#idx + 1] = vector.new(x,y,z)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Lookup data and cache for later
|
||||||
|
local name = minetest.get_name_from_content_id(cid)
|
||||||
|
if minetest.get_item_group(name, "attracts_lightning") then
|
||||||
|
cid_attractors = IS_ATTRACTOR
|
||||||
|
idx[#idx + 1] = vector.new(x,y,z)
|
||||||
|
else
|
||||||
|
cid_attractors = IS_NOT_ATTRACTOR
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save for later use
|
||||||
|
save_index_vector(pos_r, idx)
|
||||||
|
end
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
|
local modname = minetest.get_current_modname()
|
||||||
|
local modpath = minetest.get_modpath(modname)
|
||||||
local S = minetest.get_translator("mcl_lightning_rods")
|
local S = minetest.get_translator("mcl_lightning_rods")
|
||||||
|
|
||||||
|
mcl_lightning_rods = {}
|
||||||
|
local mod = mcl_lightning_rods
|
||||||
|
|
||||||
|
dofile(modpath.."/api.lua")
|
||||||
|
|
||||||
---@type nodebox
|
---@type nodebox
|
||||||
local cbox = {
|
local cbox = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
|
@ -59,6 +66,17 @@ local rod_def = {
|
||||||
|
|
||||||
return minetest.item_place(itemstack, placer, pointed_thing, param2)
|
return minetest.item_place(itemstack, placer, pointed_thing, param2)
|
||||||
end,
|
end,
|
||||||
|
after_place_node = function(pos, placer, itemstack, pointed_thing)
|
||||||
|
mod.register_lightning_attractor(pos)
|
||||||
|
end,
|
||||||
|
after_destruct = function(pos, oldnode)
|
||||||
|
mod.unregister_lightning_attractor(pos)
|
||||||
|
end,
|
||||||
|
_on_lightning_strike = function(pos, node)
|
||||||
|
minetest.set_node(pos, { name = "mcl_lightning_rods:rod_powered", param2 = node.param2 })
|
||||||
|
mesecon.receptor_on(pos, mesecon.rules.alldirs)
|
||||||
|
minetest.get_node_timer(pos):start(0.4)
|
||||||
|
end,
|
||||||
|
|
||||||
_mcl_blast_resistance = 6,
|
_mcl_blast_resistance = 6,
|
||||||
_mcl_hardness = 3,
|
_mcl_hardness = 3,
|
||||||
|
@ -92,21 +110,21 @@ end
|
||||||
|
|
||||||
minetest.register_node("mcl_lightning_rods:rod_powered", rod_def_a)
|
minetest.register_node("mcl_lightning_rods:rod_powered", rod_def_a)
|
||||||
|
|
||||||
|
|
||||||
lightning.register_on_strike(function(pos, pos2, objects)
|
lightning.register_on_strike(function(pos, pos2, objects)
|
||||||
local lr = minetest.find_node_near(pos, 128, { "group:attracts_lightning" }, true)
|
local lr = mod.find_closest_attractor(pos, 64)
|
||||||
|
if not lr then return end
|
||||||
|
|
||||||
if lr then
|
-- Make sure this possition attracts lightning
|
||||||
local node = minetest.get_node(lr)
|
local node = minetest.get_node(lr)
|
||||||
|
if minetest.get_item_group(node.name, "attracts_lightning") == 0 then return end
|
||||||
|
|
||||||
if node.name == "mcl_lightning_rods:rod" then
|
-- Allow the node to process a lightning strike
|
||||||
minetest.set_node(lr, { name = "mcl_lightning_rods:rod_powered", param2 = node.param2 })
|
local nodedef = minetest.registered_nodes[node.name]
|
||||||
mesecon.receptor_on(lr, mesecon.rules.alldirs)
|
if nodedef and nodedef._on_lightning_strike then
|
||||||
minetest.get_node_timer(lr):start(0.4)
|
nodedef._on_lightning_strike(lr, node)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return lr, nil
|
return lr
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -117,3 +135,10 @@ minetest.register_craft({
|
||||||
{ "", "mcl_copper:copper_ingot", "" },
|
{ "", "mcl_copper:copper_ingot", "" },
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
minetest.register_lbm({
|
||||||
|
name = "mcl_lightning_rods:index_rods",
|
||||||
|
nodenames = {"mcl_lightning_rods:rod","mcl_lightning_rods:rod_powered"},
|
||||||
|
action = function(pos, node)
|
||||||
|
mod.register_lightning_attractor(pos)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
|
@ -213,6 +213,11 @@ local player_attached = mcl_player.player_attached
|
||||||
|
|
||||||
-- Check each player and apply animations
|
-- Check each player and apply animations
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
|
-- Track server lag greater than 110ms
|
||||||
|
if dtime > 0.11 then
|
||||||
|
minetest.log("warning", "Timestep greater than 110ms("..tostring(math.floor(dtime*1000)).." ms), server lag detected")
|
||||||
|
end
|
||||||
|
|
||||||
for _, player in pairs(minetest.get_connected_players()) do
|
for _, player in pairs(minetest.get_connected_players()) do
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local model_name = player_model[name]
|
local model_name = player_model[name]
|
||||||
|
|
Loading…
Reference in New Issue