using System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using UnityEngine; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyTitle("Vasodilation")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Vasodilation")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("15fa7750-965f-4249-837f-3d54157b5401")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace VasodilationMod { internal enum WarmthSource { None, Sprint, Jump, SprintJump, ClimbJump, WallClimb, RopeClimb, VineClimb } [BepInPlugin("tony4twentys.Vasodilation", "Vasodilation", "2.0.0")] [BepInProcess("PEAK.exe")] public class VasodilationPlugin : BaseUnityPlugin { public const string PluginGuid = "tony4twentys.Vasodilation"; public const string PluginName = "Vasodilation"; public const string PluginVersion = "2.0.0"; internal const byte EventCode = 162; internal const int ProtocolVersion = 3; internal const string EventMagic = "tony4twentys.Vasodilation"; internal const int ConfigPayloadLength = 13; internal static ConfigEntry SprintRatio; internal static ConfigEntry JumpRatio; internal static ConfigEntry SprintJumpRatio; internal static ConfigEntry ClimbJumpRatio; internal static ConfigEntry WallClimbRatio; internal static ConfigEntry RopeClimbRatio; internal static ConfigEntry VineClimbRatio; internal static ConfigEntry EmoteColdPerSecond; internal static ConfigEntry GateOn; internal static ConfigEntry GateOff; internal static ConfigEntry VerboseLogs; internal static float syncedSprintRatio = 0.5f; internal static float syncedJumpRatio = 0.25f; internal static float syncedSprintJumpRatio = 0.25f; internal static float syncedClimbJumpRatio = 0.25f; internal static float syncedWallClimbRatio = 0.5f; internal static float syncedRopeClimbRatio = 1f; internal static float syncedVineClimbRatio = 0.75f; internal static float syncedEmoteColdPerSecond = 0.01f; internal static float syncedGateOn = 0.025f; internal static float syncedGateOff = 0f; internal static bool isHandshakeValid = true; private Harmony _harmony; private bool _warmingActive; private bool _loggedTickError; private bool _loggedStaminaError; private float _nextEmoteLog; private static readonly float[] NextSourceLog = new float[8]; private static float _alpineCachedAt = -999f; private static bool _alpineCached; internal static VasodilationPlugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static bool IsGameplayEnabled { get { try { if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient) { return true; } } catch { return isHandshakeValid; } return isHandshakeValid; } } internal static bool DebugLogs { get { if (VerboseLogs != null) { return VerboseLogs.Value; } return false; } } private void Awake() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfig(); ApplyLocalConfig(); if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient) { isHandshakeValid = true; } _harmony = new Harmony("tony4twentys.Vasodilation"); PatchAllSafe(); VasoNet.Ensure(); ((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged; Log.LogInfo((object)string.Format("{0} v{1} loaded. Photon {2}.", "Vasodilation", "2.0.0", (byte)162)); } private void Update() { try { TickEmoteWarmth(Time.deltaTime); } catch (Exception ex) { LogOnce(ref _loggedTickError, "[Vasodilation] Emote warmth tick failed.", ex); } } private void BindConfig() { if ((0u | (DropOldConfig("General", "ColdPerSecond") ? 1u : 0u) | (DropOldConfig("General", "TickSeconds") ? 1u : 0u) | (DropOldConfig("General", "StaminaToColdRatio") ? 1u : 0u) | (DropOldConfig("General", "EmoteColdPerSecond") ? 1u : 0u)) != 0) { ((BaseUnityPlugin)this).Config.Save(); } SprintRatio = BindWarmthRatio("Sprint", 0.5f, "Grounded sprint."); JumpRatio = BindWarmthRatio("Jump", 0.25f, "Standing jump."); SprintJumpRatio = BindWarmthRatio("SprintJump", 0.25f, "Jump while sprinting."); ClimbJumpRatio = BindWarmthRatio("ClimbJump", 0.25f, "Wall sprint-boost. Alpine walls are ignored."); WallClimbRatio = BindWarmthRatio("WallClimb", 0.5f, "Wall hang, move, or re-grab. Alpine walls are ignored."); RopeClimbRatio = BindWarmthRatio("RopeClimb", 1f, "Climbing up a rope. Hang and climb-down are ignored."); VineClimbRatio = BindWarmthRatio("VineClimb", 0.75f, "Climbing a vine. Hang, slide, and grab are ignored."); EmoteColdPerSecond = ((BaseUnityPlugin)this).Config.Bind("Warmth", "EmoteColdPerSecond", 0.01f, "Host only. Cold removed per second during Dance, Crashout, Shimmy, Backflip, Wave, or Bully. Emotes do not use stamina. Host value is synced to the room."); GateOn = ((BaseUnityPlugin)this).Config.Bind("General", "ColdGateOn", 0.025f, "Host only. Start warming once Cold is above this. Host value is synced to the room."); GateOff = ((BaseUnityPlugin)this).Config.Bind("General", "ColdGateOff", 0f, "Host only. Stop warming once Cold is at or below this. Host value is synced to the room."); VerboseLogs = ((BaseUnityPlugin)this).Config.Bind("Debug", "VerboseLogs", false, "Local only. Log warmth about once per second per move. Not host-synced."); } private ConfigEntry BindWarmthRatio(string key, float defaultValue, string what) { return ((BaseUnityPlugin)this).Config.Bind("Warmth", key, defaultValue, "Host only. Cold removed per stamina spent: " + what + " 0.5 = half, 1 = 1:1. Host value is synced to the room."); } private bool DropOldConfig(string section, string key) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition(section, key); if (!((BaseUnityPlugin)this).Config.ContainsKey(val)) { return false; } ((BaseUnityPlugin)this).Config.Remove(val); return true; } private void OnSettingChanged(object sender, SettingChangedEventArgs args) { if (args == null || (object)args.ChangedSetting != VerboseLogs) { VasoNet.OnLocalSettingChanged(); } } internal static void ApplyLocalConfig() { ApplySyncedValues(GateOn.Value, GateOff.Value, EmoteColdPerSecond.Value, SprintRatio.Value, JumpRatio.Value, SprintJumpRatio.Value, ClimbJumpRatio.Value, WallClimbRatio.Value, RopeClimbRatio.Value, VineClimbRatio.Value); } internal static object[] BuildConfigPayload(byte sub) { return new object[13] { "tony4twentys.Vasodilation", 3, sub, GateOn.Value, GateOff.Value, EmoteColdPerSecond.Value, SprintRatio.Value, JumpRatio.Value, SprintJumpRatio.Value, ClimbJumpRatio.Value, WallClimbRatio.Value, RopeClimbRatio.Value, VineClimbRatio.Value }; } internal static void ApplyRemoteConfig(object[] arr) { if (arr == null || arr.Length < 13) { throw new InvalidOperationException("Vasodilation config payload too short."); } ApplySyncedValues(Convert.ToSingle(arr[3]), Convert.ToSingle(arr[4]), Convert.ToSingle(arr[5]), Convert.ToSingle(arr[6]), Convert.ToSingle(arr[7]), Convert.ToSingle(arr[8]), Convert.ToSingle(arr[9]), Convert.ToSingle(arr[10]), Convert.ToSingle(arr[11]), Convert.ToSingle(arr[12])); } private static void ApplySyncedValues(float gateOn, float gateOff, float emote, float sprint, float jump, float sprintJump, float climbJump, float wall, float rope, float vine) { syncedGateOn = Mathf.Max(0f, gateOn); syncedGateOff = Mathf.Max(0f, gateOff); syncedEmoteColdPerSecond = Mathf.Max(0f, emote); syncedSprintRatio = Mathf.Max(0f, sprint); syncedJumpRatio = Mathf.Max(0f, jump); syncedSprintJumpRatio = Mathf.Max(0f, sprintJump); syncedClimbJumpRatio = Mathf.Max(0f, climbJump); syncedWallClimbRatio = Mathf.Max(0f, wall); syncedRopeClimbRatio = Mathf.Max(0f, rope); syncedVineClimbRatio = Mathf.Max(0f, vine); if (syncedGateOff > syncedGateOn) { syncedGateOff = syncedGateOn; } } internal static void DebugLog(string message) { if (DebugLogs) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)message); } } } internal static void LogOnce(ref bool flag, string message, Exception ex) { if (flag) { return; } flag = true; if (ex != null) { ManualLogSource log = Log; if (log != null) { log.LogError((object)(message + " " + ex)); } } else { ManualLogSource log2 = Log; if (log2 != null) { log2.LogError((object)message); } } } internal static void OnStaminaSpent(Character character, float spent) { VasodilationPlugin instance = Instance; if ((Object)(object)instance == (Object)null) { return; } try { instance.TryWarmFromStamina(character, spent); } catch (Exception ex) { LogOnce(ref instance._loggedStaminaError, "[Vasodilation] Stamina warmth failed.", ex); } } private void TryWarmFromStamina(Character character, float spent) { if (spent <= 1E-05f || !IsGameplayEnabled || !CanWarm(character)) { return; } WarmthSource warmthSource = GetWarmthSource(character); if (warmthSource != WarmthSource.None && UpdateWarmingGate(character)) { float num = spent * GetSyncedRatio(warmthSource); if (!(num <= 0f)) { character.refs.afflictions.SubtractStatus((STATUSTYPE)2, num, false, false); MaybeLogWarmth(warmthSource, spent, num); } } } private void TickEmoteWarmth(float deltaTime) { if (deltaTime <= 0f || syncedEmoteColdPerSecond <= 0f || !IsGameplayEnabled) { return; } Character localCharacter = Character.localCharacter; if (!EmoteWarmth.IsWarming(localCharacter) || !CanWarm(localCharacter) || !UpdateWarmingGate(localCharacter)) { return; } float num = syncedEmoteColdPerSecond * deltaTime; if (!(num <= 0f)) { localCharacter.refs.afflictions.SubtractStatus((STATUSTYPE)2, num, false, false); if (DebugLogs && Time.unscaledTime >= _nextEmoteLog) { _nextEmoteLog = Time.unscaledTime + 1f; DebugLog("[Vasodilation] emote coldDelta=" + num.ToString("0.####")); } } } private bool CanWarm(Character character) { if ((Object)(object)character == (Object)null || !character.IsLocal) { return false; } if ((Object)(object)character.data == (Object)null || character.refs == null || (Object)(object)character.refs.afflictions == (Object)null) { return false; } if (character.data.dead) { return false; } return true; } private bool UpdateWarmingGate(Character character) { float currentStatus = character.refs.afflictions.GetCurrentStatus((STATUSTYPE)2); if (currentStatus <= syncedGateOff) { _warmingActive = false; } else if (currentStatus > syncedGateOn) { _warmingActive = true; } return _warmingActive; } internal static WarmthSource GetWarmthSource(Character character) { if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null) { return WarmthSource.None; } CharacterData data = character.data; if (WarmthSpendMark.Ignore) { return WarmthSource.None; } if (WarmthSpendMark.ClimbJump) { if (!IsAlpine()) { return WarmthSource.ClimbJump; } return WarmthSource.None; } if (data.isJumping) { if (!data.isSprinting) { return WarmthSource.Jump; } return WarmthSource.SprintJump; } if (data.isRopeClimbing) { if (!IsClimbingRopeUp(character)) { return WarmthSource.None; } return WarmthSource.RopeClimb; } if (data.isVineClimbing) { if (!IsClimbingVine(character)) { return WarmthSource.None; } return WarmthSource.VineClimb; } if (data.isClimbing) { if (!IsAlpine()) { return WarmthSource.WallClimb; } return WarmthSource.None; } if (data.isSprinting) { return WarmthSource.Sprint; } return WarmthSource.None; } internal static float GetSyncedRatio(WarmthSource source) { return source switch { WarmthSource.Sprint => syncedSprintRatio, WarmthSource.Jump => syncedJumpRatio, WarmthSource.SprintJump => syncedSprintJumpRatio, WarmthSource.ClimbJump => syncedClimbJumpRatio, WarmthSource.WallClimb => syncedWallClimbRatio, WarmthSource.RopeClimb => syncedRopeClimbRatio, WarmthSource.VineClimb => syncedVineClimbRatio, _ => 0f, }; } private static bool IsClimbingRopeUp(Character character) { if ((Object)(object)character == (Object)null || (Object)(object)character.input == (Object)null) { return false; } return character.input.movementInput.y > 0.01f; } private static bool IsClimbingVine(Character character) { if ((Object)(object)character == (Object)null || (Object)(object)character.input == (Object)null) { return false; } if (character.refs != null && (Object)(object)character.refs.vineClimbing != (Object)null && character.refs.vineClimbing.Sliding()) { return false; } return Mathf.Abs(character.input.movementInput.y) >= 0.01f; } private void MaybeLogWarmth(WarmthSource source, float spent, float amount) { if (!DebugLogs) { return; } if (source >= WarmthSource.None && (int)source < NextSourceLog.Length) { float unscaledTime = Time.unscaledTime; if (!(spent < 0.02f) || !(unscaledTime < NextSourceLog[(int)source])) { NextSourceLog[(int)source] = unscaledTime + 1f; DebugLog($"[Vasodilation] stam={spent:0.####} coldDelta={amount:0.####} source={source}"); } } } internal static bool IsAlpine() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 float unscaledTime = Time.unscaledTime; if (unscaledTime - _alpineCachedAt < 0.5f) { return _alpineCached; } _alpineCachedAt = unscaledTime; try { MapHandler instance = Singleton.Instance; _alpineCached = (Object)(object)instance != (Object)null && (int)instance.GetCurrentBiome() == 2; } catch { _alpineCached = false; } return _alpineCached; } private void PatchAllSafe() { Type[] types = typeof(VasodilationPlugin).Assembly.GetTypes(); foreach (Type type in types) { if (!(type == null) && type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0) { try { _harmony.CreateClassProcessor(type).Patch(); } catch (Exception ex) { Log.LogError((object)("[Vasodilation] Patch failed on " + type.Name + ": " + ex.Message)); } } } } } internal sealed class VasoNet : MonoBehaviourPunCallbacks, IOnEventCallback { private const byte SubConfig = 1; private const byte SubConfigRequest = 2; private const float HostSyncTimeoutSeconds = 12f; private const float HostSyncRetrySeconds = 2f; internal static bool HostModConfirmed; private Coroutine _debounce; private Coroutine _hostSyncWatch; private bool _syncingFromNet; internal static VasoNet Instance { get; private set; } internal static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if ((Object)(object)Instance != (Object)null) { return; } GameObject val = new GameObject("Vasodilation_Net"); Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent(); try { if (PhotonNetwork.InRoom) { Instance.HandleJoinedRoom(); } } catch { } } private void Awake() { Instance = this; } public override void OnEnable() { ((MonoBehaviourPunCallbacks)this).OnEnable(); PhotonNetwork.AddCallbackTarget((object)this); } public override void OnDisable() { PhotonNetwork.RemoveCallbackTarget((object)this); ((MonoBehaviourPunCallbacks)this).OnDisable(); } public override void OnJoinedRoom() { HandleJoinedRoom(); } public override void OnLeftRoom() { StopHostSyncWatch(); HostModConfirmed = false; VasodilationPlugin.isHandshakeValid = true; VasodilationPlugin.ApplyLocalConfig(); } public override void OnMasterClientSwitched(Player newMasterClient) { if (PhotonNetwork.IsMasterClient) { HostModConfirmed = true; VasodilationPlugin.isHandshakeValid = true; VasodilationPlugin.ApplyLocalConfig(); BroadcastNow(); StopHostSyncWatch(); } else { HostModConfirmed = false; VasodilationPlugin.isHandshakeValid = false; RequestHostSync(); RestartHostSyncWatch(); } } public override void OnPlayerEnteredRoom(Player newPlayer) { if (PhotonNetwork.IsMasterClient) { ((MonoBehaviour)this).StartCoroutine(BroadcastAfterDelay(0.5f)); } } public void OnEvent(EventData photonEvent) { if (photonEvent == null || photonEvent.Code != 162 || !(photonEvent.CustomData is object[] array) || array.Length < 3 || !(array[0] is string text) || text != "tony4twentys.Vasodilation" || ToInt(array[1]) != 3) { return; } byte b = ToByte(array[2]); if (b == 2 && PhotonNetwork.IsMasterClient) { BroadcastNow(); } else { if (b != 1 || PhotonNetwork.IsMasterClient) { return; } try { _syncingFromNet = true; VasodilationPlugin.ApplyRemoteConfig(array); StopHostSyncWatch(); HostModConfirmed = true; VasodilationPlugin.isHandshakeValid = true; VasodilationPlugin.Log.LogInfo((object)"[Vasodilation] Host config sync applied."); } catch (Exception ex) { VasodilationPlugin.Log.LogError((object)("[Vasodilation] Config sync failed: " + ex.Message)); } finally { _syncingFromNet = false; } } } internal static void OnLocalSettingChanged() { if (!((Object)(object)Instance != (Object)null) || !Instance._syncingFromNet) { if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient) { VasodilationPlugin.ApplyLocalConfig(); } ScheduleBroadcast(); } } internal static void ScheduleBroadcast() { if (!((Object)(object)Instance == (Object)null) && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) { if (Instance._debounce != null) { ((MonoBehaviour)Instance).StopCoroutine(Instance._debounce); } Instance._debounce = ((MonoBehaviour)Instance).StartCoroutine(Instance.DebounceBroadcast()); } } private void HandleJoinedRoom() { if (PhotonNetwork.IsMasterClient) { HostModConfirmed = true; VasodilationPlugin.isHandshakeValid = true; VasodilationPlugin.ApplyLocalConfig(); BroadcastNow(); StopHostSyncWatch(); } else { HostModConfirmed = false; VasodilationPlugin.isHandshakeValid = false; RequestHostSync(); RestartHostSyncWatch(); } } private static void RequestHostSync() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient) { PhotonNetwork.RaiseEvent((byte)162, (object)new object[3] { "tony4twentys.Vasodilation", 3, (byte)2 }, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); } } private void RestartHostSyncWatch() { StopHostSyncWatch(); if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient) { _hostSyncWatch = ((MonoBehaviour)this).StartCoroutine(WatchForHostSync()); } } private void StopHostSyncWatch() { if (_hostSyncWatch != null) { ((MonoBehaviour)this).StopCoroutine(_hostSyncWatch); _hostSyncWatch = null; } } private IEnumerator WatchForHostSync() { float elapsed = 0f; float nextRetry = 2f; while (elapsed < 12f) { if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient || HostModConfirmed) { yield break; } elapsed += Time.unscaledDeltaTime; if (elapsed >= nextRetry) { RequestHostSync(); nextRetry += 2f; } yield return null; } if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && !HostModConfirmed) { VasodilationPlugin.isHandshakeValid = false; VasodilationPlugin.Log.LogWarning((object)"[Vasodilation] Host does not appear to have Vasodilation — warmth disabled."); } _hostSyncWatch = null; } private IEnumerator DebounceBroadcast() { yield return (object)new WaitForSeconds(0.25f); BroadcastNow(); _debounce = null; } private IEnumerator BroadcastAfterDelay(float seconds) { yield return (object)new WaitForSeconds(seconds); BroadcastNow(); } private static void BroadcastNow() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) { PhotonNetwork.RaiseEvent((byte)162, (object)VasodilationPlugin.BuildConfigPayload(1), new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } } private static int ToInt(object value) { return Convert.ToInt32(value); } private static byte ToByte(object value) { return Convert.ToByte(value); } } internal static class EmoteWarmth { internal static bool LastIsWarming; private static readonly string[] WarmTokens = new string[6] { "dance", "crashout", "shimmy", "backflip", "wave", "bully" }; internal static bool IsWarmingName(string emoteName) { if (string.IsNullOrEmpty(emoteName)) { return false; } string text = emoteName.ToLowerInvariant(); for (int i = 0; i < WarmTokens.Length; i++) { if (text.IndexOf(WarmTokens[i], StringComparison.Ordinal) >= 0) { return true; } } return false; } internal static bool IsWarming(Character character) { if (!LastIsWarming) { return false; } if ((Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.animations == (Object)null) { return false; } return character.refs.animations.emoting; } internal static void Remember(CharacterAnimations animations, string emoteName) { if (!((Object)(object)animations == (Object)null) && !string.IsNullOrEmpty(emoteName)) { Character character = animations.character; if (!((Object)(object)character == (Object)null) && character.IsLocal) { LastIsWarming = IsWarmingName(emoteName); } } } } internal static class WarmthSpendMark { internal static bool Ignore; internal static bool ClimbJump; } [HarmonyPatch(typeof(CharacterVineClimbing), "GrabVineRpc")] internal static class VineGrabSkipPatch { private static void Prefix() { WarmthSpendMark.Ignore = true; } private static Exception Finalizer(Exception __exception) { WarmthSpendMark.Ignore = false; return __exception; } } [HarmonyPatch(typeof(CharacterGrabbing), "KickCast")] internal static class KickSkipPatch { private static void Prefix() { WarmthSpendMark.Ignore = true; } private static Exception Finalizer(Exception __exception) { WarmthSpendMark.Ignore = false; return __exception; } } [HarmonyPatch(typeof(CharacterClimbing), "RPCA_ClimbJump")] internal static class ClimbJumpMarkPatch { private static void Prefix() { WarmthSpendMark.ClimbJump = true; } private static Exception Finalizer(Exception __exception) { WarmthSpendMark.ClimbJump = false; return __exception; } } [HarmonyPatch(typeof(Character), "UseStamina")] internal static class UseStaminaWarmthPatch { private static bool _logged; private static void Prefix(Character __instance, out float __state) { __state = -1f; try { if (!((Object)(object)__instance == (Object)null) && __instance.IsLocal) { __state = __instance.GetTotalStamina(); } } catch (Exception ex) { VasodilationPlugin.LogOnce(ref _logged, "[Vasodilation] UseStamina prefix failed.", ex); } } private static void Postfix(Character __instance, float __state) { if (__state < 0f || (Object)(object)__instance == (Object)null) { return; } try { float num = __state - __instance.GetTotalStamina(); if (num > 1E-05f) { VasodilationPlugin.OnStaminaSpent(__instance, num); } } catch (Exception ex) { VasodilationPlugin.LogOnce(ref _logged, "[Vasodilation] UseStamina postfix failed.", ex); } } } [HarmonyPatch(typeof(CharacterAnimations), "RPCA_PlayRemove")] internal static class EmotePlayPatch { private static bool _logged; private static void Postfix(CharacterAnimations __instance, string emoteName) { try { EmoteWarmth.Remember(__instance, emoteName); } catch (Exception ex) { VasodilationPlugin.LogOnce(ref _logged, "[Vasodilation] Emote postfix failed.", ex); } } } [HarmonyPatch(typeof(CharacterAnimations), "PlayEmote")] internal static class EmoteLocalPlayPatch { private static bool _logged; private static void Postfix(CharacterAnimations __instance, string emoteName) { try { EmoteWarmth.Remember(__instance, emoteName); } catch (Exception ex) { VasodilationPlugin.LogOnce(ref _logged, "[Vasodilation] PlayEmote postfix failed.", ex); } } } }