Replace IConditionConsumer w/ variable observers for multiple variable expressions for traits.

This commit is contained in:
atlimit8
2017-03-10 22:10:46 -06:00
parent 843ac85c92
commit d433473249
4 changed files with 49 additions and 40 deletions

View File

@@ -12,7 +12,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Primitives;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
@@ -25,7 +24,7 @@ namespace OpenRA.Mods.Common.Traits
} }
[Desc("Attach this to a unit to enable dynamic conditions by warheads, experience, crates, support powers, etc.")] [Desc("Attach this to a unit to enable dynamic conditions by warheads, experience, crates, support powers, etc.")]
public class ConditionManagerInfo : TraitInfo<ConditionManager>, Requires<IConditionConsumerInfo> { } public class ConditionManagerInfo : TraitInfo<ConditionManager>, Requires<IObservesVariablesInfo> { }
public class ConditionManager : INotifyCreated, ITick public class ConditionManager : INotifyCreated, ITick
{ {
@@ -47,8 +46,8 @@ namespace OpenRA.Mods.Common.Traits
class ConditionState class ConditionState
{ {
/// <summary>Traits that have registered to be notified when this condition changes.</summary> /// <summary>Delegates that have registered to be notified when this condition changes.</summary>
public readonly List<IConditionConsumer> Consumers = new List<IConditionConsumer>(); public readonly List<VariableObserverNotifier> Notifiers = new List<VariableObserverNotifier>();
/// <summary>Unique integers identifying granted instances of the condition.</summary> /// <summary>Unique integers identifying granted instances of the condition.</summary>
public readonly HashSet<int> Tokens = new HashSet<int>(); public readonly HashSet<int> Tokens = new HashSet<int>();
@@ -76,21 +75,24 @@ namespace OpenRA.Mods.Common.Traits
state = new Dictionary<string, ConditionState>(); state = new Dictionary<string, ConditionState>();
readOnlyConditionCache = new ReadOnlyDictionary<string, int>(conditionCache); readOnlyConditionCache = new ReadOnlyDictionary<string, int>(conditionCache);
var allConsumers = new HashSet<IConditionConsumer>(); var allObservers = new HashSet<VariableObserverNotifier>();
var allWatchers = self.TraitsImplementing<IConditionTimerWatcher>().ToList(); var allWatchers = self.TraitsImplementing<IConditionTimerWatcher>().ToList();
foreach (var consumer in self.TraitsImplementing<IConditionConsumer>()) foreach (var provider in self.TraitsImplementing<IObservesVariables>())
{ {
allConsumers.Add(consumer); foreach (var variableUser in provider.GetVariableObservers())
foreach (var condition in consumer.Conditions)
{ {
var cs = state.GetOrAdd(condition); allObservers.Add(variableUser.Notifier);
cs.Consumers.Add(consumer); foreach (var variable in variableUser.Variables)
{
var cs = state.GetOrAdd(variable);
cs.Notifiers.Add(variableUser.Notifier);
foreach (var w in allWatchers) foreach (var w in allWatchers)
if (w.Condition == condition) if (w.Condition == variable)
cs.Watchers.Add(w); cs.Watchers.Add(w);
conditionCache[condition] = 0; conditionCache[variable] = 0;
}
} }
} }
@@ -106,8 +108,8 @@ namespace OpenRA.Mods.Common.Traits
} }
// Update all traits with their initial condition state // Update all traits with their initial condition state
foreach (var consumer in allConsumers) foreach (var consumer in allObservers)
consumer.ConditionsChanged(self, readOnlyConditionCache); consumer(self, readOnlyConditionCache);
} }
void UpdateConditionState(Actor self, string condition, int token, bool isRevoke) void UpdateConditionState(Actor self, string condition, int token, bool isRevoke)
@@ -123,8 +125,8 @@ namespace OpenRA.Mods.Common.Traits
conditionCache[condition] = conditionState.Tokens.Count; conditionCache[condition] = conditionState.Tokens.Count;
foreach (var t in conditionState.Consumers) foreach (var notify in conditionState.Notifiers)
t.ConditionsChanged(self, readOnlyConditionCache); notify(self, readOnlyConditionCache);
} }
/// <summary>Grants a specified condition.</summary> /// <summary>Grants a specified condition.</summary>

View File

