Units heading in generally opposite directions are now considered blockers; this fixes pathing deadlocks.
This commit is contained in:
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
// Find harvestable resources nearby:
|
// Find harvestable resources nearby:
|
||||||
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(
|
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(
|
||||||
PathSearch.Search(self.World, mobileInfo, self.Owner, true)
|
PathSearch.Search(self.World, mobileInfo, self, true)
|
||||||
.WithCustomCost(loc =>
|
.WithCustomCost(loc =>
|
||||||
{
|
{
|
||||||
// Avoid enemy territory:
|
// Avoid enemy territory:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
var mobile = self.Trait<Mobile>();
|
var mobile = self.Trait<Mobile>();
|
||||||
|
|
||||||
var ps1 = new PathSearch( self.World, mobile.Info, self.Owner )
|
var ps1 = new PathSearch( self.World, mobile.Info, self )
|
||||||
{
|
{
|
||||||
checkForBlocked = true,
|
checkForBlocked = true,
|
||||||
heuristic = location => 0,
|
heuristic = location => 0,
|
||||||
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
|
|
||||||
ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );
|
ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );
|
||||||
|
|
||||||
var ps2 = PathSearch.FromPoint( self.World, mobile.Info, self.Owner, mobile.toCell, target.CenterLocation.ToCPos(), true );
|
var ps2 = PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, target.CenterLocation.ToCPos(), true );
|
||||||
var ret = self.World.WorldActor.Trait<PathFinder>().FindBidiPath( ps1, ps2 );
|
var ret = self.World.WorldActor.Trait<PathFinder>().FindBidiPath( ps1, ps2 );
|
||||||
|
|
||||||
return Util.SequenceActivities( mobile.MoveTo( () => ret ), this );
|
return Util.SequenceActivities( mobile.MoveTo( () => ret ), this );
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace OpenRA.Mods.RA.Crates
|
|||||||
|
|
||||||
for (var i = -1; i < 2; i++)
|
for (var i = -1; i < 2; i++)
|
||||||
for (var j = -1; j < 2; j++)
|
for (var j = -1; j < 2; j++)
|
||||||
if (mi.CanEnterCell(self.World, self.Owner, near + new CVec(i, j), null, true, true))
|
if (mi.CanEnterCell(self.World, self, near + new CVec(i, j), null, true, true))
|
||||||
yield return near + new CVec(i, j);
|
yield return near + new CVec(i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ namespace OpenRA.Mods.RA
|
|||||||
// Start a search from each refinery's delivery location:
|
// Start a search from each refinery's delivery location:
|
||||||
var mi = self.Info.Traits.Get<MobileInfo>();
|
var mi = self.Info.Traits.Get<MobileInfo>();
|
||||||
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(
|
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(
|
||||||
PathSearch.FromPoints(self.World, mi, self.Owner, refs.Values.Select(r => r.Location), self.Location, false)
|
PathSearch.FromPoints(self.World, mi, self, refs.Values.Select(r => r.Location), self.Location, false)
|
||||||
.WithCustomCost((loc) =>
|
.WithCustomCost((loc) =>
|
||||||
{
|
{
|
||||||
if (!refs.ContainsKey(loc)) return 0;
|
if (!refs.ContainsKey(loc)) return 0;
|
||||||
@@ -349,7 +349,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
// Find any harvestable resources:
|
// Find any harvestable resources:
|
||||||
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(
|
var path = self.World.WorldActor.Trait<PathFinder>().FindPath(
|
||||||
PathSearch.Search(self.World, mobileInfo, self.Owner, true)
|
PathSearch.Search(self.World, mobileInfo, self, true)
|
||||||
.WithHeuristic(loc =>
|
.WithHeuristic(loc =>
|
||||||
{
|
{
|
||||||
// Get the resource at this location:
|
// Get the resource at this location:
|
||||||
|
|||||||
@@ -77,7 +77,25 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
{SubCell.FullCell, new PVecInt(0,0)},
|
{SubCell.FullCell, new PVecInt(0,0)},
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool CanEnterCell(World world, Player owner, CPos cell, Actor ignoreActor, bool checkTransientActors, bool blockedByMovers)
|
static bool IsMovingInMyDirection(Actor self, Actor other)
|
||||||
|
{
|
||||||
|
if (!other.IsMoving()) return false;
|
||||||
|
if (self == null) return true;
|
||||||
|
|
||||||
|
var selfMobile = self.TraitOrDefault<Mobile>();
|
||||||
|
if (selfMobile == null) return false;
|
||||||
|
|
||||||
|
var otherMobile = other.TraitOrDefault<Mobile>();
|
||||||
|
if (otherMobile == null) return false;
|
||||||
|
|
||||||
|
// Sign of dot-product indicates (roughly) if vectors are facing in same or opposite directions:
|
||||||
|
var dp = CVec.Dot((selfMobile.toCell - self.Location), (otherMobile.toCell - other.Location));
|
||||||
|
if (dp <= 0) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor, bool checkTransientActors, bool blockedByMovers)
|
||||||
{
|
{
|
||||||
if (MovementCostForCell(world, cell) == int.MaxValue)
|
if (MovementCostForCell(world, cell) == int.MaxValue)
|
||||||
return false;
|
return false;
|
||||||
@@ -88,7 +106,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
var blockingActors = world.ActorMap.GetUnitsAt(cell)
|
var blockingActors = world.ActorMap.GetUnitsAt(cell)
|
||||||
.Where(x => x != ignoreActor)
|
.Where(x => x != ignoreActor)
|
||||||
// Neutral/enemy units are blockers. Allied units that are moving are not blockers.
|
// Neutral/enemy units are blockers. Allied units that are moving are not blockers.
|
||||||
.Where(x => blockedByMovers || ((owner.Stances[x.Owner] != Stance.Ally) || !x.IsMoving()))
|
.Where(x => blockedByMovers || ((self.Owner.Stances[x.Owner] != Stance.Ally) || !IsMovingInMyDirection(self, x)))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (checkTransientActors && blockingActors.Count > 0)
|
if (checkTransientActors && blockingActors.Count > 0)
|
||||||
@@ -98,7 +116,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (blockingActors.Any(a => !(a.HasTrait<ICrushable>() &&
|
if (blockingActors.Any(a => !(a.HasTrait<ICrushable>() &&
|
||||||
a.TraitsImplementing<ICrushable>().Any(b => b.CrushableBy(Crushes, owner)))))
|
a.TraitsImplementing<ICrushable>().Any(b => b.CrushableBy(Crushes, self.Owner)))))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +365,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
|
|
||||||
public bool CanEnterCell(CPos cell, Actor ignoreActor, bool checkTransientActors)
|
public bool CanEnterCell(CPos cell, Actor ignoreActor, bool checkTransientActors)
|
||||||
{
|
{
|
||||||
return Info.CanEnterCell(self.World, self.Owner, cell, ignoreActor, checkTransientActors, true);
|
return Info.CanEnterCell(self.World, self, cell, ignoreActor, checkTransientActors, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnteringCell(Actor self)
|
public void EnteringCell(Actor self)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
{
|
{
|
||||||
this.getPath = (self,mobile) =>
|
this.getPath = (self,mobile) =>
|
||||||
self.World.WorldActor.Trait<PathFinder>().FindPath(
|
self.World.WorldActor.Trait<PathFinder>().FindPath(
|
||||||
PathSearch.FromPoint( self.World, mobile.Info, self.Owner, mobile.toCell, destination, false )
|
PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, destination, false )
|
||||||
.WithoutLaneBias());
|
.WithoutLaneBias());
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
this.nearEnough = 0;
|
this.nearEnough = 0;
|
||||||
@@ -49,7 +49,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
{
|
{
|
||||||
this.getPath = (self,mobile) =>
|
this.getPath = (self,mobile) =>
|
||||||
self.World.WorldActor.Trait<PathFinder>().FindPath(
|
self.World.WorldActor.Trait<PathFinder>().FindPath(
|
||||||
PathSearch.FromPoint( self.World, mobile.Info, self.Owner, mobile.toCell, destination, false )
|
PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, destination, false )
|
||||||
.WithIgnoredBuilding( ignoreBuilding ));
|
.WithIgnoredBuilding( ignoreBuilding ));
|
||||||
|
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
var mi = self.Info.Traits.Get<MobileInfo>();
|
var mi = self.Info.Traits.Get<MobileInfo>();
|
||||||
|
|
||||||
var pb = FindBidiPath(
|
var pb = FindBidiPath(
|
||||||
PathSearch.FromPoint(world, mi, self.Owner, target, from, true),
|
PathSearch.FromPoint(world, mi, self, target, from, true),
|
||||||
PathSearch.FromPoint(world, mi, self.Owner, from, target, true).InReverse()
|
PathSearch.FromPoint(world, mi, self, from, target, true).InReverse()
|
||||||
);
|
);
|
||||||
|
|
||||||
CheckSanePath2(pb, from, target);
|
CheckSanePath2(pb, from, target);
|
||||||
@@ -73,11 +73,11 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
{
|
{
|
||||||
var mi = self.Info.Traits.Get<MobileInfo>();
|
var mi = self.Info.Traits.Get<MobileInfo>();
|
||||||
var tilesInRange = world.FindTilesInCircle(target, range)
|
var tilesInRange = world.FindTilesInCircle(target, range)
|
||||||
.Where(t => mi.CanEnterCell(self.World, self.Owner, t, null, true, true));
|
.Where(t => mi.CanEnterCell(self.World, self, t, null, true, true));
|
||||||
|
|
||||||
var path = FindBidiPath(
|
var path = FindBidiPath(
|
||||||
PathSearch.FromPoints(world, mi, self.Owner, tilesInRange, src, true),
|
PathSearch.FromPoints(world, mi, self, tilesInRange, src, true),
|
||||||
PathSearch.FromPoint(world, mi, self.Owner, src, target, true).InReverse()
|
PathSearch.FromPoint(world, mi, self, src, target, true).InReverse()
|
||||||
);
|
);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
|
|||||||
@@ -28,14 +28,15 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
public bool inReverse;
|
public bool inReverse;
|
||||||
|
|
||||||
MobileInfo mobileInfo;
|
MobileInfo mobileInfo;
|
||||||
Player owner;
|
Actor self;
|
||||||
|
public Player owner { get { return self.Owner; } }
|
||||||
|
|
||||||
public PathSearch(World world, MobileInfo mobileInfo, Player owner)
|
public PathSearch(World world, MobileInfo mobileInfo, Actor self)
|
||||||
{
|
{
|
||||||
this.world = world;
|
this.world = world;
|
||||||
cellInfo = InitCellInfo();
|
cellInfo = InitCellInfo();
|
||||||
this.mobileInfo = mobileInfo;
|
this.mobileInfo = mobileInfo;
|
||||||
this.owner = owner;
|
this.self = self;
|
||||||
customCost = null;
|
customCost = null;
|
||||||
queue = new PriorityQueue<PathDistance>();
|
queue = new PriorityQueue<PathDistance>();
|
||||||
}
|
}
|
||||||
@@ -120,7 +121,7 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
if (costHere == int.MaxValue)
|
if (costHere == int.MaxValue)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!mobileInfo.CanEnterCell(world, owner, newHere, ignoreBuilding, checkForBlocked, false))
|
if (!mobileInfo.CanEnterCell(world, self, newHere, ignoreBuilding, checkForBlocked, false))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (customBlock != null && customBlock(newHere))
|
if (customBlock != null && customBlock(newHere))
|
||||||
@@ -182,18 +183,18 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
queue.Add(new PathDistance(heuristic(location), location));
|
queue.Add(new PathDistance(heuristic(location), location));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PathSearch Search(World world, MobileInfo mi, Player owner, bool checkForBlocked)
|
public static PathSearch Search(World world, MobileInfo mi, Actor self, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
var search = new PathSearch(world, mi, owner)
|
var search = new PathSearch(world, mi, self)
|
||||||
{
|
{
|
||||||
checkForBlocked = checkForBlocked
|
checkForBlocked = checkForBlocked
|
||||||
};
|
};
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PathSearch FromPoint(World world, MobileInfo mi, Player owner, CPos from, CPos target, bool checkForBlocked)
|
public static PathSearch FromPoint(World world, MobileInfo mi, Actor self, CPos from, CPos target, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
var search = new PathSearch(world, mi, owner)
|
var search = new PathSearch(world, mi, self)
|
||||||
{
|
{
|
||||||
heuristic = DefaultEstimator(target),
|
heuristic = DefaultEstimator(target),
|
||||||
checkForBlocked = checkForBlocked
|
checkForBlocked = checkForBlocked
|
||||||
@@ -203,9 +204,9 @@ namespace OpenRA.Mods.RA.Move
|
|||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PathSearch FromPoints(World world, MobileInfo mi, Player owner, IEnumerable<CPos> froms, CPos target, bool checkForBlocked)
|
public static PathSearch FromPoints(World world, MobileInfo mi, Actor self, IEnumerable<CPos> froms, CPos target, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
var search = new PathSearch(world, mi, owner)
|
var search = new PathSearch(world, mi, self)
|
||||||
{
|
{
|
||||||
heuristic = DefaultEstimator(target),
|
heuristic = DefaultEstimator(target),
|
||||||
checkForBlocked = checkForBlocked
|
checkForBlocked = checkForBlocked
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ namespace OpenRA.Mods.RA
|
|||||||
var mobileInfo = producee.Traits.GetOrDefault<MobileInfo>();
|
var mobileInfo = producee.Traits.GetOrDefault<MobileInfo>();
|
||||||
|
|
||||||
return mobileInfo == null ||
|
return mobileInfo == null ||
|
||||||
mobileInfo.CanEnterCell(self.World, self.Owner, self.Location + s.ExitCellVector, self, true, true);
|
mobileInfo.CanEnterCell(self.World, self, self.Location + s.ExitCellVector, self, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user