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

Add helper methods to locate actors that can be reached via a path. #20227

Merged
merged 2 commits into from Sep 7, 2023

Conversation

RoosterDragon
Copy link
Member

@RoosterDragon RoosterDragon commented Aug 27, 2022

Fixes AI trying to attack units they can't reach, and other automated behaviours will now only consider reachable locations, e.g. if rearming. Fixes #17753

Test scenario:

Start a map with an AI on an island and park some naval units near to their base. Deploy a barracks onto their island but far away from their base and build some units.

On bleed: When the AI creates a squad from the land units it will try and attack the nearest units - the naval units.
This PR: The squad will attack the nearest reachable units - the barracks. The closer naval units are ignored because the land units can't move to them.


Previously, the ClosestTo and PositionClosestTo existed to perform a simple distance based check to choose the closest location from a choice of locations to a single other location. For some functions this is sufficient, but for many functions we want to then move between the locations. If the location selected is in fact unreachable (e.g. on another island) then we would not want to consider it.

We now introduce ClosestToIgnoringPath for checks where we don't care about a path existing, e.g. weapons hitting nearby targets. When we do care about paths, we introduce ClosestToWithPathFrom and ClosestToWithPathTo which will check that a path exists. The PathFrom check will make sure one of the actors from the list can make it to the single target location. The PathTo check will make sure the single actor can make it to one of the target locations. This difference allows us to specify which actor will be doing the moving. This is important as a path might exists for one actor, but not another. Consider two islands with a hovercraft on one and a tank on the other. The hovercraft can path to the tank, but the tank cannot path to the hovercraft.

We also introduce WithPathFrom and WithPathTo. These will perform filtering by checking for valid paths, but won't select the closest location.

By employing the new methods that filter for paths, we fix various behaviour that would cause actors to get confused. Imagine an islands map, by checking for paths we ensure logic will locate reachable locations on the island, rather than considering a location on a nearby island that is physically closer but unreachable. This fixes AI squad automation, and other automated behaviours such as rearming.

@pchote pchote added this to the Next release milestone Aug 27, 2022
Copy link
Member

@PunkPun PunkPun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise code LGTM

I've ran a large AI game and noticed some bugs, I'm not sure if they are regressions

Boat can't group
Screenshot 2022-08-28 at 22 44 07

boats try to attack an out of range target
Screenshot 2022-08-28 at 22 47 28

Artilleries unable to attack move
Screenshot 2022-08-28 at 22 48 09

submarines try to move towards visible ground enemy units
Screenshot 2022-08-28 at 22 55 22

OpenRA.Mods.Common/WorldExtensions.cs Outdated Show resolved Hide resolved
OpenRA.Mods.Common/WorldExtensions.cs Outdated Show resolved Hide resolved
@PunkPun
Copy link
Member

PunkPun commented Aug 29, 2022

note: in my testing everything went perfectly, I just listed the few exceptions I noticed

@RoosterDragon
Copy link
Member Author

Hmm - the fact boats will move to attack land at all is actually suspect. That should be prevented by the new checks.

That also reveals a wider issues - we might want things like boats to get close to land to attack things on it, but if the checks were working they wouldn't ever try and do this unless they happened to be in autotarget range. So instead of seeing if we can reach the target, we might want to see if we can reach a location close to the target instead. That would be more complicated.

Will need to investigate this some more.

@RoosterDragon
Copy link
Member Author

#20239 fixes things so boats now ignore the land units.

However it seems like a regression to not allow boats to attack units near the shore - we need to teach the AI that it can attack units it can't reach - they don't need to get to the unit - just close enough to be in weapons range. Plus revalidating the other scenarios @PunkPun reported.

@dnqbob
Copy link
Contributor

dnqbob commented Sep 3, 2022

I think it is ok to ignore the land units, for we also have an Autotarget can get target while the squad attack moving

Copy link
Member

@PunkPun PunkPun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did another game (rebased on bleed)

