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

AI simple factory behavior #5508

Merged
merged 7 commits into from
Oct 10, 2023
Merged

Conversation

Garanas
Copy link
Member

@Garanas Garanas commented Oct 6, 2023

Introduces an alternative to the complicated infrastructure surrounding AI factory behavior. The current infrastructure involves factory templates, platoon templates and other abstractions that require a lot of manual work. Too much manual work in my opinion.

The new system is relatively easy yet very powerful. It entirely relies on the use of EntityCategoryGetUnitList in combination with builders and builder groups. We'll start with a basic builder of the new format:

DefaultDirectFire = AIBuilderTemplate {
    BuilderManager = 'FactoryManager',
    BuilderName = 'Easy AI - Direct fire units',
    BuilderConditions = {},
    BuilderType = 'LAND',
    BuilderData = {                             
        Categories = categories.DIRECTFIRE - categories.ANTIAIR, 
    },

    BuilderPriority = 200,
}

The builder type and builder conditions work as previous builders do. The builder name purely exists for debugging purposes. The builder data consists of just one field: the categories that you'd like to factory to try and build if it is assigned the builder.

Those categories are combined with the categories that the factory can build. This is passed into EntityCategoryGetUnitList, which returns a list of blueprint IDs. These are the units that the factory can build and that meet the requirements of the builder template. The factory then proceeds to build one at random.

-------------------------------------------------------------------
-- determine what to build through the factory manager

local builder = self.Base.FactoryManager:GetHighestBuilder(self, units[1], self.BuilderType)

if builder then
    local candidates = EntityCategoryGetUnitList(builder.BuilderData.Categories * self.BuildableCategories)
    if candidates and table.getn(candidates) > 0 then
        local candidate = table.random(candidates)
        IssueBuildFactory(units, candidate, 1)

        self:ChangeState(self.Building)
        return
    end
end

This has several advantages:

  • There's one place where the logic is defined: inside the builder template
  • -> This includes faction-specific builders
  • The logic as to what a factory ends up doing with a builder is simple and elegant
  • The solution has complete support for mods, as long as those mods have sane categories set to units

In future pull requests we'll create various additional builders to make the behavior of the factory a little more intelligent 😃

@Garanas Garanas added the area: AI related to AI functions label Oct 6, 2023
@Garanas Garanas added this to the Development iteration IV milestone Oct 6, 2023
@Garanas Garanas requested a review from relent0r October 6, 2023 13:54
@Garanas
Copy link
Member Author

Garanas commented Oct 6, 2023

There's an interesting problem: support factories! How do we properly determine (in the sim) what a support factory can actually build in practice? In the UI we'd use something like GetUnitCommandData, but in the sim there is no equivalent I think

@Garanas
Copy link
Member Author

Garanas commented Oct 6, 2023

And support factories are supported. The platoon that you're checking the build condition is now send to all build conditions. With that we can:

DefaultDirectFireTech2 = AIBuilderTemplate {
    BuilderManager = 'FactoryManager',
    BuilderName = 'Easy AI - Direct fire units',
    BuilderConditions = {
        { FactoryManagerConditions.ResearchedTech2 }
    },
    BuilderType = 'LAND',
    BuilderData = {
        Categories = categories.TECH2 * (categories.DIRECTFIRE - categories.ANTIAIR),
    },

    BuilderPriority = 210,
}

Which then references:

---@param aiBrain AIBrain
---@param base AIBase
---@param platoon AIPlatoon
function ResearchedTech2 (aiBrain, base, platoon)
    local unit = platoon:GetPlatoonUnits()[1]
    local blueprint = unit.Blueprint
    return (aiBrain:CountHQs(blueprint.FactionCategory, blueprint.LayerCategory, 'TECH2') + aiBrain:CountHQs(blueprint.FactionCategory, blueprint.LayerCategory, 'TECH3')) > 0
end

And there we go 😃 , it works even across factions!

@Garanas
Copy link
Member Author

Garanas commented Oct 6, 2023

@relent0r the easiest way to test this is by cheating in factories and a paragon. The builders are entirely unaware of the economy at this moment, of course. These are just the very basic builders

@relent0r
Copy link
Contributor

relent0r commented Oct 9, 2023

Initial testing (using your default builders) looks amazing. Like almost magic. I'm going to be testing custom builders over the coming weeks with conditions.

Any thoughts on what eco manager integration might look like? Looks like you could have some great integration with these.
e.g a particular builder could have eco manager integration enabled/disabled and possibly a completion percentage cutoff to decide if a factory will just wait for completion and not assign anymore builders or pause the current builder.

Will be a little slow to get this review completed as I need to focus on getting the state machines running cleanly before the next release.

@Garanas
Copy link
Member Author

Garanas commented Oct 10, 2023

Any thoughts on what eco manager integration might look like? Looks like you could have some great integration with these.
e.g a particular builder could have eco manager integration enabled/disabled and possibly a completion percentage cutoff to decide if a factory will just wait for completion and not assign anymore builders or pause the current builder.

Yes, this would either be done through the factory state machine or by a thread that runs in the base or aibrain. Instead of not producing units (e.g., no conditions satisfy) I'd rather pause / unpause factories accordingly. It is a lot more efficient and gives us a lot more (read: army-wide) control over how many resources we're actually spending on factories producing units

@Garanas
Copy link
Member Author

Garanas commented Oct 10, 2023

@relent0r I'm merging this in to prevent future conflicts

@Garanas Garanas merged commit 014846f into deploy/fafdevelop Oct 10, 2023
1 check passed
@Garanas Garanas deleted the ai/simple-factory-behavior branch October 10, 2023 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: AI related to AI functions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants