Some initial hacks towards multiple-infantry-per-cell. Make the pathfinder smart enough to do what we need, and remove a *lot* of stupid duplication. Needs more work.
This commit is contained in:
@@ -72,9 +72,9 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pb = FindBidiPath(
|
var pb = FindBidiPath(
|
||||||
PathSearch.FromPoint(world, target, from, umt, true)
|
PathSearch.FromPoint(self, target, from, umt, true)
|
||||||
.WithCustomBlocker(AvoidUnitsNear(from, 4, self)),
|
.WithCustomBlocker(AvoidUnitsNear(from, 4, self)),
|
||||||
PathSearch.FromPoint(world, from, target, umt, true)
|
PathSearch.FromPoint(self, from, target, umt, true)
|
||||||
.WithCustomBlocker(AvoidUnitsNear(from, 4, self))
|
.WithCustomBlocker(AvoidUnitsNear(from, 4, self))
|
||||||
.InReverse());
|
.InReverse());
|
||||||
|
|
||||||
@@ -90,10 +90,11 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
using( new PerfSample( "find_unit_path_multiple_src" ) )
|
using( new PerfSample( "find_unit_path_multiple_src" ) )
|
||||||
{
|
{
|
||||||
|
var mobile = self.traits.Get<Mobile>();
|
||||||
var tilesInRange = world.FindTilesInCircle(target, range)
|
var tilesInRange = world.FindTilesInCircle(target, range)
|
||||||
.Where( t => world.IsPathableCell( t, umt ) );
|
.Where( t => mobile.CanEnterCell(t));
|
||||||
|
|
||||||
var path = FindPath( PathSearch.FromPoints( world, tilesInRange, src, umt, false )
|
var path = FindPath( PathSearch.FromPoints( self, tilesInRange, src, umt, false )
|
||||||
.WithCustomBlocker(AvoidUnitsNear(src, 4, self))
|
.WithCustomBlocker(AvoidUnitsNear(src, 4, self))
|
||||||
.InReverse());
|
.InReverse());
|
||||||
path.Reverse();
|
path.Reverse();
|
||||||
|
|||||||
@@ -37,14 +37,16 @@ namespace OpenRA
|
|||||||
Func<int2, bool> customBlock;
|
Func<int2, bool> customBlock;
|
||||||
public bool checkForBlocked;
|
public bool checkForBlocked;
|
||||||
public Actor ignoreBuilding;
|
public Actor ignoreBuilding;
|
||||||
|
Actor self;
|
||||||
public bool inReverse;
|
public bool inReverse;
|
||||||
|
|
||||||
BuildingInfluence buildingInfluence;
|
BuildingInfluence buildingInfluence;
|
||||||
UnitInfluence unitInfluence;
|
UnitInfluence unitInfluence;
|
||||||
|
|
||||||
public PathSearch(World world)
|
public PathSearch(Actor self)
|
||||||
{
|
{
|
||||||
this.world = world;
|
this.self = self;
|
||||||
|
world = self.World;
|
||||||
cellInfo = InitCellInfo();
|
cellInfo = InitCellInfo();
|
||||||
queue = new PriorityQueue<PathDistance>();
|
queue = new PriorityQueue<PathDistance>();
|
||||||
|
|
||||||
@@ -70,6 +72,18 @@ namespace OpenRA
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PathSearch WithHeuristic(Func<int2, float> h)
|
||||||
|
{
|
||||||
|
heuristic = h;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PathSearch FromPoint(int2 from)
|
||||||
|
{
|
||||||
|
AddInitialCell( self.World, from );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
const float LaneBias = .5f;
|
const float LaneBias = .5f;
|
||||||
|
|
||||||
public int2 Expand( World world, float[][ , ] passableCost )
|
public int2 Expand( World world, float[][ , ] passableCost )
|
||||||
@@ -101,8 +115,8 @@ namespace OpenRA
|
|||||||
if (!buildingInfluence.CanMoveHere(newHere, ignoreBuilding))
|
if (!buildingInfluence.CanMoveHere(newHere, ignoreBuilding))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Replicate real-ra behavior of not being able to enter a cell if there is a mixture of crushable and uncrushable units
|
var mobile = self.traits.Get<Mobile>();
|
||||||
if (checkForBlocked && (unitInfluence.GetUnitsAt(newHere).Any(a => !world.IsActorPathableToCrush(a, umt))))
|
if (checkForBlocked && !mobile.CanEnterCell(newHere))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (customBlock != null && customBlock(newHere))
|
if (customBlock != null && customBlock(newHere))
|
||||||
@@ -158,20 +172,28 @@ namespace OpenRA
|
|||||||
queue.Add( new PathDistance( heuristic( location ), location ) );
|
queue.Add( new PathDistance( heuristic( location ), location ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PathSearch FromPoint( World world, int2 from, int2 target, UnitMovementType umt, bool checkForBlocked )
|
public static PathSearch Search( Actor self, UnitMovementType umt, bool checkForBlocked )
|
||||||
{
|
{
|
||||||
var search = new PathSearch(world) {
|
var search = new PathSearch(self) {
|
||||||
|
umt = umt,
|
||||||
|
checkForBlocked = checkForBlocked };
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PathSearch FromPoint( Actor self, int2 from, int2 target, UnitMovementType umt, bool checkForBlocked )
|
||||||
|
{
|
||||||
|
var search = new PathSearch(self) {
|
||||||
heuristic = DefaultEstimator( target ),
|
heuristic = DefaultEstimator( target ),
|
||||||
umt = umt,
|
umt = umt,
|
||||||
checkForBlocked = checkForBlocked };
|
checkForBlocked = checkForBlocked };
|
||||||
|
|
||||||
search.AddInitialCell( world, from );
|
search.AddInitialCell( self.World, from );
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PathSearch FromPoints(World world, IEnumerable<int2> froms, int2 target, UnitMovementType umt, bool checkForBlocked)
|
public static PathSearch FromPoints(Actor self, IEnumerable<int2> froms, int2 target, UnitMovementType umt, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
var search = new PathSearch(world)
|
var search = new PathSearch(self)
|
||||||
{
|
{
|
||||||
heuristic = DefaultEstimator(target),
|
heuristic = DefaultEstimator(target),
|
||||||
umt = umt,
|
umt = umt,
|
||||||
@@ -179,7 +201,7 @@ namespace OpenRA
|
|||||||
};
|
};
|
||||||
|
|
||||||
foreach (var sl in froms)
|
foreach (var sl in froms)
|
||||||
search.AddInitialCell(world, sl);
|
search.AddInitialCell(self.World, sl);
|
||||||
|
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ namespace OpenRA.Traits.Activities
|
|||||||
{
|
{
|
||||||
this.getPath = (self, mobile) =>
|
this.getPath = (self, mobile) =>
|
||||||
self.World.PathFinder.FindPath(
|
self.World.PathFinder.FindPath(
|
||||||
PathSearch.FromPoint( self.World, self.Location, destination, mobile.GetMovementType(), false )
|
PathSearch.FromPoint( self, self.Location, destination, mobile.GetMovementType(), false )
|
||||||
.WithCustomBlocker( self.World.PathFinder.AvoidUnitsNear( self.Location, 4, self ))
|
.WithCustomBlocker( self.World.PathFinder.AvoidUnitsNear( self.Location, 4, self ))
|
||||||
.WithIgnoredBuilding( ignoreBuilding ));
|
.WithIgnoredBuilding( ignoreBuilding ));
|
||||||
|
|
||||||
@@ -89,17 +89,6 @@ namespace OpenRA.Traits.Activities
|
|||||||
this.nearEnough = 0;
|
this.nearEnough = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanEnterCell( int2 c, Actor self )
|
|
||||||
{
|
|
||||||
if (!self.World.WorldActor.traits.Get<BuildingInfluence>().CanMoveHere(c)
|
|
||||||
&& self.World.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(c) != ignoreBuilding)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Cannot enter a cell if any unit inside is uncrushable
|
|
||||||
// This will need to be updated for multiple-infantry-in-a-cell
|
|
||||||
return (!self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(c).Any(a => a != self && !self.World.IsActorCrushableByActor(a, self)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IActivity Tick( Actor self )
|
public IActivity Tick( Actor self )
|
||||||
{
|
{
|
||||||
var unit = self.traits.Get<Unit>();
|
var unit = self.traits.Get<Unit>();
|
||||||
@@ -179,7 +168,7 @@ namespace OpenRA.Traits.Activities
|
|||||||
{
|
{
|
||||||
if( path.Count == 0 ) return null;
|
if( path.Count == 0 ) return null;
|
||||||
var nextCell = path[ path.Count - 1 ];
|
var nextCell = path[ path.Count - 1 ];
|
||||||
if( !CanEnterCell( nextCell, self ) )
|
if( !mobile.CanEnterCell( nextCell ) )
|
||||||
{
|
{
|
||||||
if( ( mobile.toCell - destination.Value ).LengthSquared <= nearEnough )
|
if( ( mobile.toCell - destination.Value ).LengthSquared <= nearEnough )
|
||||||
{
|
{
|
||||||
@@ -255,6 +244,8 @@ namespace OpenRA.Traits.Activities
|
|||||||
var frac = (float)moveFraction / moveFractionTotal;
|
var frac = (float)moveFraction / moveFractionTotal;
|
||||||
|
|
||||||
self.CenterLocation = float2.Lerp( from, to, frac );
|
self.CenterLocation = float2.Lerp( from, to, frac );
|
||||||
|
// + self.traits.WithInterface<IOffsetCenterLocation>().Aggregate(float2.Zero, (a, x) => a + x.CenterOffset);
|
||||||
|
|
||||||
if( moveFraction >= moveFractionTotal )
|
if( moveFraction >= moveFractionTotal )
|
||||||
unit.Facing = toFacing & 0xFF;
|
unit.Facing = toFacing & 0xFF;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -31,16 +31,6 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
public static class WorldUtils
|
public static class WorldUtils
|
||||||
{
|
{
|
||||||
public static bool IsPathableCell(this World world, int2 a, UnitMovementType umt)
|
|
||||||
{
|
|
||||||
if (world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(a) != null) return false;
|
|
||||||
if (world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(a).Any()) return false;
|
|
||||||
|
|
||||||
return world.Map.IsInMap(a.X, a.Y) &&
|
|
||||||
Rules.TerrainTypes[world.TileSet.GetTerrainType(world.Map.MapTiles[a.X, a.Y])]
|
|
||||||
.GetCost(umt) < float.PositiveInfinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsCellBuildable(this World world, int2 a, bool waterBound)
|
public static bool IsCellBuildable(this World world, int2 a, bool waterBound)
|
||||||
{
|
{
|
||||||
return world.IsCellBuildable(a, waterBound, null);
|
return world.IsCellBuildable(a, waterBound, null);
|
||||||
|
|||||||
@@ -76,15 +76,9 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
self.QueueActivity(new Move(
|
self.QueueActivity(new Move(
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
var search = new PathSearch(self.World)
|
return self.World.PathFinder.FindPath(PathSearch.Search(self, UnitMovementType.Wheel, true)
|
||||||
{
|
.WithHeuristic(loc => (res.GetResource(loc) != null && harv.Resources.Contains( res.GetResource(loc).info.Name )) ? 0 : 1)
|
||||||
heuristic = loc => (res.GetResource(loc) != null
|
.FromPoint(self.Location));
|
||||||
&& harv.Resources.Contains( res.GetResource(loc).info.Name )) ? 0 : 1,
|
|
||||||
umt = UnitMovementType.Wheel,
|
|
||||||
checkForBlocked = true
|
|
||||||
};
|
|
||||||
search.AddInitialCell(self.World, self.Location);
|
|
||||||
return self.World.PathFinder.FindPath(search);
|
|
||||||
}));
|
}));
|
||||||
self.QueueActivity(new Harvest());
|
self.QueueActivity(new Harvest());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
if (unit.Altitude == 0)
|
if (unit.Altitude == 0)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
if (requireSpace && !self.World.IsPathableCell(self.Location, UnitMovementType.Foot))
|
// Todo: check if we can land here
|
||||||
return this; // fail to land if no space
|
//if (requireSpace && !self.World.IsPathableCell(self.Location, UnitMovementType.Foot))
|
||||||
|
// return this; // fail to land if no space
|
||||||
|
|
||||||
--unit.Altitude;
|
--unit.Altitude;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -30,17 +30,18 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
public IActivity NextActivity { get; set; }
|
public IActivity NextActivity { get; set; }
|
||||||
bool isCanceled;
|
bool isCanceled;
|
||||||
|
|
||||||
int2? ChooseExitTile(Actor self)
|
int2? ChooseExitTile(Actor self, Actor cargo)
|
||||||
{
|
{
|
||||||
// is anyone still hogging this tile?
|
// is anyone still hogging this tile?
|
||||||
if (self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(self.Location).Count() > 1)
|
if (self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(self.Location).Count() > 1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
var mobile = cargo.traits.Get<Mobile>();
|
||||||
|
|
||||||
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 ((i != 0 || j != 0) &&
|
if ((i != 0 || j != 0) &&
|
||||||
self.World.IsPathableCell(self.Location + new int2(i, j),
|
mobile.CanEnterCell(self.Location + new int2(i, j)))
|
||||||
UnitMovementType.Foot))
|
|
||||||
return self.Location + new int2(i, j);
|
return self.Location + new int2(i, j);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -68,7 +69,7 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
if (ru != null)
|
if (ru != null)
|
||||||
ru.PlayCustomAnimation(self, "unload", null);
|
ru.PlayCustomAnimation(self, "unload", null);
|
||||||
|
|
||||||
var exitTile = ChooseExitTile(self);
|
var exitTile = ChooseExitTile(self, cargo.Peek(self));
|
||||||
if (exitTile == null)
|
if (exitTile == null)
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ namespace OpenRA.Mods.RA
|
|||||||
return cargo.Count == 0;
|
return cargo.Count == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Actor Peek(Actor self)
|
||||||
|
{
|
||||||
|
return cargo[0];
|
||||||
|
}
|
||||||
|
|
||||||
public Actor Unload(Actor self)
|
public Actor Unload(Actor self)
|
||||||
{
|
{
|
||||||
var a = cargo[0];
|
var a = cargo[0];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using OpenRA.GameRules;
|
using OpenRA.GameRules;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
using OpenRA.Traits.Activities;
|
using OpenRA.Traits.Activities;
|
||||||
@@ -65,8 +66,16 @@ namespace OpenRA.Mods.RA
|
|||||||
for (var n = 0; n < threshold; n++ )
|
for (var n = 0; n < threshold; n++ )
|
||||||
{
|
{
|
||||||
var p = self.World.ChooseRandomCell(self.World.SharedRandom);
|
var p = self.World.ChooseRandomCell(self.World.SharedRandom);
|
||||||
if (self.World.IsPathableCell(p, inWater ? UnitMovementType.Float : UnitMovementType.Wheel))
|
|
||||||
{
|
// Don't drop on any actors
|
||||||
|
if (self.World.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(p) != null) continue;
|
||||||
|
if (self.World.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(p).Any()) continue;
|
||||||
|
|
||||||
|
// Don't drop on unpathable cells
|
||||||
|
if (!(self.World.Map.IsInMap(p.X, p.Y) &&
|
||||||
|
Rules.TerrainTypes[self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[p.X, p.Y])]
|
||||||
|
.GetCost(inWater ? UnitMovementType.Float : UnitMovementType.Wheel) < float.PositiveInfinity)) continue;
|
||||||
|
|
||||||
self.World.AddFrameEndTask(w =>
|
self.World.AddFrameEndTask(w =>
|
||||||
{
|
{
|
||||||
var crate = new Actor(w, "crate", new int2(0, 0), w.WorldActor.Owner);
|
var crate = new Actor(w, "crate", new int2(0, 0), w.WorldActor.Owner);
|
||||||
@@ -77,12 +86,11 @@ namespace OpenRA.Mods.RA
|
|||||||
plane.traits.Get<Unit>().Facing = Util.GetFacing(p - startPos, 0);
|
plane.traits.Get<Unit>().Facing = Util.GetFacing(p - startPos, 0);
|
||||||
plane.CancelActivity();
|
plane.CancelActivity();
|
||||||
plane.QueueActivity(new FlyCircle(p));
|
plane.QueueActivity(new FlyCircle(p));
|
||||||
plane.traits.Get<ParaDrop>().SetLZ(p, null, inWater);
|
plane.traits.Get<ParaDrop>().SetLZ(p, null);
|
||||||
plane.traits.Get<Cargo>().Load(plane, crate);
|
plane.traits.Get<Cargo>().Load(plane, crate);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,23 +68,18 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
var mobile = self.traits.Get<Mobile>();
|
var mobile = self.traits.Get<Mobile>();
|
||||||
|
|
||||||
var search = new PathSearch(self.World)
|
var refs = self.World.Queries.OwnedBy[self.Owner]
|
||||||
{
|
|
||||||
heuristic = PathSearch.DefaultEstimator(self.Location),
|
|
||||||
umt = mobile.GetMovementType(),
|
|
||||||
checkForBlocked = false,
|
|
||||||
};
|
|
||||||
var refineries = self.World.Queries.OwnedBy[self.Owner]
|
|
||||||
.Where(x => x != ignore && x.traits.Contains<IAcceptOre>())
|
.Where(x => x != ignore && x.traits.Contains<IAcceptOre>())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach (var r in refineries)
|
var path = self.World.PathFinder.FindPath(PathSearch.FromPoints(self,
|
||||||
search.AddInitialCell(self.World, r.Location + r.traits.Get<IAcceptOre>().DeliverOffset);
|
refs.Select(r => r.Location + r.traits.Get<IAcceptOre>().DeliverOffset),
|
||||||
|
self.Location,
|
||||||
var path = self.World.PathFinder.FindPath(search);
|
mobile.GetMovementType(),
|
||||||
|
false));
|
||||||
path.Reverse();
|
path.Reverse();
|
||||||
if (path.Count != 0)
|
if (path.Count != 0)
|
||||||
return refineries.FirstOrDefault(x => x.Location + x.traits.Get<IAcceptOre>().DeliverOffset == path[0]);
|
return refs.FirstOrDefault(x => x.Location + x.traits.Get<IAcceptOre>().DeliverOffset == path[0]);
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,13 +37,11 @@ namespace OpenRA.Mods.RA
|
|||||||
readonly List<int2> droppedAt = new List<int2>();
|
readonly List<int2> droppedAt = new List<int2>();
|
||||||
int2 lz;
|
int2 lz;
|
||||||
Actor flare;
|
Actor flare;
|
||||||
bool waterDrop;
|
|
||||||
|
|
||||||
public void SetLZ( int2 lz, Actor flare, bool waterDrop )
|
public void SetLZ( int2 lz, Actor flare )
|
||||||
{
|
{
|
||||||
this.lz = lz;
|
this.lz = lz;
|
||||||
this.flare = flare;
|
this.flare = flare;
|
||||||
this.waterDrop = waterDrop;
|
|
||||||
droppedAt.Clear();
|
droppedAt.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +77,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
bool IsSuitableCell(Actor self, int2 p)
|
bool IsSuitableCell(Actor self, int2 p)
|
||||||
{
|
{
|
||||||
return self.World.IsPathableCell(p, waterDrop ? UnitMovementType.Float : UnitMovementType.Wheel);
|
return self.traits.Get<Mobile>().CanEnterCell(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinishedDropping(Actor self)
|
void FinishedDropping(Actor self)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
a.CancelActivity();
|
a.CancelActivity();
|
||||||
a.QueueActivity(new FlyCircle(p));
|
a.QueueActivity(new FlyCircle(p));
|
||||||
a.traits.Get<ParaDrop>().SetLZ(p, flare, false);
|
a.traits.Get<ParaDrop>().SetLZ(p, flare);
|
||||||
|
|
||||||
var cargo = a.traits.Get<Cargo>();
|
var cargo = a.traits.Get<Cargo>();
|
||||||
foreach (var i in items)
|
foreach (var i in items)
|
||||||
|
|||||||
Reference in New Issue
Block a user