Almost done with event regrowth.
Have to think about how to monitor player planted entities such as grass from tufts since the source code only pushes the onremove event for renewable resources. TODO: - implmenet event regrowth load/save - implement event regrowth CACHE/FAIL/SUCCESS states - currently the mod rehooks all entities every 3 seconds to mitigate the issue above but it eats performance. Maybe do it once per day? or simply don't care? - refactor natural regrowth's array iteration.
This commit is contained in:
parent
a3463e6c1f
commit
165648c40a
13
modmain.lua
13
modmain.lua
@ -2,22 +2,29 @@ if GLOBAL.STRINGS.NAMES.MIGRATION_PORTAL then
|
||||
AddPrefabPostInit("world", function(inst)
|
||||
if inst.ismastersim then
|
||||
inst:AddComponent("natural_regrowth")
|
||||
inst:AddComponent("event_regrowth")
|
||||
end
|
||||
end)
|
||||
else
|
||||
AddPrefabPostInit("forest", function(inst)
|
||||
AddPrefabPostInit("world", function(inst)
|
||||
if inst.ismastersim then
|
||||
inst:AddComponent("natural_regrowth")
|
||||
inst:AddComponent("event_regrowth")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
AddComponentPostInit("natural_regrowth", function(component)
|
||||
component:RegisterRegrowth("grass", "grass")
|
||||
component:RegisterRegrowth("evergreen", "evergreen")
|
||||
end)
|
||||
|
||||
AddComponentPostInit("natural_regrowth", function(component)
|
||||
AddComponentPostInit("event_regrowth", function(component)
|
||||
component:RegisterRegrowth("knight", "knight")
|
||||
component:RegisterRegrowth("evergreen", "evergreen")
|
||||
component:RegisterRegrowth("grass", "grass")
|
||||
component:RegisterRegrowth("rock1", "rock1")
|
||||
component:RegisterRegrowth("rock2", "rock2")
|
||||
component:FinishModConfig()
|
||||
end)
|
||||
|
||||
|
||||
|
220
scripts/components/event_regrowth.lua
Normal file
220
scripts/components/event_regrowth.lua
Normal file
@ -0,0 +1,220 @@
|
||||
--------------------------------------------------------------------------
|
||||
--[[ EventRegrowth class definition ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
return Class(function(self, inst)
|
||||
|
||||
assert(TheWorld.ismastersim, "event_regrowth should not exist on client")
|
||||
|
||||
require "map/terrain"
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Constants ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local DEBUG = true
|
||||
local DEBUG_TELE = true
|
||||
local RETRY_PER_PREFAB = 10 -- retry 5 times for each prefab
|
||||
local UPDATE_PERIOD = 3 -- less likely to update on the same frame as others
|
||||
local BASE_RADIUS = 20
|
||||
local EXCLUDE_RADIUS = 2
|
||||
local JITTER_RADIUS = 10
|
||||
local MIN_PLAYER_DISTANCE = 40 -- this is our "outer" sleep radius
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Member variables ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
--Public
|
||||
self.inst = inst
|
||||
|
||||
--Private
|
||||
local regrowth_table_populated_by_mod = false
|
||||
local regrowth_table = {}
|
||||
local entity_list = {}
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Private member functions ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local function EntityDeathEventHandler(ent)
|
||||
if entity_list[ent.prefab] == nil then
|
||||
entity_list[ent.prefab] = {}
|
||||
end
|
||||
local position = ent:GetPosition()
|
||||
|
||||
table.insert(entity_list[ent.prefab], position)
|
||||
ent:RemoveEventCallback("onremove", EntityDeathEventHandler, nil)
|
||||
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Entity of type ", ent.prefab, " was removed at ", position)
|
||||
end
|
||||
end
|
||||
|
||||
local function TestForRegrow(x, y, z, tile)
|
||||
if TheWorld.Map:GetTileAtPoint(x, y, z) ~= tile then
|
||||
-- keep things in their biome (more or less)
|
||||
return false
|
||||
end
|
||||
|
||||
local ents = TheSim:FindEntities(x,y,z, EXCLUDE_RADIUS)
|
||||
if #ents > 0 then
|
||||
-- Too dense
|
||||
return false
|
||||
end
|
||||
|
||||
if IsAnyPlayerInRange(x,y,z, MIN_PLAYER_DISTANCE, nil) then
|
||||
return false
|
||||
end
|
||||
|
||||
local ents = TheSim:FindEntities(x,y,z, BASE_RADIUS, nil, nil, { "structure", "wall" })
|
||||
if #ents > 0 then
|
||||
-- No regrowth around players and their bases
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function TryRegrowth(prefab, product, position)
|
||||
local x = position.x
|
||||
local y = position.y
|
||||
local z = position.z
|
||||
|
||||
local orig_tile = TheWorld.Map:GetTileAtPoint(x,y,z)
|
||||
|
||||
local theta = math.random() * 2 * PI
|
||||
local radius = math.random() * JITTER_RADIUS
|
||||
local x = x + radius * math.cos(theta)
|
||||
local z = z - radius * math.sin(theta)
|
||||
|
||||
if TestForRegrow(x,y,z, orig_tile) then
|
||||
local instance = SpawnPrefab(product)
|
||||
if instance ~= nil then
|
||||
instance.Transform:SetPosition(x,y,z)
|
||||
instance:ListenForEvent("onremove", EntityDeathEventHandler, nil)
|
||||
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Spawned a ",product," for prefab ",prefab," at ", "(", x,0,z, ")")
|
||||
end
|
||||
|
||||
if DEBUG_TELE then
|
||||
c_teleport(x,0,z)
|
||||
end
|
||||
end
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function HookAllEntities()
|
||||
while next(Ents) == nil do
|
||||
end
|
||||
local count = 0
|
||||
for k, v in pairs(Ents) do
|
||||
if regrowth_table[v.prefab] ~= nil then
|
||||
v:RemoveEventCallback("onremove", EntityDeathEventHandler, nil)
|
||||
v:ListenForEvent("onremove", EntityDeathEventHandler, nil)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Hooked ", count, " entities.")
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Public member functions ]]
|
||||
--------------------------------------------------------------------------
|
||||
function self:FinishModConfig()
|
||||
regrowth_table_populated_by_mod = true
|
||||
end
|
||||
|
||||
function self:RegisterRegrowth(prefab, product)
|
||||
if regrowth_table[prefab] == nil then
|
||||
-- avoid duplicate registration
|
||||
regrowth_table[prefab] = product
|
||||
HookAllEntities()
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Registered ", product ," for ", prefab)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Initialization ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
inst:DoPeriodicTask(UPDATE_PERIOD, function() self:LongUpdate(UPDATE_PERIOD) end)
|
||||
|
||||
inst:DoPeriodicTask(99, HookAllEntities, 0)
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Update ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
for prefab in pairs(entity_list) do
|
||||
if entity_list[prefab] == nil or #entity_list[prefab] == 0 then
|
||||
-- only do meaningful work
|
||||
else
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Regrowing ", prefab, "...")
|
||||
end
|
||||
if regrowth_table[prefab] == nil then
|
||||
-- if we don't have it registered, discard
|
||||
entity_list[prefab] = nil
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Discarded")
|
||||
end
|
||||
else
|
||||
for i = #entity_list[prefab],1,-1 do
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Spawning at location", entity_list[prefab][i])
|
||||
end
|
||||
local attempts = 0
|
||||
while attempts < RETRY_PER_PREFAB do
|
||||
local success = TryRegrowth(prefab, regrowth_table[prefab], entity_list[prefab][i])
|
||||
attempts = attempts + 1
|
||||
|
||||
if success then
|
||||
print("[EventRegrowth] Succeeded after ", attempts, " attempts.")
|
||||
-- we respawned this guy, remove from the list
|
||||
table.remove(entity_list[prefab], i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if DEBUG and attempts == RETRY_PER_PREFAB then
|
||||
print("[EventRegrowth] Failed after ", attempts, " attempts.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Save/Load ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
function self:OnSave()
|
||||
|
||||
end
|
||||
|
||||
function self:OnLoad(data)
|
||||
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ End ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
end)
|
||||
|
@ -1,7 +1,7 @@
|
||||
--------------------------------------------------------------------------
|
||||
--[[ NaturalRegrowth class definition ]]
|
||||
-- A modified version of the original desolationspawner.lua
|
||||
-- It acts as a standalone regrowth manager and is in dependent 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)
|
||||
-- Klei has copyright over existing code used in this file.
|
||||
-- by lolo Jan. 2018.
|
||||
@ -16,12 +16,13 @@ return Class(function(self, inst)
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Constants ]]
|
||||
--------------------------------------------------------------------------
|
||||
local RETRY_PER_PREFAB = 5 -- retry 5 times for each prefab
|
||||
local DEBUG = true
|
||||
local RETRY_PER_PREFAB = 10 -- retry 5 times for each prefab
|
||||
local DEBUG = false
|
||||
local DEBUG_TELE = false
|
||||
local UPDATE_PERIOD = 31 -- less likely to update on the same frame as others
|
||||
local BASE_RADIUS = 20
|
||||
local EXCLUDE_RADIUS = 3
|
||||
local MIN_PLAYER_DISTANCE = 64 * 1.2 -- this is our "outer" sleep radius
|
||||
local EXCLUDE_RADIUS = 2
|
||||
local MIN_PLAYER_DISTANCE = 40 -- this is our "outer" sleep radius
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Member variables ]]
|
||||
@ -85,7 +86,10 @@ return Class(function(self, inst)
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
print("[RegrowthEx] Spawned a ",product," for prefab ",prefab," at ", "(", x,0,z, ")", " in ", area)
|
||||
print("[NaturalRegrowth] Spawned a ",product," for prefab ",prefab," at ", "(", x,0,z, ")", " in ", area)
|
||||
end
|
||||
|
||||
if DEBUG_TELE then
|
||||
c_teleport(x,0,z)
|
||||
end
|
||||
|
||||
@ -153,27 +157,36 @@ return Class(function(self, inst)
|
||||
for prefab in pairs(area_data) do
|
||||
|
||||
if DEBUG then
|
||||
print("[RegrowthEx] Regrowing ", prefab, "...")
|
||||
print("[NaturalRegrowth] Regrowing ", prefab, "...")
|
||||
end
|
||||
|
||||
local areas = area_data[prefab]
|
||||
local rand = math.random(1, #areas)
|
||||
local attempts = 0
|
||||
|
||||
while attempts < RETRY_PER_PREFAB do
|
||||
local success = TryRegrowth(areas[rand], prefab, regrowth_table[prefab])
|
||||
attempts = attempts + 1
|
||||
if regrowth_table[prefab] == nil then
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth] Discarded")
|
||||
end
|
||||
area_data[prefab] = nil
|
||||
else
|
||||
local rand = math.random(1, #areas)
|
||||
local attempts = 0
|
||||
|
||||
if success then
|
||||
print("[RegrowthEx] Succeeded after ", attempts, " attempts.")
|
||||
break
|
||||
while attempts < RETRY_PER_PREFAB do
|
||||
local success = TryRegrowth(areas[rand], prefab, regrowth_table[prefab])
|
||||
attempts = attempts + 1
|
||||
|
||||
if success then
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth] Succeeded after ", attempts, " attempts.")
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if DEBUG and attempts == RETRY_PER_PREFAB then
|
||||
print("[NaturalRegrowth] Failed after ", attempts, " attempts.")
|
||||
end
|
||||
end
|
||||
|
||||
if DEBUG and attempts == RETRY_PER_PREFAB then
|
||||
print("[RegrowthEx] Failed after ", attempts, " attempts.")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user