[minetest-mod-advspawning] 01/02: Imported Upstream version 0.0.13

Julien Puydt julien.puydt at laposte.net
Sun Jul 10 14:54:35 UTC 2016


This is an automated email from the git hooks/post-receive script.

jpuydt-guest pushed a commit to branch master
in repository minetest-mod-advspawning.

commit d190204ca5540fb0f78a8ed62f595f7906e40a6f
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Sat Jul 9 15:38:16 2016 +0200

    Imported Upstream version 0.0.13
---
 README.txt                          |  220 +++++
 api.lua                             |   53 ++
 init.lua                            |   34 +
 internal.lua                        | 1691 +++++++++++++++++++++++++++++++++++
 spawn_seed.lua                      |  403 +++++++++
 spawndef_checks.lua                 |   73 ++
 testmod/depends.txt                 |    1 +
 testmod/init.lua                    |  154 ++++
 testmod/textures/testmod_num1.png   |  Bin 0 -> 327 bytes
 testmod/textures/testmod_num2.png   |  Bin 0 -> 701 bytes
 testmod/textures/testmod_num3.png   |  Bin 0 -> 790 bytes
 testmod/textures/testmod_num4.png   |  Bin 0 -> 543 bytes
 textures/adv_spawning_invisible.png |  Bin 0 -> 180 bytes
 textures/adv_spawning_spawner.png   |  Bin 0 -> 1543 bytes
 14 files changed, 2629 insertions(+)

diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..5b14caa
--- /dev/null
+++ b/README.txt
@@ -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
\ No newline at end of file
diff --git a/api.lua b/api.lua
new file mode 100644
index 0000000..298d742
--- /dev/null
+++ b/api.lua
@@ -0,0 +1,53 @@
+-------------------------------------------------------------------------------
+-- advanced spawning mod
+--
+-- at license WTFP
+-- at copyright Sapier
+-- at author Sapier
+-- at 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
\ No newline at end of file
diff --git a/init.lua b/init.lua
new file mode 100644
index 0000000..411fc9d
--- /dev/null
+++ b/init.lua
@@ -0,0 +1,34 @@
+-------------------------------------------------------------------------------
+-- advanced spawning mod
+--
+-- at license WTFP
+-- at copyright Sapier
+-- at author Sapier
+-- at 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")
diff --git a/internal.lua b/internal.lua
new file mode 100644
index 0000000..caa595e
--- /dev/null
+++ b/internal.lua
@@ -0,0 +1,1691 @@
+-------------------------------------------------------------------------------
+-- advanced spawning mod
+--
+-- at license WTFP
+-- at copyright Sapier
+-- at author Sapier
+-- at date 2013-12-05
+--
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] MAX
+-- @param a first value to compare
+-- @param b second value to compare
+-- @return maximum of a and b
+--------------------------------------------------------------------------------
+function adv_spawning.MAX(a,b)
+	if a == nil then
+		return (b or 0)
+	end
+	if b == nil then
+		return (a or 0)
+	end
+	if a > b then
+		return (a or 0)
+	else
+		return (b or 0)
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] MIN
+-- @param a first value to compare
+-- @param b second value to compare
+-- @return minimum of a and b
+--------------------------------------------------------------------------------
+function adv_spawning.MIN(a,b)
+	if a == nil then
+		return (b or 0)
+	end
+	if b == nil then
+		return (a or 0)
+	end
+	if a > b then
+		return (b or 0)
+	else
+		return (a or 0)
+	end
+end
+
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] initialize
+--------------------------------------------------------------------------------
+function adv_spawning.initialize()
+
+	--initialize data
+	adv_spawning.quota_starttime = nil
+	adv_spawning.quota_reload = 100
+	adv_spawning.quota_left = adv_spawning.quota_reload
+	adv_spawning.max_spawns_per_spawner = 2
+	adv_spawning.spawner_distance = 70
+	adv_spawning.spawner_y_offset = 20
+	adv_spawning.max_spawning_frequency_hz = 5
+	adv_spawning.max_mapgen_tries_per_step = 3
+	adv_spawning.spawner_warned = {}
+	adv_spawning.loglevel = 0
+	adv_spawning.spawner_validation_delta = 0
+	adv_spawning.spawner_validation_interval = 30
+
+	adv_spawning.active_range = minetest.setting_get("active_block_range")
+
+	if (adv_spawning.active_range == nil) then
+		adv_spawning.log("info", "No \"active_block_range\" set, defaulting to 5")
+		adv_spawning.active_range = 5
+	else
+		adv_spawning.active_range = adv_spawning.active_range * 16
+	end
+
+	adv_spawning.spawner_definitions = {}
+	adv_spawning.mapgen_jobqueue = {}
+	adv_spawning.statistics =
+	{
+		session =
+		{
+			spawners_created = 0,
+			entities_created = 0,
+			steps = 0,
+		},
+		step =
+		{
+			min = 0,
+			max = 0,
+			last = 0,
+		},
+		load =
+		{
+			min = 0,
+			max = 0,
+			cur = 0,
+			avg = 0
+		}
+	}
+
+	adv_spawning.gettime = function() return os.clock() * 1000 end
+
+	if type(minetest.get_us_time) == "function" then
+		adv_spawning.log("action", "Using minetest.get_us_time() for quota calc")
+		adv_spawning.gettime = function()
+				return minetest.get_us_time() / 1000
+			end
+	else
+		if socket == nil then
+			local status, module = pcall(require, 'socket')
+
+			if status and type(module.gettime) == "function" then
+				adv_spawning.log("action", "Using socket.gettime() for quota calc")
+				adv_spawning.gettime = function()
+						return socket.gettime()*1000
+					end
+			end
+		end
+	end
+
+	--register global onstep
+	minetest.register_globalstep(adv_spawning.global_onstep)
+
+	--register seed spawner entity
+	adv_spawning.seed_initialize()
+
+	--register mapgen hook
+	minetest.register_on_generated(adv_spawning.mapgen_hook)
+end
+
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] mapgen_hook
+-- @param minp minimal position of block
+-- @param maxp maximal position of block
+-- @param blockseed seed for this block
+--------------------------------------------------------------------------------
+function adv_spawning.mapgen_hook(minp,maxp,blockseed)
+	if adv_spawning.quota_enter(true) then
+		--find positions within current block to place a spawner seed
+		local start_x =
+			math.floor(minp.x/adv_spawning.spawner_distance)
+			* adv_spawning.spawner_distance
+		local start_y =
+			(math.floor(minp.y/adv_spawning.spawner_distance)
+				* adv_spawning.spawner_distance)
+				+ adv_spawning.spawner_y_offset
+		local start_z =
+			math.floor(minp.z/adv_spawning.spawner_distance)
+			* adv_spawning.spawner_distance
+
+		for x=start_x,maxp.x,adv_spawning.spawner_distance do
+		for y=start_y,maxp.y,adv_spawning.spawner_distance do
+		for z=start_z,maxp.z,adv_spawning.spawner_distance do
+
+			if x > minp.x and
+				y > minp.y and
+				z > minp.z then
+				if not adv_spawning.quota_leave() then
+					adv_spawning.dbg_log(2, "mapgen_hook did use way too much time 1")
+				end
+				minetest.add_entity({x=x,y=y,z=z},"adv_spawning:spawn_seed")
+				adv_spawning.quota_enter(true)
+				adv_spawning.log("info", "adv_spawning: adding spawner entity at "
+					.. minetest.pos_to_string({x=x,y=y,z=z}))
+				adv_spawning.statistics.session.spawners_created =
+					adv_spawning.statistics.session.spawners_created +1
+			end
+		end
+		end
+		end
+
+		adv_spawning.queue_mapgen_jobs(minp,maxp)
+		if not adv_spawning.quota_leave() then
+			adv_spawning.dbg_log(2, "mapgen_hook did use way too much time 2")
+		end
+	else
+		assert("Mapgen hook could not be executed" == nil)
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] global_onstep
+-- @param dtime time since last call
+--------------------------------------------------------------------------------
+function adv_spawning.global_onstep(dtime)
+
+	if dtime == 0 then
+		-- don't try to calc differences for no time
+		return
+	end
+
+	adv_spawning.statistics.step.last =
+		math.floor(adv_spawning.quota_reload - adv_spawning.quota_left + 0.5)
+
+	adv_spawning.statistics.step.max = adv_spawning.MAX(adv_spawning.statistics.step.last,
+											adv_spawning.statistics.step.max)
+
+	adv_spawning.statistics.step.min = adv_spawning.MIN(adv_spawning.statistics.step.last,
+											adv_spawning.statistics.step.min)
+
+	adv_spawning.statistics.session.steps =
+		adv_spawning.statistics.session.steps + 1
+
+	adv_spawning.statistics.load.cur =
+		adv_spawning.statistics.step.last/(dtime*1000)
+
+	adv_spawning.statistics.load.max = adv_spawning.MAX(adv_spawning.statistics.load.cur,
+											adv_spawning.statistics.load.max)
+
+	adv_spawning.statistics.load.min = adv_spawning.MIN(adv_spawning.statistics.load.cur,
+											adv_spawning.statistics.load.min)
+
+	adv_spawning.statistics.load.avg =
+		(	(adv_spawning.statistics.load.avg *
+			(adv_spawning.statistics.session.steps-1)) +
+			adv_spawning.statistics.load.cur) /
+			adv_spawning.statistics.session.steps
+			
+	if core.is_yes(
+			core.setting_get("adv_spawning_validate_spawners")) then
+		
+			adv_spawning.spawner_validation_delta =
+					adv_spawning.spawner_validation_delta + dtime
+					
+			if adv_spawning.spawner_validation_delta >
+					adv_spawning.spawner_validation_interval then
+				
+				if adv_spawning.quota_enter() then
+					local playerlist = core.get_connected_players()
+					
+					for k,v in ipairs(playerlist) do
+						if not adv_spawning.time_over(10) then
+							adv_spawning.refresh_spawners(v:getpos())
+						else
+							break
+						end
+					end
+					
+					adv_spawning.spawner_validation_delta = 0
+				
+				end
+			end
+	end
+
+	--reduce following quota by overtime from last step
+	if adv_spawning.quota_left < 0 then
+		adv_spawning.quota_left =
+			adv_spawning.MAX(0,adv_spawning.quota_left + adv_spawning.quota_reload)
+	else
+		adv_spawning.quota_left = adv_spawning.quota_reload
+	end
+
+	if adv_spawning.quota_enter() then
+		adv_spawning.handle_mapgen_spawning()
+		if not adv_spawning.quota_leave() then
+			adv_spawning.dbg_log(2, "globalstep took to long")
+		end
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] quota_enter
+-- @param force ignore quota but start calculation
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.quota_enter(force)
+	--ONLY enable this one if you're quite sure there aren't bugs in
+	--assert(adv_spawning.quota_starttime == nil)
+	local retval = false
+	
+	if adv_spawning.quota_left <= 0 then
+	
+		if force == true then
+			if adv_spawning.quota_left < -10 then
+				adv_spawning.dbg_log(1, "Quota: task is too important to skip do it anyway," ..
+					" quota already passed by: " ..
+					string.format("%.2f ms",adv_spawning.quota_left))
+			end
+			retval = true
+		else
+			if adv_spawning.quota_left * -2 > adv_spawning.quota_reload then
+				adv_spawning.dbg_log(1, "Quota: no time left: " ..
+					string.format("%.2f ms",adv_spawning.quota_left))
+			end
+		end
+	else
+		retval = true
+	end
+--	print("+++++++++++++++++Quota enter+++++++++++++++++++++")
+--	print(debug.traceback())
+--	print("+++++++++++++++++++++++++++++++++++++++++++++++++")
+	if retval then
+		adv_spawning.quota_starttime = adv_spawning.gettime()
+	end
+	
+	return retval
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] time_over
+-- @param minimum minimal value required to be left
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.time_over(minimum)
+	assert(adv_spawning.quota_starttime ~= nil)
+--	if adv_spawning.quota_starttime == nil then
+--		return
+--	end
+
+	if minimum == nil then
+		minimum = 0
+	end
+
+	local now = adv_spawning.gettime()
+
+	local time_passed = now - adv_spawning.quota_starttime
+	
+	if (time_passed < 0) then
+		if adv_spawning.timebackwardwarning ~= true then
+			core.log("error", "ADV_SPAWNING: Error either there's a bug in time"
+				.." calculation\n or your time just went backwards: old timestamp: "
+				.. adv_spawning.quota_starttime .. " current_time: " .. now .. "\n")
+			adv_spawning.timebackwardwarning = true
+			
+		end
+		return true
+	end
+
+	return (adv_spawning.quota_left - time_passed) < minimum
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] quota_leave
+--------------------------------------------------------------------------------
+function adv_spawning.quota_leave()
+	--assert(adv_spawning.quota_starttime ~= nil)
+	if adv_spawning.quota_starttime == nil then
+		return
+	end
+
+	local now = adv_spawning.gettime()
+
+	local time_passed = now - adv_spawning.quota_starttime
+
+	if (time_passed < 0) then
+		if adv_spawning.timebackwardwarning ~= true then
+			core.log("error", "ADV_SPAWNING: Error either there's a bug in time"
+				.." calculation\n or your time just went backwards: old timestamp: "
+				.. adv_spawning.quota_starttime .. " current_time: " .. now .. "\n")
+			adv_spawning.timebackwardwarning = true
+		end
+	else
+		adv_spawning.quota_left = adv_spawning.quota_left - time_passed
+	end
+	
+	if (adv_spawning.quota_left < -adv_spawning.quota_reload) then
+		adv_spawning.dbg_log(1, "excessive overtime, quota remaining: " .. adv_spawning.quota_left)
+		return false
+	end
+	
+	adv_spawning.quota_starttime = nil
+	--print("-----------------Quota leave----------------------")
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] handlespawner
+-- @param spawnername unique name of spawner
+-- @param spawnerpos position of spawner
+-- @param minp (OPTIONAL) override spawner defaults
+-- @param maxp (OPTIONAL) override spawner defaults
+-- @param ignore_active_area set to true for mapgen spawning
+-- @return successfull true/false, permanent_error true,false, reason_string
+--------------------------------------------------------------------------------
+function adv_spawning.handlespawner(spawnername,spawnerpos,minp,maxp,ignore_active_area)
+
+	local permanent_error = false
+	local spawndef = adv_spawning.spawner_definitions[spawnername]
+
+	if not adv_spawning.check_daytime(spawndef.daytimes) then
+		adv_spawning.log("info","didn't meet daytime check")
+		return false,nil, "daytimecheck failed"
+	end
+
+	local max_x = spawnerpos.x + adv_spawning.spawner_distance/2
+	local min_x = spawnerpos.x - adv_spawning.spawner_distance/2
+
+	local max_z = spawnerpos.z + adv_spawning.spawner_distance/2
+	local min_z = spawnerpos.z - adv_spawning.spawner_distance/2
+
+	local upper_y = spawnerpos.y + adv_spawning.spawner_distance/2
+	local lower_y = spawnerpos.y - adv_spawning.spawner_distance/2
+
+	if minp ~= nil then
+		min_x = minp.x
+		min_z = minp.z
+		lower_y = minp.y
+	end
+
+	if maxp ~= nil then
+		max_x = maxp.x
+		max_z = maxp.z
+		upper_y = maxp.y
+	end
+
+	--get random pos
+	local new_pos = {}
+
+	new_pos.x = math.random(min_x,max_x)
+	new_pos.z = math.random(min_z,max_z)
+
+	local yreason = "ukn"
+
+	--check if entity is configured to spawn at surface
+	if spawndef.relative_height == nil or
+		(spawndef.relative_height.max ~= nil and
+			spawndef.relative_height.max <= 1) then
+		new_pos.y, yreason = adv_spawning.get_surface(lower_y,upper_y,new_pos,
+							spawndef.spawn_inside)
+	else
+		if spawndef.spawn_inside == nil then
+			print("ERROR: " .. spawnername .. " tries to spawn within nil")
+			assert(false)
+		end
+		new_pos.y, yreason = adv_spawning.get_relative_pos(lower_y,upper_y,new_pos,
+							spawndef.spawn_inside,
+							spawndef.relative_height,
+							spawndef.absolute_height)
+	end
+
+	--check if we did found a position within relative range
+	if new_pos.y == nil then
+		new_pos.y="?"
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't find a suitable y pos "
+			.. lower_y .. "<-->" .. upper_y )
+		return false, nil, "didn't find a valid ypos at " .. minetest.pos_to_string(new_pos)
+				    .. " " .. lower_y .. "<-->" .. upper_y .. " rsn: " .. yreason
+	end
+
+	--check absolute height
+	local abs_height_retval, abs_height_rsn = adv_spawning.check_absolute_height(new_pos,spawndef.absolute_height)
+	if not abs_height_retval then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet absolute height check")
+		return false, true, "absolute height check failed rsn: " .. abs_height_rsn
+	end
+
+	--check active area
+	if not ignore_active_area and not adv_spawning.check_active_block(new_pos) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet active area check")
+		return false, nil , "area check failed"
+	end
+
+	--check surface
+	--NOTE needs to be done before collision box check as y pos may be modified there
+	if not adv_spawning.check_surface(new_pos,
+										spawndef.surfaces,
+										spawndef.relative_height,
+										spawndef.spawn_inside) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) ..
+			" didn't meet surface check, is: " ..
+			minetest.get_node({x=new_pos.x,z=new_pos.z,y=new_pos.y-1}).name)
+		return false, nil, "surface check failed"
+	end
+
+	--flat area check
+	--NOTE needs to be done before collision box check as y pos may be modified there
+	if not adv_spawning.check_flat_area(new_pos,
+								spawndef.flat_area,
+								spawndef.spawn_inside,
+								spawndef.surfaces) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet flat area check")
+		return false, nil, "flat area check failed"
+	end
+
+	--check collisionbox
+	local checkresult,y_pos =
+		adv_spawning.check_collisionbox(new_pos,
+						spawndef.collisionbox,spawndef.spawn_inside)
+
+	if checkresult and y_pos ~= nil then
+		new_pos.y = y_pos
+	end
+
+	if not checkresult then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet collisionbox check")
+		return false, nil, "collision box check failed"
+	end
+
+	--check entities around
+	if not adv_spawning.check_entities_around(new_pos,spawndef.entities_around) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet entities check")
+		return false, nil, "entitie around check failed"
+	end
+
+	--check nodes around
+	if not adv_spawning.check_nodes_around(new_pos,spawndef.nodes_around) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet nodes check")
+		return false, nil, "nodes around check failed"
+	end
+
+	--check light around
+	if not adv_spawning.check_light_around(new_pos,spawndef.light_around) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet light  check")
+		return false, nil, "light check failed"
+	end
+
+--  ONLY use this if you have luajit
+--	--check light around
+--	if not adv_spawning.check_light_around_voxel(new_pos,spawndef.light_around) then
+--		adv_spawning.log("info",
+--			minetest.pos_to_string(new_pos) .. " didn't meet light  check")
+--		return false, nil, "luajit light check failed"
+--	end
+
+	--check humidity
+	if not adv_spawning.check_humidity_around(new_pos,spawndef.humidity_around) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet humidity check")
+		return false, nil, "humidity check failed"
+	end
+
+	--check temperature
+	if not adv_spawning.check_temperature_around(new_pos,spawndef.temperature_around) then
+		adv_spawning.log("info",
+			minetest.pos_to_string(new_pos) .. " didn't meet temperature check")
+		return false, nil, "temperature check failed"
+	end
+
+	--custom check
+	if (spawndef.custom_check ~= nil and
+		type(spawndef.custom_check) == "function") then
+	  
+		local retval, reason = spawndef.custom_check(new_pos,spawndef)
+		
+		if not reason then
+			reason = "custom check failed"
+		end
+
+		if not retval then
+			adv_spawning.log("info",
+				minetest.pos_to_string(new_pos) .. " didn't meet custom check")
+			return false, nil, reason
+		end
+	end
+
+	--do spawn
+	--print("Now spawning: " .. spawndef.spawnee .. " at " ..
+	--	minetest.pos_to_string(new_pos))
+
+	if type(spawndef.spawnee) == "function" then
+		spawndef.spawnee(new_pos)
+	else
+		minetest.add_entity(new_pos,spawndef.spawnee)
+	end
+
+	adv_spawning.statistics.session.entities_created =
+			adv_spawning.statistics.session.entities_created +1
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] get_surface
+-- @param y_min minumum relevant y pos
+-- @param y_max maximum relevant y pos
+-- @param new_pos position to spawn at
+-- @param spawn_inside nodes to spawn at
+-- @return y-value of last spawnable node
+--------------------------------------------------------------------------------
+function adv_spawning.get_surface(y_min,y_max,new_pos,spawn_inside)
+
+	local top_pos = { x=new_pos.x, z=new_pos.z, y=y_max}
+	local bottom_pos = { x=new_pos.x, z=new_pos.z, y=y_min}
+
+	-- get list of all nodes within our y-range we could spawn within
+	local spawnable_nodes =
+		minetest.find_nodes_in_area(bottom_pos, top_pos, spawn_inside)
+
+	-- if there ain't a single node to spawn within get out of here
+	if #spawnable_nodes == 0 then
+		return nil, "no spawnable nodes at all"
+	end
+
+	local spawnable_node_passed = false
+
+	-- loop from topmost position to bottom
+	for i=y_max, y_min, -1 do
+		-- get current position
+		local pos = { x=new_pos.x,z=new_pos.z,y=i}
+		
+		-- if the node at current position ain't one of those we can spawn within
+		if not adv_spawning.contains_pos(spawnable_nodes,pos) then
+			
+			-- get more information about this node
+			local node = minetest.get_node(pos)
+			
+			local text = "false"
+			
+			if spawnable_node_passed then
+			   text = "true"
+			end
+
+			-- if node ain't unloaded and we did already see a spawnable node above
+			-- return position above as pos to spawn
+			if node.name ~= "ignore" and
+				spawnable_node_passed then
+				return i+1, "pos found"
+			end
+		else
+			-- set marker about having seen a spawnable node above
+			spawnable_node_passed = true
+		end
+	end
+
+	return nil, "no matching node, nodecnt: " ..  #spawnable_nodes
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] get_relative_pos
+-- @param y_min minumum relevant y pos
+-- @param y_max maximum relevant y pos
+-- @param new_pos position to spawn at
+-- @param spawn_inside nodes to spawn at
+-- @param relative_height
+-- @param absolute_height
+-- @return y-value of last spawnable node
+--------------------------------------------------------------------------------
+function adv_spawning.get_relative_pos(y_min,y_max,new_pos,spawn_inside,relative_height,absolute_height)
+	local y_val = adv_spawning.get_surface(y_min,y_max,new_pos,spawn_inside)
+
+	if y_val == nil then
+		if (relative_height.min ~= nil or
+			relative_height.max ~= nil) then
+			return nil, "y_pos not witing range of " 
+				.. relative_height.min .. "<-->" .. relative_height.max
+		else
+			y_val = y_min
+		end
+	end
+
+	local top_pos = { x=new_pos.x, z=new_pos.z, y=y_max}
+	local bottom_pos = { x=new_pos.x, z=new_pos.z, y=y_val}
+
+	if relative_height ~= nil then
+		if relative_height.min ~= nil then
+			bottom_pos.y = y_val + relative_height.min
+		end
+
+		if relative_height.max ~= nil then
+			top_pos.y = y_val + relative_height.max
+		end
+	end
+
+	top_pos.y = adv_spawning.MIN(absolute_height.max,top_pos.y)
+	bottom_pos.y = adv_spawning.MAX(absolute_height.min,bottom_pos.y)
+
+	if top_pos.y < bottom_pos.y then
+		--print("Invalid interval: " .. bottom_pos.y .. "<-->" .. top_pos.y)
+		return nil, "invalid interval: " .. bottom_pos.y .. "<-->" .. top_pos.y
+	end
+
+	local spawnable_nodes =
+		minetest.find_nodes_in_area(bottom_pos, top_pos, spawn_inside)
+
+	if #spawnable_nodes > 0 then
+		return spawnable_nodes[math.random(1,#spawnable_nodes)].y, "rpos found"
+	else
+		--print("no suitable nodes" .. bottom_pos.y .. "<-->" .. top_pos.y)
+		return nil, "no spawnable nodes found around"
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] contains_pos
+-- @param pos_list table containing positions
+-- @param pos a position to search
+-- @param remove if this is set to true a position is removed on match
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.contains_pos(pos_list,pos,remove)
+
+	for i=1,#pos_list,1 do
+		if pos_list[i].x == pos.x and
+			pos_list[i].z == pos.z and
+			pos_list[i].y == pos.y then
+
+			if remove then
+				table.remove(pos_list,i)
+			end
+			return true
+	end
+	end
+	return false
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_absolute_height
+-- @param pos to verify
+-- @param absolute_height configuration for absolute height check
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_absolute_height(pos,absolute_height)
+	if absolute_height == nil then
+		return true, "no height limit"
+	end
+
+	if absolute_height.min ~= nil and
+		pos.y < absolute_height.min then
+		return false, pos.y .. " < " .. absolute_height.min
+	end
+
+	if absolute_height.max ~= nil and
+		pos.y > absolute_height.max then
+		return false, pos.y .. " > " .. absolute_height.max
+	end
+
+	return true, "height ok"
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_surface
+-- @param pos to verify
+-- @param surface configuration
+-- @param relative_height required to check for non ground bound spawning
+-- @param spawn_inside nodes to spawn inside
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_surface(pos,surfaces,relative_height,spawn_inside)
+
+	if surfaces == nil then
+		return true
+	end
+
+	if relative_height == nil or (
+		relative_height.max ~= nil and
+		relative_height.max <= 1) then
+
+		local lower_pos = {x=pos.x, y= pos.y-1, z=pos.z}
+
+		local node_below = minetest.get_node(lower_pos)
+
+		return adv_spawning.contains(surfaces,node_below.name)
+	else
+		local ymin = pos.y-relative_height.max-1
+		local ymax = pos.y+relative_height.max
+		local surface = adv_spawning.get_surface(ymin, ymax, pos, spawn_inside)
+		if surface == nil then
+			return false
+		else
+			local lower_pos = {x=pos.x, y= surface-1, z=pos.z}
+
+			local node_below = minetest.get_node(lower_pos)
+
+			return adv_spawning.contains(surfaces,node_below.name)
+		end
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] contains
+-- @param table_to_check
+-- @param value
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.contains(table_to_check,value)
+	for i=1,#table_to_check,1 do
+		if table_to_check[i] == value then
+			return true
+		end
+	end
+	return false
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_daytimes
+-- @param table_to_check
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_daytime(daytimedefs)
+	if daytimedefs == nil then
+		return true
+	end
+
+	local current_time = minetest.get_timeofday()
+	local match = false
+
+	for i=1,#daytimedefs,1 do
+		if daytimedefs[i].begin ~= nil and
+			daytimedefs[i].stop ~= nil then
+
+			if current_time < daytimedefs[i].stop and
+				current_time > daytimedefs[i].begin then
+				match = true
+			end
+			break
+		end
+
+		if daytimedefs[i].begin ~= nil and
+			current_time > daytimedefs[i].begin then
+			match = true
+			break
+		end
+
+		if daytimedefs[i].stop ~= nil and
+			current_time < daytimedefs[i].stop then
+			match = true
+			break
+		end
+	end
+
+	return match
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_nodes_around
+-- @param pos position to validate
+-- @param nodes_around node around definitions
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_nodes_around(pos,nodes_around)
+
+	if nodes_around == nil then
+		return true
+	end
+
+	for i=1,#nodes_around,1 do
+		--first handle special cases 0 and 1 in a quick way
+		if  (nodes_around[i].threshold == 1 and nodes_around[i].type == "MIN") or
+			(nodes_around[i].threshold == 0 and nodes_around[i].type == "MAX")then
+
+			local found =
+				minetest.find_node_near(pos,nodes_around[i].distance,
+										nodes_around[i].name)
+
+			if nodes_around[i].type == "MIN" then
+				if found == nil then
+					--print("not enough: " .. dump(nodes_around[i].name) .. " around")
+					return false
+				end
+			else
+				if found ~= nil then
+					--print("to many: " .. dump(nodes_around[i].name) .. " around " .. dump(found))
+					return false
+				end
+			end
+		else
+			--need to do the full blown check
+			local found_nodes = minetest.find_nodes_in_area(
+										{   x=pos.x-nodes_around[i].distance,
+											y=pos.y-nodes_around[i].distance,
+											z=pos.z-nodes_around[i].distance},
+										{   x=pos.x+nodes_around[i].distance,
+											y=pos.y+nodes_around[i].distance,
+											z=pos.z+nodes_around[i].distance},
+										nodes_around[i].name)
+
+			if nodes_around[i].type == "MIN" and
+				#found_nodes < nodes_around[i].threshold then
+				--print("Found MIN: " .. dump(nodes_around[i].name) ..
+				--	"\n at locations: " .. dump(found_nodes))
+				--print ("Only " .. #found_nodes .. "/" .. nodes_around[i].threshold)
+				return false
+			end
+
+			if nodes_around[i].type == "MAX" and
+				#found_nodes > nodes_around[i].threshold then
+				--print("Found MAX: " .. dump(nodes_around[i].name) ..
+				--	"\n at locations: " .. dump(found_nodes))
+				return false
+			end
+		end
+	end
+
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_entities_around
+-- @param pos position to validate
+-- @param entities_around entity around definitions
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_entities_around(pos,entities_around)
+	if entities_around == nil then
+		return true
+	end
+
+	for i=1,#entities_around,1 do
+		local entity_in_range =
+			minetest.get_objects_inside_radius(pos, entities_around[i].distance)
+
+		if entities_around[i].entityname == nil then
+			if entities_around[i].type == "MIN" and
+				#entity_in_range < entities_around[i].threshold then
+				return false
+			end
+
+			if entities_around[i].type == "MAX" and
+				#entity_in_range > entities_around[i].threshold then
+				return false
+			end
+		end
+
+		local count = 0
+
+		for j=1,#entity_in_range,1 do
+			local entity = entity_in_range[j]:get_luaentity()
+
+			if entity ~= nil then
+				if entity.name == entities_around[i].entityname then
+					count = count +1
+				end
+
+				if count > entities_around[i].threshold then
+					break
+				end
+			end
+		end
+
+		if entities_around[i].type == "MIN" and
+			count < entities_around[i].threshold then
+			return false
+		end
+
+		if entities_around[i].type == "MAX" and
+			count > entities_around[i].threshold then
+			return false
+		end
+	end
+
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_light_around
+-- @param pos position to validate
+-- @param light_around light around definitions
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_light_around(pos,light_around)
+	if light_around == nil then
+		return true
+	end
+
+	for i=1,#light_around,1 do
+
+		for x=pos.x-light_around[i].distance,pos.x+light_around[i].distance,1 do
+		for y=pos.y-light_around[i].distance,pos.y+light_around[i].distance,1 do
+		for x=pos.z-light_around[i].distance,pos.z+light_around[i].distance,1 do
+			local checkpos = { x=x,y=y,z=z}
+			local time = minetest.get_timeofday()
+			if light_around[i].type == "TIMED_MIN" or
+				light_around[i].type == "TIMED_MAX" then
+				time = light_around[i].time
+			end
+
+			if light_around[i].type == "OVERALL_MIN" or
+				light_around[i].type == "OVERALL_MAX" then
+
+				for j=0,24000,1000 do
+					local light_level = minetest.get_node_light(checkpos, j)
+
+					if light_level ~= nil then
+						if light_around[i].type == "OVERALL_MAX" and
+							light_level > light_around[i].threshold then
+							return false
+						end
+
+						if light_around[i].type == "OVERALL_MIN" and
+							light_level < light_around[i].threshold then
+							return false
+						end
+					end
+				end
+
+			else
+				local light_level = minetest.get_node_light(checkpos, time)
+
+				if light_level ~= nil then
+					if (light_around[i].type == "TIMED_MIN" or
+						light_around[i].type == "CURRENT_MIN") and
+						light_level < light_around[i].threshold then
+							return false
+					end
+
+					if (light_around[i].type == "TIMED_MAX" or
+						light_around[i].type == "CURRENT_MAX") and
+						light_level > light_around[i].threshold then
+							return false
+					end
+				end
+			end
+		end
+		end
+		end
+	end
+
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_light_around_voxel
+-- @param pos position to validate
+-- @param light_around light around definitions
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_light_around_voxel(pos,light_around)
+	if light_around == nil then
+		return true
+	end
+
+	local maxdistance = 0
+
+	for i=1,#light_around,1 do
+		maxdistance = adv_spawning.MAX(maxdistance,light_around[i].distance)
+	end
+
+	-- voxelmanip is of no use for low counts of nodes
+	if maxdistance <=10 then
+		return adv_spawning.check_light_around(pos,light_around)
+	end
+
+	local minp = { x=math.floor(pos.x - maxdistance),
+					y=math.floor(pos.y - maxdistance),
+					z=math.floor(pos.z - maxdistance)}
+	local maxp = { x=math.ceil(pos.x + maxdistance),
+					y=math.ceil(pos.y + maxdistance),
+					z=math.ceil(pos.z + maxdistance)}
+
+	local voxeldata = minetest.get_voxel_manip()
+	local got_minp,got_maxp = voxeldata:read_from_map(minp,maxp)
+
+	local voxel_light_data = voxeldata:get_light_data()
+	local node_data = voxeldata:get_data()
+	local voxelhelper = VoxelArea:new({MinEdge=got_minp,MaxEdge=got_maxp})
+
+
+	for i=1,#light_around,1 do
+
+		for x=pos.x-light_around[i].distance,pos.x+light_around[i].distance,1 do
+		for y=pos.y-light_around[i].distance,pos.y+light_around[i].distance,1 do
+		for z=pos.z-light_around[i].distance,pos.z+light_around[i].distance,1 do
+			local checkpos = { x=x,y=y,z=z}
+			local time = minetest.get_timeofday()
+			if light_around[i].type == "TIMED_MIN" or
+				light_around[i].type == "TIMED_MAX" then
+				time = light_around[i].time
+			end
+
+			if light_around[i].type == "OVERALL_MIN" or
+				light_around[i].type == "OVERALL_MAX" then
+
+				for j=0,24000,1000 do
+					local light_level =
+						adv_spawning.voxelmaniplight(node_data,
+														voxel_light_data,
+														voxelhelper,
+														checkpos,j)
+
+					if light_level ~= nil then
+						if light_around[i].type == "OVERALL_MAX" and
+							light_level > light_around[i].threshold then
+							return false
+						end
+
+						if light_around[i].type == "OVERALL_MIN" and
+							light_level < light_around[i].threshold then
+							return false
+						end
+					end
+				end
+
+			else
+				local light_level =
+						adv_spawning.voxelmaniplight(node_data,
+														voxel_light_data,
+														voxelhelper,
+														checkpos,time)
+
+				if light_level ~= nil then
+					if (light_around[i].type == "TIMED_MIN" or
+						light_around[i].type == "CURRENT_MIN") and
+						light_level < light_around[i].threshold then
+							return false
+					end
+
+					if (light_around[i].type == "TIMED_MAX" or
+						light_around[i].type == "CURRENT_MAX") and
+						light_level > light_around[i].threshold then
+							return false
+					end
+				end
+			end
+		end
+		end
+		end
+	end
+
+	return true
+end
+
+local light_lookup = {
+		{4250+125, 150},
+		{4500+125, 150},
+		{4750+125, 250},
+		{5000+125, 350},
+		{5250+125, 500},
+		{5500+125, 675},
+		{5750+125, 875},
+		{6000+125, 1000},
+		{6250+125, 1000}
+	}
+
+function adv_spawning.day_night_ratio(time)
+
+	--make sure time is between 0 and 240000
+	if time < 0 then
+		time = time - (((time*-1)/24000)*24000)
+	end
+	if time > 24000 then
+		time = time + ((time/24000)*24000)
+	end
+
+	--invert time for sunset
+	if time > 12000 then
+		time = 24000 - time
+	end
+
+	local dnr = 1000
+
+	for i=1,#light_lookup,1 do
+		if time < light_lookup[i][1] then
+			dnr = light_lookup[i][2]
+			break
+		end
+	end
+
+	return dnr
+end
+
+function adv_spawning.voxelmaniplight(node_data,light_data,area,pos,time)
+
+	if not area:containsp(pos) then
+		return minetest.get_node_light(pos, time)
+	end
+
+	pos = vector.round(pos)
+	local index = area:indexp(pos)
+
+	local raw_light_value = light_data[index]
+
+	if raw_light_value == nil then
+		return nil
+	end
+
+	local light_day   = nil
+	local light_night = nil
+
+	--read node information
+	local content_id = node_data[index]
+	local nodename = minetest.get_name_from_content_id(content_id)
+	local nodedef = minetest.registered_nodes[nodename]
+
+	-- check for solid node
+	if nodedef.paramtype ~= "light" then
+		light_day = 0
+		light_night = 0
+	else
+		light_day   = raw_light_value % 16
+		light_night = (raw_light_value - light_day)/16
+	end
+
+	--check lightsource
+	if nodedef.light_source ~= nil then
+		light_day = adv_spawning.MAX(nodedef.light_source,light_day)
+		light_night = adv_spawning.MAX(nodedef.light_source,light_night)
+	end
+
+	time = time *24000
+	time = time %24000
+
+	local dnr = adv_spawning.day_night_ratio(time)
+
+	local c = 1000
+	local current_light = ((dnr * light_day + (c-dnr) * light_night))/c
+	if(current_light > LIGHT_MAX+1) then
+		current_light = LIGHT_MAX+1
+	end
+
+	return math.floor(current_light)
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_temperature_around
+-- @param pos position to validate
+-- @param temperature_around temperature around definitions
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_temperature_around(pos,temperature_around)
+	if temperature_around == nil then
+		return true
+	end
+
+	--TODO
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_humidity_around
+-- @param pos position to validate
+-- @param humidity_around humidity around definitions
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_humidity_around(pos,humidity_around)
+	if humidity_around == nil then
+		return true
+	end
+	--TODO
+	return true
+end
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_flat_area
+-- @param pos position to validate
+-- @param range to check for same height
+-- @param deviation maximum nmber of nodes not matching flat check
+-- @param spawn_inside nodes to spawn inside
+-- @return true/false
+--------------------------------------------------------------------------------
+function adv_spawning.check_flat_area(new_pos,flat_area,spawn_inside,surfaces)
+
+	if flat_area == nil then
+		return true
+	end
+
+	local range = flat_area.range
+
+	local back_left = {x=new_pos.x-range,y=new_pos.y-1,z=new_pos.z-range}
+	local front_right = { x=new_pos.x+range,y=new_pos.y-1,z=new_pos.z+range}
+
+	local current_deviation = 0
+
+	if flat_area.deviation ~= nil then
+		current_deviation = flat_area.deviation
+	end
+
+	local required_nodes = (range*2+1)*(range*2+1) - current_deviation
+
+	if surfaces == nil then
+		local ground_nodes =
+			minetest.find_nodes_in_area(back_left, front_right, spawn_inside)
+
+		if #ground_nodes > current_deviation then
+			adv_spawning.log("info","check_flat_area: " .. range .. " "
+				..dump(current_deviation).. " " .. #ground_nodes )
+			--adv_spawning.dump_area({x=back_left.x,y=new_pos.y-1,z=back_left.z},
+			--						front_right)
+			return false
+		end
+	else
+		local ground_nodes =
+			minetest.find_nodes_in_area(back_left, front_right, surfaces)
+
+		if #ground_nodes < required_nodes then
+			adv_spawning.log("info","check_flat_area: " .. range .. " " ..
+				dump(current_deviation).. " " .. #ground_nodes )
+			--adv_spawning.dump_area({x=back_left.x,y=new_pos.y-1,z=back_left.z},
+			--						front_right)
+			return false
+		end
+	end
+
+	back_left.y = new_pos.y
+	front_right.y = new_pos.y
+
+	local inside_nodes =
+		minetest.find_nodes_in_area(back_left, front_right, spawn_inside)
+
+	if #inside_nodes < required_nodes then
+		adv_spawning.log("info","check_flat_area: " .. range .. " " ..
+			dump(current_deviation) .. " "
+			.. #inside_nodes .. "/" .. required_nodes)
+		--adv_spawning.dump_area({x=back_left.x,y=new_pos.y-1,z=back_left.z},
+		--						front_right)
+		return false
+	end
+
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] log
+-- @param level
+-- @param text
+--------------------------------------------------------------------------------
+function adv_spawning.log(level,text)
+	local is_debug = false
+
+	if not is_debug then
+		return
+	end
+	print("ADV_SPAWNING:" .. text)
+	minetest.log(level,text)
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_collisionbox
+-- @param pos position to check
+-- @param collisionbox collisionbox to use
+-- @param spawn_inside nodes to spawn inside
+--------------------------------------------------------------------------------
+function adv_spawning.check_collisionbox(pos,collisionbox,spawn_inside)
+	if collisionbox == nil then
+		return true,nil
+	end
+
+	--skip for collisionboxes smaller then a single node
+	if collisionbox[1] >= -0.5 and collisionbox[2] >= -0.5 and collisionbox[3] >= -0.5 and
+		collisionbox[4] <= 0.5 and collisionbox[5] <= 0.5 and collisionbox[6] <= 0.5 then
+		return true,nil
+	end
+
+	--lets do the more complex checks
+	--first check if we need to move up
+	if collisionbox[2] < -0.5 then
+		pos.y = pos.y + (collisionbox[2]*-1) - 0.45
+	end
+
+	local minp = {
+				x=pos.x+collisionbox[1],
+				y=pos.y+collisionbox[2],
+				z=pos.z+collisionbox[3]
+				}
+	local maxp = {
+				x=pos.x+collisionbox[4],
+				y=pos.y+collisionbox[5],
+				z=pos.z+collisionbox[6]
+				}
+
+	local lastpos = nil
+
+	for y=minp.y,maxp.y,1 do
+	for z=minp.z,maxp.z,1 do
+	for x=minp.x,maxp.x,1 do
+		local checkpos = {x=x,y=y,z=z}
+		if not adv_spawning.is_same_pos(checkpos,lastpos) then
+			local node = minetest.get_node(checkpos)
+
+			if not adv_spawning.contains(spawn_inside,node.name) then
+				adv_spawning.log("info","Failed collision box check: " ..
+						minetest.pos_to_string(pos) .. " "
+						.. dump(node.name) .. " at ".. minetest.pos_to_string(checkpos))
+				--adv_spawning.dump_area()
+				return false,nil
+			end
+
+			lastpos = checkpos
+		end
+	end
+	end
+	end
+
+	return true,pos.y
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_active_block
+-- @param pos position to check
+-- @param collisionbox collisionbox to use
+-- @param spawn_inside nodes to spawn inside
+--------------------------------------------------------------------------------
+function adv_spawning.check_active_block(pos)
+	local players = minetest.get_connected_players()
+
+	for i=1,#players,1 do
+		if vector.distance(pos,players[i]:getpos()) < adv_spawning.active_range then
+			return true
+		end
+	end
+
+	return false
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] is_same_pos
+-- @param pos1 first for comparison
+-- @param pos2 second position for comparison
+--------------------------------------------------------------------------------
+function adv_spawning.is_same_pos(pos1,pos2)
+	if pos1 == nil or pos2 == nil then
+		return false
+	end
+
+	if pos1.x ~= pos2.x or
+		pos1.y ~= pos2.y or
+		pos1.z ~= pos2.z then
+		return false
+	end
+
+	return true
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] handle_mapgen_spawning
+--------------------------------------------------------------------------------
+function adv_spawning.handle_mapgen_spawning()
+	local continue = false
+	while(not continue and #adv_spawning.mapgen_jobqueue > 0) do
+		local toprocess = adv_spawning.mapgen_jobqueue[1]
+		table.remove(adv_spawning.mapgen_jobqueue,1)
+
+		--print("Processing job: " .. dump(toprocess) .. " no_quota: " ..
+		--			dump(adv_spawning.time_over(10)))
+
+		local tries = 0
+
+		while ( toprocess.retries > 0 and
+				toprocess.spawntotal > 0 and
+				tries < adv_spawning.max_mapgen_tries_per_step and
+				(not adv_spawning.time_over(10)) )do
+
+			local single_spawn_check = adv_spawning.gettime()
+
+			local retval,permanent_error = adv_spawning.handlespawner(toprocess.spawner,
+											{x=0,y=0,z=0},
+											toprocess.minp,
+											toprocess.maxp,
+											true)
+			
+			local delta = adv_spawning.gettime() - adv_spawning.quota_starttime
+
+			if retval then
+				toprocess.spawntotal = toprocess.spawntotal -1
+			end
+
+			if permanent_error then
+				toprocess.retries = 0
+			end
+
+			toprocess.retries = toprocess.retries -1
+			tries = tries +1
+		end
+
+		if toprocess.retries > 0 then
+			if toprocess.spawntotal > 0 then
+				table.insert(adv_spawning.mapgen_jobqueue,toprocess)
+			end
+			continue = true
+		end
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] queue_mapgen_jobs
+-- @param minp
+-- @param maxp
+--------------------------------------------------------------------------------
+function adv_spawning.queue_mapgen_jobs(minp,maxp)
+	for key,value in pairs(adv_spawning.spawner_definitions) do
+		local continue = false
+
+		--check if cyclic spawning is enabled
+		if not continue and
+			(value.mapgen == nil or
+			value.mapgen.enabled == false) then
+			continue = true
+		end
+
+
+		if not continue then
+			table.insert(adv_spawning.mapgen_jobqueue,
+				{
+					minp = minp,
+					maxp = maxp,
+					spawner = key,
+					retries = value.mapgen.retries,
+					spawntotal = value.mapgen.spawntotal
+				})
+		end
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] dump_area
+-- @param minp
+-- @param maxp
+--------------------------------------------------------------------------------
+function adv_spawning.dump_area(minp,maxp)
+	print("Dumping: " .. dump(minp) .. "<-->" .. dump(maxp))
+	for y=minp.y,maxp.y,1 do
+	print("--- ypos: " .. y .. " --------------------------------------------------------------")
+	for z=minp.z,maxp.z,1 do
+	local line = ""
+	for x=minp.x,maxp.x,1 do
+		local node = minetest.get_node({x=x,y=y,z=z})
+
+		local toprint = node.name
+
+		if toprint:find(":") ~= nil then
+			toprint = toprint:sub(toprint:find(":")+1)
+		end
+
+		line = line .. string.format(" %15s |",toprint)
+	end
+		print(line)
+	end
+	print("")
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] check_time
+-- @param starttime time since when to check
+-- @param checkid name of this check
+--
+-- @return current time for next check
+--------------------------------------------------------------------------------
+function adv_spawning.check_time(starttime, checkid)
+	local currenttime = adv_spawning.gettime()
+	local delta = currenttime - starttime
+	
+	if (delta > adv_spawning.quota_reload) then
+		if adv_spawning.spawner_warned[checkid] ~= true then
+			adv_spawning.dbg_log(1, "spawner " .. checkid ..
+				"\n\texceeded more then full reload time on init (" .. delta .. " ms)." ..
+				"\n\tFix it as it will cause major lag on mapgen!")
+			adv_spawning.spawner_warned[checkid] = true
+		end
+	end
+	
+	return currenttime
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] dbg_log
+-- @param loglevel level print it
+-- @param message message to print
+--------------------------------------------------------------------------------
+function adv_spawning.dbg_log(loglevel, message)
+	if (adv_spawning.loglevel >= loglevel ) then
+		core.log("action", "ADV_SPAWNING: " .. message)
+	end
+end
+
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] refresh_spawners
+-- @param pos to refresh spawners around
+--------------------------------------------------------------------------------
+function adv_spawning.refresh_spawners(pos)
+
+	local min = {x=pos.x-32, y=pos.y-32, z=pos.z-32}
+	local max = {x=pos.x+32, y=pos.y+32, z=pos.z+32}
+
+	local start_x =
+		math.floor(min.x/adv_spawning.spawner_distance)
+		* adv_spawning.spawner_distance
+	local start_y =
+		(math.floor(min.y/adv_spawning.spawner_distance)
+			* adv_spawning.spawner_distance)
+			+ adv_spawning.spawner_y_offset
+	local start_z =
+		math.floor(min.z/adv_spawning.spawner_distance)
+		* adv_spawning.spawner_distance
+
+	for x=start_x,max.x,adv_spawning.spawner_distance do
+	for y=start_y,max.y,adv_spawning.spawner_distance do
+	for z=start_z,max.z,adv_spawning.spawner_distance do
+		if x > min.x and
+			y > min.y and
+			z > min.z then
+			if not adv_spawning.quota_leave() then
+				adv_spawning.dbg_log(2,
+					"adv_spawning: refresh_spawners did use way too much time 1")
+			end
+			minetest.add_entity({x=x,y=y,z=z},"adv_spawning:spawn_seed")
+			adv_spawning.quota_enter(true)
+			adv_spawning.log("info", "adv_spawning: adding spawner entity at "
+				.. core.pos_to_string({x=x,y=y,z=z}))
+			adv_spawning.statistics.session.spawners_created =
+				adv_spawning.statistics.session.spawners_created +1
+		end
+	end
+	end
+	end
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] table_count
+-- @param tocount table to get number of elements from
+--------------------------------------------------------------------------------
+function adv_spawning.table_count(tocount)
+	local retval = 0
+	for k,v in pairs(tocount) do
+		retval = retval +1
+	end
+	
+	return retval
+end
+
+function adv_spawning.build_shell(pos, d)
+	local retval = {}
+	
+	-- build top face
+	for x = -d , d , 1 do
+		for z = -d, d, 1 do
+			retval[#retval+1] =  { x = pos.x + x, y = pos.y + d, z = pos.z + z}
+		end
+	end
+	
+	-- build bottom face
+	for x = -d , d , 1 do
+		for z = -d, d, 1 do
+			retval[#retval+1] =  { x = pos.x + x, y = pos.y -d, z = pos.z + z}
+		end
+	end
+	
+	-- build x- face
+	for z = -d , d , 1 do
+		for y = - (d -1) , (d -1), 1 do
+			retval[#retval+1] =  { x = pos.x -d, y = pos.y + y, z = pos.z + z}
+		end
+	end
+	
+	-- build x+ face
+	for z = -d , d , 1 do
+		for y = - (d -1) , (d -1), 1 do
+			retval[#retval+1] =  { x = pos.x + d, y = pos.y + y, z = pos.z + z}
+		end
+	end
+	
+	-- build z- face
+	for x = - (d -1) , (d -1) , 1 do
+		for y = - (d -1) , (d -1), 1 do
+			retval[#retval+1] =  { x = pos.x + x, y = pos.y + y, z = pos.z - d}
+		end
+	end
+	
+	-- build z+ face
+	for x = -(d -1) , (d -1) , 1 do
+		for y = - (d -1) , (d -1), 1 do
+			retval[#retval+1] =  { x = pos.x + x, y = pos.y + y, z = pos.z + d}
+		end
+	end
+	
+	return retval;
+end
+
+--------------------------------------------------------------------------------
+-- @function [parent=#adv_spawning] table_count
+-- @param tocount table to get number of elements from
+--------------------------------------------------------------------------------
+function adv_spawning.find_nodes_in(pos, min_range, max_range, nodetypes)
+
+	local nodetypes_to_use = nodetypes
+
+	if type(nodetypes) == "string" then
+		nodetypes_to_use = { }
+		table.insert(nodetypes_to_use, nodetypes)
+	end
+	
+	for i = min_range, max_range, 1 do
+		local positions = adv_spawning.build_shell(pos, i)
+		
+		for i = 1, #positions, 1 do
+			local node = minetest.get_node_or_nil(positions[i])
+			
+			if node ~= nil then
+				for i = 1, #nodetypes_to_use, 1 do
+					if node.name == nodetypes_to_use[i] then
+						return positions[i]
+					end
+				end
+			end
+		end
+	end
+	
+	return nil
+end
diff --git a/spawn_seed.lua b/spawn_seed.lua
new file mode 100644
index 0000000..fd4d6ce
--- /dev/null
+++ b/spawn_seed.lua
@@ -0,0 +1,403 @@
+-------------------------------------------------------------------------------
+-- advanced spawning mod
+--
+-- at license WTFP
+-- at copyright Sapier
+-- at author Sapier
+-- at 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
\ No newline at end of file
diff --git a/spawndef_checks.lua b/spawndef_checks.lua
new file mode 100644
index 0000000..9070f71
--- /dev/null
+++ b/spawndef_checks.lua
@@ -0,0 +1,73 @@
+-------------------------------------------------------------------------------
+-- advanced spawning mod
+--
+-- at license WTFP
+-- at copyright Sapier
+-- at author Sapier
+-- at 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
\ No newline at end of file
diff --git a/testmod/depends.txt b/testmod/depends.txt
new file mode 100644
index 0000000..5902e98
--- /dev/null
+++ b/testmod/depends.txt
@@ -0,0 +1 @@
+adv_spawning
\ No newline at end of file
diff --git a/testmod/init.lua b/testmod/init.lua
new file mode 100644
index 0000000..bd4aea5
--- /dev/null
+++ b/testmod/init.lua
@@ -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
+	})
\ No newline at end of file
diff --git a/testmod/textures/testmod_num1.png b/testmod/textures/testmod_num1.png
new file mode 100644
index 0000000..2913413
Binary files /dev/null and b/testmod/textures/testmod_num1.png differ
diff --git a/testmod/textures/testmod_num2.png b/testmod/textures/testmod_num2.png
new file mode 100644
index 0000000..29f27f0
Binary files /dev/null and b/testmod/textures/testmod_num2.png differ
diff --git a/testmod/textures/testmod_num3.png b/testmod/textures/testmod_num3.png
new file mode 100644
index 0000000..e3744aa
Binary files /dev/null and b/testmod/textures/testmod_num3.png differ
diff --git a/testmod/textures/testmod_num4.png b/testmod/textures/testmod_num4.png
new file mode 100644
index 0000000..862ed9c
Binary files /dev/null and b/testmod/textures/testmod_num4.png differ
diff --git a/textures/adv_spawning_invisible.png b/textures/adv_spawning_invisible.png
new file mode 100644
index 0000000..8cb82be
Binary files /dev/null and b/textures/adv_spawning_invisible.png differ
diff --git a/textures/adv_spawning_spawner.png b/textures/adv_spawning_spawner.png
new file mode 100644
index 0000000..5ba21c1
Binary files /dev/null and b/textures/adv_spawning_spawner.png differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/minetest-mod-advspawning.git



More information about the Pkg-games-commits mailing list