Remove plumbing for trait unit tests.
This commit is contained in:
committed by
Paul Chote
parent
8d0acaaa4f
commit
044b51742f
@@ -22,30 +22,13 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
public interface IActor
|
public class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>
|
||||||
{
|
|
||||||
ActorInfo Info { get; }
|
|
||||||
IWorld World { get; }
|
|
||||||
uint ActorID { get; }
|
|
||||||
Player Owner { get; set; }
|
|
||||||
|
|
||||||
T TraitOrDefault<T>();
|
|
||||||
T Trait<T>();
|
|
||||||
IEnumerable<T> TraitsImplementing<T>();
|
|
||||||
|
|
||||||
IEnumerable<IRenderable> Render(WorldRenderer wr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>, IActor
|
|
||||||
{
|
{
|
||||||
public readonly ActorInfo Info;
|
public readonly ActorInfo Info;
|
||||||
ActorInfo IActor.Info { get { return this.Info; } }
|
|
||||||
|
|
||||||
public readonly World World;
|
public readonly World World;
|
||||||
IWorld IActor.World { get { return World; } }
|
|
||||||
|
|
||||||
public readonly uint ActorID;
|
public readonly uint ActorID;
|
||||||
uint IActor.ActorID { get { return this.ActorID; } }
|
|
||||||
|
|
||||||
[Sync] public Player Owner { get; set; }
|
[Sync] public Player Owner { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
readonly T[] entries;
|
readonly T[] entries;
|
||||||
|
|
||||||
public CellLayer(IMap map)
|
public CellLayer(Map map)
|
||||||
: this(map.TileShape, new Size(map.MapSize.X, map.MapSize.Y)) { }
|
: this(map.TileShape, new Size(map.MapSize.X, map.MapSize.Y)) { }
|
||||||
|
|
||||||
public CellLayer(TileShape shape, Size size)
|
public CellLayer(TileShape shape, Size size)
|
||||||
|
|||||||
@@ -111,19 +111,7 @@ namespace OpenRA
|
|||||||
MissionSelector = 4
|
MissionSelector = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IMap
|
public class Map
|
||||||
{
|
|
||||||
TileShape TileShape { get; }
|
|
||||||
|
|
||||||
int2 MapSize { get; set; }
|
|
||||||
bool Contains(CPos cell);
|
|
||||||
CPos CellContaining(WPos pos);
|
|
||||||
WVec OffsetOfSubCell(SubCell subCell);
|
|
||||||
IEnumerable<CPos> FindTilesInCircle(CPos center, int maxRange);
|
|
||||||
WPos CenterOfCell(CPos cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Map : IMap
|
|
||||||
{
|
{
|
||||||
static readonly int[][] CellCornerHalfHeights = new int[][]
|
static readonly int[][] CellCornerHalfHeights = new int[][]
|
||||||
{
|
{
|
||||||
@@ -163,10 +151,6 @@ namespace OpenRA
|
|||||||
|
|
||||||
public const int MaxTilesInCircleRange = 50;
|
public const int MaxTilesInCircleRange = 50;
|
||||||
public readonly TileShape TileShape;
|
public readonly TileShape TileShape;
|
||||||
TileShape IMap.TileShape
|
|
||||||
{
|
|
||||||
get { return TileShape; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[FieldLoader.Ignore] public readonly WVec[] SubCellOffsets;
|
[FieldLoader.Ignore] public readonly WVec[] SubCellOffsets;
|
||||||
public readonly SubCell DefaultSubCell;
|
public readonly SubCell DefaultSubCell;
|
||||||
@@ -243,12 +227,6 @@ namespace OpenRA
|
|||||||
|
|
||||||
public int2 MapSize;
|
public int2 MapSize;
|
||||||
|
|
||||||
int2 IMap.MapSize
|
|
||||||
{
|
|
||||||
get { return MapSize; }
|
|
||||||
set { MapSize = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[FieldLoader.Ignore] public Lazy<CellLayer<TerrainTile>> MapTiles;
|
[FieldLoader.Ignore] public Lazy<CellLayer<TerrainTile>> MapTiles;
|
||||||
[FieldLoader.Ignore] public Lazy<CellLayer<ResourceTile>> MapResources;
|
[FieldLoader.Ignore] public Lazy<CellLayer<ResourceTile>> MapResources;
|
||||||
[FieldLoader.Ignore] public Lazy<CellLayer<byte>> MapHeight;
|
[FieldLoader.Ignore] public Lazy<CellLayer<byte>> MapHeight;
|
||||||
|
|||||||
@@ -24,15 +24,7 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
public enum WorldType { Regular, Shellmap }
|
public enum WorldType { Regular, Shellmap }
|
||||||
|
|
||||||
public interface IWorld
|
public class World
|
||||||
{
|
|
||||||
IActor WorldActor { get; }
|
|
||||||
int WorldTick { get; }
|
|
||||||
IMap Map { get; }
|
|
||||||
TileSet TileSet { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class World : IWorld
|
|
||||||
{
|
{
|
||||||
class ActorIDComparer : IComparer<Actor>
|
class ActorIDComparer : IComparer<Actor>
|
||||||
{
|
{
|
||||||
@@ -122,13 +114,10 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
|
|
||||||
public readonly Actor WorldActor;
|
public readonly Actor WorldActor;
|
||||||
IActor IWorld.WorldActor { get { return WorldActor; } }
|
|
||||||
|
|
||||||
public readonly Map Map;
|
public readonly Map Map;
|
||||||
IMap IWorld.Map { get { return Map; } }
|
|
||||||
|
|
||||||
public readonly TileSet TileSet;
|
public readonly TileSet TileSet;
|
||||||
TileSet IWorld.TileSet { get { return TileSet; } }
|
|
||||||
|
|
||||||
public readonly ActorMap ActorMap;
|
public readonly ActorMap ActorMap;
|
||||||
public readonly ScreenMap ScreenMap;
|
public readonly ScreenMap ScreenMap;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates (or obtains from the pool) a CellLayer given a map
|
/// Creates (or obtains from the pool) a CellLayer given a map
|
||||||
/// </summary>
|
/// </summary>
|
||||||
CellLayer<CellInfo> NewLayer(IMap map);
|
CellLayer<CellInfo> NewLayer(Map map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class CellInfoLayerManager : ICellInfoLayerManager
|
public sealed class CellInfoLayerManager : ICellInfoLayerManager
|
||||||
@@ -65,7 +65,7 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
cellInfoPool.Enqueue(ci);
|
cellInfoPool.Enqueue(ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CellLayer<CellInfo> NewLayer(IMap map)
|
public CellLayer<CellInfo> NewLayer(Map map)
|
||||||
{
|
{
|
||||||
CellLayer<CellInfo> result = null;
|
CellLayer<CellInfo> result = null;
|
||||||
var mapSize = new Size(map.MapSize.X, map.MapSize.Y);
|
var mapSize = new Size(map.MapSize.X, map.MapSize.Y);
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int MaxPathAge = 50;
|
const int MaxPathAge = 50;
|
||||||
readonly IWorld world;
|
readonly World world;
|
||||||
Dictionary<string, CachedPath> cachedPaths = new Dictionary<string, CachedPath>(100);
|
Dictionary<string, CachedPath> cachedPaths = new Dictionary<string, CachedPath>(100);
|
||||||
|
|
||||||
public PathCacheStorage(IWorld world)
|
public PathCacheStorage(World world)
|
||||||
{
|
{
|
||||||
this.world = world;
|
this.world = world;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
this.cacheStorage = cacheStorage;
|
this.cacheStorage = cacheStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CPos> FindUnitPath(CPos source, CPos target, IActor self)
|
public List<CPos> FindUnitPath(CPos source, CPos target, Actor self)
|
||||||
{
|
{
|
||||||
using (new PerfSample("Pathfinder"))
|
using (new PerfSample("Pathfinder"))
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WRange range, IActor self)
|
public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WRange range, Actor self)
|
||||||
{
|
{
|
||||||
using (new PerfSample("Pathfinder"))
|
using (new PerfSample("Pathfinder"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
|
|
||||||
bool InReverse { get; set; }
|
bool InReverse { get; set; }
|
||||||
|
|
||||||
IActor IgnoredActor { get; set; }
|
Actor IgnoredActor { get; set; }
|
||||||
|
|
||||||
IWorld World { get; }
|
World World { get; }
|
||||||
|
|
||||||
IActor Actor { get; }
|
Actor Actor { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct GraphConnection
|
public struct GraphConnection
|
||||||
@@ -61,21 +61,21 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
|
|
||||||
public class PathGraph : IGraph<CellInfo>
|
public class PathGraph : IGraph<CellInfo>
|
||||||
{
|
{
|
||||||
public IActor Actor { get; private set; }
|
public Actor Actor { get; private set; }
|
||||||
public IWorld World { get; private set; }
|
public World World { get; private set; }
|
||||||
public Func<CPos, bool> CustomBlock { get; set; }
|
public Func<CPos, bool> CustomBlock { get; set; }
|
||||||
public Func<CPos, int> CustomCost { get; set; }
|
public Func<CPos, int> CustomCost { get; set; }
|
||||||
public int LaneBias { get; set; }
|
public int LaneBias { get; set; }
|
||||||
public bool InReverse { get; set; }
|
public bool InReverse { get; set; }
|
||||||
public IActor IgnoredActor { get; set; }
|
public Actor IgnoredActor { get; set; }
|
||||||
|
|
||||||
readonly CellConditions checkConditions;
|
readonly CellConditions checkConditions;
|
||||||
readonly IMobileInfo mobileInfo;
|
readonly MobileInfo mobileInfo;
|
||||||
CellLayer<CellInfo> cellInfo;
|
CellLayer<CellInfo> cellInfo;
|
||||||
|
|
||||||
public const int InvalidNode = int.MaxValue;
|
public const int InvalidNode = int.MaxValue;
|
||||||
|
|
||||||
public PathGraph(CellLayer<CellInfo> cellInfo, IMobileInfo mobileInfo, IActor actor, IWorld world, bool checkForBlocked)
|
public PathGraph(CellLayer<CellInfo> cellInfo, MobileInfo mobileInfo, Actor actor, World world, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
this.cellInfo = cellInfo;
|
this.cellInfo = cellInfo;
|
||||||
World = world;
|
World = world;
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
considered = new LinkedList<Pair<CPos, int>>();
|
considered = new LinkedList<Pair<CPos, int>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IPathSearch Search(IWorld world, IMobileInfo mi, IActor self, bool checkForBlocked)
|
public static IPathSearch Search(World world, MobileInfo mi, Actor self, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
var graph = new PathGraph(CellInfoLayerManager.Instance.NewLayer(world.Map), mi, self, world, checkForBlocked);
|
var graph = new PathGraph(CellInfoLayerManager.Instance.NewLayer(world.Map), mi, self, world, checkForBlocked);
|
||||||
return new PathSearch(graph);
|
return new PathSearch(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IPathSearch FromPoint(IWorld world, IMobileInfo mi, IActor self, CPos from, CPos target, bool checkForBlocked)
|
public static IPathSearch FromPoint(World world, MobileInfo mi, Actor self, CPos from, CPos target, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
var graph = new PathGraph(CellInfoLayerManager.Instance.NewLayer(world.Map), mi, self, world, checkForBlocked);
|
var graph = new PathGraph(CellInfoLayerManager.Instance.NewLayer(world.Map), mi, self, world, checkForBlocked);
|
||||||
var search = new PathSearch(graph)
|
var search = new PathSearch(graph)
|
||||||
@@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Pathfinder
|
|||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IPathSearch FromPoints(IWorld world, IMobileInfo mi, IActor self, IEnumerable<CPos> froms, CPos target, bool checkForBlocked)
|
public static IPathSearch FromPoints(World world, MobileInfo mi, Actor self, IEnumerable<CPos> froms, CPos target, bool checkForBlocked)
|
||||||
{
|
{
|
||||||
var graph = new PathGraph(CellInfoLayerManager.Instance.NewLayer(world.Map), mi, self, world, checkForBlocked);
|
var graph = new PathGraph(CellInfoLayerManager.Instance.NewLayer(world.Map), mi, self, world, checkForBlocked);
|
||||||
var search = new PathSearch(graph)
|
var search = new PathSearch(graph)
|
||||||
|
|||||||
@@ -29,16 +29,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
All = TransientActors | BlockedByMovers
|
All = TransientActors | BlockedByMovers
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IMobileInfo : IMoveInfo
|
|
||||||
{
|
|
||||||
int MovementCostForCell(World world, CPos cell);
|
|
||||||
bool CanEnterCell(World world, Actor self, CPos cell, out int movementCost, Actor ignoreActor = null, CellConditions check = CellConditions.All);
|
|
||||||
bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All);
|
|
||||||
int GetMovementClass(TileSet tileset);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Desc("Unit is able to move.")]
|
[Desc("Unit is able to move.")]
|
||||||
public class MobileInfo : IMobileInfo, IOccupySpaceInfo, IFacingInfo, UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
|
public class MobileInfo : IMoveInfo, IOccupySpaceInfo, IFacingInfo, UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
|
||||||
{
|
{
|
||||||
[FieldLoader.LoadUsing("LoadSpeeds")]
|
[FieldLoader.LoadUsing("LoadSpeeds")]
|
||||||
[Desc("Set Water: 0 for ground units and lower the value on rough terrain.")]
|
[Desc("Set Water: 0 for ground units and lower the value on rough terrain.")]
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
/// Calculates a path for the actor from source to destination
|
/// Calculates a path for the actor from source to destination
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A path from start to target</returns>
|
/// <returns>A path from start to target</returns>
|
||||||
List<CPos> FindUnitPath(CPos source, CPos target, IActor self);
|
List<CPos> FindUnitPath(CPos source, CPos target, Actor self);
|
||||||
|
|
||||||
List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WRange range, IActor self);
|
List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WRange range, Actor self);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates a path given a search specification
|
/// Calculates a path given a search specification
|
||||||
@@ -52,16 +52,16 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public class PathFinder : IPathFinder
|
public class PathFinder : IPathFinder
|
||||||
{
|
{
|
||||||
static readonly List<CPos> EmptyPath = new List<CPos>(0);
|
static readonly List<CPos> EmptyPath = new List<CPos>(0);
|
||||||
readonly IWorld world;
|
readonly World world;
|
||||||
|
|
||||||
public PathFinder(IWorld world)
|
public PathFinder(World world)
|
||||||
{
|
{
|
||||||
this.world = world;
|
this.world = world;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CPos> FindUnitPath(CPos source, CPos target, IActor self)
|
public List<CPos> FindUnitPath(CPos source, CPos target, Actor self)
|
||||||
{
|
{
|
||||||
var mi = self.Info.Traits.Get<IMobileInfo>();
|
var mi = self.Info.Traits.Get<MobileInfo>();
|
||||||
|
|
||||||
// If a water-land transition is required, bail early
|
// If a water-land transition is required, bail early
|
||||||
var domainIndex = world.WorldActor.TraitOrDefault<DomainIndex>();
|
var domainIndex = world.WorldActor.TraitOrDefault<DomainIndex>();
|
||||||
@@ -81,7 +81,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return pb;
|
return pb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WRange range, IActor self)
|
public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WRange range, Actor self)
|
||||||
{
|
{
|
||||||
var mi = self.Info.Traits.Get<MobileInfo>();
|
var mi = self.Info.Traits.Get<MobileInfo>();
|
||||||
var targetCell = world.Map.CellContaining(target);
|
var targetCell = world.Map.CellContaining(target);
|
||||||
|
|||||||
@@ -1,206 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
|
|
||||||
* This file is part of OpenRA, which is free software. It is made
|
|
||||||
* available to you under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using OpenRA.Mods.Common.Traits;
|
|
||||||
|
|
||||||
namespace OpenRA.Test
|
|
||||||
{
|
|
||||||
public class FakeActor : IActor
|
|
||||||
{
|
|
||||||
IWorld world;
|
|
||||||
|
|
||||||
public ActorInfo Info
|
|
||||||
{
|
|
||||||
get { throw new NotImplementedException("No need to implement this yet"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IWorld World
|
|
||||||
{
|
|
||||||
get { return world; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint ActorID
|
|
||||||
{
|
|
||||||
get { return 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player Owner
|
|
||||||
{
|
|
||||||
get { return null; }
|
|
||||||
set { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public T TraitOrDefault<T>()
|
|
||||||
{
|
|
||||||
return default(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Trait<T>()
|
|
||||||
{
|
|
||||||
return default(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<T> TraitsImplementing<T>()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("No need to implement this yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
public T TraitInfo<T>()
|
|
||||||
{
|
|
||||||
return default(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Graphics.IRenderable> Render(Graphics.WorldRenderer wr)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("No need to implement this yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
public FakeActor(IWorld world)
|
|
||||||
{
|
|
||||||
// TODO: Complete member initialization
|
|
||||||
this.world = world;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FakeActor()
|
|
||||||
{
|
|
||||||
// TODO: Complete member initialization
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FakeWorld : IWorld
|
|
||||||
{
|
|
||||||
FakeActor worldactor;
|
|
||||||
IMap map;
|
|
||||||
|
|
||||||
public IActor WorldActor
|
|
||||||
{
|
|
||||||
get { return worldactor; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int WorldTick
|
|
||||||
{
|
|
||||||
get { return 50; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IMap Map
|
|
||||||
{
|
|
||||||
get { return map; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileSet TileSet
|
|
||||||
{
|
|
||||||
get { throw new NotImplementedException("No need to implement this yet"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public FakeWorld(IMap map)
|
|
||||||
{
|
|
||||||
// TODO: Complete member initialization
|
|
||||||
this.map = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FakeWorld(IMap map, FakeActor worldactor)
|
|
||||||
{
|
|
||||||
// TODO: Complete member initialization
|
|
||||||
this.map = map;
|
|
||||||
this.worldactor = worldactor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FakeMobileInfo : IMobileInfo
|
|
||||||
{
|
|
||||||
Func<CPos, bool> conditions;
|
|
||||||
|
|
||||||
public int MovementCostForCell(World world, CPos cell)
|
|
||||||
{
|
|
||||||
if (conditions(cell))
|
|
||||||
return 125;
|
|
||||||
return int.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanEnterCell(World world, Actor self, CPos cell, out int movementCost, Actor ignoreActor = null, CellConditions check = CellConditions.All)
|
|
||||||
{
|
|
||||||
movementCost = MovementCostForCell(world, cell);
|
|
||||||
return conditions(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetMovementClass(TileSet tileset)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("No need to implement this yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
public FakeMobileInfo(Func<CPos, bool> conditions)
|
|
||||||
{
|
|
||||||
this.conditions = conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All)
|
|
||||||
{
|
|
||||||
return conditions(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Create(ActorInitializer init)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FakeMap : IMap
|
|
||||||
{
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
public FakeMap(int width, int height)
|
|
||||||
{
|
|
||||||
// TODO: Complete member initialization
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileShape TileShape
|
|
||||||
{
|
|
||||||
get { return TileShape.Rectangle; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int2 MapSize
|
|
||||||
{
|
|
||||||
get { return new int2(width, height); }
|
|
||||||
set { throw new NotImplementedException("No need to implement this yet"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(CPos cell)
|
|
||||||
{
|
|
||||||
return cell.X >= 0 && cell.X < width && cell.Y >= 0 && cell.Y < height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CPos CellContaining(WPos pos)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("No need to implement this yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
public WVec OffsetOfSubCell(Traits.SubCell subCell)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("No need to implement this yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<CPos> FindTilesInCircle(CPos center, int maxRange)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("No need to implement this yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
public WPos CenterOfCell(CPos cell)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("No need to implement this yet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,12 +45,10 @@
|
|||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Fakes.cs" />
|
|
||||||
<Compile Include="OpenRA.Game\MiniYamlTest.cs" />
|
<Compile Include="OpenRA.Game\MiniYamlTest.cs" />
|
||||||
<Compile Include="OpenRA.Game\ActorInfoTest.cs" />
|
<Compile Include="OpenRA.Game\ActorInfoTest.cs" />
|
||||||
<Compile Include="OpenRA.Game\OrderTest.cs" />
|
<Compile Include="OpenRA.Game\OrderTest.cs" />
|
||||||
<Compile Include="OpenRA.Game\PlatformTest.cs" />
|
<Compile Include="OpenRA.Game\PlatformTest.cs" />
|
||||||
<Compile Include="PathfinderTests.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
|
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
|
||||||
|
|||||||
@@ -1,269 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
|
|
||||||
* This file is part of OpenRA, which is free software. It is made
|
|
||||||
* available to you under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using OpenRA;
|
|
||||||
using OpenRA.Mods.Common.Pathfinder;
|
|
||||||
using OpenRA.Mods.Common.Traits;
|
|
||||||
using OpenRA.Test;
|
|
||||||
|
|
||||||
namespace PathfinderTests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class PathfinderTests
|
|
||||||
{
|
|
||||||
const int Width = 128;
|
|
||||||
const int Height = 128;
|
|
||||||
IWorld world;
|
|
||||||
IMap map;
|
|
||||||
IActor actor;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
map = new FakeMap(Width, Height);
|
|
||||||
var worldactor = new FakeActor();
|
|
||||||
world = new FakeWorld(map, worldactor);
|
|
||||||
actor = new FakeActor(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
IMap BuildFakeMap(int mapWidth, int mapHeight)
|
|
||||||
{
|
|
||||||
var map = new Mock<IMap>();
|
|
||||||
map.SetupGet(m => m.TileShape).Returns(TileShape.Rectangle);
|
|
||||||
map.Setup(m => m.MapSize).Returns(new int2(mapWidth, mapHeight));
|
|
||||||
map.Setup(m => m.Contains(It.Is<CPos>(pos => pos.X >= 0 && pos.X < mapWidth && pos.Y >= 0 && pos.Y < mapHeight))).Returns(true);
|
|
||||||
|
|
||||||
return map.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWorld BuildFakeWorld(IMap map)
|
|
||||||
{
|
|
||||||
var world = new Mock<IWorld>();
|
|
||||||
world.SetupGet(m => m.Map).Returns(map);
|
|
||||||
world.SetupGet(m => m.WorldActor).Returns(new Mock<IActor>().Object);
|
|
||||||
return world.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsValidPos(CPos pos, int mapWidth, int mapHeight)
|
|
||||||
{
|
|
||||||
return pos.X >= 0 && pos.X < mapWidth && pos.Y >= 0 && pos.Y < mapHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
[Ignore]
|
|
||||||
public void FindPathOnRoughTerrainTest()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
|
|
||||||
// Create the MobileInfo Mock. Playing with this can help to
|
|
||||||
// check the different paths and points a unit can walk into
|
|
||||||
var mi = new FakeMobileInfo(pos => !(!IsValidPos(pos, Width, Height) ||
|
|
||||||
(pos.X == 50 && pos.Y < 100) ||
|
|
||||||
(pos.X == 100 && pos.Y > 50)));
|
|
||||||
|
|
||||||
var from = new CPos(1, 1);
|
|
||||||
var target = new CPos(125, 75);
|
|
||||||
|
|
||||||
IPathSearch search;
|
|
||||||
Stopwatch stopwatch;
|
|
||||||
List<CPos> path5 = null;
|
|
||||||
List<CPos> path6 = null;
|
|
||||||
List<CPos> path7 = null;
|
|
||||||
List<CPos> path8 = null;
|
|
||||||
var pathfinder = new PathFinder(world);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
stopwatch = new Stopwatch();
|
|
||||||
foreach (var a in Enumerable.Range(1, 50))
|
|
||||||
{
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, from, target, true);
|
|
||||||
stopwatch.Start();
|
|
||||||
path5 = pathfinder.FindPath(search);
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, new CPos(0, 0), new CPos(51, 100), true);
|
|
||||||
stopwatch.Start();
|
|
||||||
path6 = pathfinder.FindPath(search);
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, new CPos(0, 0), new CPos(49, 50), true);
|
|
||||||
stopwatch.Start();
|
|
||||||
path7 = pathfinder.FindPath(search);
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, new CPos(127, 0), new CPos(50, 101), true);
|
|
||||||
stopwatch.Start();
|
|
||||||
path8 = pathfinder.FindPath(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("I took " + stopwatch.ElapsedMilliseconds + " ms with new pathfinder");
|
|
||||||
|
|
||||||
IPathSearch search2;
|
|
||||||
stopwatch = new Stopwatch();
|
|
||||||
foreach (var a in Enumerable.Range(1, 50))
|
|
||||||
{
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, from, target, true);
|
|
||||||
search2 = PathSearch.FromPoint(world, mi, actor, target, from, true).Reverse();
|
|
||||||
stopwatch.Start();
|
|
||||||
path5 = pathfinder.FindBidiPath(search, search2);
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, new CPos(0, 0), new CPos(51, 100), true);
|
|
||||||
search2 = PathSearch.FromPoint(world, mi, actor, new CPos(51, 100), new CPos(0, 0), true).Reverse();
|
|
||||||
stopwatch.Start();
|
|
||||||
path6 = pathfinder.FindBidiPath(search, search2);
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, new CPos(0, 0), new CPos(49, 50), true);
|
|
||||||
search2 = PathSearch.FromPoint(world, mi, actor, new CPos(49, 50), new CPos(0, 0), true).Reverse();
|
|
||||||
stopwatch.Start();
|
|
||||||
path7 = pathfinder.FindBidiPath(search, search2);
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
search = PathSearch.FromPoint(world, mi, actor, new CPos(127, 0), new CPos(50, 101), true);
|
|
||||||
search2 = PathSearch.FromPoint(world, mi, actor, new CPos(50, 101), new CPos(127, 0), true).Reverse();
|
|
||||||
stopwatch.Start();
|
|
||||||
path8 = pathfinder.FindBidiPath(search, search2);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("I took " + stopwatch.ElapsedMilliseconds + " ms with new FindBidipathfinder");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// We can't rely on floating point math to be deterministic across all runtimes.
|
|
||||||
/// The cases that use this will need to be changed to use integer math
|
|
||||||
/// </summary>
|
|
||||||
public const double Sqrt2 = 1.414;
|
|
||||||
|
|
||||||
static int Est1(CPos here, CPos destination)
|
|
||||||
{
|
|
||||||
var diag = Math.Min(Math.Abs(here.X - destination.X), Math.Abs(here.Y - destination.Y));
|
|
||||||
var straight = Math.Abs(here.X - destination.X) + Math.Abs(here.Y - destination.Y);
|
|
||||||
|
|
||||||
// Min cost to arrive from once cell to an adjacent one
|
|
||||||
// (125 according to tests)
|
|
||||||
const int D = 100;
|
|
||||||
|
|
||||||
// According to the information link, this is the shape of the function.
|
|
||||||
// We just extract factors to simplify.
|
|
||||||
var h = D * straight + (D * Sqrt2 - 2 * D) * diag;
|
|
||||||
|
|
||||||
return (int)(h * 1.001);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int Est2(CPos here, CPos destination)
|
|
||||||
{
|
|
||||||
var diag = Math.Min(Math.Abs(here.X - destination.X), Math.Abs(here.Y - destination.Y));
|
|
||||||
var straight = Math.Abs(here.X - destination.X) + Math.Abs(here.Y - destination.Y);
|
|
||||||
|
|
||||||
// HACK: this relies on fp and cell-size assumptions.
|
|
||||||
var h = (100 * diag * Sqrt2) + 100 * (straight - (2 * diag));
|
|
||||||
return (int)(h * 1.001);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tests the refactor of the default heuristic for pathFinder
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void EstimatorsTest()
|
|
||||||
{
|
|
||||||
Assert.AreEqual(Est1(new CPos(0, 0), new CPos(20, 30)), Est2(new CPos(0, 0), new CPos(20, 30)));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Remove1000StoredPaths()
|
|
||||||
{
|
|
||||||
var world = new Mock<IWorld>();
|
|
||||||
world.SetupGet(m => m.WorldTick).Returns(50);
|
|
||||||
var pathCacheStorage = new PathCacheStorage(world.Object);
|
|
||||||
var stopwatch = new Stopwatch();
|
|
||||||
for (var i = 0; i < 1100; i++)
|
|
||||||
{
|
|
||||||
if (i == 100)
|
|
||||||
{
|
|
||||||
// Let's make the world tick further so we can trigger the removals
|
|
||||||
// when storing more stuff
|
|
||||||
world.SetupGet(m => m.WorldTick).Returns(110);
|
|
||||||
stopwatch.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
pathCacheStorage.Store(i.ToString(), new List<CPos>());
|
|
||||||
if (i == 100)
|
|
||||||
{
|
|
||||||
stopwatch.Stop();
|
|
||||||
Console.WriteLine("I took " + stopwatch.ElapsedMilliseconds + " ms to remove 1000 stored paths");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test for the future feature of path smoothing for Pathfinder
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void RayCastingTest()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var sut = new RayCaster();
|
|
||||||
CPos source = new CPos(1, 3);
|
|
||||||
CPos target = new CPos(3, 0);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var valid = sut.RayCast(source, target);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RayCaster
|
|
||||||
{
|
|
||||||
// Algorithm obtained in http://playtechs.blogspot.co.uk/2007/03/raytracing-on-grid.html
|
|
||||||
public IEnumerable<CPos> RayCast(CPos source, CPos target)
|
|
||||||
{
|
|
||||||
int dx = Math.Abs(target.X - source.X);
|
|
||||||
int dy = Math.Abs(target.Y - source.Y);
|
|
||||||
int x = source.X;
|
|
||||||
int y = source.Y;
|
|
||||||
|
|
||||||
int x_inc = (target.X > source.X) ? 1 : -1;
|
|
||||||
int y_inc = (target.Y > source.Y) ? 1 : -1;
|
|
||||||
int error = dx - dy;
|
|
||||||
dx *= 2;
|
|
||||||
dy *= 2;
|
|
||||||
|
|
||||||
for (int n = 1 + dx + dy; n > 0; --n)
|
|
||||||
{
|
|
||||||
yield return new CPos(x, y);
|
|
||||||
|
|
||||||
if (error > 0)
|
|
||||||
{
|
|
||||||
x += x_inc;
|
|
||||||
error -= dy;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
y += y_inc;
|
|
||||||
error += dx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RayClear()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user