using System; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Logging; using HarmonyLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace CodexPatches.DawnLibNullDungeonGuard; [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("codex.dawnlibnulldungeonguard", "DawnLib Null Dungeon Guard", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "codex.dawnlibnulldungeonguard"; public const string PluginName = "DawnLib Null Dungeon Guard"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; try { new Harmony("codex.dawnlibnulldungeonguard").PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"Installed DawnLib null dungeon guard."); } catch (Exception ex) { Log.LogError((object)("Failed to install DawnLib null dungeon guard: " + ex)); } } } [HarmonyPatch] internal static class LoadDungeonBundleMoveNextPatch { private static bool generatedOnceAfterNull; private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("Dawn.DungeonRegistrationHandler+d__11"); if (!(type == null)) { return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null); } return null; } private static bool Prefix(object __instance, ref bool __result) { try { FieldInfo fieldInfo = AccessTools.Field(__instance.GetType(), "<>1__state"); if ((fieldInfo == null) ? true : ((byte)(int)fieldInfo.GetValue(__instance) != 0)) { return true; } object currentDungeonFlow = GetCurrentDungeonFlow(); if (currentDungeonFlow == null) { return true; } object dawnInfo = GetDawnInfo(currentDungeonFlow); if (dawnInfo != null) { return true; } Plugin.Log.LogWarning((object)("DawnLib returned null DawnDungeonInfo for dungeon flow '" + GetObjectName(currentDungeonFlow) + "'. Letting vanilla/LLL generation continue.")); GenerateCurrentDungeon(); generatedOnceAfterNull = true; if (fieldInfo != null) { fieldInfo.SetValue(__instance, -2); } __result = false; return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Guard prefix failed; allowing DawnLib original coroutine to run. " + ex)); return true; } } private static Exception Finalizer(Exception __exception, object __instance, ref bool __result) { if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } try { object currentDungeonFlow = GetCurrentDungeonFlow(); object obj = ((currentDungeonFlow == null) ? null : GetDawnInfo(currentDungeonFlow)); if (currentDungeonFlow != null && obj == null) { Plugin.Log.LogWarning((object)("Caught DawnLib null dungeon crash for flow '" + GetObjectName(currentDungeonFlow) + "'. Suppressing and continuing generation.")); if (!generatedOnceAfterNull) { GenerateCurrentDungeon(); generatedOnceAfterNull = true; } FieldInfo fieldInfo = AccessTools.Field(__instance.GetType(), "<>1__state"); if (fieldInfo != null) { fieldInfo.SetValue(__instance, -2); } __result = false; return null; } } catch (Exception ex) { Plugin.Log.LogError((object)("Guard finalizer failed while handling DawnLib null reference: " + ex)); } return __exception; } private static object GetCurrentDungeonFlow() { object staticProperty = GetStaticProperty("RoundManager", "Instance"); object field = GetField(staticProperty, "dungeonGenerator"); object field2 = GetField(field, "Generator"); return GetField(field2, "DungeonFlow"); } private static object GetDawnInfo(object dungeonFlow) { Type type = AccessTools.TypeByName("Dawn.DungeonFlowExtensions"); MethodInfo methodInfo = AccessTools.Method(type, "GetDawnInfo", (Type[])null, (Type[])null); if (!(methodInfo == null)) { return methodInfo.Invoke(null, new object[1] { dungeonFlow }); } return null; } private static void GenerateCurrentDungeon() { object staticProperty = GetStaticProperty("RoundManager", "Instance"); object field = GetField(staticProperty, "dungeonGenerator"); MethodInfo methodInfo = ((field == null) ? null : AccessTools.Method(field.GetType(), "Generate", (Type[])null, (Type[])null)); if (methodInfo == null) { Plugin.Log.LogWarning((object)"Could not find RuntimeDungeon.Generate(); generation was not resumed."); } else { methodInfo.Invoke(field, null); } } private static object GetStaticProperty(string typeName, string propertyName) { Type type = AccessTools.TypeByName(typeName); PropertyInfo propertyInfo = AccessTools.Property(type, propertyName); if (!(propertyInfo == null)) { return propertyInfo.GetValue(null, null); } return null; } private static object GetField(object instance, string fieldName) { if (instance == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); if (!(fieldInfo == null)) { return fieldInfo.GetValue(instance); } return null; } private static string GetObjectName(object obj) { if (obj == null) { return ""; } PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "name"); object obj2 = ((propertyInfo == null) ? null : propertyInfo.GetValue(obj, null)); if (obj2 != null) { return obj2.ToString(); } return obj.ToString(); } }