using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AudioImportLib;
using BoneLib;
using BoneLib.BoneMenu;
using BulletWhiz;
using HarmonyLib;
using Il2CppSLZ.Marrow;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "BulletWhiz", "1.0.2", "Lunobe", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BulletWhiz")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BulletWhiz")]
[assembly: AssemblyTitle("BulletWhiz")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BulletWhiz
{
public class Core : MelonMod
{
[HarmonyPatch(typeof(Gun))]
public static class GunPatches
{
[HarmonyPatch("OnFire")]
[HarmonyPostfix]
public static void OnFirePostfix(Gun __instance)
{
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((Object)(object)__instance == (Object)null)
{
LogDebug("[PATCH] Gun.OnFire called with null instance");
return;
}
LogDebug("[PATCH] Gun.OnFire triggered: " + ((Object)__instance).name);
bool flag = IsLocalPlayerGun(__instance);
Transform firePointTransform = __instance.firePointTransform;
if ((Object)(object)firePointTransform == (Object)null)
{
LogDebug("[PATCH] " + ((Object)__instance).name + " has no firePointTransform");
return;
}
Vector3 position = firePointTransform.position;
Vector3 forward = firePointTransform.forward;
LogDebug($"[PATCH] {((Object)__instance).name} | Muzzle: {position} | Dir: {forward} | IsLocal: {flag}");
OnGunFired(__instance, position, forward, flag);
}
catch (Exception value)
{
LogError($"[PATCH] Gun.OnFire error: {value}");
}
}
}
public static Core Instance;
public static List<AudioClip> WhizSounds = new List<AudioClip>();
private static string FolderPath;
private static MelonPreferences_Category _prefCategory;
public static MelonPreferences_Entry<bool> PrefEnabled;
public static MelonPreferences_Entry<float> PrefVolume;
public static MelonPreferences_Entry<float> PrefMinDistance;
public static MelonPreferences_Entry<float> PrefPassDistance;
public static MelonPreferences_Entry<float> PrefSpeedThreshold;
public static MelonPreferences_Entry<bool> PrefDebugLogs;
private static FloatElement _volumeElement;
private static FloatElement _minDistanceElement;
private static FloatElement _passDistanceElement;
private static FloatElement _speedThresholdElement;
public static bool IsEnabled => PrefEnabled?.Value ?? false;
public static bool DebugMode => PrefDebugLogs?.Value ?? false;
public override void OnInitializeMelon()
{
Instance = this;
Log("=== BulletWhiz Initialization Started ===");
try
{
SetupPreferences();
Log("Preferences initialized");
}
catch (Exception value)
{
LogError($"Failed to setup preferences: {value}");
}
try
{
SetupBoneMenu();
Log("BoneMenu initialized");
}
catch (Exception value2)
{
LogError($"Failed to setup BoneMenu: {value2}");
}
try
{
FolderPath = Path.Combine(MelonEnvironment.UserDataDirectory, "BulletWhiz");
Log("Audio folder path: " + FolderPath);
if (!Directory.Exists(FolderPath))
{
Directory.CreateDirectory(FolderPath);
Log("Created audio folder");
}
LoadAudioFiles();
}
catch (Exception value3)
{
LogError($"Failed to setup audio folder: {value3}");
}
Log($"=== BulletWhiz Ready | Enabled: {IsEnabled} | Sounds: {WhizSounds.Count} ===");
}
private void SetupPreferences()
{
_prefCategory = MelonPreferences.CreateCategory("BulletWhiz");
PrefEnabled = _prefCategory.CreateEntry<bool>("Enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
PrefVolume = _prefCategory.CreateEntry<float>("Volume", 50f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
PrefMinDistance = _prefCategory.CreateEntry<float>("MinDistance", 100f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
PrefPassDistance = _prefCategory.CreateEntry<float>("PassDistance", 5f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
PrefSpeedThreshold = _prefCategory.CreateEntry<float>("SpeedThreshold", 250f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
PrefDebugLogs = _prefCategory.CreateEntry<bool>("DebugLogs", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
LogDebug($"Prefs loaded - Enabled:{PrefEnabled.Value} Vol:{PrefVolume.Value} MinFiredDist:{PrefMinDistance.Value} PassDist:{PrefPassDistance.Value} Speed:{PrefSpeedThreshold.Value} Debug:{PrefDebugLogs.Value}");
}
private void SetupBoneMenu()
{
//IL_000b: 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_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
Page val = Page.Root.CreatePage("Bullet Whiz", Color.yellow, 0, true);
LogDebug("Created BoneMenu page");
val.CreateBool("Enabled", Color.green, PrefEnabled.Value, (Action<bool>)delegate(bool value)
{
SafeSetPref("Enabled", delegate
{
PrefEnabled.Value = value;
});
});
_volumeElement = val.CreateFloat("Volume", Color.white, PrefVolume.Value, 1f, 0f, 100f, (Action<float>)delegate(float value)
{
SafeSetPref("Volume", delegate
{
PrefVolume.Value = Mathf.Max(0f, value);
});
});
_minDistanceElement = val.CreateFloat("Min Firing Distance", Color.white, PrefMinDistance.Value, 10f, 0f, 2000f, (Action<float>)delegate(float value)
{
SafeSetPref("MinDistance", delegate
{
PrefMinDistance.Value = Mathf.Max(0f, value);
});
});
_passDistanceElement = val.CreateFloat("Pass Distance", Color.white, PrefPassDistance.Value, 0.5f, 0.1f, 20f, (Action<float>)delegate(float value)
{
SafeSetPref("PassDistance", delegate
{
PrefPassDistance.Value = Mathf.Max(0.1f, value);
});
});
_speedThresholdElement = val.CreateFloat("Speed Threshold", Color.white, PrefSpeedThreshold.Value, 1f, 1f, 500f, (Action<float>)delegate(float value)
{
SafeSetPref("SpeedThreshold", delegate
{
PrefSpeedThreshold.Value = Mathf.Max(1f, value);
});
});
val.CreateFunction("Reset to Defaults", Color.red, (Action)delegate
{
ResetToDefaults();
});
LogDebug("All BoneMenu elements created");
}
private void SafeSetPref(string name, Action action)
{
try
{
action();
_prefCategory.SaveToFile(true);
LogDebug("Pref changed: " + name);
}
catch (Exception value)
{
LogError($"Failed to save pref '{name}': {value}");
}
}
private void ResetToDefaults()
{
try
{
PrefVolume.Value = 50f;
PrefMinDistance.Value = 100f;
PrefPassDistance.Value = 5f;
PrefSpeedThreshold.Value = 250f;
_prefCategory.SaveToFile(true);
if (_volumeElement != null)
{
_volumeElement.Value = 50f;
}
if (_minDistanceElement != null)
{
_minDistanceElement.Value = 100f;
}
if (_passDistanceElement != null)
{
_passDistanceElement.Value = 5f;
}
if (_speedThresholdElement != null)
{
_speedThresholdElement.Value = 250f;
}
Log("Settings reset to defaults");
}
catch (Exception value)
{
LogError($"Failed to reset settings: {value}");
}
}
private void LoadAudioFiles()
{
if (!Directory.Exists(FolderPath))
{
LogWarning("Audio folder does not exist: " + FolderPath);
return;
}
string[] files = Directory.GetFiles(FolderPath);
Log($"Found {files.Length} files in audio folder");
string[] array = files;
foreach (string text in array)
{
string fileName = Path.GetFileName(text);
try
{
LogDebug("Loading audio: " + fileName);
AudioClip val = API.LoadAudioClip(text, true);
if ((Object)(object)val != (Object)null)
{
WhizSounds.Add(val);
Log($"Loaded audio: {fileName} (duration: {val.length:F2}s)");
}
else
{
LogWarning("AudioImportLib returned null for: " + fileName);
}
}
catch (Exception value)
{
LogError($"Failed to load audio '{fileName}': {value}");
}
}
Log($"Total audio clips loaded: {WhizSounds.Count}");
}
public static void OnGunFired(Gun gun, Vector3 muzzlePos, Vector3 direction, bool isLocalPlayer)
{
//IL_00c4: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: 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_01d3: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
//IL_020f: Unknown result type (might be due to invalid IL or missing references)
//IL_0210: Unknown result type (might be due to invalid IL or missing references)
//IL_0213: Unknown result type (might be due to invalid IL or missing references)
//IL_0218: Unknown result type (might be due to invalid IL or missing references)
//IL_021d: Unknown result type (might be due to invalid IL or missing references)
//IL_021f: Unknown result type (might be due to invalid IL or missing references)
//IL_0221: Unknown result type (might be due to invalid IL or missing references)
//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
try
{
string text = ((gun != null) ? ((Object)gun).name : null) ?? "Unknown";
if (!IsEnabled)
{
LogDebug("[FIRE] " + text + " - Mod disabled, skipping");
return;
}
if (WhizSounds.Count == 0)
{
LogDebug("[FIRE] " + text + " - No audio clips loaded, skipping");
return;
}
if (isLocalPlayer)
{
LogDebug("[FIRE] " + text + " - LocalOwned, skipping");
return;
}
Transform head = Player.Head;
if ((Object)(object)head == (Object)null)
{
LogDebug("[FIRE] " + text + " - Player.Head is null, skipping");
return;
}
Vector3 position = head.position;
float num = Vector3.Distance(muzzlePos, position);
float value = PrefMinDistance.Value;
LogDebug($"[FIRE] {text} | RemoteOwned | MuzzleDist: {num:F1}m | MinFiringDist: {value:F1}m");
if (num < value)
{
LogDebug($"[FIRE] {text} - Fired too close ({num:F1}m < {value:F1}m), skipping");
return;
}
Vector3 val = position - muzzlePos;
float num2 = Vector3.Dot(val, direction);
if (num2 < 0f)
{
LogDebug("[FIRE] " + text + " - Shooting away from player, skipping");
return;
}
Vector3 val2 = muzzlePos + direction * num2;
float num3 = Vector3.Distance(val2, position);
float value2 = PrefPassDistance.Value;
LogDebug($"[FIRE] {text} | ClosestApproach: {num3:F2}m | MaxPassDist: {value2:F1}m");
if (num3 > value2)
{
LogDebug($"[FIRE] {text} - Trajectory too far from head ({num3:F2}m > {value2:F1}m), skipping");
}
else
{
Log($"[WHIZ!] {text} | PassDist: {num3:F2}m (<= {value2:F1}m) | FiredFrom: {num:F1}m (>= {value:F1}m)");
PlayWhizSound(val2);
}
}
catch (Exception value3)
{
LogError($"OnGunFired error: {value3}");
}
}
public static void PlayWhizSound(Vector3 position)
{
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
if (WhizSounds.Count == 0)
{
LogWarning("PlayWhizSound called but no clips loaded");
return;
}
try
{
int num = Random.Range(0, WhizSounds.Count);
AudioClip val = WhizSounds[num];
float num2 = Mathf.Max(0f, PrefVolume.Value) / 10f;
LogDebug($"[AUDIO] Playing clip {num} at volume {num2 * 100f:F0}% (raw:{PrefVolume.Value:F0}) at position {position}");
AudioSource.PlayClipAtPoint(val, position, num2);
LogDebug("[AUDIO] Playback started");
}
catch (Exception value)
{
LogError($"PlayWhizSound error: {value}");
}
}
private static bool IsLocalPlayerGun(Gun gun)
{
//IL_0029: 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_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_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((Object)(object)gun == (Object)null)
{
LogDebug("[OWNER] Gun is null, assuming local");
return true;
}
Vector3 position = ((Component)gun).transform.position;
Transform head = Player.Head;
Hand leftHand = Player.LeftHand;
Hand rightHand = Player.RightHand;
float num = (((Object)(object)head != (Object)null) ? Vector3.Distance(position, head.position) : float.MaxValue);
float num2 = float.MaxValue;
float num3 = float.MaxValue;
try
{
if ((Object)(object)leftHand != (Object)null && (Object)(object)((Component)leftHand).transform != (Object)null)
{
num2 = Vector3.Distance(position, ((Component)leftHand).transform.position);
}
}
catch (Exception ex)
{
LogDebug("[OWNER] LeftHand access error: " + ex.Message);
}
try
{
if ((Object)(object)rightHand != (Object)null && (Object)(object)((Component)rightHand).transform != (Object)null)
{
num3 = Vector3.Distance(position, ((Component)rightHand).transform.position);
}
}
catch (Exception ex2)
{
LogDebug("[OWNER] RightHand access error: " + ex2.Message);
}
float num4 = Mathf.Min(new float[3] { num, num2, num3 });
bool flag = num4 < 2f;
LogDebug($"[OWNER] Gun '{((Object)gun).name}' | HeadDist:{num:F2} LeftDist:{num2:F2} RightDist:{num3:F2} | MinDist:{num4:F2} | IsLocal:{flag}");
return flag;
}
catch (Exception value)
{
LogError($"IsLocalPlayerGun error: {value}");
return true;
}
}
public static void Log(string msg)
{
Core instance = Instance;
if (instance != null)
{
((MelonBase)instance).LoggerInstance.Msg(msg);
}
}
public static void LogWarning(string msg)
{
Core instance = Instance;
if (instance != null)
{
((MelonBase)instance).LoggerInstance.Warning(msg);
}
}
public static void LogError(string msg)
{
Core instance = Instance;
if (instance != null)
{
((MelonBase)instance).LoggerInstance.Error(msg);
}
}
public static void LogDebug(string msg)
{
if (DebugMode)
{
Core instance = Instance;
if (instance != null)
{
((MelonBase)instance).LoggerInstance.Msg("[DEBUG] " + msg);
}
}
}
}
}