@@ -10,14 +10,13 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Support; using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
/// <summary>Use as base class for *Info to subclass of UpgradableTrait. (See UpgradableTrait.)</summary> /// <summary>Use as base class for *Info to subclass of UpgradableTrait. (See UpgradableTrait.)</summary>
public abstract class ConditionalTraitInfo : IConditionConsumerInfo, IRulesetLoaded public abstract class ConditionalTraitInfo : IObservesVariablesInfo, IRulesetLoaded
{ {
static readonly IReadOnlyDictionary<string, int> NoConditions = new ReadOnlyDictionary<string, int>(new Dictionary<string, int>()); static readonly IReadOnlyDictionary<string, int> NoConditions = new ReadOnlyDictionary<string, int>(new Dictionary<string, int>());
@@ -43,19 +42,15 @@ namespace OpenRA.Mods.Common.Traits
/// Requires basing *Info on UpgradableTraitInfo and using base(info) constructor. /// Requires basing *Info on UpgradableTraitInfo and using base(info) constructor.
/// TraitEnabled will be called at creation if the trait starts enabled or does not use conditions. /// TraitEnabled will be called at creation if the trait starts enabled or does not use conditions.
/// </summary> /// </summary>
public abstract class ConditionalTrait<InfoType> : IConditionConsumer, IDisabledTrait, INotifyCreated, ISync where InfoType : ConditionalTraitInfo public abstract class ConditionalTrait<InfoType> : IObservesVariables, IDisabledTrait, INotifyCreated, ISync where InfoType : ConditionalTraitInfo
{ {
public readonly InfoType Info; public readonly InfoType Info;
IEnumerable<string> IConditionConsumer.Conditions // Overrides must call `base.GetVariableObservers()` to avoid breaking RequiresCondition.
{ public virtual IEnumerable<VariableObserver> GetVariableObservers()
get
{ {
if (Info.RequiresCondition != null) if (Info.RequiresCondition != null)
return Info.RequiresCondition.Variables; yield return new VariableObserver(RequiredConditionsChanged, Info.RequiresCondition.Variables);
return Enumerable.Empty<string>();
}
} }
[Sync] public bool IsTraitDisabled { get; private set; } [Sync] public bool IsTraitDisabled { get; private set; }
@@ -65,7 +60,7 @@ namespace OpenRA.Mods.Common.Traits
Info = info; Info = info;
// Conditional traits will be enabled (if appropriate) by the ConditionManager // Conditional traits will be enabled (if appropriate) by the ConditionManager
// calling IConditionConsumer.ConditionsChanged at the end of INotifyCreated. // calling ConditionConsumers at the end of INotifyCreated.
IsTraitDisabled = Info.RequiresCondition != null; IsTraitDisabled = Info.RequiresCondition != null;
} }
@@ -77,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits
void INotifyCreated.Created(Actor self) { Created(self); } void INotifyCreated.Created(Actor self) { Created(self); }
void IConditionConsumer.ConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions) void RequiredConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions)
{ {
if (Info.RequiresCondition == null) if (Info.RequiresCondition == null)
return; return;

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Primitives;
using OpenRA.Support; using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
@@ -44,7 +45,7 @@ namespace OpenRA.Mods.Common.Traits
public object Create(ActorInitializer init) { return new Pluggable(init, this); } public object Create(ActorInitializer init) { return new Pluggable(init, this); }
} }
public class Pluggable : IConditionConsumer, INotifyCreated public class Pluggable : IObservesVariables, INotifyCreated
{ {
public readonly PluggableInfo Info; public readonly PluggableInfo Info;
@@ -114,12 +115,12 @@ namespace OpenRA.Mods.Common.Traits
active = null; active = null;
} }
IEnumerable<string> IConditionConsumer.Conditions { get { return Info.ConsumedConditions; } } IEnumerable<VariableObserver> IObservesVariables.GetVariableObservers()
void IConditionConsumer.ConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions)
{ {
foreach (var req in Info.Requirements) foreach (var req in Info.Requirements)
plugTypesAvailability[req.Key] = req.Value.Evaluate(conditions); yield return new VariableObserver(
(self, variables) => plugTypesAvailability[req.Key] = req.Value.Evaluate(variables),
req.Value.Variables);
} }
} }

View File

@@ -105,12 +105,23 @@ namespace OpenRA.Mods.Common.Traits
public interface INotifyPassengerExited { void OnPassengerExited(Actor self, Actor passenger); } public interface INotifyPassengerExited { void OnPassengerExited(Actor self, Actor passenger); }
[RequireExplicitImplementation] [RequireExplicitImplementation]
public interface IConditionConsumerInfo : ITraitInfo { } public interface IObservesVariablesInfo : ITraitInfo { }
public interface IConditionConsumer public delegate void VariableObserverNotifier(Actor self, IReadOnlyDictionary<string, int> variables);
public struct VariableObserver
{ {
IEnumerable<string> Conditions { get; } public VariableObserverNotifier Notifier;
void ConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions); public IEnumerable<string> Variables;
public VariableObserver(VariableObserverNotifier notifier, IEnumerable<string> variables)
{
Notifier = notifier;
Variables = variables;
}
}
public interface IObservesVariables
{
IEnumerable<VariableObserver> GetVariableObservers();
} }
public interface INotifyHarvesterAction public interface INotifyHarvesterAction