Replace IConditionConsumer w/ variable observers for multiple variable expressions for traits.
This commit is contained in:
@@ -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)
|
||||||
foreach (var w in allWatchers)
|
{
|
||||||
if (w.Condition == condition)
|
var cs = state.GetOrAdd(variable);
|
||||||
cs.Watchers.Add(w);
|
cs.Notifiers.Add(variableUser.Notifier);
|
||||||
|
foreach (var w in allWatchers)
|
||||||
|
if (w.Condition == variable)
|
||||||
|
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>
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
yield return new VariableObserver(RequiredConditionsChanged, Info.RequiresCondition.Variables);
|
||||||
if (Info.RequiresCondition != null)
|
|
||||||
return 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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user