using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using AK; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using CellMenu; using GameData; using Gear; using HarmonyLib; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Microsoft.CodeAnalysis; using Player; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("Zose_ReloadTimerPlus")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Zose_ReloadTimerPlus")] [assembly: AssemblyTitle("Zose_ReloadTimerPlus")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace Zose_ReloadTimerPlus { public static class PluginData { public const string GUID = "Zose_ReloadTimerPlus"; public const string Name = "Zose_ReloadTimerPlus"; public const string Version = "1.6.0"; } public enum ReloadSoundOption { None, HACKING_PUZZLE_CORRECT, BUTTONGENERICBLIPCONFIRM, BUTTONGENERICSEQUENCEDONE, HUD_TIMER_RUSH, CustomLocalFile } [BepInPlugin("Zose_ReloadTimerPlus", "Zose_ReloadTimerPlus", "1.6.0")] public class EntryPoint : BasePlugin { public static EntryPoint? Instance; public static ConfigEntry? ConfigOffset; public static ConfigEntry? ConfigChargeColor; public static ConfigEntry? ConfigLowAmmoThreshold; public static ConfigEntry? ConfigLowAmmoColor; public static ConfigEntry? ConfigReloadSoundCue; public static ConfigEntry? ConfigCustomSoundFileName; public static ConfigEntry? ConfigEnableChargeCircleEffects; public static ConfigEntry? ConfigEnableLowAmmoWarning; public static Color ParsedChargeColor = new Color(0f, 1f, 0f, 0.8f); public static Color ParsedLowAmmoColor = new Color(1f, 0f, 0f, 0.8f); public static bool NeedsConfigReload = false; private static Harmony? harmony; private static FileSystemWatcher? _configWatcher; public override void Load() { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown Instance = this; ClassInjector.RegisterTypeInIl2Cpp(); ConfigOffset = ((BasePlugin)this).Config.Bind("Settings", "TextOffset", 85f, "Vertical offset of the reload text from the crosshair."); ConfigOffset.SettingChanged += delegate { Zose_ReloadTimerPlus.Instance?.UpdateUIPosition(); }; ConfigChargeColor = ((BasePlugin)this).Config.Bind("Settings", "ChargeColor", "#00FF0080", "Color of the reload charge circle in Hex format (#RRGGBBAA)."); ConfigEnableChargeCircleEffects = ((BasePlugin)this).Config.Bind("Settings", "EnableChargeCircleEffects", true, "Enable the reload charge circle progress, ready effects, and text timer."); ConfigEnableLowAmmoWarning = ((BasePlugin)this).Config.Bind("AmmoWarning", "EnableLowAmmoWarning", true, "Enable the low ammo 'RELOAD' warning text."); ConfigLowAmmoThreshold = ((BasePlugin)this).Config.Bind("AmmoWarning", "LowAmmoThreshold", 0.35f, "Ammo threshold (0.0-1.0) for warning."); ConfigLowAmmoColor = ((BasePlugin)this).Config.Bind("AmmoWarning", "LowAmmoColor", "#FF000080", "Color of the 'RELOAD' warning text in Hex format (#RRGGBBAA)."); ConfigReloadSoundCue = ((BasePlugin)this).Config.Bind("Sound", "ReloadSoundCue", ReloadSoundOption.HACKING_PUZZLE_CORRECT, "Sound event name to play on reload complete. Select 'None' to disable. Select 'CustomLocalFile' to use a local audio file."); ConfigCustomSoundFileName = ((BasePlugin)this).Config.Bind("Sound", "CustomSoundFileName", "custom_reload.wav", "The name of the audio file (.wav/.ogg) to play when ReloadSoundCue is set to CustomLocalFile.\nPlace this file inside the 'BepInEx/config/Zose_ReloadTimerPlus' folder."); UpdateParsedColor(); ConfigChargeColor.SettingChanged += delegate { UpdateParsedColor(); }; ConfigLowAmmoColor.SettingChanged += delegate { UpdateParsedColor(); }; SetupConfigWatcher(); harmony = new Harmony("Zose_ReloadTimerPlus"); harmony.PatchAll(); Zose_ReloadTimerPlus.LoadCache(); Logger.Info("Zose_ReloadTimerPlus 1.6.0 loaded."); } public void ReloadConfig() { ((BasePlugin)this).Config.Reload(); UpdateParsedColor(); SoundHelper.InvalidateCache(); Logger.Info("Config reloaded from disk."); } private void UpdateParsedColor() { //IL_0021: 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_0048: 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) Color parsedChargeColor = default(Color); if (ConfigChargeColor != null && ColorUtility.TryParseHtmlString(ConfigChargeColor.Value, ref parsedChargeColor)) { ParsedChargeColor = parsedChargeColor; } Color parsedLowAmmoColor = default(Color); if (ConfigLowAmmoColor != null && ColorUtility.TryParseHtmlString(ConfigLowAmmoColor.Value, ref parsedLowAmmoColor)) { ParsedLowAmmoColor = parsedLowAmmoColor; } } private void SetupConfigWatcher() { try { _configWatcher = new FileSystemWatcher(Path.GetDirectoryName(((BasePlugin)this).Config.ConfigFilePath), Path.GetFileName(((BasePlugin)this).Config.ConfigFilePath)); _configWatcher.NotifyFilter = NotifyFilters.LastWrite; _configWatcher.Changed += delegate { NeedsConfigReload = true; }; _configWatcher.EnableRaisingEvents = true; } catch (Exception ex) { Logger.Error("Failed to setup ConfigWatcher: " + ex.Message); } } } internal static class Logger { private static readonly ManualLogSource _Logger; static Logger() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown _Logger = new ManualLogSource("Zose_ReloadTimerPlus"); Logger.Sources.Add((ILogSource)(object)_Logger); } public static void Info(string str) { _Logger.LogMessage((object)str); } public static void Info(object data) { _Logger.LogMessage((object)data?.ToString()); } public static void Debug(string str) { _Logger.LogDebug((object)str); } public static void Debug(object data) { _Logger.LogDebug((object)data?.ToString()); } public static void Error(string str) { _Logger.LogError((object)str); } public static void Error(object data) { _Logger.LogError((object)data?.ToString()); } public static void Fatal(string str) { _Logger.LogFatal((object)str); } public static void Fatal(object data) { _Logger.LogFatal((object)data?.ToString()); } public static void Warn(string str) { _Logger.LogWarning((object)str); } public static void Warn(object data) { _Logger.LogWarning((object)data?.ToString()); } } public class Zose_ReloadTimerPlus : MonoBehaviour { private TextMeshProUGUI _textMesh = null; private TextMeshProUGUI _glitchTextMesh2 = null; private GameObject _uiRoot = null; public static Zose_ReloadTimerPlus Instance; private bool _isReloading = false; private float _reloadStartTime = 0f; private float _lastReloadDuration = 0f; private string _currentWeaponName = ""; private int _lastClipCount = -1; private AudioSource? _audioSource; private AudioClip? _customClip; private string _lastLoadedFileName = ""; private static Dictionary _persistentRatioMap = new Dictionary(); private string _currFingerprint = ""; private bool _ammoFilledThisReload = false; private bool _isStutteringDuringReload = false; private float _readyEffectStartTime = -1f; private bool _hasTriggeredReadyEffect = false; private bool _isAnimatingReady = false; private bool _waitingForNativeReloadToEnd = false; private bool _isChargeWeapon = false; private float _lastGlitchTime = 0f; private string _currGlitchedText = ""; private const string GLITCH_CHARS = "#@&!$%01X?"; private bool _chargeShown = false; private static bool _reflectionChecked = false; private Color _originalChargeColor; private static MethodInfo? _setChargeUpVisibleAndProgressMethod; private static Il2CppObjectBase? _circleTarget; private static MethodInfo? _setChargeMethod; private static MethodInfo? _showChargeMethod; private static MethodInfo? _setChargeColorMethod; private static FieldInfo? _chargeUpColOrgField; private static FieldInfo? _isAimingField; private IntPtr _lastWieldPointer = IntPtr.Zero; private BulletWeapon? _cachedBulletWeapon; private static MethodInfo? _getIdentifierMethod; private PlayerAgent? _localPlayer; private const float MAX_SWAY_OFFSET = 12f; private const float SWAY_SENSITIVITY = 1.2f; private const float SWAY_SMOOTHING = 0.12f; private const float ADS_SWAY_MULTIPLIER = 0.25f; private Vector2 _currentSwayOffset = Vector2.zero; private Vector2 _swayVelocity = Vector2.zero; private bool _isFirstSwayFrame = true; private static string _cachePath = Path.Combine(Paths.ConfigPath, "Zose_ReloadTimerPlus_Cache.txt"); private static bool _cacheLoaded = false; private static string _cachedRundownInfo = ""; private Vector3 _lastCamForward = Vector3.one; public void Awake() { //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_005a: Expected O, but got Unknown //IL_008c: 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_009a: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) Instance = this; Logger.Info("Zose_ReloadTimerPlus INITIALIZED."); _audioSource = ((Component)this).gameObject.AddComponent(); _audioSource.playOnAwake = false; if (!_cacheLoaded) { LoadCache(); } _uiRoot = new GameObject("ReloadTimer") { layer = 5 }; _uiRoot.transform.SetParent(((Component)GuiManager.CrosshairLayer.m_circleCrosshair).transform.parent, false); UpdateUIPosition(); GameObject val = new GameObject("MainText") { layer = 5 }; val.transform.SetParent(_uiRoot.transform, false); _textMesh = SetupTextMesh(val, new Color(1f, 1f, 1f, 1f)); GameObject val2 = new GameObject("GlitchR") { layer = 5 }; val2.transform.SetParent(_uiRoot.transform, false); GameObject val3 = new GameObject("GlitchC") { layer = 5 }; val3.transform.SetParent(_uiRoot.transform, false); _glitchTextMesh2 = SetupTextMesh(val3, new Color(1f, 1f, 1f, 0f)); } public string GetWeaponFingerprint(BulletWeapon weapon) { if ((Object)(object)weapon == (Object)null) { return ""; } if (string.IsNullOrEmpty(_cachedRundownInfo) || _cachedRundownInfo == "RD_UNK") { _cachedRundownInfo = ""; try { Type typeFromHandle = typeof(RundownManager); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; string[] array = new string[3] { "CurrentlySelectedRundownKey", "ActiveRundownData", "m_activeRundownKey" }; string[] array2 = array; foreach (string name in array2) { try { PropertyInfo property = typeFromHandle.GetProperty(name, bindingAttr); FieldInfo field = typeFromHandle.GetField(name, bindingAttr); object obj = property?.GetValue(null) ?? field?.GetValue(null); if (obj != null) { string text = ((obj is string text2) ? text2 : obj.ToString()); if (!string.IsNullOrEmpty(text) && text != "0" && !text.Contains("DataBlock")) { _cachedRundownInfo = "RD_" + text; break; } } } catch { } } if (string.IsNullOrEmpty(_cachedRundownInfo)) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string fullName = assembly.FullName; if (fullName.Contains("System") || fullName.Contains("Unity") || fullName.Contains("mscorlib") || fullName.Contains("BepInEx")) { continue; } Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (type.Name.Contains("Config") || type.Name.Contains("Rundown") || type.Name.Contains("Archive") || type.Name.Contains("Global")) { PropertyInfo[] properties = type.GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { if (!(propertyInfo.PropertyType == typeof(string)) || (!propertyInfo.Name.Contains("Rundown") && !propertyInfo.Name.Contains("SelectedKey"))) { continue; } try { string text3 = propertyInfo.GetValue(null)?.ToString(); if (!string.IsNullOrEmpty(text3) && text3.Length > 2 && !text3.Contains(" ") && !text3.Contains("/")) { _cachedRundownInfo = text3; break; } } catch { } } if (!string.IsNullOrEmpty(_cachedRundownInfo)) { break; } FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType == typeof(string)) || (!fieldInfo.Name.Contains("Rundown") && !fieldInfo.Name.Contains("ActiveKey"))) { continue; } try { string text4 = fieldInfo.GetValue(null)?.ToString(); if (!string.IsNullOrEmpty(text4) && text4.Length > 2 && !text4.Contains(" ")) { _cachedRundownInfo = text4; break; } } catch { } } } if (!string.IsNullOrEmpty(_cachedRundownInfo)) { break; } } if (!string.IsNullOrEmpty(_cachedRundownInfo)) { break; } } } catch { } } if (string.IsNullOrEmpty(_cachedRundownInfo)) { try { object obj6 = typeFromHandle.GetMethod("GetActiveRundownData", bindingAttr)?.Invoke(null, null); if (obj6 != null) { _cachedRundownInfo = (obj6.GetType().GetProperty("name") ?? obj6.GetType().GetProperty("Key"))?.GetValue(obj6)?.ToString() ?? "RD_UNK"; } } catch { } } if (string.IsNullOrEmpty(_cachedRundownInfo)) { _cachedRundownInfo = "RD_UNK"; } if (_cachedRundownInfo != "RD_UNK") { _cachedRundownInfo = Regex.Replace(_cachedRundownInfo, "[^a-zA-Z0-9_-]", ""); Logger.Info("Rundown Identified: " + _cachedRundownInfo); } } catch (Exception ex) { Logger.Error("Rundown Scan Error: " + ex.Message); } } return $"{_cachedRundownInfo}_{((GameDataBlockBase)(object)((ItemEquippable)weapon).ArchetypeData).persistentID}_{((Item)weapon).PublicName}_{((ItemEquippable)weapon).ArchetypeData.DefaultReloadTime:F2}_{((ItemEquippable)weapon).ClipSize}"; } public static void LoadCache() { if (string.IsNullOrEmpty(_cachePath)) { return; } try { if (!File.Exists(_cachePath)) { Logger.Info("No existing calibration cache found. Starting fresh."); _cacheLoaded = true; return; } string[] array = File.ReadAllLines(_cachePath); string[] array2 = array; foreach (string text in array2) { if (!string.IsNullOrWhiteSpace(text)) { string[] array3 = text.Split('='); if (array3.Length == 2 && float.TryParse(array3[1], out var result)) { _persistentRatioMap[array3[0]] = result; } } } _cacheLoaded = true; Logger.Info($"SUCCESS: Loaded {_persistentRatioMap.Count} calibrated weapon profiles from disk."); } catch (Exception ex) { Logger.Error("Cache Load Error: " + ex.Message); } } private static void SaveCache() { try { List list = new List(); foreach (KeyValuePair item in _persistentRatioMap) { list.Add($"{item.Key}={item.Value:F4}"); } File.WriteAllLines(_cachePath, list); } catch (Exception ex) { Logger.Error("Cache Save Error: " + ex.Message); } } private TextMeshProUGUI SetupTextMesh(GameObject go, Color col) { //IL_0024: 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) TextMeshProUGUI val = go.AddComponent(); ((TMP_Text)val).alignment = (TextAlignmentOptions)514; ((Component)val).GetComponent().sizeDelta = new Vector2(400f, 100f); ((TMP_Text)val).fontSize = 20f; ((TMP_Text)val).font = ((TMP_Text)GuiManager.PlayerLayer.m_playerStatus.m_healthText).font; ((Graphic)val).color = col; ((TMP_Text)val).characterSpacing = 0f; ((TMP_Text)val).richText = true; return val; } public void OnAmmoRefreshed() { if (!_isReloading || _ammoFilledThisReload) { return; } _ammoFilledThisReload = true; if (_isStutteringDuringReload) { Logger.Info("Stutter detected during reload, skipping calibration to maintain accuracy."); } else { float num = Time.time - _reloadStartTime; if (_lastReloadDuration > 0f && !string.IsNullOrEmpty(_currFingerprint)) { float num2 = Mathf.Clamp(num / _lastReloadDuration, 0.3f, 0.98f); if (!_persistentRatioMap.ContainsKey(_currFingerprint)) { _persistentRatioMap[_currFingerprint] = num2; SaveCache(); } else { float num3 = _persistentRatioMap[_currFingerprint]; if (Mathf.Abs(num2 - num3) > 0.01f) { float value = (num3 * 4f + num2) / 5f; _persistentRatioMap[_currFingerprint] = value; SaveCache(); } } } } if (!_hasTriggeredReadyEffect) { _readyEffectStartTime = Time.time; _hasTriggeredReadyEffect = true; _isAnimatingReady = true; PlayReloadCue(); } } private void Update() { //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) ConfigEntry? configReloadSoundCue = EntryPoint.ConfigReloadSoundCue; if (configReloadSoundCue != null && configReloadSoundCue.Value == ReloadSoundOption.CustomLocalFile) { string text = EntryPoint.ConfigCustomSoundFileName?.Value ?? "custom_reload.wav"; if (text != _lastLoadedFileName) { _lastLoadedFileName = text; string text2 = Path.Combine(Paths.ConfigPath, "Zose_ReloadTimerPlus"); if (!Directory.Exists(text2)) { Directory.CreateDirectory(text2); } string text3 = Path.Combine(text2, text); if (File.Exists(text3)) { Logger.Info("Loading custom WAV audio from: " + text3); try { _customClip = WavUtility.ToAudioClip(text3, text); if ((Object)(object)_customClip != (Object)null) { ((Object)_customClip).hideFlags = (HideFlags)32; Logger.Info("Successfully loaded custom WAV audio: " + text); } else { Logger.Error("Failed to parse WAV file: " + text3 + ". Ensure it is a valid RIFF/WAVE file."); } } catch (Exception ex) { Logger.Error("Error loading custom WAV audio: " + ex.Message); } } else { Logger.Error("Custom audio file not found: " + text3); } } } if (EntryPoint.NeedsConfigReload) { EntryPoint.NeedsConfigReload = false; EntryPoint.Instance?.ReloadConfig(); UpdateUIPosition(); } if ((Object)(object)_localPlayer == (Object)null) { _localPlayer = PlayerManager.GetLocalPlayerAgent(); if ((Object)(object)_localPlayer == (Object)null) { return; } } PlayerInventoryBase inventory = _localPlayer.Inventory; ItemEquippable val = ((inventory != null) ? inventory.WieldedItem : null); if ((Object)(object)val == (Object)null) { return; } if (((Il2CppObjectBase)val).Pointer != _lastWieldPointer) { _lastWieldPointer = ((Il2CppObjectBase)val).Pointer; _cachedBulletWeapon = ((Il2CppObjectBase)val).TryCast(); ResetReloadState(); if ((Object)(object)_cachedBulletWeapon != (Object)null) { _currentWeaponName = ((Item)_cachedBulletWeapon).PublicName; _currFingerprint = GetWeaponFingerprint(_cachedBulletWeapon); _lastReloadDuration = ((ItemEquippable)_cachedBulletWeapon).ArchetypeData.DefaultReloadTime * GetWeaponMultiplier(_cachedBulletWeapon); _isChargeWeapon = DetectIsChargeWeapon(_cachedBulletWeapon); } UpdateUIPosition(); } if ((Object)(object)_cachedBulletWeapon == (Object)null) { return; } if (!_reflectionChecked && GuiManager.CrosshairLayer != null) { InitializeReflection(); } bool isReloading = ((ItemEquippable)_cachedBulletWeapon).IsReloading; if (isReloading && !_isReloading && !_waitingForNativeReloadToEnd) { _isReloading = true; _ammoFilledThisReload = false; _reloadStartTime = Time.time; _currGlitchedText = string.Empty; _lastReloadDuration = ((ItemEquippable)_cachedBulletWeapon).ArchetypeData.DefaultReloadTime * GetWeaponMultiplier(_cachedBulletWeapon); bool flag = EntryPoint.ConfigEnableChargeCircleEffects?.Value ?? true; if (!_chargeShown && _circleTarget != null && flag) { if (_chargeUpColOrgField != null) { _originalChargeColor = (Color)_chargeUpColOrgField.GetValue(_circleTarget); } _setChargeColorMethod?.Invoke(_circleTarget, new object[1] { EntryPoint.ParsedChargeColor }); _chargeUpColOrgField?.SetValue(_circleTarget, EntryPoint.ParsedChargeColor); _setChargeUpVisibleAndProgressMethod?.Invoke(GuiManager.CrosshairLayer, new object[2] { true, 0f }); _showChargeMethod?.Invoke(_circleTarget, new object[1] { true }); _chargeShown = true; } _isStutteringDuringReload = false; } if (_isReloading && !_ammoFilledThisReload && Time.deltaTime > 0.1f) { _isStutteringDuringReload = true; } else if (!isReloading) { _waitingForNativeReloadToEnd = false; if (_isReloading) { if (!_isAnimatingReady) { ResetReloadState(); } else { _isReloading = false; } } } if (_isAnimatingReady && Time.time - _readyEffectStartTime >= 0.5f) { ResetReloadState(); } if (isReloading || _isAnimatingReady) { return; } ConfigEntry? configEnableLowAmmoWarning = EntryPoint.ConfigEnableLowAmmoWarning; if (configEnableLowAmmoWarning != null && !configEnableLowAmmoWarning.Value) { return; } int clip = _cachedBulletWeapon.m_clip; int clipSize = ((ItemEquippable)_cachedBulletWeapon).ClipSize; _lastClipCount = clip; if (isReloading || _isAnimatingReady) { return; } float num = ((clipSize <= 20) ? 0.5f : (EntryPoint.ConfigLowAmmoThreshold?.Value ?? 0.35f)); if ((float)clip <= (float)clipSize * num) { if (Time.time - _lastGlitchTime > 0.08f) { _lastGlitchTime = Time.time; bool flag2 = clip == 0; string original = "RELOAD"; _currGlitchedText = GetGlitchedText(original, flag2 ? 0.4f : 0.25f); } } else { _currGlitchedText = string.Empty; } } private void LateUpdate() { //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0577: Unknown result type (might be due to invalid IL or missing references) //IL_05ab: 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_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_067b: Unknown result type (might be due to invalid IL or missing references) //IL_069f: Unknown result type (might be due to invalid IL or missing references) //IL_04cf: Unknown result type (might be due to invalid IL or missing references) //IL_06c1: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_07a8: Unknown result type (might be due to invalid IL or missing references) //IL_0872: Unknown result type (might be due to invalid IL or missing references) //IL_0896: Unknown result type (might be due to invalid IL or missing references) //IL_08b8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_cachedBulletWeapon == (Object)null || (Object)(object)_localPlayer == (Object)null) { return; } ApplyHUDSway(); bool isReloading = ((ItemEquippable)_cachedBulletWeapon).IsReloading; bool flag = _isAnimatingReady && Time.time - _readyEffectStartTime < 0.5f; bool flag2 = isReloading && !_ammoFilledThisReload; if (flag2 || flag || !string.IsNullOrEmpty(_currGlitchedText)) { string text = ""; if (flag) { text = "0.00s"; bool flag3 = EntryPoint.ConfigEnableChargeCircleEffects?.Value ?? true; if (_circleTarget != null && flag3) { float num = Mathf.Clamp01((Time.time - _readyEffectStartTime) / 0.5f); float num2 = Mathf.Lerp(1.25f, 1f, num); GameObject gameObject = _circleTarget.Cast().gameObject; if ((Object)(object)gameObject != (Object)null) { gameObject.transform.localScale = new Vector3(num2, num2, 1f); } _showChargeMethod?.Invoke(_circleTarget, new object[1] { true }); _setChargeMethod?.Invoke(_circleTarget, new object[1] { 1f }); _setChargeUpVisibleAndProgressMethod?.Invoke(GuiManager.CrosshairLayer, new object[2] { true, 1f }); } } else if (flag2) { float num3 = Time.time - _reloadStartTime; float num4 = 0.9f; if (!string.IsNullOrEmpty(_currFingerprint) && _persistentRatioMap.ContainsKey(_currFingerprint)) { num4 = _persistentRatioMap[_currFingerprint]; } else if (((ItemEquippable)_cachedBulletWeapon).ArchetypeData.DefaultClipSize > 10) { num4 = 0.6f; } float num5 = _lastReloadDuration * num4; float num6 = Mathf.Clamp01(num3 / num5); float num7 = Mathf.Max(0f, num5 - num3); text = ((num7 > 0f) ? $"{num7:0.00}s" : ""); bool flag4 = EntryPoint.ConfigEnableChargeCircleEffects?.Value ?? true; if (_circleTarget != null && flag4) { _showChargeMethod?.Invoke(_circleTarget, new object[1] { true }); _setChargeMethod?.Invoke(_circleTarget, new object[1] { num6 }); _setChargeUpVisibleAndProgressMethod?.Invoke(GuiManager.CrosshairLayer, new object[2] { true, num6 }); GameObject gameObject2 = _circleTarget.Cast().gameObject; if ((Object)(object)gameObject2 != (Object)null) { gameObject2.transform.localScale = Vector3.one; } } } else if (!string.IsNullOrEmpty(_currGlitchedText)) { text = _currGlitchedText; } bool flag5 = EntryPoint.ConfigEnableChargeCircleEffects?.Value ?? true; if (!flag5 && (flag || flag2)) { text = ""; } ((TMP_Text)_textMesh).text = text; if (flag && flag5) { ((Graphic)_textMesh).color = new Color(0f, 1f, 0f, 0.8f); } else if (!string.IsNullOrEmpty(_currGlitchedText) && !isReloading) { float a = ((Mathf.Floor(Time.time * 5f) % 2f == 0f) ? 0.85f : 0.75f); Color parsedLowAmmoColor = EntryPoint.ParsedLowAmmoColor; parsedLowAmmoColor.a = a; ((Graphic)_textMesh).color = parsedLowAmmoColor; float value = Random.value; float num8 = 0f; if (value < 0.04f) { num8 = Random.Range(-6f, 6f); } else if (value < 0.05f) { num8 = Random.Range(-12f, 12f); } ((Transform)((TMP_Text)_textMesh).rectTransform).localPosition = new Vector3(num8, 0f, 0f); } else { ((Graphic)_textMesh).color = Color.white; ((Transform)((TMP_Text)_textMesh).rectTransform).localPosition = Vector3.zero; } } else { ((TMP_Text)_textMesh).text = string.Empty; } ClearGlitchLayers(); if (_circleTarget == null) { return; } bool flag6 = EntryPoint.ConfigEnableChargeCircleEffects?.Value ?? true; if (flag6) { if (flag) { _setChargeColorMethod?.Invoke(_circleTarget, new object[1] { ((Graphic)_textMesh).color }); } else if (flag2) { _setChargeColorMethod?.Invoke(_circleTarget, new object[1] { EntryPoint.ParsedChargeColor }); } } if (!flag6 && _chargeShown) { _setChargeUpVisibleAndProgressMethod?.Invoke(GuiManager.CrosshairLayer, new object[2] { false, 0f }); _showChargeMethod?.Invoke(_circleTarget, new object[1] { false }); _setChargeMethod?.Invoke(_circleTarget, new object[1] { 0f }); GameObject gameObject3 = _circleTarget.Cast().gameObject; if ((Object)(object)gameObject3 != (Object)null) { gameObject3.transform.localScale = Vector3.one; } _setChargeColorMethod?.Invoke(_circleTarget, new object[1] { _originalChargeColor }); _chargeUpColOrgField?.SetValue(_circleTarget, _originalChargeColor); _chargeShown = false; } else { if (flag2 || flag || !_chargeShown) { return; } if (isReloading) { _setChargeUpVisibleAndProgressMethod?.Invoke(GuiManager.CrosshairLayer, new object[2] { false, 0f }); _showChargeMethod?.Invoke(_circleTarget, new object[1] { false }); _setChargeMethod?.Invoke(_circleTarget, new object[1] { 0f }); GameObject gameObject4 = _circleTarget.Cast().gameObject; if ((Object)(object)gameObject4 != (Object)null) { gameObject4.transform.localScale = Vector3.one; } } else if (!_isChargeWeapon) { _setChargeUpVisibleAndProgressMethod?.Invoke(GuiManager.CrosshairLayer, new object[2] { false, 0f }); _showChargeMethod?.Invoke(_circleTarget, new object[1] { false }); _setChargeMethod?.Invoke(_circleTarget, new object[1] { 0f }); GameObject gameObject5 = _circleTarget.Cast().gameObject; if ((Object)(object)gameObject5 != (Object)null) { gameObject5.transform.localScale = Vector3.one; } _setChargeColorMethod?.Invoke(_circleTarget, new object[1] { _originalChargeColor }); _chargeUpColOrgField?.SetValue(_circleTarget, _originalChargeColor); _chargeShown = false; } } } private void ClearGlitchLayers() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_glitchTextMesh2 != (Object)null) { ((TMP_Text)_glitchTextMesh2).text = ""; ((Graphic)_glitchTextMesh2).color = new Color(0f, 0f, 0f, 0f); } } private void PlayReloadCue() { try { ConfigEntry? configReloadSoundCue = EntryPoint.ConfigReloadSoundCue; if (configReloadSoundCue != null && configReloadSoundCue.Value == ReloadSoundOption.CustomLocalFile) { if ((Object)(object)_customClip != (Object)null && (Object)(object)_audioSource != (Object)null) { _audioSource.PlayOneShot(_customClip); } else { Logger.Warn("Custom audio clip is not loaded yet or file is missing."); } return; } string text = EntryPoint.ConfigReloadSoundCue?.Value.ToString() ?? ""; if (!string.IsNullOrEmpty(text) && !text.Equals("None", StringComparison.OrdinalIgnoreCase) && !((Object)(object)_localPlayer == (Object)null) && _localPlayer.Sound != null) { uint soundEventId = SoundHelper.GetSoundEventId(text); if (soundEventId != 0) { _localPlayer.Sound.Post(soundEventId, true); } else { Logger.Warn("Sound event '" + text + "' not found in AK.EVENTS, skipping cue."); } } } catch (Exception ex) { Logger.Error("PlayReloadCue failed: " + ex.Message); } } private string GetGlitchedText(string original, float intensity) { if (string.IsNullOrEmpty(original) || Random.value > intensity) { return original; } char[] array = original.ToCharArray(); int num = Random.Range(0, array.Length); if (array[num] != ' ' && array[num] != '[' && array[num] != ']' && array[num] != '[' && array[num] != ']') { array[num] = "#@&!$%01X?"[Random.Range(0, "#@&!$%01X?".Length)]; } return new string(array); } private void ResetReloadState() { //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) _isReloading = false; _isAnimatingReady = false; _hasTriggeredReadyEffect = false; _readyEffectStartTime = -1f; ((TMP_Text)_textMesh).text = string.Empty; _currGlitchedText = string.Empty; _lastClipCount = -1; _waitingForNativeReloadToEnd = (Object)(object)_cachedBulletWeapon != (Object)null && ((ItemEquippable)_cachedBulletWeapon).IsReloading; if (_circleTarget != null) { _showChargeMethod?.Invoke(_circleTarget, new object[1] { false }); _setChargeMethod?.Invoke(_circleTarget, new object[1] { 0f }); _setChargeUpVisibleAndProgressMethod?.Invoke(GuiManager.CrosshairLayer, new object[2] { false, 0f }); if (_chargeShown) { _setChargeColorMethod?.Invoke(_circleTarget, new object[1] { _originalChargeColor }); _chargeUpColOrgField?.SetValue(_circleTarget, _originalChargeColor); GameObject gameObject = _circleTarget.Cast().gameObject; if ((Object)(object)gameObject != (Object)null) { gameObject.transform.localScale = Vector3.one; } _chargeShown = false; } } ClearGlitchLayers(); } private void ApplyHUDSway() { //IL_0025: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0062: 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_0065: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0114: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) FPSCamera fPSCamera = _localPlayer.FPSCamera; if ((Object)(object)fPSCamera == (Object)null) { return; } Vector3 forward = ((Component)fPSCamera).transform.forward; if (_isFirstSwayFrame) { _lastCamForward = forward; _isFirstSwayFrame = false; return; } Vector3 val = ((Component)fPSCamera).transform.InverseTransformDirection(forward - _lastCamForward); _lastCamForward = forward; float num = 1800.0001f; bool flag = false; try { if (_isAimingField != null) { flag = (bool)_isAimingField.GetValue(_cachedBulletWeapon); } } catch { } if ((Object)(object)_cachedBulletWeapon != (Object)null && flag) { num *= 0.25f; } Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor((0f - val.x) * num, val.y * num); if (((Vector2)(ref val2)).magnitude > 12f) { val2 = ((Vector2)(ref val2)).normalized * 12f; } _currentSwayOffset = Vector2.SmoothDamp(_currentSwayOffset, val2, ref _swayVelocity, 0.12f); _currentSwayOffset.x = Mathf.Clamp(_currentSwayOffset.x, -12f, 12f); _currentSwayOffset.y = Mathf.Clamp(_currentSwayOffset.y, -12f, 12f); float num2 = EntryPoint.ConfigOffset?.Value ?? 85f; _uiRoot.transform.localPosition = new Vector3(_currentSwayOffset.x, 0f - num2 + _currentSwayOffset.y, 0f); } public void UpdateUIPosition() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_uiRoot == (Object)null)) { float num = EntryPoint.ConfigOffset?.Value ?? 85f; _uiRoot.transform.localPosition = new Vector3(0f, 0f - num, 0f); } } private float GetWeaponMultiplier(BulletWeapon weapon) { try { GearIDRange gearIDRange = ((ItemEquippable)weapon).GearIDRange; if (gearIDRange == null) { return 1f; } if (_getIdentifierMethod == null) { _getIdentifierMethod = ((object)gearIDRange).GetType().GetMethod("GetIdentifier"); } if (_getIdentifierMethod == null) { return 1f; } for (int i = 0; i < 64; i++) { try { uint num = (uint)_getIdentifierMethod.Invoke(gearIDRange, new object[1] { (object)(InventorySlot)(byte)i }); if (num != 0) { GearMagPartDataBlock block = GameDataBlockBase.GetBlock(num); if (block != null) { return block.ReloadTimeMultiplier; } } } catch { } } } catch { } return 1f; } private void InitializeReflection() { _reflectionChecked = true; if (GuiManager.CrosshairLayer != null) { Type type = ((object)GuiManager.CrosshairLayer).GetType(); _setChargeUpVisibleAndProgressMethod = type.GetMethod("SetChargeUpVisibleAndProgress"); CircleCrosshair circleCrosshair = GuiManager.CrosshairLayer.m_circleCrosshair; if ((Object)(object)circleCrosshair != (Object)null) { _circleTarget = (Il2CppObjectBase?)(object)circleCrosshair; Type type2 = ((object)circleCrosshair).GetType(); _setChargeMethod = type2.GetMethod("SetCharge"); _showChargeMethod = type2.GetMethod("ShowCharge"); _setChargeColorMethod = type2.GetMethod("SetChargeUpColor"); _chargeUpColOrgField = type2.GetField("m_chargeUpColOrg", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } Type typeFromHandle = typeof(ItemEquippable); if ((object)_isAimingField == null) { _isAimingField = typeFromHandle.GetField("m_isAiming", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } } } private bool DetectIsChargeWeapon(BulletWeapon weapon) { if (((weapon != null) ? ((ItemEquippable)weapon).ArchetypeData : null) == null) { return false; } try { ArchetypeDataBlock archetypeData = ((ItemEquippable)weapon).ArchetypeData; Type type = ((object)archetypeData).GetType(); BindingFlags bindingAttr = BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; PropertyInfo[] properties = type.GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.PropertyType == typeof(float) && propertyInfo.Name.IndexOf("charge", StringComparison.OrdinalIgnoreCase) >= 0 && ((float?)propertyInfo.GetValue(archetypeData)).GetValueOrDefault() > 0.001f) { return true; } } FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(float) && fieldInfo.Name.IndexOf("charge", StringComparison.OrdinalIgnoreCase) >= 0 && ((float?)fieldInfo.GetValue(archetypeData)).GetValueOrDefault() > 0.001f) { return true; } } } catch { } return false; } } [HarmonyPatch(typeof(PlayerInventoryLocal), "DoReload")] internal static class ReloadDonePatch { public static void Postfix() { if ((Object)(object)Zose_ReloadTimerPlus.Instance != (Object)null) { Zose_ReloadTimerPlus.Instance.OnAmmoRefreshed(); } } } internal static class SoundHelper { private static Dictionary? _eventCache; private static bool _initDone; public static void InvalidateCache() { _eventCache = null; _initDone = false; } public static uint GetSoundEventId(string eventName) { if (!_initDone) { BuildCache(); } if (_eventCache != null && _eventCache.TryGetValue(eventName, out var value)) { return value; } return 0u; } private static void BuildCache() { _initDone = true; _eventCache = new Dictionary(StringComparer.OrdinalIgnoreCase); try { Type typeFromHandle = typeof(EVENTS); IEnumerable enumerable = from p in typeFromHandle.GetProperties(BindingFlags.Static | BindingFlags.Public) where p.PropertyType == typeof(uint) && p.GetMethod != null select p; foreach (PropertyInfo item in enumerable) { try { uint value = (uint)item.GetValue(null); _eventCache[item.Name] = value; } catch { } } IEnumerable enumerable2 = from f in typeFromHandle.GetFields(BindingFlags.Static | BindingFlags.Public) where f.FieldType == typeof(uint) select f; foreach (FieldInfo item2 in enumerable2) { try { uint value2 = (uint)item2.GetValue(null); if (!_eventCache.ContainsKey(item2.Name)) { _eventCache[item2.Name] = value2; } } catch { } } Logger.Info($"SoundHelper: cached {_eventCache.Count} sound events from AK.EVENTS."); } catch (Exception ex) { Logger.Error("SoundHelper init failed: " + ex.Message); } } } public static class WavUtility { public static AudioClip? ToAudioClip(string filePath, string clipName = "CustomWav") { if (!File.Exists(filePath)) { return null; } byte[] buffer = File.ReadAllBytes(filePath); using MemoryStream memoryStream = new MemoryStream(buffer); using BinaryReader binaryReader = new BinaryReader(memoryStream); if (new string(binaryReader.ReadChars(4)) != "RIFF") { return null; } binaryReader.ReadInt32(); if (new string(binaryReader.ReadChars(4)) != "WAVE") { return null; } short num = 1; int num2 = 44100; short num3 = 16; int num4 = 0; while (memoryStream.Position < memoryStream.Length) { string text = new string(binaryReader.ReadChars(4)); int num5 = binaryReader.ReadInt32(); if (text == "fmt ") { binaryReader.ReadInt16(); num = binaryReader.ReadInt16(); num2 = binaryReader.ReadInt32(); binaryReader.ReadInt32(); binaryReader.ReadInt16(); num3 = binaryReader.ReadInt16(); if (num5 > 16) { memoryStream.Position += num5 - 16; } } else { if (text == "data") { num4 = num5; break; } memoryStream.Position += num5; } } if (num4 <= 0) { return null; } int num6 = num3 / 8; int num7 = num4 / num6; float[] array = new float[num7]; for (int i = 0; i < num7; i++) { switch (num3) { case 16: array[i] = (float)binaryReader.ReadInt16() / 32768f; break; case 8: array[i] = (float)(binaryReader.ReadByte() - 128) / 128f; break; case 32: array[i] = binaryReader.ReadSingle(); break; } } AudioClip val = AudioClip.Create(clipName, num7 / num, (int)num, num2, false); if ((Object)(object)val != (Object)null) { val.SetData(new Il2CppStructArray(array), 0); return val; } return null; } } } namespace Zose_ReloadTimerPlus.Patches { [HarmonyPatch(typeof(CM_PageRundown_New), "PlaceRundown")] internal static class CM_PageRundown_New_PlaceRundown { private static bool _injected; private static void Postfix() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!_injected) { _injected = true; GameObject val = new GameObject("RT_CompInject"); val.AddComponent(); Object.DontDestroyOnLoad((Object)(object)val); } } } }