Decompiled source of SpawnConfigLateBundlesFix v1.0.0

SpawnConfigLateBundlesFix.dll

Decompiled 14 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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 SpawnConfig;
using SpawnConfig.Patches;
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(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[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 SpawnConfigLateBundlesFix
{
	[BepInPlugin("local.spawnconfig.latebundlesfix", "SpawnConfig Late Bundles Fix", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "local.spawnconfig.latebundlesfix";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> Verbose;

		private void Awake()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Activa o desactiva todo el mod. Solo hace falta en el host.");
			Verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLog", false, "Escribe en el log mas detalle (nombres de enemigos escaneados).");
			new Harmony("local.spawnconfig.latebundlesfix").PatchAll();
			EarlyFix.Hook();
			Log.LogInfo((object)"Loaded.");
		}
	}
	internal static class EarlyFix
	{
		private static MethodInfo _registerEnemies;

		internal static void Hook()
		{
			Type type = AccessTools.TypeByName("REPOLib.BundleLoader");
			Type type2 = AccessTools.TypeByName("REPOLib.Modules.Enemies");
			if (type == null || type2 == null)
			{
				Plugin.Log.LogWarning((object)"No encontre REPOLib.BundleLoader / REPOLib.Modules.Enemies. Solo funcionara la red de seguridad al entrar a un nivel.");
				return;
			}
			_registerEnemies = AccessTools.Method(type2, "RegisterEnemies", (Type[])null, (Type[])null);
			EventInfo eventInfo = type.GetEvent("OnAllBundlesLoaded", BindingFlags.Static | BindingFlags.Public);
			if (_registerEnemies == null || eventInfo == null)
			{
				Plugin.Log.LogWarning((object)"REPOLib cambio (RegisterEnemies / OnAllBundlesLoaded no encontrados). Solo funcionara la red de seguridad al entrar a un nivel.");
				return;
			}
			eventInfo.AddEventHandler(null, new Action(OnAllBundlesLoaded));
			Plugin.Log.LogInfo((object)"Suscrito a REPOLib.BundleLoader.OnAllBundlesLoaded (antes que SpawnConfig).");
		}

		private static void OnAllBundlesLoaded()
		{
			if (!Plugin.Enabled.Value)
			{
				return;
			}
			try
			{
				EnemyDirector instance = EnemyDirector.instance;
				if ((Object)(object)instance == (Object)null)
				{
					Plugin.Log.LogWarning((object)"EnemyDirector.instance es null; se usara la red de seguridad.");
					return;
				}
				HashSet<string> before = EnemyNames(instance);
				_registerEnemies.Invoke(null, null);
				List<string> list = (from n in EnemyNames(instance)
					where !before.Contains(n)
					select n).ToList();
				if (list.Count > 0)
				{
					Plugin.Log.LogInfo((object)("Enemigos tardios anadidos al director ANTES del setup de SpawnConfig (" + list.Count + "): " + string.Join(", ", list)));
				}
				else
				{
					Plugin.Log.LogInfo((object)"No habia enemigos tardios que anadir.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Fallo la inyeccion temprana (SpawnConfig seguira normal): " + ex));
			}
		}

		internal static HashSet<string> EnemyNames(EnemyDirector director)
		{
			HashSet<string> hashSet = new HashSet<string>();
			AddNames(director.enemiesDifficulty1, hashSet);
			AddNames(director.enemiesDifficulty2, hashSet);
			AddNames(director.enemiesDifficulty3, hashSet);
			return hashSet;
		}

		private static void AddNames(List<EnemySetup> list, HashSet<string> names)
		{
			if (list == null)
			{
				return;
			}
			foreach (EnemySetup item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					names.Add(((Object)item).name);
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyDirector), "AmountSetup")]
	internal static class AmountSetupPatch
	{
		private static readonly HashSet<string> GivenUp = new HashSet<string>();

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Prefix(EnemyDirector __instance)
		{
			if (!Plugin.Enabled.Value || !SemiFunc.IsMasterClientOrSingleplayer() || !EnemyDirectorPatch.setupDone)
			{
				return;
			}
			List<string> list = FindMissing(__instance);
			if (list.Count == 0)
			{
				return;
			}
			Plugin.Log.LogInfo((object)("SpawnConfig no conoce estos enemigos, repitiendo su setup: " + string.Join(", ", list)));
			List<Action> list2 = new List<Action>
			{
				Snapshot(ListManager.spawnObjectsDict),
				Snapshot(ListManager.extendedSetups),
				Snapshot(ListManager.extendedSpawnObjects),
				Snapshot(ListManager.extendedGroupCounts),
				Snapshot(ListManager.loadedLevelNames),
				Snapshot(ListManager.levelNumbers),
				Snapshot(ListManager.difficulty1Counts),
				Snapshot(ListManager.difficulty2Counts),
				Snapshot(ListManager.difficulty3Counts)
			};
			HashSet<string> knownBefore = new HashSet<string>(ListManager.spawnObjectsDict.Keys);
			try
			{
				ListManager.spawnObjectsDict.Clear();
				ListManager.extendedSetups.Clear();
				ListManager.extendedSpawnObjects.Clear();
				ListManager.extendedGroupCounts.Clear();
				ListManager.loadedLevelNames.Clear();
				ListManager.levelNumbers.Clear();
				ListManager.difficulty1Counts.Clear();
				ListManager.difficulty2Counts.Clear();
				ListManager.difficulty3Counts.Clear();
				EnemyDirectorPatch.setupDone = false;
				EnemyDirectorPatch.SetupOnStart(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Fallo al repetir el setup; restauro el estado anterior de SpawnConfig: " + ex));
				foreach (Action item in list2)
				{
					item();
				}
				EnemyDirectorPatch.setupDone = true;
				foreach (string item2 in list)
				{
					GivenUp.Add(item2);
				}
				return;
			}
			List<string> list3 = ListManager.spawnObjectsDict.Keys.Where((string k) => !knownBefore.Contains(k)).ToList();
			Plugin.Log.LogInfo((object)((list3.Count > 0) ? ("SpawnConfig ahora reconoce (" + list3.Count + "): " + string.Join(", ", list3)) : "SpawnConfig no incorporo enemigos nuevos tras repetir el setup."));
			foreach (string item3 in FindMissing(__instance))
			{
				GivenUp.Add(item3);
			}
		}

		private static List<string> FindMissing(EnemyDirector director)
		{
			List<string> result = new List<string>();
			HashSet<string> seen = new HashSet<string>();
			Scan(director.enemiesDifficulty1, result, seen);
			Scan(director.enemiesDifficulty2, result, seen);
			Scan(director.enemiesDifficulty3, result, seen);
			return result;
		}

		private static void Scan(List<EnemySetup> list, List<string> result, HashSet<string> seen)
		{
			if (list == null)
			{
				return;
			}
			foreach (EnemySetup item in list)
			{
				if ((Object)(object)item == (Object)null || item.spawnObjects == null)
				{
					continue;
				}
				foreach (PrefabRef spawnObject in item.spawnObjects)
				{
					string prefabName = ((PrefabRef<GameObject>)(object)spawnObject).PrefabName;
					if (!string.IsNullOrEmpty(prefabName) && !ListManager.spawnObjectsDict.ContainsKey(prefabName) && !GivenUp.Contains(prefabName) && seen.Add(prefabName))
					{
						result.Add(prefabName);
					}
				}
			}
		}

		private static Action Snapshot<K, V>(Dictionary<K, V> dict)
		{
			Dictionary<K, V> copy = new Dictionary<K, V>(dict);
			return delegate
			{
				dict.Clear();
				foreach (KeyValuePair<K, V> item in copy)
				{
					dict[item.Key] = item.Value;
				}
			};
		}

		private static Action Snapshot<T>(List<T> list)
		{
			List<T> copy = new List<T>(list);
			return delegate
			{
				list.Clear();
				list.AddRange(copy);
			};
		}
	}
}