Ver 2.0 with ocean support

This commit is contained in:
quackerd 2019-10-27 04:52:14 -04:00
parent 4812518e76
commit 4e4cf915cd
5 changed files with 241 additions and 528 deletions

View File

@ -1,6 +1,6 @@
name = "World Regrowth++" name = "World Regrowth++"
version = "1.0" version = "2.0"
description = "Version "..version.."\n\nWorld regrowth with caves support. Please see the Steam Workshop page for changes notes.\n\nHappy hunting and do starve!" description = "Version "..version.."\n\nWorld regrowth with caves and ocean support. Please see the Steam Workshop page for changes notes.\n\nHappy hunting and do starve!"
author = "lolo" author = "lolo"
forumthread = "" forumthread = ""
@ -16,54 +16,53 @@ dst_compatible = true
local REGROWTH_TYPE = local REGROWTH_TYPE =
{ {
NATURAL = 1, EVENT = 1
EVENT = 2
} }
-- Configuration Generation -- Configuration Generation
-- I can't reference this from another file... duplicate -- I can't reference this from another file... duplicate
local config_table = local config_table =
{ {
{"evergreen","Evergreen", REGROWTH_TYPE.NATURAL, 1}, {"evergreen","Evergreen", REGROWTH_TYPE.EVENT, 1},
{"deciduoustree","Birchnut Tree",REGROWTH_TYPE.NATURAL, 1}, {"deciduoustree","Birchnut Tree",REGROWTH_TYPE.EVENT, 1},
{"marsh_tree","Spiky Tree",REGROWTH_TYPE.NATURAL, 2}, {"marsh_tree","Spiky Tree",REGROWTH_TYPE.EVENT, 2},
{"twiggytree","Twiggy Tree",REGROWTH_TYPE.NATURAL, 2}, {"twiggytree","Twiggy Tree",REGROWTH_TYPE.EVENT, 2},
{"marbletree","Marble Tree",REGROWTH_TYPE.EVENT, 4}, {"marbletree","Marble Tree",REGROWTH_TYPE.EVENT, 4},
{"livingtree","Totally Normal Tree",REGROWTH_TYPE.EVENT, 4}, {"livingtree","Totally Normal Tree",REGROWTH_TYPE.EVENT, 4},
{"mushtree_tall","Blue Mushtree", REGROWTH_TYPE.NATURAL, 1}, {"mushtree_tall","Blue Mushtree", REGROWTH_TYPE.EVENT, 1},
{"mushtree_medium","Red Mushtree",REGROWTH_TYPE.NATURAL, 1}, {"mushtree_medium","Red Mushtree",REGROWTH_TYPE.EVENT, 1},
{"mushtree_small","Green Mushtree", REGROWTH_TYPE.NATURAL, 1}, {"mushtree_small","Green Mushtree", REGROWTH_TYPE.EVENT, 1},
{"berrybush","Berry Bush",REGROWTH_TYPE.NATURAL, 4}, {"berrybush","Berry Bush",REGROWTH_TYPE.EVENT, 4},
{"berrybush2","Spiky Berry Bush",REGROWTH_TYPE.NATURAL, 4}, {"berrybush2","Spiky Berry Bush",REGROWTH_TYPE.EVENT, 4},
{"berrybush_juicy","Juicy Berry Bush",REGROWTH_TYPE.NATURAL, 4}, {"berrybush_juicy","Juicy Berry Bush",REGROWTH_TYPE.EVENT, 4},
{"carrot_planted","Carrot",REGROWTH_TYPE.NATURAL, 1}, {"carrot_planted","Carrot",REGROWTH_TYPE.EVENT, 1},
{"flower","Flower",REGROWTH_TYPE.NATURAL, 1}, {"flower","Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_evil","Evil Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_evil","Evil Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_cave","Light Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_cave","Light Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_cave_double","Double Light Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_cave_double","Double Light Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_cave_triple","Triple Light Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_cave_triple","Triple Light Flower",REGROWTH_TYPE.EVENT, 1},
{"blue_mushroom","Blue Mushroom",REGROWTH_TYPE.NATURAL, 1}, {"blue_mushroom","Blue Mushroom",REGROWTH_TYPE.EVENT, 1},
{"red_mushroom","Red Mushroom",REGROWTH_TYPE.NATURAL, 1}, {"red_mushroom","Red Mushroom",REGROWTH_TYPE.EVENT, 1},
{"green_mushroom","Green Mushroom",REGROWTH_TYPE.NATURAL, 1}, {"green_mushroom","Green Mushroom",REGROWTH_TYPE.EVENT, 1},
{"cactus","Cactus",REGROWTH_TYPE.NATURAL, 2}, {"cactus","Cactus",REGROWTH_TYPE.EVENT, 2},
{"mandrake_planted","Mandrake",REGROWTH_TYPE.EVENT, 6}, {"mandrake_planted","Mandrake",REGROWTH_TYPE.EVENT, 6},
{"cave_fern","Fern",REGROWTH_TYPE.NATURAL, 1}, {"cave_fern","Fern",REGROWTH_TYPE.EVENT, 1},
{"lichen","Lichen",REGROWTH_TYPE.NATURAL, 1}, {"lichen","Lichen",REGROWTH_TYPE.EVENT, 1},
{"reeds","Reeds",REGROWTH_TYPE.NATURAL, 2}, {"reeds","Reeds",REGROWTH_TYPE.EVENT, 2},
{"sapling","Sapling",REGROWTH_TYPE.NATURAL, 1}, {"sapling","Sapling",REGROWTH_TYPE.EVENT, 1},
{"grass","Grass",REGROWTH_TYPE.NATURAL, 1}, {"grass","Grass",REGROWTH_TYPE.EVENT, 1},
{"marsh_bush","Spiky Bush",REGROWTH_TYPE.NATURAL, 2}, {"marsh_bush","Spiky Bush",REGROWTH_TYPE.EVENT, 2},
{"rock1","Boulder",REGROWTH_TYPE.NATURAL, 1}, {"rock1","Boulder",REGROWTH_TYPE.EVENT, 1},
{"rock2","Gold Vein",REGROWTH_TYPE.NATURAL, 1}, {"rock2","Gold Vein",REGROWTH_TYPE.EVENT, 1},
{"rock_flintless","Flintless Boulder",REGROWTH_TYPE.NATURAL, 2}, {"rock_flintless","Flintless Boulder",REGROWTH_TYPE.EVENT, 2},
{"rock_moon","Moon Rock",REGROWTH_TYPE.NATURAL, 2}, {"rock_moon","Moon Rock",REGROWTH_TYPE.EVENT, 2},
{"stalagmite","Stalagmite",REGROWTH_TYPE.NATURAL, 1}, {"stalagmite","Stalagmite",REGROWTH_TYPE.EVENT, 1},
{"stalagmite_tall","Tall Stalagmite",REGROWTH_TYPE.NATURAL, 1}, {"stalagmite_tall","Tall Stalagmite",REGROWTH_TYPE.EVENT, 1},
{"rabbithole","Rabbit Hole",REGROWTH_TYPE.EVENT, 2}, {"rabbithole","Rabbit Hole",REGROWTH_TYPE.EVENT, 2},
{"beehive","Beehive",REGROWTH_TYPE.EVENT, 4}, {"beehive","Beehive",REGROWTH_TYPE.EVENT, 4},

View File

@ -1,55 +1,52 @@
local REGROWTH_TYPE = local REGROWTH_TYPE =
{ {
NATURAL = 1, EVENT = 1
EVENT = 2
} }
local DEBUG = false
-- Configuration Generation -- Configuration Generation
-- I can't reference this from another file... duplicate -- I can't reference this from another file... duplicate
local config_table = local config_table =
{ {
{"evergreen","Evergreen", REGROWTH_TYPE.NATURAL, 1}, {"evergreen","Evergreen", REGROWTH_TYPE.EVENT, 1},
{"deciduoustree","Birchnut Tree",REGROWTH_TYPE.NATURAL, 1}, {"deciduoustree","Birchnut Tree",REGROWTH_TYPE.EVENT, 1},
{"marsh_tree","Spiky Tree",REGROWTH_TYPE.NATURAL, 2}, {"marsh_tree","Spiky Tree",REGROWTH_TYPE.EVENT, 2},
{"twiggytree","Twiggy Tree",REGROWTH_TYPE.NATURAL, 2}, {"twiggytree","Twiggy Tree",REGROWTH_TYPE.EVENT, 2},
{"marbletree","Marble Tree",REGROWTH_TYPE.EVENT, 4}, {"marbletree","Marble Tree",REGROWTH_TYPE.EVENT, 4},
{"livingtree","Totally Normal Tree",REGROWTH_TYPE.EVENT, 4}, {"livingtree","Totally Normal Tree",REGROWTH_TYPE.EVENT, 4},
{"mushtree_tall","Blue Mushtree", REGROWTH_TYPE.NATURAL, 1}, {"mushtree_tall","Blue Mushtree", REGROWTH_TYPE.EVENT, 1},
{"mushtree_medium","Red Mushtree",REGROWTH_TYPE.NATURAL, 1}, {"mushtree_medium","Red Mushtree",REGROWTH_TYPE.EVENT, 1},
{"mushtree_small","Green Mushtree", REGROWTH_TYPE.NATURAL, 1}, {"mushtree_small","Green Mushtree", REGROWTH_TYPE.EVENT, 1},
{"berrybush","Berry Bush",REGROWTH_TYPE.NATURAL, 4}, {"berrybush","Berry Bush",REGROWTH_TYPE.EVENT, 4},
{"berrybush2","Spiky Berry Bush",REGROWTH_TYPE.NATURAL, 4}, {"berrybush2","Spiky Berry Bush",REGROWTH_TYPE.EVENT, 4},
{"berrybush_juicy","Juicy Berry Bush",REGROWTH_TYPE.NATURAL, 4}, {"berrybush_juicy","Juicy Berry Bush",REGROWTH_TYPE.EVENT, 4},
{"carrot_planted","Carrot",REGROWTH_TYPE.NATURAL, 1}, {"carrot_planted","Carrot",REGROWTH_TYPE.EVENT, 1},
{"flower","Flower",REGROWTH_TYPE.NATURAL, 1}, {"flower","Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_evil","Evil Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_evil","Evil Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_cave","Light Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_cave","Light Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_cave_double","Double Light Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_cave_double","Double Light Flower",REGROWTH_TYPE.EVENT, 1},
{"flower_cave_triple","Triple Light Flower",REGROWTH_TYPE.EVENT, 1}, {"flower_cave_triple","Triple Light Flower",REGROWTH_TYPE.EVENT, 1},
{"blue_mushroom","Blue Mushroom",REGROWTH_TYPE.NATURAL, 1}, {"blue_mushroom","Blue Mushroom",REGROWTH_TYPE.EVENT, 1},
{"red_mushroom","Red Mushroom",REGROWTH_TYPE.NATURAL, 1}, {"red_mushroom","Red Mushroom",REGROWTH_TYPE.EVENT, 1},
{"green_mushroom","Green Mushroom",REGROWTH_TYPE.NATURAL, 1}, {"green_mushroom","Green Mushroom",REGROWTH_TYPE.EVENT, 1},
{"cactus","Cactus",REGROWTH_TYPE.NATURAL, 2}, {"cactus","Cactus",REGROWTH_TYPE.EVENT, 2},
{"mandrake_planted","Mandrake",REGROWTH_TYPE.EVENT, 6}, {"mandrake_planted","Mandrake",REGROWTH_TYPE.EVENT, 6},
{"cave_fern","Fern",REGROWTH_TYPE.NATURAL, 1}, {"cave_fern","Fern",REGROWTH_TYPE.EVENT, 1},
{"lichen","Lichen",REGROWTH_TYPE.NATURAL, 1}, {"lichen","Lichen",REGROWTH_TYPE.EVENT, 1},
{"reeds","Reeds",REGROWTH_TYPE.NATURAL, 2}, {"reeds","Reeds",REGROWTH_TYPE.EVENT, 2},
{"sapling","Sapling",REGROWTH_TYPE.NATURAL, 1}, {"sapling","Sapling",REGROWTH_TYPE.EVENT, 1},
{"grass","Grass",REGROWTH_TYPE.NATURAL, 1}, {"grass","Grass",REGROWTH_TYPE.EVENT, 1},
{"marsh_bush","Spiky Bush",REGROWTH_TYPE.NATURAL, 2}, {"marsh_bush","Spiky Bush",REGROWTH_TYPE.EVENT, 2},
{"rock1","Boulder",REGROWTH_TYPE.NATURAL, 1}, {"rock1","Boulder",REGROWTH_TYPE.EVENT, 1},
{"rock2","Gold Vein",REGROWTH_TYPE.NATURAL, 1}, {"rock2","Gold Vein",REGROWTH_TYPE.EVENT, 1},
{"rock_flintless","Flintless Boulder",REGROWTH_TYPE.NATURAL, 2}, {"rock_flintless","Flintless Boulder",REGROWTH_TYPE.EVENT, 2},
{"rock_moon","Moon Rock",REGROWTH_TYPE.NATURAL, 2}, {"rock_moon","Moon Rock",REGROWTH_TYPE.EVENT, 2},
{"stalagmite","Stalagmite",REGROWTH_TYPE.NATURAL, 1}, {"stalagmite","Stalagmite",REGROWTH_TYPE.EVENT, 1},
{"stalagmite_tall","Tall Stalagmite",REGROWTH_TYPE.NATURAL, 1}, {"stalagmite_tall","Tall Stalagmite",REGROWTH_TYPE.EVENT, 1},
{"rabbithole","Rabbit Hole",REGROWTH_TYPE.EVENT, 2}, {"rabbithole","Rabbit Hole",REGROWTH_TYPE.EVENT, 2},
{"beehive","Beehive",REGROWTH_TYPE.EVENT, 4}, {"beehive","Beehive",REGROWTH_TYPE.EVENT, 4},
@ -89,48 +86,31 @@ if GLOBAL.STRINGS.NAMES.MIGRATION_PORTAL then
-- we have caves -- we have caves
AddPrefabPostInit("forest", function(inst) AddPrefabPostInit("forest", function(inst)
if inst.ismastersim then if inst.ismastersim then
inst:AddComponent("natural_regrowth") inst:AddComponent("extra_regrowth")
inst:AddComponent("event_regrowth")
end end
end) end)
AddPrefabPostInit("cave", function(inst) AddPrefabPostInit("cave", function(inst)
if inst.ismastersim then if inst.ismastersim then
inst:AddComponent("natural_regrowth") inst:AddComponent("extra_regrowth")
inst:AddComponent("event_regrowth")
end end
end) end)
else else
-- only overworld -- only overworld
AddPrefabPostInit("world", function(inst) AddPrefabPostInit("world", function(inst)
if inst.ismastersim then if inst.ismastersim then
inst:AddComponent("natural_regrowth") inst:AddComponent("extra_regrowth")
inst:AddComponent("event_regrowth")
end end
end) end)
end end
AddComponentPostInit("natural_regrowth", function(component) AddComponentPostInit("extra_regrowth", function(component)
for i = 1, #config_table do for i = 1, #config_table do
local entry = config_table[i] local entry = config_table[i]
local prefab = entry[1] local prefab = entry[1]
if (entry[3] == REGROWTH_TYPE.NATURAL) and (GetModConfigData(prefab) ~= 0) then if GetModConfigData(prefab) ~= 0 then
-- i % 3 - 1 = round robbin -1,0,1 local delay = GetModConfigData(prefab) * 240
local delay = GetModConfigData(prefab) * 240 + ((i % 3) - 1) * component:GetUpdatePeriod() component:RegisterRegrowth(prefab, prefab, delay)
component:RegisterRegrowth(prefab, prefab, DEBUG and (delay / 100) or delay)
end end
end end
component:FinishModConfig() component:FinishModConfig()
end)
AddComponentPostInit("event_regrowth", function(component)
for i = 1, #config_table do
local entry = config_table[i]
local prefab = entry[1]
if (entry[3] == REGROWTH_TYPE.EVENT) and (GetModConfigData(prefab) ~= 0) then
-- i % 3 - 1 = round robbin -1,0,1
local delay = GetModConfigData(prefab) * 240 + ((i % 3) - 1) * component:GetUpdatePeriod()
component:RegisterRegrowth(prefab, prefab, DEBUG and (delay / 100) or delay)
end
end
component:FinishModConfig()
end) end)

View File

@ -1,29 +1,75 @@
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ EventRegrowth class definition ]] --[[ EventRegrowth class definition ]]
-- A modified version of the original regrowthmanager.lua -- A modified and more feature-rich version of the original regrowthmanager.lua
-- It acts as a standalone regrowth manager and is independent of the 3 existing ones -- It acts as a standalone regrowth manager and is independent of the 3 existing ones
-- It's unlikely affected by game updates as long as Klei doesn't change the API (they shouldn't) -- It's unlikely affected by game updates as long as Klei doesn't break the API (they shouldn't)
-- by lolo Jan. 2018 -- quackerd
-------------------------------------------------------------------------- --------------------------------------------------------------------------
return Class(function(self, inst) return Class(function(self, inst)
assert(inst.ismastersim, "event_regrowth should not exist on client") assert(inst.ismastersim, "extra_regrowth should not exist on client")
require "map/terrain" require "map/terrain"
require "wrpp_util" require "ocean_util"
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Constants ]] --[[ Constants ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
local DEBUG = false local DEBUG = false
local DEBUG_TELE = false local DEBUG_TELE = false
local UPDATE_PERIOD = 9 local UPDATE_PERIOD = 9 -- 9 seconds per tick
local JITTER_RADIUS = 6 local JITTER_RADIUS = 1 -- random point within this radius
local MAX_RADIUS = 1000 local MAX_RADIUS = 1000 -- cap the max radius
local INC_RADIUS = BASE_RADIUS / 2 local INC_RADIUS = 3 -- increase this amount after we fail
local THREADS_PER_BATCH = 3 local BASE_RADIUS = 15 -- don't spawn near player's base
local THREADS_PER_BATCH_HOOK = 5 local EXCLUDE_RADIUS = 2 -- no other entities in this radius within the spawn point
local MIN_PLAYER_DISTANCE = 30 -- minimum distance of player to spawn entities
local EXCLUDE_TAGS =
{
"statue", -- marble stuff on the ground, ancient statues
"hive", --spiderden, wasphive, beehive
} -- these aren't considered structures
local EXCLUDE_PREFABS =
{
catcoonden = 1,
ancient_altar = 1,
ancient_altar_broken = 1,
houndmound = 1,
mermhouse = 1,
pigtorch = 1,
mermhead = 1,
pighead = 1,
pandoraschest = 1,
minotaurchest = 1,
pighouse = 1,
rabbithouse = 1,
chessjunk1 = 1,
chessjunk2 = 1,
chessjunk3 = 1,
wall_ruins = 1,
} -- these aren't considered structures
local REGROW_STATUS =
{
SUCCESS = 0,
STRUCT = 1,
CACHE = 2,
PLAYER = 3,
DENSITY = 4,
TILE = 5,
ROAD = 6,
OCEAN = 7
}
local CACHE_RETRY =
{
[REGROW_STATUS.PLAYER] = true,
} -- we don't increase the radius for these reasons
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Member variables ]] --[[ Member variables ]]
@ -33,13 +79,91 @@ return Class(function(self, inst)
self.inst = inst self.inst = inst
--Private --Private
local regrowth_table_populated_by_mod = false local ready = false
local regrowth_table = {} local regrowth_table = {}
local entity_list = {} local entity_list = {}
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Private member functions ]] --[[ Private member functions ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
local function TestStructures(x, y, z, radius)
local ents = TheSim:FindEntities(x,y,z, BASE_RADIUS, nil, EXCLUDE_TAGS, { "structure", "wall" })
for i, v in ipairs(ents) do
if EXCLUDE_PREFABS[v.prefab] == nil then
-- if we cannot find it from the exclude table, then it is a structure and we failed the test
return false
end
end
return true
end
local function CanPlaceAtPoint(x, y, z)
local tile = TheWorld.Map:GetTileAtPoint(x, y, z)
return tile ~= GROUND.IMPASSABLE and
tile ~= GROUND.INVALID and
not GROUND_FLOORING[tile]
end
local function TestPlayers(x, y, z, radius)
return not IsAnyPlayerInRange(x,y,z, MIN_PLAYER_DISTANCE, nil)
end
local function TestEntities(x, y, z, radius)
local ents = TheSim:FindEntities(x,y,z, EXCLUDE_RADIUS)
return not (#ents > 0)
end
local function TestRegrowth(x, y, z, prefab, tile)
local cur_tile = TheWorld.Map:GetTileAtPoint(x, y, z)
if not TestPlayers(x,y,z, MIN_PLAYER_DISTANCE) then
return REGROW_STATUS.PLAYER
end
if not TestStructures(x, y, z, BASE_RADIUS) then
-- No regrowth around players and their bases
return REGROW_STATUS.STRUCT
end
if not TestEntities(x,y,z, EXCLUDE_RADIUS) then
-- Too dense
return REGROW_STATUS.DENSITY
end
if (RoadManager ~= nil) and (RoadManager:IsOnRoad(x, 0, z)) then
return REGROW_STATUS.ROAD
end
-- hack to get away with it for now
if IsOceanTile(cur_tile) then
return REGROW_STATUS.OCEAN
end
if (CanPlaceAtPoint(x, y, z) and TheWorld.Map:CanPlacePrefabFilteredAtPoint(x, y, z, prefab)) or ((tile ~= nil) and (cur_tile == tile)) then
return REGROW_STATUS.SUCCESS
end
return REGROW_STATUS.TILE
end
local function GetPosStr(pos)
return "( " .. pos.x .. " , " .. pos.y .. " , ".. pos.z .. " )"
end
local function GetCoordStr(x,y,z)
return "( " .. x .. " , " .. y .. " , ".. z .. " )"
end
local function GetRStatusStr(status)
for k, v in pairs(REGROW_STATUS) do
if v == status then
return k
end
end
return nil
end
local function EntityDeathEventHandler(ent) local function EntityDeathEventHandler(ent)
if entity_list[ent.prefab] == nil then if entity_list[ent.prefab] == nil then
@ -57,7 +181,7 @@ return Class(function(self, inst)
ent:RemoveEventCallback("onremove", EntityDeathEventHandler, nil) ent:RemoveEventCallback("onremove", EntityDeathEventHandler, nil)
if DEBUG then if DEBUG then
print("[EventRegrowth] " .. ent.prefab .. " was removed at " .. GetPosStr(position) .. " Tile: " .. TheWorld.Map:GetTileAtPoint(position.x, position.y, position.z)) print("[ExtraRegrowth] " .. ent.prefab .. " was removed at " .. GetPosStr(position) .. " Tile: " .. TheWorld.Map:GetTileAtPoint(position.x, position.y, position.z))
end end
end end
@ -75,16 +199,16 @@ return Class(function(self, inst)
local orig_tile = inst.Map:GetTileAtPoint(position.x, position.y, position.z) local orig_tile = inst.Map:GetTileAtPoint(position.x, position.y, position.z)
local status = TestRegrowth(x,y,z, prefab, orig_tile) local status = TestRegrowth(x,y,z, prefab, orig_tile)
if status == REGROW_STATUS.STRUCT then if CACHE_RETRY[status] ~= nil then
if DEBUG then if DEBUG then
print("[EventRegrowth] Failed to spawn a product " .. product .. " at " .. GetCoordStr(x,y,z) .. " for prefab " .. prefab .. " at " .. GetPosStr(position) .. " with rand radius " .. rand_radius .. " due to " .. GetRStatusStr(status)) print("[ExtraRegrowth] Cached a " .. product .. " at " .. GetCoordStr(x,y,z) .. " for " .. prefab .. " at " .. GetPosStr(position) .. " with radius " .. rand_radius .. " due to " .. GetRStatusStr(status))
end end
return status return status
end end
if status ~= REGROW_STATUS.SUCCESS then if status ~= REGROW_STATUS.SUCCESS then
if DEBUG then if DEBUG then
print("[EventRegrowth] Cached a product " .. product .. " at ".. GetCoordStr(x,y,z) .. " for prefab " .. prefab .. " at " .. GetPosStr(position) .. " with rand radius ".. rand_radius .. " due to " .. GetRStatusStr(status)) print("[ExtraRegrowth] Failed to spawn a " .. product .. " at ".. GetCoordStr(x,y,z) .. " for " .. prefab .. " at " .. GetPosStr(position) .. " with radius ".. rand_radius .. " due to " .. GetRStatusStr(status))
end end
return status return status
end end
@ -95,7 +219,7 @@ return Class(function(self, inst)
instance:ListenForEvent("onremove", EntityDeathEventHandler, nil) instance:ListenForEvent("onremove", EntityDeathEventHandler, nil)
if DEBUG then if DEBUG then
print("[EventRegrowth] Spawned a product " .. product .. " at " .. GetCoordStr(x,y,z) .. " for prefab " .. prefab .. " at " .. GetPosStr(position) .. " with rand radius " .. rand_radius) print("[ExtraRegrowth] Spawned a " .. product .. " at " .. GetCoordStr(x,y,z) .. " for " .. prefab .. " at " .. GetPosStr(position) .. " with radius " .. rand_radius .. " tile: " .. TheWorld.Map:GetTileAtPoint(x,y,z))
end end
if DEBUG_TELE then if DEBUG_TELE then
@ -120,20 +244,23 @@ return Class(function(self, inst)
end end
end end
if DEBUG then if DEBUG then
print("[EventRegrowth] Hooked " .. count .. " " .. prefab) print("[ExtraRegrowth] Hooked " .. count .. " " .. prefab)
end end
end end
local function HookAllEntities(ents) local function HookAllRegisteredPrefabs()
local count = 0 local count = 0
local delay = 0 for guid,ent in pairs(Ents) do
for prefab in pairs(ents) do if regrowth_table[ent.prefab] ~= nil then
inst:DoTaskInTime(delay, function() HookEntities(prefab) end) ent:RemoveEventCallback("onremove", EntityDeathEventHandler, nil)
count = count + 1 ent:ListenForEvent("onremove", EntityDeathEventHandler, nil)
if math.fmod(count, THREADS_PER_BATCH_HOOK) == 0 then count = count + 1
delay = delay + 1
end end
end end
if DEBUG then
print("[ExtraRegrowth] Hooked " .. count .. " entities")
end
end end
-------------------------------------------------------------------------- --------------------------------------------------------------------------
@ -144,18 +271,23 @@ return Class(function(self, inst)
end end
function self:FinishModConfig() function self:FinishModConfig()
regrowth_table_populated_by_mod = true HookAllRegisteredPrefabs()
ready = true
end end
function self:RegisterRegrowth(prefab, product, interval) function self:RegisterRegrowth(prefab, product, interval)
if interval == nil then if interval == nil then
if DEBUG then if DEBUG then
print("[EventRegrowth] WARNING: interval for prefab " .. prefab .. " is null. Using default.") print("[ExtraRegrowth] WARNING: interval for prefab " .. prefab .. " is null. Using default.")
end end
interval = 480 interval = 480
end end
if DEBUG then
interval = interval / 100
end
if regrowth_table[prefab] == nil then if regrowth_table[prefab] == nil then
-- avoid duplicate registration -- avoid duplicate registration
regrowth_table[prefab] = regrowth_table[prefab] =
@ -164,21 +296,19 @@ return Class(function(self, inst)
interval = interval interval = interval
} }
HookEntities(prefab)
end end
if DEBUG then if DEBUG then
print("[EventRegrowth] Registered product " .. product .. " for prefab " .. prefab .. " with interval " .. interval) print("[ExtraRegrowth] Registered product " .. product .. " for prefab " .. prefab .. " with interval " .. interval)
end end
end end
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Initialization ]] --[[ Initialization ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
inst:DoTaskInTime(0, function() HookAllRegisteredPrefabs() end)
inst:DoPeriodicTask(UPDATE_PERIOD, function() self:LongUpdate(UPDATE_PERIOD) end) inst:DoPeriodicTask(UPDATE_PERIOD, function() self:LongUpdate() end)
inst:ListenForEvent("ms_cyclecomplete", function() HookAllEntities(regrowth_table) end) -- every ~ 1 day we rehook every entities inst:ListenForEvent("ms_cyclecomplete", function() HookAllRegisteredPrefabs() end) -- every ~ 1 day we rehook every entities
inst:DoTaskInTime(0, function() HookAllEntities(regrowth_table) end)
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Update ]] --[[ Update ]]
@ -195,21 +325,20 @@ return Class(function(self, inst)
data.remove = true data.remove = true
end end
if success == REGROW_STATUS.STRUCT then if CACHE_RETRY[success] == nil then
-- only increase radius when there are structures nearby -- only increase radius when not cached
data.retry = data.retry + 1 data.retry = data.retry + 1
end end
end end
function self:LongUpdate(dt) function self:LongUpdate()
if not regrowth_table_populated_by_mod then if not ready then
-- do nothing if the table is not fully initialized -- do nothing if the table is not fully initialized
-- in case we accidentally drop some saved entities due to the respawn_table[prefab] == nil check -- in case we accidentally drop some saved entities due to the respawn_table[prefab] == nil check
return return
end end
local count = 0 local count = 0
local delay = 0
for prefab in pairs(entity_list) do for prefab in pairs(entity_list) do
if entity_list[prefab] == nil or #entity_list[prefab] == 0 then if entity_list[prefab] == nil or #entity_list[prefab] == 0 then
-- only do meaningful work -- only do meaningful work
@ -222,7 +351,7 @@ return Class(function(self, inst)
if entity_list[prefab][i].remove then if entity_list[prefab][i].remove then
-- handle expired objects first -- handle expired objects first
if DEBUG then if DEBUG then
print("[EventRegrowth] Removed prefab " .. prefab .. " at ".. GetPosStr(entity_list[prefab][i].position) .." from the entity list.") print("[ExtraRegrowth] Removed prefab " .. prefab .. " at ".. GetPosStr(entity_list[prefab][i].position) .." from the entity list.")
end end
table.remove(entity_list[prefab], i) table.remove(entity_list[prefab], i)
else else
@ -235,19 +364,14 @@ return Class(function(self, inst)
end end
if DEBUG then if DEBUG then
print("[EventRegrowth] Prefab " .. prefab .. " at " .. GetPosStr(entity_list[prefab][i].position) .. " has interval " .. entity_list[prefab][i].interval ) print("[ExtraRegrowth] Prefab " .. prefab .. " at " .. GetPosStr(entity_list[prefab][i].position) .. " has interval " .. entity_list[prefab][i].interval )
end end
if entity_list[prefab][i].interval == 0 then if entity_list[prefab][i].interval == 0 then
-- different threads -- different threads
local data = entity_list[prefab][i] local data = entity_list[prefab][i]
inst:DoTaskInTime(delay, function() RegrowPrefabTask(prefab, data) end)
-- try not to flood the server with threads RegrowPrefabTask(prefab, data)
count = count + 1
if math.fmod( count,THREADS_PER_BATCH ) == 0 then
delay = delay + 1
end
end end
end end
end end
@ -283,7 +407,7 @@ return Class(function(self, inst)
} }
end end
if DEBUG then if DEBUG then
print("[EventRegrowth] Saved " .. #data.entities[prefab] .. " entities for prefab " .. prefab) print("[ExtraRegrowth] Saved " .. #data.entities[prefab] .. " entities for prefab " .. prefab)
end end
end end
end end
@ -309,7 +433,7 @@ return Class(function(self, inst)
} }
end end
if DEBUG then if DEBUG then
print("[EventRegrowth] Loaded " .. #entity_list[prefab] .. " entities for prefab " .. prefab) print("[ExtraRegrowth] Loaded " .. #entity_list[prefab] .. " entities for prefab " .. prefab)
end end
end end
end end

View File

@ -1,281 +0,0 @@
--------------------------------------------------------------------------
--[[ NaturalRegrowth class definition ]]
-- A modified version of the original desolationspawner.lua
-- It acts as a standalone regrowth manager and is independent of the 3 existing ones
-- It's unlikely affected by game updates as long as Klei doesn't change the API (they shouldn't)
-- by lolo Jan. 2018
--------------------------------------------------------------------------
return Class(function(self, inst)
assert(inst.ismastersim, "natural_regrowth should not exist on client")
require "map/terrain"
require "wrpp_util"
--------------------------------------------------------------------------
--[[ Constants ]]
--------------------------------------------------------------------------
local DEBUG = false
local DEBUG_TELE = false
local UPDATE_PERIOD = 11
local THREADS_PER_BATCH = 3
--------------------------------------------------------------------------
--[[ Member variables ]]
--------------------------------------------------------------------------
--Public
self.inst = inst
--Private
local regrowth_table = {}
local area_data = {}
local intervals = {}
local regrowth_table_populated_by_mod = false
--------------------------------------------------------------------------
--[[ Private member functions ]]
--------------------------------------------------------------------------
local function TryRegrowth(x, y, z , prefab, product)
local status = TestRegrowth(x,0,z, product, nil)
if status == REGROW_STATUS.SUCCESS then
local instance = SpawnPrefab(product)
if instance ~= nil then
instance.Transform:SetPosition(x,0,z)
end
if DEBUG then
print("[NaturalRegrowth] Spawned a product " .. product .. " at " .. GetCoordStr(x,0,z) .. " for prefab " .. prefab)
end
if DEBUG_TELE then
c_teleport(x,0,z)
end
return true
else
if DEBUG then
print("[NaturalRegrowth] Failed to spawn a product " .. product .. " at " .. GetCoordStr(x,0,z) .. " for prefab " .. prefab .. " due to " .. GetRStatusStr(status))
end
return false
end
end
local function PrintDensities()
for area, densities in pairs(inst.generated.densities) do
for k,v in pairs(densities) do
print(area, k, v)
end
end
end
local function PopulateAreaData(prefab)
if inst.generated == nil then
-- Still starting up
return
end
if area_data[prefab] ~= nil then
if DEBUG then
print("[NaturalRegrowth] Already populated prefab " .. prefab)
end
return
end
-- PrintDensities()
for area, densities in pairs(inst.generated.densities) do
if densities[prefab] ~= nil then
for id, v in ipairs(inst.topology.ids) do
if v == area then
if area_data[prefab] == nil then
area_data[prefab] = {}
end
area_data[prefab][#area_data[prefab] + 1] = id
break
end
end
end
end
if DEBUG then
print("[NaturalRegrowth] Populated " .. (area_data[prefab] == nil and 0 or #area_data[prefab]) .. " areas for prefab " .. prefab)
end
end
local function PopulateAllAreaData()
-- This has to be run after 1 frame from startup
for prefab in pairs(regrowth_table) do
PopulateAreaData(prefab)
end
end
--------------------------------------------------------------------------
--[[ Public member functions ]]
--------------------------------------------------------------------------
function self:GetUpdatePeriod()
return UPDATE_PERIOD
end
function self:FinishModConfig()
regrowth_table_populated_by_mod = true
end
function self:RegisterRegrowth(prefab, product, interval)
if interval == nil then
if DEBUG then
print("[NaturalRegrowth] WARNING: interval for prefab " .. prefab .. " is null. Using default.")
end
interval = 480
end
if DEBUG then
print("[NaturalRegrowth] Registered product " .. product .. " for prefab " .. prefab .. " with interval " .. interval)
end
regrowth_table[prefab] = {product = product, interval = interval}
if intervals[prefab] == nil then
intervals[prefab] = interval
end
PopulateAreaData(prefab)
end
--------------------------------------------------------------------------
--[[ Initialization ]]
--------------------------------------------------------------------------
inst:DoPeriodicTask(UPDATE_PERIOD, function() self:LongUpdate(UPDATE_PERIOD) end)
inst:DoTaskInTime(0, PopulateAllAreaData)
--------------------------------------------------------------------------
--[[ Update ]]
--------------------------------------------------------------------------
local function RegrowPrefabTask(areas, prefab)
local success = false
local rand = math.random(1, #areas)
local area = areas[rand]
if inst.topology.nodes[area] == nil then
return false
end
local points_x, points_y = inst.Map:GetRandomPointsForSite(inst.topology.nodes[area].x, inst.topology.nodes[area].y, inst.topology.nodes[area].poly, 1)
if #points_x < 1 or #points_y < 1 then
return false
end
success = TryRegrowth(points_x[1], 0, points_y[1], prefab, regrowth_table[prefab].product)
if success then
-- success, reset the timer
intervals[prefab] = regrowth_table[prefab] == nil and nil or regrowth_table[prefab].interval
end
end
function self:LongUpdate(dt)
if not regrowth_table_populated_by_mod then
-- do nothing if the table is not fully initialized
-- in case we accidentally drop some saved entities due to the respawn_table[prefab] == nil check
return
end
local count = 0
local delay = 0
-- area data because we only care about stuff that can naturally spawn
for prefab in pairs(area_data) do
if regrowth_table[prefab] == nil or area_data[prefab] == nil then
-- if regrowth table didn't register, or the entity doesn't have a natural density, do nothing
intervals[prefab] = nil
else
if intervals[prefab] > UPDATE_PERIOD then
intervals[prefab] = intervals[prefab] - UPDATE_PERIOD
else
intervals[prefab] = 0
end
if DEBUG then
print("[NaturalRegrowth] Prefab " .. prefab .. " has interval " .. intervals[prefab])
end
if intervals[prefab] == 0 then
local area = area_data[prefab]
-- use multiple threads? In the future a threadpool maybe?
inst:DoTaskInTime(delay, function() RegrowPrefabTask(area, prefab) end)
-- try not to flood the server with threads
count = count + 1
if math.fmod( count,THREADS_PER_BATCH ) == 0 then
delay = delay + 1
end
end
end
end
end
--------------------------------------------------------------------------
--[[ Save/Load ]]
--------------------------------------------------------------------------
function self:OnSave()
local data = {
areas = {},
intervals = {}
}
for prefab in pairs(area_data) do
data.areas[prefab] = {}
for i = 1, #area_data[prefab] do
data.areas[prefab][#data.areas[prefab] + 1] = area_data[prefab][i]
end
if DEBUG then
print("[NaturalRegrowth] Saved " .. #data.areas[prefab] .. " areas for prefab " .. prefab)
end
end
for prefab, interval in pairs(intervals) do
if interval ~= nil then
-- it can be set to nil in the event loop
data.intervals[prefab] = interval
if DEBUG then
print("[NaturalRegrowth] Saved interval " .. data.intervals[prefab] .. " for prefab " .. prefab)
end
end
end
return data
end
function self:OnLoad(data)
for prefab in pairs(data.areas) do
if area_data[prefab] == nil then
area_data[prefab] = {}
for i = 1, #data.areas[prefab] do
area_data[prefab][#area_data[prefab] + 1] = data.areas[prefab][i]
end
if DEBUG then
print("[NaturalRegrowth] Loaded " .. #area_data[prefab] .. " areas for prefab " .. prefab)
end
end
end
for prefab, interval in pairs(data.intervals) do
intervals[prefab] = interval
if DEBUG then
print("[NaturalRegrowth] Loaded interval " .. intervals[prefab] .. " for prefab " .. prefab)
end
end
end
--------------------------------------------------------------------------
--[[ End ]]
--------------------------------------------------------------------------
end)

View File

@ -1,109 +0,0 @@
EXCLUDE_TAGS =
{
"statue", -- marble stuff on the ground, ancient statues
"hive", --spiderden, wasphive, beehive
}
EXCLUDE_PREFABS =
{
catcoonden = 1,
ancient_altar = 1,
ancient_altar_broken = 1,
houndmound = 1,
mermhouse = 1,
pigtorch = 1,
mermhead = 1,
pighead = 1,
pandoraschest = 1,
minotaurchest = 1,
pighouse = 1,
rabbithouse = 1
}
BASE_RADIUS = 20
EXCLUDE_RADIUS = 2
MIN_PLAYER_DISTANCE = 40
REGROW_STATUS =
{
SUCCESS = 0,
STRUCT = 1,
CACHE = 2,
PLAYER = 3,
DENSITY = 4,
TILE = 5,
ROAD = 6
}
local function TestStructures(x, y, z, radius)
local ents = TheSim:FindEntities(x,y,z, BASE_RADIUS, nil, EXCLUDE_TAGS, { "structure", "wall" })
for i, v in ipairs(ents) do
if EXCLUDE_PREFABS[v.prefab] == nil then
-- if we cannot find it from the exclude table, then it is a structure and we failed the test
return false
end
end
return true
end
local function CanPlaceAtPoint(x, y, z)
local tile = TheWorld.Map:GetTileAtPoint(x, y, z)
return tile ~= GROUND.IMPASSABLE and
tile ~= GROUND.INVALID and
not GROUND_FLOORING[tile]
end
local function TestPlayers(x, y, z, radius)
return not IsAnyPlayerInRange(x,y,z, MIN_PLAYER_DISTANCE, nil)
end
local function TestEntities(x, y, z, radius)
local ents = TheSim:FindEntities(x,y,z, EXCLUDE_RADIUS)
return not (#ents > 0)
end
function TestRegrowth(x, y, z, prefab, tile)
if not TestPlayers(x,y,z, MIN_PLAYER_DISTANCE) then
return REGROW_STATUS.PLAYER
end
if not TestStructures(x, y, z, BASE_RADIUS) then
-- No regrowth around players and their bases
return REGROW_STATUS.STRUCT
end
if not TestEntities(x,y,z, EXCLUDE_RADIUS) then
-- Too dense
return REGROW_STATUS.DENSITY
end
if (RoadManager ~= nil) and (RoadManager:IsOnRoad(x, 0, z)) then
return REGROW_STATUS.ROAD
end
if (CanPlaceAtPoint(x, y, z) and TheWorld.Map:CanPlacePrefabFilteredAtPoint(x, y, z, prefab)) or ((tile ~= nil) and (TheWorld.Map:GetTileAtPoint(x, y, z) == tile)) then
return REGROW_STATUS.SUCCESS
end
return REGROW_STATUS.TILE
end
function GetPosStr(pos)
return "( " .. pos.x .. " , " .. pos.y .. " , ".. pos.z .. " )"
end
function GetCoordStr(x,y,z)
return "( " .. x .. " , " .. y .. " , ".. z .. " )"
end
function GetRStatusStr(status)
for k, v in pairs(REGROW_STATUS) do
if v == status then
return k
end
end
return nil
end