The artillery but happened again (ignore the light tank he's attacking the airfield)
Screenshot 2022-09-04 at 13 39 30

Naval grouping seems to be broken. These submarines attacked a naval yard which was built right next to them and did nothing afterwards. When a new sub was built it went kill the enemy naval yard, after that it also went idle. Not that there were anymore targets in water afterwards
Screenshot 2022-09-04 at 13 37 12

In the end, the winning AI was unable to finish the game. There were 4 other AI's which had only the sub pen / naval yard left as their last structure
Screenshot 2022-09-04 at 13 57 56

Probably unrelated to this PR, but AI nuked its own forces. (nuke was launched by the yellow AI)
Screenshot 2022-09-04 at 13 44 41

@RoosterDragon
Copy link
Member Author

Pushed a commit that attempts to solve the problem where the AI squad can't directly path to the unit, e.g. boats trying to attack a land unit, but can get close enough to attack, e.g. the land units are on the beach.

Code is godawful and the overall approach still needs some thinking, but this is a step forward. Marking as a draft because more work is needed here.

@PunkPun
Copy link
Member

PunkPun commented Oct 7, 2022

I would imagine the proper solution would be to generate a circle around the target the size of weapon range and see if all if any of those cells can be reached.

@dnqbob
Copy link
Contributor

dnqbob commented Oct 22, 2022

I think it could be better that split commit "Add helper methods to locate actors that can be reached via a path." into another PR and we merge that first. AI squad control is a really messing thing that will takes much longer time on fixing and testing.

@RoosterDragon
Copy link
Member Author

With only the first commit, AI navy won't attack any land units. This is because they can't path to them. That would probably be worse than the current behaviour of trying to attack land units they can't reach. So we probably do want a solution that finds the balance - navy can attack land units, but only tries to attack land units within range rather than anything.

@dnqbob
Copy link
Contributor

dnqbob commented Oct 29, 2022

With only the first commit, AI navy won't attack any land units. This is because they can't path to them. That would probably be worse than the current behaviour of trying to attack land units they can't reach. So we probably do want a solution that finds the balance - navy can attack land units, but only tries to attack land units within range rather than anything.

I think it is OK, because "current behaviour of trying to attack land units they can't reach" can give us a huge lag while also stuck the navy on the shore. I personally prefer a smoother gameplay on this issue. I remember RA2 also make AI navy can only attack navy, it is possible that it is due to the same reason.

@PunkPun
Copy link
Member

PunkPun commented Oct 29, 2022

It is not fine, see my previous comment

In the end, the winning AI was unable to finish the game. There were 4 other AI's which had only the sub pen / naval yard left as their last structure

@dnqbob
Copy link
Contributor

dnqbob commented Oct 29, 2022

But I think it is better than when situation happends like MustaphaTR/Romanovs-Vengeance#88, which make the game almost unplayable when there is too many unit trying to attack unreachable.

Add: for optimazing this situation I did many works, like only allow leader do the pathfinding to target, kick stuck unit from squad, but it also happen sometimes when units try to attack unreachable units.

@anvilvapre
Copy link
Contributor

Sounds like two different types of path searches, one to reach a destination, another to try to attack something (that will be) in target range?

@dnqbob
Copy link
Contributor

dnqbob commented Jul 15, 2023

Could you please add BlockedByActor parameter to those pathfinder helper? To solve the problem of AI stuck by enclosed buildings we need a helper method like that.

@RoosterDragon
Copy link
Member Author

We're reliant on HierarchicalPathFinder.PathExists for this check. It isn't sufficiently smart enough to help with that I think. It can do BlockedByActor.None and some of BlockedByActor.Immovable but that's it.

I think something like #20945 is along the right lines anyway. Rather than trying to get clever and working out if placing a building will complete a wall that traps in some units, just enforcing spacing on some/all buildings help reduce the chance of congested AI bases that might trap things in.

@RoosterDragon RoosterDragon force-pushed the domain-checks branch 2 times, most recently from 8e234f3 to 02f0311 Compare July 16, 2023 16:04
@RoosterDragon
Copy link
Member Author

I have updated the code to deal with issues noted previously. Here are the scenarios which are now improved.

I used the following map for testing these scenarios out. Human player should use spawn 'A'. Enabling cheats and actor tags are useful. IslandsPathfinding.zip

Target Units on Same Island

  • Check the AI squad target.
  • Build a barracks in the bottom-right of your island.
  • Build a barracks at the top of the AI island.

On bleed, the squad will initially target your base - the "Assault, fact XX" in the actor tags tells you the squad target. Once the first barracks is placed, they will target that instead - "tent XX". Once the second barracks is placed, they ignore it as the first is physically closer.

With this PR, they won't target the base as it isn't reachable. Same with the first barracks. Once the second barrack is placed, the squad will attack it.

1
With this PR, the AI squad ignores the closer barracks to move to the one on their island.

Target Naval Units In Range of Island

  • Build a naval yard, then a gunboat.
  • Move the gunboat to the AI island shoreline.
  • Wait for the AI to react.
  • Move the gunboat along the coast, near the shore. Force the AI squad to keep moving to keep up with it.
  • Create a second gunboat and place it near the enemy shoreline.
  • Move the first gunboat out of range to the left side of the map.

On bleed, the AI squad will attack the gunboat. But when it moves out of range, they won't retarget. They won't respond to new units as a result. With the PR they will drop the target when it moves out of range - and can retarget to the new unit immediately.

2
Squad targetting the boat.

Target Lands Units In Range Of Island

  • Build some rifles and send them to the stair step at the bottom of your island.
  • Wait for the AI squad to react.
  • Move the units out of range.

The AI squad will attack these units. On bleed when the units move away the squad won't retarget and will keep trying to attack. With this PR they will go idle and return to base.

3
The AI squad has dropped the targets that moved out of range.

AI Units used after squad disbanded

  • Set SquadManagerBotModuleInfo.RushInterval to 0 and SquadManagerBotModuleInfo.MinimumAttackForceDelay to 60000. This will ensurce the AI creates a Rush squad.
  • Build a Construction Yard on the AI island.
  • Wait for the AI squad to destroy it and return to base.
  • Build another Construction Yard on the AI island.

On bleed, the squad stays put - they have retargetted to the unreachable construction yard and will be useless. With this PR the units will go idle. Once the next strucuture is placed a new squad is formed once the AI has enough units and will attack your new structure. Importantly, idle units from the first squad will be included in the force.

There existed a bug where an AI squad that disbands doesn't mark those units as available. So the AI never notices they can be assigned into another squad. So the units that returned to base from the first squad would never have been assigned to the new squad without this fix.


Finally, I tested a large AI game and didn't notice any performance issues. If you experience any, they are likely to present as lag spikes spaced approx 1 second apart. This is because the AI does some thinking approx every 1 second so it would almost certainly be AI related. If you experience this please include a replay! And if possible some repro steps.

OpenRA.Mods.Common/WorldExtensions.cs Outdated Show resolved Hide resolved
OpenRA.Mods.Common/WorldExtensions.cs Outdated Show resolved Hide resolved
OpenRA.Mods.Common/WorldExtensions.cs Outdated Show resolved Hide resolved
OpenRA.Mods.Common/WorldExtensions.cs Outdated Show resolved Hide resolved
OpenRA.Mods.Common/Traits/Mobile.cs Show resolved Hide resolved
OpenRA.Mods.Common/Traits/CaptureManager.cs Outdated Show resolved Hide resolved
OpenRA.Mods.Common/Traits/AutoCrusher.cs Show resolved Hide resolved
@Mailaender
Copy link
Member

Needs a rebase.

Previously, the ClosestTo and PositionClosestTo existed to perform a simple distance based check to choose the closest location from a choice of locations to a single other location. For some functions this is sufficient, but for many functions we want to then move between the locations. If the location selected is in fact unreachable (e.g. on another island) then we would not want to consider it.

We now introduce ClosestToIgnoringPath for checks where we don't care about a path existing, e.g. weapons hitting nearby targets. When we do care about paths, we introduce ClosestToWithPathFrom and ClosestToWithPathTo which will check that a path exists. The PathFrom check will make sure one of the actors from the list can make it to the single target location. The PathTo check will make sure the single actor can make it to one of the target locations. This difference allows us to specify which actor will be doing the moving. This is important as a path might exists for one actor, but not another. Consider two islands with a hovercraft on one and a tank on the other. The hovercraft can path to the tank, but the tank cannot path to the hovercraft.

We also introduce WithPathFrom and WithPathTo. These will perform filtering by checking for valid paths, but won't select the closest location.

By employing the new methods that filter for paths, we fix various behaviour that would cause actors to get confused. Imagine an islands map, by checking for paths we ensure logic will locate reachable locations on the island, rather than considering a location on a nearby island that is physically closer but unreachable. This fixes AI squad automation, and other automated behaviours such as rearming.
@PunkPun PunkPun merged commit 23f3f8d into OpenRA:bleed Sep 7, 2023
3 checks passed
@PunkPun
Copy link
Member

PunkPun commented Sep 7, 2023

Changelog

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pathfinding performance issues
6 participants