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 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 World World;
public readonly uint ActorID;
IWorld IActor.World
{
get { return World; }
}
public uint ActorID { get; private set; }
[Sync] [Sync]
public Player Owner; public Player Owner { get; set; }
public bool IsInWorld { get; internal set; } public bool IsInWorld { get; internal set; }
public bool Destroyed { get; private set; } public bool Destroyed { get; private set; }
@@ -202,6 +224,11 @@ namespace OpenRA
return World.TraitDict.WithInterface<T>(this); return World.TraitDict.WithInterface<T>(this);
} }
public T TraitInfo<T>()
{
return Info.Traits.Get<T>();
}
public bool HasTrait<T>() public bool HasTrait<T>()
{ {
return World.TraitDict.Contains<T>(this); return World.TraitDict.Contains<T>(this);
@@ -235,7 +262,7 @@ namespace OpenRA
{ {
World.AddFrameEndTask(w => World.AddFrameEndTask(w =>
{ {
if (this.Destroyed) if (Destroyed)
return; return;
var oldOwner = Owner; 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 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 const int MaxTilesInCircleRange = 50;
public readonly TileShape TileShape; public readonly TileShape TileShape;
TileShape IMap.TileShape
{
get { return TileShape; }
}
[FieldLoader.Ignore] [FieldLoader.Ignore]
public readonly WVec[] SubCellOffsets; public readonly WVec[] SubCellOffsets;
public readonly SubCell DefaultSubCell; public readonly SubCell DefaultSubCell;
public readonly SubCell LastSubCell; public readonly SubCell LastSubCell;
[FieldLoader.Ignore] public IFolder Container; [FieldLoader.Ignore]
public IFolder Container;
public string Path { get; private set; } public string Path { get; private set; }
// Yaml map data // Yaml map data
@@ -165,41 +183,65 @@ namespace OpenRA
return videos; 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 int PlayerCount { get { return Players.Count(p => p.Value.Playable); } }
public Rectangle Bounds; public Rectangle Bounds;
// Yaml map data // Yaml map data
[FieldLoader.Ignore] public Dictionary<string, PlayerReference> Players = new Dictionary<string, PlayerReference>(); [FieldLoader.Ignore]
[FieldLoader.Ignore] public Lazy<List<SmudgeReference>> Smudges; 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]
[FieldLoader.Ignore] public List<MiniYamlNode> SequenceDefinitions = new List<MiniYamlNode>(); public List<MiniYamlNode> RuleDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> VoxelSequenceDefinitions = new List<MiniYamlNode>(); [FieldLoader.Ignore]
[FieldLoader.Ignore] public List<MiniYamlNode> WeaponDefinitions = new List<MiniYamlNode>(); public List<MiniYamlNode> SequenceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> VoiceDefinitions = new List<MiniYamlNode>(); [FieldLoader.Ignore]
[FieldLoader.Ignore] public List<MiniYamlNode> NotificationDefinitions = new List<MiniYamlNode>(); public List<MiniYamlNode> VoxelSequenceDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> TranslationDefinitions = 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 // Binary map data
[FieldLoader.Ignore] public byte TileFormat = 2; [FieldLoader.Ignore]
public byte TileFormat = 2;
public int2 MapSize; public int2 MapSize;
[FieldLoader.Ignore] public Lazy<CellLayer<TerrainTile>> MapTiles; int2 IMap.MapSize
[FieldLoader.Ignore] public Lazy<CellLayer<ResourceTile>> MapResources; {
[FieldLoader.Ignore] public Lazy<CellLayer<byte>> MapHeight; 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]
[FieldLoader.Ignore] Lazy<Ruleset> rules; 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 Ruleset Rules { get { return rules != null ? rules.Value : null; } }
public SequenceProvider SequenceProvider { get { return Rules.Sequences[Tileset]; } } public SequenceProvider SequenceProvider { get { return Rules.Sequences[Tileset]; } }
[FieldLoader.Ignore] public CellRegion Cells; [FieldLoader.Ignore]
public CellRegion Cells;
public static Map FromTileset(TileSet tileset) public static Map FromTileset(TileSet tileset)
{ {

View File

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

View File

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

View File

@@ -29,8 +29,17 @@ namespace OpenRA.Mods.Common.Traits
All = TransientActors | BlockedByMovers 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.")] [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")] [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.")]
@@ -165,11 +174,61 @@ namespace OpenRA.Mods.Common.Traits
return true; 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) public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All)
{ {
if (MovementCostForCell(world, cell) == int.MaxValue) if (MovementCostForCell(world, cell) == int.MaxValue)
return false; 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)) if (SharesCell && world.ActorMap.HasFreeSubCell(cell))
return true; return true;
@@ -506,6 +565,11 @@ namespace OpenRA.Mods.Common.Traits
return Info.CanEnterCell(self.World, self, cell, ignoreActor, checkTransientActors ? CellConditions.All : CellConditions.BlockedByMovers); 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) public void EnteringCell(Actor self)
{ {
var crushables = self.World.ActorMap.GetUnitsAt(ToCell).Where(a => a != self) var crushables = self.World.ActorMap.GetUnitsAt(ToCell).Where(a => a != self)