using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using BepInEx;
using Dungeonator;
using MonoMod.RuntimeDetour;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TheGarbageCollector")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Apache Modding Inc.")]
[assembly: AssemblyProduct("TheGarbageCollector")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("42932dec-6cbb-4428-aab7-35c7bee8110b")]
[assembly: AssemblyFileVersion("1.4.4.0")]
[assembly: AssemblyVersion("1.4.4.0")]
namespace TheGarbageCollector;
public class AudioResourceLoader
{
public static uint LoadedSoundBankID = 0u;
public static readonly string BankName = "GCSFX.bnk";
public static bool InitAudio()
{
return LoadBankFromModProject("TheGarbageCollector." + BankName, out LoadedSoundBankID);
}
public static bool LoadBankFromModProject(string path, out uint bankid)
{
path = path.Replace("/", ".").Replace("\\", ".");
if (!path.EndsWith(".bnk"))
{
path += ".bnk";
}
Assembly callingAssembly = Assembly.GetCallingAssembly();
bankid = 0u;
using (Stream stream = callingAssembly.GetManifestResourceStream(path))
{
if (stream != null)
{
string text = path.Substring(0, path.LastIndexOf('.'));
string bankName = path;
if (text.LastIndexOf('.') >= 0)
{
bankName = text.Substring(text.LastIndexOf('.') + 1);
}
return LoadSoundbankFromStream(stream, bankName, out bankid);
}
}
return false;
}
private static bool LoadSoundbankFromStream(Stream stream, string bankName, out uint bankID)
{
//IL_0011: 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_002d: 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_0039: Invalid comparison between Unknown and I4
byte[] array = StreamToByteArray(stream);
IntPtr intPtr = Marshal.AllocHGlobal(array.Length);
AKRESULT val = (AKRESULT)2;
bankID = 0u;
try
{
Marshal.Copy(array, 0, intPtr, array.Length);
val = AkSoundEngine.LoadAndDecodeBankFromMemory(intPtr, (uint)array.Length, false, bankName, false, ref bankID);
}
finally
{
Marshal.FreeHGlobal(intPtr);
}
return (int)val == 1;
}
private static byte[] StreamToByteArray(Stream input)
{
byte[] array = new byte[16384];
using MemoryStream memoryStream = new MemoryStream();
int count;
while ((count = input.Read(array, 0, array.Length)) > 0)
{
memoryStream.Write(array, 0, count);
}
return memoryStream.ToArray();
}
}
public class GCFoyer : BraveBehaviour
{
private enum State
{
PreFoyerCheck,
EnableMod,
Exit
}
private State m_State;
public GCFoyer()
{
m_State = State.PreFoyerCheck;
}
public void Awake()
{
}
public void Start()
{
}
public void Update()
{
switch (m_State)
{
case State.PreFoyerCheck:
if (!Foyer.DoIntroSequence || !Foyer.DoMainMenu)
{
m_State = State.EnableMod;
}
break;
case State.EnableMod:
{
int @int = PlayerPrefs.GetInt(TheGarbageCollector.GarbageCollectorMemoryCap);
if (@int >= 1024)
{
GC_Manager.MemoryGrowthAllowence = @int;
if (@int >= 8196)
{
TheGarbageCollector.disableMonitor = true;
}
}
else
{
GC_Manager.MemoryGrowthAllowence = TheGarbageCollector.GetBestMemoryCap;
if (SystemInfo.systemMemorySize > 24576)
{
TheGarbageCollector.disableMonitor = true;
}
}
if (PlayerPrefs.GetInt(TheGarbageCollector.GarbageCollectorToggleName) == 1)
{
TheGarbageCollector.DisableGC = false;
break;
}
if (TheGarbageCollector.DisableGC)
{
ETGModConsole.Log((object)(TheGarbageCollector.ModNameInRed + "TheGarbageCollector is currently enabled. Use command 'garbagecolletor toggle' disable the mod."), false);
if (GC_Manager.load_mono_gc())
{
TheGarbageCollector.ToggleHooksAndGC(state: true);
if (SystemInfo.systemMemorySize < 8196)
{
ETGModConsole.Log((object)(TheGarbageCollector.ModNameInRed + "Warning: Your computer was detected as having 8GB or less ram. It is recommended only to enable this mod on machines with more then 8GB of ram!"), true);
}
}
}
else
{
ETGModConsole.Log((object)(TheGarbageCollector.ModNameInRed + "TheGarbageCollector is currently disabled. Use command 'garbagecolletor toggle' to enable TheGarbageCollector and disable Unity's GarbageCollector."), false);
}
m_State = State.Exit;
break;
}
case State.Exit:
if (Object.op_Implicit((Object)(object)((Component)this).gameObject))
{
Object.Destroy((Object)(object)((Component)this).gameObject);
}
break;
}
}
protected override void OnDestroy()
{
((BraveBehaviour)this).OnDestroy();
}
}
public class GCStats : MonoBehaviour
{
public static GameObject GCStatsObject;
public bool ShowGcData;
public Vector3 UIPosition;
public StringBuilder stringBuilder;
private dfLabel m_label;
private bool IsRedText;
private bool WaitingForCollection;
private Color32 WhiteColor;
private Color32 RedColor;
private float AllocationLimit;
public static GCStats Instance
{
get
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
if (!Object.op_Implicit((Object)(object)GCStatsObject))
{
GCStatsObject = new GameObject("GCStats")
{
layer = 14
};
Object.DontDestroyOnLoad((Object)(object)GCStatsObject);
}
return GameObjectExtensions.GetOrAddComponent<GCStats>(GCStatsObject);
}
}
public GCStats()
{
//IL_001d: 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_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: 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_005c: Unknown result type (might be due to invalid IL or missing references)
ShowGcData = false;
UIPosition = new Vector3(-710f, 130f, 0f);
RedColor = new Color32((byte)190, (byte)160, (byte)0, byte.MaxValue);
WhiteColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
IsRedText = false;
WaitingForCollection = false;
}
private void SetupLabel()
{
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: 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)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0202: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_0219: Unknown result type (might be due to invalid IL or missing references)
//IL_022e: Unknown result type (might be due to invalid IL or missing references)
//IL_0239: Unknown result type (might be due to invalid IL or missing references)
//IL_023e: Unknown result type (might be due to invalid IL or missing references)
//IL_0245: Unknown result type (might be due to invalid IL or missing references)
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
//IL_0253: Unknown result type (might be due to invalid IL or missing references)
//IL_025f: Expected O, but got Unknown
//IL_027e: Unknown result type (might be due to invalid IL or missing references)
GameUIRoot instance = GameUIRoot.Instance;
if (Object.op_Implicit((Object)(object)((instance != null) ? instance.Manager : null)))
{
AssetBundle obj = ResourceManager.LoadAssetBundle("shared_auto_001");
dfTiledSprite component = obj.LoadAsset<GameObject>("Weapon Skull Ammo FG").GetComponent<dfTiledSprite>();
dfFont component2 = obj.LoadAsset<GameObject>("04b03_df40").GetComponent<dfFont>();
dfLabel val = GameUIRoot.Instance.Manager.AddControl<dfLabel>();
val.Atlas = ((dfSprite)component).Atlas;
val.Font = (dfFontBase)(object)component2;
((dfControl)val).Anchor = (dfAnchorStyle)6;
((dfControl)val).IsEnabled = true;
((dfControl)val).IsVisible = false;
((dfControl)val).IsInteractive = true;
((dfControl)val).Tooltip = string.Empty;
((dfControl)val).Pivot = (dfPivotPoint)6;
((dfControl)val).zindex = 29;
((dfControl)val).Opacity = 0.5f;
((dfControl)val).Color = Color32.op_Implicit(Color.white);
((dfControl)val).DisabledColor = new Color32((byte)128, (byte)128, (byte)128, byte.MaxValue);
((dfControl)val).Size = new Vector2(350f, 120f);
((dfControl)val).MinimumSize = ((dfControl)val).Size;
((dfControl)val).MaximumSize = new Vector2(400f, 240f);
((dfControl)val).ClipChildren = false;
((dfControl)val).InverseClipChildren = false;
((dfControl)val).TabIndex = -1;
((dfControl)val).CanFocus = false;
((dfControl)val).AutoFocus = false;
((dfControl)val).IsLocalized = false;
((dfControl)val).HotZoneScale = Vector2.one;
((dfControl)val).AllowSignalEvents = true;
((dfControl)val).PrecludeUpdateCycle = false;
val.PerCharacterOffset = Vector2.op_Implicit(Vector2.zero);
val.PreventFontChanges = true;
val.BackgroundSprite = string.Empty;
val.BackgroundColor = Color32.op_Implicit(Color.white);
val.AutoSize = true;
val.AutoHeight = false;
val.WordWrap = false;
val.Text = "PLACEHOLDER";
val.BottomColor = Color32.op_Implicit(Color.white);
val.TextAlignment = (TextAlignment)0;
val.VerticalAlignment = (dfVerticalAlignment)0;
val.TextScale = 0.5f;
val.TextScaleMode = (dfTextScaleMode)0;
val.CharacterSpacing = 0;
val.ColorizeSymbols = false;
val.ProcessMarkup = false;
val.Outline = false;
val.OutlineSize = 0;
val.ShowGradient = false;
val.OutlineColor = Color32.op_Implicit(Color.black);
val.Shadow = false;
val.ShadowColor = Color32.op_Implicit(Color.black);
val.ShadowOffset = new Vector2(1f, -1f);
val.Padding = new RectOffset
{
left = 0,
right = 0,
top = 0,
bottom = 0
};
val.TabSize = 48;
val.MaintainJapaneseFont = false;
val.MaintainKoreanFont = false;
val.MaintainRussianFont = false;
((dfControl)val).Position = UIPosition;
m_label = val;
component2 = null;
component = null;
}
}
private void Start()
{
stringBuilder = new StringBuilder(500);
AllocationLimit = GC_Manager.MemoryGrowthAllowence;
}
protected void Update()
{
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
if (ShowGcData && GC_Manager.d_gc_disabled)
{
if (!Object.op_Implicit((Object)(object)m_label))
{
SetupLabel();
}
if (!Object.op_Implicit((Object)(object)m_label))
{
return;
}
if (!((dfControl)m_label).IsVisible)
{
((dfControl)m_label).IsVisible = true;
}
if (GC_Manager.Instance.AllocatedMemorySinceLastCollection != -1)
{
AllocationLimit = Mathf.Max(AllocationLimit, (float)GC_Manager.Instance.AllocatedMemorySinceLastCollection);
}
if ((float)GC_Manager.GetTotalMemoryAllocatedInMB >= AllocationLimit)
{
if (!WaitingForCollection)
{
WaitingForCollection = true;
}
if (!IsRedText)
{
((dfControl)m_label).Color = RedColor;
IsRedText = true;
}
}
else
{
if (WaitingForCollection)
{
WaitingForCollection = false;
}
if (IsRedText)
{
((dfControl)m_label).Color = WhiteColor;
IsRedText = false;
}
}
stringBuilder.Length = 0;
stringBuilder.AppendFormat("Current Allocation: {0:0} MB / {1:0} MB\n", GC_Manager.GetTotalMemoryAllocatedInMB, AllocationLimit);
stringBuilder.AppendFormat("Current Heap Size: {0:0} MB\n", ProfileUtils.GetMonoHeapSize() / 1024 / 1024);
stringBuilder.AppendFormat("Time Since Last In Combat: {0: 00} sec\n", Time.realtimeSinceStartup - GC_Manager.Instance.LastInCombatTime);
if (Time.realtimeSinceStartup - GC_Manager.Instance.LastUnpausedTime > 0.1f)
{
stringBuilder.AppendFormat("Time Spent In Pause Screen: {0: 00} sec\n", Time.realtimeSinceStartup - GC_Manager.Instance.LastUnpausedTime);
}
stringBuilder.AppendFormat("Time Since Last Collection: {0: 00} sec\n", Time.realtimeSinceStartup - GC_Manager.Instance.LastCollectionTime);
stringBuilder.AppendFormat("Total Collections: {0}\n", ProfileUtils.GetMonoCollectionCount());
if (WaitingForCollection)
{
stringBuilder.Append("Waiting to do a Collection...\n");
}
else if (TheGarbageCollector.disableMonitor)
{
stringBuilder.Append("GC Monitor is Disabled.\n");
}
m_label.Text = stringBuilder.ToString();
}
else if (!ShowGcData && GC_Manager.d_gc_disabled && Object.op_Implicit((Object)(object)m_label) && ((dfControl)m_label).IsVisible)
{
((dfControl)m_label).IsVisible = false;
}
}
}
public class GC_Manager : MonoBehaviour
{
public static FieldInfo LastGcTime = typeof(BraveMemory).GetField("LastGcTime", BindingFlags.Static | BindingFlags.NonPublic);
private static FieldInfo m_stringBuilder = typeof(HUDGC).GetField("stringBuilder", BindingFlags.Instance | BindingFlags.NonPublic);
public static int offset_mono_gc_disable = 111376;
public static int offset_mono_gc_enable = 111384;
public static int offset_mono_gc_collect = 111300;
public static int MemoryGrowthAllowence = 2048;
public long AllocatedMemorySinceLastCollection;
public static Action mono_gc_disable;
public static Action mono_gc_enable;
public static Action mono_gc_collect;
public static bool d_gc_disabled = false;
private static bool mono_gc_loaded = false;
public bool turn_off_mono_gc;
public bool CanDoCollectionNow;
private bool DoManualCollection;
public float PauseTimeTillManualCollection;
public float OutOfCombatTimeTillManualCollection;
public float LastUnpausedTime;
public float LastInCombatTime;
public float LastCollectionTime;
private float AllocationLimit;
private int[] dummy_object;
public static GC_Manager Instance
{
get
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
GameObject gCManagerObject = TheGarbageCollector.GCManagerObject;
if (!Object.op_Implicit((Object)(object)((gCManagerObject != null) ? gCManagerObject.GetComponent<GC_Manager>() : null)) && !Object.op_Implicit((Object)(object)TheGarbageCollector.GCManagerObject))
{
TheGarbageCollector.GCManagerObject = new GameObject("TheGarbageCollector");
Object.DontDestroyOnLoad((Object)(object)TheGarbageCollector.GCManagerObject);
}
return GameObjectExtensions.GetOrAddComponent<GC_Manager>(TheGarbageCollector.GCManagerObject);
}
}
public static long GetTotalMemoryAllocatedInMB => GC.GetTotalMemory(forceFullCollection: false) / 1024 / 1024;
public GC_Manager()
{
turn_off_mono_gc = false;
LastInCombatTime = 0f;
LastUnpausedTime = 0f;
DoManualCollection = false;
CanDoCollectionNow = false;
PauseTimeTillManualCollection = 120f;
OutOfCombatTimeTillManualCollection = 300f;
AllocatedMemorySinceLastCollection = -1L;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
public static bool load_mono_gc()
{
if (mono_gc_loaded)
{
return true;
}
IntPtr moduleHandle = GetModuleHandle("mono.dll");
IntPtr intPtr = new IntPtr(moduleHandle.ToInt64() + offset_mono_gc_collect);
IntPtr procAddress = GetProcAddress(moduleHandle, "mono_gc_collect");
if (intPtr != procAddress)
{
ETGModConsole.Log((object)("[TheGarbageCollector] Cannot load GarbageCollector functions. Expected mono's collect at " + intPtr.ToInt64() + " Actual at " + intPtr.ToInt64() + " Module root " + moduleHandle.ToInt64()), true);
return false;
}
mono_gc_enable = (Action)Marshal.GetDelegateForFunctionPointer(new IntPtr(moduleHandle.ToInt64() + offset_mono_gc_enable), typeof(Action));
mono_gc_disable = (Action)Marshal.GetDelegateForFunctionPointer(new IntPtr(moduleHandle.ToInt64() + offset_mono_gc_disable), typeof(Action));
mono_gc_collect = (Action)Marshal.GetDelegateForFunctionPointer(new IntPtr(moduleHandle.ToInt64() + offset_mono_gc_collect), typeof(Action));
mono_gc_loaded = true;
return true;
}
public void Disable()
{
mono_gc_enable();
d_gc_disabled = false;
turn_off_mono_gc = false;
}
public void Enable()
{
mono_gc_disable();
d_gc_disabled = true;
turn_off_mono_gc = true;
}
public void DoCollect()
{
if (d_gc_disabled)
{
Collect();
return;
}
LastGcTime.SetValue(typeof(BraveMemory), Time.realtimeSinceStartup);
GC.Collect();
}
private void Collect()
{
if (GCStats.Instance.ShowGcData && !Dungeon.IsGenerating && Object.op_Implicit((Object)(object)GameManager.Instance) && !GameManager.Instance.IsLoadingLevel && Object.op_Implicit((Object)(object)((Component)ETGModMainBehaviour.Instance).gameObject))
{
AkSoundEngine.PostEvent(TheGarbageCollector.ModSoundEventName, ((Component)ETGModMainBehaviour.Instance).gameObject);
}
int monoCollectionCount = ProfileUtils.GetMonoCollectionCount();
mono_gc_enable();
for (int i = 0; i < 100; i++)
{
dummy_object = new int[1];
dummy_object[0] = 0;
}
if (ProfileUtils.GetMonoCollectionCount() == monoCollectionCount)
{
LastGcTime.SetValue(null, Time.realtimeSinceStartup);
LastCollectionTime = Time.realtimeSinceStartup;
GC.Collect();
}
mono_gc_disable();
AllocatedMemorySinceLastCollection = GetTotalMemoryAllocatedInMB;
if (GCStats.Instance.ShowGcData && !Dungeon.IsGenerating && Object.op_Implicit((Object)(object)GameManager.Instance) && !GameManager.Instance.IsLoadingLevel && GCStats.Instance.stringBuilder != null)
{
Debug.Log((object)"TheGarbageCollector Collection ran. Last GC Stats:");
Debug.Log((object)GCStats.Instance.stringBuilder);
}
}
private void Start()
{
}
protected void Update()
{
if (!d_gc_disabled | Dungeon.IsGenerating | (Object.op_Implicit((Object)(object)GameManager.Instance) && GameManager.Instance.IsLoadingLevel))
{
return;
}
if (GameManager.Instance.IsPaused)
{
if (LastUnpausedTime > 0.1f && Time.realtimeSinceStartup - LastUnpausedTime > PauseTimeTillManualCollection)
{
DoManualCollection = true;
LastUnpausedTime = Time.realtimeSinceStartup;
}
}
else
{
DoManualCollection = false;
LastUnpausedTime = Time.realtimeSinceStartup;
}
if (Object.op_Implicit((Object)(object)GameManager.Instance.PrimaryPlayer) && !GameManager.Instance.IsPaused)
{
if (GameManager.Instance.PrimaryPlayer.IsInCombat)
{
LastInCombatTime = Time.realtimeSinceStartup;
DoManualCollection = false;
}
else if (LastInCombatTime > 0f && Time.realtimeSinceStartup - LastInCombatTime > OutOfCombatTimeTillManualCollection)
{
DoManualCollection = true;
LastInCombatTime = Time.realtimeSinceStartup;
}
else
{
DoManualCollection = false;
}
}
GameManager instance = GameManager.Instance;
if (Object.op_Implicit((Object)(object)((instance != null) ? instance.PrimaryPlayer : null)) && GameManager.Instance.PrimaryPlayer.IsInCombat)
{
CanDoCollectionNow = false;
}
else
{
CanDoCollectionNow = true;
}
AllocationLimit = MemoryGrowthAllowence;
if (AllocatedMemorySinceLastCollection != -1)
{
AllocationLimit = Mathf.Max(AllocationLimit, (float)AllocatedMemorySinceLastCollection);
}
if (DoManualCollection | (!TheGarbageCollector.disableMonitor && CanDoCollectionNow && (float)GetTotalMemoryAllocatedInMB >= AllocationLimit))
{
Collect();
DoManualCollection = false;
CanDoCollectionNow = false;
}
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("ApacheThunder.etg.TheGarbageCollector", "TheGarbageCollector", "1.4.4")]
public class TheGarbageCollector : BaseUnityPlugin
{
public static bool DisableGC = true;
public static bool disableMonitor = false;
public const string GUID = "ApacheThunder.etg.TheGarbageCollector";
public const string ModName = "TheGarbageCollector";
public const string VERSION = "1.4.4";
public static readonly string ConsoleCommandName = "garbagecollector";
public static readonly string GarbageCollectorToggleName = "TheGarbageCollectorDisabled";
public static readonly string GarbageCollectorMemoryCap = "TheGarbageCollectorMemCap";
public static readonly string ModNameInRed = "<color=#00FF00>[TheGarbageCollector]</color> ";
public static readonly string ModSoundEventName = "Play_TrashMan_01";
public static string FolderPath;
public static Hook BraveMemoryCollectHook;
public static Hook clearLevelDataHook;
public static Hook gameManagerHook;
public static GameObject GCManagerObject;
public static GameObject GCFoyerCheckerOBJ;
public static int GetBestMemoryCap
{
get
{
if (SystemInfo.systemMemorySize > 24576)
{
return 8196;
}
if (SystemInfo.systemMemorySize > 12288)
{
return 5120;
}
if (SystemInfo.systemMemorySize > 8196)
{
return 3072;
}
return 2048;
}
}
public void Start()
{
ETGModMainBehaviour.WaitForGameManagerStart((Action<GameManager>)GMStart);
}
public void GMStart(GameManager gameManager)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Invalid comparison between Unknown and I4
FolderPath = ETGMod.FolderPath((BaseUnityPlugin)(object)this);
if ((int)Application.platform != 2)
{
ETGModConsole.Log((object)(ModNameInRed + "ERROR: Linux/MacOS/Other version of the game detected!. This mod only supports the Windows version of ETG!"), false);
return;
}
if (!AudioResourceLoader.InitAudio())
{
ETGModConsole.Log((object)(ModNameInRed + "WARNING: Failed to load custom sound bank!"), false);
}
ETGModConsole.Commands.AddGroup(ConsoleCommandName, (Action<string[]>)ConsoleInfo);
ETGModConsole.Commands.GetGroup(ConsoleCommandName).AddUnit("toggle", (Action<string[]>)ToggleGCSetting);
ETGModConsole.Commands.GetGroup(ConsoleCommandName).AddUnit("collect", (Action<string[]>)DoACollect);
ETGModConsole.Commands.GetGroup(ConsoleCommandName).AddUnit("stats", (Action<string[]>)ToggleGCStats);
ETGModConsole.Commands.GetGroup(ConsoleCommandName).AddUnit("setmemcap", (Action<string[]>)SetMemoryCap);
CreateFoyerController();
}
public static void CreateFoyerController()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
if (!Object.op_Implicit((Object)(object)GCFoyerCheckerOBJ))
{
GCFoyerCheckerOBJ = new GameObject("TheGarbageCollector Foyer Checker", new Type[1] { typeof(GCFoyer) });
}
}
private void GameManager_Awake(Action<GameManager> orig, GameManager self)
{
orig(self);
self.OnNewLevelFullyLoaded += OnLevelFullyLoaded;
}
public static void OnLevelFullyLoaded()
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Expected O, but got Unknown
if (DisableGC && Object.op_Implicit((Object)(object)GC_Manager.Instance) && GC_Manager.d_gc_disabled)
{
if (gameManagerHook == null)
{
gameManagerHook = new Hook((MethodBase)typeof(GameManager).GetMethod("Awake", BindingFlags.Instance | BindingFlags.NonPublic), typeof(TheGarbageCollector).GetMethod("GameManager_Awake", BindingFlags.Instance | BindingFlags.NonPublic), (object)typeof(GameManager));
}
GC_Manager.Instance.DoCollect();
}
}
private void ConsoleInfo(string[] consoleText)
{
if (ETGModConsole.Commands.GetGroup(ConsoleCommandName) == null || ETGModConsole.Commands.GetGroup(ConsoleCommandName).GetAllUnitNames() == null)
{
return;
}
List<string> list = new List<string>();
string[] allUnitNames = ETGModConsole.Commands.GetGroup(ConsoleCommandName).GetAllUnitNames();
foreach (string item in allUnitNames)
{
list.Add(item);
}
if (list.Count <= 0)
{
return;
}
if (!m_IsCommandValid(consoleText, string.Empty, string.Empty))
{
ETGModConsole.Log((object)"[TheGarbageCollector] No sub command specified! The following console commands are available for TheGarbageCollector:\n", false);
{
foreach (string item2 in list)
{
ETGModConsole.Log((object)(" " + item2 + "\n"), false);
}
return;
}
}
if (list.Contains(consoleText[0].ToLower()))
{
return;
}
ETGModConsole.Log((object)"[TheGarbageCollector] Invalid sub-command! The following console commands are available for TheGarbageCollector:\n", false);
foreach (string item3 in list)
{
ETGModConsole.Log((object)(" " + item3 + "\n"), false);
}
}
private bool m_IsCommandValid(string[] CommandText, string validCommands, string sourceSubCommand)
{
if (CommandText == null)
{
if (!string.IsNullOrEmpty(validCommands) && !string.IsNullOrEmpty(sourceSubCommand))
{
ETGModConsole.Log((object)("[TheGarbageCollector] [" + sourceSubCommand + "] ERROR: Invalid console command specified! Valid Sub-Commands: \n" + validCommands), false);
}
return false;
}
if (CommandText.Length == 0)
{
if (!string.IsNullOrEmpty(validCommands) && !string.IsNullOrEmpty(sourceSubCommand))
{
ETGModConsole.Log((object)("[TheGarbageCollector] [" + sourceSubCommand + "] No sub-command specified. Valid Sub-Commands: \n" + validCommands), false);
}
return false;
}
if (string.IsNullOrEmpty(CommandText[0]))
{
if (!string.IsNullOrEmpty(validCommands) && !string.IsNullOrEmpty(sourceSubCommand))
{
ETGModConsole.Log((object)("[TheGarbageCollector] [" + sourceSubCommand + "] No sub-command specified. Valid Sub-Commands: \n" + validCommands), false);
}
return false;
}
if (CommandText.Length > 1)
{
if (!string.IsNullOrEmpty(validCommands) && !string.IsNullOrEmpty(sourceSubCommand))
{
ETGModConsole.Log((object)("[TheGarbageCollector] [" + sourceSubCommand + "] ERROR: Only one sub-command is accepted!. Valid Commands: \n" + validCommands), false);
}
return false;
}
return true;
}
private void ToggleGCSetting(string[] consoleText)
{
if (!Object.op_Implicit((Object)(object)Foyer.Instance) | Foyer.DoIntroSequence | Foyer.DoMainMenu)
{
ETGModConsole.Log((object)"[TheGarbageCollector] Warning: Please wait until the foyer is loaded before trying to enable/disable the mod!", false);
return;
}
if (!DisableGC)
{
DisableGC = true;
if (GC_Manager.load_mono_gc())
{
AkSoundEngine.PostEvent(ModSoundEventName, ((Component)ETGModMainBehaviour.Instance).gameObject);
ToggleHooksAndGC(DisableGC);
if (SystemInfo.systemMemorySize < 8196)
{
ETGModConsole.Log((object)"[TheGarbageCollector] Warning: Your computer was detected as having 8GB or less ram. It is recommended only to use this feature on machines with more then 8GB of ram!", false);
}
ETGModConsole.Log((object)"[TheGarbageCollector] TheGarbageCollector mod is now enabled.\nNow will only do collections during floor loads and if player is AFK or been in pause menu for more then 30 seconds!", false);
}
PlayerPrefs.SetInt(GarbageCollectorToggleName, 0);
}
else
{
DisableGC = false;
ToggleHooksAndGC(DisableGC);
ETGModConsole.Log((object)"[TheGarbageCollector] TheGarbageCollector mod is now disabled.\nUnity's GC will now run normally!", false);
PlayerPrefs.SetInt(GarbageCollectorToggleName, 1);
}
PlayerPrefs.Save();
}
private void ToggleGCStats(string[] consoleText)
{
if (GCStats.Instance.ShowGcData)
{
GCStats.Instance.ShowGcData = false;
ETGModConsole.Log((object)(ModNameInRed + "GC Stats disabled!"), false);
}
else
{
GCStats.Instance.ShowGcData = true;
ETGModConsole.Log((object)(ModNameInRed + "GC Stats enabled!"), false);
}
}
private void DoACollect(string[] consoleText)
{
ETGModConsole.Log((object)"TheGarbageCollector Doing a Collection", false);
if (Object.op_Implicit((Object)(object)GameManager.Instance) && Object.op_Implicit((Object)(object)GameManager.Instance.PrimaryPlayer))
{
AkSoundEngine.PostEvent(ModSoundEventName, ((Component)GameManager.Instance.PrimaryPlayer).gameObject);
}
else
{
AkSoundEngine.PostEvent(ModSoundEventName, ((Component)ETGModMainBehaviour.Instance).gameObject);
}
if (DisableGC)
{
GC_Manager.Instance.DoCollect();
}
else
{
BraveMemory.DoCollect();
}
}
private void SetMemoryCap(string[] consoleText)
{
if (consoleText != null && consoleText.Length == 1)
{
int num = int.Parse(consoleText[0]);
bool flag = false;
if (num < 1024)
{
num = GetBestMemoryCap;
flag = true;
}
if (num >= 8196)
{
disableMonitor = true;
}
else
{
disableMonitor = false;
}
GC_Manager.MemoryGrowthAllowence = num;
PlayerPrefs.SetInt(GarbageCollectorMemoryCap, num);
PlayerPrefs.Save();
if (flag)
{
ETGModConsole.Log((object)(ModNameInRed + "Memory allocation limit manually set. To allow this to be auto set again, set it to a value below 1024!"), false);
}
else
{
ETGModConsole.Log((object)(ModNameInRed + "Requested memory cap is below minimum allowed value.\nMemory cap is now set to Auto based on your current system memory spec."), false);
}
}
else
{
ETGModConsole.Log((object)(ModNameInRed + "No memory value specified. Please specify a memory limit you want to use!"), false);
}
}
public static void ToggleHooksAndGC(bool state)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Expected O, but got Unknown
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Expected O, but got Unknown
if (state)
{
GC_Manager.Instance.Enable();
if (BraveMemoryCollectHook == null)
{
BraveMemoryCollectHook = new Hook((MethodBase)typeof(BraveMemory).GetMethod("DoCollect", BindingFlags.Static | BindingFlags.Public), typeof(TheGarbageCollector).GetMethod("DoCollect", BindingFlags.Static | BindingFlags.Public));
}
if (clearLevelDataHook == null)
{
clearLevelDataHook = new Hook((MethodBase)typeof(GameManager).GetMethod("ClearPerLevelData", BindingFlags.Instance | BindingFlags.Public), typeof(TheGarbageCollector).GetMethod("ClearPerLevelDataHook", BindingFlags.Instance | BindingFlags.Public), (object)typeof(GameManager));
}
GameManager.Instance.OnNewLevelFullyLoaded += OnLevelFullyLoaded;
return;
}
GC_Manager.Instance.Disable();
if (BraveMemoryCollectHook != null)
{
BraveMemoryCollectHook.Dispose();
BraveMemoryCollectHook = null;
}
if (clearLevelDataHook != null)
{
clearLevelDataHook.Dispose();
clearLevelDataHook = null;
}
if (gameManagerHook != null)
{
gameManagerHook.Dispose();
gameManagerHook = null;
}
GameManager.Instance.OnNewLevelFullyLoaded -= OnLevelFullyLoaded;
}
public void ClearPerLevelDataHook(Action<GameManager> orig, GameManager self)
{
orig(self);
if (DisableGC && GC_Manager.d_gc_disabled && GC_Manager.load_mono_gc())
{
GC_Manager.Instance.DoCollect();
}
}
public static void DoCollect()
{
if (!GC_Manager.d_gc_disabled || GameManager.Instance.IsLoadingLevel)
{
if (GC_Manager.d_gc_disabled)
{
GC_Manager.Instance.DoCollect();
return;
}
GC_Manager.LastGcTime.SetValue(typeof(BraveMemory), Time.realtimeSinceStartup);
GC.Collect();
}
}
}