Fix circular trait dependencies on UpgradeManager.
Don't use Requires to force an ordering, instead just use INotifyCreated to grab all the traits once constructed.
This commit is contained in:
@@ -17,12 +17,18 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Attach this to a unit to enable dynamic upgrades by warheads, experience, crates, support powers, etc.")]
|
||||
public class UpgradeManagerInfo : ITraitInfo, Requires<IUpgradableInfo>
|
||||
public class UpgradeManagerInfo : TraitInfo<UpgradeManager>, IRulesetLoaded
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new UpgradeManager(init); }
|
||||
public void RulesetLoaded(Ruleset rules, ActorInfo info)
|
||||
{
|
||||
if (!info.Name.StartsWith("^") && !info.TraitInfos<IUpgradableInfo>().Any())
|
||||
throw new YamlException(
|
||||
"There are no upgrades to be managed for actor '{0}'. You are either missing some upgradeable traits, or this UpgradeManager trait is not required.".F(
|
||||
info.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public class UpgradeManager : ITick
|
||||
public class UpgradeManager : INotifyCreated, ITick
|
||||
{
|
||||
class TimedUpgrade
|
||||
{
|
||||
@@ -67,20 +73,21 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
readonly List<TimedUpgrade> timedUpgrades = new List<TimedUpgrade>();
|
||||
readonly Lazy<Dictionary<string, UpgradeState>> upgrades;
|
||||
readonly Dictionary<IUpgradable, int> levels = new Dictionary<IUpgradable, int>();
|
||||
Dictionary<string, UpgradeState> upgrades;
|
||||
|
||||
public UpgradeManager(ActorInitializer init)
|
||||
void INotifyCreated.Created(Actor self)
|
||||
{
|
||||
upgrades = Exts.Lazy(() =>
|
||||
{
|
||||
var ret = new Dictionary<string, UpgradeState>();
|
||||
foreach (var up in init.Self.TraitsImplementing<IUpgradable>())
|
||||
foreach (var t in up.UpgradeTypes)
|
||||
ret.GetOrAdd(t).Traits.Add(up);
|
||||
upgrades = new Dictionary<string, UpgradeState>();
|
||||
foreach (var up in self.TraitsImplementing<IUpgradable>())
|
||||
foreach (var t in up.UpgradeTypes)
|
||||
upgrades.GetOrAdd(t).Traits.Add(up);
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
void CheckCanManageUpgrades()
|
||||
{
|
||||
if (upgrades == null)
|
||||
throw new InvalidOperationException("Upgrades cannot be managed until the actor has been fully created.");
|
||||
}
|
||||
|
||||
/// <summary>Upgrade level increments are limited to dupesAllowed per source, i.e., if a single
|
||||
@@ -139,8 +146,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void GrantUpgrade(Actor self, string upgrade, object source)
|
||||
{
|
||||
CheckCanManageUpgrades();
|
||||
|
||||
UpgradeState s;
|
||||
if (!upgrades.Value.TryGetValue(upgrade, out s))
|
||||
if (!upgrades.TryGetValue(upgrade, out s))
|
||||
return;
|
||||
|
||||
// Track the upgrade source so that the upgrade can be removed without conflicts
|
||||
@@ -151,8 +160,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void RevokeUpgrade(Actor self, string upgrade, object source)
|
||||
{
|
||||
CheckCanManageUpgrades();
|
||||
|
||||
UpgradeState s;
|
||||
if (!upgrades.Value.TryGetValue(upgrade, out s))
|
||||
if (!upgrades.TryGetValue(upgrade, out s))
|
||||
return;
|
||||
|
||||
if (!s.Sources.Remove(source))
|
||||
@@ -164,14 +175,17 @@ namespace OpenRA.Mods.Common.Traits
|
||||
/// <summary>Returns true if the actor uses the given upgrade. Does not check the actual level of the upgrade.</summary>
|
||||
public bool AcknowledgesUpgrade(Actor self, string upgrade)
|
||||
{
|
||||
return upgrades.Value.ContainsKey(upgrade);
|
||||
CheckCanManageUpgrades();
|
||||
return upgrades.ContainsKey(upgrade);
|
||||
}
|
||||
|
||||
/// <summary>Returns true only if the actor can accept another level of the upgrade.</summary>
|
||||
public bool AcceptsUpgrade(Actor self, string upgrade)
|
||||
{
|
||||
CheckCanManageUpgrades();
|
||||
|
||||
UpgradeState s;
|
||||
if (!upgrades.Value.TryGetValue(upgrade, out s))
|
||||
if (!upgrades.TryGetValue(upgrade, out s))
|
||||
return false;
|
||||
|
||||
return s.Traits.Any(up => up.AcceptsUpgradeLevel(self, upgrade, GetOverallLevel(up) + 1));
|
||||
@@ -179,8 +193,10 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public void RegisterWatcher(string upgrade, Action<int, int> action)
|
||||
{
|
||||
CheckCanManageUpgrades();
|
||||
|
||||
UpgradeState s;
|
||||
if (!upgrades.Value.TryGetValue(upgrade, out s))
|
||||
if (!upgrades.TryGetValue(upgrade, out s))
|
||||
return;
|
||||
|
||||
s.Watchers.Add(action);
|
||||
@@ -192,6 +208,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
/// GrantTimedUpgrade).</summary>
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
CheckCanManageUpgrades();
|
||||
|
||||
foreach (var u in timedUpgrades)
|
||||
{
|
||||
u.Tick();
|
||||
@@ -201,7 +219,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
u.Sources.RemoveWhere(source => source.Remaining <= 0);
|
||||
|
||||
foreach (var a in upgrades.Value[u.Upgrade].Watchers)
|
||||
foreach (var a in upgrades[u.Upgrade].Watchers)
|
||||
a(u.Duration, u.Remaining);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user