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 InteropFixes v1.0.1
InteropFixes.dll
Decompiled 3 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("InteropFixes")] [assembly: AssemblyDescription("Runtime compatibility fixes for Valheim mods")] [assembly: AssemblyCompany("sighsorry")] [assembly: AssemblyProduct("InteropFixes")] [assembly: ComVisible(false)] [assembly: Guid("D710223A-7033-4535-B9A8-C3E2D98D20DF")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 InteropFixes { internal static class CharacterLifecycleCompatibility { private static bool _installed; internal static void TryInstall(Harmony harmony) { //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Expected O, but got Unknown //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Expected O, but got Unknown //IL_0217: Expected O, but got Unknown //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Expected O, but got Unknown if (_installed) { return; } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNetScene), "Destroy", new Type[1] { typeof(GameObject) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(StatusEffect), "RemoveStartEffects", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(Character), "OnDestroy", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(ZNetScene), "OnDestroy", (Type[])null, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(StatusEffect), "m_character"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(StatusEffect), "m_startEffectInstances"); FieldInfo fieldInfo3 = AccessTools.Field(typeof(Character), "m_seman"); MethodInfo methodInfo5 = AccessTools.DeclaredMethod(typeof(CharacterLifecycleCompatibility), "TrackDestroyPrefix", (Type[])null, (Type[])null); MethodInfo methodInfo6 = AccessTools.DeclaredMethod(typeof(CharacterLifecycleCompatibility), "RemoveStartEffectsPrefix", (Type[])null, (Type[])null); MethodInfo methodInfo7 = AccessTools.DeclaredMethod(typeof(CharacterLifecycleCompatibility), "CharacterOnDestroyPrefix", (Type[])null, (Type[])null); MethodInfo methodInfo8 = AccessTools.DeclaredMethod(typeof(CharacterLifecycleCompatibility), "CharacterOnDestroyFinalizer", (Type[])null, (Type[])null); MethodInfo methodInfo9 = AccessTools.DeclaredMethod(typeof(CharacterLifecycleCompatibility), "SceneOnDestroyPostfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null || fieldInfo == null || fieldInfo2 == null || fieldInfo3 == null || methodInfo5 == null || methodInfo6 == null || methodInfo7 == null || methodInfo8 == null || methodInfo9 == null) { InteropFixesPlugin.ModLogger.LogWarning((object)"Character lifecycle compatibility skipped: one or more required Valheim methods or fields were not found."); return; } try { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo5) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo6) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(methodInfo7) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo8) { priority = 0 }, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(methodInfo9), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _installed = true; InteropFixesPlugin.ModLogger.LogInfo((object)"Installed Character removal tracking, StatusEffect teardown guard, and Character.OnDestroy repair."); } catch (Exception ex) { SafeUnpatch(harmony, methodInfo, methodInfo5); SafeUnpatch(harmony, methodInfo2, methodInfo6); SafeUnpatch(harmony, methodInfo3, methodInfo7); SafeUnpatch(harmony, methodInfo3, methodInfo8); SafeUnpatch(harmony, methodInfo4, methodInfo9); CreatureRemovalTracker.Clear(); bool flag = !IsPatchInstalled(methodInfo, methodInfo5) && !IsPatchInstalled(methodInfo2, methodInfo6) && !IsPatchInstalled(methodInfo3, methodInfo7) && !IsPatchInstalled(methodInfo3, methodInfo8) && !IsPatchInstalled(methodInfo4, methodInfo9); if (!flag) { try { harmony.UnpatchSelf(); } catch { } flag = !IsPatchInstalled(methodInfo, methodInfo5) && !IsPatchInstalled(methodInfo2, methodInfo6) && !IsPatchInstalled(methodInfo3, methodInfo7) && !IsPatchInstalled(methodInfo3, methodInfo8) && !IsPatchInstalled(methodInfo4, methodInfo9); } if (flag) { InteropFixesPlugin.ModLogger.LogWarning((object)("Character lifecycle compatibility was rolled back after an installation failure: " + ex.Message)); } else { InteropFixesPlugin.ModLogger.LogError((object)$"Character lifecycle compatibility installation failed and rollback was incomplete: {ex}"); } } } internal static void ResetInstallationState() { _installed = false; } private static void TrackDestroyPrefix(GameObject __0) { CreatureRemovalTracker.Track(__0); } private static bool RemoveStartEffectsPrefix(Character ___m_character, ref GameObject[]? ___m_startEffectInstances) { if (!CreatureRemovalTracker.IsPending(___m_character)) { return true; } GameObject[] array = ___m_startEffectInstances; if (array == null || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return false; } GameObject[] array2 = array; foreach (GameObject val in array2) { if (Object.op_Implicit((Object)(object)val)) { ZNetView component = val.GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { component.ClaimOwnership(); component.Destroy(); } else { Object.Destroy((Object)(object)val); } } } ___m_startEffectInstances = null; return false; } private static bool CharacterOnDestroyPrefix(Character __instance, SEMan? ___m_seman) { if (___m_seman != null) { return true; } try { CreatureRemovalTracker.RepairCharacterReferences(__instance); } catch (Exception arg) { InteropFixesPlugin.ModLogger.LogWarning((object)$"Failed to repair an uninitialized Character.OnDestroy: {arg}"); } finally { CreatureRemovalTracker.Complete(__instance); } return false; } private static Exception? CharacterOnDestroyFinalizer(Character __instance, Exception? __exception) { bool flag = CreatureRemovalTracker.IsPending(__instance); try { if (flag || __exception != null) { CreatureRemovalTracker.RepairCharacterReferences(__instance); } } catch (Exception arg) { InteropFixesPlugin.ModLogger.LogWarning((object)$"Failed to repair Character.OnDestroy bookkeeping: {arg}"); } finally { CreatureRemovalTracker.Complete(__instance); } return __exception; } private static void SceneOnDestroyPostfix() { CreatureRemovalTracker.Clear(); } private static void SafeUnpatch(Harmony harmony, MethodBase original, MethodInfo patch) { try { harmony.Unpatch(original, patch); } catch { } } private static bool IsPatchInstalled(MethodBase original, MethodInfo expectedPatch) { Patches patchInfo = Harmony.GetPatchInfo(original); if (patchInfo == null) { return false; } if (!ContainsPatch(patchInfo.Prefixes, expectedPatch) && !ContainsPatch(patchInfo.Postfixes, expectedPatch)) { return ContainsPatch(patchInfo.Finalizers, expectedPatch); } return true; } private static bool ContainsPatch(IEnumerable<Patch> patches, MethodInfo expectedPatch) { foreach (Patch patch in patches) { MethodInfo patchMethod = patch.PatchMethod; if ((object)patchMethod == expectedPatch || patchMethod.Equals(expectedPatch)) { return true; } } return false; } } internal static class CreatureRemovalTracker { private sealed class PendingRemoval { internal Character Character { get; } internal float ExpiresAt { get; set; } internal PendingRemoval(Character character, float expiresAt) { Character = character; ExpiresAt = expiresAt; } } private const float PendingLifetimeSeconds = 15f; private const float PruneIntervalSeconds = 1f; private static readonly Dictionary<int, PendingRemoval> PendingByInstanceId = new Dictionary<int, PendingRemoval>(); private static readonly List<int> ExpiredInstanceIds = new List<int>(); private static float _nextPruneAt; internal static void Track(GameObject gameObject) { if (!Object.op_Implicit((Object)(object)gameObject)) { return; } Character component = gameObject.GetComponent<Character>(); if (Object.op_Implicit((Object)(object)component)) { int instanceID = ((Object)component).GetInstanceID(); float expiresAt = Time.realtimeSinceStartup + 15f; if (PendingByInstanceId.TryGetValue(instanceID, out PendingRemoval value) && value.Character == component) { value.ExpiresAt = expiresAt; } else { PendingByInstanceId[instanceID] = new PendingRemoval(component, expiresAt); } } } internal static bool IsPending(Character character) { if (character == null) { return false; } int instanceID = ((Object)character).GetInstanceID(); if (PendingByInstanceId.TryGetValue(instanceID, out PendingRemoval value)) { return value.Character == character; } return false; } internal static void Complete(Character character) { if (character != null) { int instanceID = ((Object)character).GetInstanceID(); if (PendingByInstanceId.TryGetValue(instanceID, out PendingRemoval value) && value.Character == character) { PendingByInstanceId.Remove(instanceID); } } } internal static void Update() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (PendingByInstanceId.Count == 0 || realtimeSinceStartup < _nextPruneAt) { return; } _nextPruneAt = realtimeSinceStartup + 1f; ExpiredInstanceIds.Clear(); foreach (KeyValuePair<int, PendingRemoval> item in PendingByInstanceId) { if (realtimeSinceStartup >= item.Value.ExpiresAt) { ExpiredInstanceIds.Add(item.Key); } } foreach (int expiredInstanceId in ExpiredInstanceIds) { PendingByInstanceId.Remove(expiredInstanceId); } ExpiredInstanceIds.Clear(); } internal static void RepairCharacterReferences(Character character) { if (character == null) { return; } List<Character> allCharacters = Character.GetAllCharacters(); for (int num = allCharacters.Count - 1; num >= 0; num--) { if (allCharacters[num] == character) { allCharacters.RemoveAt(num); } } TryRemoveCharacterHud(character); } internal static void Clear() { PendingByInstanceId.Clear(); ExpiredInstanceIds.Clear(); _nextPruneAt = 0f; } private static void TryRemoveCharacterHud(Character character) { try { if (Object.op_Implicit((Object)(object)EnemyHud.instance)) { EnemyHud.instance.RemoveCharacterHud(character); } } catch (Exception ex) { InteropFixesPlugin.ModLogger.LogDebug((object)("Failed to repair a removed Character HUD reference: " + ex.Message)); } } } [BepInPlugin("sighsorry.InteropFixes", "InteropFixes", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class InteropFixesPlugin : BaseUnityPlugin { internal const string ModGuid = "sighsorry.InteropFixes"; internal const string ModName = "InteropFixes"; internal const string ModVersion = "1.0.1"; internal const string MagicPluginGuid = "blacks7ar.MagicPlugin"; private Harmony? _harmony; internal static ManualLogSource ModLogger { get; private set; } private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown ModLogger = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("sighsorry.InteropFixes"); try { CharacterLifecycleCompatibility.TryInstall(_harmony); } catch (Exception arg) { ModLogger.LogError((object)$"Character lifecycle compatibility initialization failed safely: {arg}"); } try { MagicPluginCompatibility.TryInstall(_harmony); } catch (Exception arg2) { ModLogger.LogError((object)$"MagicPlugin compatibility initialization failed safely: {arg2}"); } } private void Update() { CreatureRemovalTracker.Update(); } private void OnDestroy() { CreatureRemovalTracker.Clear(); if (_harmony == null) { return; } try { _harmony.UnpatchSelf(); MagicPluginCompatibility.RestoreExternalPatchesAndReset(); CharacterLifecycleCompatibility.ResetInstallationState(); } catch (Exception arg) { ModLogger.LogError((object)$"InteropFixes shutdown could not fully restore its patch state: {arg}"); } finally { _harmony = null; } } } internal static class MagicPluginCompatibility { private sealed class ProjectileConfiguration { internal ConfigEntry<float> MagicVelocity { get; } internal ConfigEntry<float> MagicAccuracy { get; } internal ConfigEntry<float> SurtlingStaffAoe { get; } internal ConfigEntry<float> EikthyrStaffAoe { get; } internal ConfigEntry<float> LightningStaffAoe { get; } internal ConfigEntry<float> PoisonStaffAoe { get; } internal ConfigEntry<float> ArcticStaffAoe { get; } internal ConfigEntry<float> ModersAoeRange { get; } internal ConfigEntry<float> ModersChopDamage { get; } internal ConfigEntry<float> ModersFrostDamage { get; } internal ConfigEntry<float> ModersPickaxeDamage { get; } internal ConfigEntry<float> ModersPierceDamage { get; } internal ConfigEntry<float> YagluthAoeRange { get; } internal ConfigEntry<float> YagluthBluntDamage { get; } internal ConfigEntry<float> YagluthChopDamage { get; } internal ConfigEntry<float> YagluthFireDamage { get; } internal ConfigEntry<float> YagluthPickaxeDamage { get; } private ProjectileConfiguration(ConfigEntry<float> magicVelocity, ConfigEntry<float> magicAccuracy, ConfigEntry<float> surtlingStaffAoe, ConfigEntry<float> eikthyrStaffAoe, ConfigEntry<float> lightningStaffAoe, ConfigEntry<float> poisonStaffAoe, ConfigEntry<float> arcticStaffAoe, ConfigEntry<float> modersAoeRange, ConfigEntry<float> modersChopDamage, ConfigEntry<float> modersFrostDamage, ConfigEntry<float> modersPickaxeDamage, ConfigEntry<float> modersPierceDamage, ConfigEntry<float> yagluthAoeRange, ConfigEntry<float> yagluthBluntDamage, ConfigEntry<float> yagluthChopDamage, ConfigEntry<float> yagluthFireDamage, ConfigEntry<float> yagluthPickaxeDamage) { MagicVelocity = magicVelocity; MagicAccuracy = magicAccuracy; SurtlingStaffAoe = surtlingStaffAoe; EikthyrStaffAoe = eikthyrStaffAoe; LightningStaffAoe = lightningStaffAoe; PoisonStaffAoe = poisonStaffAoe; ArcticStaffAoe = arcticStaffAoe; ModersAoeRange = modersAoeRange; ModersChopDamage = modersChopDamage; ModersFrostDamage = modersFrostDamage; ModersPickaxeDamage = modersPickaxeDamage; ModersPierceDamage = modersPierceDamage; YagluthAoeRange = yagluthAoeRange; YagluthBluntDamage = yagluthBluntDamage; YagluthChopDamage = yagluthChopDamage; YagluthFireDamage = yagluthFireDamage; YagluthPickaxeDamage = yagluthPickaxeDamage; } internal static bool TryCreate(Type? pluginType, Type? configType, out ProjectileConfiguration? configuration, out string missingField) { configuration = null; missingField = "MagicPlugin.Plugin"; if (pluginType == null) { return false; } missingField = "MagicPlugin.Functions.ConfigSetup"; if (configType == null) { return false; } if (!TryGetFloatConfig(pluginType, "_magicVelocity", out ConfigEntry<float> entry, out missingField) || !TryGetFloatConfig(pluginType, "_magciAccuracy", out ConfigEntry<float> entry2, out missingField) || !TryGetFloatConfig(configType, "_surtlingStaffAOE", out ConfigEntry<float> entry3, out missingField) || !TryGetFloatConfig(configType, "_eikthyrStaffAOE", out ConfigEntry<float> entry4, out missingField) || !TryGetFloatConfig(configType, "_lightningStaffAOE", out ConfigEntry<float> entry5, out missingField) || !TryGetFloatConfig(configType, "_poisonStaffAOE", out ConfigEntry<float> entry6, out missingField) || !TryGetFloatConfig(configType, "_arcticStaffAOE", out ConfigEntry<float> entry7, out missingField) || !TryGetFloatConfig(configType, "_modersAoeRange", out ConfigEntry<float> entry8, out missingField) || !TryGetFloatConfig(configType, "_modersChopDamage", out ConfigEntry<float> entry9, out missingField) || !TryGetFloatConfig(configType, "_modersFrostDamage", out ConfigEntry<float> entry10, out missingField) || !TryGetFloatConfig(configType, "_modersPickaxeDamage", out ConfigEntry<float> entry11, out missingField) || !TryGetFloatConfig(configType, "_modersPierceDamage", out ConfigEntry<float> entry12, out missingField) || !TryGetFloatConfig(configType, "_yagluthAoeRange", out ConfigEntry<float> entry13, out missingField) || !TryGetFloatConfig(configType, "_yagluthBluntDamage", out ConfigEntry<float> entry14, out missingField) || !TryGetFloatConfig(configType, "_yagluthChopDamage", out ConfigEntry<float> entry15, out missingField) || !TryGetFloatConfig(configType, "_yagluthFireDamage", out ConfigEntry<float> entry16, out missingField) || !TryGetFloatConfig(configType, "_yagluthPickaxeDamage", out ConfigEntry<float> entry17, out missingField)) { return false; } configuration = new ProjectileConfiguration(entry, entry2, entry3, entry4, entry5, entry6, entry7, entry8, entry9, entry10, entry11, entry12, entry13, entry14, entry15, entry16, entry17); return true; } private static bool TryGetFloatConfig(Type ownerType, string fieldName, out ConfigEntry<float> entry, out string missingField) { missingField = ownerType.FullName + "." + fieldName; FieldInfo fieldInfo = AccessTools.Field(ownerType, fieldName); if (fieldInfo == null || !fieldInfo.IsStatic || fieldInfo.FieldType != typeof(ConfigEntry<float>) || !(fieldInfo.GetValue(null) is ConfigEntry<float> val)) { entry = null; return false; } entry = val; return true; } } private sealed class PatchReplacement { internal MethodInfo Original { get; } internal Patch ExternalPatch { get; } internal HarmonyPatchType PatchType { get; } internal PatchReplacement(MethodInfo original, Patch externalPatch, HarmonyPatchType patchType) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Original = original; ExternalPatch = externalPatch; PatchType = patchType; } } private const string PluginTypeName = "MagicPlugin.Plugin"; private const string ConfigTypeName = "MagicPlugin.Functions.ConfigSetup"; private const string AttackPatchTypeName = "MagicPlugin.Patches.AttackPatch"; private const string PlayerPatchTypeName = "MagicPlugin.Patches.PlayerPatch"; private static ProjectileConfiguration? _projectileConfiguration; private static bool _projectilePatchInstalled; private static bool _teleportPatchInstalled; private static bool _registryGuardInstalled; private static bool _reportedProjectileRuntimeError; private static bool _reportedTeleportRuntimeError; private static bool _reportedRegistryRuntimeError; private static PatchReplacement? _projectileReplacement; private static PatchReplacement? _teleportReplacement; internal static void TryInstall(Harmony harmony) { if (!Chainloader.PluginInfos.TryGetValue("blacks7ar.MagicPlugin", out var value)) { InteropFixesPlugin.ModLogger.LogDebug((object)"MagicPlugin is not loaded; MagicPlugin-specific compatibility fixes are inactive."); return; } Assembly magicAssembly = ((object)value.Instance)?.GetType().Assembly ?? FindAssemblyWithType("MagicPlugin.Plugin"); if (magicAssembly == null) { InteropFixesPlugin.ModLogger.LogWarning((object)"MagicPlugin compatibility skipped: the plugin assembly could not be resolved."); return; } string version = value.Metadata.Version?.ToString() ?? "unknown"; TryInstallCapability("projectile compatibility", delegate { TryInstallProjectilePatch(harmony, magicAssembly, version); }); TryInstallCapability("teleport compatibility", delegate { TryInstallTeleportPatch(harmony, magicAssembly, version); }); TryInstallCapability("Character registry guard", delegate { TryInstallRegistryGuard(harmony, magicAssembly, version); }); } internal static void RestoreExternalPatchesAndReset() { RestoreExternalPatch(_projectileReplacement); RestoreExternalPatch(_teleportReplacement); _projectileConfiguration = null; _projectileReplacement = null; _teleportReplacement = null; _projectilePatchInstalled = false; _teleportPatchInstalled = false; _registryGuardInstalled = false; _reportedProjectileRuntimeError = false; _reportedTeleportRuntimeError = false; _reportedRegistryRuntimeError = false; } private static void TryInstallProjectilePatch(Harmony harmony, Assembly magicAssembly, string version) { if (_projectilePatchInstalled) { return; } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Attack), "FireProjectileBurst", (Type[])null, (Type[])null); MethodInfo methodInfo2 = magicAssembly.GetType("MagicPlugin.Patches.AttackPatch", throwOnError: false)?.GetMethod("FireProjectileBurst_Prefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Attack) }, null); if (methodInfo == null || methodInfo2 == null || methodInfo2.ReturnType != typeof(bool)) { InteropFixesPlugin.ModLogger.LogWarning((object)"MagicPlugin projectile compatibility skipped: the expected FireProjectileBurst patch structure was not found."); return; } Patch val = FindOwnedPatch(methodInfo, (HarmonyPatchType)1, methodInfo2); if (val == null) { InteropFixesPlugin.ModLogger.LogWarning((object)"MagicPlugin projectile compatibility skipped: the exact MagicPlugin FireProjectileBurst prefix is not installed."); return; } Type? type = magicAssembly.GetType("MagicPlugin.Plugin", throwOnError: false); Type type2 = magicAssembly.GetType("MagicPlugin.Functions.ConfigSetup", throwOnError: false); if (!ProjectileConfiguration.TryCreate(type, type2, out ProjectileConfiguration configuration, out string missingField)) { InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin projectile compatibility skipped: required float config '" + missingField + "' was not found.")); return; } MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(MagicPluginCompatibility), "FireProjectileBurstPrefix", (Type[])null, (Type[])null); string failure = "the InteropFixes replacement prefix was not found."; if (methodInfo3 == null || !TryReplacePatch(harmony, methodInfo, val, methodInfo3, (HarmonyPatchType)1, out failure)) { InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin projectile compatibility skipped: " + failure)); return; } _projectileConfiguration = configuration; _projectileReplacement = new PatchReplacement(methodInfo, val, (HarmonyPatchType)1); _projectilePatchInstalled = true; InteropFixesPlugin.ModLogger.LogInfo((object)("Installed MagicPlugin FireProjectileBurst compatibility for MagicPlugin " + version + ".")); } private static void TryInstallTeleportPatch(Harmony harmony, Assembly magicAssembly, string version) { if (_teleportPatchInstalled) { return; } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Player), "TeleportTo", new Type[3] { typeof(Vector3), typeof(Quaternion), typeof(bool) }, (Type[])null); MethodInfo methodInfo2 = magicAssembly.GetType("MagicPlugin.Patches.PlayerPatch", throwOnError: false)?.GetMethod("TeleportTo_Postfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(Player), typeof(Vector3).MakeByRefType(), typeof(Quaternion).MakeByRefType() }, null); if (methodInfo == null || methodInfo2 == null || methodInfo2.ReturnType != typeof(void)) { InteropFixesPlugin.ModLogger.LogWarning((object)"MagicPlugin teleport compatibility skipped: the expected Player.TeleportTo patch structure was not found."); return; } Patch val = FindOwnedPatch(methodInfo, (HarmonyPatchType)2, methodInfo2); if (val == null) { InteropFixesPlugin.ModLogger.LogWarning((object)"MagicPlugin teleport compatibility skipped: the exact MagicPlugin TeleportTo postfix is not installed."); return; } MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(MagicPluginCompatibility), "TeleportToPostfix", (Type[])null, (Type[])null); string failure = "the InteropFixes replacement postfix was not found."; if (methodInfo3 == null || !TryReplacePatch(harmony, methodInfo, val, methodInfo3, (HarmonyPatchType)2, out failure)) { InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin teleport compatibility skipped: " + failure)); return; } _teleportReplacement = new PatchReplacement(methodInfo, val, (HarmonyPatchType)2); _teleportPatchInstalled = true; InteropFixesPlugin.ModLogger.LogInfo((object)("Installed MagicPlugin safe teleport compatibility for MagicPlugin " + version + ".")); } private static void TryInstallRegistryGuard(Harmony harmony, Assembly magicAssembly, string version) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown if (_registryGuardInstalled) { return; } MethodInfo methodInfo = magicAssembly.GetType("MagicPlugin.Plugin", throwOnError: false)?.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(MagicPluginCompatibility), "MagicPluginUpdatePrefix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != typeof(void) || methodInfo2 == null) { InteropFixesPlugin.ModLogger.LogWarning((object)"MagicPlugin Character registry guard skipped: MagicPlugin.Plugin.Update did not match the expected structure."); return; } try { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _registryGuardInstalled = true; InteropFixesPlugin.ModLogger.LogInfo((object)("Installed MagicPlugin Character registry guard for MagicPlugin " + version + ".")); } catch (Exception ex) { harmony.Unpatch((MethodBase)methodInfo, methodInfo2); InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin Character registry guard skipped after a patching failure: " + ex.Message)); } } private static bool FireProjectileBurstPrefix(Attack __instance) { try { ProjectileConfiguration projectileConfiguration = _projectileConfiguration; if (projectileConfiguration != null) { ApplyFireProjectileBurstAdjustments(__instance, projectileConfiguration); } } catch (Exception ex) { if (!_reportedProjectileRuntimeError) { _reportedProjectileRuntimeError = true; InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin projectile compatibility failed while applying an adjustment: " + ex.Message)); } } return true; } private static void ApplyFireProjectileBurstAdjustments(Attack attack, ProjectileConfiguration configuration) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 if (attack == null) { return; } Humanoid character = attack.m_character; Player val = (Player)(object)((character is Player) ? character : null); if (val == null) { return; } SharedData val2 = attack.m_weapon?.m_shared; if (val2 == null || (int)val2.m_skillType != 9) { return; } string text = val2.m_name ?? ""; if (text.EndsWith("scepter", StringComparison.Ordinal) || text.Contains("flamestaff") || text.Contains("thunderstaff")) { return; } string ammoType = val2.m_ammoType; if ((ammoType != null && ammoType.Contains("ammo_spells")) || ((Object)(object)val2.m_secondaryAttack?.m_attackProjectile != (Object)null && ((Object)val2.m_secondaryAttack.m_attackProjectile).name == "BDS_DvergerStaffFire_clusterbomb_projectile")) { return; } if (text == "$bmp_arcticstaff" || text == "$item_stafficeshards") { attack.m_projectileVel *= 1.2f; attack.m_projectileVelMin *= 1.2f; attack.m_projectileAccuracy *= 0f; attack.m_projectileAccuracyMin *= 0f; } else { attack.m_projectileVel *= configuration.MagicVelocity.Value; attack.m_projectileVelMin *= configuration.MagicVelocity.Value; attack.m_projectileAccuracy *= configuration.MagicAccuracy.Value; attack.m_projectileAccuracyMin *= configuration.MagicAccuracy.Value; } GameObject attackProjectile = attack.m_attackProjectile; if (Object.op_Implicit((Object)(object)attackProjectile)) { string obj = ((Object)attackProjectile).name ?? ""; string text2 = obj.ToLowerInvariant(); float skillFactor = ((Character)val).GetSkillFactor((SkillType)9); if (text2.Contains("surtlingstaff")) { ApplyProjectileAoe(attackProjectile, configuration.SurtlingStaffAoe, skillFactor); } if (text2.Contains("eikthyrsstaff")) { ApplyProjectileAoe(attackProjectile, configuration.EikthyrStaffAoe, skillFactor); } if (text2.Contains("lightningstaff")) { ApplyProjectileAoe(attackProjectile, configuration.LightningStaffAoe, skillFactor); } if (text2.Contains("poisonstaff")) { ApplyProjectileAoe(attackProjectile, configuration.PoisonStaffAoe, skillFactor); } if (text2.Contains("arcticstaff")) { ApplyProjectileAoe(attackProjectile, configuration.ArcticStaffAoe, skillFactor); } if (obj == "bmp_modersheritage_projectile") { ApplyModersHeritage(attackProjectile, skillFactor, configuration); } if (obj == "bmp_yagluthsheritage_projectile") { ApplyYagluthsHeritage(attackProjectile, skillFactor, configuration); } } } private static void ApplyProjectileAoe(GameObject projectilePrefab, ConfigEntry<float> aoeConfig, float elementalSkillFactor) { Projectile component = projectilePrefab.GetComponent<Projectile>(); if (Object.op_Implicit((Object)(object)component)) { component.m_aoe = aoeConfig.Value + 2f * elementalSkillFactor; } } private static void ApplyModersHeritage(GameObject projectilePrefab, float elementalSkillFactor, ProjectileConfiguration configuration) { Projectile val = TryGetSpawnedProjectile(projectilePrefab); if (Object.op_Implicit((Object)(object)val)) { val.m_aoe = configuration.ModersAoeRange.Value + 2f * elementalSkillFactor; val.m_damage.m_chop = configuration.ModersChopDamage.Value; val.m_damage.m_frost = configuration.ModersFrostDamage.Value * (1f + elementalSkillFactor); val.m_damage.m_pickaxe = configuration.ModersPickaxeDamage.Value; val.m_damage.m_pierce = configuration.ModersPierceDamage.Value; } } private static void ApplyYagluthsHeritage(GameObject projectilePrefab, float elementalSkillFactor, ProjectileConfiguration configuration) { Projectile val = TryGetSpawnedProjectile(projectilePrefab); if (Object.op_Implicit((Object)(object)val)) { val.m_aoe = configuration.YagluthAoeRange.Value + 2f * elementalSkillFactor; val.m_damage.m_blunt = configuration.YagluthBluntDamage.Value; val.m_damage.m_chop = configuration.YagluthChopDamage.Value; val.m_damage.m_fire = configuration.YagluthFireDamage.Value * (1f + elementalSkillFactor); val.m_damage.m_pickaxe = configuration.YagluthPickaxeDamage.Value; } } private static Projectile? TryGetSpawnedProjectile(GameObject projectilePrefab) { GameObject obj = projectilePrefab.GetComponent<Projectile>()?.m_spawnOnHit; SpawnAbility val = ((obj != null) ? obj.GetComponent<SpawnAbility>() : null); if (val?.m_spawnPrefab == null || val.m_spawnPrefab.Length == 0) { return null; } GameObject obj2 = val.m_spawnPrefab[0]; if (obj2 == null) { return null; } return obj2.GetComponent<Projectile>(); } private static void TeleportToPostfix(Player __instance, ref Vector3 pos, ref Quaternion rot) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) try { TeleportFollowingMagicSummons(__instance, pos, rot); } catch (Exception ex) { if (!_reportedTeleportRuntimeError) { _reportedTeleportRuntimeError = true; InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin teleport compatibility failed while moving followed summons: " + ex.Message)); } } } private static void TeleportFollowingMagicSummons(Player player, Vector3 position, Quaternion rotation) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player)) { return; } GameObject gameObject = ((Component)player).gameObject; if (!Object.op_Implicit((Object)(object)gameObject)) { return; } Vector3 position2 = position + ((Component)player).transform.forward; List<Character> allCharacters = Character.GetAllCharacters(); for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if (IsFollowedMagicSummon(val, gameObject)) { Transform transform = ((Component)val).transform; transform.position = position2; transform.rotation = rotation; } } } private static bool IsFollowedMagicSummon(Character character, GameObject owner) { if (!Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)((Component)character).gameObject)) { return false; } ZNetView nview = character.m_nview; if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid()) { return false; } if (!(((Object)((Component)character).gameObject).name ?? "").StartsWith("BMP_", StringComparison.Ordinal) || !character.IsTamed()) { return false; } Tameable component = ((Component)character).GetComponent<Tameable>(); MonsterAI val = (Object.op_Implicit((Object)(object)component) ? component.m_monsterAI : null); return (Object)(object)(Object.op_Implicit((Object)(object)val) ? val.GetFollowTarget() : null) == (Object)(object)owner; } private static void MagicPluginUpdatePrefix() { try { List<Character> allCharacters = Character.GetAllCharacters(); for (int num = allCharacters.Count - 1; num >= 0; num--) { Character val = allCharacters[num]; if (val == null || !Object.op_Implicit((Object)(object)val)) { allCharacters.RemoveAt(num); if (val != null) { TryRemoveCharacterHud(val); } } } } catch (Exception ex) { ReportRegistryRuntimeError(ex); } } private static void TryRemoveCharacterHud(Character character) { try { if (Object.op_Implicit((Object)(object)EnemyHud.instance)) { EnemyHud.instance.RemoveCharacterHud(character); } } catch (Exception ex) { ReportRegistryRuntimeError(ex); } } private static void ReportRegistryRuntimeError(Exception ex) { if (!_reportedRegistryRuntimeError) { _reportedRegistryRuntimeError = true; InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin Character registry guard failed while pruning stale references: " + ex.Message)); } } private static Patch? FindOwnedPatch(MethodBase original, HarmonyPatchType patchType, MethodInfo expectedMethod) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 Patches patchInfo = Harmony.GetPatchInfo(original); if (patchInfo == null) { return null; } foreach (Patch item in (IEnumerable<Patch>)(((int)patchType == 1) ? patchInfo.Prefixes : patchInfo.Postfixes)) { if (item.owner == "blacks7ar.MagicPlugin" && IsSameMethod(item.PatchMethod, expectedMethod)) { return item; } } return null; } private static bool TryReplacePatch(Harmony harmony, MethodInfo original, Patch externalPatch, MethodInfo replacement, HarmonyPatchType patchType, out string failure) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) bool flag = false; try { harmony.Unpatch((MethodBase)original, externalPatch.PatchMethod); flag = FindOwnedPatch(original, patchType, externalPatch.PatchMethod) == null; if (!flag) { failure = $"the exact external {patchType} could not be removed."; return false; } HarmonyMethod val = new HarmonyMethod(replacement) { priority = externalPatch.priority, before = externalPatch.before, after = externalPatch.after }; if ((int)patchType == 1) { harmony.Patch((MethodBase)original, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { harmony.Patch((MethodBase)original, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } failure = ""; return true; } catch (Exception ex) { try { harmony.Unpatch((MethodBase)original, replacement); } catch { } if (flag) { TryRestoreExternalPatch(original, externalPatch, patchType); } failure = "patch replacement failed (" + ex.Message + ")."; return false; } } private static void TryRestoreExternalPatch(MethodInfo original, Patch externalPatch, HarmonyPatchType patchType) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Invalid comparison between Unknown and I4 try { HarmonyMethod val = new HarmonyMethod(externalPatch.PatchMethod) { priority = externalPatch.priority, before = externalPatch.before, after = externalPatch.after }; Harmony val2 = new Harmony(externalPatch.owner); if ((int)patchType == 1) { val2.Patch((MethodBase)original, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { val2.Patch((MethodBase)original, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception arg) { InteropFixesPlugin.ModLogger.LogError((object)$"Failed to restore a MagicPlugin patch after compatibility installation failed: {arg}"); } } private static void RestoreExternalPatch(PatchReplacement? replacement) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (replacement == null) { return; } try { if (FindOwnedPatch(replacement.Original, replacement.PatchType, replacement.ExternalPatch.PatchMethod) == null) { TryRestoreExternalPatch(replacement.Original, replacement.ExternalPatch, replacement.PatchType); } } catch (Exception arg) { InteropFixesPlugin.ModLogger.LogError((object)$"Failed to restore a replaced MagicPlugin patch while InteropFixes was shutting down: {arg}"); } } private static void TryInstallCapability(string capability, Action install) { try { install(); } catch (Exception ex) { InteropFixesPlugin.ModLogger.LogWarning((object)("MagicPlugin " + capability + " skipped after a structural probe failed: " + ex.Message)); } } private static bool IsSameMethod(MethodInfo left, MethodInfo right) { if ((object)left == right || left.Equals(right)) { return true; } try { return left.Module.Equals(right.Module) && left.MetadataToken == right.MetadataToken; } catch { return false; } } private static Assembly? FindAssemblyWithType(string fullTypeName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetType(fullTypeName, throwOnError: false) != null) { return assembly; } } return null; } } }