using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SolidAim")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jangnana")] [assembly: AssemblyProduct("SolidAim")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e586ebd9-69f1-4ec0-8bab-8f11d86d3340")] [assembly: AssemblyFileVersion("0.1.5.5")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.1.5.5")] namespace SolidAim; [BepInPlugin("Jangnana.SolidAim", "SolidAim", "0.1.5")] public class SolidAim : BaseUnityPlugin { public static SolidAim Instance; private readonly Harmony harmony = new Harmony("Jangnana.SolidAim"); public static ConfigEntry AimStabilizationEnabled; public static ConfigEntry DebugMode; public static ConfigEntry GunSpread; public static ConfigEntry DroopWhenEmpty; public static ConfigEntry AntiStuck; public static ConfigEntry StuckRecoverKey; private float lastRecoveryTime = -3f; private void Awake() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown Instance = this; AimStabilizationEnabled = ((BaseUnityPlugin)this).Config.Bind("AimSettings", "AimStabilization", true, "Enables fixed gun aiming and camera alignment logic."); DroopWhenEmpty = ((BaseUnityPlugin)this).Config.Bind("AimSettings", "DroopWhenEmpty", true, "Allows the gun to droop when out of ammo (Vanilla behavior)."); GunSpread = ((BaseUnityPlugin)this).Config.Bind("GunSettings", "GunSpread", 0f, new ConfigDescription("Bullet spread multiplier (0.0: No spread, 1.0: Vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); AntiStuck = ((BaseUnityPlugin)this).Config.Bind("GunSettings", "AntiStuck", true, "Automatically detects and recovers guns stuck in terrain."); StuckRecoverKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "StuckRecoverKey", (KeyCode)98, "Hotkey to manually recover your held weapon (3s cooldown)."); DebugMode = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugMode", false, "Show development logs in the console."); harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[SolidAim] v0.1.5 initialized successfully!"); } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!Input.GetKeyDown(StuckRecoverKey.Value)) { return; } if (Time.time - lastRecoveryTime < 3f) { if (DebugMode.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}] Recovery cooldown: {1:F1}s remaining.", "SolidAim", 3f - (Time.time - lastRecoveryTime))); } } else if (SolidAimHandler.RecoverStuckWeapons()) { lastRecoveryTime = Time.time; if (DebugMode.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[SolidAim] Manual Recovery Success. Cooldown started (3s)."); } } else if (DebugMode.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[SolidAim] No weapon held. Cooldown skipped."); } } } public static class PluginInfo { public const string PLUGIN_GUID = "Jangnana.SolidAim"; public const string PLUGIN_NAME = "SolidAim"; public const string PLUGIN_VERSION = "0.1.5"; public const string ASSEMBLY_VERSION = "0.1.5.5"; } [HarmonyPatch(typeof(PhysGrabObject))] public class SolidAimHandler : MonoBehaviour { private static Dictionary originalSpreads = new Dictionary(); private static Dictionary lastAppliedMultipliers = new Dictionary(); private static Dictionary lastBatteryLevels = new Dictionary(); private static Dictionary lastPos = new Dictionary(); private static Dictionary thrashTimer = new Dictionary(); private static HashSet recoveryQueue = new HashSet(); private static float lastBatteryUpdateTime = 0f; private static bool isResourceEmpty = false; private static FieldInfo isCrouchingField = typeof(PlayerAvatar).GetField("isCrouching", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static FieldInfo gunStateField = typeof(ItemGun).GetField("stateCurrent", BindingFlags.Instance | BindingFlags.NonPublic); private static FieldInfo gunBatteryField = typeof(ItemGun).GetField("itemBattery", BindingFlags.Instance | BindingFlags.NonPublic); private static int layerMask = LayerMask.GetMask(new string[4] { "Default", "Environment", "Terrain", "Static" }); public static void RestoreWeaponPhysics(PhysGrabObject obj, int gunId) { obj.rb.isKinematic = false; obj.rb.detectCollisions = true; recoveryQueue.Remove(gunId); if (SolidAim.DebugMode.Value) { Debug.Log((object)string.Format("[{0}] Manual Recovery Applied for {1}({2})", "SolidAim", ((Object)obj).name, gunId)); } } public static bool RecoverStuckWeapons() { PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); if ((Object)(object)val == (Object)null) { return false; } bool result = false; PhysGrabObject[] array = Object.FindObjectsOfType(); PhysGrabObject[] array2 = array; foreach (PhysGrabObject val2 in array2) { ItemGun component = ((Component)val2).GetComponent(); if (!((Object)(object)component == (Object)null)) { if (recoveryQueue.Contains(((Object)component).GetInstanceID())) { RestoreWeaponPhysics(val2, ((Object)component).GetInstanceID()); } if (val2.playerGrabbing != null && val2.playerGrabbing.Contains(val.physGrabber)) { ExecuteRecovery(val2, val); result = true; } } } return result; } private static void ExecuteRecovery(PhysGrabObject obj, PlayerAvatar player) { //IL_003c: 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_004c: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) Rigidbody rb = obj.rb; if (!((Object)(object)rb == (Object)null)) { Transform val = (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform : ((Component)player).transform); rb.position = val.position + val.forward * 0.5f + val.right * 0.01f + val.up * 0.01f; rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; rb.rotation = val.rotation; rb.isKinematic = true; rb.detectCollisions = false; ItemGun component = ((Component)obj).GetComponent(); int instanceID = ((Object)component).GetInstanceID(); recoveryQueue.Add(instanceID); if (SolidAim.DebugMode.Value) { Debug.Log((object)string.Format("[{0}] Recovery Enqueued for {1}({2})", "SolidAim", ((Object)component).name, instanceID)); } } } [HarmonyPatch("FixedUpdate")] [HarmonyPostfix] private static void FixedUpdatePostfix(PhysGrabObject __instance) { ItemGun component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return; } int instanceID = ((Object)component).GetInstanceID(); if (recoveryQueue.Contains(instanceID)) { RestoreWeaponPhysics(__instance, instanceID); } PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); if ((Object)(object)val == (Object)null || !__instance.playerGrabbing.Contains(val.physGrabber)) { return; } float value = SolidAim.GunSpread.Value; if (!originalSpreads.ContainsKey(instanceID)) { originalSpreads[instanceID] = component.gunRandomSpread; lastAppliedMultipliers[instanceID] = -1f; if (SolidAim.DebugMode.Value) { Debug.Log((object)string.Format("[{0}] Detected: {1}({2}) (Original Spread: {3})", "SolidAim", ((Object)component).name, instanceID, originalSpreads[instanceID])); } } if (value != lastAppliedMultipliers[instanceID]) { float num = originalSpreads[instanceID] * value; if (SolidAim.DebugMode.Value) { if (lastAppliedMultipliers[instanceID] == -1f) { Debug.Log((object)string.Format("[{0}] {1}({2}) Initial Spread Applied: {3} -> {4}", "SolidAim", ((Object)component).name, instanceID, originalSpreads[instanceID], num)); } else { float num2 = originalSpreads[instanceID] * lastAppliedMultipliers[instanceID]; Debug.Log((object)string.Format("[{0}] {1}({2}) Config Changed: {3} -> {4} (Multiplier: {5} -> {6})", "SolidAim", ((Object)component).name, instanceID, num2, num, lastAppliedMultipliers[instanceID], value)); } } component.gunRandomSpread = num; lastAppliedMultipliers[instanceID] = value; } else { component.gunRandomSpread = originalSpreads[instanceID] * value; } HandleSolidAimState(__instance, component, val); if (SolidAim.AntiStuck.Value) { DetectThrashingAndRecover(__instance, component, val); } } private static void HandleSolidAimState(PhysGrabObject obj, ItemGun gun, PlayerAvatar player) { //IL_0022: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 bool value = SolidAim.AimStabilizationEnabled.Value; bool value2 = SolidAim.DroopWhenEmpty.Value; State val = (State)gunStateField.GetValue(gun); bool flag = (int)val == 1; float num = 1f; object value3 = gunBatteryField.GetValue(gun); if (value3 != null) { num = Traverse.Create(value3).Field("batteryLife").GetValue(); if (SolidAim.DebugMode.Value) { float time = Time.time; if (time - lastBatteryUpdateTime >= 1f) { lastBatteryUpdateTime = time; int instanceID = ((Object)gun).GetInstanceID(); if (!lastBatteryLevels.ContainsKey(instanceID) || Mathf.Abs(lastBatteryLevels[instanceID] - num) > 0.01f) { lastBatteryLevels[instanceID] = num; Debug.Log((object)string.Format("[{0}] {1}({2}) Battery Updated: {3:F1}%", "SolidAim", ((Object)gun).name, instanceID, num)); } } } } bool flag2 = num <= 0.1f; isResourceEmpty = flag2 || flag; bool flag3 = value; if (isResourceEmpty) { flag3 = !value2; } if (flag3) { ApplyAimStabilization(obj, gun, player); } } private static void ApplyAimStabilization(PhysGrabObject obj, ItemGun gun, PlayerAvatar player) { //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_00bf: 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_00d0: Unknown result type (might be due to invalid IL or missing references) bool flag = (bool)isCrouchingField.GetValue(player); gun.aimVerticalOffset = (flag ? (-1f) : (-3f)); obj.OverrideMass(0.25f, 0.1f); obj.OverrideGrabStrength(2f, 0.1f); obj.OverrideTorqueStrength(5f, 0.1f); obj.OverrideDrag(2f, 0.1f); obj.rb.angularDrag = 29f; if (!isResourceEmpty) { gun.torqueMultiplier = 2f; } if ((Object)(object)Camera.main != (Object)null) { Quaternion rotation = ((Component)Camera.main).transform.rotation; obj.rb.rotation = Quaternion.Slerp(obj.rb.rotation, rotation, Time.fixedDeltaTime * 10f); } } private static void DetectThrashingAndRecover(PhysGrabObject obj, ItemGun gun, PlayerAvatar player) { //IL_0022: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00aa: 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_0187: Unknown result type (might be due to invalid IL or missing references) Rigidbody rb = obj.rb; if ((Object)(object)rb == (Object)null) { return; } int instanceID = ((Object)gun).GetInstanceID(); Vector3 position = rb.position; if (!lastPos.ContainsKey(instanceID)) { lastPos[instanceID] = position; thrashTimer[instanceID] = 0f; return; } float num = Vector3.Distance(position, lastPos[instanceID]); Vector3 angularVelocity = rb.angularVelocity; float magnitude = ((Vector3)(ref angularVelocity)).magnitude; Vector3 val = ((Component)obj).transform.position + ((Component)obj).transform.forward * 0.2f; bool flag = Physics.CheckSphere(val, 0.1f, layerMask, (QueryTriggerInteraction)1); if (num < 0.026f && magnitude > 1.3f && flag) { thrashTimer[instanceID] += Time.fixedDeltaTime * ((magnitude >= 15.99f) ? 3f : 1f); } else { thrashTimer[instanceID] = Mathf.Max(0f, thrashTimer[instanceID] - Time.fixedDeltaTime * 1.5f); } if (thrashTimer[instanceID] >= 0.11f) { ExecuteRecovery(obj, player); thrashTimer[instanceID] = 0f; } lastPos[instanceID] = position; } }