Some mods may be broken due to the recent Alloyed Collective update.
Decompiled source of CleanupSnatcher v1.0.2
plugins/com.pwdcat.CleanupSnatcher.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Drifter; using EntityStates.Drifter.Bag; using HarmonyLib; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.Options; using RoR2; using RoR2.Projectile; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Networking; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.pwdcat.CleanupSnatcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2")] [assembly: AssemblyProduct("com.pwdcat.CleanupSnatcher")] [assembly: AssemblyTitle("CleanupSnatcher")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.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.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] [Microsoft.CodeAnalysis.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; } } [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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace CleanupSnatcher { internal static class Constants { public const string LogPrefix = "[CleanupSnatcher]"; public const string PluginGuid = "pwdcat.CleanupSnatcher"; public const string PluginName = "CleanupSnatcher"; public const string PluginVersion = "1.0.0"; } internal static class Log { private static ManualLogSource? _logSource; private const string ERROR_PREFIX = "[ERROR] "; private const string FATAL_PREFIX = "[FATAL] "; private const string INFO_PREFIX = "[INFO] "; private const string WARNING_PREFIX = "[WARNING] "; internal static bool EnableDebugLogs { get; set; } internal static void Init(ManualLogSource logSource) { _logSource = logSource; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Error(object data) { ManualLogSource? logSource = _logSource; if (logSource != null) { logSource.LogMessage((object)("[ERROR] " + data)); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Fatal(object data) { ManualLogSource? logSource = _logSource; if (logSource != null) { logSource.LogMessage((object)("[FATAL] " + data)); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Info(object data) { if (EnableDebugLogs) { ManualLogSource? logSource = _logSource; if (logSource != null) { logSource.LogMessage((object)("[INFO] " + data)); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Message(object data) { ManualLogSource? logSource = _logSource; if (logSource != null) { logSource.LogMessage(data); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void Warning(object data) { ManualLogSource? logSource = _logSource; if (logSource != null) { logSource.LogMessage((object)("[WARNING] " + data)); } } } [BepInPlugin("pwdcat.CleanupSnatcher", "CleanupSnatcher", "1.0.0")] public class CleanupSnatcherPlugin : BaseUnityPlugin { private EventHandler debugLogsHandler; private EventHandler projectileGrabbingHandler; public static CleanupSnatcherPlugin Instance { get; private set; } public static bool RooInstalled => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); public string DirectoryName => Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); public void Awake() { Instance = this; Log.Init(((BaseUnityPlugin)this).Logger); Log.Info("[CleanupSnatcher] CleanupSnatcherPlugin.Awake() called"); PluginConfig.Init(((BaseUnityPlugin)this).Config); Log.EnableDebugLogs = PluginConfig.EnableDebugLogs.Value; Log.Info(string.Format("{0} Debug logs enabled: {1}", "[CleanupSnatcher]", Log.EnableDebugLogs)); SetupConfigurationEventHandlers(); ApplyHarmonyPatches(); RegisterGameEvents(); Log.Info("[CleanupSnatcher] Plugin initialization complete"); } public void OnDestroy() { PluginConfig.RemoveEventHandlers(debugLogsHandler, projectileGrabbingHandler); } public void Start() { SetupRiskOfOptions(); } private void SetupConfigurationEventHandlers() { debugLogsHandler = delegate { Log.EnableDebugLogs = PluginConfig.EnableDebugLogs.Value; }; PluginConfig.EnableDebugLogs.SettingChanged += debugLogsHandler; projectileGrabbingHandler = delegate { }; PluginConfig.EnableProjectileGrabbing.SettingChanged += projectileGrabbingHandler; } private void ApplyHarmonyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Harmony val = new Harmony("pwdcat.CleanupSnatcher"); val.PatchAll(); } private void RegisterGameEvents() { SceneManager.activeSceneChanged += OnSceneChanged; } private static void OnSceneChanged(Scene oldScene, Scene newScene) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Scene changed from " + ((Scene)(ref oldScene)).name + " to " + ((Scene)(ref newScene)).name); } } private void SetupRiskOfOptions() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (RooInstalled) { ModSettingsManager.SetModDescription("Allows Drifter to grab projectiles from their Cleanup ability.", "pwdcat.CleanupSnatcher", "CleanupSnatcher"); try { byte[] array = File.ReadAllBytes(Path.Combine(DirectoryName, "icon.png")); Texture2D val = new Texture2D(256, 256); ImageConversion.LoadImage(val, array); ModSettingsManager.SetModIcon(Sprite.Create(val, new Rect(0f, 0f, 256f, 256f), new Vector2(0.5f, 0.5f))); } catch (Exception) { } AddConfigurationOptions(); } } private void AddConfigurationOptions() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown if (RooInstalled) { ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PluginConfig.EnableProjectileGrabbing)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PluginConfig.EnableDebugLogs)); } } } public static class PluginConfig { public static ConfigEntry<bool> EnableProjectileGrabbing { get; private set; } public static ConfigEntry<bool> EnableDebugLogs { get; private set; } public static void Init(ConfigFile cfg) { EnableProjectileGrabbing = cfg.Bind<bool>("General", "EnableProjectileGrabbing", true, "Enable grabbing of projectiles from Drifter's Cleanup ability"); EnableDebugLogs = cfg.Bind<bool>("General", "EnableDebugLogs", false, "Enable debug logging for projectile grabbing operations"); } public static void RemoveEventHandlers(EventHandler debugLogsHandler, EventHandler projectileGrabbingHandler) { EnableDebugLogs.SettingChanged -= debugLogsHandler; EnableProjectileGrabbing.SettingChanged -= projectileGrabbingHandler; } } } namespace CleanupSnatcher.Patches { public static class ProjectilePatches { [HarmonyPatch(typeof(DrifterCleanupController), "ToggleVisuals")] public class DrifterCleanupController_ToggleVisuals_Patch { [HarmonyPrefix] public static void Prefix(DrifterCleanupController __instance, GameObject target, bool enabled, float duration) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} ToggleVisuals called - target: {1}, enabled: {2}, duration: {3}", "[CleanupSnatcher]", (target != null) ? ((Object)target).name : null, enabled, duration)); } _isToggleVisualsDisplayActive = enabled; if (!enabled) { _shouldMakeNextProjectilesGrabbable = false; if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Display disabled - clearing grab flag"); } } } } [HarmonyPatch(typeof(ProjectileManager), "FireProjectileServer", new Type[] { typeof(FireProjectileInfo), typeof(NetworkConnection), typeof(ushort), typeof(double) })] public class ProjectileManager_FireProjectileServer_Patch { [HarmonyPostfix] public static void Postfix(FireProjectileInfo fireProjectileInfo) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (PluginConfig.EnableDebugLogs.Value) { object[] obj = new object[4] { "[CleanupSnatcher]", null, null, null }; GameObject projectilePrefab = fireProjectileInfo.projectilePrefab; obj[1] = ((projectilePrefab != null) ? ((Object)projectilePrefab).name : null); obj[2] = fireProjectileInfo.position; GameObject owner = fireProjectileInfo.owner; obj[3] = ((owner != null) ? ((Object)owner).name : null); Log.Info(string.Format("{0} ProjectileManager.FireProjectileServer - prefab: {1}, position: {2}, owner: {3}", obj)); } if (PluginConfig.EnableProjectileGrabbing.Value && _shouldMakeNextProjectilesGrabbable) { if (PluginConfig.EnableDebugLogs.Value) { GameObject projectilePrefab2 = fireProjectileInfo.projectilePrefab; Log.Info("[CleanupSnatcher] ProjectileManager.FireProjectileServer - flag set for projectile: " + ((projectilePrefab2 != null) ? ((Object)projectilePrefab2).name : null)); } _shouldMakeNextProjectilesGrabbable = false; } } } [HarmonyPatch(typeof(NetworkServer), "Spawn", new Type[] { typeof(GameObject) })] public class NetworkServer_Spawn_Patch { [HarmonyPostfix] public static void Postfix(GameObject obj) { if (PluginConfig.EnableProjectileGrabbing.Value && _shouldMakeNextProjectilesGrabbable && !((Object)(object)obj == (Object)null) && (Object)(object)obj.GetComponent<ProjectileController>() != (Object)null) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] NetworkServer.Spawn - making projectile grabbable: " + ((Object)obj).name); } AddSpecialObjectAttributesToProjectile(obj); _activeProjectile = obj; if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Set active projectile: " + ((Object)obj).name); } } } } [HarmonyPatch(typeof(GenericSkill), "ExecuteIfReady")] public class GenericSkill_ExecuteIfReady_Patch { [HarmonyPrefix] public static bool Prefix(GenericSkill __instance, ref bool __result) { //IL_060a: Unknown result type (might be due to invalid IL or missing references) //IL_061b: Unknown result type (might be due to invalid IL or missing references) //IL_061d: Unknown result type (might be due to invalid IL or missing references) //IL_0624: Unknown result type (might be due to invalid IL or missing references) //IL_0626: Unknown result type (might be due to invalid IL or missing references) //IL_062b: Unknown result type (might be due to invalid IL or missing references) //IL_0630: Unknown result type (might be due to invalid IL or missing references) //IL_0661: Unknown result type (might be due to invalid IL or missing references) //IL_0677: Unknown result type (might be due to invalid IL or missing references) //IL_0679: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Unknown result type (might be due to invalid IL or missing references) //IL_05f0: Unknown result type (might be due to invalid IL or missing references) //IL_05f7: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04d1: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_0541: Unknown result type (might be due to invalid IL or missing references) //IL_0546: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_054f: 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) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_056e: Unknown result type (might be due to invalid IL or missing references) if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] ExecuteIfReady called for skill: " + __instance.skillDef?.skillName); } if (!PluginConfig.EnableProjectileGrabbing.Value) { return true; } GameObject value; float value2; float value3; float value4; GameObject gameObject; Vector3 val5; Vector3 val6; if (__instance.skillDef?.skillName == "Repossess" && _isToggleVisualsDisplayActive) { if (!__instance.CanExecute()) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Repossess pressed but skill is not ready (cooldown) - skipping projectile spawn"); } return true; } if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Repossess pressed while ToggleVisuals display is ACTIVE - spawning projectile directly"); } SkillLocator component = ((Component)__instance).GetComponent<SkillLocator>(); if ((Object)(object)component != (Object)null && (Object)(object)component.secondary != (Object)null) { GenericSkill secondary = component.secondary; EntityStateMachine val = EntityStateMachine.FindByCustomName(((Component)component).gameObject, "Bag"); if ((Object)(object)val != (Object)null && val.state is BaggedObject) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Bag is already full, skipping projectile spawn"); } return true; } DrifterCleanupController component2 = ((Component)component).gameObject.GetComponent<DrifterCleanupController>(); if ((Object)(object)component2 != (Object)null) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Manually cycling projectile index in DrifterCleanupController"); } FieldInfo field = typeof(DrifterCleanupController).GetField("prefabIndex", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { try { FieldInfo field2 = typeof(DrifterCleanupController).GetField("projectileCandidateSelection", BindingFlags.Instance | BindingFlags.NonPublic); if (field2 != null) { if (field2.GetValue(component2) is WeightedSelection<Candidate> val2) { int num = (int)field.GetValue(component2); int num2 = Math.Abs(num); int num3 = (num2 + 1) % val2.Count; if (num < 0) { num3 = -num3; } field.SetValue(component2, num3); if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Cycled prefabIndex from {1} to {2} (total candidates: {3})", "[CleanupSnatcher]", num, num3, val2.Count)); } } else if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Could not get projectile candidate selection"); } } else { int num4 = (int)field.GetValue(component2); int num5 = Math.Abs(num4); int num6 = (num5 + 1) % 3; if (num4 < 0) { num6 = -num6; } field.SetValue(component2, num6); if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Fallback cycling prefabIndex from {1} to {2}", "[CleanupSnatcher]", num4, num6)); } } } catch (Exception ex) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Failed to cycle prefabIndex: " + ex.Message); } } } else if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Could not find prefabIndex field in DrifterCleanupController"); } } else if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Could not find DrifterCleanupController for manual cycling"); } if ((Object)(object)secondary.stateMachine != (Object)null) { EntityState state = secondary.stateMachine.state; AimMagicBag val3 = (AimMagicBag)(object)((state is AimMagicBag) ? state : null); if (val3 != null) { Traverse val4 = Traverse.Create((object)val3); value = val4.Field("projectilePrefab").GetValue<GameObject>(); if ((Object)(object)value != (Object)null) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Spawning cycled projectile: " + ((Object)value).name); } _shouldMakeNextProjectilesGrabbable = true; value2 = val4.Field("damageCoefficient").GetValue<float>(); value3 = val4.Field("force").GetValue<float>(); value4 = val4.Field("damageStat").GetValue<float>(); gameObject = ((Component)component).gameObject; if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Drifter position: {1}", "[CleanupSnatcher]", gameObject.transform.position)); Log.Info(string.Format("{0} Drifter forward: {1}", "[CleanupSnatcher]", gameObject.transform.forward)); Camera main = Camera.main; Log.Info(string.Format("{0} Camera position: {1}", "[CleanupSnatcher]", (main != null) ? new Vector3?(((Component)main).transform.position) : null)); Camera main2 = Camera.main; Log.Info(string.Format("{0} Camera forward: {1}", "[CleanupSnatcher]", (main2 != null) ? new Vector3?(((Component)main2).transform.forward) : null)); } val5 = gameObject.transform.position + gameObject.transform.forward * 2f + Vector3.up * 1f; val6 = gameObject.transform.forward; if ((Object)(object)secondary.stateMachine != (Object)null) { EntityState state2 = secondary.stateMachine.state; AimMagicBag val7 = (AimMagicBag)(object)((state2 is AimMagicBag) ? state2 : null); if (val7 != null) { Traverse val8 = Traverse.Create((object)val7); object value5 = val8.Field("currentTrajectoryInfo").GetValue(); if (value5 != null) { try { Ray val9 = (Ray)value5.GetType().GetField("finalRay").GetValue(value5); val5 = ((Ray)(ref val9)).origin; val6 = ((Ray)(ref val9)).direction; if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Using AimMagicBag trajectory - position: {1}, direction: {2}", "[CleanupSnatcher]", val5, val6)); } } catch (Exception ex2) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Failed to get trajectory data: " + ex2.Message + ", using fallback"); } } } else if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] No trajectory info available, using fallback values"); } goto IL_05da; } } if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Could not find AimMagicBag state, using fallback values"); } goto IL_05da; } if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] No projectile prefab found after Cleanup execution"); } goto IL_06e5; } } if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Could not find AimMagicBag state after Cleanup execution"); } } else if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Could not find SkillLocator or Cleanup skill"); } goto IL_06e5; } return true; IL_05da: if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Final spawn position: {1}, direction: {2}", "[CleanupSnatcher]", val5, val6)); } FireProjectileInfo val10 = default(FireProjectileInfo); val10.projectilePrefab = value; val10.position = val5; val10.rotation = Util.QuaternionSafeLookRotation(val6, Vector3.up); ((FireProjectileInfo)(ref val10)).speedOverride = 0f; val10.damage = value2 * value4; val10.owner = gameObject; val10.crit = false; val10.damageColorIndex = (DamageColorIndex)0; val10.force = value3; val10.target = null; FireProjectileInfo val11 = val10; ProjectileManager.instance.FireProjectile(val11); if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Cycled projectile spawned for Repossess grab"); } goto IL_06e5; IL_06e5: return true; } } [HarmonyPatch(typeof(BaggedObject), "OnEnter")] public class BaggedObject_OnEnter_Patch { [HarmonyPostfix] public static void Postfix(BaggedObject __instance) { if ((Object)(object)_activeProjectile != (Object)null) { Traverse val = Traverse.Create((object)__instance); GameObject value = val.Field("targetObject").GetValue<GameObject>(); if ((Object)(object)value == (Object)(object)_activeProjectile) { Log.Info("[CleanupSnatcher] Active projectile grabbed: " + ((Object)_activeProjectile).name); _activeProjectile = null; } } } } [HarmonyPatch(typeof(ThrownObjectProjectileController), "ImpactBehavior")] public class ThrownObjectProjectileController_ImpactBehavior_Patch { [HarmonyPostfix] public static void Postfix(ThrownObjectProjectileController __instance) { if ((Object)(object)_activeProjectile != (Object)null && (Object)(object)((Component)__instance).gameObject == (Object)(object)_activeProjectile) { Log.Info("[CleanupSnatcher] Active projectile impacted: " + ((Object)_activeProjectile).name); _activeProjectile = null; } } } [HarmonyPatch(typeof(Object), "Destroy", new Type[] { typeof(Object) })] public class Object_Destroy_Patch { [HarmonyPrefix] public static void Prefix(Object obj) { if ((Object)(object)_activeProjectile != (Object)null) { GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null); if (val != null && (Object)(object)val == (Object)(object)_activeProjectile) { Log.Info("[CleanupSnatcher] Active projectile destroyed: " + ((Object)_activeProjectile).name); _activeProjectile = null; } } } } [HarmonyPatch(typeof(RepossessBullseyeSearch), "GetResults")] public class RepossessBullseyeSearch_GetResults_Patch { [HarmonyPostfix] public static void Postfix(ref IEnumerable<GameObject> __result) { if ((Object)(object)_activeProjectile != (Object)null) { List<GameObject> list = new List<GameObject>(__result); if (!list.Contains(_activeProjectile)) { list.Insert(0, _activeProjectile); Log.Info("[CleanupSnatcher] Force-added active projectile to repossess results: " + ((Object)_activeProjectile).name); } else { list.Remove(_activeProjectile); list.Insert(0, _activeProjectile); Log.Info("[CleanupSnatcher] Moved active projectile to front of repossess results: " + ((Object)_activeProjectile).name); } __result = list; } } } private static bool _shouldMakeNextProjectilesGrabbable; private static bool _isToggleVisualsDisplayActive; private static GameObject _activeProjectile; private static Texture GetProjectileIcon(string projectileName) { //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) string text = projectileName switch { "DrifterGrenade" => "RoR2/Base/StickyBomb/texStickyBombIcon.png", "DrifterJunkBall" => "RoR2/DLC3/Items/texJunkIcon.png", "DrifterToolbotCrate" => "RoR2/DLC3/Items/PowerCube/texPowerCubeIcon.png", "DrifterHotSauce" => "RoR2/DLC1/Molotov/texMolotovIcon.png", "DrifterKnife" => "RoR2/Base/Dagger/texDaggerIcon.png", "DrifterBubbleShield" => "RoR2/Junk/Engi/texEngiShieldSpriteCrosshair.png", "DrifterGeode" => "RoR2/DLC2/texAFUIChunkIcon.png", "DrifterBarrel" => "RoR2/Base/Common/MiscIcons/texBarrelIcon.png", "DrifterBrokenDrone" => "RoR2/Base/Drones/texDrone2Icon.png", "DrifterBrokenHAND" => "RoR2/Base/Toolbot/texToolbotIcon.png", "DrifterEvilSkull" => "RoR2/Base/AltarSkeleton/texAltarSkeletonBody.png", _ => "RoR2/Base/Common/MiscIcons/texMysteryIcon.png", }; if (!string.IsNullOrEmpty(text)) { try { Texture2D val = Addressables.LoadAssetAsync<Texture2D>((object)text).WaitForCompletion(); if ((Object)(object)val != (Object)null) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Loaded icon via Addressables: " + text); } return (Texture)(object)val; } } catch (Exception ex) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Failed to load via Addressables " + text + ": " + ex.Message + ", falling back to LegacyResourcesAPI"); } } } return null; } private static void AddSpecialObjectAttributesToProjectile(GameObject obj) { //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_054f: Unknown result type (might be due to invalid IL or missing references) //IL_0559: Unknown result type (might be due to invalid IL or missing references) //IL_055a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)obj == (Object)null) { return; } string text = ((Object)obj).name; string text2 = text.ToLowerInvariant(); if (string.IsNullOrEmpty(text)) { string text4 = (((Object)obj).name = "Projectile_" + ((Object)obj).GetInstanceID()); text = text4; text2 = text.ToLowerInvariant(); } if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Using projectile object " + ((Object)obj).name + " for SpecialObjectAttributes (original: " + text + ")"); } NetworkIdentity component = obj.GetComponent<NetworkIdentity>(); if ((Object)(object)component != (Object)null) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Target {1} already has NetworkIdentity: netId = {2}", "[CleanupSnatcher]", ((Object)obj).name, component.netId)); } } else { component = obj.AddComponent<NetworkIdentity>(); component.serverOnly = false; component.localPlayerAuthority = false; try { if (NetworkServer.active) { NetworkServer.Spawn(obj); if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Successfully spawned projectile {1} on network with netId = {2}", "[CleanupSnatcher]", ((Object)obj).name, component.netId)); } } else if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] NetworkServer not active, cannot spawn projectile " + ((Object)obj).name); } } catch (Exception ex) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Failed to spawn projectile " + ((Object)obj).name + " on network: " + ex.Message); } } if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Added NetworkIdentity to projectile {1}: netId = {2}", "[CleanupSnatcher]", ((Object)obj).name, component.netId)); } } SpecialObjectAttributes component2 = obj.GetComponent<SpecialObjectAttributes>(); if ((Object)(object)component2 != (Object)null) { if (!component2.grabbable || string.IsNullOrEmpty(component2.breakoutStateMachineName)) { component2.grabbable = true; component2.breakoutStateMachineName = ""; component2.orientToFloor = true; if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Updated existing SpecialObjectAttributes on projectile " + ((Object)obj).name); } } return; } SpecialObjectAttributes val = obj.AddComponent<SpecialObjectAttributes>(); val.renderersToDisable = new List<Renderer>(); val.behavioursToDisable = new List<MonoBehaviour>(); val.collisionToDisable = new List<GameObject>(); val.childObjectsToDisable = new List<GameObject>(); val.pickupDisplaysToDisable = new List<PickupDisplay>(); val.lightsToDisable = new List<Light>(); val.objectsToDetach = new List<GameObject>(); val.childSpecialObjectAttributes = new List<SpecialObjectAttributes>(); val.skillHighlightRenderers = new List<Renderer>(); val.soundEventsToStop = new List<AkEvent>(); val.soundEventsToPlay = new List<AkEvent>(); (float massOverride, int maxDurability) tuple = CalculateScaledAttributes(obj, text); float item = tuple.massOverride; int item2 = tuple.maxDurability; val.grabbable = true; val.massOverride = item; val.maxDurability = item2; val.durability = item2; val.hullClassification = (HullClassification)0; val.breakoutStateMachineName = ""; val.orientToFloor = true; string input = text.Replace("(Clone)", ""); Regex regex = new Regex("\\s*\\(\\d+\\)$"); input = (val.bestName = regex.Replace(input, "")); val.isVoid = text2.Contains("void"); if (PluginConfig.EnableDebugLogs.Value && val.isVoid) { Log.Info("[CleanupSnatcher] Marked projectile " + text + " as void object"); } val.portraitIcon = GetProjectileIcon(input); if (PluginConfig.EnableDebugLogs.Value && (Object)(object)val.portraitIcon != (Object)null) { Log.Info("[CleanupSnatcher] Set icon for projectile " + text); } Renderer[] componentsInChildren = obj.GetComponentsInChildren<Renderer>(false); Renderer[] array = componentsInChildren; foreach (Renderer item3 in array) { val.renderersToDisable.Add(item3); } Collider[] componentsInChildren2 = obj.GetComponentsInChildren<Collider>(false); Collider[] array2 = componentsInChildren2; foreach (Collider val2 in array2) { val.collisionToDisable.Add(((Component)val2).gameObject); } Light[] componentsInChildren3 = obj.GetComponentsInChildren<Light>(false); Light[] array3 = componentsInChildren3; foreach (Light item4 in array3) { val.lightsToDisable.Add(item4); } PickupDisplay[] componentsInChildren4 = obj.GetComponentsInChildren<PickupDisplay>(false); PickupDisplay[] array4 = componentsInChildren4; foreach (PickupDisplay item5 in array4) { val.pickupDisplaysToDisable.Add(item5); } MonoBehaviour[] componentsInChildren5 = obj.GetComponentsInChildren<MonoBehaviour>(true); MonoBehaviour[] array5 = componentsInChildren5; foreach (MonoBehaviour val3 in array5) { if ((Object)(object)val3 == (Object)null || !((Behaviour)val3).enabled) { continue; } Type type = ((object)val3).GetType(); if (!(type == typeof(NetworkIdentity)) && !(type == typeof(SpecialObjectAttributes)) && !(type == typeof(CharacterBody))) { val.behavioursToDisable.Add(val3); if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Disabled behavior: " + type.Name + " on " + text); } } } CharacterBody component3 = obj.GetComponent<CharacterBody>(); if (!((Object)(object)component3 != (Object)null)) { return; } try { component3.bodyFlags = (BodyFlags)(component3.bodyFlags & -524289); if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Cleared Ungrabbable flag on CharacterBody for projectile " + text); } } catch (Exception ex2) { if (PluginConfig.EnableDebugLogs.Value) { Log.Info("[CleanupSnatcher] Failed to clear Ungrabbable flag on CharacterBody for projectile " + text + ": " + ex2.Message); } } } private static (float massOverride, int maxDurability) CalculateScaledAttributes(GameObject obj, string objName) { float num = CalculateObjectSizeMetric(obj); float num2 = Mathf.Clamp(num / 10f, 0.5f, 5f); float num3 = 100f * num2; int num4 = Mathf.RoundToInt(8f * num2); num3 = Mathf.Max(num3, 25f); num4 = Mathf.Max(num4, 3); if (PluginConfig.EnableDebugLogs.Value) { Log.Info(string.Format("{0} Size scaling for {1}: sizeMetric={2:F2}, scaleFactor={3:F2}, mass={4:F0}, durability={5}", "[CleanupSnatcher]", objName, num, num2, num3, num4)); } return (num3, num4); } private static float CalculateObjectSizeMetric(GameObject obj) { //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_005b: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_0106: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)obj == (Object)null) { return 1f; } float num = 0f; Collider[] componentsInChildren = obj.GetComponentsInChildren<Collider>(false); Collider[] array = componentsInChildren; foreach (Collider val in array) { if ((Object)(object)val == (Object)null || !val.enabled) { continue; } BoxCollider val2 = (BoxCollider)(object)((val is BoxCollider) ? val : null); if (val2 != null) { Vector3 size = val2.size; num += size.x * size.y * size.z; continue; } SphereCollider val3 = (SphereCollider)(object)((val is SphereCollider) ? val : null); if (val3 != null) { float radius = val3.radius; num += 4.1887903f * radius * radius * radius; continue; } CapsuleCollider val4 = (CapsuleCollider)(object)((val is CapsuleCollider) ? val : null); if (val4 != null) { float radius2 = val4.radius; float height = val4.height; num += MathF.PI * radius2 * radius2 * height; continue; } MeshCollider val5 = (MeshCollider)(object)((val is MeshCollider) ? val : null); if (val5 != null) { Bounds bounds = ((Collider)val5).bounds; num += ((Bounds)(ref bounds)).size.x * ((Bounds)(ref bounds)).size.y * ((Bounds)(ref bounds)).size.z; } } return Mathf.Max(num, 0.1f); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }