using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using ClimbStamina;
using ClimbStamina.Compatibility;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.VRMK;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(ClimbStaminaMod), "ClimbStamina", "1.3.0", "Cesar", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "BoneLib" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ClimbStamina")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0+c417cbe30ed54091dc052cf07de631265199e42b")]
[assembly: AssemblyProduct("ClimbStamina")]
[assembly: AssemblyTitle("ClimbStamina")]
[assembly: AssemblyVersion("1.3.0.0")]
namespace ClimbStamina
{
internal sealed class ClimbDetector
{
private sealed class HandSlot
{
internal Hand Hand;
internal Grip Grip;
internal bool IsClimbing
{
get
{
if ((Object)(object)Hand != (Object)null)
{
return (Object)(object)Grip != (Object)null;
}
return false;
}
}
internal void Clear()
{
Hand = null;
Grip = null;
}
}
private readonly HandSlot _left = new HandSlot();
private readonly HandSlot _right = new HandSlot();
internal Action<Hand, Grip> OnBlockedClimbAttach;
internal Action<Hand> OnClimbAttached;
internal Func<bool> CanStartClimb = () => true;
internal int ClimbingHandCount => (_left.IsClimbing ? 1 : 0) + (_right.IsClimbing ? 1 : 0);
internal bool LeftClimbing => _left.IsClimbing;
internal bool RightClimbing => _right.IsClimbing;
internal void Subscribe()
{
Hooking.OnGripAttached += OnGripAttached;
Hooking.OnGripDetached += OnGripDetached;
}
internal void Unsubscribe()
{
Hooking.OnGripAttached -= OnGripAttached;
Hooking.OnGripDetached -= OnGripDetached;
}
internal static bool IsClimbingGrip(Grip grip)
{
if ((Object)(object)grip == (Object)null)
{
return false;
}
if ((Object)(object)((Il2CppObjectBase)grip).TryCast<UIInteractionVolume>() != (Object)null)
{
return false;
}
if ((Object)(object)((Il2CppObjectBase)grip).TryCast<WorldGrip>() != (Object)null)
{
return true;
}
return ((HandReciever)grip).IsStatic;
}
private void OnGripAttached(Grip grip, Hand hand)
{
if (!PlayerTracker.IsLocalHand(hand) || !IsClimbingGrip(grip))
{
return;
}
if (!CanStartClimb())
{
OnBlockedClimbAttach?.Invoke(hand, grip);
return;
}
HandSlot handSlot = SlotFor(hand);
if (handSlot != null)
{
handSlot.Hand = hand;
handSlot.Grip = grip;
ClimbStaminaMod.LogDebug("Climb attach: " + SideName(hand) + " -> " + ((Object)grip).name);
OnClimbAttached?.Invoke(hand);
}
}
private void OnGripDetached(Grip grip, Hand hand)
{
if (!((Object)(object)hand == (Object)null))
{
HandSlot handSlot = SlotFor(hand);
if (handSlot != null && handSlot.IsClimbing && !((Object)(object)handSlot.Hand != (Object)(object)hand) && ((Object)(object)handSlot.Grip == (Object)(object)grip || (Object)(object)grip == (Object)null))
{
ClimbStaminaMod.LogDebug("Climb detach: " + SideName(hand));
handSlot.Clear();
}
}
}
internal void Validate()
{
ValidateSlot(_left);
ValidateSlot(_right);
}
private static void ValidateSlot(HandSlot slot)
{
if (!slot.IsClimbing)
{
if ((Object)(object)slot.Hand != (Object)null || (Object)(object)slot.Grip != (Object)null)
{
slot.Clear();
}
}
else if ((Object)(object)slot.Hand == (Object)null || (Object)(object)slot.Grip == (Object)null || !PlayerTracker.IsLocalHand(slot.Hand) || (Object)(object)slot.Hand.AttachedReceiver != (Object)(object)slot.Grip)
{
slot.Clear();
}
}
internal void Rescan()
{
RescanHand(Player.LeftHand, _left);
RescanHand(Player.RightHand, _right);
}
private static void RescanHand(Hand hand, HandSlot slot)
{
if (slot.IsClimbing || (Object)(object)hand == (Object)null || !PlayerTracker.IsLocalHand(hand))
{
return;
}
HandReciever attachedReceiver = hand.AttachedReceiver;
if (!((Object)(object)attachedReceiver == (Object)null))
{
Grip val = ((Il2CppObjectBase)attachedReceiver).TryCast<Grip>();
if (!((Object)(object)val == (Object)null) && IsClimbingGrip(val))
{
slot.Hand = hand;
slot.Grip = val;
}
}
}
internal void ForEachClimbingHand(Action<Hand> action)
{
if (_left.IsClimbing)
{
action(_left.Hand);
}
if (_right.IsClimbing)
{
action(_right.Hand);
}
}
internal void Clear()
{
_left.Clear();
_right.Clear();
}
private HandSlot SlotFor(Hand hand)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Invalid comparison between Unknown and I4
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Invalid comparison between Unknown and I4
Handedness handedness = hand.handedness;
if ((int)handedness != 1)
{
if ((int)handedness == 2)
{
return _right;
}
return null;
}
return _left;
}
private static string SideName(Hand hand)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
if ((int)hand.handedness != 1)
{
return "right";
}
return "left";
}
}
public class ClimbStaminaMod : MelonMod
{
internal static bool ClimbBlocked;
private static Instance _logger;
private static float _lastBlockedNotifyStatic = -999f;
private ClimbDetector _detector;
private GripController _grips;
private StaminaController _stamina;
private StaminaHud _hud;
private HapticsController _haptics;
private PanicGrabController _panic;
private bool _wasEnabled = true;
private float _debugLogTimer;
private Action<LevelInfo> _onLevelLoaded;
private Action _onLevelUnloaded;
private Action<Avatar> _onAvatarSwitched;
private Action<RigManager> _onPlayerDeath;
private Action<RigManager> _onPlayerResurrected;
public override void OnInitializeMelon()
{
_logger = ((MelonBase)this).LoggerInstance;
Prefs.Setup();
SettingsMenu.Setup();
_detector = new ClimbDetector();
_grips = new GripController();
_stamina = new StaminaController(_detector, _grips);
_hud = new StaminaHud();
_haptics = new HapticsController(_detector);
_panic = new PanicGrabController(_detector, _stamina, _haptics, _hud);
_detector.OnBlockedClimbAttach = OnBlockedClimbAttach;
_detector.OnClimbAttached = _panic.OnClimbAttached;
_stamina.OnExhausted = OnExhausted;
_stamina.OnLowStamina = OnLowStamina;
_detector.Subscribe();
GripController.ApplyPatches(((MelonBase)this).HarmonyInstance);
_onLevelLoaded = OnLevelLoaded;
_onLevelUnloaded = OnLevelUnloaded;
_onAvatarSwitched = delegate
{
PlayerTracker.RefreshAvatarMultiplier();
};
_onPlayerDeath = delegate(RigManager rig)
{
if (IsLocalRig(rig))
{
_detector.Clear();
_grips.Clear();
_panic.Reset();
}
};
_onPlayerResurrected = delegate(RigManager rig)
{
if (IsLocalRig(rig))
{
_stamina.ResetFull();
}
};
Hooking.OnLevelLoaded += _onLevelLoaded;
Hooking.OnLevelUnloaded += _onLevelUnloaded;
Hooking.OnSwitchAvatarPostfix += _onAvatarSwitched;
Hooking.OnPlayerDeath += _onPlayerDeath;
Hooking.OnPlayerResurrected += _onPlayerResurrected;
Log("BoneLib detected.");
FusionCompatibility.Detect();
ClimbAnythingCompatibility.Detect();
Log("Initialized.");
}
public override void OnDeinitializeMelon()
{
_hud?.Drop();
_detector?.Unsubscribe();
Hooking.OnLevelLoaded -= _onLevelLoaded;
Hooking.OnLevelUnloaded -= _onLevelUnloaded;
Hooking.OnSwitchAvatarPostfix -= _onAvatarSwitched;
Hooking.OnPlayerDeath -= _onPlayerDeath;
Hooking.OnPlayerResurrected -= _onPlayerResurrected;
}
public override void OnUpdate()
{
if (_stamina == null)
{
return;
}
bool value = Prefs.Enabled.Value;
if (value != _wasEnabled)
{
_wasEnabled = value;
if (!value)
{
_detector.Clear();
_grips.Clear();
_stamina.ResetFull();
_hud.Drop();
_haptics.Reset();
_panic.Reset();
}
else if (PlayerTracker.IsValid)
{
_detector.Rescan();
}
}
if (value)
{
float deltaTime = Time.deltaTime;
_panic.Update(deltaTime);
_stamina.Update(deltaTime);
_hud.Update(_stamina, deltaTime);
_haptics.Update(_stamina, deltaTime);
EmitDebugLog(deltaTime);
}
}
private void OnLevelLoaded(LevelInfo info)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
_detector.Clear();
_grips.Clear();
_stamina.ResetFull();
_hud.Drop();
_haptics.Reset();
_panic.Reset();
PlayerTracker.RefreshAvatarMultiplier();
Log("BONELAB player rig acquired (" + info.title + ").");
}
private void OnLevelUnloaded()
{
_detector.Clear();
_grips.Clear();
_hud.Drop();
_haptics.Reset();
_panic.Reset();
}
private void OnBlockedClimbAttach(Hand hand, Grip grip)
{
_grips.QueueDetach(hand);
NotifyBlockedRegrab();
}
internal static void NotifyBlockedRegrab()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Expected O, but got Unknown
if (!(Time.time - _lastBlockedNotifyStatic < 2.5f))
{
_lastBlockedNotifyStatic = Time.time;
Notifier.Send(new Notification
{
Title = NotificationText.op_Implicit("Climb Stamina"),
Message = NotificationText.op_Implicit("Too exhausted to climb."),
Type = (NotificationType)1,
PopupLength = 1.2f,
ShowTitleOnPopup = false
});
}
}
private static bool IsLocalRig(RigManager rig)
{
RigManager rigManager = Player.RigManager;
if ((Object)(object)rig != (Object)null && (Object)(object)rigManager != (Object)null)
{
return (Object)(object)rig == (Object)(object)rigManager;
}
return false;
}
private void OnExhausted()
{
_haptics.PulseRelease();
}
private void OnLowStamina()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Expected O, but got Unknown
Notifier.Send(new Notification
{
Title = NotificationText.op_Implicit("Climb Stamina"),
Message = NotificationText.op_Implicit("Grip weakening..."),
Type = (NotificationType)0,
PopupLength = 1.2f,
ShowTitleOnPopup = false
});
}
private void EmitDebugLog(float deltaTime)
{
if (!Prefs.DebugLogging.Value)
{
return;
}
_debugLogTimer += deltaTime;
if (!(_debugLogTimer < 1f))
{
_debugLogTimer = 0f;
if (PlayerTracker.IsValid)
{
LogDebug($"left climbing = {_detector.LeftClimbing}, right climbing = {_detector.RightClimbing}, stamina = {_stamina.Stamina:0.0}, state = {_stamina.State}, standing = {PlayerTracker.IsStanding} ({PlayerTracker.DescribeGroundState()}), avatarMult = {PlayerTracker.AvatarDrainMultiplier:0.###}");
}
}
}
internal static void Log(string message)
{
Instance logger = _logger;
if (logger != null)
{
logger.Msg(message);
}
}
internal static void LogWarning(string message)
{
Instance logger = _logger;
if (logger != null)
{
logger.Warning(message);
}
}
internal static void LogDebug(string message)
{
if (Prefs.DebugLogging != null && Prefs.DebugLogging.Value)
{
Instance logger = _logger;
if (logger != null)
{
logger.Msg("[debug] " + message);
}
}
}
}
internal sealed class GripController
{
private readonly List<Hand> _pendingDetach = new List<Hand>(2);
internal static void ReleaseClimbingHand(Hand hand)
{
if ((Object)(object)hand == (Object)null)
{
return;
}
HandReciever attachedReceiver = hand.AttachedReceiver;
if (!((Object)(object)attachedReceiver == (Object)null))
{
Grip val = ((Il2CppObjectBase)attachedReceiver).TryCast<Grip>();
if (!((Object)(object)val == (Object)null) && ClimbDetector.IsClimbingGrip(val))
{
val.ForceDetach(hand);
ClimbStaminaMod.LogDebug("Force-detached climbing hand");
}
}
}
internal static void SweepClimbingHands()
{
Hand leftHand = Player.LeftHand;
if ((Object)(object)leftHand != (Object)null && PlayerTracker.IsLocalHand(leftHand))
{
ReleaseClimbingHand(leftHand);
}
Hand rightHand = Player.RightHand;
if ((Object)(object)rightHand != (Object)null && PlayerTracker.IsLocalHand(rightHand))
{
ReleaseClimbingHand(rightHand);
}
}
internal void QueueDetach(Hand hand)
{
if ((Object)(object)hand != (Object)null && !_pendingDetach.Contains(hand))
{
_pendingDetach.Add(hand);
}
}
internal void ProcessQueue()
{
if (_pendingDetach.Count == 0)
{
return;
}
for (int i = 0; i < _pendingDetach.Count; i++)
{
Hand val = _pendingDetach[i];
if ((Object)(object)val != (Object)null && PlayerTracker.IsLocalHand(val))
{
ReleaseClimbingHand(val);
}
}
_pendingDetach.Clear();
}
internal void Clear()
{
_pendingDetach.Clear();
}
internal static void ApplyPatches(Harmony harmony)
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
MethodInfo method = typeof(Grip).GetMethod("OnGrabConfirm", AccessTools.all);
MethodInfo method2 = typeof(GripController).GetMethod("OnGrabConfirmPrefix", AccessTools.all);
if (method == null || method2 == null)
{
ClimbStaminaMod.LogWarning("Grip.OnGrabConfirm not found; exhausted grabs will be detached a frame late instead of blocked.");
}
else
{
harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
private static bool OnGrabConfirmPrefix(Grip __instance, Hand hand)
{
try
{
if (!ClimbStaminaMod.ClimbBlocked)
{
return true;
}
if ((Object)(object)hand == (Object)null || !PlayerTracker.IsLocalHand(hand))
{
return true;
}
if ((Object)(object)__instance == (Object)null || !ClimbDetector.IsClimbingGrip(__instance))
{
return true;
}
ClimbStaminaMod.NotifyBlockedRegrab();
ClimbStaminaMod.LogDebug("Blocked climbing grab while exhausted");
return false;
}
catch (Exception ex)
{
ClimbStaminaMod.LogDebug("Grab prefix error, failing open: " + ex.GetType().Name);
return true;
}
}
}
internal sealed class HapticsController
{
private const float StartFraction = 0.35f;
private const float MinAmplitude = 0.05f;
private const float MaxAmplitude = 0.55f;
private const float IntensityCurve = 1.6f;
private const float MaxInterval = 0.6f;
private const float MinInterval = 0.1f;
private const float IntervalCurve = 1.3f;
private const float MinTickSeconds = 0.03f;
private const float MaxTickSeconds = 0.08f;
private const float TickFrequencyCalm = 170f;
private const float TickFrequencyEmpty = 120f;
private const float ReleaseAmplitude = 0.9f;
private const float ReleaseSeconds = 0.15f;
private const float ReleaseFrequency = 140f;
private const float PanicAmplitude = 0.75f;
private const float PanicSeconds = 0.12f;
private const float PanicFrequency = 150f;
private readonly ClimbDetector _detector;
private float _sinceLastPulse;
private bool _leftWasClimbing;
private bool _rightWasClimbing;
internal HapticsController(ClimbDetector detector)
{
_detector = detector;
}
internal void Reset()
{
_sinceLastPulse = 0f;
_leftWasClimbing = false;
_rightWasClimbing = false;
}
internal void Update(StaminaController stamina, float deltaTime)
{
bool leftClimbing = _detector.LeftClimbing;
bool rightClimbing = _detector.RightClimbing;
bool flag = stamina.State == StaminaState.CLIMBING_ONE_HAND || stamina.State == StaminaState.CLIMBING_TWO_HANDS;
float fraction = stamina.Fraction;
if (!Prefs.HapticsEnabled.Value || !flag || fraction >= 0.35f)
{
_sinceLastPulse = 0f;
}
else
{
float num = Mathf.Clamp01((0.35f - fraction) / 0.35f);
float num2 = Mathf.Lerp(0.6f, 0.1f, Mathf.Pow(num, 1.3f));
_sinceLastPulse += deltaTime;
if (_sinceLastPulse >= num2)
{
_sinceLastPulse = 0f;
float amplitude = Mathf.Lerp(0.05f, 0.55f, Mathf.Pow(num, 1.6f));
float seconds = Mathf.Lerp(0.03f, 0.08f, num);
float frequency = Mathf.Lerp(170f, 120f, num);
if (leftClimbing)
{
Pulse(Player.LeftController, seconds, frequency, amplitude);
}
if (rightClimbing)
{
Pulse(Player.RightController, seconds, frequency, amplitude);
}
}
}
_leftWasClimbing = leftClimbing;
_rightWasClimbing = rightClimbing;
}
internal void PulsePanic(Hand hand)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Invalid comparison between Unknown and I4
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Invalid comparison between Unknown and I4
if (!Prefs.HapticsEnabled.Value || (Object)(object)hand == (Object)null)
{
return;
}
Handedness handedness = hand.handedness;
BaseController controller;
if ((int)handedness != 1)
{
if ((int)handedness != 2)
{
return;
}
controller = Player.RightController;
}
else
{
controller = Player.LeftController;
}
Pulse(controller, 0.12f, 150f, 0.75f);
}
internal void PulseRelease()
{
if (Prefs.HapticsEnabled.Value)
{
if (_leftWasClimbing)
{
Pulse(Player.LeftController, 0.15f, 140f, 0.9f);
}
if (_rightWasClimbing)
{
Pulse(Player.RightController, 0.15f, 140f, 0.9f);
}
}
}
private static void Pulse(BaseController controller, float seconds, float frequency, float amplitude)
{
try
{
if ((Object)(object)controller == (Object)null)
{
return;
}
Haptor haptor = controller.haptor;
if (!((Object)(object)haptor == (Object)null) && haptor.hapticsAllowed)
{
amplitude = Mathf.Clamp01(amplitude * Mathf.Max(0f, Prefs.HapticStrength.Value));
if (!(amplitude <= 0f))
{
haptor.SENDHAPTIC(0f, seconds, frequency, amplitude);
}
}
}
catch (Exception ex)
{
ClimbStaminaMod.LogDebug("Haptic pulse failed: " + ex.GetType().Name);
}
}
}
internal sealed class PanicGrabController
{
private const float PeakHoldSeconds = 0.2f;
private const float CooldownSeconds = 0.75f;
private readonly ClimbDetector _detector;
private readonly StaminaController _stamina;
private readonly HapticsController _haptics;
private readonly StaminaHud _hud;
private float _peakFallSpeed;
private float _peakAge;
private float _cooldown;
internal PanicGrabController(ClimbDetector detector, StaminaController stamina, HapticsController haptics, StaminaHud hud)
{
_detector = detector;
_stamina = stamina;
_haptics = haptics;
_hud = hud;
}
internal void Reset()
{
_peakFallSpeed = 0f;
_peakAge = 0f;
_cooldown = 0f;
}
internal void Update(float deltaTime)
{
if (_cooldown > 0f)
{
_cooldown -= deltaTime;
}
float verticalVelocity = PlayerTracker.VerticalVelocity;
if (PlayerTracker.IsStanding)
{
_peakFallSpeed = verticalVelocity;
_peakAge = 0f;
return;
}
if (verticalVelocity <= _peakFallSpeed)
{
_peakFallSpeed = verticalVelocity;
_peakAge = 0f;
return;
}
_peakAge += deltaTime;
if (_peakAge >= 0.2f)
{
_peakFallSpeed = verticalVelocity;
_peakAge = 0f;
}
}
internal void OnClimbAttached(Hand hand)
{
if (Prefs.PanicGrabEnabled.Value && !(_cooldown > 0f) && _detector.ClimbingHandCount == 1 && !PlayerTracker.IsStanding)
{
float num = Mathf.Max(0.5f, Prefs.PanicFallSpeed.Value);
if (!(_peakFallSpeed > 0f - num))
{
_cooldown = 0.75f;
ClimbStaminaMod.LogDebug($"Panic grab at {_peakFallSpeed:0.0} m/s");
_peakFallSpeed = 0f;
_peakAge = 0f;
_haptics.PulsePanic(hand);
_hud.FlashPanic();
_stamina.ApplyPanicGrab();
}
}
}
}
internal static class PlayerTracker
{
private static float _avatarDrainMultiplier = 1f;
private const float MinGroundNormalUp = 0.55f;
internal static bool IsValid
{
get
{
if (HelperMethods.IsLoading())
{
return false;
}
if ((Object)(object)Player.RigManager != (Object)null)
{
return (Object)(object)Player.PhysicsRig != (Object)null;
}
return false;
}
}
internal static bool IsStanding
{
get
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: 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_001a: Invalid comparison between Unknown and I4
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Invalid comparison between Unknown and I4
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Invalid comparison between Unknown and I4
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
PhysicsRig physicsRig = Player.PhysicsRig;
if ((Object)(object)physicsRig == (Object)null)
{
return true;
}
StepState stepState = physicsRig._stepState;
if ((int)stepState == 3 || (int)stepState == 4 || (int)stepState == 5)
{
return false;
}
PhysGrounder physG = physicsRig.physG;
if ((Object)(object)physG == (Object)null)
{
return true;
}
if (!physG.isGrounded)
{
return false;
}
return physG.groundNormal.y >= 0.55f;
}
}
internal static float VerticalVelocity
{
get
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
PhysicsRig physicsRig = Player.PhysicsRig;
if ((Object)(object)physicsRig == (Object)null)
{
return 0f;
}
PhysTorso torso = physicsRig.torso;
if ((Object)(object)torso == (Object)null)
{
return 0f;
}
Rigidbody rbPelvis = torso.rbPelvis;
if ((Object)(object)rbPelvis == (Object)null)
{
return 0f;
}
return rbPelvis.velocity.y;
}
}
internal static float AvatarDrainMultiplier => _avatarDrainMultiplier;
internal static bool IsLocalHand(Hand hand)
{
if ((Object)(object)hand == (Object)null)
{
return false;
}
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager != (Object)null)
{
return (Object)(object)hand.manager == (Object)(object)rigManager;
}
return false;
}
internal static string DescribeGroundState()
{
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
try
{
PhysicsRig physicsRig = Player.PhysicsRig;
if ((Object)(object)physicsRig == (Object)null)
{
return "physicsRig=null";
}
PhysGrounder physG = physicsRig.physG;
if (!((Object)(object)physG == (Object)null))
{
Collider groundedCollider = physG._groundedCollider;
return $"step={physicsRig._stepState}, isGrounded={physG.isGrounded}, normalY={physG.groundNormal.y:0.00}, groundCollider={(((Object)(object)groundedCollider != (Object)null) ? ((Object)groundedCollider).name : "none")}, footSupported={physicsRig.footSupported:0.00}";
}
return $"step={physicsRig._stepState}, grounder=null";
}
catch (Exception ex)
{
return "unavailable (" + ex.GetType().Name + ")";
}
}
internal static void RefreshAvatarMultiplier()
{
_avatarDrainMultiplier = 1f;
if (!Prefs.AvatarStrengthScaling.Value)
{
return;
}
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
return;
}
Avatar avatar = rigManager.avatar;
if (!((Object)(object)avatar == (Object)null))
{
float strengthUpper = avatar._strengthUpper;
float num = Mathf.Max(0.01f, Prefs.AvatarReferenceStrength.Value);
if (float.IsNaN(strengthUpper) || strengthUpper <= 0f)
{
ClimbStaminaMod.LogDebug("Avatar strengthUpper unavailable; multiplier stays 1.0");
return;
}
_avatarDrainMultiplier = Mathf.Clamp(num / strengthUpper, 0.7f, 1.3f);
ClimbStaminaMod.LogDebug($"Avatar strengthUpper={strengthUpper:0.###} reference={num:0.###} drainMult={_avatarDrainMultiplier:0.###}");
}
}
}
internal static class Prefs
{
internal static MelonPreferences_Category Category;
internal static MelonPreferences_Entry<bool> Enabled;
internal static MelonPreferences_Entry<float> MaxStamina;
internal static MelonPreferences_Entry<float> OneHandDrainRate;
internal static MelonPreferences_Entry<float> TwoHandDrainRate;
internal static MelonPreferences_Entry<float> AscendingMultiplier;
internal static MelonPreferences_Entry<float> GroundedRegenRate;
internal static MelonPreferences_Entry<float> AirborneRegenRate;
internal static MelonPreferences_Entry<float> RecoveryDelay;
internal static MelonPreferences_Entry<float> MinRegrabStamina;
internal static MelonPreferences_Entry<bool> AvatarStrengthScaling;
internal static MelonPreferences_Entry<float> AvatarReferenceStrength;
internal static MelonPreferences_Entry<bool> ShowHud;
internal static MelonPreferences_Entry<bool> HapticsEnabled;
internal static MelonPreferences_Entry<float> HapticStrength;
internal static MelonPreferences_Entry<bool> PanicGrabEnabled;
internal static MelonPreferences_Entry<float> PanicFallSpeed;
internal static MelonPreferences_Entry<float> PanicStaminaCost;
internal static MelonPreferences_Entry<bool> DebugLogging;
internal static void Setup()
{
Category = MelonPreferences.CreateCategory("ClimbStamina", "Climb Stamina");
Enabled = Category.CreateEntry<bool>("Enabled", true, "Enabled", "Master switch for the climbing stamina system.", false, false, (ValueValidator)null, (string)null);
MaxStamina = Category.CreateEntry<float>("MaxStamina", 100f, "Max Stamina", "Total stamina pool.", false, false, (ValueValidator)null, (string)null);
OneHandDrainRate = Category.CreateEntry<float>("OneHandDrainRate", 10f, "One-Hand Drain Rate", "Stamina drained per second while hanging from one hand.", false, false, (ValueValidator)null, (string)null);
TwoHandDrainRate = Category.CreateEntry<float>("TwoHandDrainRate", 5f, "Two-Hand Drain Rate", "Stamina drained per second while hanging from two hands.", false, false, (ValueValidator)null, (string)null);
AscendingMultiplier = Category.CreateEntry<float>("AscendingMultiplier", 1.3f, "Ascending Multiplier", "Extra drain multiplier while actively climbing upward.", false, false, (ValueValidator)null, (string)null);
GroundedRegenRate = Category.CreateEntry<float>("GroundedRegenRate", 20f, "Grounded Regen Rate", "Stamina regenerated per second while standing on the ground.", false, false, (ValueValidator)null, (string)null);
AirborneRegenRate = Category.CreateEntry<float>("AirborneRegenRate", 5f, "Airborne Regen Rate", "Stamina regenerated per second while airborne (not climbing).", false, false, (ValueValidator)null, (string)null);
RecoveryDelay = Category.CreateEntry<float>("RecoveryDelay", 1f, "Recovery Delay", "Seconds after climbing stops before stamina starts regenerating.", false, false, (ValueValidator)null, (string)null);
MinRegrabStamina = Category.CreateEntry<float>("MinRegrabStamina", 100f, "Regrab Stamina %", "After exhaustion, climbing stays blocked until the bar refills to this percent.", false, false, (ValueValidator)null, (string)null);
AvatarStrengthScaling = Category.CreateEntry<bool>("AvatarStrengthScaling", false, "Avatar Strength Scaling", "Scale drain by the avatar's upper-body strength stat (clamped 0.70x-1.30x).", false, false, (ValueValidator)null, (string)null);
AvatarReferenceStrength = Category.CreateEntry<float>("AvatarReferenceStrength", 1f, "Avatar Reference Strength", "strengthUpper value treated as the 1.0x baseline. Enable Debug Logging to see your avatars' values.", false, false, (ValueValidator)null, (string)null);
ShowHud = Category.CreateEntry<bool>("ShowHud", true, "Show Stamina HUD", "World-space stamina bar shown while climbing/recovering.", false, false, (ValueValidator)null, (string)null);
HapticsEnabled = Category.CreateEntry<bool>("HapticsEnabled", true, "Haptic Feedback", "Pulse the gripping hands' controllers as stamina runs low.", false, false, (ValueValidator)null, (string)null);
HapticStrength = Category.CreateEntry<float>("HapticStrength", 1f, "Haptic Strength", "Multiplier on haptic pulse strength (0 = silent, 1 = default).", false, false, (ValueValidator)null, (string)null);
PanicGrabEnabled = Category.CreateEntry<bool>("PanicGrabEnabled", true, "Panic Grab", "Catching a climbable surface mid-fall costs stamina and briefly drains faster.", false, false, (ValueValidator)null, (string)null);
PanicFallSpeed = Category.CreateEntry<float>("PanicFallSpeed", 4f, "Panic Fall Speed", "Downward speed (m/s) a fall must reach for a grab to count as a panic grab.", false, false, (ValueValidator)null, (string)null);
PanicStaminaCost = Category.CreateEntry<float>("PanicStaminaCost", 20f, "Panic Stamina Cost %", "Stamina lost instantly on a panic grab, as a percent of max.", false, false, (ValueValidator)null, (string)null);
DebugLogging = Category.CreateEntry<bool>("DebugLogging", false, "Debug Logging", "Verbose state logging for troubleshooting.", false, false, (ValueValidator)null, (string)null);
}
internal static void Save()
{
MelonPreferences.Save();
}
}
internal static class SettingsMenu
{
internal static void Setup()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_0264: Unknown result type (might be due to invalid IL or missing references)
//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0321: Unknown result type (might be due to invalid IL or missing references)
//IL_035b: Unknown result type (might be due to invalid IL or missing references)
//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
//IL_03de: Unknown result type (might be due to invalid IL or missing references)
//IL_0427: Unknown result type (might be due to invalid IL or missing references)
//IL_046f: Unknown result type (might be due to invalid IL or missing references)
Page obj = Page.Root.CreatePage("Climb Stamina", new Color(0.35f, 0.75f, 1f), 0, true);
obj.CreateBool("Enabled", Color.white, Prefs.Enabled.Value, (Action<bool>)delegate(bool v)
{
Prefs.Enabled.Value = v;
Prefs.Save();
});
obj.CreateFloat("Max Stamina", Color.white, Prefs.MaxStamina.Value, 10f, 20f, 300f, (Action<float>)delegate(float v)
{
Prefs.MaxStamina.Value = v;
Prefs.Save();
});
obj.CreateFloat("One-Hand Drain Rate", Color.white, Prefs.OneHandDrainRate.Value, 1f, 0f, 60f, (Action<float>)delegate(float v)
{
Prefs.OneHandDrainRate.Value = v;
Prefs.Save();
});
obj.CreateFloat("Two-Hand Drain Rate", Color.white, Prefs.TwoHandDrainRate.Value, 1f, 0f, 60f, (Action<float>)delegate(float v)
{
Prefs.TwoHandDrainRate.Value = v;
Prefs.Save();
});
obj.CreateFloat("Ascending Multiplier", Color.white, Prefs.AscendingMultiplier.Value, 0.05f, 1f, 3f, (Action<float>)delegate(float v)
{
Prefs.AscendingMultiplier.Value = v;
Prefs.Save();
});
obj.CreateFloat("Grounded Regen Rate", Color.white, Prefs.GroundedRegenRate.Value, 1f, 0f, 100f, (Action<float>)delegate(float v)
{
Prefs.GroundedRegenRate.Value = v;
Prefs.Save();
});
obj.CreateFloat("Airborne Regen Rate", Color.white, Prefs.AirborneRegenRate.Value, 1f, 0f, 100f, (Action<float>)delegate(float v)
{
Prefs.AirborneRegenRate.Value = v;
Prefs.Save();
});
obj.CreateFloat("Recovery Delay", Color.white, Prefs.RecoveryDelay.Value, 0.25f, 0f, 10f, (Action<float>)delegate(float v)
{
Prefs.RecoveryDelay.Value = v;
Prefs.Save();
});
obj.CreateFloat("Regrab Stamina %", Color.white, Prefs.MinRegrabStamina.Value, 5f, 0f, 100f, (Action<float>)delegate(float v)
{
Prefs.MinRegrabStamina.Value = v;
Prefs.Save();
});
obj.CreateBool("Avatar Strength Scaling", Color.white, Prefs.AvatarStrengthScaling.Value, (Action<bool>)delegate(bool v)
{
Prefs.AvatarStrengthScaling.Value = v;
Prefs.Save();
PlayerTracker.RefreshAvatarMultiplier();
});
obj.CreateBool("Show Stamina HUD", Color.white, Prefs.ShowHud.Value, (Action<bool>)delegate(bool v)
{
Prefs.ShowHud.Value = v;
Prefs.Save();
});
obj.CreateBool("Haptic Feedback", Color.white, Prefs.HapticsEnabled.Value, (Action<bool>)delegate(bool v)
{
Prefs.HapticsEnabled.Value = v;
Prefs.Save();
});
obj.CreateFloat("Haptic Strength", Color.white, Prefs.HapticStrength.Value, 0.1f, 0f, 2f, (Action<float>)delegate(float v)
{
Prefs.HapticStrength.Value = v;
Prefs.Save();
});
obj.CreateBool("Panic Grab", Color.white, Prefs.PanicGrabEnabled.Value, (Action<bool>)delegate(bool v)
{
Prefs.PanicGrabEnabled.Value = v;
Prefs.Save();
});
obj.CreateFloat("Panic Fall Speed", Color.white, Prefs.PanicFallSpeed.Value, 0.5f, 1f, 12f, (Action<float>)delegate(float v)
{
Prefs.PanicFallSpeed.Value = v;
Prefs.Save();
});
obj.CreateFloat("Panic Stamina Cost %", Color.white, Prefs.PanicStaminaCost.Value, 5f, 0f, 60f, (Action<float>)delegate(float v)
{
Prefs.PanicStaminaCost.Value = v;
Prefs.Save();
});
obj.CreateBool("Debug Logging", Color.white, Prefs.DebugLogging.Value, (Action<bool>)delegate(bool v)
{
Prefs.DebugLogging.Value = v;
Prefs.Save();
});
}
}
internal enum StaminaState
{
READY,
CLIMBING_ONE_HAND,
CLIMBING_TWO_HANDS,
RECOVERY_DELAY,
RECOVERING,
EXHAUSTED
}
internal sealed class StaminaController
{
private const float AscendDeadZone = 0.3f;
private const float AscendSmoothingRate = 8f;
internal const float LowStaminaFraction = 0.25f;
private const float LowStaminaRearmFraction = 0.3f;
private const float PanicDrainWindowSeconds = 1f;
private const float PanicDrainMultiplier = 1.75f;
private readonly ClimbDetector _detector;
private readonly GripController _grips;
private float _stamina;
private float _timeSinceDrain = float.MaxValue;
private float _smoothedVerticalVelocity;
private bool _wasSupporting;
private float _panicDrainRemaining;
internal Action OnExhausted;
internal Action OnLowStamina;
private bool _lowStaminaSignaled;
internal StaminaState State { get; private set; }
internal float Stamina => _stamina;
internal float MaxStamina => Mathf.Max(1f, Prefs.MaxStamina.Value);
internal float Fraction => Mathf.Clamp01(_stamina / MaxStamina);
internal bool IsExhausted => State == StaminaState.EXHAUSTED;
internal StaminaController(ClimbDetector detector, GripController grips)
{
_detector = detector;
_grips = grips;
_stamina = MaxStamina;
_detector.CanStartClimb = () => !IsExhausted;
}
internal void ResetFull()
{
_stamina = MaxStamina;
_timeSinceDrain = float.MaxValue;
_smoothedVerticalVelocity = 0f;
_wasSupporting = false;
_panicDrainRemaining = 0f;
_lowStaminaSignaled = false;
State = StaminaState.READY;
ClimbStaminaMod.ClimbBlocked = false;
}
internal void Update(float deltaTime)
{
if (!PlayerTracker.IsValid)
{
_detector.Clear();
_grips.Clear();
_smoothedVerticalVelocity = 0f;
return;
}
_grips.ProcessQueue();
_detector.Validate();
float maxStamina = MaxStamina;
_stamina = Mathf.Min(_stamina, maxStamina);
int climbingHandCount = _detector.ClimbingHandCount;
bool isStanding = PlayerTracker.IsStanding;
bool flag = climbingHandCount > 0 && !isStanding;
if (flag != _wasSupporting)
{
if (Prefs.DebugLogging.Value && climbingHandCount > 0)
{
ClimbStaminaMod.LogDebug($"support {(flag ? "gained" : "lost")}: hands={climbingHandCount}, {PlayerTracker.DescribeGroundState()}");
}
_wasSupporting = flag;
}
UpdateAscendSmoothing(deltaTime, flag);
if (_timeSinceDrain < float.MaxValue)
{
_timeSinceDrain += deltaTime;
}
if (_panicDrainRemaining > 0f)
{
_panicDrainRemaining -= deltaTime;
}
if (State == StaminaState.EXHAUSTED)
{
GripController.SweepClimbingHands();
_detector.Clear();
Regenerate(deltaTime, isStanding);
float num = maxStamina * Mathf.Clamp01(Prefs.MinRegrabStamina.Value / 100f);
if (_timeSinceDrain >= Prefs.RecoveryDelay.Value && _stamina >= num)
{
State = StaminaState.READY;
ClimbStaminaMod.ClimbBlocked = false;
_lowStaminaSignaled = false;
ClimbStaminaMod.LogDebug($"Recovered from exhaustion at stamina={_stamina:0.0}");
}
}
else if (flag)
{
State = ((climbingHandCount < 2) ? StaminaState.CLIMBING_ONE_HAND : StaminaState.CLIMBING_TWO_HANDS);
float num2 = ((climbingHandCount >= 2) ? Prefs.TwoHandDrainRate.Value : Prefs.OneHandDrainRate.Value);
if (_smoothedVerticalVelocity > 0.3f)
{
num2 *= Mathf.Max(1f, Prefs.AscendingMultiplier.Value);
}
num2 *= PlayerTracker.AvatarDrainMultiplier;
if (_panicDrainRemaining > 0f)
{
num2 *= 1.75f;
}
_stamina -= Mathf.Max(0f, num2) * deltaTime;
_timeSinceDrain = 0f;
if (!_lowStaminaSignaled && Fraction < 0.25f)
{
_lowStaminaSignaled = true;
OnLowStamina?.Invoke();
}
if (_stamina <= 0f)
{
_stamina = 0f;
Exhaust(deferRelease: false);
}
}
else if (_stamina >= maxStamina)
{
State = StaminaState.READY;
_lowStaminaSignaled = false;
}
else if (_timeSinceDrain < Prefs.RecoveryDelay.Value)
{
State = StaminaState.RECOVERY_DELAY;
}
else
{
State = StaminaState.RECOVERING;
Regenerate(deltaTime, isStanding);
if (_lowStaminaSignaled && Fraction >= 0.3f)
{
_lowStaminaSignaled = false;
}
if (_stamina >= maxStamina)
{
_stamina = maxStamina;
State = StaminaState.READY;
_lowStaminaSignaled = false;
}
}
}
internal void ApplyPanicGrab()
{
float num = MaxStamina * Mathf.Clamp01(Prefs.PanicStaminaCost.Value / 100f);
_stamina -= num;
_timeSinceDrain = 0f;
_panicDrainRemaining = 1f;
if (_stamina <= 0f)
{
_stamina = 0f;
Exhaust(deferRelease: true);
}
}
private void Regenerate(float deltaTime, bool standing)
{
if (!(_timeSinceDrain < Prefs.RecoveryDelay.Value))
{
float num = (standing ? Prefs.GroundedRegenRate.Value : Prefs.AirborneRegenRate.Value);
_stamina = Mathf.Min(MaxStamina, _stamina + Mathf.Max(0f, num) * deltaTime);
}
}
private void UpdateAscendSmoothing(float deltaTime, bool supporting)
{
if (!supporting)
{
_smoothedVerticalVelocity = 0f;
return;
}
float verticalVelocity = PlayerTracker.VerticalVelocity;
float num = 1f - Mathf.Exp(-8f * deltaTime);
_smoothedVerticalVelocity = Mathf.Lerp(_smoothedVerticalVelocity, verticalVelocity, num);
}
private void Exhaust(bool deferRelease)
{
State = StaminaState.EXHAUSTED;
ClimbStaminaMod.ClimbBlocked = true;
_timeSinceDrain = 0f;
if (deferRelease)
{
_detector.ForEachClimbingHand(_grips.QueueDetach);
}
else
{
_detector.ForEachClimbingHand(GripController.ReleaseClimbingHand);
}
_detector.Clear();
ClimbStaminaMod.LogDebug("Stamina exhausted; climbing grips released");
OnExhausted?.Invoke();
}
}
internal sealed class StaminaHud
{
private const float FollowDistance = 0.72f;
private const float FollowDrop = 0.16f;
private const float FollowRate = 5f;
private const float FadeRate = 7f;
private const float FullLingerSeconds = 1.2f;
private const float WallClearance = 0.06f;
private const float MinFollowDistance = 0.1f;
private const float AbsoluteMinDistance = 0.055f;
private const float BaseScale = 0.00075f;
private const float SnapDistance = 2.5f;
private const float WarnFraction = 0.5f;
private static readonly float NominalDistance = Mathf.Sqrt(0.544f);
private static readonly Color BarNormal = new Color(0.55f, 0.85f, 0.55f, 1f);
private static readonly Color BarWarn = new Color(0.93f, 0.78f, 0.35f, 1f);
private static readonly Color BarLow = new Color(0.9f, 0.35f, 0.28f, 1f);
private static readonly Color BarExhausted = new Color(0.82f, 0.16f, 0.12f, 1f);
private static readonly Color LabelExhausted = new Color(1f, 0.55f, 0.5f, 1f);
private readonly string[] _percentText;
private const float MinFillFraction = 0.11f;
private GameObject _root;
private CanvasGroup _group;
private RectTransform _fillRect;
private Image _fillImage;
private TextMeshProUGUI _label;
private Texture2D _bgTexture;
private Sprite _bgSprite;
private Texture2D _fillTexture;
private Sprite _fillSprite;
private Texture2D _outlineTexture;
private Sprite _outlineSprite;
private Texture2D _glowTexture;
private Sprite _glowSprite;
private Image _glowImage;
private float _glowAlpha;
private float _alpha;
private float _fullSince = -999f;
private int _shownPercent = -1;
private bool _shownExhausted;
private float _shownFraction = -1f;
private int _shownColorBand = -1;
internal StaminaHud()
{
_percentText = new string[101];
for (int i = 0; i <= 100; i++)
{
_percentText[i] = i + "%";
}
}
internal void Drop()
{
if ((Object)(object)_root != (Object)null)
{
Object.Destroy((Object)(object)_root);
}
DestroyVisualAssets();
_root = null;
_group = null;
_fillRect = null;
_fillImage = null;
_label = null;
_glowImage = null;
_glowAlpha = 0f;
_alpha = 0f;
_shownPercent = -1;
_shownFraction = -1f;
_shownColorBand = -1;
}
private void DestroyVisualAssets()
{
if ((Object)(object)_bgSprite != (Object)null)
{
Object.Destroy((Object)(object)_bgSprite);
}
if ((Object)(object)_bgTexture != (Object)null)
{
Object.Destroy((Object)(object)_bgTexture);
}
if ((Object)(object)_fillSprite != (Object)null)
{
Object.Destroy((Object)(object)_fillSprite);
}
if ((Object)(object)_fillTexture != (Object)null)
{
Object.Destroy((Object)(object)_fillTexture);
}
if ((Object)(object)_outlineSprite != (Object)null)
{
Object.Destroy((Object)(object)_outlineSprite);
}
if ((Object)(object)_outlineTexture != (Object)null)
{
Object.Destroy((Object)(object)_outlineTexture);
}
if ((Object)(object)_glowSprite != (Object)null)
{
Object.Destroy((Object)(object)_glowSprite);
}
if ((Object)(object)_glowTexture != (Object)null)
{
Object.Destroy((Object)(object)_glowTexture);
}
_bgSprite = null;
_bgTexture = null;
_fillSprite = null;
_fillTexture = null;
_outlineSprite = null;
_outlineTexture = null;
_glowSprite = null;
_glowTexture = null;
}
internal void Update(StaminaController stamina, float deltaTime)
{
bool flag = ComputeVisibility(stamina);
if ((Object)(object)_root == (Object)null)
{
if (!flag || !PlayerTracker.IsValid || !Build())
{
return;
}
SnapToTarget();
}
float num = (flag ? 1f : 0f);
_alpha = Mathf.Lerp(_alpha, num, 1f - Mathf.Exp(-7f * deltaTime));
if (_alpha < 0.01f && !flag)
{
if (_root.activeSelf)
{
_root.SetActive(false);
}
return;
}
if (!_root.activeSelf)
{
_root.SetActive(true);
SnapToTarget();
}
_group.alpha = _alpha;
Follow(deltaTime);
Refresh(stamina, deltaTime);
}
private bool ComputeVisibility(StaminaController stamina)
{
if (!Prefs.ShowHud.Value || !PlayerTracker.IsValid)
{
return false;
}
if (stamina.Fraction < 1f || stamina.IsExhausted)
{
_fullSince = Time.time;
return true;
}
return Time.time - _fullSince < 1.2f;
}
private void Refresh(StaminaController stamina, float deltaTime)
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_0249: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_0199: Unknown result type (might be due to invalid IL or missing references)
//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
float fraction = stamina.Fraction;
if (fraction <= 0.001f)
{
if (((Behaviour)_fillImage).enabled)
{
((Behaviour)_fillImage).enabled = false;
}
}
else
{
if (!((Behaviour)_fillImage).enabled)
{
((Behaviour)_fillImage).enabled = true;
}
if (fraction != _shownFraction)
{
_shownFraction = fraction;
_fillRect.anchorMax = new Vector2(Mathf.Max(fraction, 0.11f), 1f);
}
}
bool isExhausted = stamina.IsExhausted;
int num;
Color color;
if (isExhausted)
{
num = 3;
color = BarExhausted;
}
else if (fraction < 0.25f)
{
num = 2;
color = BarLow;
}
else if (fraction < 0.5f)
{
num = 1;
color = BarWarn;
}
else
{
num = 0;
color = BarNormal;
}
if (num != _shownColorBand)
{
_shownColorBand = num;
((Graphic)_fillImage).color = color;
}
if ((Object)(object)_glowImage != (Object)null)
{
float num2 = ((isExhausted || fraction < 0.25f) ? (0.45f + 0.25f * Mathf.Sin(Time.time * 5f)) : 0f);
_glowAlpha = Mathf.Lerp(_glowAlpha, num2, 1f - Mathf.Exp(-6f * deltaTime));
if (_glowAlpha < 0.01f)
{
if (((Behaviour)_glowImage).enabled)
{
((Behaviour)_glowImage).enabled = false;
}
}
else
{
if (!((Behaviour)_glowImage).enabled)
{
((Behaviour)_glowImage).enabled = true;
}
Color val = (isExhausted ? BarExhausted : BarLow);
((Graphic)_glowImage).color = new Color(val.r, val.g, val.b, _glowAlpha);
}
}
if ((Object)(object)_label == (Object)null)
{
return;
}
if (isExhausted)
{
if (!_shownExhausted)
{
_shownExhausted = true;
_shownPercent = -1;
((TMP_Text)_label).text = "EXHAUSTED";
((Graphic)_label).color = LabelExhausted;
}
return;
}
_shownExhausted = false;
int num3 = Mathf.Clamp(Mathf.RoundToInt(fraction * 100f), 0, 100);
if (num3 != _shownPercent)
{
_shownPercent = num3;
((TMP_Text)_label).text = _percentText[num3];
((Graphic)_label).color = Color.white;
}
}
internal void FlashPanic()
{
_glowAlpha = Mathf.Max(_glowAlpha, 0.85f);
}
private void Follow(float deltaTime)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: 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_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
Transform head = Player.Head;
if ((Object)(object)head == (Object)null)
{
return;
}
Vector3 val = TargetPosition(head);
Transform transform = _root.transform;
Vector3 val2 = transform.position - val;
if (((Vector3)(ref val2)).sqrMagnitude > 6.25f)
{
transform.position = val;
Vector3 val3 = val - head.position;
if (((Vector3)(ref val3)).sqrMagnitude > 1E-06f)
{
transform.rotation = Quaternion.LookRotation(val3, Vector3.up);
}
ApplyDistanceScale(((Vector3)(ref val3)).magnitude);
return;
}
float num = 1f - Mathf.Exp(-5f * deltaTime);
Vector3 val4 = Vector3.Lerp(transform.position, val, num);
Vector3 val5 = val4 - head.position;
float num2 = ((Vector3)(ref val5)).magnitude;
if (num2 > 0.001f)
{
Vector3 val6 = val5 / num2;
float num3 = ClampToGeometry(head.position, val6, num2);
if (num3 < num2)
{
num2 = num3;
val4 = head.position + val6 * num2;
}
}
transform.position = val4;
Vector3 val7 = val4 - head.position;
if (((Vector3)(ref val7)).sqrMagnitude > 1E-06f)
{
Quaternion val8 = Quaternion.LookRotation(val7, Vector3.up);
transform.rotation = Quaternion.Slerp(transform.rotation, val8, num);
}
ApplyDistanceScale(num2);
}
private void SnapToTarget()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
Transform head = Player.Head;
if (!((Object)(object)head == (Object)null) && !((Object)(object)_root == (Object)null))
{
Vector3 val = TargetPosition(head);
_root.transform.position = val;
_root.transform.rotation = Quaternion.LookRotation(val - head.position, Vector3.up);
Vector3 val2 = val - head.position;
ApplyDistanceScale(((Vector3)(ref val2)).magnitude);
}
}
private static Vector3 TargetPosition(Transform head)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//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_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: 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)
Vector3 forward = head.forward;
forward.y = 0f;
if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
{
forward = Vector3.forward;
}
((Vector3)(ref forward)).Normalize();
Vector3 val = (forward * 0.72f + Vector3.down * 0.16f) / NominalDistance;
float num = ClampToGeometry(head.position, val, NominalDistance);
return head.position + val * num;
}
private static float ClampToGeometry(Vector3 origin, Vector3 dir, float desired)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
RaycastHit val = default(RaycastHit);
if (!Physics.Raycast(origin, dir, ref val, desired + 0.06f, -5, (QueryTriggerInteraction)1))
{
return desired;
}
Collider collider = ((RaycastHit)(ref val)).collider;
if ((Object)(object)collider == (Object)null || (Object)(object)collider.attachedRigidbody != (Object)null)
{
return desired;
}
float num = ((RaycastHit)(ref val)).distance - 0.06f;
if (num >= 0.1f)
{
return Mathf.Min(num, desired);
}
return Mathf.Max(((RaycastHit)(ref val)).distance * 0.75f, 0.055f);
}
private void ApplyDistanceScale(float distance)
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
float num = 0.00075f * Mathf.Clamp(distance / NominalDistance, 0.05f, 1f);
_root.transform.localScale = new Vector3(num, num, num);
}
private bool Build()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Expected O, but got Unknown
//IL_0206: Unknown result type (might be due to invalid IL or missing references)
//IL_0223: Unknown result type (might be due to invalid IL or missing references)
//IL_022e: Unknown result type (might be due to invalid IL or missing references)
//IL_0239: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Unknown result type (might be due to invalid IL or missing references)
//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
//IL_02f1: Expected O, but got Unknown
//IL_031a: Unknown result type (might be due to invalid IL or missing references)
//IL_0263: Unknown result type (might be due to invalid IL or missing references)
//IL_0268: Unknown result type (might be due to invalid IL or missing references)
//IL_027f: Unknown result type (might be due to invalid IL or missing references)
//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
//IL_0361: Unknown result type (might be due to invalid IL or missing references)
//IL_0371: Unknown result type (might be due to invalid IL or missing references)
//IL_038b: Unknown result type (might be due to invalid IL or missing references)
//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
//IL_03f7: Expected O, but got Unknown
//IL_046c: Unknown result type (might be due to invalid IL or missing references)
//IL_0477: Unknown result type (might be due to invalid IL or missing references)
//IL_0482: Unknown result type (might be due to invalid IL or missing references)
//IL_048c: Unknown result type (might be due to invalid IL or missing references)
DestroyVisualAssets();
_root = new GameObject("ClimbStamina_HUD");
Canvas obj = _root.AddComponent<Canvas>();
obj.renderMode = (RenderMode)2;
obj.sortingOrder = 100;
_group = _root.AddComponent<CanvasGroup>();
_group.interactable = false;
_group.blocksRaycasts = false;
_group.alpha = 0f;
RectTransform component = _root.GetComponent<RectTransform>();
component.sizeDelta = new Vector2(276f, 36f);
((Transform)component).localScale = new Vector3(0.00075f, 0.00075f, 0.00075f);
_bgSprite = CreateRoundedSprite(10, out _bgTexture);
_fillSprite = CreateRoundedSprite(8, out _fillTexture);
_outlineSprite = CreateRoundedOutlineSprite(10, 1.5f, soft: false, out _outlineTexture);
_glowSprite = CreateRoundedOutlineSprite(10, 8f, soft: true, out _glowTexture);
GameObject val = new GameObject("Background");
val.transform.SetParent(_root.transform, false);
Image val2 = val.AddComponent<Image>();
((Graphic)val2).color = new Color(0f, 0f, 0f, 0.55f);
if ((Object)(object)_bgSprite != (Object)null)
{
val2.sprite = _bgSprite;
val2.type = (Type)1;
}
RectTransform component2 = val.GetComponent<RectTransform>();
component2.anchorMin = Vector2.zero;
component2.anchorMax = Vector2.one;
component2.offsetMin = Vector2.zero;
component2.offsetMax = Vector2.zero;
if ((Object)(object)_glowSprite != (Object)null)
{
GameObject val3 = new GameObject("Glow");
val3.transform.SetParent(_root.transform, false);
_glowImage = val3.AddComponent<Image>();
_glowImage.sprite = _glowSprite;
_glowImage.type = (Type)1;
((Graphic)_glowImage).color = new Color(0f, 0f, 0f, 0f);
((Behaviour)_glowImage).enabled = false;
RectTransform component3 = val3.GetComponent<RectTransform>();
component3.anchorMin = Vector2.zero;
component3.anchorMax = Vector2.one;
component3.offsetMin = Vector2.zero;
component3.offsetMax = Vector2.zero;
}
if ((Object)(object)_outlineSprite != (Object)null)
{
GameObject val4 = new GameObject("Outline");
val4.transform.SetParent(_root.transform, false);
Image obj2 = val4.AddComponent<Image>();
obj2.sprite = _outlineSprite;
obj2.type = (Type)1;
((Graphic)obj2).color = new Color(0.38f, 0.38f, 0.38f, 0.85f);
RectTransform component4 = val4.GetComponent<RectTransform>();
component4.anchorMin = Vector2.zero;
component4.anchorMax = Vector2.one;
component4.offsetMin = Vector2.zero;
component4.offsetMax = Vector2.zero;
}
GameObject val5 = new GameObject("Fill");
val5.transform.SetParent(_root.transform, false);
_fillImage = val5.AddComponent<Image>();
((Graphic)_fillImage).color = BarNormal;
if ((Object)(object)_fillSprite != (Object)null)
{
_fillImage.sprite = _fillSprite;
_fillImage.type = (Type)1;
}
_fillRect = val5.GetComponent<RectTransform>();
_fillRect.anchorMin = Vector2.zero;
_fillRect.anchorMax = Vector2.one;
_fillRect.pivot = new Vector2(0f, 0.5f);
_fillRect.offsetMin = new Vector2(4f, 4f);
_fillRect.offsetMax = new Vector2(-4f, -4f);
((Transform)_fillRect).localScale = Vector3.one;
TMP_FontAsset val6 = ResolveFont();
if ((Object)(object)val6 != (Object)null)
{
GameObject val7 = new GameObject("Label");
val7.transform.SetParent(_root.transform, false);
_label = val7.AddComponent<TextMeshProUGUI>();
((TMP_Text)_label).font = val6;
((TMP_Text)_label).fontSize = 20f;
((TMP_Text)_label).alignment = (TextAlignmentOptions)514;
((TMP_Text)_label).enableWordWrapping = false;
((TMP_Text)_label).text = string.Empty;
RectTransform component5 = val7.GetComponent<RectTransform>();
component5.anchorMin = Vector2.zero;
component5.anchorMax = Vector2.one;
component5.offsetMin = Vector2.zero;
component5.offsetMax = Vector2.zero;
}
else
{
ClimbStaminaMod.LogDebug("No TMP font asset found; HUD runs bar-only");
}
_shownPercent = -1;
_shownExhausted = false;
_shownFraction = -1f;
_shownColorBand = -1;
return true;
}
private static Sprite CreateRoundedSprite(int radius, out Texture2D texture)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Expected O, but got Unknown
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
texture = null;
try
{
int num = radius * 2 + 6;
texture = new Texture2D(num, num, (TextureFormat)4, false);
((Texture)texture).wrapMode = (TextureWrapMode)1;
((Texture)texture).filterMode = (FilterMode)1;
Color32[] array = (Color32[])(object)new Color32[num * num];
float num2 = (float)num * 0.5f;
float num3 = num2 - (float)radius;
for (int i = 0; i < num; i++)
{
for (int j = 0; j < num; j++)
{
float num4 = Mathf.Max(Mathf.Abs((float)j + 0.5f - num2) - num3, 0f);
float num5 = Mathf.Max(Mathf.Abs((float)i + 0.5f - num2) - num3, 0f);
float num6 = Mathf.Sqrt(num4 * num4 + num5 * num5) - ((float)radius - 0.5f);
float num7 = Mathf.Clamp01(0.5f - num6);
array[i * num + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(num7 * 255f));
}
}
texture.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(array));
texture.Apply(false, true);
float num8 = (float)radius + 2f;
return Sprite.Create(texture, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(num8, num8, num8, num8));
}
catch (Exception ex)
{
ClimbStaminaMod.LogDebug("Rounded sprite creation failed (" + ex.GetType().Name + "); HUD keeps square corners");
if ((Object)(object)texture != (Object)null)
{
Object.Destroy((Object)(object)texture);
}
texture = null;
return null;
}
}
private static Sprite CreateRoundedOutlineSprite(int radius, float thickness, bool soft, out Texture2D texture)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
//IL_018e: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
texture = null;
try
{
int num = Mathf.CeilToInt(thickness * 0.5f + 1.5f);
int num2 = radius * 2 + num * 2 + 4;
texture = new Texture2D(num2, num2, (TextureFormat)4, false);
((Texture)texture).wrapMode = (TextureWrapMode)1;
((Texture)texture).filterMode = (FilterMode)1;
Color32[] array = (Color32[])(object)new Color32[num2 * num2];
float num3 = (float)num2 * 0.5f;
float num4 = num3 - (float)num - (float)radius;
for (int i = 0; i < num2; i++)
{
for (int j = 0; j < num2; j++)
{
float num5 = Mathf.Max(Mathf.Abs((float)j + 0.5f - num3) - num4, 0f);
float num6 = Mathf.Max(Mathf.Abs((float)i + 0.5f - num3) - num4, 0f);
float num7 = Mathf.Abs(Mathf.Sqrt(num5 * num5 + num6 * num6) - (float)radius);
float num8;
if (soft)
{
num8 = Mathf.Clamp01(1f - num7 / (thickness * 0.5f));
num8 *= num8;
}
else
{
num8 = Mathf.Clamp01(thickness * 0.5f + 0.5f - num7);
}
array[i * num2 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)(num8 * 255f));
}
}
texture.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(array));
texture.Apply(false, true);
float num9 = (float)(radius + num) + 1f;
return Sprite.Create(texture, new Rect(0f, 0f, (float)num2, (float)num2), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(num9, num9, num9, num9));
}
catch (Exception ex)
{
ClimbStaminaMod.LogDebug("Outline sprite creation failed (" + ex.GetType().Name + "); HUD runs without an outline");
if ((Object)(object)texture != (Object)null)
{
Object.Destroy((Object)(object)texture);
}
texture = null;
return null;
}
}
private static TMP_FontAsset ResolveFont()
{
TMP_FontAsset defaultFontAsset = TMP_Settings.defaultFontAsset;
if ((Object)(object)defaultFontAsset != (Object)null)
{
return defaultFontAsset;
}
Il2CppReferenceArray<Object> val = Resources.FindObjectsOfTypeAll(Il2CppType.Of<TMP_FontAsset>());
if (val != null && ((Il2CppArrayBase<Object>)(object)val).Length > 0)
{
return ((Il2CppObjectBase)((Il2CppArrayBase<Object>)(object)val)[0]).TryCast<TMP_FontAsset>();
}
return null;
}
}
}
namespace ClimbStamina.Compatibility
{
internal static class ClimbAnythingCompatibility
{
internal static bool ClimbAnythingDetected { get; private set; }
internal static void Detect()
{
foreach (MelonBase registeredMelon in MelonBase.RegisteredMelons)
{
MelonInfoAttribute info = registeredMelon.Info;
string text = ((info != null) ? info.Name : null);
if (text != null && text.Replace(" ", "").ToLowerInvariant().Contains("climbanything"))
{
ClimbAnythingDetected = true;
ClimbStaminaMod.Log("'" + text + "' detected; its climbing grips are covered by stamina rules automatically.");
break;
}
}
}
}
internal static class FusionCompatibility
{
internal static bool FusionDetected { get; private set; }
internal static void Detect()
{
FusionDetected = MelonBase.FindMelon("LabFusion", "Lakatrazz") != null;
if (FusionDetected)
{
ClimbStaminaMod.Log("Fusion detected; local-only mode enabled.");
}
}
}
}