Added interval for each entity. Optimized event regrowth algorithem and structure check.
This commit is contained in:
parent
165648c40a
commit
4f11d8b07e
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 secXsQuared
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,7 +1,7 @@
|
||||
name = "World Regrowth Ex"
|
||||
name = "Advanced World Regrowth"
|
||||
description = "Advanced world regrowth"
|
||||
author = "lolo"
|
||||
version = "0.0.1"
|
||||
version = "1.0.0"
|
||||
|
||||
forumthread = ""
|
||||
|
||||
|
86
modmain.lua
86
modmain.lua
@ -1,11 +1,19 @@
|
||||
if GLOBAL.STRINGS.NAMES.MIGRATION_PORTAL then
|
||||
AddPrefabPostInit("world", function(inst)
|
||||
-- we have caves
|
||||
AddPrefabPostInit("forest", function(inst)
|
||||
if inst.ismastersim then
|
||||
inst:AddComponent("natural_regrowth")
|
||||
inst:AddComponent("event_regrowth")
|
||||
end
|
||||
end)
|
||||
AddPrefabPostInit("cave", function(inst)
|
||||
if inst.ismastersim then
|
||||
inst:AddComponent("natural_regrowth")
|
||||
inst:AddComponent("event_regrowth")
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- only overworld
|
||||
AddPrefabPostInit("world", function(inst)
|
||||
if inst.ismastersim then
|
||||
inst:AddComponent("natural_regrowth")
|
||||
@ -14,18 +22,80 @@ else
|
||||
end)
|
||||
end
|
||||
|
||||
local natural =
|
||||
{
|
||||
--plants
|
||||
berrybush = 1440,
|
||||
berrybush2 = 1440,
|
||||
berrybush_juicy = 1440,
|
||||
carrot_planted = 240,
|
||||
evergreen = 30,
|
||||
deciduoustree = 30,
|
||||
marsh_tree = 480,
|
||||
twiggytree = 480,
|
||||
flower = 240,
|
||||
flower_evil = 480,
|
||||
grass = 240,
|
||||
blue_mushroom = 240,
|
||||
red_mushroom = 240,
|
||||
green_mushroom = 240,
|
||||
reeds = 480,
|
||||
sapling = 240,
|
||||
marsh_bush = 480,
|
||||
cactus = 480,
|
||||
rock1 = 240,
|
||||
rock2 = 240,
|
||||
rock_flintless = 240,
|
||||
marbletree=1440,
|
||||
rock_moon = 480,
|
||||
stalagmite = 240,
|
||||
stalagmite_tall = 240,
|
||||
}
|
||||
|
||||
local event =
|
||||
{
|
||||
houndbone = 960,
|
||||
pighead = 960,
|
||||
marblepillar = 1440,
|
||||
livingtree = 960,
|
||||
mandrake = 960,
|
||||
beehive = 480,
|
||||
wasphive = 960,
|
||||
houndmound = 1440,
|
||||
pighouse = 960,
|
||||
mermhouse = 960,
|
||||
spiderden = 960,
|
||||
molehill = 960,
|
||||
catcoonden = 960,
|
||||
tentacle = 480,
|
||||
rabbithole = 480,
|
||||
fireflies = 480,
|
||||
knight = 23,
|
||||
bishop = 9,
|
||||
rook = 34,
|
||||
knight_nightmare = 1440,
|
||||
bishop_nightmare = 1440,
|
||||
rook_nightmare = 1440,
|
||||
monkeypods = 1440,
|
||||
ruins_statue_mage = 960,
|
||||
ruins_statue_mage_nogem = 960,
|
||||
ruins_statue_head = 960,
|
||||
ruins_statue_head_nogem = 960,
|
||||
rabbithouse = 960
|
||||
}
|
||||
|
||||
AddComponentPostInit("natural_regrowth", function(component)
|
||||
component:RegisterRegrowth("evergreen", "evergreen")
|
||||
for prefab, time in pairs(natural) do
|
||||
component:RegisterRegrowth(prefab, prefab, time)
|
||||
end
|
||||
end)
|
||||
|
||||
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")
|
||||
for prefab, time in pairs(event) do
|
||||
component:RegisterRegrowth(prefab, prefab, time)
|
||||
end
|
||||
component:FinishModConfig()
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
--"forest" for the overworld
|
||||
|
@ -1,25 +1,36 @@
|
||||
--------------------------------------------------------------------------
|
||||
--[[ EventRegrowth class definition ]]
|
||||
-- A modified version of the original regrowthmanager.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(TheWorld.ismastersim, "event_regrowth should not exist on client")
|
||||
|
||||
assert(inst.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 DEBUG_TELE = false
|
||||
|
||||
local UPDATE_PERIOD = 11
|
||||
local BASE_RADIUS = 20
|
||||
local EXCLUDE_RADIUS = 2
|
||||
local JITTER_RADIUS = 10
|
||||
local MIN_PLAYER_DISTANCE = 40 -- this is our "outer" sleep radius
|
||||
local EXCLUDE_RADIUS = 3
|
||||
local JITTER_RADIUS = 6
|
||||
local TOTAL_RADIUS = 1000
|
||||
local MIN_PLAYER_DISTANCE = 40
|
||||
local THREADS_PER_BATCH = 5 -- since we retry a lot, we reduce the # of threads to guarantee performance
|
||||
local THREADS_PER_BATCH_HOOK = 5
|
||||
local REGROW_STATUS = {
|
||||
SUCCESS = 0,
|
||||
FAILED = 1,
|
||||
CACHE = 2,
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Member variables ]]
|
||||
@ -43,83 +54,145 @@ return Class(function(self, inst)
|
||||
end
|
||||
local position = ent:GetPosition()
|
||||
|
||||
table.insert(entity_list[ent.prefab], position)
|
||||
table.insert(entity_list[ent.prefab], {position = position, interval = regrowth_table[ent.prefab].interval})
|
||||
ent:RemoveEventCallback("onremove", EntityDeathEventHandler, nil)
|
||||
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Entity of type ", ent.prefab, " was removed at ", position)
|
||||
print("[EventRegrowth] ", ent.prefab, " was removed at ", position)
|
||||
end
|
||||
end
|
||||
|
||||
local function TestForRegrow(x, y, z, tile)
|
||||
if TheWorld.Map:GetTileAtPoint(x, y, z) ~= tile then
|
||||
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 REGROW_STATUS.FAILED
|
||||
end
|
||||
|
||||
if inst.Map:GetTileAtPoint(x, y, z) ~= tile then
|
||||
-- keep things in their biome (more or less)
|
||||
return false
|
||||
return REGROW_STATUS.CACHE
|
||||
end
|
||||
|
||||
local ents = TheSim:FindEntities(x,y,z, EXCLUDE_RADIUS)
|
||||
if #ents > 0 then
|
||||
-- Too dense
|
||||
return false
|
||||
return REGROW_STATUS.CACHE
|
||||
end
|
||||
|
||||
if IsAnyPlayerInRange(x,y,z, MIN_PLAYER_DISTANCE, nil) then
|
||||
return REGROW_STATUS.CACHE
|
||||
end
|
||||
|
||||
return REGROW_STATUS.SUCCESS
|
||||
end
|
||||
|
||||
-- duplicate of canregrow in natural regrowth
|
||||
local function CanRegrow(x, y, z, prefab)
|
||||
|
||||
if IsAnyPlayerInRange(x,y,z, MIN_PLAYER_DISTANCE, nil) then
|
||||
return false
|
||||
end
|
||||
|
||||
local ents = TheSim:FindEntities(x,y,z, EXCLUDE_RADIUS)
|
||||
if #ents > 0 then
|
||||
-- Too dense
|
||||
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
|
||||
-- Don't spawn inside bases
|
||||
return false
|
||||
end
|
||||
|
||||
if not (inst.Map:CanPlantAtPoint(x, y, z) and
|
||||
inst.Map:CanPlacePrefabFilteredAtPoint(x, y, z, prefab))
|
||||
or (RoadManager ~= nil and RoadManager:IsOnRoad(x, 0, z)) then
|
||||
-- Not ground we can grow on
|
||||
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 function GetRandomLocation(x, y, z, radius)
|
||||
local theta = math.random() * 2 * PI
|
||||
local radius = math.random() * JITTER_RADIUS
|
||||
local radius = math.random() * 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
|
||||
return x,y,z
|
||||
end
|
||||
|
||||
local function HookAllEntities()
|
||||
local function TryRegrowth(prefab, product, position)
|
||||
local x,y,z = GetRandomLocation(position.x,position.y,position.z,JITTER_RADIUS)
|
||||
local orig_tile = inst.Map:GetTileAtPoint(x,y,z)
|
||||
local status = TestForRegrow(x,y,z, orig_tile)
|
||||
|
||||
if status == REGROW_STATUS.CACHE then
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Cached a ",product," for prefab ",prefab," at ", x, ",", y,",",z)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
if status == REGROW_STATUS.FAILED then
|
||||
-- for the failed case, we want to try spawning at a random location
|
||||
x,y,z = GetRandomLocation(position.x,position.y,position.z,TOTAL_RADIUS)
|
||||
|
||||
if not CanRegrow(x,y,z, product) then
|
||||
-- if cannot regrow, return CACHE status
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Failed to spawn a ",product," for prefab ",prefab," at ", x, ",", y,",",z)
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
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, ",", y,",",z)
|
||||
end
|
||||
|
||||
if DEBUG_TELE then
|
||||
c_teleport(x,0,z)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function HookEntities(prefab)
|
||||
while next(Ents) == nil do
|
||||
end
|
||||
|
||||
local count = 0
|
||||
for k, v in pairs(Ents) do
|
||||
if regrowth_table[v.prefab] ~= nil then
|
||||
if v.prefab == prefab then
|
||||
v:RemoveEventCallback("onremove", EntityDeathEventHandler, nil)
|
||||
v:ListenForEvent("onremove", EntityDeathEventHandler, nil)
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Hooked ", count, " entities.")
|
||||
print("[EventRegrowth] Hooked ", count, " ",prefab)
|
||||
end
|
||||
end
|
||||
|
||||
local function HookAllEntities(ents)
|
||||
local count = 0
|
||||
local delay = 0
|
||||
for prefab in pairs(ents) do
|
||||
inst:DoTaskInTime(delay, function() HookEntities(prefab) end)
|
||||
count = count + 1
|
||||
if math.fmod(count, THREADS_PER_BATCH_HOOK) == 0 then
|
||||
delay = delay + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -130,11 +203,15 @@ return Class(function(self, inst)
|
||||
regrowth_table_populated_by_mod = true
|
||||
end
|
||||
|
||||
function self:RegisterRegrowth(prefab, product)
|
||||
function self:RegisterRegrowth(prefab, product, interval)
|
||||
if regrowth_table[prefab] == nil then
|
||||
-- avoid duplicate registration
|
||||
regrowth_table[prefab] = product
|
||||
HookAllEntities()
|
||||
regrowth_table[prefab] =
|
||||
{
|
||||
product = product,
|
||||
interval = interval
|
||||
}
|
||||
HookEntities(prefab)
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
@ -147,12 +224,23 @@ return Class(function(self, inst)
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
inst:DoPeriodicTask(UPDATE_PERIOD, function() self:LongUpdate(UPDATE_PERIOD) end)
|
||||
inst:ListenForEvent("ms_cyclecomplete", function() HookAllEntities(regrowth_table) end) -- every ~ 1 day we rehook every entities
|
||||
inst:DoTaskInTime(0, function() HookAllEntities(regrowth_table) end)
|
||||
|
||||
inst:DoPeriodicTask(99, HookAllEntities, 0)
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Update ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local function RegrowPrefabTask(prefab)
|
||||
for i = #entity_list[prefab],1,-1 do
|
||||
local success = TryRegrowth(prefab, regrowth_table[prefab].product, entity_list[prefab][i].position)
|
||||
|
||||
if success then
|
||||
-- remove from the list if it's success or failed
|
||||
table.remove(entity_list[prefab], i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function self:LongUpdate(dt)
|
||||
if not regrowth_table_populated_by_mod then
|
||||
-- do nothing if the table is not fully initialized
|
||||
@ -160,40 +248,39 @@ return Class(function(self, inst)
|
||||
return
|
||||
end
|
||||
|
||||
local count = 0
|
||||
local delay = 0
|
||||
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
|
||||
for i = 1, #entity_list[prefab] do
|
||||
-- decrease the interval
|
||||
if entity_list[prefab][i].interval > UPDATE_PERIOD then
|
||||
entity_list[prefab][i].interval = entity_list[prefab][i].interval - UPDATE_PERIOD
|
||||
else
|
||||
-- else set to 0 and regen
|
||||
entity_list[prefab][i].interval = 0
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
print("[EventRegrowth] Spawning at location", entity_list[prefab][i])
|
||||
print("[EventRegrowth]", prefab, " at ", entity_list[prefab][i].position, " has interval ", entity_list[prefab][i].interval )
|
||||
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
|
||||
|
||||
if entity_list[prefab][i].interval == 0 then
|
||||
-- different threads
|
||||
inst:DoTaskInTime(delay, function() RegrowPrefabTask(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
|
||||
|
||||
if DEBUG and attempts == RETRY_PER_PREFAB then
|
||||
print("[EventRegrowth] Failed after ", attempts, " attempts.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -205,11 +292,27 @@ return Class(function(self, inst)
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
function self:OnSave()
|
||||
|
||||
local data = {
|
||||
entities = {}
|
||||
}
|
||||
for prefab in pairs(entity_list) do
|
||||
data.entities[prefab] = {}
|
||||
for i = 1, #entity_list[prefab] do
|
||||
table.insert(data.entities[prefab], {interval = entity_list[prefab][i].interval, position = entity_list[prefab][i].position})
|
||||
end
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
function self:OnLoad(data)
|
||||
|
||||
for prefab in pairs(data.entities) do
|
||||
if entity_list[prefab] == nil then
|
||||
entity_list[prefab] = {}
|
||||
end
|
||||
for i = 1, #data.entities[prefab] do
|
||||
table.insert(entity_list[prefab], {interval = data.entities[prefab][i].interval, position = data.entities[prefab][i].position})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
@ -3,27 +3,25 @@
|
||||
-- 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)
|
||||
-- Klei has copyright over existing code used in this file.
|
||||
-- by lolo Jan. 2018.
|
||||
-- by lolo Jan. 2018
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
return Class(function(self, inst)
|
||||
|
||||
assert(TheWorld.ismastersim, "natrual_regrowth should not exist on client")
|
||||
assert(inst.ismastersim, "natrual_regrowth should not exist on client")
|
||||
|
||||
require "map/terrain"
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Constants ]]
|
||||
--------------------------------------------------------------------------
|
||||
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 UPDATE_PERIOD = 9
|
||||
local BASE_RADIUS = 20
|
||||
local EXCLUDE_RADIUS = 2
|
||||
local MIN_PLAYER_DISTANCE = 40 -- this is our "outer" sleep radius
|
||||
|
||||
local EXCLUDE_RADIUS = 3
|
||||
local MIN_PLAYER_DISTANCE = 40
|
||||
local THREADS_PER_BATCH = 5
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Member variables ]]
|
||||
--------------------------------------------------------------------------
|
||||
@ -34,6 +32,7 @@ return Class(function(self, inst)
|
||||
--Private
|
||||
local regrowth_table = {}
|
||||
local area_data = {}
|
||||
local intervals = {}
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Private member functions ]]
|
||||
@ -57,8 +56,8 @@ return Class(function(self, inst)
|
||||
return false
|
||||
end
|
||||
|
||||
if not (TheWorld.Map:CanPlantAtPoint(x, y, z) and
|
||||
TheWorld.Map:CanPlacePrefabFilteredAtPoint(x, y, z, prefab))
|
||||
if not (inst.Map:CanPlantAtPoint(x, y, z) and
|
||||
inst.Map:CanPlacePrefabFilteredAtPoint(x, y, z, prefab))
|
||||
or (RoadManager ~= nil and RoadManager:IsOnRoad(x, 0, z)) then
|
||||
-- Not ground we can grow on
|
||||
return false
|
||||
@ -67,13 +66,13 @@ return Class(function(self, inst)
|
||||
end
|
||||
|
||||
local function TryRegrowth(area, prefab, product)
|
||||
if TheWorld.topology.nodes[area] == nil then
|
||||
if inst.topology.nodes[area] == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local points_x, points_y = TheWorld.Map:GetRandomPointsForSite(TheWorld.topology.nodes[area].x, TheWorld.topology.nodes[area].y, TheWorld.topology.nodes[area].poly, 1)
|
||||
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
|
||||
return false
|
||||
end
|
||||
local x = points_x[1]
|
||||
local z = points_y[1]
|
||||
@ -95,20 +94,32 @@ return Class(function(self, inst)
|
||||
|
||||
return true
|
||||
else
|
||||
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth] Failed to spawn a ",product," for prefab ",prefab," at ", "(", x,0,z, ")", " in ", area)
|
||||
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 TheWorld.generated == nil then
|
||||
if inst.generated == nil then
|
||||
-- Still starting up, not ready yet.
|
||||
return
|
||||
end
|
||||
|
||||
for area, densities in pairs(TheWorld.generated.densities) do
|
||||
-- PrintDensities()
|
||||
|
||||
for area, densities in pairs(inst.generated.densities) do
|
||||
if densities[prefab] ~= nil then
|
||||
for id, v in ipairs(TheWorld.topology.ids) do
|
||||
for id, v in ipairs(inst.topology.ids) do
|
||||
if v == area then
|
||||
if area_data[prefab] == nil then
|
||||
area_data[prefab] = {}
|
||||
@ -120,11 +131,15 @@ return Class(function(self, inst)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth] Populated ", area_data[prefab] == nil and 0 or #area_data[prefab], " areas for ", prefab)
|
||||
end
|
||||
end
|
||||
|
||||
local function PopulateAllAreaData()
|
||||
-- This has to be run after 1 frame from startup
|
||||
for prefab, _ in pairs(regrowth_table) do
|
||||
for prefab in pairs(regrowth_table) do
|
||||
PopulateAreaData(prefab)
|
||||
end
|
||||
end
|
||||
@ -133,11 +148,16 @@ return Class(function(self, inst)
|
||||
--[[ Public member functions ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
function self:RegisterRegrowth(prefab, product)
|
||||
function self:RegisterRegrowth(prefab, product, interval)
|
||||
if DEBUG then
|
||||
print("Registered ", product, " for prefab " ,prefab )
|
||||
print("[NaturalRegrowth] Registered ", product, " for prefab " ,prefab )
|
||||
end
|
||||
regrowth_table[prefab] = product
|
||||
regrowth_table[prefab] = {product = product, interval = interval}
|
||||
|
||||
if intervals[prefab] == nil then
|
||||
intervals[prefab] = interval
|
||||
end
|
||||
|
||||
PopulateAreaData(prefab)
|
||||
end
|
||||
|
||||
@ -152,39 +172,44 @@ return Class(function(self, inst)
|
||||
--------------------------------------------------------------------------
|
||||
--[[ Update ]]
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local function RegrowPrefabTask(areas, prefab)
|
||||
local rand = math.random(1, #areas)
|
||||
local success = TryRegrowth(areas[rand], 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)
|
||||
local count = 0
|
||||
local delay = 0
|
||||
for prefab in pairs(area_data) do
|
||||
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth] Regrowing ", prefab, "...")
|
||||
end
|
||||
|
||||
local areas = area_data[prefab]
|
||||
|
||||
if regrowth_table[prefab] == nil then
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth] Discarded")
|
||||
end
|
||||
area_data[prefab] = nil
|
||||
intervals[prefab] = nil
|
||||
else
|
||||
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 success then
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth] Succeeded after ", attempts, " attempts.")
|
||||
end
|
||||
break
|
||||
end
|
||||
if intervals[prefab] > UPDATE_PERIOD then
|
||||
intervals[prefab] = intervals[prefab] - UPDATE_PERIOD
|
||||
else
|
||||
intervals[prefab] = 0
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
print("[NaturalRegrowth]", prefab, " has interval ", intervals[prefab])
|
||||
end
|
||||
|
||||
if DEBUG and attempts == RETRY_PER_PREFAB then
|
||||
print("[NaturalRegrowth] Failed after ", attempts, " attempts.")
|
||||
if intervals[prefab] == 0 then
|
||||
-- use multiple threads? In the future a threadpool maybe?
|
||||
inst:DoTaskInTime(delay, function() RegrowPrefabTask(areas,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
|
||||
@ -196,25 +221,34 @@ return Class(function(self, inst)
|
||||
|
||||
function self:OnSave()
|
||||
local data = {
|
||||
areas = {}
|
||||
areas = {},
|
||||
intervals = {}
|
||||
}
|
||||
for prefab in pairs(area_data) do
|
||||
data.areas[prefab] = {}
|
||||
for area in pairs(area_data[prefab]) do
|
||||
table.insert(data.areas[prefab], area)
|
||||
|
||||
for i = 1, #area_data[prefab] do
|
||||
table.insert(data.areas[prefab], area_data[prefab][i])
|
||||
end
|
||||
end
|
||||
for prefab, interval in pairs(intervals) do
|
||||
data.intervals[prefab] = interval
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
function self:OnLoad(data)
|
||||
for prefab in pairs(data.areas) do
|
||||
for area in pairs(data.areas) do
|
||||
if area_data[prefab] == nil then
|
||||
area_data[prefab] = {}
|
||||
end
|
||||
table.insert(area_data[prefab], area)
|
||||
if area_data[prefab] == nil then
|
||||
area_data[prefab] = {}
|
||||
end
|
||||
for i = 1, #data.areas[prefab] do
|
||||
table.insert(area_data[prefab], data.areas[prefab][i])
|
||||
end
|
||||
end
|
||||
|
||||
for prefab, interval in pairs(data.intervals) do
|
||||
intervals[prefab] = interval
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user