diff --git a/RogueLibsCore.Test/RogueLibsCore.Test.csproj b/RogueLibsCore.Test/RogueLibsCore.Test.csproj index 2ef4daff2..6a45ffd01 100644 --- a/RogueLibsCore.Test/RogueLibsCore.Test.csproj +++ b/RogueLibsCore.Test/RogueLibsCore.Test.csproj @@ -36,7 +36,8 @@ True Resources.resx - + + diff --git a/RogueLibsCore.Test/TestPlugin.cs b/RogueLibsCore.Test/TestPlugin.cs index 7cf045caa..744badc98 100644 --- a/RogueLibsCore.Test/TestPlugin.cs +++ b/RogueLibsCore.Test/TestPlugin.cs @@ -23,11 +23,14 @@ public void Awake() { Log = Logger; Instance = this; + LootBox.Test(); Converter.Test(); Duplicator.Test(); NuclearBriefcase.Test(); + GiantAbility.Test(); + Smoker.Test(); } } diff --git a/RogueLibsCore.Test/Tests/GiantAbility.cs b/RogueLibsCore.Test/Tests/GiantAbility.cs new file mode 100644 index 000000000..367d6f210 --- /dev/null +++ b/RogueLibsCore.Test/Tests/GiantAbility.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace RogueLibsCore.Test +{ + public class GiantAbility : CustomAbility, IDoUpdate + { + public static void Test() + { + RogueLibs.CreateCustomAbility() + .WithName(new CustomNameInfo("Giant")) + .WithDescription(new CustomNameInfo("Transform into a giant and crush your enemies!")) + .WithSprite(Properties.Resources.Batteries) + .WithUnlock(new AbilityUnlock { UnlockCost = 15, CharacterCreationCost = 10, }); + } + + public override void SetupDetails() { } + public override string GetCountString() => recharge != 0f ? recharge.ToString() : base.GetCountString(); + + public override void OnAdded() { } + public override void OnHeld(OnAbilityHeldArgs e) { } + public override void OnReleased(OnAbilityReleasedArgs e) { } + public override void OnUpdated(OnAbilityUpdatedArgs e) { } + public override PlayfieldObject FindTarget() => null; + + private float recharge; + public void Update() => recharge = Mathf.Max(recharge - Time.deltaTime, 0f); + + public override void OnPressed() + { + if (recharge > 0f) return; + + Owner.statusEffects.AddStatusEffect("Giant", 15); + Owner.statusEffects.AddStatusEffect("Enraged", 15); + + recharge = 30f; + } + } +} diff --git a/RogueLibsCore.Test/Smoker.cs b/RogueLibsCore.Test/Tests/Smoker.cs similarity index 97% rename from RogueLibsCore.Test/Smoker.cs rename to RogueLibsCore.Test/Tests/Smoker.cs index 15375a28f..8a78dfda5 100644 --- a/RogueLibsCore.Test/Smoker.cs +++ b/RogueLibsCore.Test/Tests/Smoker.cs @@ -22,6 +22,7 @@ public static void Test() public override void OnAdded() { + RogueFramework.LogDebug(""); Owner.SetEndurance(Owner.enduranceStatMod - 1); Owner.SetSpeed(Owner.speedStatMod - 1); } diff --git a/RogueLibsCore/CustomName.cs b/RogueLibsCore/CustomName.cs index e04b0d5f9..277c6f6c1 100644 --- a/RogueLibsCore/CustomName.cs +++ b/RogueLibsCore/CustomName.cs @@ -140,7 +140,10 @@ public static void RegisterLanguageCode(string languageName, LanguageCode code) if (languageName is null) throw new ArgumentNullException(nameof(languageName)); if (languages.ContainsKey(languageName)) throw new ArgumentException($"The specified {nameof(languageName)} is already taken.", nameof(languageName)); - RogueFramework.Logger.LogDebug($"Registered \"{languageName}\" language ({(int)code})"); + + if (RogueFramework.IsDebugEnabled(DebugFlags.Names)) + RogueFramework.Logger.LogDebug($"Registered \"{languageName}\" language ({(int)code})"); + languages.Add(languageName, code); languageNames.Add(code, languageName); } @@ -165,6 +168,9 @@ public void GetName(string name, string type, ref string result) } public CustomName AddName(string name, string type, CustomNameInfo info) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Names)) + RogueFramework.LogDebug($"Added \"{name}\" name ({type}): {info.English}"); + CustomName customName = new CustomName(name, type, info); if (!CustomNames.TryGetValue(type, out Dictionary category)) CustomNames.Add(type, category = new Dictionary()); diff --git a/RogueLibsCore/Hooks/Effects/CustomEffect.cs b/RogueLibsCore/Hooks/Effects/CustomEffect.cs index 08a3aa5e4..bd7102d17 100644 --- a/RogueLibsCore/Hooks/Effects/CustomEffect.cs +++ b/RogueLibsCore/Hooks/Effects/CustomEffect.cs @@ -61,6 +61,8 @@ public override bool TryCreate(StatusEffect instance, out IHook ho public EffectInfo AddEffect() where T : CustomEffect, new() { EffectInfo info = EffectInfo.Get(); + if (RogueFramework.IsDebugEnabled(DebugFlags.Effects)) + RogueFramework.LogDebug($"Created custom effect {typeof(T)} ({info.Name})."); effectsDict.Add(info.Name, new EffectEntry { Initializer = () => new T(), EffectInfo = info }); return info; } diff --git a/RogueLibsCore/Hooks/Items/CustomItem.cs b/RogueLibsCore/Hooks/Items/CustomItem.cs index 84e3a99aa..7de03701e 100644 --- a/RogueLibsCore/Hooks/Items/CustomItem.cs +++ b/RogueLibsCore/Hooks/Items/CustomItem.cs @@ -106,6 +106,8 @@ public override bool TryCreate(InvItem instance, out IHook hook) public ItemInfo AddItem() where T : CustomItem, new() { ItemInfo info = ItemInfo.Get(); + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug($"Created custom item {typeof(T)} ({info.Name})."); itemsDict.Add(info.Name, new ItemEntry { Initializer = () => new T(), ItemInfo = info }); return info; } diff --git a/RogueLibsCore/Hooks/Items/InventoryChecks.cs b/RogueLibsCore/Hooks/Items/InventoryChecks.cs index f26b0ca6b..8aa9cd6df 100644 --- a/RogueLibsCore/Hooks/Items/InventoryChecks.cs +++ b/RogueLibsCore/Hooks/Items/InventoryChecks.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; namespace RogueLibsCore { @@ -11,13 +12,32 @@ public static class InventoryChecks internal static readonly RogueEvent onItemUsing = new RogueEvent(); internal static readonly RogueEvent onItemsCombining = new RogueEvent(); internal static readonly RogueEvent onItemTargeting = new RogueEvent(); + internal static readonly RogueEvent onItemTargetingAnywhere = new RogueEvent(); public static void AddItemUsingCheck(string name, RogueEventHandler check) - => onItemUsing.Subscribe(name, check); + { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug($"Added \"{name}\" usage inventory check."); + onItemUsing.Subscribe(name, check); + } public static void AddItemsCombiningCheck(string name, RogueEventHandler check) - => onItemsCombining.Subscribe(name, check); + { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug($"Added \"{name}\" combining inventory check."); + onItemsCombining.Subscribe(name, check); + } public static void AddItemTargetingCheck(string name, RogueEventHandler check) - => onItemTargeting.Subscribe(name, check); + { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug($"Added \"{name}\" targeting inventory check."); + onItemTargeting.Subscribe(name, check); + } + public static void AddItemTargetingAnywhereCheck(string name, RogueEventHandler check) + { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug($"Added \"{name}\" targeting anywhere inventory check."); + onItemTargetingAnywhere.Subscribe(name, check); + } public static bool IsCheckAllowed(InvItem item, string checkName) => IsCheckAllowed(item?.GetHook(), checkName); public static bool IsCheckAllowed(CustomItem customItem, string checkName) @@ -60,6 +80,19 @@ public OnItemTargetingArgs(InvItem item, PlayfieldObject targetObject, Agent use public PlayfieldObject Target { get; set; } public Agent User { get; set; } } + public class OnItemTargetingAnywhereArgs : RogueEventArgs + { + public OnItemTargetingAnywhereArgs(InvItem item, Vector2 position, Agent user) + { + Item = item; + Target = position; + User = user; + } + public InvDatabase Inventory => Item.database; + public InvItem Item { get; } + public Vector2 Target { get; set; } + public Agent User { get; set; } + } public class RogueEvent where TArgs : RogueEventArgs { private readonly List> list = new List>(0); diff --git a/RogueLibsCore/Hooks/Traits/CustomTrait.cs b/RogueLibsCore/Hooks/Traits/CustomTrait.cs index a3ad32845..e62883f70 100644 --- a/RogueLibsCore/Hooks/Traits/CustomTrait.cs +++ b/RogueLibsCore/Hooks/Traits/CustomTrait.cs @@ -46,6 +46,8 @@ public override bool TryCreate(Trait instance, out IHook hook) public TraitInfo AddTrait() where T : CustomTrait, new() { TraitInfo info = TraitInfo.Get(); + if (RogueFramework.IsDebugEnabled(DebugFlags.Traits)) + RogueFramework.LogDebug($"Created custom trait {typeof(T)} ({info.Name})."); traitsDict.Add(info.Name, new TraitEntry { Initializer = () => new T(), TraitInfo = info }); return info; } diff --git a/RogueLibsCore/Patches/Patches_Abilities.cs b/RogueLibsCore/Patches/Patches_Abilities.cs index 5576b6a1c..6c53e44c3 100644 --- a/RogueLibsCore/Patches/Patches_Abilities.cs +++ b/RogueLibsCore/Patches/Patches_Abilities.cs @@ -30,12 +30,12 @@ public static void StatusEffects_GiveSpecialAbility(StatusEffects __instance) CustomAbility custom = __instance.agent.GetAbility(); if (custom is null) return; + if (RogueFramework.IsDebugEnabled(DebugFlags.Abilities)) + RogueFramework.LogDebug($"Giving ability {custom} ({__instance.agent.specialAbility}, {__instance.agent.agentName})."); + try { custom.OnAdded(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error in CustomAbility.OnAdded() - {custom} ({__instance.agent.specialAbility})"); - RogueFramework.Logger.LogError(e); - } + catch (Exception e) { RogueFramework.LogError(e, "CustomAbility.OnAdded", custom, __instance.agent); } + __instance.SpecialAbilityInterfaceCheck(); __instance.RechargeSpecialAbility(custom.ItemInfo.Name); } @@ -45,12 +45,11 @@ public static void StatusEffects_PressedSpecialAbility(StatusEffects __instance) CustomAbility custom = __instance.agent.GetAbility(); if (custom is null) return; - try { custom?.OnPressed(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error in CustomAbility.OnPressed() - {custom} ({__instance.agent.specialAbility})"); - RogueFramework.Logger.LogError(e); - } + if (RogueFramework.IsDebugEnabled(DebugFlags.Abilities)) + RogueFramework.LogDebug($"Pressing ability ability {custom} ({__instance.agent.specialAbility}, {__instance.agent.agentName})."); + + try { custom.OnPressed(); } + catch (Exception e) { RogueFramework.LogError(e, "CustomAbility.OnPressed", custom, __instance.agent); } } public static void StatusEffects_HeldSpecialAbility(StatusEffects __instance) { @@ -60,18 +59,16 @@ public static void StatusEffects_HeldSpecialAbility(StatusEffects __instance) ref float held = ref GameController.gameController.playerControl.pressedSpecialAbilityTime[__instance.agent.isPlayer - 1]; float prevHeld = held; + if (RogueFramework.IsDebugEnabled(DebugFlags.Abilities)) + RogueFramework.LogDebug($"Holding ability {custom} for {prevHeld}s ({__instance.agent.specialAbility}, {__instance.agent.agentName})."); + OnAbilityHeldArgs args = new OnAbilityHeldArgs { HeldTime = prevHeld }; try { custom.OnHeld(args); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error in CustomAbility.OnHeld() - {custom} ({__instance.agent.specialAbility})"); - RogueFramework.Logger.LogError(e); - } + catch (Exception e) { RogueFramework.LogError(e, "CustomAbility.OnHeld", custom, __instance.agent); } held = args.HeldTime; - custom.lastHeld = args.HeldTime; - - if (held is 0f) custom.OnReleased(new OnAbilityReleasedArgs(prevHeld)); + custom.lastHeld = prevHeld; + __instance.ReleasedSpecialAbility(); } public static void StatusEffects_ReleasedSpecialAbility(StatusEffects __instance) { @@ -81,13 +78,12 @@ public static void StatusEffects_ReleasedSpecialAbility(StatusEffects __instance float prevHeld = custom.lastHeld; if (prevHeld is 0f) return; + if (RogueFramework.IsDebugEnabled(DebugFlags.Abilities)) + RogueFramework.LogDebug($"Releasing ability {custom} - {prevHeld}s ({__instance.agent.specialAbility}, {__instance.agent.agentName})."); + custom.lastHeld = 0f; try { custom.OnReleased(new OnAbilityReleasedArgs(prevHeld)); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error in CustomAbility.OnReleased() - {custom} ({__instance.agent.specialAbility})"); - RogueFramework.Logger.LogError(e); - } + catch (Exception e) { RogueFramework.LogError(e, "CustomAbility.OnReleased", custom, __instance.agent); } } } } diff --git a/RogueLibsCore/Patches/Patches_CharacterCreation.cs b/RogueLibsCore/Patches/Patches_CharacterCreation.cs index 884168ce2..d562e3dd8 100644 --- a/RogueLibsCore/Patches/Patches_CharacterCreation.cs +++ b/RogueLibsCore/Patches/Patches_CharacterCreation.cs @@ -8,6 +8,8 @@ using UnityEngine.UI; using BepInEx; using HarmonyLib; +using static UnityEngine.Random; +using System.Diagnostics; namespace RogueLibsCore { @@ -41,6 +43,8 @@ public static bool CharacterCreation_SortUnlocks(CharacterCreation __instance, L displayedList.Sort(); CustomCharacterCreation menu = new CustomCharacterCreation(__instance, displayedList); + if (RogueFramework.IsDebugEnabled(DebugFlags.UnlockMenus)) + RogueFramework.LogDebug($"Setting up \"{menu.Type}\" menu."); List listUnlocks = unlockType == "Item" ? __instance.listUnlocksItems : unlockType == "Trait" ? __instance.listUnlocksTraits @@ -72,7 +76,14 @@ public static bool CharacterCreation_SortUnlocks(CharacterCreation __instance, L public static bool CharacterCreation_PushedButton(CharacterCreation __instance, ButtonHelper myButton) { - if (__instance.selectedSpace == "Load") return true; + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.UnlockMenus); + if (__instance.selectedSpace == "Load") + { + if (debug) RogueFramework.LogDebug("Redirecting the button push to the original method."); + return true; + } + + if (debug) RogueFramework.LogDebug($"Pressing \"{myButton.myText.text}\" ({myButton.scrollingButtonNum}, {myButton.scrollingButtonType}) button."); string type = myButton.scrollingButtonUnlock.unlockType; List buttonsData = type == "Item" ? __instance.buttonsDataItems @@ -83,7 +94,8 @@ public static bool CharacterCreation_PushedButton(CharacterCreation __instance, ButtonData buttonData = buttonsData[myButton.scrollingButtonNum]; DisplayedUnlock du = (DisplayedUnlock)buttonData.__RogueLibsCustom; - du.OnPushedButton(); + try { du.OnPushedButton(); } + catch (Exception e) { RogueFramework.LogError(e, "DisplayedUnlock.OnPushedButton", du, du.Menu); } __instance.curSelectedButton = myButton; __instance.curSelectedButtonNum = myButton.scrollingButtonNum; return false; diff --git a/RogueLibsCore/Patches/Patches_Items.cs b/RogueLibsCore/Patches/Patches_Items.cs index a824bcfaf..199136529 100644 --- a/RogueLibsCore/Patches/Patches_Items.cs +++ b/RogueLibsCore/Patches/Patches_Items.cs @@ -8,6 +8,7 @@ using UnityEngine.UI; using BepInEx; using HarmonyLib; +using System.Diagnostics; namespace RogueLibsCore { @@ -44,9 +45,18 @@ public void PatchItems() public static void InvItem_SetupDetails(InvItem __instance) { + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.Items); + bool debug2 = RogueFramework.IsDebugEnabled(DebugFlags.Abilities); foreach (IHookFactory factory in RogueFramework.ItemFactories) if (factory.TryCreate(__instance, out IHook hook)) { + if (debug2 && hook is CustomAbility) + RogueFramework.LogDebug($"Initializing custom ability {hook} ({__instance.invItemName})."); + else if (debug) + { + if (hook is CustomItem) RogueFramework.LogDebug($"Initializing custom item {hook} ({__instance.invItemName})."); + else RogueFramework.LogDebug($"Initializing item hook {hook} for \"{__instance.invItemName}\"."); + } __instance.AddHook(hook); hook.Initialize(); } @@ -54,13 +64,17 @@ public static void InvItem_SetupDetails(InvItem __instance) public static bool ItemFunctions_UseItem(InvItem item, Agent agent) { + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.Items); CustomItem custom = item.GetHook(); if (custom is IItemTargetable || custom is IItemTargetableAnywhere) { + if (debug) RogueFramework.LogDebug($"Showing target for {custom} ({item.invItemName})."); item.invInterface.ShowOrHideTarget(item); return false; } + if (debug) RogueFramework.LogDebug($"Using {custom} ({item.invItemName}):"); + Agent originalAgent = agent; OnItemUsingArgs args = new OnItemUsingArgs(item, agent); if (InventoryChecks.onItemUsing.Raise(args, custom?.ItemInfo.IgnoredChecks)) @@ -82,19 +96,31 @@ public static bool ItemFunctions_UseItem(InvItem item, Agent agent) } // if it's not a custom item, run the original method if (!(custom is IItemUsable usable)) + { + if (debug) RogueFramework.LogDebug("---- Running the original method."); return true; + } bool success = usable.UseItem(); + if (debug) RogueFramework.LogDebug($"---- Usage {(success ? "was successful" : "failed")}."); if (success) new ItemFunctions().UseItemAnim(item, agent); } } + else + { + if (debug) RogueFramework.LogDebug("---- Usage was prevented by an inventory check."); + } return false; } public static bool InvItem_CombineItems(InvItem __instance, InvItem otherItem, int slotNum, Agent myAgent, string combineType, ref bool __result) { + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.Items); + bool actualCombining = combineType == "Combine"; CustomItem custom = __instance.GetHook(); + if (debug && actualCombining) RogueFramework.LogDebug($"Combining {custom} ({__instance.invItemName}) with {otherItem.invItemName}:"); + if (__instance.stackable && __instance.invItemName == otherItem.invItemName && InventoryChecks.IsCheckAllowed(custom, "AutoStacking")) { @@ -103,8 +129,13 @@ public static bool InvItem_CombineItems(InvItem __instance, InvItem otherItem, i __result = false; return false; } - if (combineType == "Combine") + if (actualCombining) { + if (debug) + { + RogueFramework.LogDebug("---- Triggered \"AutoStacking\" inventory check."); + RogueFramework.LogDebug("---- Combining was prevented by an inventory check."); + } if (myAgent.controllerType != "Keyboard") myAgent.gc.audioHandler.Play(myAgent, "BeginCombine"); otherItem.agent.mainGUI.invInterface.PutDraggedItemBack(); @@ -113,83 +144,127 @@ public static bool InvItem_CombineItems(InvItem __instance, InvItem otherItem, i return false; } - bool filterResult; if (custom is IItemCombinable combinable) { using (AgentSwapper swapper = new AgentSwapper(__instance, myAgent)) - filterResult = combinable.CombineFilter(otherItem); + __result = combinable.CombineFilter(otherItem); } - else filterResult = new ItemFunctions().CombineItems(__instance, myAgent, otherItem, slotNum, string.Empty); - - OnItemsCombiningArgs args = new OnItemsCombiningArgs(__instance, otherItem, myAgent); - __result = filterResult && InventoryChecks.onItemsCombining.Raise(args, custom?.ItemInfo.IgnoredChecks); + else __result = new ItemFunctions().CombineItems(__instance, myAgent, otherItem, slotNum, string.Empty); - if (__result && combineType == "Combine") + if (actualCombining) { - myAgent = args.Combiner; - otherItem = args.OtherItem; - if (custom is IItemCombinable combinable2) + OnItemsCombiningArgs args = new OnItemsCombiningArgs(__instance, otherItem, myAgent); + if (InventoryChecks.onItemsCombining.Raise(args, custom?.ItemInfo.IgnoredChecks)) { - using (AgentSwapper swapper = new AgentSwapper(__instance, myAgent)) + myAgent = args.Combiner; + otherItem = args.OtherItem; + if (custom is IItemCombinable combinable2) { - bool success = combinable2.CombineItems(otherItem); - if (success) new ItemFunctions().UseItemAnim(__instance, myAgent); + using (AgentSwapper swapper = new AgentSwapper(__instance, myAgent)) + { + bool success = combinable2.CombineItems(otherItem); + if (debug) RogueFramework.LogDebug($"---- Combining {(success ? "was successful" : "failed")}."); + if (success) new ItemFunctions().UseItemAnim(__instance, myAgent); + } + } + else + { + if (debug) RogueFramework.LogDebug("---- Running the original method."); + new ItemFunctions().CombineItems(__instance, myAgent, otherItem, slotNum, "Combine"); } - } - else new ItemFunctions().CombineItems(__instance, myAgent, otherItem, slotNum, "Combine"); - if (__instance.invItemCount < 1 || !__instance.database.InvItemList.Contains(__instance) - && InventoryChecks.IsCheckAllowed(custom, "StopOnZero")) + if (__instance.invItemCount < 1 || !__instance.database.InvItemList.Contains(__instance) + && InventoryChecks.IsCheckAllowed(custom, "StopOnZero")) + { + if (debug) RogueFramework.LogDebug("---- Triggered \"StopOnZero\" inventory check."); + myAgent.mainGUI.invInterface.HideDraggedItem(); + myAgent.mainGUI.invInterface.HideTarget(); + } + } + else { - myAgent.mainGUI.invInterface.HideDraggedItem(); - myAgent.mainGUI.invInterface.HideTarget(); + if (debug) RogueFramework.LogDebug("---- Combining was prevented by an inventory check."); } } return false; } public static bool InvItem_TargetObject(InvItem __instance, PlayfieldObject otherObject, string combineType, ref bool __result) { + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.Items); + bool actualCombining = combineType == "Combine"; CustomItem custom = __instance.GetHook(); + if (debug && actualCombining) RogueFramework.LogDebug($"Targeting {custom} ({__instance.invItemName}) on {otherObject.objectName}:"); + if (Vector2.Distance(__instance.agent.curPosition, otherObject.curPosition) > 15f && InventoryChecks.IsCheckAllowed(custom, "Distance")) { + if (debug && actualCombining) + { + RogueFramework.LogDebug("---- Triggered \"Distance\" inventory check."); + RogueFramework.LogDebug("---- Targeting was prevented by an inventory check."); + } __result = false; return false; } if ((otherObject as Agent)?.butlerBot == true && InventoryChecks.IsCheckAllowed(custom, "ButlerBot")) { + if (debug && actualCombining) + { + RogueFramework.LogDebug("---- Triggered \"ButlerBot\" inventory check."); + RogueFramework.LogDebug("---- Targeting was prevented by an inventory check."); + } __result = false; return false; } if ((otherObject as Agent)?.mechEmpty == true && InventoryChecks.IsCheckAllowed(custom, "EmptyMech")) { + if (debug && actualCombining) + { + RogueFramework.LogDebug("---- Triggered \"EmptyMech\" inventory check."); + RogueFramework.LogDebug("---- Targeting was prevented by an inventory check."); + } __result = false; return false; } - bool firstCheck = custom is IItemTargetable targetable + __result = custom is IItemTargetable targetable ? targetable.TargetFilter(otherObject) : new ItemFunctions().TargetObject(__instance, __instance.agent, otherObject, string.Empty); - OnItemTargetingArgs args = new OnItemTargetingArgs(__instance, otherObject, __instance.agent); - __result = firstCheck && InventoryChecks.onItemTargeting.Raise(args, custom?.ItemInfo.IgnoredChecks); - - if (__result && combineType == "Combine") + if (actualCombining) { - otherObject = args.Target; - using (AgentSwapper swapper = new AgentSwapper(__instance, args.User)) + OnItemTargetingArgs args = new OnItemTargetingArgs(__instance, otherObject, __instance.agent); + if (InventoryChecks.onItemTargeting.Raise(args, custom?.ItemInfo.IgnoredChecks)) { - if (custom is IItemTargetable targetable2) targetable2.TargetObject(otherObject); - else new ItemFunctions().TargetObject(__instance, __instance.agent, otherObject, "Combine"); - - if (__instance.invItemCount < 1 || !__instance.database.InvItemList.Contains(__instance) - && InventoryChecks.IsCheckAllowed(custom, "StopOnZero")) + otherObject = args.Target; + using (AgentSwapper swapper = new AgentSwapper(__instance, args.User)) { - __instance.agent.mainGUI.invInterface.HideDraggedItem(); - __instance.agent.mainGUI.invInterface.HideTarget(); + if (custom is IItemTargetable targetable2) + { + bool success = targetable2.TargetObject(otherObject); + if (debug) RogueFramework.LogDebug($"---- Targeting {(success ? "was successful" : "failed")}."); + if (success) new ItemFunctions().UseItemAnim(__instance, __instance.agent); + } + else + { + if (debug) RogueFramework.LogDebug("---- Running the original method."); + new ItemFunctions().TargetObject(__instance, __instance.agent, otherObject, "Combine"); + } + + if (__instance.invItemCount < 1 || !__instance.database.InvItemList.Contains(__instance) + && InventoryChecks.IsCheckAllowed(custom, "StopOnZero")) + { + if (debug) RogueFramework.LogDebug("---- Triggered \"StopOnZero\" inventory check."); + __instance.agent.mainGUI.invInterface.HideDraggedItem(); + __instance.agent.mainGUI.invInterface.HideTarget(); + } } } + else + { + if (debug) RogueFramework.LogDebug("---- Targeting was prevented by an inventory check."); + } } return false; } @@ -311,12 +386,16 @@ public static void InvSlot_UpdateInvSlot(InvSlot __instance, Text ___itemText) public static void InvInterface_TargetAnywhere(InvInterface __instance, Vector2 myPos, bool pressedButton) { - if (__instance.mainGUI.targetItem != null) + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.Items); + InvItem invItem = __instance.mainGUI.targetItem; + if (invItem != null) { - CustomItem custom = __instance.mainGUI.targetItem.GetHook(); + CustomItem custom = invItem.GetHook(); __instance.cursorHighlightTargetObjects = custom is IItemTargetable; if (custom is IItemTargetableAnywhere targetable) { + if (debug && pressedButton) + RogueFramework.LogDebug($"Targeting {custom} ({invItem.invItemName}) anywhere:"); if (targetTextColor is null) targetTextColor = __instance.cursorTextString3.color; bool filter = targetable.TargetFilter(myPos); @@ -330,13 +409,29 @@ public static void InvInterface_TargetAnywhere(InvInterface __instance, Vector2 if (pressedButton) { - targetable.TargetPosition(myPos); - if (custom.Count < 1 || !custom.Inventory.InvItemList.Contains(custom.Item)) + OnItemTargetingAnywhereArgs args = new OnItemTargetingAnywhereArgs(invItem, myPos, invItem.agent); + if (InventoryChecks.onItemTargetingAnywhere.Raise(args, custom?.ItemInfo.IgnoredChecks)) + { + myPos = args.Target; + using (AgentSwapper swapper = new AgentSwapper(invItem, args.User)) + { + bool success = targetable.TargetPosition(myPos); + if (debug) RogueFramework.LogDebug($"---- Targeting {(success ? "was successful" : "failed")}."); + if (success) new ItemFunctions().UseItemAnim(invItem, invItem.agent); + + if (custom.Count < 1 || !custom.Inventory.InvItemList.Contains(custom.Item) + && InventoryChecks.IsCheckAllowed(custom, "StopOnZero")) + { + if (debug) RogueFramework.LogDebug("---- Triggered \"StopOnZero\" inventory check."); + __instance.HideDraggedItem(); + __instance.HideTarget(); + } + } + } + else { - __instance.HideDraggedItem(); - __instance.HideTarget(); + if (debug) RogueFramework.LogDebug("---- Targeting was prevented by an inventory check."); } - __instance.HideTarget(); } } } @@ -375,6 +470,8 @@ public static void GhostCheck(OnItemUsingArgs e) { if (e.User.ghost) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"Ghost\" inventory check."); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; } @@ -383,6 +480,8 @@ public static void PeaBrainedCheck(OnItemUsingArgs e) { if (e.Item.itemType != ItemTypes.Food && e.User.HasTrait("CantInteract")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"PeaBrained\" inventory check."); e.User.SayDialogue("CantInteract"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -393,6 +492,8 @@ public static void OnlyOilCheck(OnItemUsingArgs e) if (e.Item.itemType == ItemTypes.Food && (e.Item.Categories.Contains("Food") || e.Item.Categories.Contains("Alcohol")) && e.User.HasTrait("OilRestoresHealth")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"OnlyOil\" inventory check."); e.User.SayDialogue("OnlyOilGivesHealth"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -403,6 +504,8 @@ public static void OnlyOilMedicineCheck(OnItemUsingArgs e) if (e.Item.itemType == ItemTypes.Consumable && e.Item.Categories.Contains("Health") && e.User.HasTrait("OilRestoresHealth")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"OnlyOilMedicine\" inventory check."); e.User.SayDialogue("OnlyOilGivesHealth"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -413,6 +516,8 @@ public static void OnlyBloodCheck(OnItemUsingArgs e) if (e.Item.itemType == ItemTypes.Food && (e.Item.Categories.Contains("Food") || e.Item.Categories.Contains("Alcohol")) && e.User.HasTrait("BloodRestoresHealth")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"OnlyBlood\" inventory check."); e.User.SayDialogue("OnlyBloodGivesHealth"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -423,6 +528,8 @@ public static void OnlyBloodMedicineCheck(OnItemUsingArgs e) if (e.Item.itemType == ItemTypes.Consumable && e.Item.Categories.Contains("Health") && e.User.HasTrait("BloodRestoresHealth")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"OnlyBloodMedicine\" inventory check."); e.User.SayDialogue("OnlyBloodGivesHealth2"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -432,6 +539,8 @@ public static void OnlyChargeCheck(OnItemUsingArgs e) { if (e.User.electronic && e.Item.itemType == ItemTypes.Food && e.Item.Categories.Contains("Food")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"OnlyCharge\" inventory check."); e.User.SayDialogue("OnlyChargeGivesHealth"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -441,6 +550,8 @@ public static void OnlyChargeMedicineCheck(OnItemUsingArgs e) { if (e.User.electronic && e.Item.itemType == ItemTypes.Consumable && e.Item.Categories.Contains("Health")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"OnlyChargeMedicine\" inventory check."); e.User.SayDialogue("OnlyChargeGivesHealth"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -451,6 +562,8 @@ public static void OnlyHumanFleshCheck(OnItemUsingArgs e) if (e.Item.itemType == ItemTypes.Food && e.Item.Categories.Contains("Food") && e.User.HasTrait("CannibalizeRestoresHealth")) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"OnlyHumanFlesh\" inventory check."); e.User.SayDialogue("OnlyCannibalizeGivesHealth"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; @@ -460,6 +573,8 @@ public static void FullHealthCheck(OnItemUsingArgs e) { if (e.Item.healthChange > 0 && e.User.health == e.User.healthMax) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Items)) + RogueFramework.LogDebug("---- Triggered \"FullHealth\" inventory check."); e.User.SayDialogue("HealthFullCantUseItem"); e.User.gc.audioHandler.Play(e.User, "CantDo"); e.Cancel = e.Handled = true; diff --git a/RogueLibsCore/Patches/Patches_Misc.cs b/RogueLibsCore/Patches/Patches_Misc.cs index be0f072b7..ccc5daff7 100644 --- a/RogueLibsCore/Patches/Patches_Misc.cs +++ b/RogueLibsCore/Patches/Patches_Misc.cs @@ -15,14 +15,14 @@ public partial class RogueLibsPlugin { public void PatchMisc() { - // get and set the current game language as a LanguageCode + // initialize LanguageService Patcher.Postfix(typeof(NameDB), nameof(NameDB.RealAwake)); // CustomNames Patcher.Postfix(typeof(NameDB), nameof(NameDB.GetName)); - // IDoUpdate.Update() + // IDoUpdate.Update Patcher.Postfix(typeof(Updater), "Update"); - // IDoFixedUpdate.FixedUpdate() + // IDoFixedUpdate.FixedUpdate Patcher.Postfix(typeof(Updater), nameof(Updater.FixedUpdate)); } @@ -30,6 +30,8 @@ public static void NameDB_RealAwake(NameDB __instance) { if (!LanguageService.Languages.TryGetValue(__instance.language, out LanguageCode code)) code = LanguageCode.English; + if (RogueFramework.IsDebugEnabled(DebugFlags.Names)) + RogueFramework.LogDebug($"Current language: {LanguageService.GetLanguageName(code)} ({(int)code})"); LanguageService.NameDB = __instance; LanguageService.Current = code; @@ -47,153 +49,101 @@ public static void NameDB_GetName(string myName, string type, ref string __resul public static void Updater_Update() { - List agents = GameController.gameController.agentList; - for (int i = 0; i < agents.Count; i++) + foreach (Agent agent in GameController.gameController.agentList.ToList()) { - Agent agent = agents[i]; - foreach (IDoUpdate obj in agents[i].GetHooks()) + foreach (IDoUpdate obj in agent.GetHooks()) try { obj.Update(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {agent.agentName}"); - RogueFramework.Logger.LogError(e); - } - - for (int j = 0; j < agent.inventory.InvItemList.Count; j++) - { - InvItem item = agent.inventory.InvItemList[j]; - foreach (IDoUpdate obj in item.GetHooks()) + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj); } + + InvItem specialAbility = agent.inventory.equippedSpecialAbility; + if (specialAbility != null) + foreach (IDoUpdate obj in specialAbility.GetHooks()) try { obj.Update(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {item.invItemName} ({agent.agentName})"); - RogueFramework.Logger.LogError(e); - } - } - - for (int j = 0; j < agent.statusEffects.StatusEffectList.Count; j++) - { - StatusEffect effect = agent.statusEffects.StatusEffectList[j]; + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj, agent); } + + foreach (InvItem item in agent.inventory.InvItemList.ToList()) + if (item != specialAbility) + foreach (IDoUpdate obj in item.GetHooks()) + try { obj.Update(); } + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj, agent); } + + foreach (StatusEffect effect in agent.statusEffects.StatusEffectList.ToList()) foreach (IDoUpdate obj in effect.GetHooks()) try { obj.Update(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {effect.statusEffectName} ({agent.agentName})"); - RogueFramework.Logger.LogError(e); - } - } - - for (int j = 0; j < agent.statusEffects.TraitList.Count; j++) - { - Trait trait = agent.statusEffects.TraitList[j]; + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj, agent); } + + foreach (Trait trait in agent.statusEffects.TraitList.ToList()) foreach (IDoUpdate obj in trait.GetHooks()) try { obj.Update(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {trait.traitName} ({agent.agentName})"); - RogueFramework.Logger.LogError(e); - } - } + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj, agent); } } - List items = GameController.gameController.itemList; - for (int i = 0; i < items.Count; i++) + foreach (ObjectReal objectReal in GameController.gameController.objectRealListUpdate.ToList()) { - foreach (IDoUpdate obj in items[i].invItem.GetHooks()) + foreach (IDoUpdate obj in objectReal.GetHooks()) try { obj.Update(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {items[i]}"); - RogueFramework.Logger.LogError(e); - } + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj); } + + if (objectReal.objectInvDatabase != null) + foreach (InvItem item in objectReal.objectInvDatabase.InvItemList) + foreach (IDoUpdate obj in item.GetHooks()) + try { obj.Update(); } + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj, objectReal); } } - List objects = GameController.gameController.objectRealListUpdate; - for (int i = 0; i < objects.Count; i++) - { - foreach (IDoUpdate obj in objects[i].GetHooks()) + foreach (Item item in GameController.gameController.itemList.ToList()) + foreach (IDoUpdate obj in item.invItem.GetHooks()) try { obj.Update(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {objects[i].objectName}"); - RogueFramework.Logger.LogError(e); - } - } + catch (Exception e) { RogueFramework.LogError(e, "IDoUpdate.Update", obj, item); } } public static void Updater_FixedUpdate() { - List agents = GameController.gameController.agentList; - for (int i = 0; i < agents.Count; i++) + foreach (Agent agent in GameController.gameController.agentList.ToList()) { - Agent agent = agents[i]; - foreach (IDoFixedUpdate obj in agents[i].GetHooks()) + foreach (IDoFixedUpdate obj in agent.GetHooks()) try { obj.FixedUpdate(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {agent.agentName}"); - RogueFramework.Logger.LogError(e); - } - - for (int j = 0; j < agent.inventory.InvItemList.Count; j++) - { - InvItem item = agent.inventory.InvItemList[j]; - foreach (IDoFixedUpdate obj in item.GetHooks()) + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj); } + + InvItem specialAbility = agent.inventory.equippedSpecialAbility; + if (specialAbility != null) + foreach (IDoFixedUpdate obj in specialAbility.GetHooks()) try { obj.FixedUpdate(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {item.invItemName} ({agent.agentName})"); - RogueFramework.Logger.LogError(e); - } - } - - for (int j = 0; j < agent.statusEffects.StatusEffectList.Count; j++) - { - StatusEffect effect = agent.statusEffects.StatusEffectList[j]; + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj, agent); } + + foreach (InvItem item in agent.inventory.InvItemList.ToList()) + if (item != specialAbility) + foreach (IDoFixedUpdate obj in item.GetHooks()) + try { obj.FixedUpdate(); } + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj, agent); } + + foreach (StatusEffect effect in agent.statusEffects.StatusEffectList.ToList()) foreach (IDoFixedUpdate obj in effect.GetHooks()) try { obj.FixedUpdate(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {effect.statusEffectName} ({agent.agentName})"); - RogueFramework.Logger.LogError(e); - } - } - - for (int j = 0; j < agent.statusEffects.TraitList.Count; j++) - { - Trait trait = agent.statusEffects.TraitList[j]; + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj, agent); } + + foreach (Trait trait in agent.statusEffects.TraitList.ToList()) foreach (IDoFixedUpdate obj in trait.GetHooks()) try { obj.FixedUpdate(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {trait.traitName} ({agent.agentName})"); - RogueFramework.Logger.LogError(e); - } - } + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj, agent); } } - List items = GameController.gameController.itemList; - for (int i = 0; i < items.Count; i++) + foreach (ObjectReal objectReal in GameController.gameController.objectRealListUpdate.ToList()) { - foreach (IDoFixedUpdate obj in items[i].invItem.GetHooks()) + foreach (IDoFixedUpdate obj in objectReal.GetHooks()) try { obj.FixedUpdate(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {items[i]}"); - RogueFramework.Logger.LogError(e); - } + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj); } + + if (objectReal.objectInvDatabase != null) + foreach (InvItem item in objectReal.objectInvDatabase.InvItemList) + foreach (IDoFixedUpdate obj in item.GetHooks()) + try { obj.FixedUpdate(); } + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj, objectReal); } } - List objects = GameController.gameController.objectRealListUpdate; - for (int i = 0; i < objects.Count; i++) - { - foreach (IDoFixedUpdate obj in objects[i].GetHooks()) + foreach (Item item in GameController.gameController.itemList.ToList()) + foreach (IDoFixedUpdate obj in item.invItem.GetHooks()) try { obj.FixedUpdate(); } - catch (Exception e) - { - RogueFramework.Logger.LogError($"Error updating {obj} in {objects[i].objectName}"); - RogueFramework.Logger.LogError(e); - } - } + catch (Exception e) { RogueFramework.LogError(e, "IDoFixedUpdate.FixedUpdate", obj, item); } } } } diff --git a/RogueLibsCore/Patches/Patches_ScrollingMenu.cs b/RogueLibsCore/Patches/Patches_ScrollingMenu.cs index 1b3a2cb11..93ed592ed 100644 --- a/RogueLibsCore/Patches/Patches_ScrollingMenu.cs +++ b/RogueLibsCore/Patches/Patches_ScrollingMenu.cs @@ -40,18 +40,22 @@ public void PatchScrollingMenu() Patcher.Postfix(typeof(ScrollingMenu), nameof(ScrollingMenu.CanHaveTrait)); RogueLibs.CreateCustomName("GiveNuggetsDebug", "Unlock", new CustomNameInfo("[DEBUG] +10 Nuggets")); - RogueLibs.CreateCustomName("D_GiveNuggetsDebug", "Unlock", new CustomNameInfo("A debug-build feature that gives you 10 nuggets.")); + RogueLibs.CreateCustomName("D_GiveNuggetsDebug", "Unlock", new CustomNameInfo("A debug tool that gives you 10 nuggets.")); } public static void ScrollingMenu_OpenScrollingMenu_Prefix(ScrollingMenu __instance, out float __state) { float x = 1f - __instance.scrollBar.value; __state = x * (__instance.numButtons - __instance.numButtonsOnScreen + 1f); + if (RogueFramework.IsDebugEnabled(DebugFlags.UnlockMenus)) + RogueFramework.LogDebug($"Stored menu's scrolling value of {__state} units."); } public static void ScrollingMenu_OpenScrollingMenu(ScrollingMenu __instance, ref float __state, List ___listUnlocks) { __instance.numButtons = ___listUnlocks.Count; float x = __state / (__instance.numButtons - __instance.numButtonsOnScreen + 1f); + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.UnlockMenus); + if (debug) RogueFramework.LogDebug($"Restoring menu's scrolling value of {__state} units."); __instance.StartCoroutine(EnsureScrollbarValue(__instance, Mathf.Clamp01(1f - x))); if (__instance.menuType == "Challenges" || __instance.menuType == "FreeItems") @@ -60,6 +64,7 @@ public static void ScrollingMenu_OpenScrollingMenu(ScrollingMenu __instance, ref } else if (__instance.menuType == "Floors") { + if (debug) RogueFramework.LogDebug("Setting up \"Floors\" menu."); List displayedUnlocks = GameController.gameController.sessionDataBig.floorUnlocks.Select(u => (DisplayedUnlock)u.__RogueLibsCustom).OrderBy(d => d).ToList(); CustomScrollingMenu menu = new CustomScrollingMenu(__instance, displayedUnlocks); @@ -77,6 +82,7 @@ public static void ScrollingMenu_OpenScrollingMenu(ScrollingMenu __instance, ref } else if (__instance.menuType == "Traits") { + if (debug) RogueFramework.LogDebug("Setting up \"Traits\" menu."); __instance.numButtons = __instance.smallTraitList.Count; List displayedUnlocks = __instance.smallTraitList.Select(u => (DisplayedUnlock)u.__RogueLibsCustom).OrderBy(d => d).ToList(); CustomScrollingMenu menu = new CustomScrollingMenu(__instance, displayedUnlocks); @@ -89,6 +95,7 @@ public static void ScrollingMenu_OpenScrollingMenu(ScrollingMenu __instance, ref } else if (__instance.menuType == "RemoveTrait" || __instance.menuType == "ChangeTraitRandom" || __instance.menuType == "UpgradeTrait") { + if (debug) RogueFramework.LogDebug($"Setting up \"{__instance.menuType}\" menu."); __instance.numButtons = __instance.customTraitList.Count; List displayedUnlocks = __instance.customTraitList.Select(u => (DisplayedUnlock)u.__RogueLibsCustom).OrderBy(d => d).ToList(); CustomScrollingMenu menu = new CustomScrollingMenu(__instance, displayedUnlocks); @@ -167,6 +174,8 @@ public static bool ScrollingMenu_SortUnlocks(ScrollingMenu __instance, List du.Unlock)); @@ -180,6 +189,7 @@ public static bool ScrollingMenu_SortUnlocks(ScrollingMenu __instance, List ___loadoutList) { + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.UnlockMenus); + if (debug) RogueFramework.LogDebug("Refreshing the loadouts."); ___loadoutList.RemoveAt(0); for (int i = 0; i < ___loadoutList.Count; i++) { Unlock unlock = ___loadoutList[i]; if (unlock.__RogueLibsCustom is null) { + if (debug) RogueFramework.LogDebug("Hooking up an unhooked unlock."); Unlock normalized = GameController.gameController.sessionDataBig.unlocks .Find(u => u.unlockName == unlock.unlockName && u.unlockType == unlock.unlockType); unlock.__RogueLibsCustom = normalized.__RogueLibsCustom; @@ -284,9 +296,10 @@ public GiveNuggetsButton() : base("GiveNuggetsDebug", true) { } public override string GetFancyName() => $"{GetName()}"; public override void OnPushedButton() { + if (RogueFramework.IsDebugEnabled(DebugFlags.UnlockMenus)) + RogueFramework.LogDebug("Added 10 nuggets with the debug tool."); gc.unlocks.AddNuggets(10); PlaySound("BuyItem"); - gc.unlocks.SaveUnlockData(true); UpdateMenu(); } } diff --git a/RogueLibsCore/Patches/Patches_Sprites.cs b/RogueLibsCore/Patches/Patches_Sprites.cs index a28a12506..81c4f6c0b 100644 --- a/RogueLibsCore/Patches/Patches_Sprites.cs +++ b/RogueLibsCore/Patches/Patches_Sprites.cs @@ -15,7 +15,7 @@ public partial class RogueLibsPlugin { public void PatchSprites() { - // define RogueSprites in the RogueSprite.addOnGCAwakeList + // define non-initialized RogueSprites Patcher.Postfix(typeof(GameController), "Awake"); // set the shared material of all renderers to the one selected in the tk2dSpriteDefinition diff --git a/RogueLibsCore/Patches/Patches_TraitsStatusEffects.cs b/RogueLibsCore/Patches/Patches_TraitsStatusEffects.cs index dec681304..f453decb8 100644 --- a/RogueLibsCore/Patches/Patches_TraitsStatusEffects.cs +++ b/RogueLibsCore/Patches/Patches_TraitsStatusEffects.cs @@ -8,6 +8,8 @@ using HarmonyLib; using UnityEngine.Networking; using UnityEngine; +using System.Diagnostics; +using static UnityEngine.Random; namespace RogueLibsCore { @@ -75,10 +77,17 @@ public static IEnumerable StatusEffects_AddStatusEffect(IEnumer private static readonly FieldInfo StatusEffect_causingAgent = typeof(StatusEffect).GetField(nameof(StatusEffect.causingAgent)); public static void SetupEffectHook(StatusEffect effect, StatusEffects parent) { + bool debug = RogueFramework.IsDebugEnabled(DebugFlags.Effects); effect.__RogueLibsContainer = parent; foreach (IHookFactory factory in RogueFramework.EffectFactories) if (factory.TryCreate(effect, out IHook hook)) { + if (debug) + { + if (hook is CustomEffect) + RogueFramework.LogDebug($"Initializing custom effect {hook} ({effect.statusEffectName}, {parent.agent.agentName})."); + else RogueFramework.LogDebug($"Initializing effect hook {hook} ({effect.statusEffectName}, {parent.agent.agentName})."); + } effect.AddHook(hook); hook.Initialize(); } @@ -86,8 +95,11 @@ public static void SetupEffectHook(StatusEffect effect, StatusEffects parent) public static void RefreshEffect(StatusEffect effect, int newTime) { CustomEffect custom = effect.GetHook(); + float oldTime = effect.curTime; if (custom is null) effect.curTime = newTime; else custom.OnRefreshed(); + if (RogueFramework.IsDebugEnabled(DebugFlags.Effects)) + RogueFramework.LogDebug($"Refreshed {custom} ({effect.statusEffectName}, {effect.GetStatusEffects().agent.agentName}): {oldTime} > {effect.curTime}."); } public static IEnumerable StatusEffects_AddTrait(IEnumerable codeEnumerable) @@ -107,11 +119,18 @@ public static IEnumerable StatusEffects_AddTrait(IEnumerable factory in RogueFramework.TraitFactories) if (factory.TryCreate(trait, out IHook hook)) { + if (debug) + { + if (hook is CustomTrait) + RogueFramework.LogDebug($"Initializing custom trait {hook} ({trait.traitName}, {parent.agent.agentName})."); + else RogueFramework.LogDebug($"Initializing trait hook {hook} ({trait.traitName}, {parent.agent.agentName})."); + } trait.AddHook(hook); hook.Initialize(); any = true; @@ -129,6 +148,8 @@ public static void StatusEffects_RemoveTrait_Prefix(StatusEffects __instance, st public static void StatusEffects_RemoveTrait(Trait __state) { CustomTrait trait = __state?.GetHook(); + if (__state != null && RogueFramework.IsDebugEnabled(DebugFlags.Traits)) + RogueFramework.LogDebug($"Removing trait {trait} ({__state.traitName}, {__state.GetStatusEffects().agent.agentName})."); trait?.OnRemoved(); } @@ -137,6 +158,8 @@ public static void StatusEffects_RemoveStatusEffect_Prefix(StatusEffects __insta public static void StatusEffects_RemoveStatusEffect(StatusEffect __state) { CustomEffect effect = __state?.GetHook(); + if (__state != null && RogueFramework.IsDebugEnabled(DebugFlags.Effects)) + RogueFramework.LogDebug($"Removing effect {effect} ({__state.statusEffectName}, {__state.GetStatusEffects().agent.agentName})."); effect?.OnRemoved(); } @@ -191,6 +214,8 @@ public static bool StatusEffects_UpdateStatusEffect(StatusEffects __instance, St { CustomEffect custom = myStatusEffect.GetHook(); if (custom is null) return true; + if (RogueFramework.IsDebugEnabled(DebugFlags.Effects)) + RogueFramework.LogDebug($"Starting {custom} update coroutine ({myStatusEffect.statusEffectName}, {myStatusEffect.GetStatusEffects().agent.agentName})."); __result = StatusEffectUpdateEnumerator(__instance, custom, showTextOnRemoval); return false; } @@ -241,6 +266,8 @@ public static bool StatusEffects_UpdateTrait(StatusEffects __instance, Trait myT { CustomTrait custom = myTrait.GetHook(); if (custom is null) return true; + if (RogueFramework.IsDebugEnabled(DebugFlags.Effects)) + RogueFramework.LogDebug($"Starting {custom} update coroutine ({myTrait.traitName}, {myTrait.GetStatusEffects().agent.agentName})."); __result = TraitUpdateEnumerator(__instance, custom); return false; } diff --git a/RogueLibsCore/Patches/Patches_Unlocks.cs b/RogueLibsCore/Patches/Patches_Unlocks.cs index 5372a0651..2fb74fd5d 100644 --- a/RogueLibsCore/Patches/Patches_Unlocks.cs +++ b/RogueLibsCore/Patches/Patches_Unlocks.cs @@ -49,6 +49,8 @@ public static void Unlocks_AddUnlock(Unlock createdUnlock, Unlock __result) private static void UnlocksClearHelper(bool dontClear) { if (dontClear) return; + if (RogueFramework.IsDebugEnabled(DebugFlags.Unlocks)) + RogueFramework.LogDebug("Reloading unlocks."); RogueFramework.Unlocks.Clear(); } public static IEnumerable Unlocks_LoadInitialUnlocks(IEnumerable codeEnumerable) @@ -81,56 +83,56 @@ public static void LoadUnlockWrappersAndCategorize() foreach (Unlock unlock in sdb.unlocks.ToList()) { // wrapping original unlocks - if (gc.unlocks.GetSpecialUnlockInfo(unlock.unlockName, unlock) != "") unlock.cost = -2; - UnlockWrapper wrapper = RogueFramework.CustomUnlocks.Find(u => u.Name == unlock.unlockName && u.Type == unlock.unlockType); - if (wrapper != null) - AddUnlockFull(wrapper); + if (gc.unlocks.GetSpecialUnlockInfo(unlock.unlockName, unlock) != "") + { + unlock.cost = -2; + if (RogueFramework.IsDebugEnabled(DebugFlags.Unlocks)) + RogueFramework.LogDebug($"\"{unlock.unlockName}\" ({unlock.unlockType}) has special unlock conditions."); + } + + UnlockWrapper wrapper; + if (unlock.unlockType == "Challenge") + { + unlock.unavailable = false; + wrapper = new MutatorUnlock(unlock); + } + else if (unlock.unlockType == "Item") + { + if (!unlock.unavailable && !unlock.onlyInCharacterCreation && !unlock.freeItem) + unlock.onlyInCharacterCreation = unlock.freeItem = true; + wrapper = new ItemUnlock(unlock); + } + else if (unlock.unlockType == "Trait") + { + unlock.onlyInCharacterCreation = !unlock.unavailable; + wrapper = new TraitUnlock(unlock); + } + else if (unlock.unlockType == "Ability") + { + unlock.onlyInCharacterCreation = !unlock.unavailable; + wrapper = new AbilityUnlock(unlock); + } + else if (unlock.unlockType == "Achievement") wrapper = new AchievementUnlock(unlock); + else if (unlock.unlockType == "Floor") wrapper = new FloorUnlock(unlock); + else if (unlock.unlockType == "BigQuest") wrapper = new BigQuestUnlock(unlock); + else if (unlock.unlockType == "HomeBase") wrapper = new HomeBaseUnlock(unlock); + else if (unlock.unlockType == "Extra") wrapper = new ExtraUnlock(unlock); + else if (unlock.unlockType == "Agent") wrapper = new AgentUnlock(unlock); + else if (unlock.unlockType == "Loadout") wrapper = new LoadoutUnlock(unlock); else { - if (unlock.unlockType == "Challenge") - { - unlock.unavailable = false; - wrapper = new MutatorUnlock(unlock); - } - else if (unlock.unlockType == "Item") - { - if (!unlock.unavailable && !unlock.onlyInCharacterCreation && !unlock.freeItem) - unlock.onlyInCharacterCreation = unlock.freeItem = true; - wrapper = new ItemUnlock(unlock); - } - else if (unlock.unlockType == "Trait") - { - unlock.onlyInCharacterCreation = !unlock.unavailable; - wrapper = new TraitUnlock(unlock); - } - else if (unlock.unlockType == "Ability") - { - unlock.onlyInCharacterCreation = !unlock.unavailable; - wrapper = new AbilityUnlock(unlock); - } - else if (unlock.unlockType == "Achievement") wrapper = new AchievementUnlock(unlock); - else if (unlock.unlockType == "Floor") wrapper = new FloorUnlock(unlock); - else if (unlock.unlockType == "BigQuest") wrapper = new BigQuestUnlock(unlock); - else if (unlock.unlockType == "HomeBase") wrapper = new HomeBaseUnlock(unlock); - else if (unlock.unlockType == "Extra") wrapper = new ExtraUnlock(unlock); - else if (unlock.unlockType == "Agent") wrapper = new AgentUnlock(unlock); - else if (unlock.unlockType == "Loadout") wrapper = new LoadoutUnlock(unlock); - else - { - RogueFramework.Logger.LogError("Unknown unlock type!\n" + - $"unlockName: {unlock.unlockName}\n" + - $"unlockType: {unlock.unlockType}\n" + - $"unlocked: {unlock.unlocked}"); - sdb.unlocks.Remove(unlock); - continue; - } - if (wrapper is IUnlockInCC inCC && !inCC.IsAvailableInCC) inCC.IsAvailableInCC = wrapper.IsAvailable; - RogueFramework.Unlocks.Add(wrapper); - AddUnlockFull(wrapper, true); + RogueFramework.LogError($"Unknown unlock type \"{unlock.unlockName}\" ({unlock.unlockType})"); + sdb.unlocks.Remove(unlock); + continue; } + if (wrapper is IUnlockInCC inCC && !inCC.IsAvailableInCC) inCC.IsAvailableInCC = wrapper.IsAvailable; + RogueFramework.Unlocks.Add(wrapper); + AddUnlockFull(wrapper, true); } foreach (UnlockWrapper wrapper in RogueFramework.CustomUnlocks) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Unlocks)) + RogueFramework.LogDebug($"Initializing custom unlock \"{wrapper.Name}\" ({wrapper.Type})."); RogueFramework.Unlocks.Add(wrapper); AddUnlockFull(wrapper); } @@ -143,9 +145,13 @@ public static void AddUnlockFull(UnlockWrapper wrapper, bool alreadyLoaded = fal Unlock result = alreadyLoaded ? wrapper.Unlock : GameController.gameController.unlocks.AddUnlock(wrapper.Unlock); if (wrapper.Unlock != result) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Unlocks)) + RogueFramework.LogDebug($"Loaded state for \"{wrapper.Name}\" ({wrapper.Type}): unlocked - {result.unlocked}, enabled - {!result.notActive}"); + List list = GameController.gameController.sessionDataBig.unlocks; list.Remove(result); list.Add(wrapper.Unlock); + wrapper.IsUnlocked = result.unlocked; if (!(wrapper is MutatorUnlock)) wrapper.IsEnabled = !result.notActive; @@ -158,7 +164,7 @@ public static void AddUnlockFull(UnlockWrapper wrapper, bool alreadyLoaded = fal } catch (Exception e) { - RogueFramework.Logger.LogError($"An error setting up {wrapper.Unlock?.unlockName} ({wrapper.Unlock?.unlockType}) unlock."); + RogueFramework.Logger.LogError($"Error setting up {wrapper.Unlock?.unlockName} ({wrapper.Unlock?.unlockType}) unlock."); RogueFramework.Logger.LogError(e); } } @@ -614,6 +620,9 @@ public static class UnlocksExtensions public static bool AllowUnlocksAnyway { get; set; } public static void DoUnlockForced(this Unlocks unlocks, string unlockName, string unlockType) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Unlocks)) + RogueFramework.LogDebug($"Force-unlocking \"{unlockName}\" ({unlockType})"); + bool prev = AllowUnlocksAnyway; AllowUnlocksAnyway = true; unlocks.DoUnlock(unlockName, unlockType); diff --git a/RogueLibsCore/Properties/AssemblyInfo.cs b/RogueLibsCore/Properties/AssemblyInfo.cs index 659bce143..950198b4f 100644 --- a/RogueLibsCore/Properties/AssemblyInfo.cs +++ b/RogueLibsCore/Properties/AssemblyInfo.cs @@ -5,21 +5,26 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("RogueLibs")] +[assembly: AssemblyTitle("RogueLibsCore")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("RogueLibs")] -[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyCompany("Abbysssal")] +[assembly: AssemblyProduct("RogueLibsCore")] +[assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. +#if DEBUG +[assembly: AssemblyConfiguration("Debug")] +#elif RELEASE +[assembly: AssemblyConfiguration("Release")] +#else +[assembly: AssemblyConfiguration("")] +#endif + [assembly: ComVisible(false)] -// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: InternalsVisibleTo("RogueLibsCore.Test")] + [assembly: Guid("43a221f2-a56c-4f59-8c3c-828de75259c4")] // Version information for an assembly consists of the following four values: @@ -32,5 +37,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion(RogueLibsCore.RogueLibs.AssemblyVersion)] +[assembly: AssemblyFileVersion(RogueLibsCore.RogueLibs.AssemblyVersion)] diff --git a/RogueLibsCore/RogueFramework.cs b/RogueLibsCore/RogueFramework.cs index 70ed9393c..8bad5295e 100644 --- a/RogueLibsCore/RogueFramework.cs +++ b/RogueLibsCore/RogueFramework.cs @@ -10,13 +10,42 @@ public static class RogueFramework public static RogueLibsPlugin Plugin { get; internal set; } internal static ManualLogSource Logger { get; set; } - public static DebugFlags Debug { get; set; } + public static bool Debug { get; set; } + public static DebugFlags DebugFlags { get; set; } #if DEBUG - = DebugFlags.All; + = DebugFlags.EnableTools | DebugFlags.Abilities | DebugFlags.Unlocks; #endif - public static bool IsDebugEnabled(DebugFlags flags) => (Debug & flags) == flags; - public static void LogDebug(string message) => Logger.LogDebug(message); + public static bool IsDebugEnabled(DebugFlags flags) => (DebugFlags & flags) == flags; + + internal static void LogDebug(string message) => Logger.LogDebug(message); + internal static void LogWarning(string message) => Logger.LogWarning(message); + internal static void LogError(string message) => Logger.LogError(message); + internal static void LogError(Exception e, string methodName, object hookObj, object container = null) + { + IHook hook = (IHook)hookObj; + object instance = hook.Instance; + + string instanceName = instance is InvItem item ? item.invItemName + : instance is StatusEffect effect ? effect.statusEffectName + : instance is Trait trait ? trait.traitName + : instance is Agent agent ? agent.agentName + : instance is ObjectReal objectReal ? objectReal.objectName + : instance is UnlockWrapper wrapper ? $"{wrapper.Name} ({wrapper.Type})" + : instance.ToString(); + + string containerName = container is null ? string.Empty + : ", " + ( + container is Item ? "on the ground" + : container is Agent a ? a.agentName + : container is ObjectReal o ? o.objectName + : container is UnlocksMenu m ? m.Type.ToString() + : container.ToString() + ); + + Logger.LogError($"{methodName} error in {hookObj} ({instanceName}{containerName})"); + Logger.LogError(e); + } public static readonly List> ItemFactories = new List>(); public static readonly List> TraitFactories = new List>(); diff --git a/RogueLibsCore/RogueLibs.cs b/RogueLibsCore/RogueLibs.cs index 6966e3846..a6caedca2 100644 --- a/RogueLibsCore/RogueLibs.cs +++ b/RogueLibsCore/RogueLibs.cs @@ -20,8 +20,13 @@ static RogueLibs() public const string GUID = "abbysssal.streetsofrogue.roguelibscore"; public const string Name = "RogueLibsCore"; - public static string Version { [MethodImpl(MethodImplOptions.NoInlining)] get => CompiledVersion; } + public const string CompiledVersion = "3.0"; + public const string CompiledSemanticVersion = "3.0.0-beta.8"; + internal const string AssemblyVersion = "3.0.0.0"; + + public static string Version { [MethodImpl(MethodImplOptions.NoInlining)] get => CompiledVersion; } + public static string SemanticVersion { [MethodImpl(MethodImplOptions.NoInlining)] get => CompiledSemanticVersion; } private static readonly CustomItemFactory ItemFactory = new CustomItemFactory(); private static readonly CustomTraitFactory TraitFactory = new CustomTraitFactory(); @@ -34,6 +39,12 @@ public static ItemBuilder CreateCustomItem() ItemInfo info = ItemFactory.AddItem(); return new ItemBuilder(info); } + public static AbilityBuilder CreateCustomAbility() + where TAbility : CustomAbility, new() + { + ItemInfo info = ItemFactory.AddItem(); + return new AbilityBuilder(info); + } public static TraitBuilder CreateCustomTrait() where TTrait : CustomTrait, new() { @@ -129,6 +140,45 @@ public ItemBuilder WithUnlock(ItemUnlock unlock) return this; } } + public class AbilityBuilder + { + public AbilityBuilder(ItemInfo info) => Info = info; + public ItemInfo Info { get; } + + public CustomName Name { get; private set; } + public CustomName Description { get; private set; } + public RogueSprite Sprite { get; private set; } + public AbilityUnlock Unlock { get; private set; } + + public AbilityBuilder WithName(CustomNameInfo name) + { + Name = RogueLibs.CreateCustomName(Info.Name, "Item", name); + return this; + } + public AbilityBuilder WithDescription(CustomNameInfo description) + { + Description = RogueLibs.CreateCustomName(Info.Name, "Description", description); + return this; + } + public AbilityBuilder WithSprite(byte[] rawData, float ppu = 64f) + { + Sprite = RogueLibs.CreateCustomSprite(Info.Name, SpriteScope.Items, rawData, ppu); + return this; + } + public AbilityBuilder WithSprite(byte[] rawData, Rect region, float ppu = 64f) + { + Sprite = RogueLibs.CreateCustomSprite(Info.Name, SpriteScope.Items, rawData, region, ppu); + return this; + } + public AbilityBuilder WithUnlock() => WithUnlock(new AbilityUnlock(Info.Name, true)); + public AbilityBuilder WithUnlock(AbilityUnlock unlock) + { + unlock.Name = Info.Name; + RogueLibs.CreateCustomUnlock(unlock); + Unlock = unlock; + return this; + } + } public class TraitBuilder { public TraitBuilder(TraitInfo info) => Info = info; diff --git a/RogueLibsCore/RogueLibsPlugin.cs b/RogueLibsCore/RogueLibsPlugin.cs index e0fbd1f61..09e04e88f 100644 --- a/RogueLibsCore/RogueLibsPlugin.cs +++ b/RogueLibsCore/RogueLibsPlugin.cs @@ -16,6 +16,7 @@ public sealed partial class RogueLibsPlugin : BaseUnityPlugin public RoguePatcher Patcher; public void Awake() { + Logger.LogInfo($"Running RogueLibs v{RogueLibs.CompiledSemanticVersion}."); Stopwatch sw = new Stopwatch(); sw.Start(); diff --git a/RogueLibsCore/RogueSprite.cs b/RogueLibsCore/RogueSprite.cs index 5ef344dfd..b11c0097c 100644 --- a/RogueLibsCore/RogueSprite.cs +++ b/RogueLibsCore/RogueSprite.cs @@ -115,11 +115,16 @@ private Sprite CreateSprite() internal static void DefinePrepared(tk2dSpriteCollectionData collection, SpriteScope scope) { if (prepared.TryGetValue(scope, out List sprites)) + { + if (RogueFramework.IsDebugEnabled(DebugFlags.Sprites)) + RogueFramework.LogDebug($"Initializing ${sprites.Count} prepared sprites in scope {scope}:"); + foreach (RogueSprite sprite in sprites) { sprite.isPrepared = false; - sprite.Define(collection, scope); + sprite.DefineInternal(collection, scope); } + } } internal RogueSprite(string spriteName, SpriteScope spriteScope, byte[] rawData, Rect? spriteRegion, float ppu = 64f) @@ -154,34 +159,44 @@ public void Define() DefineScope(Scope & SpriteScope.Items); DefineScope(Scope & SpriteScope.Objects); DefineScope(Scope & SpriteScope.Floors); + DefineScope(Scope & SpriteScope.Extra); } private void DefineScope(SpriteScope scope) { if (scope == SpriteScope.None) return; tk2dSpriteCollectionData coll = GetCollection(scope); - if (coll is null) + if (coll is null && scope != SpriteScope.Extra) { + isPrepared = true; if (prepared.TryGetValue(scope, out List sprites)) + { + if (RogueFramework.IsDebugEnabled(DebugFlags.Sprites)) + RogueFramework.LogDebug($"Prepared sprite \"{Name}\" for initialization."); sprites.Add(this); - isPrepared = true; + } + else RogueFramework.LogError($"Pseudo-prepared sprite \"{Name}\" for initialization."); } - else Define(coll, scope); + else DefineInternal(coll, scope); } internal Material Material { get; private set; } internal Material LightUpMaterial { get; private set; } - internal void Define(tk2dSpriteCollectionData coll, SpriteScope scope) + internal void DefineInternal(tk2dSpriteCollectionData coll, SpriteScope scope) { + if (RogueFramework.IsDebugEnabled(DebugFlags.Sprites)) + RogueFramework.LogDebug($"Defining \"{Name}\" sprite in scope {scope}."); + if (coll != null) { tk2dSpriteDefinition def = AddDefinition(coll, texture, region); def.__RogueLibsCustom = this; - definitions.Add(new CustomTk2dDefinition(coll, def)); + definitions.Add(new CustomTk2dDefinition(coll, def, scope)); if (Material is null) Material = def.material; if (LightUpMaterial is null) LightUpMaterial = UnityEngine.Object.Instantiate(Material); LightUpMaterial.shader = GameController.gameController.lightUpShader; } + else definitions.Add(new CustomTk2dDefinition(null, null, scope)); GameResources gr = GameResources.gameResources; @@ -194,23 +209,31 @@ public void Undefine() { if (isPrepared) { + isPrepared = false; if (prepared.TryGetValue(Scope, out List list)) list.Remove(this); - isPrepared = false; + else RogueFramework.LogWarning($"Undefined a pseudo-prepared sprite \"{Name}\"."); return; } if (!IsDefined) return; foreach (CustomTk2dDefinition def in definitions) - RemoveDefinition(def.Collection, def.Definition); + UndefineInternal(def); definitions = null; + } + private void UndefineInternal(CustomTk2dDefinition def) + { + if (RogueFramework.IsDebugEnabled(DebugFlags.Sprites)) + RogueFramework.LogDebug($"Undefining sprite \"{Name}\" from scope {def.Scope}."); - GameResources gr = GameResources.gameResources; + if (def.Collection != null) + RemoveDefinition(def.Collection, def.Definition); + GameResources gr = GameResources.gameResources; if (Scope == SpriteScope.Items) { gr.itemDic.Remove(Name); gr.itemList.Remove(Sprite); } - else if (Scope == SpriteScope.Objects) { gr.objectDic.Remove(Name); gr.objectList.Remove(Sprite); } - else if (Scope == SpriteScope.Floors) { gr.floorDic.Remove(Name); gr.floorList.Remove(Sprite); } - else if (Scope == SpriteScope.Extra) RogueFramework.ExtraSprites.Remove(Name); + if (Scope == SpriteScope.Objects) { gr.objectDic.Remove(Name); gr.objectList.Remove(Sprite); } + if (Scope == SpriteScope.Floors) { gr.floorDic.Remove(Name); gr.floorList.Remove(Sprite); } + if (Scope == SpriteScope.Extra) RogueFramework.ExtraSprites.Remove(Name); } public static tk2dSpriteDefinition CreateDefinition(Texture2D texture, Rect? region, float scale) @@ -317,13 +340,15 @@ private static void RemoveDefinition(tk2dSpriteCollectionData coll, tk2dSpriteDe public class CustomTk2dDefinition { - internal CustomTk2dDefinition(tk2dSpriteCollectionData collection, tk2dSpriteDefinition definition) + internal CustomTk2dDefinition(tk2dSpriteCollectionData collection, tk2dSpriteDefinition definition, SpriteScope scope) { Collection = collection; Definition = definition; + Scope = scope; } public tk2dSpriteCollectionData Collection { get; } public tk2dSpriteDefinition Definition { get; } + public SpriteScope Scope { get; } } } [Flags] @@ -335,6 +360,6 @@ public enum SpriteScope Items = 1 << 0, Objects = 1 << 1, - Floors = 1 << 2 + Floors = 1 << 2, } } diff --git a/RogueLibsCore/Utilities/RoguePatcher.cs b/RogueLibsCore/Utilities/RoguePatcher.cs index 5a97c90af..7168758e5 100644 --- a/RogueLibsCore/Utilities/RoguePatcher.cs +++ b/RogueLibsCore/Utilities/RoguePatcher.cs @@ -52,10 +52,12 @@ public void LogResults() $" | {time.Elapsed.TotalMilliseconds,4:####}ms |"); total += time.Elapsed; } - log.LogDebug($"Total: {total,5:#####}ms"); + log.LogDebug($"Total: {total.TotalMilliseconds,5:#####}ms"); } - private static readonly BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + private static MethodInfo GetMethod(Type type, string methodName, Type[] parameterTypes) + => parameterTypes is null ? type.GetMethod(methodName, All) : type.GetMethod(methodName, All, null, parameterTypes, null); public bool Prefix(Type targetType, string targetMethod, Type[] targetParameterTypes = null) { @@ -75,9 +77,9 @@ public bool Prefix(Type targetType, string targetMethod, string patchMethod, Typ { sw = new Stopwatch(); sw.Start(); - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, new HarmonyMethod(patch)); sw.Stop(); @@ -86,9 +88,9 @@ public bool Prefix(Type targetType, string targetMethod, string patchMethod, Typ } else { - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, new HarmonyMethod(patch)); } @@ -120,9 +122,9 @@ public bool Postfix(Type targetType, string targetMethod, string patchMethod, Ty { sw = new Stopwatch(); sw.Start(); - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, null, new HarmonyMethod(patch)); sw.Stop(); @@ -131,9 +133,9 @@ public bool Postfix(Type targetType, string targetMethod, string patchMethod, Ty } else { - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, null, new HarmonyMethod(patch)); } @@ -165,9 +167,9 @@ public bool Transpiler(Type targetType, string targetMethod, string patchMethod, { sw = new Stopwatch(); sw.Start(); - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, null, null, new HarmonyMethod(patch)); sw.Stop(); @@ -176,9 +178,9 @@ public bool Transpiler(Type targetType, string targetMethod, string patchMethod, } else { - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, null, null, new HarmonyMethod(patch)); } @@ -210,9 +212,9 @@ public bool Finalizer(Type targetType, string targetMethod, string patchMethod, { sw = new Stopwatch(); sw.Start(); - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, null, null, null, new HarmonyMethod(patch)); sw.Stop(); @@ -221,9 +223,9 @@ public bool Finalizer(Type targetType, string targetMethod, string patchMethod, } else { - MethodInfo target = targetType.GetMethod(targetMethod, All, null, targetParameterTypes, null) + MethodInfo target = GetMethod(targetType, targetMethod, targetParameterTypes) ?? throw new MemberNotFoundException($"Target method {targetType.FullName}.{targetMethod} could not be found."); - MethodInfo patch = TypeWithPatches.GetMethod(patchMethod, All) + MethodInfo patch = GetMethod(TypeWithPatches, patchMethod, null) ?? throw new MemberNotFoundException($"Patch method {TypeWithPatches.FullName}.{patchMethod} could not be found."); harmony.Patch(target, null, null, null, new HarmonyMethod(patch)); }