Skip to content

Commit

Permalink
Finalize basic implementation of a structure manager (FAForever#4970)
Browse files Browse the repository at this point in the history
* Initial draft of structure manager

* Finalize draft for basic ai structure behavior

* Upgrade builders for extractors are working

* Finalize basic structure manager
  • Loading branch information
Garanas authored May 26, 2023
1 parent 6c351fe commit 86e5482
Show file tree
Hide file tree
Showing 19 changed files with 383 additions and 354 deletions.
2 changes: 1 addition & 1 deletion lua/SimCallbacks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -864,5 +864,5 @@ Callbacks.GridPresenceDebugDisable = import("/lua/ai/gridpresence.lua").DisableD
Callbacks.AIBrainEconomyDebugEnable = import("/lua/aibrains/components/economy.lua").EnableDebugging
Callbacks.AIBrainEconomyDebugDisable = import("/lua/aibrains/components/economy.lua").DisableDebugging

Callbacks.AIPlatoonSiloTacticalBehavior = import("/lua/aibrains/platoons/platoon-silo.lua").DebugAssignToUnits
Callbacks.AIPlatoonSimpleRaidBehavior = import("/lua/aibrains/platoons/platoon-simple-raid.lua").DebugAssignToUnits
Callbacks.AIPlatoonSimpleStructureBehavior = import("/lua/aibrains/platoons/platoon-simple-structure.lua").DebugAssignToUnits
2 changes: 1 addition & 1 deletion lua/aibrains/managers/base-manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ AIBase = ClassSimple {
---@param manager AIBuilderManager
AddBuilderGroup = function(self, builderGroupTemplate, manager)
if Debug then
SPEW("Loading builder group template: " .. builderGroupTemplate.BuilderGroupName)
SPEW("Loading builder group template: " .. builderGroupTemplate.BuilderGroupName .. " for " .. manager.ManagerName)
end

local builderTemplates = builderGroupTemplate.BuilderTemplates
Expand Down
33 changes: 29 additions & 4 deletions lua/aibrains/managers/builder-manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ end
---@field Trash TrashBag # Trashbag of this manager
AIBuilderManager = ClassSimple {

ManagerName = "BuilderManager",

---@param self AIBuilderManager
---@param brain AIBrain
Create = function(self, brain, base, locationType)
Expand Down Expand Up @@ -113,16 +115,20 @@ AIBuilderManager = ClassSimple {

--- Retrieves the highest builder that is valid with the given parameters
---@param self AIBuilderManager
---@param builderType BuilderType
---@param platoon AIPlatoon
---@param unit Unit
---@return AIBuilder?
GetHighestBuilder = function(self, builderType, platoon, unit)
local builderData = self.BuilderData[builderType]
GetHighestBuilder = function(self, platoon, unit, unitType)
local builderData = self.BuilderData[unitType]
if not builderData then
error('*BUILDERMANAGER ERROR: Invalid builder type - ' .. builderType)
return nil
end

-- used to quickly reject builders
local unitTech = unit.Blueprint.TechCategory
local unitLayer = unit.Blueprint.LayerCategory
local unitFaction = unit.Blueprint.FactionCategory

local tick = GetGameTick()
local brain = self.Brain
local base = self.Base
Expand All @@ -134,6 +140,25 @@ AIBuilderManager = ClassSimple {
local builders = builderData.Builders
for k in builders do
local builder = builders[k] --[[@as AIBuilder]]
local builderTemplate = builder.Template

-- check tech requirement
local builderTech = builderTemplate.BuilderTech
if builderTech and builderTech != unitTech then
continue
end

-- check layer requirement
local builderLayer = builderTemplate.BuilderLayer
if builderLayer and builderLayer != unitLayer then
continue
end

-- check faction requirement
local builderFaction = builderTemplate.BuilderFaction
if builderFaction and builderFaction != unitFaction then
continue
end

-- builders with no priority are ignored
local priority = builder.Priority
Expand Down
27 changes: 3 additions & 24 deletions lua/aibrains/managers/engineer-manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
--****************************************************************************

local AIBuilderManager = import("/lua/aibrains/managers/builder-manager.lua").AIBuilderManager
local AIPlatoonEngineer = import("/lua/aibrains/platoons/platoon-engineer.lua").AIPlatoonEngineer
-- local AIPlatoonEngineer = import("/lua/aibrains/platoons/platoon-engineer.lua").AIPlatoonEngineer

local TableGetSize = table.getsize

Expand Down Expand Up @@ -34,6 +34,8 @@ local WeakValues = { __mode = 'v' }
---@field EngineerCount AIEngineerManagerCount # Recomputed every 10 ticks
AIEngineerManager = Class(AIBuilderManager) {

ManagerName = "EngineerManager",

---@param self AIEngineerManager
---@param brain AIBrain
---@param base AIBase
Expand Down Expand Up @@ -258,29 +260,6 @@ AIEngineerManager = Class(AIBuilderManager) {
--------------------------------------------------------------------------------------------
-- engineer manager interface

---@param self AIEngineerManager
---@param unit Unit
AssignPlatoon = function(self, unit)
-- switch any existing behavior to the blank state
local aiPlatoon = unit.AIPlatoonReference
if aiPlatoon then
aiPlatoon:ChangeState('Blank')
end

-- create the platoon, switch metatables and assign the unit
local platoon = self.Brain:MakePlatoon('Engineer platoon', '') --[[@as AIPlatoonEngineer]]
setmetatable(platoon, AIPlatoonEngineer)
self.Brain:AssignUnitsToPlatoon(platoon, {unit}, 'support', 'none')
unit.AIPlatoonReference = platoon

-- assign assets required for this platoon
platoon.Brain = self.Brain
platoon.Base = self.Base

-- enable the build behavior
platoon:ChangeState('AIBehaviorBuild')
end,

---@param self AIEngineerManager
---@param platoon AIPlatoonEngineer
---@param unit Unit
Expand Down
2 changes: 2 additions & 0 deletions lua/aibrains/managers/factory-manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ local MapFactionCategory = {
---@field FactoryBeingBuiltCount AIFactoryManagerCounts # Recomputed every 10 ticks
AIFactoryManager = Class(BuilderManager) {

ManagerName = "FactoryManager",

---@param self AIFactoryManager
---@param brain AIBrain
---@param base AIBase
Expand Down
74 changes: 15 additions & 59 deletions lua/aibrains/managers/structure-manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ local WeakValues = { __mode = 'v' }
---@field StructureBeingBuiltCount AIStructureManagerCounts # Recomputed every 10 ticks
AIStructureManager = Class(BuilderManager) {

ManagerName = "StructureManager",

---@param self AIStructureManager
---@param brain AIBrain
---@param base AIBase
Expand Down Expand Up @@ -80,7 +82,7 @@ AIStructureManager = Class(BuilderManager) {
engineerCount[tech] = count
total = total + count
end

local StructureBeingBuilt = self.StructuresBeingBuilt
local StructureBeingBuiltCount = self.StructureBeingBuiltCount
for tech, _ in StructureBeingBuiltCount do
Expand All @@ -96,10 +98,6 @@ AIStructureManager = Class(BuilderManager) {
-- unit events

--- Called by a unit as it starts being built
---
--- `Time complexity: O(1)`
---
--- `Memory complexity: O(1)`
---@param self AIStructureManager
---@param unit Unit
---@param builder Unit
Expand All @@ -110,20 +108,10 @@ AIStructureManager = Class(BuilderManager) {
local tech = blueprint.TechCategory
local id = unit.EntityId
self.StructuresBeingBuilt[tech][id] = unit

-- used by platoon functions to find the manager
local builderManagerData = unit.BuilderManagerData or { }
unit.BuilderManagerData = builderManagerData
builderManagerData.StructureManager = self
builderManagerData.LocationType = self.LocationType
end
end,

--- Called by a unit as it is finished being built
---
--- `Time complexity: O(1)`
---
--- `Memory complexity: O(1)`
---@param self AIStructureManager
---@param unit Unit
---@param builder Unit
Expand All @@ -136,19 +124,19 @@ AIStructureManager = Class(BuilderManager) {
self.StructuresBeingBuilt[tech][id] = nil
self.Structures[tech][id] = unit

-- used by platoon functions to find the manager
local builderManagerData = unit.BuilderManagerData or { }
unit.BuilderManagerData = builderManagerData
builderManagerData.StructureManager = self
builderManagerData.LocationType = self.LocationType
-- create the platoon and start the behavior
local brain = self.Brain
local platoon = brain:MakePlatoon('', '') --[[@as AIPlatoonSimpleStructure]]
platoon.Brain = self.Brain
platoon.Base = self.Base

setmetatable(platoon, import("/lua/aibrains/platoons/platoon-simple-structure.lua").AIPlatoonSimpleStructure)
brain:AssignUnitsToPlatoon(platoon, {unit}, 'Unassigned', 'None')
ChangeState(platoon, platoon.Start)
end
end,

--- Called by a unit as it is destroyed
---
--- `Time complexity: O(1)`
---
--- `Memory complexity: O(1)`
---@param self AIStructureManager
---@param unit Unit
OnUnitDestroyed = function(self, unit)
Expand All @@ -166,62 +154,30 @@ AIStructureManager = Class(BuilderManager) {
---@param unit Unit
---@param built Unit
OnUnitStartBuilding = function(self, unit, built)
local blueprint = unit.Blueprint
if blueprint.CategoriesHash['STRUCTURE'] then
end
end,

--- Called by a unit as it stops building
---@param self BuilderManager
---@param unit Unit
---@param built Unit
OnUnitStopBuilding = function(self, unit, built)
local blueprint = unit.Blueprint
if blueprint.CategoriesHash['STRUCTURE'] then
end
end,

--------------------------------------------------------------------------------------------
-- unit interface

--- Add a unit to, similar to calling `OnUnitStopBeingBuilt`
---
--- `Time complexity: O(1)`
---
--- `Memory complexity: O(1)`
--- Add a unit, similar to calling `OnUnitStopBeingBuilt`
---@param self AIStructureManager
---@param unit Unit
AddUnit = function(self, unit)
local blueprint = unit.Blueprint
if blueprint.CategoriesHash['STRUCTURE'] then
local tech = blueprint.TechCategory
local id = unit.EntityId
self.StructuresBeingBuilt[tech][id] = nil
self.Structures[tech][id] = unit

-- used by platoon functions to find the manager
local builderManagerData = unit.BuilderManagerData or { }
unit.BuilderManagerData = builderManagerData
builderManagerData.StructureManager = self
builderManagerData.LocationType = self.LocationType
end
self:OnUnitStopBeingBuilt(unit, nil, unit.Layer)
end,

--- Remove a unit, similar to calling `OnUnitDestroyed`
---
--- `Complexity: O(1)`
---
--- `Memory complexity: O(1)`
---@param self AIStructureManager
---@param unit Unit
RemoveUnit = function(self, unit)
local blueprint = unit.Blueprint
if blueprint.CategoriesHash['STRUCTURE'] then
local tech = blueprint.TechCategory
local id = unit.EntityId
self.StructuresBeingBuilt[tech][id] = nil
self.Structures[tech][id] = nil
end
self:OnUnitDestroyed(unit)
end,
}

Expand Down
Loading

0 comments on commit 86e5482

Please sign in to comment.