Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SpawnConfigLateBundlesFix v1.0.0
SpawnConfigLateBundlesFix.dll
Decompiled 14 hours agousing 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); }; } } }