Aaron Suen e4337b698c Optimize visinv ent item checks
When items are just chillin' in place and not
changing stacks, don't recalculate and reapply
entity properties.
2020-06-15 22:05:26 -04:00

181 lines
4.7 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local math, minetest, nodecore, pairs, vector
= math, minetest, nodecore, pairs, vector
local math_random
= math.random
-- LUALOCALS > ---------------------------------------------------------
nodecore.amcoremod()
--[[
Helpers for visible inventory. Use "visinv" node group.
Sets up on_construct, after_destruct and an ABM to manage
the visual entities.
--]]
local modname = minetest.get_current_modname()
------------------------------------------------------------------------
-- VISIBLE STACK ENTITY
local function getlightcheck(rp, obj, src)
return function()
local stack = nodecore.stack_get(rp)
if not stack or stack:is_empty() then return end
local def = minetest.registered_items[stack:get_name()] or {}
if (def.light_source or 0) ~= src then return end
for _, v in pairs(nodecore.get_objects_at_pos(rp)) do
if v == obj then return true end
end
end
end
minetest.register_entity(modname .. ":stackent", {
initial_properties = nodecore.stackentprops(),
is_stack = true,
itemcheck = function(self)
self.cktime = math_random() + 0.5
local obj = self.object
local pos = obj:get_pos()
if not pos then return end
local stack = nodecore.stack_get(pos)
if not stack then return obj:remove() end
local sstr = stack:to_string()
if self.stackstring == sstr then return end
self.stackstring = sstr
if stack:is_empty() then return obj:remove() end
local rp = vector.round(pos)
local def = minetest.registered_items[stack:get_name()] or {}
local src = def.light_source or 0
if src > 0 then
self.light_source = src
nodecore.dynamic_light_add(rp, src, getlightcheck(rp, obj, src))
end
local props, scale, yaw = nodecore.stackentprops(stack,
rp.x * 3 + rp.y * 5 + rp.z * 7)
rp.y = rp.y + scale - 31/64
obj:set_properties(props)
if obj:get_yaw() ~= yaw then
obj:set_yaw(yaw)
end
if not vector.equals(obj:get_pos(), rp) then
obj:set_pos(rp)
end
end,
on_activate = function(self)
return self:itemcheck()
end,
on_step = function(self, dtime)
self.cktime = (self.cktime or 0) - dtime
if self.cktime > 0 then return end
return self:itemcheck()
end
})
local visenv_ent_check = {}
nodecore.register_globalstep("visinv check", function()
for _, e in pairs(minetest.luaentities) do
if e.is_stack then
local pos = e.object:get_pos()
if pos then
local key = minetest.hash_node_position(vector.round(pos))
local max = visenv_ent_check[key]
if max then
if max < 1 then
e.object:remove()
else
visenv_ent_check[key] = max - 1
end
end
end
end
end
for k, v in pairs(visenv_ent_check) do
if v > 0 then
local pos = minetest.get_position_from_hash(k)
minetest.add_entity(pos, modname .. ":stackent")
end
end
visenv_ent_check = {}
end)
function nodecore.visinv_update_ents(pos, node)
pos = vector.round(pos)
node = node or minetest.get_node(pos)
local def = minetest.registered_items[node.name] or {}
local max = def.groups and def.groups.visinv and 1 or 0
if nodecore.stack_get(pos):is_empty() then max = 0 end
visenv_ent_check[minetest.hash_node_position(pos)] = max
end
------------------------------------------------------------------------
-- NODE REGISTRATION HELPERS
function nodecore.visinv_on_construct(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("solo", 1)
nodecore.visinv_update_ents(pos)
end
function nodecore.visinv_after_destruct(pos)
nodecore.visinv_update_ents(pos)
nodecore.fallcheck(pos)
end
nodecore.register_on_register_item(function(_, def)
if def.type ~= "node" then return end
def.groups = def.groups or {}
if def.groups.visinv then
def.on_construct = def.on_construct or nodecore.visinv_on_construct
def.after_destruct = def.after_destruct or nodecore.visinv_after_destruct
end
end)
nodecore.register_limited_abm({
label = "VisInv Check",
nodenames = {"group:visinv"},
interval = 1,
chance = 1,
ignore_stasis = true,
action = function(...) return nodecore.visinv_update_ents(...) end
})
------------------------------------------------------------------------
-- DIG INVENTORY
local digpos
local old_node_dig = minetest.node_dig
minetest.node_dig = function(pos, ...)
nodecore.stack_sounds(pos, "dug")
local function helper(...)
digpos = nil
return ...
end
digpos = pos
return helper(old_node_dig(pos, ...))
end
local old_get_node_drops = minetest.get_node_drops
minetest.get_node_drops = function(...)
local drops = old_get_node_drops(...)
if not digpos then return drops end
drops = drops or {}
local stack = nodecore.stack_get(digpos)
if stack and not stack:is_empty() then
drops[#drops + 1] = stack
end
return drops
end