Decompiled source of Too Many Ducks v1.0.1

SoManyDucks.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Omniscye")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SoManyDucks")]
[assembly: AssemblyTitle("SoManyDucks")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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 Empress.Ducks
{
	[BepInPlugin("dev.empress.repo.empressducks", "Empress Ducks", "2.0.0")]
	public sealed class EmpressDucksPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "dev.empress.repo.empressducks";

		public const string PluginName = "Empress Ducks";

		public const string PluginVersion = "2.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<int> DuckCount;

		internal static ConfigEntry<bool> MasterOnly;

		private Harmony _harmony;

		internal static Object DuckSetupObj;

		internal static bool DuckSearchTriedThisRun;

		private static Type T_EnemyDirector;

		private static Type T_EnemySetup;

		private static Type T_LevelGenerator;

		private static Type T_RunManager;

		private static Type T_GameManager;

		private static Type T_EnemyDuck;

		private static MethodInfo M_AmountSetup;

		private static MethodInfo M_GetEnemy;

		private static MethodInfo M_EnemySpawn;

		private static MethodInfo M_EnemiesSpawnedRemoveStart;

		private static FieldInfo F_TotalAmount;

		private static FieldInfo F_EnemyList;

		private static FieldInfo F_EnemyListCurrent;

		private static FieldInfo F_EnemyListIndex;

		private static FieldInfo F_EnemiesDifficulty1;

		private static FieldInfo F_EnemiesDifficulty2;

		private static FieldInfo F_EnemiesDifficulty3;

		private static PropertyInfo P_Instance_EnemyDirector;

		private static PropertyInfo P_Instance_RunManager;

		private static MethodInfo M_GameManager_Multiplayer;

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Expected O, but got Unknown
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Expected O, but got Unknown
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable/disable Empress Ducks.");
			DuckCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "DuckCount", 200, new ConfigDescription("Number of ducks to spawn per level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 500), Array.Empty<object>()));
			MasterOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "MasterOnly", true, "Apply only on MasterClient to avoid desyncs.");
			_harmony = new Harmony("dev.empress.repo.empressducks");
			T_EnemyDirector = AccessTools.TypeByName("EnemyDirector");
			T_EnemySetup = AccessTools.TypeByName("EnemySetup");
			T_LevelGenerator = AccessTools.TypeByName("LevelGenerator");
			T_RunManager = AccessTools.TypeByName("RunManager");
			T_GameManager = AccessTools.TypeByName("GameManager");
			T_EnemyDuck = AccessTools.TypeByName("EnemyDuck");
			if (T_EnemyDirector == null || T_EnemySetup == null || T_LevelGenerator == null || T_RunManager == null || T_GameManager == null)
			{
				Log.LogError((object)"[EmpressDucks] Required game types not found. Aborting patches.");
				return;
			}
			M_AmountSetup = AccessTools.Method(T_EnemyDirector, "AmountSetup", (Type[])null, (Type[])null);
			M_GetEnemy = AccessTools.Method(T_EnemyDirector, "GetEnemy", (Type[])null, (Type[])null);
			M_EnemySpawn = AccessTools.Method(T_LevelGenerator, "EnemySpawn", new Type[2]
			{
				T_EnemySetup,
				typeof(Vector3)
			}, (Type[])null);
			M_EnemiesSpawnedRemoveStart = AccessTools.Method(T_RunManager, "EnemiesSpawnedRemoveStart", (Type[])null, (Type[])null);
			F_TotalAmount = AccessTools.Field(T_EnemyDirector, "totalAmount");
			F_EnemyList = AccessTools.Field(T_EnemyDirector, "enemyList");
			F_EnemyListCurrent = AccessTools.Field(T_EnemyDirector, "enemyListCurrent");
			F_EnemyListIndex = AccessTools.Field(T_EnemyDirector, "enemyListIndex");
			F_EnemiesDifficulty1 = AccessTools.Field(T_EnemyDirector, "enemiesDifficulty1");
			F_EnemiesDifficulty2 = AccessTools.Field(T_EnemyDirector, "enemiesDifficulty2");
			F_EnemiesDifficulty3 = AccessTools.Field(T_EnemyDirector, "enemiesDifficulty3");
			P_Instance_EnemyDirector = AccessTools.Property(T_EnemyDirector, "instance") ?? AccessTools.Property(T_EnemyDirector, "Instance");
			P_Instance_RunManager = AccessTools.Property(T_RunManager, "instance") ?? AccessTools.Property(T_RunManager, "Instance");
			M_GameManager_Multiplayer = AccessTools.Method(T_GameManager, "Multiplayer", Type.EmptyTypes, (Type[])null);
			if (M_EnemiesSpawnedRemoveStart != null)
			{
				HarmonyMethod val = new HarmonyMethod(typeof(EmpressDucksPlugin).GetMethod("Prefix_RunReset", BindingFlags.Static | BindingFlags.NonPublic));
				_harmony.Patch((MethodBase)M_EnemiesSpawnedRemoveStart, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)"[EmpressDucks] Patch OK -> RunManager.EnemiesSpawnedRemoveStart (cache reset)");
			}
			else
			{
				Log.LogWarning((object)"[EmpressDucks] Could not find RunManager.EnemiesSpawnedRemoveStart");
			}
			if (M_AmountSetup != null && F_TotalAmount != null)
			{
				HarmonyMethod val2 = new HarmonyMethod(typeof(EmpressDucksPlugin).GetMethod("Postfix_AmountSetup", BindingFlags.Static | BindingFlags.NonPublic));
				_harmony.Patch((MethodBase)M_AmountSetup, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)"[EmpressDucks] Patch OK -> EnemyDirector.AmountSetup (totalAmount override + duck cache)");
			}
			else
			{
				Log.LogWarning((object)"[EmpressDucks] Could not patch EnemyDirector.AmountSetup");
			}
			if (M_GetEnemy != null)
			{
				HarmonyMethod val3 = new HarmonyMethod(typeof(EmpressDucksPlugin).GetMethod("Prefix_GetEnemy", BindingFlags.Static | BindingFlags.NonPublic));
				_harmony.Patch((MethodBase)M_GetEnemy, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)"[EmpressDucks] Patch OK -> EnemyDirector.GetEnemy (force duck return)");
			}
			else
			{
				Log.LogWarning((object)"[EmpressDucks] Could not patch EnemyDirector.GetEnemy");
			}
			if (M_EnemySpawn != null)
			{
				HarmonyMethod val4 = new HarmonyMethod(typeof(EmpressDucksPlugin).GetMethod("Prefix_EnemySpawn", BindingFlags.Static | BindingFlags.NonPublic));
				_harmony.Patch((MethodBase)M_EnemySpawn, val4, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)"[EmpressDucks] Patch OK -> LevelGenerator.EnemySpawn (force duck param)");
			}
			else
			{
				Log.LogWarning((object)"[EmpressDucks] Could not patch LevelGenerator.EnemySpawn");
			}
			Log.LogInfo((object)"\r\n┌─────────────────────────────────┐\r\n│ ██████╗ ███╗   ███╗███╗   ██╗██╗│\r\n│██╔═══██╗████╗ ████║████╗  ██║██║│\r\n│██║   ██║██╔████╔██║██╔██╗ ██║██║│\r\n│██║   ██║██║╚██╔╝██║██║╚██╗██║██║│\r\n│╚██████╔╝██║ ╚═╝ ██║██║ ╚████║██║│\r\n│ ╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═══╝╚═╝│\r\n│                                 │\r\n│██████╗ ██╗   ██╗ ██████╗██╗  ██╗│\r\n│██╔══██╗██║   ██║██╔════╝██║ ██╔╝│\r\n│██║  ██║██║   ██║██║     █████╔╝ │\r\n│██║  ██║██║   ██║██║     ██╔═██╗ │\r\n│██████╔╝╚██████╔╝╚██████╗██║  ██╗│\r\n│╚═════╝  ╚═════╝  ╚═════╝╚═╝  ╚═╝│\r\n└─────────────────────────────────┘\r\n");
			Log.LogInfo((object)"Empress Ducks 2.0.0 loaded. Runtime name-bound patches armed.");
		}

		private static bool IsMasterAllowed()
		{
			try
			{
				if (!MasterOnly.Value)
				{
					return true;
				}
				if (M_GameManager_Multiplayer != null && (bool)M_GameManager_Multiplayer.Invoke(null, null))
				{
					return PhotonNetwork.IsMasterClient;
				}
				return true;
			}
			catch
			{
				return true;
			}
		}

		private static void Prefix_RunReset()
		{
			DuckSetupObj = null;
			DuckSearchTriedThisRun = false;
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogDebug((object)"[EmpressDucks] Cache reset.");
			}
		}

		private static void Postfix_AmountSetup(object __instance)
		{
			if (!Enabled.Value || !IsMasterAllowed())
			{
				return;
			}
			try
			{
				int num = Mathf.Max(1, DuckCount.Value);
				if (F_TotalAmount != null)
				{
					F_TotalAmount.SetValue(__instance, num);
					Log.LogInfo((object)$"[EmpressDucks] totalAmount -> {num}");
				}
				TryCacheDuckSetupFromDirector(__instance);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[EmpressDucks] AmountSetup postfix failed: {arg}");
			}
		}

		private static bool Prefix_GetEnemy(object __instance, ref Object __result)
		{
			if (!Enabled.Value || !IsMasterAllowed())
			{
				return true;
			}
			try
			{
				if (DuckSetupObj == (Object)null)
				{
					TryCacheDuckSetupFromDirector(__instance);
				}
				if (DuckSetupObj != (Object)null)
				{
					__result = DuckSetupObj;
					return false;
				}
				if (!DuckSearchTriedThisRun)
				{
					Log.LogWarning((object)"[EmpressDucks] No Duck EnemySetup found on director. Letting vanilla pick.");
				}
				DuckSearchTriedThisRun = true;
				return true;
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[EmpressDucks] GetEnemy prefix failed: {arg}");
				return true;
			}
		}

		private static void Prefix_EnemySpawn(ref Object enemySetup)
		{
			if (!Enabled.Value || !IsMasterAllowed())
			{
				return;
			}
			try
			{
				if (DuckSetupObj == (Object)null)
				{
					object obj = P_Instance_EnemyDirector?.GetValue(null, null);
					if (obj != null)
					{
						TryCacheDuckSetupFromDirector(obj);
					}
				}
				if (DuckSetupObj != (Object)null)
				{
					enemySetup = DuckSetupObj;
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[EmpressDucks] EnemySpawn prefix failed: {arg}");
			}
		}

		private static void TryCacheDuckSetupFromDirector(object director)
		{
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Expected O, but got Unknown
			if (director == null || T_EnemyDirector == null || T_EnemySetup == null)
			{
				return;
			}
			try
			{
				IEnumerable[] array = new IEnumerable[3]
				{
					F_EnemiesDifficulty1?.GetValue(director) as IEnumerable,
					F_EnemiesDifficulty2?.GetValue(director) as IEnumerable,
					F_EnemiesDifficulty3?.GetValue(director) as IEnumerable
				};
				IEnumerable[] array2 = array;
				foreach (IEnumerable enumerable in array2)
				{
					if (enumerable == null)
					{
						continue;
					}
					foreach (object item in enumerable)
					{
						if (item == null || !(AccessTools.Field(T_EnemySetup, "spawnObjects")?.GetValue(item) is IEnumerable enumerable2))
						{
							continue;
						}
						foreach (object item2 in enumerable2)
						{
							GameObject val = (GameObject)((item2 is GameObject) ? item2 : null);
							if (!((Object)(object)val == (Object)null))
							{
								bool flag = false;
								if (T_EnemyDuck != null && (Object)(object)val.GetComponentInChildren(T_EnemyDuck, true) != (Object)null)
								{
									flag = true;
								}
								if (!flag && ((Object)val).name != null && ((Object)val).name.IndexOf("Duck", StringComparison.OrdinalIgnoreCase) >= 0)
								{
									flag = true;
								}
								if (flag)
								{
									DuckSetupObj = (Object)item;
									Log.LogInfo((object)("[EmpressDucks] Cached Duck setup: " + DuckSetupObj.name));
									return;
								}
							}
						}
					}
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[EmpressDucks] Duck cache scan failed: {arg}");
			}
			finally
			{
				DuckSearchTriedThisRun = true;
			}
		}
	}
}