Introduced the interfaces IActor, ICacheStorage, ILog, IMap, IWorld a…

nd IMobileInfo to separate concrete implementations and abstractions
This commit is contained in:
David Jiménez
2015-02-20 08:21:43 +01:00
committed by Rydra
parent 85fae8720d
commit 8659a3e71e
7 changed files with 221 additions and 30 deletions

View File

@@ -22,14 +22,36 @@ using OpenRA.Traits;
namespace OpenRA
{
public class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>
public interface IActor
{
public readonly ActorInfo Info;
ActorInfo Info { get; }
IWorld World { get; }
uint ActorID { get; }
Player Owner { get; set; }
T TraitOrDefault<T>();
T Trait<T>();
IEnumerable<T> TraitsImplementing<T>();
T TraitInfo<T>();
IEnumerable<IRenderable> Render(WorldRenderer wr);
}
public class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>, IActor
{
public ActorInfo Info { get; private set; }
public readonly World World;
public readonly uint ActorID;
IWorld IActor.World
{
get { return World; }
}
public uint ActorID { get; private set; }
[Sync]
public Player Owner;
public Player Owner { get; set; }
public bool IsInWorld { get; internal set; }
public bool Destroyed { get; private set; }
@@ -202,6 +224,11 @@ namespace OpenRA
return World.TraitDict.WithInterface<T>(this);
}
public T TraitInfo<T>()
{
return Info.Traits.Get<T>();
}
public bool HasTrait<T>()
{
return World.TraitDict.Contains<T>(this);
@@ -235,7 +262,7 @@ namespace OpenRA
{
World.AddFrameEndTask(w =>
{
if (this.Destroyed)
if (Destroyed)
return;
var oldOwner = Owner;

View File

@@ -0,0 +1,19 @@
#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
namespace OpenRA
{
public interface ICacheStorage<T>
{
void Remove(string key);
void Store(string key, T data);
T Retrieve(string key);
}
}

25
OpenRA.Game/LogProxy.cs Normal file
View File

@@ -0,0 +1,25 @@
#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
namespace OpenRA
{
public interface ILog
{
void Write(string channel, string format, params object[] args);
}
public class LogProxy : ILog
{
public void Write(string channel, string format, params object[] args)
{
Log.Write(channel, format, args);
}
}
}

View File

@@ -111,15 +111,33 @@ namespace OpenRA
MissionSelector = 4
}
public class Map
public interface IMap
{
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
{
public const int MaxTilesInCircleRange = 50;
public readonly TileShape TileShape;
TileShape IMap.TileShape
{
get { return TileShape; }
}
[FieldLoader.Ignore]
public readonly WVec[] SubCellOffsets;
public readonly SubCell DefaultSubCell;
public readonly SubCell LastSubCell;
[FieldLoader.Ignore] public IFolder Container;
[FieldLoader.Ignore]
public IFolder Container;
public string Path { get; private set; }
// Yaml map data
@@ -165,41 +183,65 @@ namespace OpenRA
return videos;
}
[FieldLoader.Ignore] public Lazy<Dictionary<string, ActorReference>> Actors;
[FieldLoader.Ignore]
public Lazy<Dictionary<string, ActorReference>> Actors;
public int PlayerCount { get { return Players.Count(p => p.Value.Playable); } }
public Rectangle Bounds;
// Yaml map data
[FieldLoader.Ignore] public Dictionary<string, PlayerReference> Players = new Dictionary<string, PlayerReference>();
[FieldLoader.Ignore] public Lazy<List<SmudgeReference>> Smudges;
[FieldLoader.Ignore]
public Dictionary<string, PlayerReference> Players = new Dictionary<string, PlayerReference>();
[FieldLoader.Ignore]
public Lazy<List<SmudgeReference>> Smudges;
[FieldLoader.Ignore] public List<MiniYamlNode> RuleDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> SequenceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> VoxelSequenceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> WeaponDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> VoiceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> NotificationDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> TranslationDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore]
public List<MiniYamlNode> RuleDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore]
public List<MiniYamlNode> SequenceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore]
public List<MiniYamlNode> VoxelSequenceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore]
public List<MiniYamlNode> WeaponDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore]
public List<MiniYamlNode> VoiceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore]
public List<MiniYamlNode> NotificationDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore]
public List<MiniYamlNode> TranslationDefinitions = new List<MiniYamlNode>();
// Binary map data
[FieldLoader.Ignore] public byte TileFormat = 2;
[FieldLoader.Ignore]
public byte TileFormat = 2;
public int2 MapSize;
[FieldLoader.Ignore] public Lazy<CellLayer<TerrainTile>> MapTiles;
[FieldLoader.Ignore] public Lazy<CellLayer<ResourceTile>> MapResources;
[FieldLoader.Ignore] public Lazy<CellLayer<byte>> MapHeight;
int2 IMap.MapSize
{
get { return MapSize; }
set { MapSize = value; }
}
[FieldLoader.Ignore] public CellLayer<byte> CustomTerrain;
[FieldLoader.Ignore]
public Lazy<CellLayer<TerrainTile>> MapTiles;
[FieldLoader.Ignore]
public Lazy<CellLayer<ResourceTile>> MapResources;
[FieldLoader.Ignore]
public Lazy<CellLayer<byte>> MapHeight;
[FieldLoader.Ignore] Lazy<TileSet> cachedTileSet;
[FieldLoader.Ignore] Lazy<Ruleset> rules;
[FieldLoader.Ignore]
public CellLayer<byte> CustomTerrain;
[FieldLoader.Ignore]
Lazy<TileSet> cachedTileSet;
[FieldLoader.Ignore]
Lazy<Ruleset> rules;
public Ruleset Rules { get { return rules != null ? rules.Value : null; } }
public SequenceProvider SequenceProvider { get { return Rules.Sequences[Tileset]; } }
[FieldLoader.Ignore] public CellRegion Cells;
[FieldLoader.Ignore]
public CellRegion Cells;
public static Map FromTileset(TileSet tileset)
{

View File

@@ -84,6 +84,8 @@
<Compile Include="Activities\Activity.cs" />
<Compile Include="Activities\CallFunc.cs" />
<Compile Include="Actor.cs" />
<Compile Include="CacheStorage.cs" />
<Compile Include="LogProxy.cs" />
<Compile Include="MPos.cs" />
<Compile Include="GameRules\Warhead.cs" />
<Compile Include="Graphics\QuadRenderer.cs" />

View File

@@ -24,7 +24,15 @@ namespace OpenRA
{
public enum WorldType { Regular, Shellmap }
public class World
public interface IWorld
{
IActor WorldActor { get; }
int WorldTick { get; }
IMap Map { get; }
TileSet TileSet { get; }
}
public class World : IWorld
{
class ActorIDComparer : IComparer<Actor>
{
@@ -113,9 +121,13 @@ namespace OpenRA
RenderPlayer = LocalPlayer;
}
public readonly Actor WorldActor;
public readonly Map Map;
public readonly TileSet TileSet;
public Actor WorldActor { get; private set; }
IActor IWorld.WorldActor { get { return WorldActor; } }
public Map Map { get; private set; }
IMap IWorld.Map { get { return Map; } }
public TileSet TileSet { get; private set; }
public readonly ActorMap ActorMap;
public readonly ScreenMap ScreenMap;
public readonly WorldType Type;

View File

@@ -29,8 +29,17 @@ namespace OpenRA.Mods.Common.Traits
All = TransientActors | BlockedByMovers
}
public interface IMobileInfo
{
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.")]
public class MobileInfo : ITraitInfo, IOccupySpaceInfo, IFacingInfo, IMoveInfo, UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>
public class MobileInfo : ITraitInfo, IOccupySpaceInfo, IFacingInfo, IMoveInfo, UsesInit<FacingInit>, UsesInit<LocationInit>, UsesInit<SubCellInit>, IMobileInfo
{
[FieldLoader.LoadUsing("LoadSpeeds")]
[Desc("Set Water: 0 for ground units and lower the value on rough terrain.")]
@@ -165,11 +174,61 @@ namespace OpenRA.Mods.Common.Traits
return true;
}
public int TileSetMovementHash(TileSet tileSet)
{
var terrainInfos = TilesetTerrainInfo[tileSet];
// Compute and return the hash using aggregate
return terrainInfos.Aggregate(terrainInfos.Length,
(current, terrainInfo) => unchecked(current * 31 + terrainInfo.Cost));
}
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All)
{
if (MovementCostForCell(world, cell) == int.MaxValue)
return false;
return CanMoveFreelyInto(world, self, cell, ignoreActor, check);
}
// Determines whether the actor is blocked by other Actors
public bool CanMoveFreelyInto(World world, Actor self, CPos cell, Actor ignoreActor, CellConditions check)
{
if (SharesCell && world.ActorMap.HasFreeSubCell(cell))
return true;
if (check.HasFlag(CellConditions.TransientActors))
{
var canIgnoreMovingAllies = self != null && !check.HasFlag(CellConditions.BlockedByMovers);
var needsCellExclusively = self == null || Crushes == null || !Crushes.Any();
foreach (var a in world.ActorMap.GetUnitsAt(cell))
{
if (a == ignoreActor)
continue;
// Neutral/enemy units are blockers. Allied units that are moving are not blockers.
if (canIgnoreMovingAllies && self.Owner.Stances[a.Owner] == Stance.Ally && IsMovingInMyDirection(self, a)) continue;
// Non-sharable unit can enter a cell with shareable units only if it can crush all of them.
if (needsCellExclusively)
return false;
var crushables = a.TraitsImplementing<ICrushable>();
if (!crushables.Any())
return false;
foreach (var crushable in crushables)
if (!crushable.CrushableBy(Crushes, self.Owner))
return false;
}
}
return true;
}
public bool CanEnterCell(World world, Actor self, CPos cell, out int movementCost, Actor ignoreActor = null, CellConditions check = CellConditions.All)
{
if ((movementCost = MovementCostForCell(world, cell)) == int.MaxValue)
return false;
if (SharesCell && world.ActorMap.HasFreeSubCell(cell))
return true;
@@ -506,6 +565,11 @@ namespace OpenRA.Mods.Common.Traits
return Info.CanEnterCell(self.World, self, cell, ignoreActor, checkTransientActors ? CellConditions.All : CellConditions.BlockedByMovers);
}
public bool CanMoveFreely(CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)
{
return Info.CanMoveFreelyInto(self.World, self, cell, ignoreActor, checkTransientActors ? CellConditions.All : CellConditions.BlockedByMovers);
}
public void EnteringCell(Actor self)
{
var crushables = self.World.ActorMap.GetUnitsAt(ToCell).Where(a => a != self)