Add "adv_spawning" mod.
This commit is contained in:
parent
d02b413e89
commit
7ce0a031b9
@ -4,6 +4,7 @@ A custom game for Minetest/Freeminer
|
||||
The game includes the mods from the default [minetest_game](https://github.com/minetest/minetest_game/tree/master/mods)
|
||||
|
||||
The following mods are also included:
|
||||
* [adv_spawning][] ([???](mods/adv_spawning/README.txt))
|
||||
* [animalmaterials (modpack)][animalmaterials] (CC-BY-SA / CC0)
|
||||
* [awards][] ([LGPL](mods/awards/LICENSE.txt))
|
||||
* buildings/
|
||||
@ -80,6 +81,7 @@ The following mods are also included:
|
||||
|
||||
|
||||
[3d_armor]: https://forum.minetest.net/viewtopic.php?t=4654
|
||||
[adv_spawning]: https://github.com/sapier/adv_spawning
|
||||
[animalmaterials]: https://github.com/sapier/animalmaterials
|
||||
[animals_modpack]: https://forum.minetest.net/viewtopic.php?t=629
|
||||
[awards]: https://forum.minetest.net/viewtopic.php?t=4870
|
||||
|
220
mods/adv_spawning/README.txt
Normal file
220
mods/adv_spawning/README.txt
Normal file
@ -0,0 +1,220 @@
|
||||
********************************************************************************
|
||||
* *
|
||||
* Advanced spawning mod (adv_spawning) 0.0.6 *
|
||||
* *
|
||||
* URL: http://github.com/sapier/adv_spawning *
|
||||
* Author: sapier *
|
||||
* *
|
||||
********************************************************************************
|
||||
|
||||
|
||||
Description:
|
||||
--------------------
|
||||
Advances spawning mod is designed to provide a feature rich yet easy to use
|
||||
spawner for entites. It's purpose is to support spawning within large numbers
|
||||
of different environments. While adv_spawning supports a wide configurable range
|
||||
of spawning situations, it's performance impact is clamped at minimal level.
|
||||
To achieve this performance goal adv_spawning is intended for low frequency
|
||||
entity spawning only. Typical spawn rate will be a low single digit count of
|
||||
entities per second throughout whole world.
|
||||
|
||||
|
||||
API:
|
||||
--------------------
|
||||
adv_spawning.register(spawner_name,spawning_def) --> successfull true/false
|
||||
^ register a spawn to adv_spawning mechanisms
|
||||
^ spawner_name a unique spawner name
|
||||
^ spawning_def is configuration of spawner
|
||||
|
||||
adv_spawning.statistics() --> statistics data about spawning
|
||||
|
||||
Spawning definition:
|
||||
--------------------
|
||||
{
|
||||
spawnee = "some_mod:entity_name", -- name of entity to spawn OR function to be called e.g. func(pos)
|
||||
absolute_height = -- absolute y value to check
|
||||
{
|
||||
min = 1, -- minimum height to spawn at
|
||||
max = 5 -- maximum height to spawn at
|
||||
}
|
||||
|
||||
relative_height = --relative y value to next non environment node
|
||||
{
|
||||
min = 1, -- minimum height above non environment node
|
||||
max = 5 -- maximum height above non environment node
|
||||
}
|
||||
|
||||
spawn_inside, -- [MANDATORY] list of nodes to to spawn within (see spawn inside example)
|
||||
surfaces, -- list of nodes to spawn uppon (same format as spawn_inside)
|
||||
|
||||
entities_around = -- list of surrounding entity definitions
|
||||
{
|
||||
entity_def_1,
|
||||
entity_def_2,
|
||||
...
|
||||
},
|
||||
|
||||
nodes_around = -- list of surrounding node definitions
|
||||
{
|
||||
node_def_1,
|
||||
node_def_2,
|
||||
...
|
||||
},
|
||||
|
||||
light_around = -- list of light around definitions
|
||||
{
|
||||
light_around_def_1,
|
||||
light_around_def_2,
|
||||
...
|
||||
},
|
||||
|
||||
humidity_around = -- list of humidity around definitions
|
||||
{
|
||||
humidity_around_def_1,
|
||||
humidity_around_def_2,
|
||||
...
|
||||
},
|
||||
|
||||
temperature_around = -- list of temperature around definitions
|
||||
{
|
||||
temperature_around_def_1,
|
||||
temperature_around_def_2,
|
||||
...
|
||||
},
|
||||
|
||||
mapgen = -- configuration for initial mapgen spawning
|
||||
{
|
||||
enabled = true, -- mapgen spawning enabled or not
|
||||
retries = 5, -- number of tries to spawn a entity prior giving up
|
||||
spawntotal = 3, -- number of entities to try on mapgen
|
||||
},
|
||||
|
||||
|
||||
flat_area = -- check for amount of flat area around,
|
||||
-- (only usefull for ground bound mobs)
|
||||
{
|
||||
range = 3, -- range to be checked for flattness
|
||||
deviation = 2, -- maximum number of nodes not matching flat check
|
||||
},
|
||||
|
||||
daytimes = -- do only spawn within these daytimes
|
||||
{
|
||||
daytime_def_1,
|
||||
daytime_def_2,
|
||||
...
|
||||
}
|
||||
|
||||
collisionbox = {}, -- collisionbox of entity to spawn (usually same as used for entiy itself)
|
||||
spawn_interval = 200, -- [MANDATORY] interval to try to spawn a entity
|
||||
spawns_per_interval = 1, -- try to spawn multiple mobs (if time available)
|
||||
custom_check = fct(pos,spawndef), -- a custom check to be called return true for pass, false for not pass
|
||||
cyclic_spawning = true -- spawn per spawner step (defaults to true)
|
||||
}
|
||||
|
||||
Light around definition:
|
||||
{
|
||||
type = "TIMED_MIN", -- type of light around check
|
||||
-- TIMED_MIN/TIMED_MAX at least this light level at specified time within whole distance
|
||||
-- OVERALL_MAX,OVERALL_MIN at least this light level at any time
|
||||
-- CURRENT_MIN,CURRENT_MAX at least this light level now
|
||||
distance = 2, -- distance to check (be carefull high distances may cause lag)
|
||||
-- WARNING: light check is a very very heavy operation don't use large distances
|
||||
threashold = 2, -- value to match at max/at least to pass this check
|
||||
time = 6000 -- time to do check at (TIMED_MIN/TIMED_MAX only)
|
||||
}
|
||||
|
||||
Surrounding node definition:
|
||||
{
|
||||
type = "MIN", -- type of surround check valid types are MIN and MAX
|
||||
name = { "default:tree" },-- name(s) of node(s) to check
|
||||
distance = 7, -- distance to look for node
|
||||
threshold = 1 -- number to match at max/at least to pass this check
|
||||
}
|
||||
|
||||
Surrounding entity definition:
|
||||
{
|
||||
type = "MIN", -- type of surround check valid types are MIN and MAX
|
||||
entityname = "mod:entity", -- name of entity to check (nil to match all)
|
||||
distance = 3, -- distance to look for this entity
|
||||
threshold = 2 -- number to match at max/at least to pass this check
|
||||
}
|
||||
|
||||
Surrounding temperature definition:
|
||||
{
|
||||
type = "MIN", -- type of surround check valid types are MIN and MAX
|
||||
distance = 3, -- distance to look for this temperature
|
||||
threshold = 2 -- number to match at max/at least to pass this check
|
||||
}
|
||||
|
||||
Surrounding humidity definition:
|
||||
{
|
||||
type = "MIN", -- type of surround check valid types are MIN and MAX
|
||||
distance = 3, -- distance to look for this humidity
|
||||
threshold = 2 -- number to match at max/at least to pass this check
|
||||
}
|
||||
|
||||
spawn_inside definition (list of nodenames):
|
||||
{
|
||||
"air",
|
||||
"default:water_source",
|
||||
"default:water_flowing"
|
||||
}
|
||||
|
||||
Daytime definition:
|
||||
{
|
||||
begin = 0.0, --minimum daytime
|
||||
stop = 0.25, --maximum daytime
|
||||
}
|
||||
|
||||
Statistics:
|
||||
{
|
||||
session =
|
||||
{
|
||||
spawners_created = 0, -- number of spawners created this session
|
||||
entities_created = 0, -- number of spawns done
|
||||
steps = 0, -- number of steps
|
||||
},
|
||||
step =
|
||||
{
|
||||
min = 0, -- minimum time required for a single step
|
||||
max = 0, -- maximum time required for a single step
|
||||
last = 0, -- last steps time
|
||||
},
|
||||
load =
|
||||
{
|
||||
min = 0, -- minimum load caused
|
||||
max = 0, -- maximum load caused
|
||||
cur = 0, -- load caused in last step
|
||||
avg = 0 -- average load caused
|
||||
}
|
||||
}
|
||||
|
||||
Settings:
|
||||
adv_spawning_validate_spawners = false
|
||||
^ make advanced_spawning check area around active players for lost spawner seeds
|
||||
|
||||
Changelog:
|
||||
|
||||
0.0.9
|
||||
-Fix broken spawner initialization
|
||||
-Add support for regenerating spawner seeds (only around active players)
|
||||
set >>adv_spawning_validate_spawners<< to true if you want advanced spawning
|
||||
to do this.
|
||||
Note: this might need some additional cpu time
|
||||
|
||||
0.0.8
|
||||
-Fix large steps caused by uninterruptable spawn seed initialization within activation
|
||||
|
||||
0.0.7
|
||||
-handle time steps backward without assertion
|
||||
|
||||
0.0.6
|
||||
-add configuration option adv_spawing.debug to show or hide spawner entities
|
||||
-fix quota overflow calculation
|
||||
-add rightclick function to show debug info
|
||||
|
||||
0.0.5
|
||||
-fix MIN/MAX to always return a number value
|
||||
-fix default activity range to use a initial value if not manually configured
|
||||
-don't calculate statistics with zero dtime
|
||||
-fix invalid debug log using old variable name
|
53
mods/adv_spawning/api.lua
Normal file
53
mods/adv_spawning/api.lua
Normal file
@ -0,0 +1,53 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- advanced spawning mod
|
||||
--
|
||||
--@license WTFP
|
||||
--@copyright Sapier
|
||||
--@author Sapier
|
||||
--@date 2013-12-05
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] register
|
||||
-- @param spawn_definition a definition to use for spawning
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.register(spawner_name,spawning_def)
|
||||
if adv_spawning.spawner_definitions[spawner_name] == nil then
|
||||
|
||||
|
||||
if not adv_spawning.verify_check_entities_around(spawning_def.entities_around) then
|
||||
return false
|
||||
end
|
||||
|
||||
if not adv_spawning.verify_check_nodes_around(spawning_def.nodes_around) then
|
||||
return false
|
||||
end
|
||||
|
||||
adv_spawning.spawner_definitions[spawner_name] = spawning_def
|
||||
adv_spawning.dbg_log(0, "registering spawner \"" .. spawner_name .. "\"")
|
||||
adv_spawning.dbg_log(0, "now handling: " ..
|
||||
adv_spawning.table_count(adv_spawning.spawner_definitions) ..
|
||||
" spawner definitions")
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] get_statistics
|
||||
-- @return get snapshot of statistics
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.get_statistics()
|
||||
return minetest.deserialize(minetest.serialize(adv_spawning.statistics))
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] get_spawner_density
|
||||
-- @return get snapshot of statistics
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.get_spawner_density()
|
||||
return adv_spawning.spawner_distance,adv_spawning.spawner_y_offset
|
||||
end
|
34
mods/adv_spawning/init.lua
Normal file
34
mods/adv_spawning/init.lua
Normal file
@ -0,0 +1,34 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- advanced spawning mod
|
||||
--
|
||||
--@license WTFP
|
||||
--@copyright Sapier
|
||||
--@author Sapier
|
||||
--@date 2013-12-05
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local version = "0.0.13"
|
||||
|
||||
if adv_spawning ~= nil then
|
||||
core.log("error", "MOD: adv_spawning requires adv_spawning variable to be available")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @type adv_spawning base element for usage of adv_spawning
|
||||
-- -----------------------------------------------------------------------------
|
||||
adv_spawning = {}
|
||||
|
||||
adv_spawning.debug = core.setting_get("adv_spawning.debug")
|
||||
|
||||
local adv_modpath = core.get_modpath("adv_spawning")
|
||||
|
||||
dofile (adv_modpath .. "/internal.lua")
|
||||
dofile (adv_modpath .. "/spawndef_checks.lua")
|
||||
dofile (adv_modpath .. "/api.lua")
|
||||
dofile (adv_modpath .. "/spawn_seed.lua")
|
||||
|
||||
|
||||
adv_spawning.initialize()
|
||||
|
||||
core.log("action", "Advanced spawning mod version " .. version .. " loaded")
|
1691
mods/adv_spawning/internal.lua
Normal file
1691
mods/adv_spawning/internal.lua
Normal file
File diff suppressed because it is too large
Load Diff
403
mods/adv_spawning/spawn_seed.lua
Normal file
403
mods/adv_spawning/spawn_seed.lua
Normal file
@ -0,0 +1,403 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- advanced spawning mod
|
||||
--
|
||||
--@license WTFP
|
||||
--@copyright Sapier
|
||||
--@author Sapier
|
||||
--@date 2013-12-05
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] seed_step
|
||||
-- @param self spawner entity
|
||||
-- @param dtime time since last call
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.seed_step(self,dtime)
|
||||
if not self.activated then
|
||||
local starttime = adv_spawning.gettime()
|
||||
adv_spawning.seed_activate(self)
|
||||
adv_spawning.check_time(starttime, "Initializing spawner on_step took way too much time")
|
||||
return
|
||||
end
|
||||
|
||||
self.mydtime = self.mydtime + dtime
|
||||
|
||||
if (self.mydtime < 1/adv_spawning.max_spawning_frequency_hz) then
|
||||
return
|
||||
end
|
||||
|
||||
--check if we did finish initialization of our spawner list by now
|
||||
if not adv_spawning.seed_scan_for_applyable_spawners(self) then
|
||||
return
|
||||
end
|
||||
|
||||
if adv_spawning.quota_enter() then
|
||||
self.pending_spawners = {}
|
||||
|
||||
adv_spawning.seed_countdown_spawners(self,self.mydtime)
|
||||
|
||||
self.mydtime = 0
|
||||
|
||||
--check quota again
|
||||
adv_spawning.quota_leave()
|
||||
if not adv_spawning.quota_enter() then
|
||||
return
|
||||
end
|
||||
|
||||
local per_step_count = 0
|
||||
local key = nil
|
||||
|
||||
local starttime = adv_spawning.gettime()
|
||||
|
||||
while #self.pending_spawners > 0 and
|
||||
per_step_count < adv_spawning.max_spawns_per_spawner and
|
||||
(not adv_spawning.time_over(10)) do
|
||||
|
||||
|
||||
local rand_spawner = math.random(1,#self.pending_spawners)
|
||||
key = self.pending_spawners[rand_spawner]
|
||||
|
||||
local tries = 1
|
||||
|
||||
if adv_spawning.spawner_definitions[key].spawns_per_interval ~= nil then
|
||||
tries = adv_spawning.spawner_definitions[key].spawns_per_interval
|
||||
end
|
||||
|
||||
while tries > 0 do
|
||||
local successfull, permanent_error, reason =
|
||||
adv_spawning.handlespawner(key,self.object:getpos())
|
||||
|
||||
if successfull then
|
||||
self.spawning_data[key] =
|
||||
adv_spawning.spawner_definitions[key].spawn_interval
|
||||
self.spawn_fail_reasons[key] = "successfull spawned"
|
||||
else
|
||||
self.spawning_data[key] =
|
||||
adv_spawning.spawner_definitions[key].spawn_interval/4
|
||||
self.spawn_fail_reasons[key] = reason
|
||||
end
|
||||
|
||||
--check quota again
|
||||
if not adv_spawning.quota_leave() then
|
||||
adv_spawning.dbg_log(2, "spawner " .. key .. " did use way too much time")
|
||||
end
|
||||
if not adv_spawning.quota_enter() then
|
||||
return
|
||||
end
|
||||
|
||||
tries = tries -1
|
||||
end
|
||||
|
||||
|
||||
starttime = adv_spawning.check_time(starttime, key .. " for " ..
|
||||
adv_spawning.spawner_definitions[key].spawnee .. " did use way too much time")
|
||||
|
||||
table.remove(self.pending_spawners,rand_spawner)
|
||||
per_step_count = per_step_count +1
|
||||
end
|
||||
|
||||
-- if (#self.pending_spawners > 0) then
|
||||
-- adv_spawning.dbg_log(3, "Handled " .. per_step_count .. " spawners, spawners left: " .. #self.pending_spawners)
|
||||
-- end
|
||||
if not adv_spawning.quota_leave() then
|
||||
adv_spawning.dbg_log(2, "spawner " .. key .. " did use way too much time")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] seed_activate
|
||||
-- @param self spawner entity
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.seed_activate(self)
|
||||
if adv_spawning.quota_enter() then
|
||||
|
||||
if adv_spawning.seed_check_for_collision(self) then
|
||||
adv_spawning.quota_leave()
|
||||
return
|
||||
end
|
||||
|
||||
if self.serialized_data ~= nil then
|
||||
self.spawning_data = minetest.deserialize(self.serialized_data)
|
||||
end
|
||||
|
||||
if self.spawning_data == nil then
|
||||
self.spawning_data = {}
|
||||
end
|
||||
|
||||
adv_spawning.seed_validate_spawndata(self)
|
||||
|
||||
self.pending_spawners = {}
|
||||
self.spawn_fail_reasons = {}
|
||||
self.initialized_spawners = 0
|
||||
self.activated = true
|
||||
|
||||
-- fix unaligned own pos
|
||||
local pos = self.object:getpos()
|
||||
|
||||
pos.x = math.floor(pos.x + 0.5)
|
||||
pos.y = math.floor(pos.y + 0.5)
|
||||
pos.z = math.floor(pos.z + 0.5)
|
||||
|
||||
self.object:setpos(pos)
|
||||
|
||||
if not adv_spawning.quota_leave() then
|
||||
adv_spawning.dbg_log(2, "on activate " .. self.name .. " did use way too much time")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] on_rightclick
|
||||
-- @param self spawner entity
|
||||
-- @param clicker (unused)
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.on_rightclick(self, clicker)
|
||||
if adv_spawning.debug then
|
||||
print("ADV_SPAWNING: time till next spawn: " .. self.mydtime)
|
||||
print("ADV_SPAWNING: pending spawners: " .. #self.pending_spawners)
|
||||
print("ADV_SPAWNING: Spawner may spawn " .. adv_spawning.table_count(self.spawning_data) .. " mobs:")
|
||||
local index = 1
|
||||
for key,value in pairs(self.spawning_data) do
|
||||
local reason = "unknown"
|
||||
|
||||
if self.spawn_fail_reasons[key] then
|
||||
reason = self.spawn_fail_reasons[key]
|
||||
end
|
||||
|
||||
print(string.format("%3d:",index) .. string.format("%30s ",key) .. string.format("%3d s (", value) .. reason .. ")")
|
||||
index = index +1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] seed_initialize
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.seed_initialize()
|
||||
|
||||
local spawner_texture = "adv_spawning_invisible.png^[makealpha:128,0,0^[makealpha:128,128,0"
|
||||
local spawner_collisionbox = { 0.0,0.0,0.0,0.0,0.0,0.0}
|
||||
|
||||
if adv_spawning.debug then
|
||||
spawner_texture = "adv_spawning_spawner.png"
|
||||
spawner_collisionbox = { -0.5,-0.5,-0.5,0.5,0.5,0.5 }
|
||||
end
|
||||
|
||||
minetest.register_entity("adv_spawning:spawn_seed",
|
||||
{
|
||||
collisionbox = spawner_collisionbox,
|
||||
visual = "sprite",
|
||||
textures = { spawner_texture },
|
||||
physical = false,
|
||||
groups = { "immortal" },
|
||||
on_activate = function(self,staticdata,dtime_s)
|
||||
self.activated = false
|
||||
self.mydtime = dtime_s
|
||||
self.serialized_data = staticdata
|
||||
self.object:set_armor_groups({ immortal=100 })
|
||||
adv_spawning.seed_activate(self)
|
||||
end,
|
||||
on_step = adv_spawning.seed_step,
|
||||
get_staticdata = function(self)
|
||||
return minetest.serialize(self.spawning_data)
|
||||
end,
|
||||
on_rightclick = adv_spawning.on_rightclick
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] seed_validate_spawndata
|
||||
-- @param self spawner entity
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.seed_validate_spawndata(self)
|
||||
for key,value in pairs(self.spawning_data) do
|
||||
if adv_spawning.spawner_definitions[key] == nil then
|
||||
self.spawning_data[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] seed_countdown_spawners
|
||||
-- @param self spawner entity
|
||||
-- @param dtime time to decrement spawners
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.seed_countdown_spawners(self,dtime)
|
||||
|
||||
for key,value in pairs(self.spawning_data) do
|
||||
self.spawning_data[key] = self.spawning_data[key] - dtime
|
||||
|
||||
if self.spawning_data[key] < 0 then
|
||||
table.insert(self.pending_spawners,key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] seed_check_for_collision
|
||||
-- @param self spawner entity
|
||||
-- @return true/false
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.seed_check_for_collision(self)
|
||||
assert(self ~= nil)
|
||||
local pos = self.object:getpos()
|
||||
local objects = minetest.get_objects_inside_radius(pos, 0.5)
|
||||
|
||||
if objects == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
-- check if any of those found objects is a spawning seed
|
||||
for k,v in ipairs(objects) do
|
||||
local entity = v:get_luaentity()
|
||||
|
||||
if entity ~= nil then
|
||||
if entity.name == "adv_spawning:spawn_seed" and
|
||||
entity.object ~= self.object then
|
||||
self.object:remove()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function adv_spawning.init_spawner(self, pos, name, spawnerdef)
|
||||
local starttime = adv_spawning.gettime()
|
||||
|
||||
if self.spawner_init_state ~= nil then
|
||||
self.spawner_init_state = "initial"
|
||||
end
|
||||
|
||||
local starttime = adv_spawning.gettime()
|
||||
if self.spawner_init_state == "initial" then
|
||||
|
||||
--check if cyclic spawning is enabled
|
||||
if spawnerdef.cyclic_spawning ~= nil and
|
||||
spawnerdef.cyclic_spawning == false then
|
||||
self.spawning_data[name] = nil
|
||||
return true
|
||||
end
|
||||
self.spawner_init_state = "abs_height"
|
||||
end
|
||||
|
||||
starttime = adv_spawning.check_time(starttime, name .. "cyclic check")
|
||||
if self.spawner_init_state == "abs_height" then
|
||||
--if spawner is far away from spawn area don't even try to spawn
|
||||
if spawnerdef.absolute_height ~= nil then
|
||||
if spawnerdef.absolute_height.min ~= nil and
|
||||
spawnerdef.absolute_height.min
|
||||
> pos.y + (adv_spawning.spawner_distance/2) then
|
||||
self.spawning_data[name] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
if spawnerdef.absolute_height.max ~= nil
|
||||
and spawnerdef.absolute_height.max
|
||||
< pos.y - (adv_spawning.spawner_distance/2) then
|
||||
self.spawning_data[name] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
self.spawner_init_state = "environment"
|
||||
end
|
||||
|
||||
starttime = adv_spawning.check_time(starttime, name .. "height check")
|
||||
if self.spawner_init_state == "environment" then
|
||||
|
||||
local runidx = 1
|
||||
local radius = adv_spawning.spawner_distance / 2
|
||||
|
||||
if self.spawnerinit_env_radius ~= nil then
|
||||
runidx = self.spawnerinit_env_radius
|
||||
end
|
||||
|
||||
local found = false
|
||||
|
||||
for i = runidx , radius, 1 do
|
||||
adv_spawning.quota_leave()
|
||||
|
||||
if not adv_spawning.quota_enter() then
|
||||
self.spawnerinit_env_radius = runidx
|
||||
return false
|
||||
end
|
||||
|
||||
if spawnerdef.spawn_inside == nil then
|
||||
print(name .. " tries to spawn within nil")
|
||||
assert(false)
|
||||
end
|
||||
|
||||
local resultpos = adv_spawning.find_nodes_in(pos, runidx, runidx, spawnerdef.spawn_inside)
|
||||
|
||||
if (resultpos ~= nil) then
|
||||
local node = minetest.get_node_or_nil(resultpos)
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
starttime = adv_spawning.check_time(starttime, name ..
|
||||
" at environment check radius was: " .. radius ..
|
||||
" env: " .. dump(spawnerdef.spawn_inside))
|
||||
|
||||
if not found then
|
||||
self.spawning_data[name] = nil
|
||||
end
|
||||
end
|
||||
|
||||
self.spawner_init_state = "initial"
|
||||
self.spawning_data[name] = spawnerdef.spawn_interval * math.random()
|
||||
return true
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] seed_scan_for_applyable_spawners
|
||||
-- @param self spawner entity
|
||||
-- @return true/false
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.seed_scan_for_applyable_spawners(self)
|
||||
|
||||
if self.initialized_spawners >=
|
||||
adv_spawning.table_count(adv_spawning.spawner_definitions) then
|
||||
return true
|
||||
end
|
||||
|
||||
local runindex = 0
|
||||
|
||||
if self.spawner_init_idx ~= nil then
|
||||
runindex = self.spawner_init_idx
|
||||
end
|
||||
|
||||
local pos = self.object:getpos()
|
||||
for key,value in pairs(adv_spawning.spawner_definitions) do
|
||||
if not adv_spawning.quota_enter() then
|
||||
return false
|
||||
end
|
||||
|
||||
local continue = false
|
||||
|
||||
if runindex >= self.initialized_spawners then
|
||||
self.initialized_spawners = self.initialized_spawners + 1
|
||||
else
|
||||
continue = true
|
||||
end
|
||||
|
||||
|
||||
if not continue then
|
||||
runindex = runindex + 1
|
||||
if not adv_spawning.init_spawner(self, pos, key, value) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
adv_spawning.quota_leave()
|
||||
end
|
||||
|
||||
return self.initialized_spawners == #adv_spawning.spawner_definitions
|
||||
end
|
73
mods/adv_spawning/spawndef_checks.lua
Normal file
73
mods/adv_spawning/spawndef_checks.lua
Normal file
@ -0,0 +1,73 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- advanced spawning mod
|
||||
--
|
||||
--@license WTFP
|
||||
--@copyright Sapier
|
||||
--@author Sapier
|
||||
--@date 2013-12-05
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] verify_check_entities_around
|
||||
-- @param entities_around a spawndef entities_around config
|
||||
-- @return true/false
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.verify_check_entities_around(entities_around)
|
||||
if entities_around ~= nil then
|
||||
|
||||
for i=1,#entities_around,1 do
|
||||
|
||||
if type(entities_around[i].distance) ~= "number" then
|
||||
adv_spawning.dbg_log(0, "missing distance in entities_around definition")
|
||||
return false
|
||||
end
|
||||
|
||||
if entities_around[i].type ~= "MIN" and
|
||||
entities_around[i].type ~= "MAX" then
|
||||
adv_spawning.dbg_log(0, "invalid type \"" ..
|
||||
dump(entities_around[i].type) ..
|
||||
"\" in entities_around definition")
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- @function [parent=#adv_spawning] verify_check_nodes_around
|
||||
-- @param nodes_around a spawndef entities_around config
|
||||
-- @return true/false
|
||||
--------------------------------------------------------------------------------
|
||||
function adv_spawning.verify_check_nodes_around(nodes_around)
|
||||
if nodes_around ~= nil then
|
||||
for i=1,#nodes_around,1 do
|
||||
|
||||
if type(nodes_around[i].distance) ~= "number" then
|
||||
adv_spawning.dbg_log(0, "missing distance in entities_around definition")
|
||||
return false
|
||||
end
|
||||
|
||||
if nodes_around[i].type ~= "MIN" and
|
||||
nodes_around[i].type ~= "MAX" then
|
||||
adv_spawning.dbg_log(0, "invalid type \"" ..
|
||||
dump(nodes_around[i].type) ..
|
||||
"\" in entities_around definition")
|
||||
return false
|
||||
end
|
||||
|
||||
if nodes_around[i].name == nil or
|
||||
type(nodes_around[i].name) ~= "table" then
|
||||
adv_spawning.dbg_log(0, "invalid type of name \"" ..
|
||||
type(nodes_around[i].name) .. "\"" .. " Data: " ..
|
||||
dump(nodes_around[i].name) ..
|
||||
" in nodes_around definition")
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
1
mods/adv_spawning/testmod/depends.txt
Normal file
1
mods/adv_spawning/testmod/depends.txt
Normal file
@ -0,0 +1 @@
|
||||
adv_spawning
|
154
mods/adv_spawning/testmod/init.lua
Normal file
154
mods/adv_spawning/testmod/init.lua
Normal file
@ -0,0 +1,154 @@
|
||||
|
||||
|
||||
minetest.register_entity("testmod:bogus_1",
|
||||
{
|
||||
collisionbox = { -0.5,-0.5,-0.5,0.5,0.5,0.5 },
|
||||
visual = "sprite",
|
||||
textures = { "testmod_num1.png" },
|
||||
physical = false,
|
||||
groups = { "immortal" },
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_entity("testmod:bogus_2",
|
||||
{
|
||||
collisionbox = { -0.5,-0.5,-0.5,0.5,0.5,0.5 },
|
||||
visual = "sprite",
|
||||
textures = { "testmod_num2.png" },
|
||||
physical = false,
|
||||
groups = { "immortal" },
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_entity("testmod:bogus_3",
|
||||
{
|
||||
collisionbox = { -0.5,-0.5,-0.5,0.5,0.5,0.5 },
|
||||
visual = "sprite",
|
||||
textures = { "testmod_num3.png" },
|
||||
physical = false,
|
||||
groups = { "immortal" },
|
||||
}
|
||||
)
|
||||
|
||||
minetest.register_entity("testmod:bogus_4",
|
||||
{
|
||||
collisionbox = { -0.5,-0.5,-0.5,0.5,0.5,0.5 },
|
||||
visual = "sprite",
|
||||
textures = { "testmod_num4.png" },
|
||||
physical = false,
|
||||
groups = { "immortal" },
|
||||
}
|
||||
)
|
||||
|
||||
--adv_spawning.register("some_bogus_entity_1",
|
||||
-- {
|
||||
-- spawnee = "testmod:bogus_1",
|
||||
-- spawn_interval = 10,
|
||||
--
|
||||
-- spawn_inside =
|
||||
-- {
|
||||
-- "air"
|
||||
-- },
|
||||
--
|
||||
-- entities_around =
|
||||
-- {
|
||||
-- { type="MAX",entityname = "testmod:bogus_1",distance=20,threshold=1 }
|
||||
-- },
|
||||
--
|
||||
-- relative_height =
|
||||
-- {
|
||||
-- max = 1
|
||||
-- }
|
||||
-- })
|
||||
|
||||
--adv_spawning.register("some_bogus_entity_2",
|
||||
-- {
|
||||
-- spawnee = "testmod:bogus_2",
|
||||
-- spawn_interval = 5,
|
||||
-- spawn_inside =
|
||||
-- {
|
||||
-- "air"
|
||||
-- },
|
||||
--
|
||||
-- entities_around =
|
||||
-- {
|
||||
-- { type="MAX",distance=20,threshold=1 }
|
||||
-- },
|
||||
--
|
||||
-- relative_height =
|
||||
-- {
|
||||
-- max = 1
|
||||
-- },
|
||||
--
|
||||
-- surfaces =
|
||||
-- {
|
||||
-- "default:dirt_with_grass"
|
||||
-- }
|
||||
-- })
|
||||
|
||||
--adv_spawning.register("some_bogus_entity_3",
|
||||
-- {
|
||||
-- spawnee = "testmod:bogus_3",
|
||||
-- spawn_interval = 3,
|
||||
-- spawn_inside =
|
||||
-- {
|
||||
-- "air"
|
||||
-- },
|
||||
--
|
||||
-- entities_around =
|
||||
-- {
|
||||
-- { type="MAX",entityname = "testmod:bogus_4",distance=20,threshold=1 }
|
||||
-- },
|
||||
--
|
||||
-- relative_height =
|
||||
-- {
|
||||
-- max = 4,
|
||||
-- min = 4,
|
||||
-- },
|
||||
-- })
|
||||
|
||||
adv_spawning.register("some_bogus_entity_4",
|
||||
{
|
||||
spawnee = "testmod:bogus_4",
|
||||
spawn_interval = 3,
|
||||
spawn_inside =
|
||||
{
|
||||
"air"
|
||||
},
|
||||
|
||||
entities_around =
|
||||
{
|
||||
{ type="MAX",distance=30,threshold=1 }
|
||||
},
|
||||
|
||||
relative_height =
|
||||
{
|
||||
max = 4,
|
||||
min = 4,
|
||||
},
|
||||
surfaces =
|
||||
{
|
||||
"default:leaves"
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
minetest.register_chatcommand("adv_stats",
|
||||
{
|
||||
params = "",
|
||||
description = "print advanced spawning satistics to logfile" ,
|
||||
func = function()
|
||||
local stats = adv_spawning.get_statistics()
|
||||
|
||||
adv_spawning.dbg_log(0, "Adv. Spawning stats:")
|
||||
adv_spawning.dbg_log(0, "----------------------------------------")
|
||||
adv_spawning.dbg_log(0, "Spawners added: " .. stats.session.spawners_created)
|
||||
adv_spawning.dbg_log(0, "Spawnees added: " .. stats.session.entities_created)
|
||||
adv_spawning.dbg_log(0, "")
|
||||
adv_spawning.dbg_log(0, "Longest step: " .. stats.step.max)
|
||||
adv_spawning.dbg_log(0, "")
|
||||
adv_spawning.dbg_log(0, "Current load: " .. stats.load.cur)
|
||||
adv_spawning.dbg_log(0, "Average load: " .. stats.load.avg)
|
||||
adv_spawning.dbg_log(0, "Maximum load: " .. stats.load.max)
|
||||
end
|
||||
})
|
BIN
mods/adv_spawning/testmod/textures/testmod_num1.png
Normal file
BIN
mods/adv_spawning/testmod/textures/testmod_num1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 327 B |
BIN
mods/adv_spawning/testmod/textures/testmod_num2.png
Normal file
BIN
mods/adv_spawning/testmod/textures/testmod_num2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 701 B |
BIN
mods/adv_spawning/testmod/textures/testmod_num3.png
Normal file
BIN
mods/adv_spawning/testmod/textures/testmod_num3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 790 B |
BIN
mods/adv_spawning/testmod/textures/testmod_num4.png
Normal file
BIN
mods/adv_spawning/testmod/textures/testmod_num4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 543 B |
BIN
mods/adv_spawning/textures/adv_spawning_invisible.png
Normal file
BIN
mods/adv_spawning/textures/adv_spawning_invisible.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 180 B |
BIN
mods/adv_spawning/textures/adv_spawning_spawner.png
Normal file
BIN
mods/adv_spawning/textures/adv_spawning_spawner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Loading…
x
Reference in New Issue
Block a user