Split hostile and non-hostile mob caps

This commit is contained in:
ancientmarinerdev 2023-05-29 19:26:43 +01:00
parent 4c3d726882
commit ae32ce4a0a
2 changed files with 76 additions and 37 deletions

@ -27,8 +27,11 @@ local table_remove = table.remove
local pairs = pairs local pairs = pairs
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_spawning", false) local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_spawning", false)
local function mcl_log (message) local function mcl_log (message, property)
if LOGGING_ON then if LOGGING_ON then
if property then
message = message .. ": " .. dump(property)
end
mcl_util.mcl_log (message, "[Mobs spawn]", true) mcl_util.mcl_log (message, "[Mobs spawn]", true)
end end
end end
@ -52,7 +55,7 @@ local MOB_CAP_INNER_RADIUS = 32
local aoc_range = 136 local aoc_range = 136
local MISSING_CAP_DEFAULT = 15 local MISSING_CAP_DEFAULT = 15
local MOBS_CAP_CLOSE = 5 local MOBS_CAP_CLOSE = 10
local SPAWN_MAPGEN_LIMIT = mcl_vars.mapgen_limit - 150 local SPAWN_MAPGEN_LIMIT = mcl_vars.mapgen_limit - 150
@ -63,6 +66,8 @@ local mob_cap = {
water = tonumber(minetest.settings:get("mcl_mob_cap_water")) or 8, water = tonumber(minetest.settings:get("mcl_mob_cap_water")) or 8,
water_ambient = tonumber(minetest.settings:get("mcl_mob_cap_water_ambient")) or 20, --currently unused water_ambient = tonumber(minetest.settings:get("mcl_mob_cap_water_ambient")) or 20, --currently unused
player = tonumber(minetest.settings:get("mcl_mob_cap_player")) or 75, player = tonumber(minetest.settings:get("mcl_mob_cap_player")) or 75,
global_hostile = tonumber(minetest.settings:get("mcl_mob_cap_hostile")) or 300,
global_non_hostile = tonumber(minetest.settings:get("mcl_mob_cap_non_hostile")) or 300,
total = tonumber(minetest.settings:get("mcl_mob_cap_total")) or 500, total = tonumber(minetest.settings:get("mcl_mob_cap_total")) or 500,
} }
@ -340,15 +345,32 @@ local function count_mobs_all(categorise_by, pos)
end end
local function count_mobs_total_cap(mob_type) local function count_mobs_total_cap(mob_type)
local total = 0
local num = 0 local num = 0
local hostile = 0
local non_hostile = 0
for _,l in pairs(minetest.luaentities) do for _,l in pairs(minetest.luaentities) do
if l.is_mob then if l.is_mob then
if ( mob_type == nil or l.type == mob_type ) and l.can_despawn and not l.nametag then total = total + 1
local nametagged = l.nametag and l.nametag ~= ""
if ( mob_type == nil or l.type == mob_type ) and not nametagged then
if l.spawn_class == "hostile" then
hostile = hostile + 1
else
non_hostile = non_hostile + 1
end
num = num + 1 num = num + 1
else
mcl_log("l.nametag", l.name)
mcl_log("l.nametag", l.nametag)
end end
end end
end end
return num mcl_log("Total mobs", total)
mcl_log("hostile", hostile)
mcl_log("non_hostile", non_hostile)
return num, non_hostile, hostile
end end
local function output_mob_stats(mob_counts, total_mobs, chat_display) local function output_mob_stats(mob_counts, total_mobs, chat_display)
@ -704,13 +726,13 @@ local function spawn_check(pos, spawn_def)
--mcl_log("Level 3 spawn check passed") --mcl_log("Level 3 spawn check passed")
return true return true
else else
mcl_log("Spawn check level 3 failed") --mcl_log("Spawn check level 3 failed")
end end
else else
mcl_log("Spawn check level 2 failed") --mcl_log("Spawn check level 2 failed")
end end
else else
mcl_log("Spawn check level 1 failed") --mcl_log("Spawn check level 1 failed")
end end
return false return false
end end
@ -831,7 +853,7 @@ if mobs_spawn then
-- Get pos to spawn, x and z are randomised, y is range -- Get pos to spawn, x and z are randomised, y is range
local function mob_cap_space (pos, mob_type, mob_counts_close, mob_counts_wide) local function mob_cap_space (pos, mob_type, mob_counts_close, mob_counts_wide, cap_space_hostile, cap_space_non_hostile)
-- Some mob examples -- Some mob examples
--type = "monster", spawn_class = "hostile", --type = "monster", spawn_class = "hostile",
@ -847,10 +869,20 @@ if mobs_spawn then
mob_total_wide = 0 mob_total_wide = 0
end end
local cap_space_wide = type_cap - mob_total_wide local cap_space_wide = math.max(type_cap - mob_total_wide, 0)
if cap_space_wide < 1 then
cap_space_wide = 0 local cap_space_available = 0
if mob_type == "hostile" then
mcl_log("cap_space_global", cap_space_hostile)
cap_space_available = math.min(cap_space_hostile, cap_space_wide)
else
mcl_log("cap_space_global", cap_space_non_hostile)
cap_space_available = math.min(cap_space_non_hostile, cap_space_wide)
end end
mcl_log("mob_type", mob_type)
mcl_log("cap_space_wide", cap_space_wide)
--mcl_log("cap_space_available", cap_space_available)
local mob_total_close = mob_counts_close[mob_type] local mob_total_close = mob_counts_close[mob_type]
if not mob_total_close then if not mob_total_close then
@ -858,12 +890,12 @@ if mobs_spawn then
mob_total_close = 0 mob_total_close = 0
end end
local cap_space_close = close_zone_cap - mob_total_close local cap_space_close = math.max(close_zone_cap - mob_total_close, 0)
if cap_space_close < 1 then mcl_log("cap_space_close", cap_space_close)
cap_space_close = 0
end cap_space_available = math.min(cap_space_available, cap_space_close)
mcl_log("cap_space_available", cap_space_available)
--mcl_log("spawn_class: " .. spawn_class)
if false and mob_type == "water" then if false and mob_type == "water" then
mcl_log("mob_type: " .. mob_type .. " and pos: " .. minetest.pos_to_string(pos)) mcl_log("mob_type: " .. mob_type .. " and pos: " .. minetest.pos_to_string(pos))
@ -873,7 +905,7 @@ if mobs_spawn then
mcl_log("cap_space_close: " .. cap_space_close) mcl_log("cap_space_close: " .. cap_space_close)
end end
return cap_space_wide, cap_space_close return cap_space_available
end end
local function find_spawning_position(pos, max_times) local function find_spawning_position(pos, max_times)
@ -884,7 +916,7 @@ if mobs_spawn then
local y_min, y_max = decypher_limits(pos.y) local y_min, y_max = decypher_limits(pos.y)
mcl_log("mapgen_limit: " .. SPAWN_MAPGEN_LIMIT) --mcl_log("mapgen_limit: " .. SPAWN_MAPGEN_LIMIT)
local i = 0 local i = 0
repeat repeat
local goal_pos = get_next_mob_spawn_pos(pos) local goal_pos = get_next_mob_spawn_pos(pos)
@ -916,7 +948,7 @@ if mobs_spawn then
return spawning_position return spawning_position
end end
local function spawn_a_mob(pos) local function spawn_a_mob(pos, cap_space_hostile, cap_space_non_hostile)
--create a disconnected clone of the spawn dictionary, prevents memory leak --create a disconnected clone of the spawn dictionary, prevents memory leak
local mob_library_worker_table = table_copy(spawn_dictionary) local mob_library_worker_table = table_copy(spawn_dictionary)
@ -954,22 +986,20 @@ if mobs_spawn then
if mob_def and mob_def.name and minetest.registered_entities[mob_def.name] then if mob_def and mob_def.name and minetest.registered_entities[mob_def.name] then
local mob_def_ent = minetest.registered_entities[mob_def.name] local mob_def_ent = minetest.registered_entities[mob_def.name]
--local mob_type = mob_def_ent.type
local mob_spawn_class = mob_def_ent.spawn_class
local mob_spawn_class = mob_def_ent.spawn_class
--mcl_log("mob_spawn_class: " .. mob_spawn_class) --mcl_log("mob_spawn_class: " .. mob_spawn_class)
local cap_space_wide, cap_space_close = mob_cap_space (spawning_position, mob_spawn_class, mob_counts_close, mob_counts_wide) local cap_space_available = mob_cap_space (spawning_position, mob_spawn_class, mob_counts_close, mob_counts_wide, cap_space_hostile, cap_space_non_hostile)
if cap_space_available > 0 then
if cap_space_close > 0 and cap_space_wide > 0 then
--mcl_log("Cap space available") --mcl_log("Cap space available")
-- Spawn caps for animals and water creatures fill up rapidly. Need to throttle this somewhat -- Spawn caps for animals and water creatures fill up rapidly. Need to throttle this somewhat
-- for performance and for early game challenge. We don't want to reduce hostiles though. -- for performance and for early game challenge. We don't want to reduce hostiles though.
local spawn_hostile = (mob_spawn_class == "hostile") local spawn_hostile = (mob_spawn_class == "hostile")
local spawn_passive = (mob_spawn_class ~= "hostile") and math.random(100) < peaceful_percentage_spawned local spawn_passive = (mob_spawn_class ~= "hostile") and math.random(100) < peaceful_percentage_spawned
-- or not hostile
--mcl_log("Spawn_passive: " .. tostring(spawn_passive)) --mcl_log("Spawn_passive: " .. tostring(spawn_passive))
--mcl_log("Spawn_hostile: " .. tostring(spawn_hostile)) --mcl_log("Spawn_hostile: " .. tostring(spawn_hostile))
@ -1000,13 +1030,10 @@ if mobs_spawn then
local group_min = mob_def_ent.spawn_in_group_min or 1 local group_min = mob_def_ent.spawn_in_group_min or 1
if not group_min then group_min = 1 end if not group_min then group_min = 1 end
local amount_to_spawn = math.random(group_min,spawn_in_group) local amount_to_spawn = math.random(group_min, spawn_in_group)
mcl_log("Spawning quantity: " .. amount_to_spawn)
if amount_to_spawn > cap_space_wide then amount_to_spawn = math.min(amount_to_spawn, cap_space_available)
mcl_log("Spawning quantity: " .. amount_to_spawn) mcl_log("throttled spawning quantity: " .. amount_to_spawn)
mcl_log("Throttle amount to cap space: " .. cap_space_wide)
amount_to_spawn = cap_space_wide
end
if logging then if logging then
minetest.log("action", "[mcl_mobs] A group of " ..amount_to_spawn .. " " .. mob_def.name .. " mob spawns on " ..minetest.get_node(vector.offset(spawning_position,0,-1,0)).name .." at " .. minetest.pos_to_string(spawning_position, 1)) minetest.log("action", "[mcl_mobs] A group of " ..amount_to_spawn .. " " .. mob_def.name .. " mob spawns on " ..minetest.get_node(vector.offset(spawning_position,0,-1,0)).name .." at " .. minetest.pos_to_string(spawning_position, 1))
@ -1021,7 +1048,7 @@ if mobs_spawn then
if spawned then if spawned then
--mcl_log("We have spawned") --mcl_log("We have spawned")
mob_counts_close, mob_counts_wide, total_mobs = count_mobs_all("type", pos) mob_counts_close, mob_counts_wide, total_mobs = count_mobs_all("spawn_class", pos)
local new_spawning_position = find_spawning_position(pos, FIND_SPAWN_POS_RETRIES_SUCCESS_RESPIN) local new_spawning_position = find_spawning_position(pos, FIND_SPAWN_POS_RETRIES_SUCCESS_RESPIN)
if new_spawning_position then if new_spawning_position then
mcl_log("Setting new spawning position") mcl_log("Setting new spawning position")
@ -1034,7 +1061,7 @@ if mobs_spawn then
--mcl_log("Spawn check failed") --mcl_log("Spawn check failed")
end end
else else
mcl_log("Cap space full") --mcl_log("Cap space full")
end end
end end
@ -1054,7 +1081,13 @@ if mobs_spawn then
timer = 0 timer = 0
local players = get_connected_players() local players = get_connected_players()
local total_mobs = count_mobs_total_cap() local total_mobs, total_non_hostile, total_hostile = count_mobs_total_cap()
local cap_space_hostile = math.max(mob_cap.global_hostile - total_hostile, 0)
local cap_space_non_hostile = math.max(mob_cap.global_non_hostile - total_non_hostile, 0)
mcl_log("global cap_space_hostile", cap_space_hostile)
mcl_log("global cap_space_non_hostile", cap_space_non_hostile)
if total_mobs > mob_cap.total or total_mobs > #players * mob_cap.player then if total_mobs > mob_cap.total or total_mobs > #players * mob_cap.player then
minetest.log("action","[mcl_mobs] global mob cap reached. no cycle spawning.") minetest.log("action","[mcl_mobs] global mob cap reached. no cycle spawning.")
return return
@ -1065,7 +1098,7 @@ if mobs_spawn then
local dimension = mcl_worlds.pos_to_dimension(pos) local dimension = mcl_worlds.pos_to_dimension(pos)
-- ignore void and unloaded area -- ignore void and unloaded area
if dimension ~= "void" and dimension ~= "default" then if dimension ~= "void" and dimension ~= "default" then
spawn_a_mob(pos) spawn_a_mob(pos, cap_space_hostile, cap_space_non_hostile)
end end
end end
end) end)

@ -130,9 +130,15 @@ mcl_mob_peaceful_group_percentage_spawned (Peaceful group percentage) int 15 0 1
#Percentage of hostile spawn attempts that are group spawns (default:20) #Percentage of hostile spawn attempts that are group spawns (default:20)
mcl_mob_hostile_group_percentage_spawned (Hostile group percentage) int 20 0 100 mcl_mob_hostile_group_percentage_spawned (Hostile group percentage) int 20 0 100
#Maximum amount mobs (default:500) #Maximum amount of mobs (default:500)
mcl_mob_cap_total (Global mob cap) int 500 0 2048 mcl_mob_cap_total (Global mob cap) int 500 0 2048
#Maximum amount of hostile mobs (default:300)
mcl_mob_cap_hostile (Global hostile mob cap) int 300 0 2048
#Maximum amount of non-hostile mobs (default:300)
mcl_mob_cap_non_hostile (Global non-hostile mob cap) int 300 0 2048
#Maximum amount of mobs per player (default:75) #Maximum amount of mobs per player (default:75)
mcl_mob_cap_player (Mob cap per player) int 75 0 2048 mcl_mob_cap_player (Mob cap per player) int 75 0 2048