Delete un-initialized item entities on first step

Due to data corruption, item entities in a world may be loaded with
empty staticdata. These items are now deleted on their first on_step.
This commit also should fix all dropped hand bugs.
This commit is contained in:
Wuzzy 2017-12-01 18:50:15 +01:00
parent a5b213968c
commit 312652552e

View file

@ -68,7 +68,7 @@ minetest.register_globalstep(function(dtime)
-- Collection -- Collection
if vector.distance(checkpos, object:getpos()) <= item_drop_settings.radius_collect and not object:get_luaentity()._removed then if vector.distance(checkpos, object:getpos()) <= item_drop_settings.radius_collect and not object:get_luaentity()._removed then
-- Ignore if itemstring is not set yet
if object:get_luaentity().itemstring ~= "" then if object:get_luaentity().itemstring ~= "" then
inv:add_item("main", ItemStack(object:get_luaentity().itemstring)) inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
minetest.sound_play("item_drop_pickup", { minetest.sound_play("item_drop_pickup", {
@ -78,20 +78,14 @@ minetest.register_globalstep(function(dtime)
}) })
check_pickup_achievements(object, player) check_pickup_achievements(object, player)
-- If this happens, itemstring was "" (=hand). This is always a bug, the hand must never drop as item.
else
-- Scream this to the error log because this is bad.
minetest.log("error", "Player "..player:get_player_name().." collected a hand at "..minetest.pos_to_string(object:getpos()).." (age="..object:get_luaentity().age..")!")
-- Destroy entity
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
object:get_luaentity()._removed = true
object:remove()
collected = true
end end
-- Destroy entity
-- This just prevents this sectino to be run again because object:remove() doesn't remove the item immediately.
object:get_luaentity()._removed = true
object:remove()
collected = true
-- Magnet -- Magnet
else else
@ -313,17 +307,27 @@ core.register_entity(":__builtin:item", {
infotext = "", infotext = "",
}, },
-- Itemstring of dropped item. The empty string is used when the item is not yet initialized yet.
-- The itemstring MUST be set immediately to a non-empty string after creating the entity.
-- The hand is NOT permitted as dropped item. ;-)
-- Item entities will be deleted if they still have an empty itemstring on their first on_step tick.
itemstring = '', itemstring = '',
-- If true, item will fall
physical_state = true, physical_state = true,
_flowing = false, -- item entity is currently flowing
-- States: -- If item entity is currently flowing in water
-- * "magnet": Attracted to a nearby player or item _flowing = false,
-- * "flowing": Moving in a flowing liquid
-- * "normal": Affected by gravitiy -- Number of seconds this item entity has existed so far
age = 0, age = 0,
set_item = function(self, itemstring) set_item = function(self, itemstring)
self.itemstring = itemstring self.itemstring = itemstring
if self.itemstring == "" then
-- item not yet known
return
end
local stack = ItemStack(itemstring) local stack = ItemStack(itemstring)
local count = stack:get_count() local count = stack:get_count()
local max_count = stack:get_stack_max() local max_count = stack:get_stack_max()
@ -488,11 +492,12 @@ core.register_entity(":__builtin:item", {
self.object:remove() self.object:remove()
return return
end end
-- If, for some reason, an item entity with itemstring == "" (hand) appears, this is very bad. -- Delete corrupted item entities. The itemstring MUST be non-empty on its first step,
if not self._hand_bug_detected and self.age > 1 and self.itemstring == "" then -- otherwise there might have some data corruption.
-- We must this scream this into the error console. The bug is rare an if self.itemstring == "" then
minetest.log("error", "A hand item entity appeared at "..minetest.pos_to_string(self.object:getpos()).. "!") minetest.log("warning", "Item entity with empty itemstring found at "..minetest.pos_to_string(self.object:getpos()).. "! Deleting it now.")
self._hand_bug_detected = true self._removed = true
self.object:remove()
end end
local p = self.object:getpos() local p = self.object:getpos()