Add support for offline mob accounting

Fix bug orphaned lifebars stay forever
Fix crash due to invalid data passed to path based movegen
This commit is contained in:
sapier 2013-12-09 15:25:55 +01:00
parent 09df9aa431
commit 60fb792151
5 changed files with 195 additions and 7 deletions

View File

@ -196,6 +196,9 @@ function mobf_init_framework()
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initialize lifebar subsystem..")
mobf_lifebar.init()
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initialize spawning subsystem..")
spawning.init()
minetest.log(LOGLEVEL_NOTICE,"MOBF: Initialize mobf supplied modules..")
mobf_init_modules()

View File

@ -46,14 +46,18 @@ function mobf_lifebar.init()
initialized = false,
on_step = function (self,dtime)
self.lifetime = self.lifetime + dtime
if not self.initialized then
self.lifetime = self.lifetime + dtime
if self.lifetime > 1 then
dbg_mobf.lifebar_lvl3("MOBF: lifebar not attached deleting")
self.object:remove()
end
end
--parent will reset lifetime while it's active
if self.lifetime > 5 then
self.object:remove()
end
end
})

View File

@ -467,7 +467,7 @@ function mobf.activate_handler(self,staticdata)
mobf_assert_backtrace(self.dynamic_data.current_movement_gen ~= nil)
--initialize movegen entity,current time, permanent data
self.dynamic_data.current_movement_gen.init_dynamic_data(self,now,retval)
self.dynamic_data.current_movement_gen.init_dynamic_data(self,now,preserved_data)
--call enter state fct
if self.dynamic_data.state.current.HANDLER_enter_state ~= nil then
@ -632,6 +632,10 @@ function mobf.register_entity(name, graphics, mob)
return
end
if self.lifebar ~= nil then
self.lifebar:get_luaentity().lifetime = 0
end
--check lifetime
if spawning.lifecycle_callback(self,now) == false then
mobf_warn_long_fct(starttime,"on_step_total_lifecycle","on_step_total")
@ -703,6 +707,9 @@ function mobf.register_entity(name, graphics, mob)
--make sure entity is in loaded area at initialization
local pos = self.object:getpos()
--remove from mob offline storage
spawning.activate_mob(self.data.modname .. ":" .. self.data.name,pos)
if pos ~= nil and
entity_at_loaded_pos(pos,self.data.name) then
mobf.activate_handler(self,staticdata)
@ -741,9 +748,12 @@ function mobf.register_entity(name, graphics, mob)
end,
--prepare permanent data
get_staticdata = function(self)
return mobf_serialize_permanent_entity_data(self)
end,
--NOTE this isn't called if a object is deleted
get_staticdata = function(self)
--add to mob offline storage
spawning.deactivate_mob(self.data.modname .. ":" .. self.data.name,self.object:getpos())
return mobf_serialize_permanent_entity_data(self)
end,
--custom variables for each mob
data = mob,

View File

