Decompiled source of MemoryLeakFix v1.2.1

MemoryLeakFix.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using GTFO.API;
using Gear;
using HarmonyLib;
using IRF;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MemoryLeakFix.Handler;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("MemoryLeakFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e92aa57d27a40c3524a9c956d68eee9faf40aee2")]
[assembly: AssemblyProduct("MemoryLeakFix")]
[assembly: AssemblyTitle("MemoryLeakFix")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace MemoryLeakFix
{
	[BepInPlugin("Dinorush.MemoryLeakFix", "MemoryLeakFix", "1.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "MemoryLeakFix";

		public override void Load()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			((BasePlugin)this).Log.LogMessage((object)"Loading MemoryLeakFix");
			new Harmony("MemoryLeakFix").PatchAll();
			((BasePlugin)this).Log.LogMessage((object)"Loaded MemoryLeakFix");
			LevelAPI.OnLevelCleanup += OnLevelCleanup;
			AssetAPI.OnStartupAssetsLoaded += OnAssetsLoaded;
		}

		private void OnLevelCleanup()
		{
			Decay.s_poolHandle.Clear();
			FallingObjectHandler.Clear();
		}

		private void OnAssetsLoaded()
		{
			FallingObjectHandler.Current.EnsureInit();
		}
	}
}
namespace MemoryLeakFix.Utils
{
	internal static class DinoLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("MemoryLeakFix");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)32, (object)str);
			}
		}
	}
}
namespace MemoryLeakFix.Patches
{
	[HarmonyPatch]
	internal static class DecayPatches
	{
		private const float DecayClearDelay = 5f;

		[HarmonyPatch(typeof(Decay), "Initialize", new Type[]
		{
			typeof(SkinnedMeshRenderer),
			typeof(List<InstancedRenderFeature>)
		})]
		[HarmonyPostfix]
		private static void AddEndCallback(Decay __instance)
		{
			Decay __instance2 = __instance;
			Decay obj = __instance2;
			obj.OnDecaySafeToDespawnRenderer += Action.op_Implicit((Action)delegate
			{
				((MonoBehaviour)__instance2).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(DelayedClear(__instance2)));
			});
		}

		private static IEnumerator DelayedClear(Decay __instance)
		{
			yield return (object)new WaitForSeconds(5f);
			if ((Object)(object)__instance.m_particles != (Object)null)
			{
				__instance.m_particles.Stop(true, (ParticleSystemStopBehavior)0);
			}
			__instance.m_playing = true;
		}
	}
	[HarmonyPatch]
	internal static class FallingPatches
	{
		[HarmonyPatch(typeof(GlueClusterGrenadeInstance), "Start")]
		[HarmonyPostfix]
		private static void GlueGrenadeSpawn(GlueClusterGrenadeInstance __instance)
		{
			FallingObjectHandler.AddObject(((Component)__instance).gameObject);
		}

		[HarmonyPatch(typeof(GlowstickInstance), "Setup")]
		[HarmonyPostfix]
		private static void GlowstickSpawn(GlowstickInstance __instance)
		{
			FallingObjectHandler.AddObject(((Component)__instance).gameObject);
		}

		[HarmonyPatch(typeof(FogRepellerInstance), "Start")]
		[HarmonyPostfix]
		private static void FogRepellerSpawn(FogRepellerInstance __instance)
		{
			FallingObjectHandler.AddObject(((Component)__instance).gameObject);
		}

		[HarmonyPatch(typeof(GlueGunProjectile), "Awake")]
		[HarmonyPostfix]
		private static void GlueGunSpawn(GlueGunProjectile __instance)
		{
			GlueGunProjectile __instance2 = __instance;
			FallingObjectHandler.AddObject(((Component)__instance2).gameObject, delegate(GameObject go)
			{
				ProjectileManager.WantToDestroyGlue(go.GetComponent<GlueGunProjectile>().SyncID);
			}, () => __instance2.m_sound == null);
		}

		[HarmonyPatch(typeof(BulletWeapon), "DropMagazine")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void DropMag(BulletWeapon __instance)
		{
			Pool magDropPool = __instance.m_magDropPool;
			if (magDropPool != null)
			{
				FallingObjectHandler.AddPool(magDropPool);
				FallingObjectHandler.AddObject((magDropPool.m_freeInstances.Count > 0) ? magDropPool.m_freeInstances.First.Value : magDropPool.m_usedInstances.First.Value, (Action<GameObject>?)magDropPool.Return, (Func<bool>?)null);
			}
		}
	}
	[HarmonyPatch]
	internal static class SoundPatches
	{
		[HarmonyPatch(typeof(GlueGunProjectile), "SyncDestroy")]
		[HarmonyPrefix]
		private static void GlueGunSpawn(GlueGunProjectile __instance)
		{
			__instance.m_sound.Recycle();
		}

		[HarmonyPatch(typeof(ProjectileBase), "Collision")]
		[HarmonyPostfix]
		private static void ProjectileDestroy(ProjectileBase __instance)
		{
			__instance.m_soundPlayer.Recycle();
		}

		[HarmonyPatch(typeof(StrikerBigTentacle), "OnDead")]
		[HarmonyPostfix]
		private static void BigTentacleDead(StrikerBigTentacle __instance)
		{
			__instance.m_tipSound.Recycle();
		}
	}
}
namespace MemoryLeakFix.Handler
{
	internal sealed class FallingObjectHandler : MonoBehaviour
	{
		private static readonly Action<GameObject> BasicDestroy;

