Decompiled source of LCOptimizer v0.4.1

LCOptimizer.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
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("LCOptimizer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LCOptimizer")]
[assembly: AssemblyTitle("LCOptimizer")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 LCOptimizer
{
	public enum Toggle
	{
		Vanilla,
		On,
		Off
	}
	internal static class Graphics
	{
		[HarmonyPatch(typeof(IngamePlayerSettings), "SetPixelResolution")]
		private static class ResolutionPatch
		{
			private static void Postfix(IngamePlayerSettings __instance)
			{
				if (on.Value && resWidth.Value > 0 && resHeight.Value > 0)
				{
					RenderTexture playerGameplayScreenTex = __instance.playerGameplayScreenTex;
					playerGameplayScreenTex.Release();
					((Texture)playerGameplayScreenTex).width = resWidth.Value;
					((Texture)playerGameplayScreenTex).height = resHeight.Value;
				}
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "Start")]
		private static class StartOfRoundPatch
		{
			private static void Postfix()
			{
				ApplyAll();
			}
		}

		private static ConfigEntry<bool> on;

		private static ConfigEntry<float> lodBias;

		private static ConfigEntry<int> maxLod;

		private static ConfigEntry<int> resWidth;

		private static ConfigEntry<int> resHeight;

		private static readonly List<(FrameSettingsField field, ConfigEntry<Toggle> cfg)> toggles = new List<(FrameSettingsField, ConfigEntry<Toggle>)>();

		private static readonly HashSet<FrameSettingsField> ours = new HashSet<FrameSettingsField>();

		internal static void Bind(ConfigFile c)
		{
			on = c.Bind<bool>("Graphics", "Enabled", true, "Aplica los ajustes de abajo a las camaras HDRP. Todo en Vanilla = no cambia nada.");
			resWidth = c.Bind<int>("Graphics", "ResolutionWidth", 0, "Ancho de render del juego (0 = el del menu del juego). Vanilla alto = 860. Menos = mas FPS.");
			resHeight = c.Bind<int>("Graphics", "ResolutionHeight", 0, "Alto de render del juego (0 = el del menu del juego). Vanilla alto = 520.");
			lodBias = c.Bind<float>("Graphics", "LodBias", 0f, "Sesgo de LOD (0 = vanilla). Menor = modelos simples antes (ej. 0.5).");
			maxLod = c.Bind<int>("Graphics", "MaximumLODLevel", -1, "Nivel de LOD maximo forzado (-1 = vanilla). OJO: 1+ hace invisibles los objetos que no tienen LODs bajos.");
			T((FrameSettingsField)28, "VolumetricFog", "Niebla volumetrica. Off = mucho FPS, pero se ve mas lejos (cambia la visibilidad).");
			T((FrameSettingsField)29, "VolumetricReprojection", "Reproyeccion de niebla volumetrica.");
			T((FrameSettingsField)20, "Shadows", "Sombras de luces. Off = gran ahorro, se ve plano.");
			T((FrameSettingsField)21, "ContactShadows", "Sombras de contacto.");
			T((FrameSettingsField)34, "ScreenSpaceShadows", "Sombras en espacio de pantalla.");
			T((FrameSettingsField)24, "AmbientOcclusion", "Oclusion ambiental (SSAO).");
			T((FrameSettingsField)23, "ScreenSpaceReflections", "Reflejos en espacio de pantalla.");
			T((FrameSettingsField)46, "SubsurfaceScattering", "Dispersion subsuperficial (piel, cera).");
			T((FrameSettingsField)26, "Transmission", "Transmision de luz en materiales finos.");
			T((FrameSettingsField)13, "Refraction", "Refraccion (vidrio, agua).");
			T((FrameSettingsField)14, "Distortion", "Distorsion de calor y efectos.");
			T((FrameSettingsField)12, "Decals", "Calcomanias (sangre, manchas, carteles). Off puede dejar superficies sin textura.");
			T((FrameSettingsField)8, "TransparentPrepass", "Pre-pass de transparentes.");
			T((FrameSettingsField)9, "TransparentPostpass", "Post-pass de transparentes.");
			T((FrameSettingsField)18, "LowResTransparent", "On = particulas y transparentes a media resolucion (mas FPS).");
			T((FrameSettingsField)84, "Bloom", "Resplandor de luces.");
			T((FrameSettingsField)81, "DepthOfField", "Profundidad de campo.");
			T((FrameSettingsField)86, "ChromaticAberration", "Aberracion cromatica.");
			T((FrameSettingsField)89, "FilmGrain", "Grano de pelicula.");
			T((FrameSettingsField)87, "Vignette", "Vineta.");
			T((FrameSettingsField)97, "LensFlares", "Destellos de lente.");
			on.SettingChanged += delegate
			{
				ApplyAll();
				RefreshResolution();
			};
			lodBias.SettingChanged += delegate
			{
				ApplyAll();
			};
			maxLod.SettingChanged += delegate
			{
				ApplyAll();
			};
			foreach (var toggle in toggles)
			{
				toggle.cfg.SettingChanged += delegate
				{
					ApplyAll();
				};
			}
			resWidth.SettingChanged += delegate
			{
				RefreshResolution();
			};
			resHeight.SettingChanged += delegate
			{
				RefreshResolution();
			};
			void T(FrameSettingsField f, string name, string desc)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				toggles.Add((f, c.Bind<Toggle>("Graphics", name, Toggle.Vanilla, desc + " Vanilla = no tocar.")));
			}
		}

		internal static void ApplyAll()
		{
			HDAdditionalCameraData[] array = Object.FindObjectsOfType<HDAdditionalCameraData>(true);
			for (int i = 0; i < array.Length; i++)
			{
				Apply(array[i]);
			}
		}

		private static void Apply(HDAdditionalCameraData cam)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			cam.customRenderingSettings = true;
			ref FrameSettings renderingPathCustomFrameSettings = ref cam.renderingPathCustomFrameSettings;
			foreach (var toggle in toggles)
			{
				FrameSettingsField item = toggle.field;
				ConfigEntry<Toggle> item2 = toggle.cfg;
				bool flag = on.Value && item2.Value != Toggle.Vanilla;
				if (flag || ours.Contains(item))
				{
					Set(item, flag);
					if (flag)
					{
						((FrameSettings)(ref renderingPathCustomFrameSettings)).SetEnabled(item, item2.Value == Toggle.On);
					}
				}
			}
			bool flag2 = on.Value && lodBias.Value > 0f;
			if (flag2 || ours.Contains((FrameSettingsField)61))
			{
				Set((FrameSettingsField)60, flag2);
				Set((FrameSettingsField)61, flag2);
				if (flag2)
				{
					renderingPathCustomFrameSettings.lodBiasMode = (LODBiasMode)2;
					renderingPathCustomFrameSettings.lodBias = lodBias.Value;
				}
			}
			bool flag3 = on.Value && maxLod.Value >= 0;
			if (flag3 || ours.Contains((FrameSettingsField)63))
			{
				Set((FrameSettingsField)62, flag3);
				Set((FrameSettingsField)63, flag3);
				if (flag3)
				{
					renderingPathCustomFrameSettings.maximumLODLevelMode = (MaximumLODLevelMode)2;
					renderingPathCustomFrameSettings.maximumLODLevel = maxLod.Value;
				}
			}
			void Set(FrameSettingsField f, bool active)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				SetMask(ref cam.renderingPathCustomFrameSettingsOverrideMask.mask, f, active);
			}
			static void SetMask(ref BitArray128 m, FrameSettingsField f, bool active)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Expected I4, but got Unknown
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				((BitArray128)(ref m))[(uint)(int)f] = active;
				if (active)
				{
					ours.Add(f);
				}
			}
		}

		private static void RefreshResolution()
		{
			IngamePlayerSettings instance = IngamePlayerSettings.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				AccessTools.Method(typeof(IngamePlayerSettings), "SetPixelResolution", (Type[])null, (Type[])null).Invoke(instance, new object[1] { instance.settings.pixelRes });
			}
		}
	}
	[BepInPlugin("martinchu.LCOptimizer", "LCOptimizer", "0.4.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static Plugin I;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> AiOn;

		internal static ConfigEntry<float> AiFarDistance;

		internal static ConfigEntry<float> AiFarInterval;

		internal static ConfigEntry<float> AiMidDistance;

		internal static ConfigEntry<float> AiMidInterval;

		internal static ConfigEntry<bool> MemOn;

		internal static ConfigEntry<float> MemDelay;

		private void Awake()
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			I = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Graphics.Bind(((BaseUnityPlugin)this).Config);
			AiOn = ((BaseUnityPlugin)this).Config.Bind<bool>("AI", "Enabled", true, "Reduce la frecuencia de IA de enemigos lejos de todos los jugadores (solo host).");
			AiMidDistance = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "MidDistance", 40f, "Metros al jugador mas cercano para usar intervalo medio.");
			AiMidInterval = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "MidInterval", 0.3f, "Intervalo de IA (s) a distancia media. Vanilla = 0.2.");
			AiFarDistance = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "FarDistance", 80f, "Metros al jugador mas cercano para usar intervalo lejano.");
			AiFarInterval = ((BaseUnityPlugin)this).Config.Bind<float>("AI", "FarInterval", 0.5f, "Intervalo de IA (s) a distancia lejana.");
			MemOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Memory", "Enabled", true, "Libera memoria no usada despues de que la nave despega.");
			MemDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Memory", "DelaySeconds", 8f, "Segundos de espera tras ShipHasLeft antes de limpiar.");
			Presets.Bind(((BaseUnityPlugin)this).Config);
			new Harmony("martinchu.LCOptimizer").PatchAll();
			SceneManager.sceneLoaded += delegate
			{
				Graphics.ApplyAll();
			};
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LCOptimizer 0.4.0 cargado");
		}

		internal IEnumerator CleanupLater()
		{
			yield return (object)new WaitForSeconds(MemDelay.Value);
			Resources.UnloadUnusedAssets();
			GC.Collect();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Memoria liberada");
		}
	}
	[HarmonyPatch(typeof(EnemyAI), "Update")]
	internal static class EnemyAiThrottle
	{
		private struct State
		{
			public float baseInterval;

			public float nextCheck;
		}

		private static readonly Dictionary<EnemyAI, State> states = new Dictionary<EnemyAI, State>();

		private static void Postfix(EnemyAI __instance)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.AiOn.Value)
			{
				if (states.TryGetValue(__instance, out var value))
				{
					__instance.AIIntervalTime = value.baseInterval;
					states.Remove(__instance);
				}
			}
			else
			{
				if (!((NetworkBehaviour)__instance).IsOwner || __instance.isEnemyDead)
				{
					return;
				}
				if (!states.TryGetValue(__instance, out var value2))
				{
					value2 = new State
					{
						baseInterval = __instance.AIIntervalTime,
						nextCheck = 0f
					};
				}
				if (Time.time < value2.nextCheck)
				{
					states[__instance] = value2;
					return;
				}
				value2.nextCheck = Time.time + 1f;
				float num = ((__instance.currentBehaviourStateIndex == 0 && (Object)(object)__instance.targetPlayer == (Object)null && !__instance.movingTowardsTargetPlayer) ? NearestPlayerDistance(((Component)__instance).transform.position) : 0f);
				float aIIntervalTime = value2.baseInterval;
				if (num >= Plugin.AiFarDistance.Value)
				{
					aIIntervalTime = Mathf.Max(value2.baseInterval, Plugin.AiFarInterval.Value);
				}
				else if (num >= Plugin.AiMidDistance.Value)
				{
					aIIntervalTime = Mathf.Max(value2.baseInterval, Plugin.AiMidInterval.Value);
				}
				__instance.AIIntervalTime = aIIntervalTime;
				states[__instance] = value2;
			}
		}

		private static float NearestPlayerDistance(Vector3 pos)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return 0f;
			}
			float num = float.MaxValue;
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead)
				{
					float num2 = Vector3.Distance(pos, ((Component)val).transform.position);
					if (num2 < num)
					{
						num = num2;
					}
				}
			}
			if (num != float.MaxValue)
			{
				return num;
			}
			return 0f;
		}

		internal static void Forget(EnemyAI e)
		{
			if ((Object)(object)e != (Object)null)
			{
				states.Remove(e);
			}
		}
	}
	[HarmonyPatch(typeof(EnemyAI), "OnDestroy")]
	internal static class EnemyAiForget
	{
		private static void Postfix(EnemyAI __instance)
		{
			EnemyAiThrottle.Forget(__instance);
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ShipHasLeft")]
	internal static class MemoryCleanup
	{
		private static void Postfix()
		{
			if (Plugin.MemOn.Value)
			{
				((MonoBehaviour)Plugin.I).StartCoroutine(Plugin.I.CleanupLater());
			}
		}
	}
	public enum Preset
	{
		Vanilla,
		Normal,
		Optimizado,
		ModoDios,
		Custom
	}
	internal static class Presets
	{
		private static ConfigFile cfg;

		private static ConfigEntry<Preset> preset;

		private static bool applying;

		private static readonly List<(string s, string k, object[] v)> table;

		private static readonly Toggle V;

		private static readonly Toggle On;

		private static readonly Toggle Off;

		private static void Row(string s, string k, params object[] v)
		{
			table.Add((s, k, v));
		}

		static Presets()
		{
			table = new List<(string, string, object[])>();
			V = Toggle.Vanilla;
			On = Toggle.On;
			Off = Toggle.Off;
			Row("AI", "Enabled", false, true, true, true);
			Row("AI", "MidDistance", 40f, 40f, 40f, 30f);
			Row("AI", "MidInterval", 0.3f, 0.3f, 0.3f, 0.4f);
			Row("AI", "FarDistance", 80f, 80f, 80f, 60f);
			Row("AI", "FarInterval", 0.5f, 0.5f, 0.6f, 0.8f);
			Row("Memory", "Enabled", false, true, true, true);
			Row("Graphics", "Enabled", false, true, true, true);
			Row("Graphics", "ResolutionWidth", 0, 0, 0, 640);
			Row("Graphics", "ResolutionHeight", 0, 0, 0, 384);
			Row("Graphics", "LodBias", 0f, 0f, 0.7f, 0.5f);
			Row("Graphics", "MaximumLODLevel", -1, -1, -1, -1);
			Row("Graphics", "VolumetricFog", V, V, V, V);
			Row("Graphics", "VolumetricReprojection", V, V, On, On);
			Row("Graphics", "Shadows", V, V, V, Off);
			Row("Graphics", "ContactShadows", V, V, Off, Off);
			Row("Graphics", "ScreenSpaceShadows", V, V, V, Off);
			Row("Graphics", "AmbientOcclusion", V, V, V, Off);
			Row("Graphics", "ScreenSpaceReflections", V, V, Off, Off);
			Row("Graphics", "SubsurfaceScattering", V, V, V, Off);
			Row("Graphics", "Transmission", V, V, V, Off);
			Row("Graphics", "Refraction", V, V, V, V);
			Row("Graphics", "Distortion", V, V, V, Off);
			Row("Graphics", "Decals", V, V, V, V);
			Row("Graphics", "TransparentPrepass", V, V, V, V);
			Row("Graphics", "TransparentPostpass", V, V, V, V);
			Row("Graphics", "LowResTransparent", V, V, On, On);
			Row("Graphics", "Bloom", V, V, V, Off);
			Row("Graphics", "DepthOfField", V, V, Off, Off);
			Row("Graphics", "ChromaticAberration", V, V, Off, Off);
			Row("Graphics", "FilmGrain", V, V, Off, Off);
			Row("Graphics", "Vignette", V, V, Off, Off);
			Row("Graphics", "LensFlares", V, V, Off, Off);
		}

		internal static void Bind(ConfigFile c)
		{
			cfg = c;
			preset = c.Bind<Preset>("Preset", "Preset", Preset.Normal, "Vanilla = el mod no toca nada (Lethal puro).\nNormal = solo optimizaciones invisibles (IA lejana + memoria), graficos intactos.\nOptimizado = ademas apaga efectos de camara y reflejos; se ve casi igual.\nModoDios = maximo FPS: sin sombras, AO, bloom, LOD bajo y resolucion 640x384.\nCustom = usa tus valores a mano. Editar cualquier opcion cambia a Custom solo.");
			if (preset.Value != Preset.Custom && !Matches(preset.Value))
			{
				preset.Value = Preset.Custom;
			}
			preset.SettingChanged += delegate
			{
				Apply(preset.Value);
			};
			c.SettingChanged += delegate(object _, SettingChangedEventArgs e)
			{
				if (!applying && preset.Value != Preset.Custom)
				{
					ConfigDefinition d = e.ChangedSetting.Definition;
					if (table.Exists(((string s, string k, object[] v) r) => r.s == d.Section && r.k == d.Key))
					{
						preset.Value = Preset.Custom;
					}
				}
			};
		}

		private static bool Matches(Preset p)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			foreach (var (text, text2, array) in table)
			{
				if (((IDictionary<ConfigDefinition, ConfigEntryBase>)cfg).TryGetValue(new ConfigDefinition(text, text2), out ConfigEntryBase value) && !object.Equals(value.BoxedValue, array[(int)p]))
				{
					return false;
				}
			}
			return true;
		}

		private static void Apply(Preset p)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if (p == Preset.Custom)
			{
				return;
			}
			applying = true;
			try
			{
				foreach (var (text, text2, array) in table)
				{
					if (((IDictionary<ConfigDefinition, ConfigEntryBase>)cfg).TryGetValue(new ConfigDefinition(text, text2), out ConfigEntryBase value))
					{
						value.BoxedValue = array[(int)p];
					}
				}
			}
			finally
			{
				applying = false;
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Preset aplicado: " + p));
			}
		}
	}
}