Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-implementation of the AI - Part 2 #5750

Merged
merged 3 commits into from
Dec 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 97 additions & 117 deletions lua/aibrains/easy-ai.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ local StandardBrain = import("/lua/aibrain.lua").AIBrain
local EconomyComponent = import("/lua/aibrains/components/economy.lua").AIBrainEconomyComponent
local BaseManager = import("/lua/aibrains/managers/base-manager.lua")

local SimpleEnergyTasks = import("/lua/aibrains/tasks/brain/simple-energy.lua")

---@class EasyAIBrainBaseTemplates
---@field BaseTemplateMain AIBaseTemplate

Expand All @@ -30,7 +32,7 @@ local BaseManager = import("/lua/aibrains/managers/base-manager.lua")
---@field GridReclaim AIGridReclaim
---@field GridBrain AIGridBrain
---@field GridRecon AIGridRecon
---@field BuilderManagers table<LocationType, AIBase>
---@field BaseManagers AIBase[]
AIBrain = Class(StandardBrain, EconomyComponent) {

SkirmishSystems = true,
Expand All @@ -42,17 +44,15 @@ AIBrain = Class(StandardBrain, EconomyComponent) {
StandardBrain.OnCreateAI(self, planName)
EconomyComponent.OnCreateAI(self)

self:OnLoadTemplates()


-- start initial base
local startX, startZ = self:GetArmyStartPos()
local main = BaseManager.CreateBaseManager(self, 'main', { startX, 0, startZ }, 60)
main:AddBaseTemplate(self.AIBaseTemplates.BaseTemplateMain)
self.BuilderManagers = {
MAIN = main
self.BaseManagers = {
BaseManager.CreateBaseManager(self, { 0, 10} )
}

self.BaseManagers[1]:AddBrainTask(SimpleEnergyTasks.EnergyTech1)
self.BaseManagers[1]:AddBrainTask(SimpleEnergyTasks.EnergyTech1)
self.BaseManagers[1]:AddBrainTask(SimpleEnergyTasks.EnergyTech1)
self.BaseManagers[1]:AddBrainTask(SimpleEnergyTasks.EnergyTech1)

self:ForkThread(self.GetBaseDebugInfoThread)
self:IMAPConfiguration()
end,
Expand All @@ -77,33 +77,9 @@ AIBrain = Class(StandardBrain, EconomyComponent) {
self.GridPresence = import("/lua/AI/GridPresence.lua").Setup(self)
end,

---@param self EasyAIBrain
OnLoadTemplates = function(self)
self.AIBaseTemplates = self.AIBaseTemplates or { }

-- copy over templates from various files
local templates
templates = import("/lua/aibrains/templates/base/easy-main.lua")
for k, template in templates do
self.AIBaseTemplates[k] = template
end
end,

---@param self EasyAIBrain
OnDestroy = function(self)
StandardBrain.OnDestroy(self)

if self.BuilderManagers then
for _, v in self.BuilderManagers do

v.EngineerManager:SetEnabled(false)
v.FactoryManager:SetEnabled(false)
v.PlatoonFormManager:SetEnabled(false)
v.FactoryManager:Destroy()
v.PlatoonFormManager:Destroy()
v.EngineerManager:Destroy()
end
end
end,

---@param self EasyAIBrain
Expand All @@ -116,14 +92,6 @@ AIBrain = Class(StandardBrain, EconomyComponent) {
self.GridRecon:OnIntelChange(position[1], position[3], reconType, val)
end,

---@param self EasyAIBrain
---@param position Vector
---@param radius number
---@param baseName LocationType
AddBaseManagers = function(self, baseName, position, radius)
self.BuilderManagers[baseName] = BaseManager.CreateBaseManager(self, baseName, position, radius)
end,

IMAPConfiguration = function(self)
-- Used to configure imap values, used for setting threat ring sizes depending on map size to try and get a somewhat decent radius
local maxmapdimension = math.max(ScenarioInfo.size[1], ScenarioInfo.size[2])
Expand Down Expand Up @@ -160,32 +128,71 @@ AIBrain = Class(StandardBrain, EconomyComponent) {
--- Retrieves the nearest base for the given position
---@param self EasyAIBrain
---@param position Vector
---@return LocationType
FindNearestBaseIdentifier = function(self, position)
local ux, _, uz = position[1], nil, position[3]
local nearestManagerIdentifier = nil
local nearestDistance = nil
for id, managers in self.BuilderManagers do
if nearestManagerIdentifier then
local location = managers.Position
local dx, dz = location[1] - ux, location[3] - uz
local distance = dx * dx + dz * dz
if distance < nearestDistance then
nearestDistance = distance

nearestManagerIdentifier = id
end
else
local location = managers.Position
local dx, dz = location[1] - ux, location[3] - uz
nearestDistance = dx * dx + dz * dz
nearestManagerIdentifier = id
---@return AIBase
FindNearestBase = function(self, position)
return self.BaseManagers[1]
end,

---------------------------------------------------------------------------
--#region Brain evaluation

--- Delay in is game ticks
EvaluateDelay = 11,

---@param self EasyAIBrain
EvaluateBrainThread = function(self)
while true do
-- evaluate the Brain in a protected call to guarantee we can keep evaluating it in the future
local ok, msg = pcall(self.EvaluateBrain, self)
if not ok then
WARN(msg)
end

local evaluateDelay = self.EvaluateDelay
if evaluateDelay < 0 then
evaluateDelay = 1
end

WaitTicks(evaluateDelay)
end
end,

---@param self EasyAIBrain
EvaluateStructureTasks = function(self)
local brain = self.Brain
local structureTasks = self.StructureTasks

for k = 1, table.getn(structureTasks) do
local structureTask = structureTasks[k]

-- todo: evaluate if we still need this task
end
end,


---@param self EasyAIBrain
EvaluateBrain = function(self)
local brain = self.Brain

local engineeringTasks = self.EngineeringTasks
local factoryTasks = self.FactoryTasks


self:EvaluateStructureTasks()

for k = 1, table.getn(engineeringTasks) do
local engineeringTask = engineeringTasks[k]
end

for k = 1, table.getn(factoryTasks) do
local factoryTask = factoryTasks[k]
end


return nearestManagerIdentifier
end,

--#region

---------------------------------------------------------------------------
--#region C hooks

Expand Down Expand Up @@ -220,15 +227,8 @@ AIBrain = Class(StandardBrain, EconomyComponent) {
---@param builder Unit
---@param layer Layer
OnUnitStartBeingBuilt = function(self, unit, builder, layer)
-- find nearest base
local nearestBaseIdentifier = builder.AIBaseManager or self:FindNearestBaseIdentifier(unit:GetPosition())
unit.AIBaseManager = nearestBaseIdentifier

-- register unit at managers of base
local baseManager = self.BuilderManagers[nearestBaseIdentifier]
if baseManager then
baseManager:OnUnitStartBeingBuilt(unit, builder, layer)
end
local nearestBase = self:FindNearestBase(unit:GetPosition())
nearestBase:OnUnitStartBeingBuilt(unit, builder, layer)
end,

--- Called by a unit as it is finished being built
Expand All @@ -237,63 +237,43 @@ AIBrain = Class(StandardBrain, EconomyComponent) {
---@param builder Unit
---@param layer Layer
OnUnitStopBeingBuilt = function(self, unit, builder, layer)
local baseIdentifier = unit.AIBaseManager
if not baseIdentifier then
baseIdentifier = self:FindNearestBaseIdentifier(unit:GetPosition())
unit.AIBaseManager = baseIdentifier
end

local managers = self.BuilderManagers[baseIdentifier]
if managers then
managers:OnUnitStopBeingBuilt(unit, builder, layer)
local nearestBase = self:FindNearestBase(unit:GetPosition())
nearestBase:OnUnitStopBeingBuilt(unit, builder, layer)

if EntityCategoryContains(categories.ENGINEER * categories.TECH1, unit) then
local platoon = self:MakePlatoon('', '')
platoon.Base = nearestBase
platoon.Brain = self
setmetatable(platoon, import("/lua/aibrains/platoons/platoon-simple-engineer.lua").AIPlatoonEngineerSimple)
self:AssignUnitsToPlatoon(platoon, {unit}, 'Support', 'GrowthFormation')
ChangeState(platoon, platoon.Start)
end
end,

--- Called by a unit as it is destroyed
---@param self EasyAIBrain
---@param unit Unit
OnUnitDestroyed = function(self, unit)
local baseIdentifier = unit.AIBaseManager
if not baseIdentifier then
return
end

local managers = self.BuilderManagers[baseIdentifier]
if managers then
managers:OnUnitDestroyed(unit)
end
local nearestBase = self:FindNearestBase(unit:GetPosition())
nearestBase:OnUnitDestroyed(unit)
end,

--- Called by a unit as it starts building
---@param self EasyAIBrain
---@param unit Unit
---@param built Unit
OnUnitStartBuilding = function(self, unit, built)
local baseIdentifier = unit.AIBaseManager
if not baseIdentifier then
return
end

local managers = self.BuilderManagers[baseIdentifier]
if managers then
managers:OnUnitStartBuilding(unit, built)
end
local nearestBase = self:FindNearestBase(unit:GetPosition())
nearestBase:OnUnitStartBuilding(unit, built)
end,

--- Called by a unit as it stops building
---@param self EasyAIBrain
---@param unit Unit
---@param built Unit
OnUnitStopBuilding = function(self, unit, built)
local baseIdentifier = unit.AIBaseManager
if not baseIdentifier then
return
end

local managers = self.BuilderManagers[baseIdentifier]
if managers then
managers:OnUnitStopBuilding(unit, built)
end
local nearestBase = self:FindNearestBase(unit:GetPosition())
nearestBase:OnUnitStopBuilding(unit, built)
end,

--#endregion
Expand All @@ -305,15 +285,15 @@ AIBrain = Class(StandardBrain, EconomyComponent) {
---@return AIBaseDebugInfo
GetBaseDebugInfoThread = function(self)
while true do
if GetFocusArmy() == self:GetArmyIndex() then
local position = GetMouseWorldPos()
local identifier = self:FindNearestBaseIdentifier(position)
if identifier then
local base = self.BuilderManagers[identifier]
local info = base:GetDebugInfo()
Sync.AIBaseInfo = info
end
end
-- if GetFocusArmy() == self:GetArmyIndex() then
-- local position = GetMouseWorldPos()
-- local identifier = self:FindNearestBase(position)
-- if identifier then
-- local base = self.BuilderManagers[identifier]
-- local info = base:GetDebugInfo()
-- Sync.AIBaseInfo = info
-- end
-- end

WaitTicks(10)
end
Expand Down
2 changes: 1 addition & 1 deletion lua/aibrains/index.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ keyToBrain = {
tech = { "/lua/aibrains/tech-ai.lua", "AIBrain" },
turtle = { "/lua/aibrains/turtle-ai.lua", "AIBrain" },
rush = { "/lua/aibrains/rush-ai.lua", "AIBrain" },
easy = { "/lua/aibrains/medium-ai.lua", "AIBrain" },
easy = { "/lua/aibrains/easy-ai.lua", "AIBrain" },
medium = { "/lua/aibrains/medium-ai.lua", "AIBrain" },
adaptive = { "/lua/aibrains/adaptive-ai.lua", "AIBrain" },
random = { "/lua/aibrains/adaptive-ai.lua", "AIBrain" },
Expand Down
Loading
Loading