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.
This commit is contained in:
Foz 2018-03-12 03:50:14 -04:00 committed by Vanessa Dannenberg
parent eb2b3d7980
commit 39984c356b
1 changed files with 43 additions and 17 deletions

View File

@ -32,6 +32,25 @@ minetest.register_entity("itemframes:item",{
if self.nodename == "itemframes:pedestal" then if self.nodename == "itemframes:pedestal" then
self.object:set_properties({automatic_rotate = 1}) self.object:set_properties({automatic_rotate = 1})
end 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, end,
get_staticdata = function(self) get_staticdata = function(self)
if self.nodename ~= nil and self.texture ~= nil then 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 -- automatically restore entities lost from frames/pedestals
-- due to /clearobjects or similar -- due to /clearobjects or similar
minetest.register_lbm({
minetest.register_abm({ label = "Maintain itemframe and pedestal entities",
name = "itemframes:maintain_entities",
nodenames = {"itemframes:frame", "itemframes:pedestal"}, nodenames = {"itemframes:frame", "itemframes:pedestal"},
interval = 15, run_at_every_load = true,
chance = 1, action = function(pos, node)
action = function(pos, node, active_object_count, active_object_count_wider) minetest.after(0,
local num function(pos, node)
local meta = minetest.get_meta(pos)
if node.name == "itemframes:frame" then local itemstring = meta:get_string("item")
num = #minetest.get_objects_inside_radius(pos, 0.5) if itemstring ~= "" then
elseif node.name == "itemframes:pedestal" then local entity_pos = pos
pos.y = pos.y + 1 if node.name == "itemframes:pedestal" then
num = #minetest.get_objects_inside_radius(pos, 0.5) entity_pos = {x=pos.x,y=pos.y+1,z=pos.z}
pos.y = pos.y - 1 end
end local objs = minetest.get_objects_inside_radius(entity_pos, 0.5)
if #objs == 0 then
if num > 0 then return end minetest.log("action","[itemframes] Replacing missing " ..
update_item(pos, node) itemstring .. " in " .. node.name .. " at " ..
minetest.pos_to_string(pos))
update_item(pos, node)
end
end
end,
pos, node)
end end
}) })