Decompiled source of MicroOptimizer v1.0.4

BepInEx/plugins/MicroOptimizer.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using MicroOptimizer.Patches;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[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("MicroOptimizer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Micro-optimizations for smoother gameplay")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4")]
[assembly: AssemblyProduct("MicroOptimizer")]
[assembly: AssemblyTitle("MicroOptimizer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MicroOptimizer
{
	[BepInPlugin("mrbub.microoptimizer", "MicroOptimizer", "1.0.4")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		internal static ConfigFile ConfigFile;

		internal static ConfigEntry<bool> OptimizeStringAllocations;

		internal static ConfigEntry<bool> CacheRepeatedLookups;

		internal static ConfigEntry<bool> OptimizeShipItemCollection;

		internal static ConfigEntry<bool> EnableDebugLogging;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			ConfigFile = ((BaseUnityPlugin)this).Config;
			InitializeConfig();
			Harmony val = new Harmony("mrbub.microoptimizer");
			if (OptimizeStringAllocations.Value)
			{
				val.PatchAll(typeof(StringOptimizationPatches));
				Logger.LogInfo((object)"String allocation optimization enabled");
			}
			if (CacheRepeatedLookups.Value)
			{
				val.PatchAll(typeof(ComponentLookupPatches));
				Logger.LogInfo((object)"Component lookup caching enabled");
			}
			if (OptimizeShipItemCollection.Value)
			{
				val.PatchAll(typeof(ShipItemOptimizationPatches));
				Logger.LogInfo((object)"Ship item collection optimization enabled");
			}
			Logger.LogInfo((object)"MicroOptimizer v1.0.4 loaded successfully!");
		}

		private void InitializeConfig()
		{
			EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLogging", false, "Enable detailed logging for debugging (creates more log spam)");
			OptimizeStringAllocations = ((BaseUnityPlugin)this).Config.Bind<bool>("Strings", "OptimizeStringAllocations", true, "Use StringBuilder for string formatting to reduce allocations");
			CacheRepeatedLookups = ((BaseUnityPlugin)this).Config.Bind<bool>("Caching", "CacheRepeatedLookups", true, "Cache NetworkObject lookups during enemy and scrap spawning");
			OptimizeShipItemCollection = ((BaseUnityPlugin)this).Config.Bind<bool>("Optimization", "OptimizeShipItemCollection", true, "Use HashSet instead of List.Contains() for O(1) scrap collection lookups");
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "mrbub.microoptimizer";

		public const string PLUGIN_NAME = "MicroOptimizer";

		public const string PLUGIN_VERSION = "1.0.4";
	}
}
namespace MicroOptimizer.Patches
{
	[HarmonyPatch]
	internal class CollisionCachePatches
	{
		private static readonly Dictionary<GameObject, PlayerControllerB> playerControllerCache = new Dictionary<GameObject, PlayerControllerB>();

		public static PlayerControllerB GetCachedPlayerController(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			if (!playerControllerCache.TryGetValue(gameObject, out var value))
			{
				value = gameObject.GetComponent<PlayerControllerB>();
				if ((Object)(object)value != (Object)null)
				{
					playerControllerCache[gameObject] = value;
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("Cached new PlayerControllerB for " + ((Object)gameObject).name));
					}
				}
			}
			else
			{
				if ((Object)(object)value == (Object)null)
				{
					playerControllerCache.Remove(gameObject);
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("Removed destroyed PlayerControllerB from cache for " + ((Object)gameObject).name));
					}
					return null;
				}
				if (Plugin.EnableDebugLogging.Value)
				{
					Plugin.Logger.LogDebug((object)("Retrieved cached PlayerControllerB for " + ((Object)gameObject).name));
				}
			}
			return value;
		}

		[HarmonyPatch(typeof(QuicksandTrigger), "OnTriggerStay")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> QuicksandTriggerStayTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(GameObject), "GetComponent", (Type[])null, new Type[1] { typeof(PlayerControllerB) });
			MethodInfo methodInfo2 = AccessTools.Method(typeof(CollisionCachePatches), "GetCachedPlayerController", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Plugin.Logger.LogWarning((object)"Could not find methods for PlayerControllerB caching in OnTriggerStay");
				return list;
			}
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo2);
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Logger.LogInfo((object)$"Replaced {num} GetComponent<PlayerControllerB> calls in OnTriggerStay");
			}
			else if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogWarning((object)"No GetComponent<PlayerControllerB> calls found in OnTriggerStay to replace");
			}
			return list;
		}

		[HarmonyPatch(typeof(QuicksandTrigger), "OnTriggerExit")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> QuicksandTriggerExitTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(GameObject), "GetComponent", (Type[])null, new Type[1] { typeof(PlayerControllerB) });
			MethodInfo methodInfo2 = AccessTools.Method(typeof(CollisionCachePatches), "GetCachedPlayerController", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Plugin.Logger.LogWarning((object)"Could not find methods for PlayerControllerB caching in OnTriggerExit");
				return list;
			}
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo2);
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Logger.LogInfo((object)$"Replaced {num} GetComponent<PlayerControllerB> calls in OnTriggerExit");
			}
			else if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogWarning((object)"No GetComponent<PlayerControllerB> calls found in OnTriggerExit to replace");
			}
			return list;
		}

		[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
		[HarmonyPostfix]
		private static void ClearCacheOnLevelChange()
		{
			int count = playerControllerCache.Count;
			playerControllerCache.Clear();
			if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogDebug((object)$"Cleared {count} PlayerControllerB cache entries on level change");
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
		[HarmonyPostfix]
		private static void ClearCacheOnShipReset()
		{
			int count = playerControllerCache.Count;
			playerControllerCache.Clear();
			if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogDebug((object)$"Cleared {count} PlayerControllerB cache entries on ship reset");
			}
		}
	}
	[HarmonyPatch]
	internal class ComponentLookupPatches
	{
		private static readonly Dictionary<GameObject, NetworkObject> networkObjectCache = new Dictionary<GameObject, NetworkObject>();

		public static NetworkObject GetCachedNetworkObject(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			if (!networkObjectCache.TryGetValue(gameObject, out var value))
			{
				value = gameObject.GetComponent<NetworkObject>();
				if ((Object)(object)value != (Object)null)
				{
					networkObjectCache[gameObject] = value;
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("Cached new NetworkObject for " + ((Object)gameObject).name));
					}
				}
			}
			else
			{
				if ((Object)(object)value == (Object)null)
				{
					networkObjectCache.Remove(gameObject);
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("Removed destroyed NetworkObject from cache for " + ((Object)gameObject).name));
					}
					return null;
				}
				if (Plugin.EnableDebugLogging.Value)
				{
					Plugin.Logger.LogDebug((object)("Retrieved cached NetworkObject for " + ((Object)gameObject).name));
				}
			}
			return value;
		}

		public static NetworkObject GetCachedNetworkObjectInChildren(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			NetworkObject cachedNetworkObject = GetCachedNetworkObject(gameObject);
			if ((Object)(object)cachedNetworkObject != (Object)null)
			{
				return cachedNetworkObject;
			}
			cachedNetworkObject = gameObject.GetComponentInChildren<NetworkObject>();
			if ((Object)(object)cachedNetworkObject != (Object)null)
			{
				networkObjectCache[gameObject] = cachedNetworkObject;
				if (Plugin.EnableDebugLogging.Value)
				{
					Plugin.Logger.LogDebug((object)("Cached new NetworkObject (from children) for " + ((Object)gameObject).name));
				}
			}
			return cachedNetworkObject;
		}

		[HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OptimizeNetworkObjectLookups(IEnumerable<CodeInstruction> instructions)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(GameObject), "GetComponent", (Type[])null, new Type[1] { typeof(NetworkObject) });
			MethodInfo methodInfo2 = AccessTools.Method(typeof(ComponentLookupPatches), "GetCachedNetworkObject", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Plugin.Logger.LogWarning((object)"Could not find methods for NetworkObject caching in SpawnScrapInLevel");
				return list;
			}
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo2);
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Logger.LogInfo((object)$"Replaced {num} GetComponent<NetworkObject> calls in SpawnScrapInLevel");
			}
			else if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogWarning((object)"No GetComponent<NetworkObject> calls found in SpawnScrapInLevel to replace");
			}
			return list;
		}

		[HarmonyPatch(typeof(RoundManager), "SpawnEnemyOnServer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OptimizeEnemySpawnLookups(IEnumerable<CodeInstruction> instructions)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(GameObject), "GetComponentInChildren", (Type[])null, new Type[1] { typeof(NetworkObject) });
			MethodInfo methodInfo2 = AccessTools.Method(typeof(ComponentLookupPatches), "GetCachedNetworkObjectInChildren", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Plugin.Logger.LogWarning((object)"Could not find methods for NetworkObject caching in SpawnEnemyOnServer");
				return list;
			}
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo2);
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Logger.LogInfo((object)$"Replaced {num} GetComponentInChildren<NetworkObject> calls in SpawnEnemyOnServer");
			}
			else if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogWarning((object)"No GetComponentInChildren<NetworkObject> calls found in SpawnEnemyOnServer to replace");
			}
			return list;
		}

		[HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")]
		[HarmonyPostfix]
		private static void ClearCacheOnRoundEnd()
		{
			int count = networkObjectCache.Count;
			networkObjectCache.Clear();
			if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogDebug((object)$"Cleared {count} NetworkObject cache entries on round end");
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
		[HarmonyPostfix]
		private static void ClearCacheOnShipReset()
		{
			int count = networkObjectCache.Count;
			networkObjectCache.Clear();
			if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogDebug((object)$"Cleared {count} NetworkObject cache entries on ship reset");
			}
		}
	}
	[HarmonyPatch]
	internal class DebugLogPatches
	{
		[HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> RemoveDebugLogsFromSpawnScrap(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(Debug), "Log", new Type[1] { typeof(object) }, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Logger.LogWarning((object)"Could not find Debug.Log method, skipping transpiler");
				return list;
			}
			int num = 0;
			for (int num2 = list.Count - 1; num2 >= 0; num2--)
			{
				if (CodeInstructionExtensions.Calls(list[num2], methodInfo))
				{
					int num3 = 1;
					int num4 = num2 - 1;
					while (num4 >= 0 && num3 < 10 && (list[num4].opcode == OpCodes.Ldstr || list[num4].opcode == OpCodes.Ldarg || list[num4].opcode == OpCodes.Ldloc))
					{
						num3++;
						num4--;
					}
					for (int i = 0; i < num3 && num2 - i >= 0; i++)
					{
						list[num2 - i].opcode = OpCodes.Nop;
					}
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Logger.LogInfo((object)$"Removed {num} Debug.Log calls from SpawnScrapInLevel");
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal class ShipItemOptimizationPatches
	{
		private static readonly HashSet<GrabbableObject> scrapCollectedSet = new HashSet<GrabbableObject>();

		private static bool setInitialized = false;

		[HarmonyPatch(typeof(RoundManager), "CollectNewScrapForThisRound")]
		[HarmonyPrefix]
		private static bool CollectNewScrapPrefix(RoundManager __instance, GrabbableObject scrapObject)
		{
			try
			{
				if (Plugin.EnableDebugLogging.Value)
				{
					Plugin.Logger.LogDebug((object)("CollectNewScrap called for " + (scrapObject?.itemProperties?.itemName ?? "null")));
				}
				if (!scrapObject.itemProperties.isScrap)
				{
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("Item " + scrapObject.itemProperties.itemName + " is not scrap, skipping"));
					}
					return false;
				}
				if (!setInitialized && __instance.scrapCollectedThisRound != null)
				{
					scrapCollectedSet.Clear();
					foreach (GrabbableObject item in __instance.scrapCollectedThisRound)
					{
						if ((Object)(object)item != (Object)null)
						{
							scrapCollectedSet.Add(item);
						}
					}
					setInitialized = true;
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)$"Initialized scrap set with {scrapCollectedSet.Count} items");
					}
				}
				if (scrapCollectedSet.Contains(scrapObject))
				{
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("Scrap " + scrapObject.itemProperties.itemName + " already collected, skipping"));
					}
					return false;
				}
				if (scrapObject.scrapPersistedThroughRounds)
				{
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("Scrap " + scrapObject.itemProperties.itemName + " persisted through rounds, skipping"));
					}
					return false;
				}
				__instance.scrapCollectedThisRound.Add(scrapObject);
				scrapCollectedSet.Add(scrapObject);
				HUDManager.Instance.AddNewScrapFoundToDisplay(scrapObject);
				if (Plugin.EnableDebugLogging.Value)
				{
					Plugin.Logger.LogDebug((object)$"Added scrap {scrapObject.itemProperties.itemName} to collection (total: {scrapCollectedSet.Count})");
				}
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error in CollectNewScrapForThisRound patch: " + ex.Message));
				return true;
			}
		}

		[HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")]
		[HarmonyPostfix]
		private static void ClearScrapSetOnRoundEnd()
		{
			int count = scrapCollectedSet.Count;
			scrapCollectedSet.Clear();
			setInitialized = false;
			if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogDebug((object)$"Cleared {count} scrap items from HashSet on round end");
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "ResetShip")]
		[HarmonyPostfix]
		private static void ClearScrapSetOnShipReset()
		{
			int count = scrapCollectedSet.Count;
			scrapCollectedSet.Clear();
			setInitialized = false;
			if (Plugin.EnableDebugLogging.Value)
			{
				Plugin.Logger.LogDebug((object)$"Cleared {count} scrap items from HashSet on ship reset");
			}
		}
	}
	[HarmonyPatch]
	internal class StringOptimizationPatches
	{
		private static readonly StringBuilder stringBuilder = new StringBuilder(256);

		[HarmonyPatch(typeof(GrabbableObject), "SetScrapValue")]
		[HarmonyPrefix]
		private static bool OptimizeSetScrapValue(GrabbableObject __instance, int setValueTo)
		{
			try
			{
				if (Plugin.EnableDebugLogging.Value)
				{
					Plugin.Logger.LogDebug((object)string.Format("SetScrapValue called for {0} with value {1}", __instance?.itemProperties?.itemName ?? "null", setValueTo));
				}
				__instance.scrapValue = setValueTo;
				ScanNodeProperties componentInChildren = ((Component)__instance).gameObject.GetComponentInChildren<ScanNodeProperties>();
				if ((Object)(object)componentInChildren == (Object)null)
				{
					if (Plugin.EnableDebugLogging.Value)
					{
						Plugin.Logger.LogDebug((object)("No ScanNodeProperties found for " + __instance.itemProperties.itemName));
					}
					return true;
				}
				stringBuilder.Clear();
				stringBuilder.Append("Value: $");
				stringBuilder.Append(setValueTo);
				componentInChildren.subText = stringBuilder.ToString();
				componentInChildren.scrapValue = setValueTo;
				if (Plugin.EnableDebugLogging.Value)
				{
					Plugin.Logger.LogDebug((object)("Set scrap value text to '" + componentInChildren.subText + "' for " + __instance.itemProperties.itemName));
				}
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error in SetScrapValue patch: " + ex.Message));
				return true;
			}
		}
	}
}