From f65b583928b51a3fcd7afe82310cace8d936b69a Mon Sep 17 00:00:00 2001 From: homothetyhk Date: Fri, 26 Aug 2022 11:47:22 -0700 Subject: [PATCH] Track when tags and modules are loaded, add automatic loading for new tags, prevent duplicate tag/module loading. --- ItemChanger/Internal/ModuleCollection.cs | 30 +++------ ItemChanger/Modules/Module.cs | 42 +++++++++++++ ItemChanger/Tag.cs | 62 ++++++++++++++++++- ItemChanger/TaggableObject.cs | 37 ++++++++--- ItemChanger/Tags/CostTag.cs | 2 + ItemChanger/Tags/DestroyFsmTag.cs | 2 + ItemChanger/Tags/DestroyGrubRewardTag.cs | 2 + ItemChanger/Tags/DestroyObjectTag.cs | 2 + ItemChanger/Tags/DestroyOnECLReplaceTag.cs | 2 + ItemChanger/Tags/DestroySeerRewardTag.cs | 3 +- ItemChanger/Tags/DisableFsmTag.cs | 2 + ItemChanger/Tags/EquipCharmOnGiveTag.cs | 8 +++ ItemChanger/Tags/ImplicitCostTag.cs | 2 + ItemChanger/Tags/IncompatibilityWarningTag.cs | 1 + ItemChanger/Tags/ItemChainTag.cs | 2 + ItemChanger/Tags/ItemTreeTag.cs | 2 + ItemChanger/Tags/OverridePDBoolTag.cs | 2 + ItemChanger/Tags/SetIBoolOnGiveTag.cs | 2 + ItemChanger/Tags/SetPDBoolOnGiveTag.cs | 2 + ItemChanger/Tags/SetPDBoolOnLoadTag.cs | 1 + 20 files changed, 178 insertions(+), 30 deletions(-) diff --git a/ItemChanger/Internal/ModuleCollection.cs b/ItemChanger/Internal/ModuleCollection.cs index 7a4ec655..7daed277 100644 --- a/ItemChanger/Internal/ModuleCollection.cs +++ b/ItemChanger/Internal/ModuleCollection.cs @@ -10,31 +10,17 @@ public class ModuleCollection public void Initialize() { - foreach (Module m in Modules) + for (int i = 0; i < Modules.Count; i++) { - try - { - m.Initialize(); - } - catch (Exception e) - { - LogError($"Error initializing module {m.Name}:\n{e}"); - } + Modules[i].LoadOnce(); } } public void Unload() { - foreach (Module m in Modules) + for (int i = 0; i < Modules.Count; i++) { - try - { - m.Unload(); - } - catch (Exception e) - { - LogError($"Error unloading module {m.Name}:\n{e}"); - } + Modules[i].UnloadOnce(); } } @@ -42,7 +28,7 @@ public Module Add(Module m) { if (m == null) throw new ArgumentNullException(nameof(m)); Modules.Add(m); - if (Settings.loaded) m.Initialize(); + if (Settings.loaded) m.LoadOnce(); return m; } @@ -90,7 +76,7 @@ public Module GetOrAdd(Type T) public void Remove(Module m) { - if (Modules.Remove(m) && Settings.loaded) m.Unload(); + if (Modules.Remove(m) && Settings.loaded) m.UnloadOnce(); } public void Remove() @@ -100,6 +86,10 @@ public void Remove() public void Remove(Type T) { + if (Settings.loaded) + { + foreach (Module m in Modules.Where(m => m.GetType() == T)) m.UnloadOnce(); + } Modules.RemoveAll(m => m.GetType() == T); } diff --git a/ItemChanger/Modules/Module.cs b/ItemChanger/Modules/Module.cs index b160cf8d..3feb8334 100644 --- a/ItemChanger/Modules/Module.cs +++ b/ItemChanger/Modules/Module.cs @@ -8,6 +8,48 @@ public abstract class Module public string Name => GetType().Name; public abstract void Initialize(); public abstract void Unload(); + + /// + /// Initializes the module and sets the Loaded property. If the module is already loaded, does nothing. + ///
Preferred to "Initialize", which does not set the Loaded property. + ///
+ public void LoadOnce() + { + if (!Loaded) + { + try + { + Initialize(); + } + catch (Exception e) + { + LogError($"Error initializing module {Name}:\n{e}"); + } + Loaded = true; + } + } + + /// + /// Unloads the module and sets the Loaded property. If the module is not loaded, does nothing. + ///
Preferred to "Unload", which does not set the Loaded property. + ///
+ public void UnloadOnce() + { + if (Loaded) + { + try + { + Unload(); + } + catch (Exception e) + { + LogError($"Error unloading module {Name}:\n{e}"); + } + Loaded = false; + } + } + + public bool Loaded { get; private set; } } /// diff --git a/ItemChanger/Tag.cs b/ItemChanger/Tag.cs index 63fdd3ef..24336190 100644 --- a/ItemChanger/Tag.cs +++ b/ItemChanger/Tag.cs @@ -2,8 +2,66 @@ { public abstract class Tag { - public virtual void Load(object parent) { } - public virtual void Unload(object parent) { } + /// + /// Virtual method called on tags when their parent loads. The base method checks and throws an exception if the tag is already loaded. + ///
This should not be called directly. Instead, use "LoadOnce" to load and set the Loaded property. + ///
+ /// The tag is already loaded. + public virtual void Load(object parent) + { + if (Loaded) throw new InvalidOperationException($"Tag {GetType().Name} is already loaded."); + } + /// + /// Virtual method called on tags when their parent unloads. The base method checks and throws an exception if the tag is not loaded. + ///
This should not be called directly. Instead, use "UnloadOnce" to unload and set the Loaded property. + ///
+ /// The tag is not loaded. + public virtual void Unload(object parent) + { + if (!Loaded) throw new InvalidOperationException($"Tag {GetType().Name} was not loaded."); + } public virtual Tag Clone() => (Tag)MemberwiseClone(); + + /// + /// Loads the tag and sets the Loaded property. If the tag is already loaded, does nothing. + ///
Preferred to "Load", which does not set the Loaded property. + ///
+ public void LoadOnce(TaggableObject parent) + { + if (!Loaded) + { + try + { + Load(parent); + } + catch (Exception e) + { + LogError($"Error loading {GetType().Name}:\n{e}"); + } + Loaded = true; + } + } + + /// + /// Unloads the tag and sets the Loaded property. If the tag is not loaded, does nothing. + ///
Preferred to "Unload", which does not set the Loaded property. + ///
+ public void UnloadOnce(TaggableObject parent) + { + if (Loaded) + { + try + { + Unload(parent); + } + catch (Exception e) + { + LogError($"Error unloading {GetType().Name}:\n{e}"); + } + Loaded = false; + } + } + + public bool Loaded { get; private set; } } } diff --git a/ItemChanger/TaggableObject.cs b/ItemChanger/TaggableObject.cs index 06b8c80a..432c7820 100644 --- a/ItemChanger/TaggableObject.cs +++ b/ItemChanger/TaggableObject.cs @@ -1,33 +1,52 @@ -namespace ItemChanger +using Newtonsoft.Json; + +namespace ItemChanger { public class TaggableObject { - [Newtonsoft.Json.JsonProperty] - public List tags; + [JsonProperty] public List tags; + private bool _tagsLoaded; protected void LoadTags() { + _tagsLoaded = true; if (tags == null) return; - foreach (Tag tag in tags) tag.Load(this); + for (int i = 0; i < tags.Count; i++) + { + tags[i].LoadOnce(this); + } } protected void UnloadTags() { + _tagsLoaded = false; if (tags == null) return; - foreach (Tag tag in tags) tag.Unload(this); + for (int i = 0; i < tags.Count; i++) + { + tags[i].UnloadOnce(this); + } } public T AddTag() where T : Tag, new() { if (tags == null) tags = new List(); - T t = new T(); + T t = new(); + if (_tagsLoaded) t.LoadOnce(this); tags.Add(t); return t; } + public void AddTag(Tag t) + { + if (tags == null) tags = new(); + if (_tagsLoaded) t.LoadOnce(this); + tags.Add(t); + } + public void AddTags(IEnumerable ts) { if (tags == null) tags = new List(); + if (_tagsLoaded) foreach (Tag t in ts) t.LoadOnce(this); tags.AddRange(ts); } @@ -61,7 +80,11 @@ public bool HasTag() where T : Tag public void RemoveTags() { - tags = tags?.Where(t => !(t is T))?.ToList(); + if (_tagsLoaded && tags != null) + { + foreach (Tag t in tags.Where(t => t is T)) t.UnloadOnce(this); + } + tags = tags?.Where(t => t is not T)?.ToList(); } } } diff --git a/ItemChanger/Tags/CostTag.cs b/ItemChanger/Tags/CostTag.cs index 030e4977..e5f6737e 100644 --- a/ItemChanger/Tags/CostTag.cs +++ b/ItemChanger/Tags/CostTag.cs @@ -8,10 +8,12 @@ public class CostTag : Tag public Cost Cost { get; set; } public override void Load(object parent) { + base.Load(parent); Cost?.Load(); } public override void Unload(object parent) { + base.Unload(parent); Cost?.Unload(); } } diff --git a/ItemChanger/Tags/DestroyFsmTag.cs b/ItemChanger/Tags/DestroyFsmTag.cs index c64e84de..df126310 100644 --- a/ItemChanger/Tags/DestroyFsmTag.cs +++ b/ItemChanger/Tags/DestroyFsmTag.cs @@ -10,12 +10,14 @@ public class DestroyFsmTag : Tag public override void Load(object parent) { + base.Load(parent); if (sceneName == null) Events.AddFsmEdit(id, Destroy); else Events.AddFsmEdit(sceneName, id, Destroy); } public override void Unload(object parent) { + base.Unload(parent); if (sceneName == null) Events.RemoveFsmEdit(id, Destroy); else Events.RemoveFsmEdit(sceneName, id, Destroy); } diff --git a/ItemChanger/Tags/DestroyGrubRewardTag.cs b/ItemChanger/Tags/DestroyGrubRewardTag.cs index 16589d45..71cd5372 100644 --- a/ItemChanger/Tags/DestroyGrubRewardTag.cs +++ b/ItemChanger/Tags/DestroyGrubRewardTag.cs @@ -11,11 +11,13 @@ public class DestroyGrubRewardTag : Tag public override void Load(object parent) { + base.Load(parent); Events.AddSceneChangeEdit(SceneNames.Crossroads_38, DestroyGrubRewards); } public override void Unload(object parent) { + base.Unload(parent); Events.RemoveSceneChangeEdit(SceneNames.Crossroads_38, DestroyGrubRewards); } diff --git a/ItemChanger/Tags/DestroyObjectTag.cs b/ItemChanger/Tags/DestroyObjectTag.cs index 3cada67f..83e7d206 100644 --- a/ItemChanger/Tags/DestroyObjectTag.cs +++ b/ItemChanger/Tags/DestroyObjectTag.cs @@ -10,11 +10,13 @@ public class DestroyObjectTag : Tag public override void Load(object parent) { + base.Load(parent); Events.AddSceneChangeEdit(sceneName, DestroyObject); } public override void Unload(object parent) { + base.Unload(parent); Events.RemoveSceneChangeEdit(sceneName, DestroyObject); } diff --git a/ItemChanger/Tags/DestroyOnECLReplaceTag.cs b/ItemChanger/Tags/DestroyOnECLReplaceTag.cs index 0381e4c3..19aaaba7 100644 --- a/ItemChanger/Tags/DestroyOnECLReplaceTag.cs +++ b/ItemChanger/Tags/DestroyOnECLReplaceTag.cs @@ -12,12 +12,14 @@ public class DestroyOnECLReplaceTag : Tag public override void Load(object parent) { + base.Load(parent); location = (ExistingContainerLocation)parent; Events.AddSceneChangeEdit(sceneName, OnSceneChange); } public override void Unload(object parent) { + base.Unload(parent); Events.RemoveSceneChangeEdit(sceneName, OnSceneChange); } diff --git a/ItemChanger/Tags/DestroySeerRewardTag.cs b/ItemChanger/Tags/DestroySeerRewardTag.cs index 0967d1de..b277cef6 100644 --- a/ItemChanger/Tags/DestroySeerRewardTag.cs +++ b/ItemChanger/Tags/DestroySeerRewardTag.cs @@ -9,6 +9,7 @@ public class DestroySeerRewardTag : Tag public override void Load(object parent) { + base.Load(parent); for (int i = 0; i < 5; i++) { if ((destroyRewards & (SeerRewards)(1 << i)) != 0) PlayerData.instance.SetBool($"dreamReward{i + 1}", true); @@ -22,7 +23,7 @@ public override void Load(object parent) public override void Unload(object parent) { - + base.Unload(parent); } } diff --git a/ItemChanger/Tags/DisableFsmTag.cs b/ItemChanger/Tags/DisableFsmTag.cs index 0925ccea..d404394d 100644 --- a/ItemChanger/Tags/DisableFsmTag.cs +++ b/ItemChanger/Tags/DisableFsmTag.cs @@ -14,12 +14,14 @@ public class DisableFsmTag : Tag public override void Load(object parent) { + base.Load(parent); if (sceneName == null) Events.AddFsmEdit(id, Disable); else Events.AddFsmEdit(sceneName, id, Disable); } public override void Unload(object parent) { + base.Unload(parent); if (sceneName == null) Events.RemoveFsmEdit(id, Disable); else Events.RemoveFsmEdit(sceneName, id, Disable); } diff --git a/ItemChanger/Tags/EquipCharmOnGiveTag.cs b/ItemChanger/Tags/EquipCharmOnGiveTag.cs index 824da487..31473314 100644 --- a/ItemChanger/Tags/EquipCharmOnGiveTag.cs +++ b/ItemChanger/Tags/EquipCharmOnGiveTag.cs @@ -10,11 +10,19 @@ public class EquipCharmOnGiveTag : Tag public override void Load(object parent) { + base.Load(parent); Items.CharmItem charm = (Items.CharmItem)parent; charmNum = charm.charmNum; charm.AfterGive += AfterGiveItem; } + public override void Unload(object parent) + { + base.Unload(parent); + Items.CharmItem charm = (Items.CharmItem)parent; + charm.AfterGive -= AfterGiveItem; + } + public void AfterGiveItem(ReadOnlyGiveEventArgs args) { if (PlayerData.instance.GetBool(equipBool)) return; diff --git a/ItemChanger/Tags/ImplicitCostTag.cs b/ItemChanger/Tags/ImplicitCostTag.cs index a867cf49..110a102f 100644 --- a/ItemChanger/Tags/ImplicitCostTag.cs +++ b/ItemChanger/Tags/ImplicitCostTag.cs @@ -13,11 +13,13 @@ public class ImplicitCostTag : Tag public override void Load(object parent) { + base.Load(parent); Cost?.Load(); } public override void Unload(object parent) { + base.Unload(parent); Cost?.Unload(); } } diff --git a/ItemChanger/Tags/IncompatibilityWarningTag.cs b/ItemChanger/Tags/IncompatibilityWarningTag.cs index 1b035fb0..84859ffc 100644 --- a/ItemChanger/Tags/IncompatibilityWarningTag.cs +++ b/ItemChanger/Tags/IncompatibilityWarningTag.cs @@ -8,6 +8,7 @@ public class IncompatibilityWarningTag : Tag public string IncompatiblePlacementName; public override void Load(object parent) { + base.Load(parent); string parentPlacementName = parent switch { AbstractPlacement parentPlacement => parentPlacement.Name, diff --git a/ItemChanger/Tags/ItemChainTag.cs b/ItemChanger/Tags/ItemChainTag.cs index 52c969fb..71eacddc 100644 --- a/ItemChanger/Tags/ItemChainTag.cs +++ b/ItemChanger/Tags/ItemChainTag.cs @@ -12,12 +12,14 @@ public class ItemChainTag : Tag, IItemModifierTag public override void Load(object parent) { + base.Load(parent); AbstractItem item = (AbstractItem)parent; item.ModifyItem += ModifyItem; } public override void Unload(object parent) { + base.Unload(parent); AbstractItem item = (AbstractItem)parent; item.ModifyItem -= ModifyItem; } diff --git a/ItemChanger/Tags/ItemTreeTag.cs b/ItemChanger/Tags/ItemTreeTag.cs index 4b44293e..50f9d011 100644 --- a/ItemChanger/Tags/ItemTreeTag.cs +++ b/ItemChanger/Tags/ItemTreeTag.cs @@ -18,12 +18,14 @@ public class ItemTreeTag : Tag, IItemModifierTag public override void Load(object parent) { + base.Load(parent); AbstractItem item = (AbstractItem)parent; item.ModifyItem += ModifyItem; } public override void Unload(object parent) { + base.Unload(parent); AbstractItem item = (AbstractItem)parent; item.ModifyItem -= ModifyItem; } diff --git a/ItemChanger/Tags/OverridePDBoolTag.cs b/ItemChanger/Tags/OverridePDBoolTag.cs index 597a1eef..b665ff5d 100644 --- a/ItemChanger/Tags/OverridePDBoolTag.cs +++ b/ItemChanger/Tags/OverridePDBoolTag.cs @@ -10,12 +10,14 @@ public class OverridePDBoolTag : Tag public override void Load(object parent) { + base.Load(parent); ModHooks.GetPlayerBoolHook += GetPlayerBoolHook; if (overrideSet) ModHooks.SetPlayerBoolHook += SetPlayerBoolHook; } public override void Unload(object parent) { + base.Unload(parent); ModHooks.GetPlayerBoolHook -= GetPlayerBoolHook; if (overrideSet) ModHooks.SetPlayerBoolHook -= SetPlayerBoolHook; } diff --git a/ItemChanger/Tags/SetIBoolOnGiveTag.cs b/ItemChanger/Tags/SetIBoolOnGiveTag.cs index d8102e6d..69fb1640 100644 --- a/ItemChanger/Tags/SetIBoolOnGiveTag.cs +++ b/ItemChanger/Tags/SetIBoolOnGiveTag.cs @@ -11,6 +11,7 @@ public class SetIBoolOnGiveTag : Tag public override void Load(object parent) { + base.Load(parent); if (parent is AbstractItem item) { item.OnGive += OnGive; @@ -27,6 +28,7 @@ public override void Load(object parent) public override void Unload(object parent) { + base.Unload(parent); if (parent is AbstractItem item) { item.OnGive -= OnGive; diff --git a/ItemChanger/Tags/SetPDBoolOnGiveTag.cs b/ItemChanger/Tags/SetPDBoolOnGiveTag.cs index ed9b3e43..f1c90de6 100644 --- a/ItemChanger/Tags/SetPDBoolOnGiveTag.cs +++ b/ItemChanger/Tags/SetPDBoolOnGiveTag.cs @@ -12,12 +12,14 @@ public class SetPDBoolOnGiveTag : Tag public override void Load(object parent) { + base.Load(parent); AbstractItem item = (AbstractItem)parent; item.OnGive += OnGive; } public override void Unload(object parent) { + base.Unload(parent); AbstractItem item = (AbstractItem)parent; item.OnGive -= OnGive; } diff --git a/ItemChanger/Tags/SetPDBoolOnLoadTag.cs b/ItemChanger/Tags/SetPDBoolOnLoadTag.cs index 3506ce9d..1c0bac26 100644 --- a/ItemChanger/Tags/SetPDBoolOnLoadTag.cs +++ b/ItemChanger/Tags/SetPDBoolOnLoadTag.cs @@ -10,6 +10,7 @@ public class SetPDBoolOnLoadTag : Tag public override void Load(object parent) { + base.Load(parent); PlayerData.instance.SetBool(boolName, value); } }