@ -35,6 +35,153 @@ mobf_assert_backtrace(mobf_spawn_algorithms == nil)
--! @private
mobf_spawn_algorithms = {}
-------------------------------------------------------------------------------
-- name: init()
-- @function [parent=#spawning] init
--
--! @brief initialize spawning data
--! @memberof spawning
--
-------------------------------------------------------------------------------
function spawning.init()
--read from file
local world_path = minetest.get_worldpath()
local file,error = io.open(world_path .. "/mobf_spawning_data","r")
if file ~= nil then
local data_raw = file:read("*a")
file:close()
if data_raw ~= nil then
spawning.mob_spawn_data = minetest.deserialize(data_raw)
end
end
if spawning.mob_spawn_data == nil then
spawning.mob_spawn_data = {}
end
--register spawndata persistent storer to globalstep
minetest.after(300,spawning.preserve_spawn_data,true)
--register cleanup handler
minetest.register_on_shutdown(function(dstep) spawning.preserve_spawn_data(false) end)
end
-------------------------------------------------------------------------------
-- name: preserve_spawn_data()
-- @function [parent=#spawning] preserve_spawn_data
--
--! @brief save data on regular base
--! @memberof spawning
--
--! @param force
-------------------------------------------------------------------------------
function spawning.preserve_spawn_data(cyclic)
local world_path = minetest.get_worldpath()
local file,error = io.open(world_path .. "/mobf_spawning_data","w")
if error ~= nil then
minetest.log(LOGLEVEL_ERROR,"MOBF: failed to spawning preserve file")
end
mobf_assert_backtrace(file ~= nil)
local serialized_data = minetest.serialize(spawning.mob_spawn_data)
file:write(serialized_data)
if cyclic then
minetest.after(300,spawning.preserve_spawn_data,cyclic)
end
end
-------------------------------------------------------------------------------
-- name: total_offline_mobs()
-- @function [parent=#spawning] total_offline_mobs
--
--! @brief count total number of offline mobs
--! @memberof spawning
--
--! @return number of mobs
-------------------------------------------------------------------------------
function spawning.total_offline_mobs()
local count = 0
for key,value in pairs(spawning.mob_spawn_data) do
for hash,v in pairs(value) do
count = count +1
end
end
return count
end
-------------------------------------------------------------------------------
-- name: count_deactivated_mobs(name,pos,range)
-- @function [parent=#spawning] count_deactivated_mobs
--
--! @brief count number of mobs of specific type within a certain range
--! @memberof spawning
--
--! @param name name of mob to count
--! @param pos to check distance to
--! @param range to check
--
--! @return number of mobs
-------------------------------------------------------------------------------
function spawning.count_deactivated_mobs(name,pos,range)
local count = 0
if spawning.mob_spawn_data[name] ~= nil then
for hash,v in pairs(spawning.mob_spawn_data[name]) do
local mobpos = mobf_hash_to_pos(hash)
local distance = vector.distance(pos,mobpos)
if distance < range then
count = count +1
end
end
end
return count
end
-------------------------------------------------------------------------------
-- name: deactivate_mob(entity)
-- @function [parent=#spawning] deactivate_mob
--
--! @brief add mob to deactivated list
--! @memberof spawning
--
--! @param entity to deactivate
-------------------------------------------------------------------------------
function spawning.deactivate_mob(name,pos)
if spawning.mob_spawn_data[name] == nil then
spawning.mob_spawn_data[name] = {}
end
local rounded_pos = vector.round(pos)
local hash = minetest.hash_node_position(rounded_pos)
--assert (mobf_pos_is_same(mobf_hash_to_pos(hash),rounded_pos))
spawning.mob_spawn_data[name][hash] = true
end
-------------------------------------------------------------------------------
-- name: activate_mob(name,pos)
-- @function [parent=#spawning] preserve_spawn_data
--
--! @brief save data on regular base
--! @memberof spawning
--
--! @param force
-------------------------------------------------------------------------------
function spawning.activate_mob(name,pos)
if spawning.mob_spawn_data[name] ~= nil then
local rounded_pos = vector.round(pos)
local hash = minetest.hash_node_position(rounded_pos)
--assert(mobf_pos_is_same(mobf_hash_to_pos(hash),rounded_pos))
spawning.mob_spawn_data[name][hash] = nil
end
end
-------------------------------------------------------------------------------
-- name: remove_uninitialized(entity,staticdata)
@ -198,7 +345,7 @@ function spawning.population_density_check(entity,now)
mob_count .. " mobs of same type around")
entity.removed = true
minetest.log(LOGLEVEL_WARNING,"MOBF: Too many ".. mob_count .. " "..
entity.data.name.." at one place dying: " ..
entity.data.name.." at one place dieing: " ..
tostring(entity.dynamic_data.spawning.player_spawned))
spawning.remove(entity, "population density check")
return false

View File

@ -733,4 +733,28 @@ function mobf_is_pos(value)
return true
end
-------------------------------------------------------------------------------
-- name: mobf_hash_to_pos(hash)
--
--! @brief restore a position from a pos hash value
--
--! @param hash to restore pos from
--
--! @return posistion reconstructed from hash
-------------------------------------------------------------------------------
function mobf_hash_to_pos(hash)
local retval = {}
local raw_x = (hash % 65536)
local raw_y = ((hash - raw_x) % (65536*65536)) / 65536
local raw_z = ((hash - raw_x - raw_y) / 65536) / 65536
local mobpos = {}
retval.x = raw_x - 32768
retval.y = raw_y - 32768
retval.z = math.floor(raw_z - 32768)
return retval
end
--!@}