Beta Release.

This commit is contained in:
secXsQuared 2018-01-27 19:44:49 -05:00
parent 4f11d8b07e
commit 5959c9e84a
6 changed files with 265 additions and 121 deletions

Binary file not shown.

View File

@ -1,3 +0,0 @@
<Atlas><Texture filename="modicon.tex" />
<Elements><Element name="modicon.tex" u1="0" u2="1" v1="0" v2="1" />
</Elements></Atlas>

View File

@ -1,15 +1,103 @@
name = "Advanced World Regrowth" name = "Advanced World Regrowth"
description = "Advanced world regrowth" description = "Advanced world regrowth including caves!\nSee the Steam Workshop page for more information."
author = "lolo" author = "lolo"
version = "1.0.0" version = "0.1.0"
forumthread = "" forumthread = ""
api_version = 10 api_version = 10
icon_atlas = "modicon.xml" --icon_atlas = "modicon.xml"
icon = "modicon.tex" --icon = "modicon.tex"
all_clients_require_mod = false all_clients_require_mod = false
client_only_mod = false client_only_mod = false
dst_compatible = true dst_compatible = true
-- Configuration Generation
local config_table =
{
{"evergreen","Evergreen","Natural"},
{"deciduoustree","Birchnut Tree","Natural"},
{"marsh_tree","Spiky Tree","Natural"},
{"twiggytree","Twiggy Tree","Natural"},
{"marbletree","Marble Tree","Event-based"},
{"livingtree","Totally Normal Tree","Event-based"},
{"berrybush","Berry Bush","Natural"},
{"berrybush2","Spiky Berry Bush","Natural"},
{"berrybush_juicy","Juicy Berry Bush","Natural"},
{"carrot_planted","Carrot","Natural"},
{"flower","Flower","Natural"},
{"flower_evil","Evil Flower","Event-based"},
{"blue_mushroom","Blue Mushroom","Natural"},
{"red_mushroom","Red Mushroom","Natural"},
{"green_mushroom","Green Mushroom","Natural"},
{"cactus","Cactus","Natural"},
{"mandrake","Mandrake","Event-based"},
{"reeds","Reeds","Natural"},
{"sapling","Sapling","Natural"},
{"grass","Grass","Natural"},
{"marsh_bush","Spiky Bush","Natural"},
{"rock1","Boulder","Natural"},
{"rock2","Gold Vein","Natural"},
{"rock_flintless","Flintless Boulder","Natural"},
{"rock_moon","Moon Rock","Natural"},
{"stalagmite","Stalagmite","Natural"},
{"stalagmite_tall","Tall Stalagmite","Natural"},
{"beehive","Beehive","Event-based"},
{"wasphive","Killer Bee Hive","Event-based"},
{"houndmound","Hound Mound","Event-based"},
{"pighouse","Pig House","Event-based"},
{"mermhouse","Rundown House","Event-based"},
{"spiderden","Spider Den","Event-based"},
{"catcoonden","Hollow Stump","Event-based"},
{"rabbithouse","Rabbit Hutch","Event-based"},
{"monkeypods","Splumonkey Pod","Event-based"},
{"slurtlehole", "Slurtle Mound", "Event-based"},
{"fireflies","Fireflies","Event-based"},
{"tentacle","Tentacle","Event-based"},
{"knight","Clockwork Knight","Event-based"},
{"bishop","Clockwork Bishop","Event-based"},
{"rook","Clockwork Rook","Event-based"},
{"knight_nightmare","Damaged Knight","Event-based"},
{"bishop_nightmare","Damaged Bishop","Event-based"},
{"rook_nightmare","Damaged Rook","Event-based"},
{"ruins_statue_mage","Ancient Mage Statue","Event-based"},
{"ruins_statue_mage_nogem","Gemless Ancient Mage Statue","Event-based"},
{"ruins_statue_head","Ancient Head Statue","Event-based"},
{"ruins_statue_head_nogem", "Gemless Ancient Head Statue", "Event-based"}
}
local config_options = {}
for i = 1, #config_table do
local entry =
{
name = config_table[i][1],
label = config_table[i][2],
hover = config_table[i][3],
options =
{
{
description = "Disabled",
data = false
},
{
description = "Enabled",
data = true
}
},
default = true
}
config_options[#config_options+1] = entry
end
configuration_options = config_options

View File

@ -24,75 +24,76 @@ end
local natural = local natural =
{ {
--plants berrybush = 1451,
berrybush = 1440, berrybush2 = 1429,
berrybush2 = 1440, berrybush_juicy = 1429,
berrybush_juicy = 1440,
carrot_planted = 240, carrot_planted = 240,
evergreen = 30, evergreen = 251,
deciduoustree = 30, deciduoustree = 251,
marsh_tree = 480, marsh_tree = 480,
twiggytree = 480, twiggytree = 491,
flower = 240, flower = 229,
flower_evil = 480, grass = 229,
grass = 240, blue_mushroom = 251,
blue_mushroom = 240,
red_mushroom = 240, red_mushroom = 240,
green_mushroom = 240, green_mushroom = 240,
reeds = 480, reeds = 480,
sapling = 240, sapling = 240,
marsh_bush = 480, marsh_bush = 480,
cactus = 480, cactus = 479,
rock1 = 240, rock1 = 229,
rock2 = 240, rock2 = 240,
rock_flintless = 240, rock_flintless = 251,
marbletree=1440,
rock_moon = 480, rock_moon = 480,
stalagmite = 240, stalagmite = 489,
stalagmite_tall = 240, stalagmite_tall = 240,
} }
local event = local event =
{ {
houndbone = 960, flower_evil = 480,
pighead = 960, marbletree= 960,
marblepillar = 1440, livingtree = 969,
livingtree = 960, mandrake = 969,
mandrake = 960, beehive = 489,
beehive = 480, wasphive = 969,
wasphive = 960, houndmound = 1449,
houndmound = 1440,
pighouse = 960, pighouse = 960,
mermhouse = 960, mermhouse = 960,
spiderden = 960, spiderden = 1431,
molehill = 960, catcoonden = 951,
catcoonden = 960, tentacle = 489,
tentacle = 480, rabbithole = 471,
rabbithole = 480, fireflies = 471,
fireflies = 480, knight = 1431,
knight = 23, bishop = 1431,
bishop = 9, rook = 1449,
rook = 34, knight_nightmare = 1449,
knight_nightmare = 1440,
bishop_nightmare = 1440, bishop_nightmare = 1440,
rook_nightmare = 1440, rook_nightmare = 1440,
monkeypods = 1440, monkeypods = 951,
ruins_statue_mage = 960, ruins_statue_mage = 969,
ruins_statue_mage_nogem = 960, ruins_statue_mage_nogem = 969,
ruins_statue_head = 960, ruins_statue_head = 960,
ruins_statue_head_nogem = 960, ruins_statue_head_nogem = 951,
rabbithouse = 960 rabbithouse = 951,
slurtlehole = 951
} }
AddComponentPostInit("natural_regrowth", function(component) AddComponentPostInit("natural_regrowth", function(component)
for prefab, time in pairs(natural) do for prefab, time in pairs(natural) do
component:RegisterRegrowth(prefab, prefab, time) if GetModConfigData(prefab) then
component:RegisterRegrowth(prefab, prefab, time)
end
end end
component:FinishModConfig()
end) end)
AddComponentPostInit("event_regrowth", function(component) AddComponentPostInit("event_regrowth", function(component)
for prefab, time in pairs(event) do for prefab, time in pairs(event) do
component:RegisterRegrowth(prefab, prefab, time) if GetModConfigData(prefab) then
component:RegisterRegrowth(prefab, prefab, time)
end
end end
component:FinishModConfig() component:FinishModConfig()
end) end)

View File

@ -15,17 +15,17 @@ return Class(function(self, inst)
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Constants ]] --[[ Constants ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
local DEBUG = true local DEBUG = false
local DEBUG_TELE = false local DEBUG_TELE = false
local UPDATE_PERIOD = 11 local UPDATE_PERIOD = 9
local BASE_RADIUS = 20 local BASE_RADIUS = 20
local EXCLUDE_RADIUS = 3 local EXCLUDE_RADIUS = 3
local JITTER_RADIUS = 6 local JITTER_RADIUS = 6
local TOTAL_RADIUS = 1000 local TOTAL_RADIUS = 1000
local MIN_PLAYER_DISTANCE = 40 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 = 3
local THREADS_PER_BATCH_HOOK = 5 local THREADS_PER_BATCH_HOOK = 2
local REGROW_STATUS = { local REGROW_STATUS = {
SUCCESS = 0, SUCCESS = 0,
FAILED = 1, FAILED = 1,
@ -54,7 +54,7 @@ return Class(function(self, inst)
end end
local position = ent:GetPosition() local position = ent:GetPosition()
table.insert(entity_list[ent.prefab], {position = position, interval = regrowth_table[ent.prefab].interval}) entity_list[ent.prefab][#entity_list[ent.prefab]+1] = {position = position, interval = regrowth_table[ent.prefab].interval}
ent:RemoveEventCallback("onremove", EntityDeathEventHandler, nil) ent:RemoveEventCallback("onremove", EntityDeathEventHandler, nil)
if DEBUG then if DEBUG then
@ -63,24 +63,25 @@ return Class(function(self, inst)
end end
local function TestForRegrow(x, y, z, tile) local function TestForRegrow(x, y, z, tile)
if IsAnyPlayerInRange(x,y,z, MIN_PLAYER_DISTANCE, nil) then
return REGROW_STATUS.CACHE
end
local ents = TheSim:FindEntities(x,y,z, BASE_RADIUS, nil, nil, { "structure", "wall" }) local ents = TheSim:FindEntities(x,y,z, BASE_RADIUS, nil, nil, { "structure", "wall" })
if #ents > 0 then if #ents > 0 then
-- No regrowth around players and their bases -- No regrowth around players and their bases
return REGROW_STATUS.FAILED return REGROW_STATUS.FAILED
end end
if inst.Map:GetTileAtPoint(x, y, z) ~= tile then
-- keep things in their biome (more or less)
return REGROW_STATUS.CACHE
end
local ents = TheSim:FindEntities(x,y,z, EXCLUDE_RADIUS) local ents = TheSim:FindEntities(x,y,z, EXCLUDE_RADIUS)
if #ents > 0 then if #ents > 0 then
-- Too dense -- Too dense
return REGROW_STATUS.CACHE return REGROW_STATUS.CACHE
end end
if IsAnyPlayerInRange(x,y,z, MIN_PLAYER_DISTANCE, nil) then if inst.Map:GetTileAtPoint(x, y, z) ~= tile then
-- keep things in their biome (more or less)
return REGROW_STATUS.CACHE return REGROW_STATUS.CACHE
end end
@ -211,6 +212,7 @@ return Class(function(self, inst)
product = product, product = product,
interval = interval interval = interval
} }
HookEntities(prefab) HookEntities(prefab)
end end
@ -230,9 +232,9 @@ return Class(function(self, inst)
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Update ]] --[[ Update ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
local function RegrowPrefabTask(prefab) local function RegrowPrefabTask(prefab, position)
for i = #entity_list[prefab],1,-1 do for i = #entity_list[prefab],1,-1 do
local success = TryRegrowth(prefab, regrowth_table[prefab].product, entity_list[prefab][i].position) local success = TryRegrowth(prefab, regrowth_table[prefab].product, position)
if success then if success then
-- remove from the list if it's success or failed -- remove from the list if it's success or failed
@ -273,7 +275,7 @@ return Class(function(self, inst)
if entity_list[prefab][i].interval == 0 then if entity_list[prefab][i].interval == 0 then
-- different threads -- different threads
inst:DoTaskInTime(delay, function() RegrowPrefabTask(prefab) end) inst:DoTaskInTime(delay, function() RegrowPrefabTask(prefab, entity_list[prefab][i].position) end)
-- try not to flood the server with threads -- try not to flood the server with threads
count = count + 1 count = count + 1
@ -296,9 +298,15 @@ return Class(function(self, inst)
entities = {} entities = {}
} }
for prefab in pairs(entity_list) do for prefab in pairs(entity_list) do
data.entities[prefab] = {} if entity_list[prefab] ~= nil then
for i = 1, #entity_list[prefab] do -- could be nil (set in the event loop)
table.insert(data.entities[prefab], {interval = entity_list[prefab][i].interval, position = entity_list[prefab][i].position}) data.entities[prefab] = {}
for i = 1, #entity_list[prefab] do
data.entities[prefab][#data.entities[prefab] + 1] = {interval = entity_list[prefab][i].interval, position = entity_list[prefab][i].position}
end
if DEBUG then
print("[EventRegrowth] Saved ", #data.entities[prefab]," entities for ", prefab)
end
end end
end end
return data return data
@ -308,9 +316,12 @@ return Class(function(self, inst)
for prefab in pairs(data.entities) do for prefab in pairs(data.entities) do
if entity_list[prefab] == nil then if entity_list[prefab] == nil then
entity_list[prefab] = {} entity_list[prefab] = {}
end for i = 1, #data.entities[prefab] do
for i = 1, #data.entities[prefab] do entity_list[prefab][#entity_list[prefab] + 1] = {interval = data.entities[prefab][i].interval, position = data.entities[prefab][i].position}
table.insert(entity_list[prefab], {interval = data.entities[prefab][i].interval, position = data.entities[prefab][i].position}) end
if DEBUG then
print("[EventRegrowth] Loaded ", #entity_list[prefab]," entities for ", prefab)
end
end end
end end
end end

View File

@ -8,7 +8,7 @@
return Class(function(self, inst) return Class(function(self, inst)
assert(inst.ismastersim, "natrual_regrowth should not exist on client") assert(inst.ismastersim, "natural_regrowth should not exist on client")
require "map/terrain" require "map/terrain"
@ -17,11 +17,11 @@ return Class(function(self, inst)
-------------------------------------------------------------------------- --------------------------------------------------------------------------
local DEBUG = false local DEBUG = false
local DEBUG_TELE = false local DEBUG_TELE = false
local UPDATE_PERIOD = 9 local UPDATE_PERIOD = 11
local BASE_RADIUS = 20 local BASE_RADIUS = 20
local EXCLUDE_RADIUS = 3 local EXCLUDE_RADIUS = 3
local MIN_PLAYER_DISTANCE = 40 local MIN_PLAYER_DISTANCE = 40
local THREADS_PER_BATCH = 5 local THREADS_PER_BATCH = 3
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Member variables ]] --[[ Member variables ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
@ -33,6 +33,7 @@ return Class(function(self, inst)
local regrowth_table = {} local regrowth_table = {}
local area_data = {} local area_data = {}
local intervals = {} local intervals = {}
local regrowth_table_populated_by_mod = false
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Private member functions ]] --[[ Private member functions ]]
@ -65,18 +66,7 @@ return Class(function(self, inst)
return true return true
end end
local function TryRegrowth(area, prefab, product) local function TryRegrowth(x, y, z , prefab, product)
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
local x = points_x[1]
local z = points_y[1]
if CanRegrow(x,0,z, product) then if CanRegrow(x,0,z, product) then
local instance = SpawnPrefab(product) local instance = SpawnPrefab(product)
@ -85,7 +75,7 @@ return Class(function(self, inst)
end end
if DEBUG then if DEBUG then
print("[NaturalRegrowth] Spawned a ",product," for prefab ",prefab," at ", "(", x,0,z, ")", " in ", area) print("[NaturalRegrowth] Spawned a ",product," for prefab ",prefab," at ", "(", x,0,z, ")")
end end
if DEBUG_TELE then if DEBUG_TELE then
@ -95,7 +85,7 @@ return Class(function(self, inst)
return true return true
else else
if DEBUG then if DEBUG then
print("[NaturalRegrowth] Failed to spawn a ",product," for prefab ",prefab," at ", "(", x,0,z, ")", " in ", area) print("[NaturalRegrowth] Failed to spawn a ",product," for prefab ",prefab," at ", "(", x,0,z, ")")
end end
return false return false
end end
@ -111,12 +101,18 @@ return Class(function(self, inst)
local function PopulateAreaData(prefab) local function PopulateAreaData(prefab)
if inst.generated == nil then if inst.generated == nil then
-- Still starting up, not ready yet. -- Still starting up
return
end
if area_data[prefab] ~= nil then
if DEBUG then
print("[NaturalRegrowth] Already populated ", prefab)
end
return return
end end
-- PrintDensities() -- PrintDensities()
for area, densities in pairs(inst.generated.densities) do for area, densities in pairs(inst.generated.densities) do
if densities[prefab] ~= nil then if densities[prefab] ~= nil then
for id, v in ipairs(inst.topology.ids) do for id, v in ipairs(inst.topology.ids) do
@ -125,7 +121,7 @@ return Class(function(self, inst)
area_data[prefab] = {} area_data[prefab] = {}
end end
table.insert(area_data[prefab], id) area_data[prefab][#area_data[prefab] + 1] = id
break break
end end
end end
@ -147,6 +143,10 @@ return Class(function(self, inst)
-------------------------------------------------------------------------- --------------------------------------------------------------------------
--[[ Public member functions ]] --[[ Public member functions ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
function self:FinishModConfig()
regrowth_table_populated_by_mod = true
end
function self:RegisterRegrowth(prefab, product, interval) function self:RegisterRegrowth(prefab, product, interval)
if DEBUG then if DEBUG then
@ -173,9 +173,32 @@ return Class(function(self, inst)
--[[ Update ]] --[[ Update ]]
-------------------------------------------------------------------------- --------------------------------------------------------------------------
-- duplicate of event_regrowth
local function GetRandomLocation(x, y, z, radius)
local theta = math.random() * 2 * PI
local radius = math.random() * radius
local x = x + radius * math.cos(theta)
local z = z - radius * math.sin(theta)
return x,y,z
end
local function RegrowPrefabTask(areas, prefab) local function RegrowPrefabTask(areas, prefab)
local success = false
local rand = math.random(1, #areas) local rand = math.random(1, #areas)
local success = TryRegrowth(areas[rand], prefab, regrowth_table[prefab].product) 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 if success then
-- success, reset the timer -- success, reset the timer
intervals[prefab] = regrowth_table[prefab] == nil and nil or regrowth_table[prefab].interval intervals[prefab] = regrowth_table[prefab] == nil and nil or regrowth_table[prefab].interval
@ -183,35 +206,42 @@ return Class(function(self, inst)
end end
function self:LongUpdate(dt) 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 count = 0
local delay = 0 local delay = 0
-- area data because we only care about stuff that can naturally spawn
for prefab in pairs(area_data) do for prefab in pairs(area_data) do
local areas = area_data[prefab] 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
if regrowth_table[prefab] == nil then intervals[prefab] = nil
area_data[prefab] = nil
intervals[prefab] = nil
else
if intervals[prefab] > UPDATE_PERIOD then
intervals[prefab] = intervals[prefab] - UPDATE_PERIOD
else else
intervals[prefab] = 0 if intervals[prefab] > UPDATE_PERIOD then
end intervals[prefab] = intervals[prefab] - UPDATE_PERIOD
else
if DEBUG then intervals[prefab] = 0
print("[NaturalRegrowth]", prefab, " has interval ", intervals[prefab]) end
end
if DEBUG then
print("[NaturalRegrowth]", prefab, " has interval ", intervals[prefab])
end
if intervals[prefab] == 0 then if intervals[prefab] == 0 then
-- use multiple threads? In the future a threadpool maybe? -- use multiple threads? In the future a threadpool maybe?
inst:DoTaskInTime(delay, function() RegrowPrefabTask(areas,prefab) end) inst:DoTaskInTime(delay, function() RegrowPrefabTask(area_data[prefab], prefab) end)
-- try not to flood the server with threads -- try not to flood the server with threads
count = count + 1 count = count + 1
if math.fmod( count,THREADS_PER_BATCH ) == 0 then if math.fmod( count,THREADS_PER_BATCH ) == 0 then
delay = delay + 1 delay = delay + 1
end
end end
end end
end
end end
end end
@ -228,27 +258,44 @@ return Class(function(self, inst)
data.areas[prefab] = {} data.areas[prefab] = {}
for i = 1, #area_data[prefab] do for i = 1, #area_data[prefab] do
table.insert(data.areas[prefab], area_data[prefab][i]) data.areas[prefab][#data.areas[prefab] + 1] = area_data[prefab][i]
end
if DEBUG then
print("[NaturalRegrowth] Saved ", #data.areas[prefab]," areas for ", prefab)
end end
end end
for prefab, interval in pairs(intervals) do for prefab, interval in pairs(intervals) do
data.intervals[prefab] = interval 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)
end
end
end end
return data return data
end end
function self:OnLoad(data) function self:OnLoad(data)
for prefab in pairs(data.areas) do for prefab in pairs(data.areas) do
if area_data[prefab] == nil then if area_data[prefab] == nil then
area_data[prefab] = {} area_data[prefab] = {}
end for i = 1, #data.areas[prefab] do
for i = 1, #data.areas[prefab] do area_data[prefab][#area_data[prefab] + 1] = data.areas[prefab][i]
table.insert(area_data[prefab], data.areas[prefab][i]) end
if DEBUG then
print("[NaturalRegrowth] Loaded", #area_data[prefab]," areas for ", prefab)
end
end end
end end
for prefab, interval in pairs(data.intervals) do for prefab, interval in pairs(data.intervals) do
intervals[prefab] = interval intervals[prefab] = interval
if DEBUG then
print("[NaturalRegrowth] Loaded interval ", intervals[prefab]," for ", prefab)
end
end end
end end