Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SilkSuture v0.5.1
plugins/SilkSuture.dll
Decompiled 16 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HutongGames.PlayMaker; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SilkSuture")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SilkSuture")] [assembly: AssemblyTitle("SilkSuture")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SilkSuture { [BepInPlugin("com.fabulator_k.silksuture", "Silk Suture", "0.5.1")] public class SilkSuture : BaseUnityPlugin { private class AppliedEdits { public PlayMakerFSM fsm; public FsmState bindStartState; public AdvanceHealAction advanceAction; public FsmState loopBindState; public LoopHealAdjustAction loopAction; public FsmState warriorState; public BeastAdvanceAction beastAction; } internal static ManualLogSource Logger; internal static SilkSuture Instance; internal const int AdvanceAmount = 1; internal static ConfigEntry<bool> configEnabled; internal static ConfigEntry<string> configMultibinderPattern; internal static ConfigEntry<bool> configWitchAdvance; internal static ConfigEntry<bool> configBeastAdvance; internal static ConfigEntry<bool> configShamanAdvance; internal static ConfigEntry<bool> configMaggotAdvance; internal static ConfigEntry<bool> configMaggotMultibindAdvance; internal static ConfigEntry<bool> configLifebloodAdvance; internal static int lastAdvanceGranted; internal static int witchAdvanceGranted; internal static int rageAdvanceGranted; internal static bool maggotMultibindPending; private Harmony harmony; private AppliedEdits appliedEdits; private void Awake() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"[Silk Suture] Initializing..."); SetupConfig(); if (configEnabled.Value) { harmony = new Harmony("com.fabulator_k.silksuture"); harmony.PatchAll(); ((MonoBehaviour)this).StartCoroutine(SearchForBindFSM()); SceneManager.sceneLoaded += OnSceneLoaded; Logger.LogInfo((object)string.Format("[{0}] Enabled: Pattern={1}, Witch={2}, Beast={3}, Shaman={4}", "Silk Suture", configMultibinderPattern.Value, configWitchAdvance.Value, configBeastAdvance.Value, configShamanAdvance.Value)); } else { Logger.LogInfo((object)"[Silk Suture] Disabled in config"); } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; RevertEdits(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (configEnabled.Value) { ((MonoBehaviour)this).StartCoroutine(VerifyEditsAfterLoad()); } } private IEnumerator VerifyEditsAfterLoad() { yield return null; yield return null; CheckEditsPresence(); } private void CheckEditsPresence() { try { if (appliedEdits == null) { return; } PlayMakerFSM fsm = appliedEdits.fsm; if ((Object)(object)fsm == (Object)null) { appliedEdits = null; return; } FsmState val = FindState(fsm, "Bind Start"); if (val == null || appliedEdits.advanceAction == null || Array.IndexOf(val.Actions, (FsmStateAction)(object)appliedEdits.advanceAction) < 0) { Logger.LogWarning((object)"Bind FSM edits missing after scene load - re-applying"); appliedEdits = null; ModifyBindFSM(fsm); } } catch (Exception arg) { Logger.LogError((object)$"Error verifying FSM edits after scene load: {arg}"); } } private void SetupConfig() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown configEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Silk Suture healing modifications"); configMultibinderPattern = ((BaseUnityPlugin)this).Config.Bind<string>("Healing", "MultibinderPattern", "1+1+2", new ConfigDescription("Multibinder healing split (immediate + first completion + second completion, total 4)", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "1+1+2", "1+2+1" }), Array.Empty<object>())); configWitchAdvance = ((BaseUnityPlugin)this).Config.Bind<bool>("Crests", "WitchAdvance", true, "Witch crest: advance the immediate heal and reduce the tentacle heal cap to match. Off = fully vanilla witch binds."); configBeastAdvance = ((BaseUnityPlugin)this).Config.Bind<bool>("Crests", "BeastAdvance", true, "Beast crest: advance the immediate heal and reduce the rage mode heal cap to match. Off = fully vanilla rage binds."); configShamanAdvance = ((BaseUnityPlugin)this).Config.Bind<bool>("Crests", "ShamanAdvance", true, "Shaman (Spell) crest: advance 1 mask when the bind starts, deducted from the completion heal (total stays vanilla). Applies to the mid-air held bind too. Off = fully vanilla shaman binds."); configMaggotAdvance = ((BaseUnityPlugin)this).Config.Bind<bool>("EdgeCases", "MaggotAdvance", true, "Maggoted binds: grant the immediate heal even though vanilla heals nothing while maggoted (cleanse bind heals 1 instead of 0). The Multibinder combo is governed by MaggotMultibindAdvance instead. Off = vanilla."); configMaggotMultibindAdvance = ((BaseUnityPlugin)this).Config.Bind<bool>("EdgeCases", "MaggotMultibindAdvance", true, "Maggoted + Multibinder: advance 1 mask immediately and deduct it from the second burst (first burst cleanses; total stays vanilla's 2). Takes precedence over MaggotAdvance for this combo - keeps it from stacking to 3. Off + MaggotAdvance on = uncapped 1+2."); configLifebloodAdvance = ((BaseUnityPlugin)this).Config.Bind<bool>("EdgeCases", "LifebloodAdvance", false, "Advance the immediate heal even in the lifeblood (all blue masks) state. Off = fully vanilla (recommended: lifeblood has its own regen economy)."); } private IEnumerator SearchForBindFSM() { yield return (object)new WaitForSeconds(3f); PlayMakerFSM[] array = Resources.FindObjectsOfTypeAll<PlayMakerFSM>(); foreach (PlayMakerFSM val in array) { if (IsHeroBindFsm(val)) { Logger.LogInfo((object)("Found bind FSM: '" + val.FsmName + "' on '" + ((Object)((Component)val).gameObject).name + "'")); ModifyBindFSM(val); yield break; } } Logger.LogWarning((object)"Bind FSM not found in initial search - will catch on first bind use"); } internal static bool IsHeroBindFsm(PlayMakerFSM fsm) { if ((Object)(object)fsm == (Object)null) { return false; } if (fsm.FsmName == "Bind") { GameObject gameObject = ((Component)fsm).gameObject; return (((gameObject != null) ? ((Object)gameObject).name : null) ?? "").Contains("Hero"); } return false; } internal bool IsModified(PlayMakerFSM fsm) { if (appliedEdits != null) { return (Object)(object)appliedEdits.fsm == (Object)(object)fsm; } return false; } internal void ModifyBindFSM(PlayMakerFSM fsm) { if (IsModified(fsm)) { return; } if (this.appliedEdits != null) { RevertEdits(); } try { Logger.LogInfo((object)"Modifying Bind FSM..."); AppliedEdits appliedEdits = new AppliedEdits { fsm = fsm }; appliedEdits.bindStartState = FindState(fsm, "Bind Start"); if (appliedEdits.bindStartState != null) { appliedEdits.advanceAction = new AdvanceHealAction { fsm = fsm }; InsertAction(appliedEdits.bindStartState, (FsmStateAction)(object)appliedEdits.advanceAction); Logger.LogInfo((object)"Advance heal action installed on 'Bind Start'"); } else { Logger.LogWarning((object)"'Bind Start' state not found - advance heal unavailable"); } appliedEdits.loopBindState = FindState(fsm, "Loop Bind Start"); if (appliedEdits.loopBindState != null) { appliedEdits.loopAction = new LoopHealAdjustAction { fsm = fsm }; InsertAction(appliedEdits.loopBindState, (FsmStateAction)(object)appliedEdits.loopAction); Logger.LogInfo((object)"Multibind loop adjust installed on 'Loop Bind Start'"); } else { Logger.LogWarning((object)"'Loop Bind Start' state not found - multibind totals may be off"); } appliedEdits.warriorState = FindState(fsm, "Warrior Kickup"); if (appliedEdits.warriorState != null) { appliedEdits.beastAction = new BeastAdvanceAction(); InsertAction(appliedEdits.warriorState, (FsmStateAction)(object)appliedEdits.beastAction); Logger.LogInfo((object)"Beast advance installed on 'Warrior Kickup'"); } else { Logger.LogWarning((object)"'Warrior Kickup' state not found - Beast advance unavailable"); } this.appliedEdits = appliedEdits; } catch (Exception arg) { Logger.LogError((object)$"Failed to modify bind FSM: {arg}"); } } private void RevertEdits() { if (appliedEdits == null) { return; } try { if ((Object)(object)appliedEdits.fsm != (Object)null) { if (appliedEdits.bindStartState != null && appliedEdits.advanceAction != null) { RemoveAction(appliedEdits.bindStartState, (FsmStateAction)(object)appliedEdits.advanceAction); } if (appliedEdits.loopBindState != null && appliedEdits.loopAction != null) { RemoveAction(appliedEdits.loopBindState, (FsmStateAction)(object)appliedEdits.loopAction); } if (appliedEdits.warriorState != null && appliedEdits.beastAction != null) { RemoveAction(appliedEdits.warriorState, (FsmStateAction)(object)appliedEdits.beastAction); } Logger.LogInfo((object)"Bind FSM edits reverted"); } } catch (Exception arg) { Logger.LogError((object)$"Error reverting FSM edits: {arg}"); } appliedEdits = null; } private static FsmState FindState(PlayMakerFSM fsm, string name) { FsmState[] fsmStates = fsm.FsmStates; foreach (FsmState val in fsmStates) { if (val.Name == name) { return val; } } return null; } private static void InsertAction(FsmState state, FsmStateAction action) { List<FsmStateAction> list = new List<FsmStateAction>(state.Actions); list.Insert(0, action); state.Actions = list.ToArray(); } private static void RemoveAction(FsmState state, FsmStateAction action) { List<FsmStateAction> list = new List<FsmStateAction>(state.Actions); if (list.Remove(action)) { state.Actions = list.ToArray(); } } internal static bool LifebloodBlocks() { HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null) { return true; } if (instance.IsInLifebloodState) { return !configLifebloodAdvance.Value; } return false; } internal static bool IsMaggoted() { HeroController instance = HeroController.instance; if ((Object)(object)instance != (Object)null && instance.cState != null) { return instance.cState.isMaggoted; } return false; } internal static int GrantAdvance(int amount) { PlayerData instance = PlayerData.instance; int health = instance.health; HeroController.instance.AddHealth(amount); return instance.health - health; } } public class AdvanceHealAction : FsmStateAction { public PlayMakerFSM fsm; public override void OnEnter() { try { SilkSuture.lastAdvanceGranted = 0; SilkSuture.witchAdvanceGranted = 0; SilkSuture.maggotMultibindPending = false; if (!SilkSuture.configEnabled.Value || SilkSuture.LifebloodBlocks()) { ((FsmStateAction)this).Finish(); return; } bool flag = SilkSuture.IsMaggoted(); FsmBool obj = fsm.FsmVariables.FindFsmBool("Is Witch Equipped"); if (obj != null && obj.Value) { if (flag) { if (SilkSuture.configMaggotAdvance.Value) { int num = SilkSuture.GrantAdvance(1); if (num > 0) { SilkSuture.Logger.LogInfo((object)$"Maggot advance (bonus): +{num} on witch cleanse bind"); } } } else if (SilkSuture.configWitchAdvance.Value) { SilkSuture.witchAdvanceGranted = SilkSuture.GrantAdvance(1); SilkSuture.Logger.LogInfo((object)$"Witch advance: +{SilkSuture.witchAdvanceGranted}, tentacle cap reduced to match"); } ((FsmStateAction)this).Finish(); return; } FsmInt val = fsm.FsmVariables.FindFsmInt("Heal Amount"); if (val == null || val.Value <= 0) { ((FsmStateAction)this).Finish(); return; } FsmInt obj2 = fsm.FsmVariables.FindFsmInt("Bind Amount"); bool flag2 = ((obj2 == null) ? 1 : obj2.Value) >= 2; if (flag) { if (flag2 && SilkSuture.configMaggotMultibindAdvance.Value) { int num2 = SilkSuture.GrantAdvance(Mathf.Min(1, val.Value)); if (num2 > 0) { SilkSuture.lastAdvanceGranted = num2; SilkSuture.maggotMultibindPending = true; SilkSuture.Logger.LogInfo((object)$"Maggot multibind advance: +{num2}, second burst will be reduced"); } } else if (SilkSuture.configMaggotAdvance.Value) { int num3 = SilkSuture.GrantAdvance(1); if (num3 > 0) { SilkSuture.Logger.LogInfo((object)$"Maggot advance (bonus): +{num3} on cleanse bind"); } } ((FsmStateAction)this).Finish(); return; } FsmBool obj3 = fsm.FsmVariables.FindFsmBool("Is Shaman Equipped"); if (obj3 != null && obj3.Value && !SilkSuture.configShamanAdvance.Value) { ((FsmStateAction)this).Finish(); return; } int num4 = SilkSuture.GrantAdvance(Mathf.Min(1, val.Value)); if (num4 <= 0) { ((FsmStateAction)this).Finish(); return; } if (!flag2 || SilkSuture.configMultibinderPattern.Value == "1+1+2") { val.Value -= num4; } SilkSuture.lastAdvanceGranted = num4; SilkSuture.Logger.LogInfo((object)($"Advance heal: +{num4}, Heal Amount now {val.Value}" + (flag2 ? (" (multibind " + SilkSuture.configMultibinderPattern.Value + ")") : ""))); } catch (Exception arg) { SilkSuture.Logger.LogError((object)$"Error in AdvanceHealAction: {arg}"); } ((FsmStateAction)this).Finish(); } } public class LoopHealAdjustAction : FsmStateAction { public PlayMakerFSM fsm; public override void OnEnter() { try { int lastAdvanceGranted = SilkSuture.lastAdvanceGranted; if (!SilkSuture.configEnabled.Value || lastAdvanceGranted <= 0) { goto IL_0039; } FsmBool obj = fsm.FsmVariables.FindFsmBool("Is Witch Equipped"); if (obj != null && obj.Value) { goto IL_0039; } FsmInt val = fsm.FsmVariables.FindFsmInt("Heal Amount"); if (val != null) { int value = val.Value; if (SilkSuture.maggotMultibindPending) { val.Value = Mathf.Max(0, val.Value - lastAdvanceGranted); SilkSuture.maggotMultibindPending = false; } else if (SilkSuture.configMultibinderPattern.Value == "1+2+1") { val.Value = Mathf.Max(0, val.Value - lastAdvanceGranted); } else { val.Value += lastAdvanceGranted; } SilkSuture.Logger.LogInfo((object)$"Multibind loop adjust: Heal Amount {value} -> {val.Value}"); } SilkSuture.lastAdvanceGranted = 0; goto end_IL_0000; IL_0039: ((FsmStateAction)this).Finish(); return; end_IL_0000:; } catch (Exception arg) { SilkSuture.Logger.LogError((object)$"Error in LoopHealAdjustAction: {arg}"); } ((FsmStateAction)this).Finish(); } } public class BeastAdvanceAction : FsmStateAction { public override void OnEnter() { try { SilkSuture.rageAdvanceGranted = 0; if (!SilkSuture.configEnabled.Value || SilkSuture.LifebloodBlocks()) { ((FsmStateAction)this).Finish(); return; } if (SilkSuture.IsMaggoted()) { if (SilkSuture.configMaggotAdvance.Value) { int num = SilkSuture.GrantAdvance(1); if (num > 0) { SilkSuture.Logger.LogInfo((object)$"Maggot advance (bonus): +{num} on Beast cleanse bind"); } } } else if (SilkSuture.configBeastAdvance.Value) { SilkSuture.rageAdvanceGranted = SilkSuture.GrantAdvance(1); SilkSuture.Logger.LogInfo((object)$"Beast advance: +{SilkSuture.rageAdvanceGranted}, rage cap reduced to match"); } } catch (Exception arg) { SilkSuture.Logger.LogError((object)$"Error in BeastAdvanceAction: {arg}"); } ((FsmStateAction)this).Finish(); } } [HarmonyPatch(typeof(PlayMakerFSM), "Awake")] public class FSMAwakePatch { [HarmonyPostfix] public static void Postfix(PlayMakerFSM __instance) { if (SilkSuture.configEnabled.Value && !((Object)(object)SilkSuture.Instance == (Object)null) && SilkSuture.IsHeroBindFsm(__instance) && !SilkSuture.Instance.IsModified(__instance)) { SilkSuture.Logger.LogInfo((object)("Found bind FSM: '" + __instance.FsmName + "' on " + ((Object)((Component)__instance).gameObject).name)); SilkSuture.Instance.ModifyBindFSM(__instance); } } } [HarmonyPatch(typeof(HeroController), "CanBind")] public class CanBindPatch { [HarmonyPostfix] public static void Postfix(bool __result) { if (!__result || !SilkSuture.configEnabled.Value || (Object)(object)SilkSuture.Instance == (Object)null) { return; } SilkSuture.witchAdvanceGranted = 0; PlayMakerFSM[] array = Object.FindObjectsOfType<PlayMakerFSM>(); foreach (PlayMakerFSM val in array) { if (SilkSuture.IsHeroBindFsm(val)) { if (!SilkSuture.Instance.IsModified(val)) { SilkSuture.Logger.LogInfo((object)("Found bind FSM: '" + val.FsmName + "' on " + ((Object)((Component)val).gameObject).name)); SilkSuture.Instance.ModifyBindFSM(val); } break; } } } } [HarmonyPatch(typeof(HeroController), "GetRageModeHealCap")] public class RageHealCapPatch { [HarmonyPostfix] public static void Postfix(ref int __result) { if (SilkSuture.configEnabled.Value && SilkSuture.configBeastAdvance.Value) { __result = Mathf.Max(0, __result - SilkSuture.rageAdvanceGranted); } } } [HarmonyPatch(typeof(HeroController), "GetWitchHealCap")] public class WitchHealCapPatch { [HarmonyPostfix] public static void Postfix(ref int __result) { if (SilkSuture.configEnabled.Value && SilkSuture.configWitchAdvance.Value) { __result = Mathf.Max(0, __result - SilkSuture.witchAdvanceGranted); } } } public static class PluginInfo { public const string PLUGIN_GUID = "com.fabulator_k.silksuture"; public const string PLUGIN_NAME = "Silk Suture"; public const string PLUGIN_VERSION = "0.5.1"; } }