From 39984c356bf51161f5eddf8d48fb115098508a97 Mon Sep 17 00:00:00 2001 From: Foz Date: Mon, 12 Mar 2018 03:50:14 -0400 Subject: [PATCH] Resolve itemframe entity duplication Fixes #405. The ABM that replaces deleted entities in itemframes and pedestals can sometimes add multiple copies of each entity due to a race condition in which the ABM runs either before the server loads the entities or after they have been removed due to the map block being unloaded. Due to limitations in determining when all entities have been loaded, this race condition cannot be fully avoided. This commit converts the ABM, which ran every fifteen seconds, into and LBM that runs on every load and adds a check to the entities when they are loaded such that only the first loaded entity will be kept and any additional copies delete themselves during the loading process. --- itemframes/init.lua | 60 ++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/itemframes/init.lua b/itemframes/init.lua index d26df19c..21fac2f3 100644 --- a/itemframes/init.lua +++ b/itemframes/init.lua @@ -32,6 +32,25 @@ minetest.register_entity("itemframes:item",{ if self.nodename == "itemframes:pedestal" then self.object:set_properties({automatic_rotate = 1}) end + if self.texture ~= nil and self.nodename ~= nil then + local entity_pos = vector.round(self.object:get_pos()) + local objs = minetest.get_objects_inside_radius(entity_pos, 0.5) + for _, obj in ipairs(objs) do + if obj ~= self.object and + obj:get_luaentity() and + obj:get_luaentity().name == "itemframes:item" and + obj:get_luaentity().nodename == self.nodename and + obj:get_properties() and + obj:get_properties().textures and + obj:get_properties().textures[1] == self.texture then + minetest.log("action","[itemframes] Removing extra " .. + self.texture .. " found in " .. self.nodename .. " at " .. + minetest.pos_to_string(entity_pos)) + self.object:remove() + break + end + end + end end, get_staticdata = function(self) if self.nodename ~= nil and self.texture ~= nil then @@ -228,24 +247,31 @@ minetest.register_node("itemframes:pedestal",{ -- automatically restore entities lost from frames/pedestals -- due to /clearobjects or similar - -minetest.register_abm({ +minetest.register_lbm({ + label = "Maintain itemframe and pedestal entities", + name = "itemframes:maintain_entities", nodenames = {"itemframes:frame", "itemframes:pedestal"}, - interval = 15, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - local num - - if node.name == "itemframes:frame" then - num = #minetest.get_objects_inside_radius(pos, 0.5) - elseif node.name == "itemframes:pedestal" then - pos.y = pos.y + 1 - num = #minetest.get_objects_inside_radius(pos, 0.5) - pos.y = pos.y - 1 - end - - if num > 0 then return end - update_item(pos, node) + run_at_every_load = true, + action = function(pos, node) + minetest.after(0, + function(pos, node) + local meta = minetest.get_meta(pos) + local itemstring = meta:get_string("item") + if itemstring ~= "" then + local entity_pos = pos + if node.name == "itemframes:pedestal" then + entity_pos = {x=pos.x,y=pos.y+1,z=pos.z} + end + local objs = minetest.get_objects_inside_radius(entity_pos, 0.5) + if #objs == 0 then + minetest.log("action","[itemframes] Replacing missing " .. + itemstring .. " in " .. node.name .. " at " .. + minetest.pos_to_string(pos)) + update_item(pos, node) + end + end + end, + pos, node) end })