using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("MonstrumLocationManagerFix")] [assembly: AssemblyProduct("MonstrumLocationManagerFix")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyMetadata("Author", "sighsorry")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.1.0")] [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 MonstrumLocationManagerFix { [BepInPlugin("sighsorry.MonstrumLocationManagerFix", "MonstrumLocationManagerFix", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class MonstrumLocationManagerFixPlugin : BaseUnityPlugin { [CompilerGenerated] private sealed class d__32 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; private HashSet 5__1; private Assembly[] <>s__2; private int <>s__3; private Assembly 5__4; private Type 5__5; private MethodInfo[] 5__6; private MethodInfo[] <>s__7; private int <>s__8; private MethodInfo 5__9; private string 5__10; MethodBase IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__32(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; <>s__2 = null; 5__4 = null; 5__5 = null; 5__6 = null; <>s__7 = null; 5__9 = null; 5__10 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_01ed; } <>1__state = -1; 5__1 = new HashSet(StringComparer.Ordinal); <>s__2 = AppDomain.CurrentDomain.GetAssemblies(); <>s__3 = 0; goto IL_0248; IL_0248: if (<>s__3 < <>s__2.Length) { 5__4 = <>s__2[<>s__3]; if (IsTargetPluginAssembly(5__4)) { 5__5 = 5__4.GetType("LocationManager.Location", throwOnError: false); if ((object)5__5 == null) { ManualLogSource? logSource = LogSource; if (logSource != null) { logSource.LogWarning((object)("Found target plugin assembly " + 5__4.GetName().Name + ", but type LocationManager.Location was missing.")); } } else { 5__6 = (from method in 5__5.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where string.Equals(method.Name, "AddLocationToZoneSystem", StringComparison.Ordinal) select method).ToArray(); if (5__6.Length != 0) { <>s__7 = 5__6; <>s__8 = 0; goto IL_020a; } ManualLogSource? logSource2 = LogSource; if (logSource2 != null) { logSource2.LogWarning((object)("Found target type LocationManager.Location in " + 5__4.GetName().Name + ", but method AddLocationToZoneSystem was missing.")); } } } goto IL_023a; } <>s__2 = null; return false; IL_020a: if (<>s__8 < <>s__7.Length) { 5__9 = <>s__7[<>s__8]; 5__10 = $"{5__9.Module.ModuleVersionId:N}:{5__9.MetadataToken}"; if (5__1.Add(5__10)) { <>2__current = 5__9; <>1__state = 1; return true; } goto IL_01ed; } <>s__7 = null; 5__5 = null; 5__6 = null; 5__4 = null; goto IL_023a; IL_023a: <>s__3++; goto IL_0248; IL_01ed: 5__10 = null; 5__9 = null; <>s__8++; goto IL_020a; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__32(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__38 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable instructions; public IEnumerable <>3__instructions; private MethodBase original; public MethodBase <>3__original; private int 5__1; private bool 5__2; private string 5__3; private IEnumerator <>s__4; private CodeInstruction 5__5; private IEnumerator <>s__6; private CodeInstruction 5__7; CodeInstruction IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__38(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { switch (<>1__state) { case -3: case 1: try { } finally { <>m__Finally1(); } break; case -4: case 2: try { } finally { <>m__Finally2(); } break; } 5__3 = null; <>s__4 = null; 5__5 = null; <>s__6 = null; 5__7 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((object)DestroyMethod == null || (object)DestroyImmediateMethod == null) { <>s__4 = instructions.GetEnumerator(); <>1__state = -3; goto IL_00a2; } 5__1 = 0; 5__2 = false; <>s__6 = instructions.GetEnumerator(); <>1__state = -4; break; case 1: <>1__state = -3; 5__5 = null; goto IL_00a2; case 2: { <>1__state = -4; 5__7 = null; break; } IL_00a2: if (<>s__4.MoveNext()) { 5__5 = <>s__4.Current; <>2__current = 5__5; <>1__state = 1; return true; } <>m__Finally1(); <>s__4 = null; return false; } if (<>s__6.MoveNext()) { 5__7 = <>s__6.Current; if (CodeInstructionExtensions.Calls(5__7, DestroyImmediateMethod)) { 5__2 = true; } if (CodeInstructionExtensions.Calls(5__7, DestroyMethod)) { 5__7.operand = DestroyImmediateMethod; 5__1++; 5__2 = true; } <>2__current = 5__7; <>1__state = 2; return true; } <>m__Finally2(); <>s__6 = null; 5__3 = original.DeclaringType?.Assembly.GetName().Name ?? "unknown"; if (5__1 > 0) { ManualLogSource? logSource = LogSource; if (logSource != null) { logSource.LogInfo((object)string.Format("Patched {0}.{1}.{2} and replaced {3} Destroy call(s).", 5__3, "LocationManager.Location", original.Name, 5__1)); } return false; } if (5__2) { ManualLogSource? logSource2 = LogSource; if (logSource2 != null) { logSource2.LogInfo((object)("Verified " + 5__3 + ".LocationManager.Location." + original.Name + " is already using DestroyImmediate.")); } return false; } ManualLogSource? logSource3 = LogSource; if (logSource3 != null) { logSource3.LogWarning((object)("No matching Destroy(Object) call was found in " + 5__3 + ".LocationManager.Location." + original.Name + ".")); } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>s__4 != null) { <>s__4.Dispose(); } } private void <>m__Finally2() { <>1__state = -1; if (<>s__6 != null) { <>s__6.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__38 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__38(0); } d__.instructions = <>3__instructions; d__.original = <>3__original; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } internal const string PluginGuid = "sighsorry.MonstrumLocationManagerFix"; internal const string PluginName = "MonstrumLocationManagerFix"; internal const string PluginVersion = "1.0.1"; private const string ExpandWorldDataGuid = "expand_world_data"; private const string ExpandWorldDataDataManagerTypeFullName = "ExpandWorldData.DataManager"; private const string ExpandWorldDataCleanGhostInitMethodName = "CleanGhostInit"; private const string TargetTypeFullName = "LocationManager.Location"; private const string TargetMethodName = "AddLocationToZoneSystem"; private const string ZdoTypeFullName = "ZDO"; private const string ZNetSceneTypeFullName = "ZNetScene"; private const string ZNetViewTypeFullName = "ZNetView"; private static readonly HashSet TargetPluginGuids = new HashSet(StringComparer.OrdinalIgnoreCase) { "Therzie.Monstrum", "Therzie.MonstrumDeepNorth" }; private static readonly MethodInfo? DestroyMethod = AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null); private static readonly MethodInfo? DestroyImmediateMethod = AccessTools.Method(typeof(Object), "DestroyImmediate", new Type[1] { typeof(Object) }, (Type[])null); private static readonly Type? ZdoType = AccessTools.TypeByName("ZDO"); private static readonly Type? ZNetSceneType = AccessTools.TypeByName("ZNetScene"); private static readonly Type? ZNetViewType = AccessTools.TypeByName("ZNetView"); private static readonly MethodInfo? ZdoCreatedSetter = (((object)ZdoType == null) ? null : AccessTools.PropertySetter(ZdoType, "Created")); private static readonly MethodInfo? ZNetSceneInstanceGetter = (((object)ZNetSceneType == null) ? null : AccessTools.PropertyGetter(ZNetSceneType, "instance")); private static readonly FieldInfo? ZNetSceneInstancesField = (((object)ZNetSceneType == null) ? null : AccessTools.Field(ZNetSceneType, "m_instances")); private static readonly MethodInfo? ZNetViewGetZdoMethod = (((object)ZNetViewType == null) ? null : AccessTools.Method(ZNetViewType, "GetZDO", (Type[])null, (Type[])null)); private static readonly FieldInfo? ZNetViewGhostField = (((object)ZNetViewType == null) ? null : AccessTools.Field(ZNetViewType, "m_ghost")); private static readonly FieldInfo? ZNetViewGhostInitField = (((object)ZNetViewType == null) ? null : AccessTools.Field(ZNetViewType, "m_ghostInit")); private static ManualLogSource? LogSource; private static bool loggedExpandWorldDataMissingScene; private static bool loggedExpandWorldDataMissingZdo; private static bool loggedExpandWorldDataReflectionFailure; private Harmony? harmony; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown LogSource = ((BaseUnityPlugin)this).Logger; harmony = new Harmony("sighsorry.MonstrumLocationManagerFix"); try { int num = 0; num += ApplyLocationManagerFixes(); if (num + ApplyExpandWorldDataCompatibilityFix() == 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"No compatible target assemblies were found. Nothing to patch."); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to apply runtime patch: {arg}"); } } private void OnDestroy() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } private int ApplyLocationManagerFixes() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if ((object)DestroyMethod == null || (object)DestroyImmediateMethod == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not resolve UnityEngine.Object destroy methods for LocationManager patching."); return 0; } MethodBase[] array = FindTargetMethods().ToArray(); if (array.Length == 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"No loaded Therzie Monstrum assemblies were found for the LocationManager fix."); return 0; } MethodBase[] array2 = array; foreach (MethodBase methodBase in array2) { harmony.Patch(methodBase, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(MonstrumLocationManagerFixPlugin), "ReplaceDestroyWithDestroyImmediate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Applied runtime patch to {array.Length} LocationManager method(s)."); return array.Length; } private int ApplyExpandWorldDataCompatibilityFix() { //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown Type type = AccessTools.TypeByName("ExpandWorldData.DataManager"); if ((object)type == null) { return 0; } if ((object)ZNetViewType == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Expand World Data was detected, but the Valheim ZNetView type could not be resolved."); return 0; } if ((object)ZNetViewGhostField == null || (object)ZNetViewGhostInitField == null || (object)ZNetViewGetZdoMethod == null || (object)ZNetSceneInstanceGetter == null || (object)ZNetSceneInstancesField == null || (object)ZdoCreatedSetter == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Expand World Data was detected, but the required Valheim ghost cleanup members could not be resolved."); return 0; } MethodInfo methodInfo = AccessTools.Method(type, "CleanGhostInit", new Type[1] { ZNetViewType }, (Type[])null); if ((object)methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Expand World Data was detected, but DataManager.CleanGhostInit(ZNetView) could not be found."); return 0; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(MonstrumLocationManagerFixPlugin), "ExpandWorldDataCleanGhostInitPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Applied Expand World Data compatibility patch to DataManager.CleanGhostInit(ZNetView)."); return 1; } [IteratorStateMachine(typeof(d__32))] private static IEnumerable FindTargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__32(-2); } private static bool IsTargetPluginAssembly(Assembly assembly) { try { foreach (Type item in SafeGetTypes(assembly)) { object[] customAttributes = item.GetCustomAttributes(typeof(BepInPlugin), inherit: false); foreach (BepInPlugin item2 in customAttributes.OfType()) { if (TargetPluginGuids.Contains(item2.GUID)) { return true; } } } } catch (Exception ex) { ManualLogSource? logSource = LogSource; if (logSource != null) { logSource.LogDebug((object)("Skipping assembly " + assembly.GetName().Name + " during target scan: " + ex.Message)); } } return false; } private static IEnumerable SafeGetTypes(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type type) => (object)type != null); } } public static bool ExpandWorldDataCleanGhostInitPrefix(object? __0) { if (!IsGhostInitActive() || __0 == null) { return false; } try { if ((object)ZNetViewGhostField == null || (object)ZNetViewGetZdoMethod == null || (object)ZNetSceneInstanceGetter == null || (object)ZNetSceneInstancesField == null || (object)ZdoCreatedSetter == null) { LogExpandWorldDataCompatibilityWarning(ref loggedExpandWorldDataReflectionFailure, "Skipped Expand World Data ghost cleanup because required Valheim fields could not be resolved."); return false; } ZNetViewGhostField.SetValue(__0, true); object obj = ZNetViewGetZdoMethod.Invoke(__0, Array.Empty()); if (obj == null) { LogExpandWorldDataCompatibilityWarning(ref loggedExpandWorldDataMissingZdo, "Skipped Expand World Data ghost cleanup because the spawned ZNetView had no ZDO."); return false; } object obj2 = ZNetSceneInstanceGetter.Invoke(null, Array.Empty()); if (obj2 == null || !(ZNetSceneInstancesField.GetValue(obj2) is IDictionary dictionary)) { LogExpandWorldDataCompatibilityWarning(ref loggedExpandWorldDataMissingScene, "Skipped Expand World Data ghost cleanup because ZNetScene instance tracking was unavailable."); return false; } ZdoCreatedSetter.Invoke(obj, new object[1] { false }); dictionary.Remove(obj); } catch (Exception ex) { LogExpandWorldDataCompatibilityWarning(ref loggedExpandWorldDataReflectionFailure, "Expand World Data compatibility patch failed while cleaning ghost init: " + ex.Message); } return false; } private static bool IsGhostInitActive() { object obj = ZNetViewGhostInitField?.GetValue(null); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static void LogExpandWorldDataCompatibilityWarning(ref bool alreadyLogged, string message) { if (!alreadyLogged) { alreadyLogged = true; ManualLogSource? logSource = LogSource; if (logSource != null) { logSource.LogWarning((object)message); } } } [IteratorStateMachine(typeof(d__38))] public static IEnumerable ReplaceDestroyWithDestroyImmediate(IEnumerable instructions, MethodBase original) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__38(-2) { <>3__instructions = instructions, <>3__original = original }; } } }