		private const int MaxSteps = 20;

		private const float UpdateInterval = 1f;

		private readonly LinkedList<(GameObject? go, Action<GameObject> destroyFunc, Func<bool>? checkFunc)> _objects = new LinkedList<(GameObject, Action<GameObject>, Func<bool>)>();

		private readonly Dictionary<IntPtr, Pool> _pools = new Dictionary<IntPtr, Pool>();

		private float _nextUpdateTime;

		private LinkedListNode<(GameObject? go, Action<GameObject> destroyFunc, Func<bool>? checkFunc)>? _currentNode;

		public static FallingObjectHandler Current { get; private set; }

		static FallingObjectHandler()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			BasicDestroy = delegate(GameObject go)
			{
				Object.Destroy((Object)(object)go);
			};
			ClassInjector.RegisterTypeInIl2Cpp<FallingObjectHandler>();
			GameObject val = new GameObject("MemoryLeakFix_FallingObjectHandler");
			Object.DontDestroyOnLoad((Object)val);
			Current = val.AddComponent<FallingObjectHandler>();
		}

		public void EnsureInit()
		{
		}

		public void Awake()
		{
			Current = this;
		}

		public static void AddObject(GameObject go, Action<GameObject>? destroyFunc = null, Func<bool>? checkFunc = null)
		{
			Current._objects.AddLast((go, destroyFunc ?? BasicDestroy, checkFunc));
		}

		public static void AddPool(Pool pool)
		{
			Current._pools.TryAdd(((Il2CppObjectBase)pool).Pointer, pool);
		}

		private void Update()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (Clock.Time < _nextUpdateTime)
			{
				return;
			}
			if (_currentNode == null)
			{
				_currentNode = _objects.First;
			}
			for (int i = 0; i < 20 && _currentNode != null; _currentNode = _currentNode.Next, i++)
			{
				GameObject item = _currentNode.Value.go;
				if ((Object)(object)item != (Object)null)
				{
					if (!(item.transform.position.y < -10000f))
					{
						Func<bool>? item2 = _currentNode.Value.checkFunc;
						if (item2 == null || !item2())
						{
							goto IL_00a6;
						}
					}
					_currentNode.Value.destroyFunc(item);
					_objects.Remove(_currentNode);
					continue;
				}
				goto IL_00a6;
				IL_00a6:
				if ((Object)(object)item == (Object)null || !item.active)
				{
					_objects.Remove(_currentNode);
				}
			}
			if (_currentNode == null)
			{
				_nextUpdateTime = Clock.Time + 1f;
			}
		}

		private void OnClear()
		{
			KeyValuePair<IntPtr, Pool>[] array = _pools.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<IntPtr, Pool> keyValuePair = array[i];
				var (key, val2) = (KeyValuePair<IntPtr, Pool>)(ref keyValuePair);
				if (val2 == null)
				{
					_pools.Remove(key);
				}
				else if (val2.m_usedInstances.Count > 0)
				{
					GameObject[] array2 = (GameObject[])(object)new GameObject[val2.m_usedInstances.Count];
					LinkedListNode<GameObject> val3 = val2.m_usedInstances.First;
					int num = 0;
					while (num < val2.m_usedInstances.Count)
					{
						array2[num] = val3.Value;
						num++;
						val3 = val3.Next;
					}
					GameObject[] array3 = array2;
					foreach (GameObject val4 in array3)
					{
						val2.Return(val4);
					}
				}
			}
			_objects.Clear();
			_currentNode = null;
		}

		public static void Clear()
		{
			Current.OnClear();
		}
	}
}