Add ISingleInstanceInit interface.

Inits that are logically singletons (e.g. actor
location or owner) should implement this interface
to avoid runtime inconsistencies.

Duplicate instances are rejected at init-time,
allowing simpler queries when they are used.
This commit is contained in:
Paul Chote
2020-05-30 16:48:35 +01:00
committed by reaperrr
parent 86305879cb
commit b856613194
45 changed files with 169 additions and 95 deletions

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using Eluant; using Eluant;
using Eluant.ObjectBinding; using Eluant.ObjectBinding;
@@ -116,13 +117,19 @@ namespace OpenRA
internal Actor(World world, string name, TypeDictionary initDict) internal Actor(World world, string name, TypeDictionary initDict)
{ {
var duplicateInit = initDict.WithInterface<ISingleInstanceInit>().GroupBy(i => i.GetType())
.FirstOrDefault(i => i.Count() > 1);
if (duplicateInit != null)
throw new InvalidDataException("Duplicate initializer '{0}'".F(duplicateInit.Key.Name));
var init = new ActorInitializer(this, initDict); var init = new ActorInitializer(this, initDict);
readOnlyConditionCache = new ReadOnlyDictionary<string, int>(conditionCache); readOnlyConditionCache = new ReadOnlyDictionary<string, int>(conditionCache);
World = world; World = world;
ActorID = world.NextAID(); ActorID = world.NextAID();
var ownerInit = init.GetOrDefault<OwnerInit>(null); var ownerInit = init.GetOrDefault<OwnerInit>();
if (ownerInit != null) if (ownerInit != null)
Owner = ownerInit.Value(world); Owner = ownerInit.Value(world);

View File

@@ -26,6 +26,12 @@ namespace OpenRA
U GetValue<T, U>(TraitInfo info) where T : ValueActorInit<U>; U GetValue<T, U>(TraitInfo info) where T : ValueActorInit<U>;
U GetValue<T, U>(TraitInfo info, U fallback) where T : ValueActorInit<U>; U GetValue<T, U>(TraitInfo info, U fallback) where T : ValueActorInit<U>;
bool Contains<T>(TraitInfo info) where T : ActorInit; bool Contains<T>(TraitInfo info) where T : ActorInit;
T GetOrDefault<T>() where T : ActorInit, ISingleInstanceInit;
T Get<T>() where T : ActorInit, ISingleInstanceInit;
U GetValue<T, U>() where T : ValueActorInit<U>, ISingleInstanceInit;
U GetValue<T, U>(U fallback) where T : ValueActorInit<U>, ISingleInstanceInit;
bool Contains<T>() where T : ActorInit, ISingleInstanceInit;
} }
public class ActorInitializer : IActorInitializer public class ActorInitializer : IActorInitializer
@@ -77,6 +83,29 @@ namespace OpenRA
} }
public bool Contains<T>(TraitInfo info) where T : ActorInit { return GetOrDefault<T>(info) != null; } public bool Contains<T>(TraitInfo info) where T : ActorInit { return GetOrDefault<T>(info) != null; }
public T GetOrDefault<T>() where T : ActorInit, ISingleInstanceInit
{
return Dict.GetOrDefault<T>();
}
public T Get<T>() where T : ActorInit, ISingleInstanceInit
{
return Dict.Get<T>();
}
public U GetValue<T, U>() where T : ValueActorInit<U>, ISingleInstanceInit
{
return Get<T>().Value;
}
public U GetValue<T, U>(U fallback) where T : ValueActorInit<U>, ISingleInstanceInit
{
var init = GetOrDefault<T>();
return init != null ? init.Value : fallback;
}
public bool Contains<T>() where T : ActorInit, ISingleInstanceInit { return GetOrDefault<T>() != null; }
} }
/* /*
@@ -88,6 +117,9 @@ namespace OpenRA
* finds with an argument type that matches the given LuaValue. * finds with an argument type that matches the given LuaValue.
* - Most ActorInits will want to inherit either ValueActorInit<T> or CompositeActorInit which hide the low-level plumbing. * - Most ActorInits will want to inherit either ValueActorInit<T> or CompositeActorInit which hide the low-level plumbing.
* - Inits that reference actors should use ActorInitActorReference which allows actors to be referenced by name in map.yaml * - Inits that reference actors should use ActorInitActorReference which allows actors to be referenced by name in map.yaml
* - Inits that should only have a single instance defined on an actor should implement ISingleInstanceInit to allow
* direct queries and runtime enforcement.
* - Inits that aren't ISingleInstanceInit should expose a ctor that accepts a TraitInfo to allow per-trait targeting.
*/ */
public abstract class ActorInit public abstract class ActorInit
{ {
@@ -104,6 +136,8 @@ namespace OpenRA
public abstract MiniYaml Save(); public abstract MiniYaml Save();
} }
public interface ISingleInstanceInit { }
public abstract class ValueActorInit<T> : ActorInit public abstract class ValueActorInit<T> : ActorInit
{ {
protected readonly T value; protected readonly T value;
@@ -181,16 +215,13 @@ namespace OpenRA
} }
} }
public class LocationInit : ValueActorInit<CPos> public class LocationInit : ValueActorInit<CPos>, ISingleInstanceInit
{ {
public LocationInit(TraitInfo info, CPos value)
: base(info, value) { }
public LocationInit(CPos value) public LocationInit(CPos value)
: base(value) { } : base(value) { }
} }
public class OwnerInit : ActorInit public class OwnerInit : ActorInit, ISingleInstanceInit
{ {
public readonly string InternalName; public readonly string InternalName;
protected readonly Player value; protected readonly Player value;

View File

@@ -40,7 +40,14 @@ namespace OpenRA
{ {
var dict = new TypeDictionary(); var dict = new TypeDictionary();
foreach (var i in inits) foreach (var i in inits)
dict.Add(LoadInit(i.Key, i.Value)); {
var init = LoadInit(i.Key, i.Value);
if (init is ISingleInstanceInit && dict.Contains(init.GetType()))
throw new InvalidDataException("Duplicate initializer '{0}'".F(init.GetType().Name));
dict.Add(init);
}
return dict; return dict;
}); });
} }
@@ -88,7 +95,14 @@ namespace OpenRA
} }
// for initialization syntax // for initialization syntax
public void Add(object o) { InitDict.Add(o); } public void Add(ActorInit init)
{
if (init is ISingleInstanceInit && InitDict.Contains(init.GetType()))
throw new InvalidDataException("Duplicate initializer '{0}'".F(init.GetType().Name));
InitDict.Add(init);
}
public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); } public IEnumerator GetEnumerator() { return InitDict.GetEnumerator(); }
public ActorReference Clone() public ActorReference Clone()

View File

@@ -41,6 +41,11 @@ namespace OpenRA.Primitives
return data.ContainsKey(typeof(T)); return data.ContainsKey(typeof(T));
} }
public bool Contains(Type t)
{
return data.ContainsKey(t);
}
public T Get<T>() public T Get<T>()
{ {
return (T)Get(typeof(T), true); return (T)Get(typeof(T), true);

View File

@@ -60,7 +60,7 @@ namespace OpenRA.Mods.Cnc.Traits
{ {
self = init.Self; self = init.Self;
var returnInit = init.GetOrDefault<ChronoshiftReturnInit>(info); var returnInit = init.GetOrDefault<ChronoshiftReturnInit>();
if (returnInit != null) if (returnInit != null)
{ {
ReturnTicks = returnInit.Ticks; ReturnTicks = returnInit.Ticks;
@@ -176,7 +176,7 @@ namespace OpenRA.Mods.Cnc.Traits
void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); } void ITransformActorInitModifier.ModifyTransformActorInit(Actor self, TypeDictionary init) { ModifyActorInit(init); }
} }
public class ChronoshiftReturnInit : CompositeActorInit public class ChronoshiftReturnInit : CompositeActorInit, ISingleInstanceInit
{ {
public readonly int Ticks; public readonly int Ticks;
public readonly int Duration; public readonly int Duration;

View File

@@ -95,9 +95,9 @@ namespace OpenRA.Mods.Cnc.Traits
health = self.Trait<Health>(); health = self.Trait<Health>();
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
faction = init.GetValue<FactionInit, string>(info, self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(self.Owner.Faction.InternalName);
var returnInit = init.GetOrDefault<ChronoshiftReturnInit>(info); var returnInit = init.GetOrDefault<ChronoshiftReturnInit>();
if (returnInit != null) if (returnInit != null)
{ {
returnTicks = returnInit.Ticks; returnTicks = returnInit.Ticks;

View File

@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Cnc.Traits
public InfiltrateForTransform(ActorInitializer init, InfiltrateForTransformInfo info) public InfiltrateForTransform(ActorInitializer init, InfiltrateForTransformInfo info)
{ {
this.info = info; this.info = info;
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
void INotifyInfiltrated.Infiltrated(Actor self, Actor infiltrator, BitSet<TargetableType> types) void INotifyInfiltrated.Infiltrated(Actor self, Actor infiltrator, BitSet<TargetableType> types)

View File

@@ -45,7 +45,7 @@ namespace OpenRA.Mods.Cnc.Traits
var bibOffset = bi.Dimensions.Y - rows; var bibOffset = bi.Dimensions.Y - rows;
var centerOffset = bi.CenterOffset(init.World); var centerOffset = bi.CenterOffset(init.World);
var map = init.World.Map; var map = init.World.Map;
var location = init.GetValue<LocationInit, CPos>(this, CPos.Zero); var location = init.GetValue<LocationInit, CPos>(CPos.Zero);
for (var i = 0; i < rows * width; i++) for (var i = 0; i < rows * width; i++)
{ {

View File

@@ -82,15 +82,15 @@ namespace OpenRA.Mods.Cnc.Traits
Info = info; Info = info;
self = init.Self; self = init.Self;
var locationInit = init.GetOrDefault<LocationInit>(info); var locationInit = init.GetOrDefault<LocationInit>();
if (locationInit != null) if (locationInit != null)
SetPosition(self, locationInit.Value); SetPosition(self, locationInit.Value);
var centerPositionInit = init.GetOrDefault<CenterPositionInit>(info); var centerPositionInit = init.GetOrDefault<CenterPositionInit>();
if (centerPositionInit != null) if (centerPositionInit != null)
SetPosition(self, centerPositionInit.Value); SetPosition(self, centerPositionInit.Value);
Facing = WAngle.FromFacing(init.GetValue<FacingInit, int>(info, Info.GetInitialFacing())); Facing = WAngle.FromFacing(init.GetValue<FacingInit, int>(Info.GetInitialFacing()));
// Prevent mappers from setting bogus facings // Prevent mappers from setting bogus facings
if (Facing != Left && Facing != Right) if (Facing != Left && Facing != Right)

View File

@@ -16,38 +16,38 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common namespace OpenRA.Mods.Common
{ {
public class FacingInit : ValueActorInit<int> public class FacingInit : ValueActorInit<int>, ISingleInstanceInit
{ {
public FacingInit(int value) public FacingInit(int value)
: base(value) { } : base(value) { }
} }
public class CreationActivityDelayInit : ValueActorInit<int> public class CreationActivityDelayInit : ValueActorInit<int>, ISingleInstanceInit
{ {
public CreationActivityDelayInit(int value) public CreationActivityDelayInit(int value)
: base(value) { } : base(value) { }
} }
public class DynamicFacingInit : ValueActorInit<Func<int>> public class DynamicFacingInit : ValueActorInit<Func<int>>, ISingleInstanceInit
{ {
public DynamicFacingInit(Func<int> value) public DynamicFacingInit(Func<int> value)
: base(value) { } : base(value) { }
} }
public class SubCellInit : ValueActorInit<SubCell> public class SubCellInit : ValueActorInit<SubCell>, ISingleInstanceInit
{ {
public SubCellInit(SubCell value) public SubCellInit(SubCell value)
: base(value) { } : base(value) { }
} }
public class CenterPositionInit : ValueActorInit<WPos> public class CenterPositionInit : ValueActorInit<WPos>, ISingleInstanceInit
{ {
public CenterPositionInit(WPos value) public CenterPositionInit(WPos value)
: base(value) { } : base(value) { }
} }
// Allows maps / transformations to specify the faction variant of an actor. // Allows maps / transformations to specify the faction variant of an actor.
public class FactionInit : ValueActorInit<string> public class FactionInit : ValueActorInit<string>, ISingleInstanceInit
{ {
public FactionInit(string value) public FactionInit(string value)
: base(value) { } : base(value) { }

View File

@@ -77,6 +77,29 @@ namespace OpenRA.Mods.Common.Graphics
return init != null ? init.Value : fallback; return init != null ? init.Value : fallback;
} }
public bool Contains<T>() where T : ActorInit, ISingleInstanceInit { return GetOrDefault<T>() != null; }
public T GetOrDefault<T>() where T : ActorInit, ISingleInstanceInit
{
return dict.GetOrDefault<T>();
}
public T Get<T>() where T : ActorInit, ISingleInstanceInit
{
return dict.Get<T>();
}
public U GetValue<T, U>() where T : ValueActorInit<U>, ISingleInstanceInit
{
return Get<T>().Value;
}
public U GetValue<T, U>(U fallback) where T : ValueActorInit<U>, ISingleInstanceInit
{
var init = GetOrDefault<T>();
return init != null ? init.Value : fallback;
}
public bool Contains<T>(TraitInfo info) where T : ActorInit { return GetOrDefault<T>(info) != null; } public bool Contains<T>(TraitInfo info) where T : ActorInit { return GetOrDefault<T>(info) != null; }
public Func<WRot> GetOrientation() public Func<WRot> GetOrientation()

View File

@@ -249,16 +249,16 @@ namespace OpenRA.Mods.Common.Traits
{ {
self = init.Self; self = init.Self;
var locationInit = init.GetOrDefault<LocationInit>(info); var locationInit = init.GetOrDefault<LocationInit>();
if (locationInit != null) if (locationInit != null)
SetPosition(self, locationInit.Value); SetPosition(self, locationInit.Value);
var centerPositionInit = init.GetOrDefault<CenterPositionInit>(info); var centerPositionInit = init.GetOrDefault<CenterPositionInit>();
if (centerPositionInit != null) if (centerPositionInit != null)
SetPosition(self, centerPositionInit.Value); SetPosition(self, centerPositionInit.Value);
Facing = WAngle.FromFacing(init.GetValue<FacingInit, int>(info, Info.InitialFacing)); Facing = WAngle.FromFacing(init.GetValue<FacingInit, int>(Info.InitialFacing));
creationActivityDelay = init.GetValue<CreationActivityDelayInit, int>(info, 0); creationActivityDelay = init.GetValue<CreationActivityDelayInit, int>(0);
} }
public WDist LandAltitude public WDist LandAltitude

View File

@@ -183,7 +183,7 @@ namespace OpenRA.Mods.Common.Traits
var self = init.Self; var self = init.Self;
ActiveAttackBases = self.TraitsImplementing<AttackBase>().ToArray().Where(Exts.IsTraitEnabled); ActiveAttackBases = self.TraitsImplementing<AttackBase>().ToArray().Where(Exts.IsTraitEnabled);
stance = init.GetValue<StanceInit, UnitStance>(info, self.Owner.IsBot || !self.Owner.Playable ? info.InitialStanceAI : info.InitialStance); stance = init.GetValue<StanceInit, UnitStance>(self.Owner.IsBot || !self.Owner.Playable ? info.InitialStanceAI : info.InitialStance);
PredictedStance = stance; PredictedStance = stance;
@@ -445,7 +445,7 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class StanceInit : ValueActorInit<UnitStance> public class StanceInit : ValueActorInit<UnitStance>, ISingleInstanceInit
{ {
public StanceInit(TraitInfo info, UnitStance value) public StanceInit(TraitInfo info, UnitStance value)
: base(info, value) { } : base(info, value) { }

View File

@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
this.info = info; this.info = info;
var self = init.Self; var self = init.Self;
var faction = init.GetValue<FactionInit, string>(info, self.Owner.Faction.InternalName); var faction = init.GetValue<FactionInit, string>(self.Owner.Faction.InternalName);
quantizedFacings = Exts.Lazy(() => quantizedFacings = Exts.Lazy(() =>
{ {

View File

@@ -278,7 +278,7 @@ namespace OpenRA.Mods.Common.Traits
public Building(ActorInitializer init, BuildingInfo info) public Building(ActorInitializer init, BuildingInfo info)
{ {
self = init.Self; self = init.Self;
topLeft = init.GetValue<LocationInit, CPos>(info); topLeft = init.GetValue<LocationInit, CPos>();
Info = info; Info = info;
influence = self.World.WorldActor.Trait<BuildingInfluence>(); influence = self.World.WorldActor.Trait<BuildingInfluence>();

View File

@@ -93,7 +93,7 @@ namespace OpenRA.Mods.Common.Traits
: base(info, value) { } : base(info, value) { }
} }
public class ParentActorInit : ValueActorInit<ActorInitActorReference> public class ParentActorInit : ValueActorInit<ActorInitActorReference>, ISingleInstanceInit
{ {
public ParentActorInit(Actor value) public ParentActorInit(Actor value)
: base(value) { } : base(value) { }

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Traits
public LegacyBridgeHut(ActorInitializer init, LegacyBridgeHutInfo info) public LegacyBridgeHut(ActorInitializer init, LegacyBridgeHutInfo info)
{ {
var bridge = init.Get<ParentActorInit>(info).Value; var bridge = init.Get<ParentActorInit>().Value;
init.World.AddFrameEndTask(_ => init.World.AddFrameEndTask(_ =>
{ {
Bridge = bridge.Actor(init.World).Value.Trait<Bridge>(); Bridge = bridge.Actor(init.World).Value.Trait<Bridge>();

View File

@@ -16,13 +16,13 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
public enum LineBuildDirection { Unset, X, Y } public enum LineBuildDirection { Unset, X, Y }
public class LineBuildDirectionInit : ValueActorInit<LineBuildDirection> public class LineBuildDirectionInit : ValueActorInit<LineBuildDirection>, ISingleInstanceInit
{ {
public LineBuildDirectionInit(LineBuildDirection value) public LineBuildDirectionInit(LineBuildDirection value)
: base(value) { } : base(value) { }
} }
public class LineBuildParentInit : ValueActorInit<string[]> public class LineBuildParentInit : ValueActorInit<string[]>, ISingleInstanceInit
{ {
readonly Actor[] parents = null; readonly Actor[] parents = null;
@@ -76,7 +76,7 @@ namespace OpenRA.Mods.Common.Traits
public LineBuild(ActorInitializer init, LineBuildInfo info) public LineBuild(ActorInitializer init, LineBuildInfo info)
{ {
this.info = info; this.info = info;
var lineBuildParentInit = init.GetOrDefault<LineBuildParentInit>(info); var lineBuildParentInit = init.GetOrDefault<LineBuildParentInit>();
if (lineBuildParentInit != null) if (lineBuildParentInit != null)
parentNodes = lineBuildParentInit.ActorValue(init.World); parentNodes = lineBuildParentInit.ActorValue(init.World);
} }

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits
}, },
(actor, value) => (actor, value) =>
{ {
actor.ReplaceInit(new DeployStateInit(this, value ? DeployState.Deployed : DeployState.Undeployed)); actor.ReplaceInit(new DeployStateInit(value ? DeployState.Deployed : DeployState.Undeployed));
}); });
} }
@@ -111,7 +111,7 @@ namespace OpenRA.Mods.Common.Traits
checkTerrainType = info.AllowedTerrainTypes.Count > 0; checkTerrainType = info.AllowedTerrainTypes.Count > 0;
canTurn = self.Info.HasTraitInfo<IFacingInfo>(); canTurn = self.Info.HasTraitInfo<IFacingInfo>();
move = self.TraitOrDefault<IMove>(); move = self.TraitOrDefault<IMove>();
deployState = init.GetValue<DeployStateInit, DeployState>(info, DeployState.Undeployed); deployState = init.GetValue<DeployStateInit, DeployState>(DeployState.Undeployed);
} }
protected override void Created(Actor self) protected override void Created(Actor self)
@@ -337,11 +337,8 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class DeployStateInit : ValueActorInit<DeployState> public class DeployStateInit : ValueActorInit<DeployState>, ISingleInstanceInit
{ {
public DeployStateInit(TraitInfo info, DeployState value)
: base(info, value) { }
public DeployStateInit(DeployState value) public DeployStateInit(DeployState value)
: base(value) { } : base(value) { }
} }

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Traits
public GrantConditionOnFaction(ActorInitializer init, GrantConditionOnFactionInfo info) public GrantConditionOnFaction(ActorInitializer init, GrantConditionOnFactionInfo info)
: base(info) : base(info)
{ {
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Traits
public GrantConditionOnLineBuildDirection(ActorInitializer init, GrantConditionOnLineBuildDirectionInfo info) public GrantConditionOnLineBuildDirection(ActorInitializer init, GrantConditionOnLineBuildDirectionInfo info)
{ {
this.info = info; this.info = info;
direction = init.GetValue<LineBuildDirectionInit, LineBuildDirection>(info); direction = init.GetValue<LineBuildDirectionInit, LineBuildDirection>();
} }
void INotifyCreated.Created(Actor self) void INotifyCreated.Created(Actor self)

View File

@@ -93,7 +93,7 @@ namespace OpenRA.Mods.Common.Traits
self = init.Self; self = init.Self;
this.info = info; this.info = info;
var locationInit = init.GetOrDefault<LocationInit>(info); var locationInit = init.GetOrDefault<LocationInit>();
if (locationInit != null) if (locationInit != null)
SetPosition(self, locationInit.Value); SetPosition(self, locationInit.Value);
} }

View File

@@ -71,7 +71,7 @@ namespace OpenRA.Mods.Common.Traits
MaxHP = hp = info.HP > 0 ? info.HP : 1; MaxHP = hp = info.HP > 0 ? info.HP : 1;
// Cast to long to avoid overflow when multiplying by the health // Cast to long to avoid overflow when multiplying by the health
var healthInit = init.GetOrDefault<HealthInit>(info); var healthInit = init.GetOrDefault<HealthInit>();
if (healthInit != null) if (healthInit != null)
hp = (int)(healthInit.Value * (long)MaxHP / 100); hp = (int)(healthInit.Value * (long)MaxHP / 100);
@@ -233,13 +233,10 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class HealthInit : ValueActorInit<int> public class HealthInit : ValueActorInit<int>, ISingleInstanceInit
{ {
readonly bool allowZero; readonly bool allowZero;
public HealthInit(TraitInfo info, int value, bool allowZero = false)
: base(info, value) { this.allowZero = allowZero; }
public HealthInit(int value, bool allowZero = false) public HealthInit(int value, bool allowZero = false)
: base(value) { this.allowZero = allowZero; } : base(value) { this.allowZero = allowZero; }

View File

@@ -78,11 +78,11 @@ namespace OpenRA.Mods.Common.Traits
this.info = info; this.info = info;
self = init.Self; self = init.Self;
TopLeft = init.GetValue<LocationInit, CPos>(info); TopLeft = init.GetValue<LocationInit, CPos>();
CenterPosition = init.GetValue<CenterPositionInit, WPos>(info, init.World.Map.CenterOfCell(TopLeft)); CenterPosition = init.GetValue<CenterPositionInit, WPos>(init.World.Map.CenterOfCell(TopLeft));
Facing = WAngle.FromFacing(init.GetValue<FacingInit, int>(info, 128)); Facing = WAngle.FromFacing(init.GetValue<FacingInit, int>(128));
dragSpeed = init.GetValue<HuskSpeedInit, int>(info, 0); dragSpeed = init.GetValue<HuskSpeedInit, int>(0);
finalPosition = init.World.Map.CenterOfCell(TopLeft); finalPosition = init.World.Map.CenterOfCell(TopLeft);
effectiveOwner = init.GetValue<EffectiveOwnerInit, Player>(info, self.Owner); effectiveOwner = init.GetValue<EffectiveOwnerInit, Player>(info, self.Owner);
@@ -171,7 +171,7 @@ namespace OpenRA.Mods.Common.Traits
Player IEffectiveOwner.Owner { get { return effectiveOwner; } } Player IEffectiveOwner.Owner { get { return effectiveOwner; } }
} }
public class HuskSpeedInit : ValueActorInit<int> public class HuskSpeedInit : ValueActorInit<int>, ISingleInstanceInit
{ {
public HuskSpeedInit(int value) public HuskSpeedInit(int value)
: base(value) { } : base(value) { }

View File

@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits
public Immobile(ActorInitializer init, ImmobileInfo info) public Immobile(ActorInitializer init, ImmobileInfo info)
{ {
location = init.GetValue<LocationInit, CPos>(info); location = init.GetValue<LocationInit, CPos>();
position = init.World.Map.CenterOfCell(location); position = init.World.Map.CenterOfCell(location);
if (info.OccupiesSpace) if (info.OccupiesSpace)

View File

@@ -267,25 +267,25 @@ namespace OpenRA.Mods.Common.Traits
ToSubCell = FromSubCell = info.LocomotorInfo.SharesCell ? init.World.Map.Grid.DefaultSubCell : SubCell.FullCell; ToSubCell = FromSubCell = info.LocomotorInfo.SharesCell ? init.World.Map.Grid.DefaultSubCell : SubCell.FullCell;
var subCellInit = init.GetOrDefault<SubCellInit>(info); var subCellInit = init.GetOrDefault<SubCellInit>();
if (subCellInit != null) if (subCellInit != null)
{ {
FromSubCell = ToSubCell = subCellInit.Value; FromSubCell = ToSubCell = subCellInit.Value;
returnToCellOnCreationRecalculateSubCell = false; returnToCellOnCreationRecalculateSubCell = false;
} }
var locationInit = init.GetOrDefault<LocationInit>(info); var locationInit = init.GetOrDefault<LocationInit>();
if (locationInit != null) if (locationInit != null)
{ {
fromCell = toCell = locationInit.Value; fromCell = toCell = locationInit.Value;
SetVisualPosition(self, init.World.Map.CenterOfSubCell(FromCell, FromSubCell)); SetVisualPosition(self, init.World.Map.CenterOfSubCell(FromCell, FromSubCell));
} }
Facing = oldFacing = WAngle.FromFacing(init.GetValue<FacingInit, int>(info, info.InitialFacing)); Facing = oldFacing = WAngle.FromFacing(init.GetValue<FacingInit, int>(info.InitialFacing));
// Sets the initial visual position // Sets the initial visual position
// Unit will move into the cell grid (defined by LocationInit) as its initial activity // Unit will move into the cell grid (defined by LocationInit) as its initial activity
var centerPositionInit = init.GetOrDefault<CenterPositionInit>(info); var centerPositionInit = init.GetOrDefault<CenterPositionInit>();
if (centerPositionInit != null) if (centerPositionInit != null)
{ {
oldPos = centerPositionInit.Value; oldPos = centerPositionInit.Value;
@@ -293,7 +293,7 @@ namespace OpenRA.Mods.Common.Traits
returnToCellOnCreation = true; returnToCellOnCreation = true;
} }
creationActivityDelay = init.GetValue<CreationActivityDelayInit, int>(info, 0); creationActivityDelay = init.GetValue<CreationActivityDelayInit, int>(0);
} }
protected override void Created(Actor self) protected override void Created(Actor self)

View File

@@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Traits
// Explore map-placed actors if the "Explore Map" option is enabled // Explore map-placed actors if the "Explore Map" option is enabled
var shroudInfo = init.World.Map.Rules.Actors["player"].TraitInfo<ShroudInfo>(); var shroudInfo = init.World.Map.Rules.Actors["player"].TraitInfo<ShroudInfo>();
var exploredMap = init.World.LobbyInfo.GlobalSettings.OptionOrDefault("explored", shroudInfo.ExploredMapCheckboxEnabled); var exploredMap = init.World.LobbyInfo.GlobalSettings.OptionOrDefault("explored", shroudInfo.ExploredMapCheckboxEnabled);
startsRevealed = exploredMap && init.Contains<SpawnedByMapInit>(info) && !init.Contains<HiddenUnderFogInit>(info); startsRevealed = exploredMap && init.Contains<SpawnedByMapInit>() && !init.Contains<HiddenUnderFogInit>();
var buildingInfo = init.Self.Info.TraitInfoOrDefault<BuildingInfo>(); var buildingInfo = init.Self.Info.TraitInfoOrDefault<BuildingInfo>();
var footprintCells = buildingInfo != null ? buildingInfo.FrozenUnderFogTiles(init.Self.Location).ToList() : new List<CPos>() { init.Self.Location }; var footprintCells = buildingInfo != null ? buildingInfo.FrozenUnderFogTiles(init.Self.Location).ToList() : new List<CPos>() { init.Self.Location };
footprint = footprintCells.SelectMany(c => map.ProjectedCellsCovering(c.ToMPos(map))).ToArray(); footprint = footprintCells.SelectMany(c => map.ProjectedCellsCovering(c.ToMPos(map))).ToArray();
@@ -195,5 +195,5 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class HiddenUnderFogInit : RuntimeFlagInit { } public class HiddenUnderFogInit : RuntimeFlagInit, ISingleInstanceInit { }
} }

View File

@@ -131,7 +131,7 @@ namespace OpenRA.Mods.Common.Traits
self = init.Self; self = init.Self;
Info = info; Info = info;
Faction = init.GetValue<FactionInit, string>(info, self.Owner.Faction.InternalName); Faction = init.GetValue<FactionInit, string>(self.Owner.Faction.InternalName);
IsValidFaction = !info.Factions.Any() || info.Factions.Contains(Faction); IsValidFaction = !info.Factions.Any() || info.Factions.Contains(Faction);
Enabled = IsValidFaction; Enabled = IsValidFaction;

View File

@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Traits
if (string.IsNullOrEmpty(prerequisite)) if (string.IsNullOrEmpty(prerequisite))
prerequisite = init.Self.Info.Name; prerequisite = init.Self.Info.Name;
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
public IEnumerable<string> ProvidesPrerequisites public IEnumerable<string> ProvidesPrerequisites

View File

@@ -120,7 +120,7 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class PlugsInit : ValueActorInit<Dictionary<CVec, string>> public class PlugsInit : ValueActorInit<Dictionary<CVec, string>>, ISingleInstanceInit
{ {
public PlugsInit(Dictionary<CVec, string> value) public PlugsInit(Dictionary<CVec, string> value)
: base(value) { } : base(value) { }

View File

@@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.Traits
: base(info) : base(info)
{ {
rp = Exts.Lazy(() => init.Self.IsDead ? null : init.Self.TraitOrDefault<RallyPoint>()); rp = Exts.Lazy(() => init.Self.IsDead ? null : init.Self.TraitOrDefault<RallyPoint>());
Faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); Faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
public virtual void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits) public virtual void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits)

View File

@@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits.Render
{ {
var sequenceProvider = init.World.Map.Rules.Sequences; var sequenceProvider = init.World.Map.Rules.Sequences;
var faction = init.GetValue<FactionInit, string>(this); var faction = init.GetValue<FactionInit, string>(this);
var ownerName = init.Get<OwnerInit>(this).InternalName; var ownerName = init.Get<OwnerInit>().InternalName;
var image = GetImage(init.Actor, sequenceProvider, faction); var image = GetImage(init.Actor, sequenceProvider, faction);
var palette = init.WorldRenderer.Palette(Palette ?? PlayerPalette + ownerName); var palette = init.WorldRenderer.Palette(Palette ?? PlayerPalette + ownerName);
@@ -169,7 +169,7 @@ namespace OpenRA.Mods.Common.Traits.Render
public RenderSprites(ActorInitializer init, RenderSpritesInfo info) public RenderSprites(ActorInitializer init, RenderSpritesInfo info)
{ {
Info = info; Info = info;
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
public string GetImage(Actor self) public string GetImage(Actor self)

View File

@@ -58,7 +58,7 @@ namespace OpenRA.Mods.Common.Traits.Render
{ {
var body = init.Actor.TraitInfo<BodyOrientationInfo>(); var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var faction = init.GetValue<FactionInit, string>(this); var faction = init.GetValue<FactionInit, string>(this);
var ownerName = init.Get<OwnerInit>(this).InternalName; var ownerName = init.Get<OwnerInit>().InternalName;
var sequenceProvider = init.World.Map.Rules.Sequences; var sequenceProvider = init.World.Map.Rules.Sequences;
var image = Image ?? init.Actor.Name; var image = Image ?? init.Actor.Name;
var facings = body.QuantizedFacings == -1 ? var facings = body.QuantizedFacings == -1 ?

View File

@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Traits.Render
p = init.WorldRenderer.Palette(Palette); p = init.WorldRenderer.Palette(Palette);
Func<WAngle> facing; Func<WAngle> facing;
var dynamicfacingInit = init.GetOrDefault<DynamicFacingInit>(this); var dynamicfacingInit = init.GetOrDefault<DynamicFacingInit>();
if (dynamicfacingInit != null) if (dynamicfacingInit != null)
{ {
var getFacing = dynamicfacingInit.Value; var getFacing = dynamicfacingInit.Value;
@@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
else else
{ {
var f = WAngle.FromFacing(init.GetValue<FacingInit, int>(this, 0)); var f = WAngle.FromFacing(init.GetValue<FacingInit, int>(0));
facing = () => f; facing = () => f;
} }

View File

@@ -78,12 +78,12 @@ namespace OpenRA.Mods.Common.Traits.Render
p = init.WorldRenderer.Palette(Palette); p = init.WorldRenderer.Palette(Palette);
Func<int> facing; Func<int> facing;
var dynamicfacingInit = init.GetOrDefault<DynamicFacingInit>(this); var dynamicfacingInit = init.GetOrDefault<DynamicFacingInit>();
if (dynamicfacingInit != null) if (dynamicfacingInit != null)
facing = dynamicfacingInit.Value; facing = dynamicfacingInit.Value;
else else
{ {
var f = init.GetValue<FacingInit, int>(this, 0); var f = init.GetValue<FacingInit, int>(0);
facing = () => f; facing = () => f;
} }

View File

@@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.Traits.Render
}; };
if (IsPlayerPalette) if (IsPlayerPalette)
p = init.WorldRenderer.Palette(Palette + init.Get<OwnerInit>(this).InternalName); p = init.WorldRenderer.Palette(Palette + init.Get<OwnerInit>().InternalName);
else if (Palette != null) else if (Palette != null)
p = init.WorldRenderer.Palette(Palette); p = init.WorldRenderer.Palette(Palette);

View File

@@ -37,8 +37,8 @@ namespace OpenRA.Mods.Common.Traits.Render
yield break; yield break;
var adjacent = 0; var adjacent = 0;
var locationInit = init.GetOrDefault<LocationInit>(this); var locationInit = init.GetOrDefault<LocationInit>();
var neighbourInit = init.GetOrDefault<RuntimeNeighbourInit>(this); var neighbourInit = init.GetOrDefault<RuntimeNeighbourInit>();
if (locationInit != null && neighbourInit != null) if (locationInit != null && neighbourInit != null)
{ {
@@ -168,7 +168,7 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
} }
public class RuntimeNeighbourInit : ValueActorInit<Dictionary<CPos, string[]>>, ISuppressInitExport public class RuntimeNeighbourInit : ValueActorInit<Dictionary<CPos, string[]>>, ISuppressInitExport, ISingleInstanceInit
{ {
public RuntimeNeighbourInit(Dictionary<CPos, string[]> value) public RuntimeNeighbourInit(Dictionary<CPos, string[]> value)
: base(value) { } : base(value) { }

View File

@@ -72,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits
: base(info) : base(info)
{ {
enabled = !info.RequiresLobbyCreeps || init.Self.World.WorldActor.Trait<MapCreeps>().Enabled; enabled = !info.RequiresLobbyCreeps || init.Self.World.WorldActor.Trait<MapCreeps>().Enabled;
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
void INotifyKilled.Killed(Actor self, AttackInfo e) void INotifyKilled.Killed(Actor self, AttackInfo e)

View File

@@ -47,7 +47,7 @@ namespace OpenRA.Mods.Common.Traits
public ProduceActorPower(ActorInitializer init, ProduceActorPowerInfo info) public ProduceActorPower(ActorInitializer init, ProduceActorPowerInfo info)
: base(init.Self, info) : base(init.Self, info)
{ {
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
public override void SelectTarget(Actor self, string order, SupportPowerManager manager) public override void SelectTarget(Actor self, string order, SupportPowerManager manager)

View File

@@ -65,8 +65,8 @@ namespace OpenRA.Mods.Common.Traits
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
// TODO: Carry orientation over from the parent instead of just facing // TODO: Carry orientation over from the parent instead of just facing
var dynamicFacingInit = init.GetOrDefault<DynamicFacingInit>(info); var dynamicFacingInit = init.GetOrDefault<DynamicFacingInit>();
var bodyFacing = dynamicFacingInit != null ? dynamicFacingInit.Value() : init.GetValue<FacingInit, int>(info, 0); var bodyFacing = dynamicFacingInit != null ? dynamicFacingInit.Value() : init.GetValue<FacingInit, int>(0);
facing = WAngle.FromFacing(Turreted.TurretFacingFromInit(init, info, 0)()); facing = WAngle.FromFacing(Turreted.TurretFacingFromInit(init, info, 0)());
// Calculate final position // Calculate final position

View File

@@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.Traits
public TransformCrusherOnCrush(ActorInitializer init, TransformCrusherOnCrushInfo info) public TransformCrusherOnCrush(ActorInitializer init, TransformCrusherOnCrushInfo info)
{ {
this.info = info; this.info = info;
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
void INotifyCrushed.WarnCrush(Actor self, Actor crusher, BitSet<CrushClass> crushClasses) { } void INotifyCrushed.WarnCrush(Actor self, Actor crusher, BitSet<CrushClass> crushClasses) { }

View File

@@ -40,7 +40,7 @@ namespace OpenRA.Mods.Common.Traits
public TransformOnCapture(ActorInitializer init, TransformOnCaptureInfo info) public TransformOnCapture(ActorInitializer init, TransformOnCaptureInfo info)
{ {
this.info = info; this.info = info;
faction = init.GetValue<FactionInit, string>(info, init.Self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(init.Self.Owner.Faction.InternalName);
} }
void INotifyCapture.OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner, BitSet<CaptureType> captureTypes) void INotifyCapture.OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner, BitSet<CaptureType> captureTypes)

View File

@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits
self = init.Self; self = init.Self;
actorInfo = self.World.Map.Rules.Actors[info.IntoActor]; actorInfo = self.World.Map.Rules.Actors[info.IntoActor];
buildingInfo = actorInfo.TraitInfoOrDefault<BuildingInfo>(); buildingInfo = actorInfo.TraitInfoOrDefault<BuildingInfo>();
faction = init.GetValue<FactionInit, string>(info, self.Owner.Faction.InternalName); faction = init.GetValue<FactionInit, string>(self.Owner.Faction.InternalName);
} }
public string VoicePhraseForOrder(Actor self, Order order) public string VoicePhraseForOrder(Actor self, Order order)

View File

@@ -106,12 +106,12 @@ namespace OpenRA.Mods.Common.Traits
if (turret != null) if (turret != null)
{ {
Func<int> getFacing; Func<int> getFacing;
var dynamicTurretFacingsInit = init.GetOrDefault<DynamicTurretFacingsInit>(info); var dynamicTurretFacingsInit = init.GetOrDefault<DynamicTurretFacingsInit>();
if (dynamicTurretFacingsInit != null && dynamicTurretFacingsInit.Value.TryGetValue(turret, out getFacing)) if (dynamicTurretFacingsInit != null && dynamicTurretFacingsInit.Value.TryGetValue(turret, out getFacing))
return getFacing; return getFacing;
int facing; int facing;
var turretFacingsInit = init.GetOrDefault<TurretFacingsInit>(info); var turretFacingsInit = init.GetOrDefault<TurretFacingsInit>();
if (turretFacingsInit != null && turretFacingsInit.Value.TryGetValue(turret, out facing)) if (turretFacingsInit != null && turretFacingsInit.Value.TryGetValue(turret, out facing))
return () => facing; return () => facing;
} }
@@ -123,11 +123,11 @@ namespace OpenRA.Mods.Common.Traits
return () => facing; return () => facing;
} }
var dynamicFacingInit = init.GetOrDefault<DynamicFacingInit>(info); var dynamicFacingInit = init.GetOrDefault<DynamicFacingInit>();
if (dynamicFacingInit != null) if (dynamicFacingInit != null)
return dynamicFacingInit.Value; return dynamicFacingInit.Value;
var facingInit = init.GetOrDefault<FacingInit>(info); var facingInit = init.GetOrDefault<FacingInit>();
if (facingInit != null) if (facingInit != null)
{ {
var facing = facingInit.Value; var facing = facingInit.Value;
@@ -245,7 +245,7 @@ namespace OpenRA.Mods.Common.Traits
var facings = inits.GetOrDefault<DynamicTurretFacingsInit>(); var facings = inits.GetOrDefault<DynamicTurretFacingsInit>();
if (facings == null) if (facings == null)
{ {
facings = new DynamicTurretFacingsInit(Info, new Dictionary<string, Func<int>>()); facings = new DynamicTurretFacingsInit(new Dictionary<string, Func<int>>());
inits.Add(facings); inits.Add(facings);
} }
@@ -278,15 +278,15 @@ namespace OpenRA.Mods.Common.Traits
: base(value) { } : base(value) { }
} }
public class TurretFacingsInit : ValueActorInit<Dictionary<string, int>> public class TurretFacingsInit : ValueActorInit<Dictionary<string, int>>, ISingleInstanceInit
{ {
public TurretFacingsInit(Dictionary<string, int> value) public TurretFacingsInit(Dictionary<string, int> value)
: base(value) { } : base(value) { }
} }
public class DynamicTurretFacingsInit : ValueActorInit<Dictionary<string, Func<int>>> public class DynamicTurretFacingsInit : ValueActorInit<Dictionary<string, Func<int>>>, ISingleInstanceInit
{ {
public DynamicTurretFacingsInit(TraitInfo info, Dictionary<string, Func<int>> value) public DynamicTurretFacingsInit(Dictionary<string, Func<int>> value)
: base(info, value) { } : base(value) { }
} }
} }

View File

@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Traits
} }
public class SkipMakeAnimsInit : RuntimeFlagInit { } public class SkipMakeAnimsInit : RuntimeFlagInit { }
public class SpawnedByMapInit : ValueActorInit<string>, ISuppressInitExport public class SpawnedByMapInit : ValueActorInit<string>, ISuppressInitExport, ISingleInstanceInit
{ {
public SpawnedByMapInit(string value) public SpawnedByMapInit(string value)
: base(value) { } : base(value) { }