Decompiled source of Blasted Swimming Tarred Bug Fix v1.2.6

BlastedSwimmingTarredBugFix.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using Unity.Collections;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.2.6.0")]
[assembly: AssemblyInformationalVersion("1.2.6")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("sighsorry")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyProduct("BlastedSwimmingTarredBugFix")]
[assembly: AssemblyTitle("BlastedSwimmingTarredBugFix")]
[assembly: AssemblyVersion("1.2.6.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 BlastedSwimmingTarredBugFix
{
	internal static class CharacterLifecycleCompatibility
	{
		private static bool _installed;

		internal static bool IsInstalled => _installed;

		internal static void TryInstall(Harmony harmony)
		{
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Expected O, but got Unknown
			//IL_01f7: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: 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_startEffectInstances");
			FieldInfo fieldInfo2 = 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 || methodInfo5 == null || methodInfo6 == null || methodInfo7 == null || methodInfo8 == null || methodInfo9 == null)
			{
				LiquidStuckFixPlugin.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;
				LiquidStuckFixPlugin.ModLogger.LogInfo((object)"Installed Character removal tracking, StatusEffect teardown guard, and Character.OnDestroy repair.");
			}
			catch (Exception ex)
			{
				CreatureRemovalTracker.Clear();
				bool num = LiquidStuckFixPlugin.TryUnpatch(harmony, "Character lifecycle compatibility");
				if (num)
				{
					LiquidStuckFixPlugin.ModLogger.LogWarning((object)("Character lifecycle compatibility was rolled back after an installation failure: " + ex.Message));
				}
				else
				{
					LiquidStuckFixPlugin.ModLogger.LogError((object)$"Character lifecycle compatibility installation failed and rollback was incomplete: {ex}");
				}
				_installed = !num;
			}
		}

		internal static void ResetInstallationState()
		{
			_installed = false;
		}

		private static void TrackDestroyPrefix(GameObject __0)
		{
			CreatureRemovalTracker.Track(__0);
		}

		private static void RemoveStartEffectsPrefix(ref GameObject[]? ___m_startEffectInstances)
		{
			GameObject[] array = ___m_startEffectInstances;
			if (array == null || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			for (int i = 0; i < array.Length; i++)
			{
				GameObject val = array[i];
				if (Object.op_Implicit((Object)(object)val))
				{
					ZNetView component = val.GetComponent<ZNetView>();
					if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
					{
						array[i] = null;
						Object.Destroy((Object)(object)val);
					}
				}
			}
		}

		private static bool CharacterOnDestroyPrefix(Character __instance, SEMan? ___m_seman)
		{
			if (___m_seman != null)
			{
				return true;
			}
			try
			{
				CreatureRemovalTracker.RepairCharacterReferences(__instance);
			}
			catch (Exception arg)
			{
				LiquidStuckFixPlugin.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)
			{
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)$"Failed to repair Character.OnDestroy bookkeeping: {arg}");
			}
			finally
			{
				CreatureRemovalTracker.Complete(__instance);
			}
			return __exception;
		}

		private static void SceneOnDestroyPostfix()
		{
			CreatureRemovalTracker.Clear();
		}
	}
	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;
		}

		internal static void TryRemoveCharacterHud(Character character)
		{
			try
			{
				if (Object.op_Implicit((Object)(object)EnemyHud.instance))
				{
					EnemyHud.instance.RemoveCharacterHud(character);
				}
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.ModLogger.LogDebug((object)("Failed to repair a removed Character HUD reference: " + ex.Message));
			}
		}
	}
	internal static class LiquidStateModule
	{
		private static readonly Type[] PatchTypes = new Type[10]
		{
			typeof(CharacterSetLiquidLevelPatch),
			typeof(FloatingSetLiquidLevelPatch),
			typeof(WaterVolumeUpdateFloatersPatch),
			typeof(LiquidSurfaceUpdateFloatersPatch),
			typeof(CharacterIncrementPatch),
			typeof(CharacterDecrementPatch),
			typeof(FloatingIncrementPatch),
			typeof(FloatingDecrementPatch),
			typeof(CharacterUpdateWaterPatch),
			typeof(PlayerTeleportToPatch)
		};

		private static bool _installed;

		internal static bool TryInstall(Harmony harmony)
		{
			if (_installed)
			{
				return true;
			}
			try
			{
				Type[] patchTypes = PatchTypes;
				foreach (Type type in patchTypes)
				{
					harmony.CreateClassProcessor(type).Patch();
				}
				_installed = true;
				return true;
			}
			catch (Exception ex)
			{
				bool num = LiquidStuckFixPlugin.TryUnpatch(harmony, "Liquid state compatibility rollback");
				if (num)
				{
					LiquidStuckFixPlugin.Log.LogWarning((object)("Liquid state compatibility could not be installed and was rolled back: " + ex.Message));
				}
				else
				{
					LiquidStuckFixPlugin.Log.LogError((object)$"Liquid state compatibility installation failed and rollback was incomplete: {ex}");
				}
				_installed = !num;
				return false;
			}
		}

		internal static bool Uninstall(Harmony harmony)
		{
			if (!_installed)
			{
				return true;
			}
			bool num = LiquidStuckFixPlugin.TryUnpatch(harmony, "Liquid state");
			if (num)
			{
				_installed = false;
			}
			return num;
		}
	}
	internal static class LiquidGuard
	{
		private const float NoLiquidLevel = -10000f;

		private const float NoLiquidThreshold = -9999f;

		private const float ActualOverlapPadding = 0.35f;

		private const float PlayerRecoveryProbeInterval = 0.5f;

		private const string WaterVolumeLayerName = "WaterVolume";

		private static readonly Collider[] ProbeBuffer = (Collider[])(object)new Collider[256];

		private static readonly List<Collider> SourceColliderBuffer = new List<Collider>(64);

		private static readonly List<Collider> TargetColliderBuffer = new List<Collider>(64);

		private static readonly FieldInfo? CharacterWaterLevel = AccessTools.Field(typeof(Character), "m_waterLevel");

		private static readonly FieldInfo? CharacterTarLevel = AccessTools.Field(typeof(Character), "m_tarLevel");

		private static readonly FieldInfo? CharacterLiquidLevel = AccessTools.Field(typeof(Character), "m_liquidLevel");

		private static readonly FieldInfo? CharacterCachedLiquidDepth = AccessTools.Field(typeof(Character), "m_cashedInLiquidDepth");

		private static readonly FieldInfo? CharacterSwimTimer = AccessTools.Field(typeof(Character), "m_swimTimer");

		private static readonly FieldInfo? CharacterLiquids = AccessTools.Field(typeof(Character), "m_liquids");

		private static readonly FieldInfo? FloatingWaterLevel = AccessTools.Field(typeof(Floating), "m_waterLevel");

		private static readonly FieldInfo? FloatingTarLevel = AccessTools.Field(typeof(Floating), "m_tarLevel");

		private static readonly FieldInfo? FloatingLiquids = AccessTools.Field(typeof(Floating), "m_liquids");

		private static readonly FieldInfo? WaterVolumeInWater = AccessTools.Field(typeof(WaterVolume), "m_inWater");

		private static readonly FieldInfo? LiquidSurfaceInWater = AccessTools.Field(typeof(LiquidSurface), "m_inWater");

		private static readonly MethodInfo? LiquidSurfaceGetLiquidType = AccessTools.Method(typeof(LiquidSurface), "GetLiquidType", (Type[])null, (Type[])null);

		private static int _waterVolumeMask;

		private static float _nextPlayerRecoveryProbeTime;

		internal static bool ShouldRejectLiquidLevel(Component target, float level, LiquidType type, Component liquidObj, out bool shouldClearTarget)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			shouldClearTarget = false;
			if (!LiquidStuckFixPlugin.LiquidEnabled.Value)
			{
				return false;
			}
			if (level <= -9999f)
			{
				return false;
			}
			if (IsUnityNull(target) || IsUnityNull(liquidObj))
			{
				return false;
			}
			Component val = TryGetLiquidSourceComponent(liquidObj);
			if (IsUnityNull(val))
			{
				return false;
			}
			Character val2 = (Character)(object)((target is Character) ? target : null);
			if (val2 != null)
			{
				try
				{
					if (val2.IsTeleporting())
					{
						return true;
					}
				}
				catch
				{
				}
			}
			if (!SourceStillTouchesTarget(val, target, type))
			{
				shouldClearTarget = !HasActualLiquidOverlap(target, type);
				return true;
			}
			return false;
		}

		internal static void RecoverLocalPlayerLiquidState(Character character)
		{
			if (!LiquidStuckFixPlugin.LiquidEnabled.Value || IsUnityNull(character))
			{
				return;
			}
			Player val = (Player)(object)((character is Player) ? character : null);
			if (val == null || IsUnityNull(Player.m_localPlayer) || (Object)(object)val != (Object)(object)Player.m_localPlayer || ((Character)val).IsTeleporting())
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup < _nextPlayerRecoveryProbeTime) && !(GetFloat(CharacterLiquidLevel, val, -10000f) <= -9999f))
			{
				_nextPlayerRecoveryProbeTime = realtimeSinceStartup + 0.5f;
				if (!HasActualLiquidOverlap((Component)(object)val, (LiquidType)10))
				{
					ClearCharacter((Character)(object)val, (LiquidType)10);
				}
			}
		}

		internal static void PurgeStaleEntries(Component source, LiquidType sourceType)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (!LiquidStuckFixPlugin.LiquidEnabled.Value || IsUnityNull(source))
			{
				return;
			}
			IList inWaterList = GetInWaterList(source);
			if (inWaterList == null || inWaterList.Count == 0)
			{
				return;
			}
			for (int num = inWaterList.Count - 1; num >= 0; num--)
			{
				object obj = inWaterList[num];
				bool flag = IsUnityNull(obj);
				if (!flag)
				{
					Component val = (Component)((obj is Component) ? obj : null);
					if (!IsUnityNull(val))
					{
						flag = !SourceStillTouchesTarget(source, val, sourceType);
					}
					else
					{
						IWaterInteractable val2 = (IWaterInteractable)((obj is IWaterInteractable) ? obj : null);
						if (val2 != null)
						{
							Transform val3 = TryGetInteractableTransform(val2);
							flag = IsUnityNull(val3) || !SourceBoundsContainPoint(source, val3.position);
						}
						else
						{
							flag = true;
						}
					}
				}
				if (flag)
				{
					try
					{
						inWaterList.RemoveAt(num);
						if (!IsUnityNull(obj))
						{
							DecrementInteractable(obj, sourceType);
							Component val4 = (Component)((obj is Component) ? obj : null);
							if (val4 == null || IsUnityNull(val4) || !HasActualLiquidOverlap(val4, sourceType))
							{
								ClearTargetLiquid(obj, sourceType);
							}
						}
					}
					catch (Exception ex)
					{
						string text = (IsUnityNull(source) ? "<null>" : ((Object)source).name);
						LiquidStuckFixPlugin.Log.LogWarning((object)("Failed to purge stale liquid entry from " + text + ": " + ex.Message));
					}
				}
			}
		}

		internal static bool SafeIncrement(object target, LiquidType type, ref int result)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			if (!LiquidStuckFixPlugin.LiquidEnabled.Value)
			{
				return true;
			}
			int[] liquidCounters = GetLiquidCounters(target);
			int num = (int)type;
			if (liquidCounters == null || num < 0 || num >= liquidCounters.Length)
			{
				return true;
			}
			int num2 = Math.Max(0, liquidCounters[num]);
			liquidCounters[num] = ((num2 == int.MaxValue) ? int.MaxValue : (num2 + 1));
			result = liquidCounters[num];
			return false;
		}

		internal static bool SafeDecrement(object target, LiquidType type, ref int result)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			if (!LiquidStuckFixPlugin.LiquidEnabled.Value)
			{
				return true;
			}
			int[] liquidCounters = GetLiquidCounters(target);
			int num = (int)type;
			if (liquidCounters == null || num < 0 || num >= liquidCounters.Length)
			{
				return true;
			}
			int num2 = liquidCounters[num];
			liquidCounters[num] = ((num2 > 0) ? (num2 - 1) : 0);
			result = liquidCounters[num];
			return false;
		}

		internal static void ClearTargetLiquid(object target, LiquidType type)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Character val = (Character)((target is Character) ? target : null);
			if (val != null && !IsUnityNull(val))
			{
				ClearCharacter(val, type);
				return;
			}
			Floating val2 = (Floating)((target is Floating) ? target : null);
			if (val2 != null && !IsUnityNull(val2))
			{
				ClearFloating(val2, type);
				return;
			}
			IWaterInteractable val3 = (IWaterInteractable)((target is IWaterInteractable) ? target : null);
			if (val3 != null)
			{
				try
				{
					val3.SetLiquidLevel(-10000f, type, (Component)null);
				}
				catch
				{
				}
			}
		}

		private static void ClearCharacter(Character character, LiquidType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type == 10 || (int)type == 0)
			{
				SetFloat(CharacterWaterLevel, character, -10000f);
			}
			if ((int)type == 10 || (int)type == 1)
			{
				SetFloat(CharacterTarLevel, character, -10000f);
			}
			float num = GetFloat(CharacterWaterLevel, character, -10000f);
			float num2 = GetFloat(CharacterTarLevel, character, -10000f);
			float num3 = Mathf.Max(num, num2);
			SetFloat(CharacterLiquidLevel, character, num3);
			SetFloat(CharacterCachedLiquidDepth, character, 0f);
			if (num3 <= -9999f)
			{
				float num4 = GetFloat(CharacterSwimTimer, character, 999f);
				SetFloat(CharacterSwimTimer, character, Mathf.Max(num4, 1f));
			}
			ZeroLiquidCounters(character, type);
		}

		private static void ClearFloating(Floating floating, LiquidType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type == 10 || (int)type == 0)
			{
				SetFloat(FloatingWaterLevel, floating, -10000f);
			}
			if ((int)type == 10 || (int)type == 1)
			{
				SetFloat(FloatingTarLevel, floating, -10000f);
			}
			ZeroLiquidCounters(floating, type);
		}

		private static bool SourceStillTouchesTarget(Component source, Component target, LiquidType requestedType)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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)
			LiquidType? val = TryGetSourceLiquidType(source);
			if (val.HasValue && !LiquidTypeMatches(requestedType, val.Value))
			{
				return false;
			}
			if (!TryGetSourceBounds(source, out var bounds))
			{
				return true;
			}
			Bounds val2 = bounds;
			float boundsPadding = GetBoundsPadding();
			((Bounds)(ref val2)).Expand(boundsPadding * 2f);
			Transform transform = target.transform;
			if (((Bounds)(ref val2)).Contains(transform.position))
			{
				return true;
			}
			GetColliders(target, TargetColliderBuffer);
			foreach (Collider item in TargetColliderBuffer)
			{
				if (!IsUnityNull(item) && item.enabled)
				{
					Bounds bounds2 = item.bounds;
					((Bounds)(ref bounds2)).Expand(boundsPadding * 2f);
					if (((Bounds)(ref val2)).Intersects(bounds2))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool HasActualLiquidOverlap(Component target, LiquidType requestedType)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			if (IsUnityNull(target))
			{
				return false;
			}
			int waterVolumeMask = GetWaterVolumeMask();
			if (waterVolumeMask == 0)
			{
				return true;
			}
			if (!TryGetTargetBounds(target, out var bounds))
			{
				return AnyHitMatchesCurrentLiquid(Physics.OverlapSphereNonAlloc(target.transform.position, 1.35f, ProbeBuffer, waterVolumeMask, (QueryTriggerInteraction)2), requestedType, null);
			}
			float num = 0.35f;
			((Bounds)(ref bounds)).Expand(num * 2f);
			return AnyHitMatchesCurrentLiquid(Physics.OverlapBoxNonAlloc(((Bounds)(ref bounds)).center, ((Bounds)(ref bounds)).extents, ProbeBuffer, Quaternion.identity, waterVolumeMask, (QueryTriggerInteraction)2), requestedType, bounds);
		}

		private static bool AnyHitMatchesCurrentLiquid(int count, LiquidType requestedType, Bounds? targetBounds)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (count >= ProbeBuffer.Length)
			{
				return true;
			}
			int num = Math.Min(count, ProbeBuffer.Length);
			for (int i = 0; i < num; i++)
			{
				Collider val = ProbeBuffer[i];
				if (IsUnityNull(val))
				{
					continue;
				}
				Component val2 = TryGetLiquidSourceComponent((Component)(object)val);
				if (IsUnityNull(val2))
				{
					continue;
				}
				LiquidType? val3 = TryGetSourceLiquidType(val2);
				if (!val3.HasValue || LiquidTypeMatches(requestedType, val3.Value))
				{
					if (!targetBounds.HasValue)
					{
						return true;
					}
					if (!TryGetSourceBounds(val2, out var bounds))
					{
						return true;
					}
					float num2 = 0.35f;
					((Bounds)(ref bounds)).Expand(num2 * 2f);
					if (((Bounds)(ref bounds)).Intersects(targetBounds.Value))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static int GetWaterVolumeMask()
		{
			if (_waterVolumeMask == 0)
			{
				_waterVolumeMask = LayerMask.GetMask(new string[1] { "WaterVolume" });
			}
			return _waterVolumeMask;
		}

		private static float GetBoundsPadding()
		{
			return Math.Max(0f, LiquidStuckFixPlugin.BoundsPadding.Value);
		}

		private static IList? GetInWaterList(Component source)
		{
			if (source is WaterVolume)
			{
				return WaterVolumeInWater?.GetValue(source) as IList;
			}
			if (source is LiquidSurface)
			{
				return LiquidSurfaceInWater?.GetValue(source) as IList;
			}
			return null;
		}

		private static bool SourceBoundsContainPoint(Component source, Vector3 point)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!TryGetSourceBounds(source, out var bounds))
			{
				return true;
			}
			((Bounds)(ref bounds)).Expand(GetBoundsPadding() * 2f);
			return ((Bounds)(ref bounds)).Contains(point);
		}

		private static bool TryGetSourceBounds(Component source, out Bounds bounds)
		{
			return TryGetColliderBounds(source, preferTriggerColliders: true, SourceColliderBuffer, out bounds);
		}

		private static bool TryGetTargetBounds(Component target, out Bounds bounds)
		{
			return TryGetColliderBounds(target, preferTriggerColliders: false, TargetColliderBuffer, out bounds);
		}

		private static bool TryGetColliderBounds(Component component, bool preferTriggerColliders, List<Collider> buffer, out Bounds bounds)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			if (IsUnityNull(component))
			{
				return false;
			}
			GetColliders(component, buffer);
			if (preferTriggerColliders && TryBuildBounds(buffer, triggerOnly: true, out bounds))
			{
				return true;
			}
			return TryBuildBounds(buffer, triggerOnly: false, out bounds);
		}

		private static void GetColliders(Component component, List<Collider> buffer)
		{
			buffer.Clear();
			component.GetComponentsInChildren<Collider>(true, buffer);
		}

		private static bool TryBuildBounds(List<Collider> colliders, bool triggerOnly, out Bounds bounds)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			bool flag = false;
			foreach (Collider collider in colliders)
			{
				if (!IsUnityNull(collider) && collider.enabled && (!triggerOnly || collider.isTrigger))
				{
					if (!flag)
					{
						bounds = collider.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(collider.bounds);
					}
				}
			}
			return flag;
		}

		private static Component? TryGetLiquidSourceComponent(Component source)
		{
			if (IsUnityNull(source))
			{
				return null;
			}
			if (source is WaterVolume || source is LiquidSurface)
			{
				return source;
			}
			WaterVolume val = source.GetComponent<WaterVolume>() ?? source.GetComponentInParent<WaterVolume>() ?? source.GetComponentInChildren<WaterVolume>();
			if (!IsUnityNull(val))
			{
				return (Component?)(object)val;
			}
			LiquidSurface val2 = source.GetComponent<LiquidSurface>() ?? source.GetComponentInParent<LiquidSurface>() ?? source.GetComponentInChildren<LiquidSurface>();
			if (!IsUnityNull(val2))
			{
				return (Component?)(object)val2;
			}
			return null;
		}

		internal static LiquidType? TryGetSourceLiquidType(Component source)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Component val = TryGetLiquidSourceComponent(source);
			if (IsUnityNull(val))
			{
				return null;
			}
			if (val is WaterVolume)
			{
				return (LiquidType)0;
			}
			if (!(val is LiquidSurface))
			{
				return null;
			}
			try
			{
				if (LiquidSurfaceGetLiquidType != null)
				{
					return (LiquidType)LiquidSurfaceGetLiquidType.Invoke(val, Array.Empty<object>());
				}
			}
			catch
			{
			}
			return null;
		}

		private static bool LiquidTypeMatches(LiquidType requested, LiquidType source)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000a: 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)
			if ((int)requested != 10 && (int)source != 10)
			{
				return requested == source;
			}
			return true;
		}

		private static Transform? TryGetInteractableTransform(IWaterInteractable interactable)
		{
			try
			{
				return interactable.GetTransform();
			}
			catch
			{
			}
			return null;
		}

		private static void DecrementInteractable(object item, LiquidType type)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			IWaterInteractable val = (IWaterInteractable)((item is IWaterInteractable) ? item : null);
			if (val == null)
			{
				return;
			}
			try
			{
				val.Decrement(type);
			}
			catch
			{
			}
		}

		private static int[]? GetLiquidCounters(object target)
		{
			try
			{
				Character val = (Character)((target is Character) ? target : null);
				if (val != null && !IsUnityNull(val))
				{
					return CharacterLiquids?.GetValue(val) as int[];
				}
				Floating val2 = (Floating)((target is Floating) ? target : null);
				if (val2 != null && !IsUnityNull(val2))
				{
					return FloatingLiquids?.GetValue(val2) as int[];
				}
				return null;
			}
			catch
			{
				return null;
			}
		}

		private static void ZeroLiquidCounters(object target, LiquidType type)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: 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_0028: Invalid comparison between Unknown and I4
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			int[] liquidCounters = GetLiquidCounters(target);
			if (liquidCounters != null)
			{
				int num = 0;
				if (((int)type == 10 || (int)type == 0) && num >= 0 && num < liquidCounters.Length)
				{
					liquidCounters[num] = 0;
				}
				int num2 = 1;
				if (((int)type == 10 || (int)type == 1) && num2 >= 0 && num2 < liquidCounters.Length)
				{
					liquidCounters[num2] = 0;
				}
			}
		}

		private static float GetFloat(FieldInfo? field, object instance, float fallback)
		{
			try
			{
				return (field?.GetValue(instance) is float num) ? num : fallback;
			}
			catch
			{
				return fallback;
			}
		}

		private static void SetFloat(FieldInfo? field, object instance, float value)
		{
			try
			{
				field?.SetValue(instance, value);
			}
			catch
			{
			}
		}

		private static bool IsUnityNull(object? obj)
		{
			if (obj == null)
			{
				return true;
			}
			Object val = (Object)((obj is Object) ? obj : null);
			if (val != null)
			{
				return val == (Object)null;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Character), "SetLiquidLevel")]
	internal static class CharacterSetLiquidLevelPatch
	{
		private static bool Prefix(Character __instance, float level, LiquidType type, Component liquidObj)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (LiquidGuard.ShouldRejectLiquidLevel((Component)(object)__instance, level, type, liquidObj, out var shouldClearTarget))
				{
					if (shouldClearTarget)
					{
						LiquidGuard.ClearTargetLiquid(__instance, type);
					}
					return false;
				}
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)("Character.SetLiquidLevel guard failed: " + ex.Message));
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Floating), "SetLiquidLevel")]
	internal static class FloatingSetLiquidLevelPatch
	{
		private static bool Prefix(Floating __instance, float level, LiquidType type, Component liquidObj)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (LiquidGuard.ShouldRejectLiquidLevel((Component)(object)__instance, level, type, liquidObj, out var shouldClearTarget))
				{
					if (shouldClearTarget)
					{
						LiquidGuard.ClearTargetLiquid(__instance, type);
					}
					return false;
				}
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)("Floating.SetLiquidLevel guard failed: " + ex.Message));
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(WaterVolume), "UpdateFloaters")]
	internal static class WaterVolumeUpdateFloatersPatch
	{
		private static void Prefix(WaterVolume __instance)
		{
			try
			{
				LiquidGuard.PurgeStaleEntries((Component)(object)__instance, (LiquidType)0);
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)("WaterVolume.UpdateFloaters purge failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(LiquidSurface), "UpdateFloaters")]
	internal static class LiquidSurfaceUpdateFloatersPatch
	{
		private static void Prefix(LiquidSurface __instance)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				LiquidType? val = LiquidGuard.TryGetSourceLiquidType((Component)(object)__instance);
				if (val.HasValue)
				{
					LiquidGuard.PurgeStaleEntries((Component)(object)__instance, val.Value);
				}
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)("LiquidSurface.UpdateFloaters purge failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Increment")]
	internal static class CharacterIncrementPatch
	{
		private static bool Prefix(Character __instance, LiquidType type, ref int __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return LiquidGuard.SafeIncrement(__instance, type, ref __result);
		}
	}
	[HarmonyPatch(typeof(Character), "Decrement")]
	internal static class CharacterDecrementPatch
	{
		private static bool Prefix(Character __instance, LiquidType type, ref int __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return LiquidGuard.SafeDecrement(__instance, type, ref __result);
		}
	}
	[HarmonyPatch(typeof(Floating), "Increment")]
	internal static class FloatingIncrementPatch
	{
		private static bool Prefix(Floating __instance, LiquidType type, ref int __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return LiquidGuard.SafeIncrement(__instance, type, ref __result);
		}
	}
	[HarmonyPatch(typeof(Floating), "Decrement")]
	internal static class FloatingDecrementPatch
	{
		private static bool Prefix(Floating __instance, LiquidType type, ref int __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return LiquidGuard.SafeDecrement(__instance, type, ref __result);
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateWater")]
	internal static class CharacterUpdateWaterPatch
	{
		private static void Postfix(Character __instance)
		{
			try
			{
				LiquidGuard.RecoverLocalPlayerLiquidState(__instance);
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)("Character.UpdateWater recovery failed: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TeleportTo")]
	internal static class PlayerTeleportToPatch
	{
		private static void Postfix(Player __instance, bool __result)
		{
			if (!LiquidStuckFixPlugin.LiquidEnabled.Value || !__result)
			{
				return;
			}
			try
			{
				LiquidGuard.ClearTargetLiquid(__instance, (LiquidType)10);
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)("Player.TeleportTo liquid reset failed: " + ex.Message));
			}
		}
	}
	[BepInPlugin("sighsorry.blastedswimmingtarredbugfix", "BlastedSwimmingTarredBugFix", "1.2.6")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class LiquidStuckFixPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "sighsorry.blastedswimmingtarredbugfix";

		public const string ModName = "BlastedSwimmingTarredBugFix";

		public const string ModVersion = "1.2.6";

		internal const string MyPitsDontLeakGuid = "Azumatt.MyPitsDontLeak";

		internal const string ScenicGuid = "redseiko.valheim.scenic";

		internal const string MagicPluginGuid = "blacks7ar.MagicPlugin";

		private const string LiquidHarmonyId = "sighsorry.blastedswimmingtarredbugfix.LiquidState";

		private const string LiquidVolumeHarmonyId = "sighsorry.blastedswimmingtarredbugfix.LiquidVolumeLifetime";

		private const string SceneCleanupHarmonyId = "sighsorry.blastedswimmingtarredbugfix.SceneCleanup";

		private const string CharacterLifecycleHarmonyId = "sighsorry.blastedswimmingtarredbugfix.CharacterLifecycle";

		private const string MagicPluginHarmonyId = "sighsorry.blastedswimmingtarredbugfix.MagicPlugin";

		private const string SessionPlayerListFontHarmonyId = "sighsorry.blastedswimmingtarredbugfix.SessionPlayerListFont";

		private static readonly ConfigSync SyncedConfig = new ConfigSync("sighsorry.blastedswimmingtarredbugfix")
		{
			DisplayName = "BlastedSwimmingTarredBugFix",
			CurrentVersion = "1.2.6",
			MinimumRequiredVersion = "1.2.6",
			ModRequired = true
		};

		private Harmony? _liquidHarmony;

		private Harmony? _liquidVolumeHarmony;

		private Harmony? _sceneCleanupHarmony;

		private Harmony? _characterLifecycleHarmony;

		private Harmony? _magicPluginHarmony;

		private Harmony? _sessionPlayerListFontHarmony;

		internal static ManualLogSource Log { get; private set; } = null;

		internal static ManualLogSource ModLogger => Log;

		internal static ConfigEntry<bool> LockConfiguration { get; private set; } = null;

		internal static ConfigEntry<bool> LiquidEnabled { get; private set; } = null;

		internal static ConfigEntry<float> BoundsPadding { get; private set; } = null;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfiguration();
			InstallLiquidAndSceneModules();
			InstallCompatibilityModules();
			Log.LogInfo((object)"BlastedSwimmingTarredBugFix 1.2.6 loaded");
		}

		private void Update()
		{
			if (CharacterLifecycleCompatibility.IsInstalled)
			{
				CreatureRemovalTracker.Update();
			}
		}

		private void OnDestroy()
		{
			StopMagicPluginModule();
			StopCharacterLifecycleModule();
			StopSceneCleanupModule();
			StopLiquidVolumeModule();
			StopLiquidStateModule();
			StopSessionPlayerListFontModule();
		}

		private void BindConfiguration()
		{
			LockConfiguration = ((BaseUnityPlugin)this).Config.Bind<bool>("Synchronization", "LockConfiguration", true, "Lock the synchronized liquid settings to the server's values.");
			SyncedConfig.AddLockingConfigEntry<bool>(LockConfiguration);
			LiquidEnabled = BindSynced("Liquid", "Enabled", defaultValue: true, "Enable stale water and tar state protection.");
			BoundsPadding = BindSynced("Liquid", "BoundsPadding", 0.75f, "Meters added to liquid source and target bounds while validating stale water or tar state.");
		}

		private ConfigEntry<T> BindSynced<T>(string section, string key, T defaultValue, string description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description + " [Synced with Server]");
			SyncedConfig.AddConfigEntry<T>(val).SynchronizedConfig = true;
			return val;
		}

		private void InstallLiquidAndSceneModules()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			Harmony liquidHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.LiquidState");
			_liquidHarmony = liquidHarmony;
			TryInitializeModule("Liquid state", delegate
			{
				LiquidStateModule.TryInstall(liquidHarmony);
			});
			Harmony liquidVolumeHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.LiquidVolumeLifetime");
			_liquidVolumeHarmony = liquidVolumeHarmony;
			TryInitializeModule("LiquidVolume lifetime compatibility", delegate
			{
				LiquidVolumeLifetimeInstaller.TryInstall(liquidVolumeHarmony);
			});
			Harmony sceneCleanupHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.SceneCleanup");
			_sceneCleanupHarmony = sceneCleanupHarmony;
			TryInitializeModule("Integrated scene cleanup", delegate
			{
				SceneCleanupInstaller.TryInstall(sceneCleanupHarmony);
			});
		}

		private void InstallCompatibilityModules()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			Harmony characterLifecycleHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.CharacterLifecycle");
			_characterLifecycleHarmony = characterLifecycleHarmony;
			TryInitializeModule("Character lifecycle compatibility", delegate
			{
				CharacterLifecycleCompatibility.TryInstall(characterLifecycleHarmony);
			});
			Harmony magicPluginHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.MagicPlugin");
			_magicPluginHarmony = magicPluginHarmony;
			TryInitializeModule("MagicPlugin compatibility", delegate
			{
				MagicPluginCompatibility.TryInstall(magicPluginHarmony);
			});
			Harmony sessionPlayerListFontHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.SessionPlayerListFont");
			_sessionPlayerListFontHarmony = sessionPlayerListFontHarmony;
			TryInitializeModule("F2 player-list font compatibility", delegate
			{
				SessionPlayerListFontFix.TryInstall(sessionPlayerListFontHarmony);
			});
		}

		private static void TryInitializeModule(string capability, Action install)
		{
			try
			{
				install();
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"{capability} initialization failed safely: {arg}");
			}
		}

		private void StopMagicPluginModule()
		{
			if (_magicPluginHarmony == null)
			{
				return;
			}
			if (!TryUnpatch(_magicPluginHarmony, "MagicPlugin"))
			{
				Log.LogError((object)"Skipped restoring the original MagicPlugin patches because BlastedSwimmingTarredBugFix replacement removal failed.");
				return;
			}
			try
			{
				if (MagicPluginCompatibility.RestoreExternalPatchesAndReset())
				{
					_magicPluginHarmony = null;
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"MagicPlugin compatibility state could not be restored: {arg}");
			}
		}

		private void StopSessionPlayerListFontModule()
		{
			if (_sessionPlayerListFontHarmony == null)
			{
				SessionPlayerListFontFix.Dispose();
			}
			else if (TryUnpatch(_sessionPlayerListFontHarmony, "F2 player-list font compatibility"))
			{
				SessionPlayerListFontFix.Dispose();
				_sessionPlayerListFontHarmony = null;
			}
		}

		private void StopCharacterLifecycleModule()
		{
			CreatureRemovalTracker.Clear();
			if (_characterLifecycleHarmony != null && TryUnpatch(_characterLifecycleHarmony, "Character lifecycle"))
			{
				CharacterLifecycleCompatibility.ResetInstallationState();
				_characterLifecycleHarmony = null;
			}
		}

		private void StopSceneCleanupModule()
		{
			if (_sceneCleanupHarmony != null && TryUnpatch(_sceneCleanupHarmony, "scene cleanup"))
			{
				SceneCleanupInstaller.ResetInstallationState();
				_sceneCleanupHarmony = null;
			}
		}

		private void StopLiquidVolumeModule()
		{
			if (_liquidVolumeHarmony != null && TryUnpatch(_liquidVolumeHarmony, "LiquidVolume lifetime"))
			{
				LiquidVolumeLifetimeInstaller.ResetInstallationState();
				_liquidVolumeHarmony = null;
			}
		}

		private void StopLiquidStateModule()
		{
			if (_liquidHarmony == null)
			{
				return;
			}
			try
			{
				if (LiquidStateModule.Uninstall(_liquidHarmony))
				{
					_liquidHarmony = null;
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Liquid state patches could not be fully removed: {arg}");
			}
		}

		internal static bool TryUnpatch(Harmony harmony, string capability)
		{
			Exception ex = null;
			try
			{
				harmony.UnpatchSelf();
			}
			catch (Exception ex2)
			{
				ex = ex2;
			}
			try
			{
				using IEnumerator<MethodBase> enumerator = harmony.GetPatchedMethods().GetEnumerator();
				if (enumerator.MoveNext())
				{
					MethodBase current = enumerator.Current;
					string text = ((ex == null) ? string.Empty : $" UnpatchSelf also reported: {ex}");
					string text2 = current.DeclaringType?.FullName ?? "<unknown type>";
					Log.LogError((object)(capability + " patches could not be fully removed; BlastedSwimmingTarredBugFix still owns a patch on " + text2 + "." + current.Name + "." + text));
					return false;
				}
			}
			catch (Exception arg)
			{
				Log.LogError((object)($"Could not verify that {capability} patches were fully removed: {arg}" + ((ex == null) ? string.Empty : $" UnpatchSelf also reported: {ex}")));
				return false;
			}
			if (ex != null)
			{
				Log.LogWarning((object)(capability + " patch removal reported an error, but verification found no remaining owned patches: " + ex.Message));
			}
			return true;
		}
	}
	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 _registryGuardInstalled;

		private static bool _reportedProjectileRuntimeError;

		private static bool _reportedTeleportRuntimeError;

		private static bool _reportedRegistryRuntimeError;

		private static PatchReplacement? _projectileReplacement;

		private static PatchReplacement? _teleportReplacement;

		private static FieldRef<Character, ZNetView>? _characterNViewAccessor;

		private static FieldRef<Tameable, MonsterAI>? _tameableMonsterAiAccessor;

		internal static void TryInstall(Harmony harmony)
		{
			if (!Chainloader.PluginInfos.TryGetValue("blacks7ar.MagicPlugin", out var value))
			{
				LiquidStuckFixPlugin.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)
			{
				LiquidStuckFixPlugin.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);
			});
			TryInstallCapability("cosmetic peer-ZDO prevention", delegate
			{
				MagicPluginCosmeticZdoPrevention.TryInstall(harmony, version);
			});
		}

		internal static bool RestoreExternalPatchesAndReset()
		{
			if (RestoreExternalPatch(_projectileReplacement))
			{
				_projectileReplacement = null;
			}
			if (RestoreExternalPatch(_teleportReplacement))
			{
				_teleportReplacement = null;
			}
			_projectileConfiguration = null;
			_characterNViewAccessor = null;
			_tameableMonsterAiAccessor = null;
			_registryGuardInstalled = false;
			_reportedProjectileRuntimeError = false;
			_reportedTeleportRuntimeError = false;
			_reportedRegistryRuntimeError = false;
			MagicPluginCosmeticZdoPrevention.Reset();
			if (_projectileReplacement == null)
			{
				return _teleportReplacement == null;
			}
			return false;
		}

		private static void TryInstallProjectilePatch(Harmony harmony, Assembly magicAssembly, string version)
		{
			if (_projectileReplacement != null)
			{
				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))
			{
				LiquidStuckFixPlugin.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)
			{
				LiquidStuckFixPlugin.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))
			{
				LiquidStuckFixPlugin.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 BlastedSwimmingTarredBugFix replacement prefix was not found.";
			if (methodInfo3 == null || !TryReplacePatch(harmony, methodInfo, val, methodInfo3, (HarmonyPatchType)1, out failure))
			{
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)("MagicPlugin projectile compatibility skipped: " + failure));
				return;
			}
			_projectileConfiguration = configuration;
			_projectileReplacement = new PatchReplacement(methodInfo, val, (HarmonyPatchType)1);
			LiquidStuckFixPlugin.ModLogger.LogInfo((object)("Installed MagicPlugin FireProjectileBurst compatibility for MagicPlugin " + version + "."));
		}

		private static void TryInstallTeleportPatch(Harmony harmony, Assembly magicAssembly, string version)
		{
			if (_teleportReplacement != null)
			{
				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))
			{
				LiquidStuckFixPlugin.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)
			{
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)"MagicPlugin teleport compatibility skipped: the exact MagicPlugin TeleportTo postfix is not installed.");
				return;
			}
			FieldRef<Character, ZNetView> characterNViewAccessor;
			FieldRef<Tameable, MonsterAI> tameableMonsterAiAccessor;
			try
			{
				characterNViewAccessor = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");
				tameableMonsterAiAccessor = AccessTools.FieldRefAccess<Tameable, MonsterAI>("m_monsterAI");
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)("MagicPlugin teleport compatibility skipped: required Valheim field accessors could not be created (" + ex.Message + ")."));
				return;
			}
			MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(MagicPluginCompatibility), "TeleportToPostfix", (Type[])null, (Type[])null);
			string failure = "the BlastedSwimmingTarredBugFix replacement postfix was not found.";
			_characterNViewAccessor = characterNViewAccessor;
			_tameableMonsterAiAccessor = tameableMonsterAiAccessor;
			if (methodInfo3 == null || !TryReplacePatch(harmony, methodInfo, val, methodInfo3, (HarmonyPatchType)2, out failure))
			{
				_characterNViewAccessor = null;
				_tameableMonsterAiAccessor = null;
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)("MagicPlugin teleport compatibility skipped: " + failure));
			}
			else
			{
				_teleportReplacement = new PatchReplacement(methodInfo, val, (HarmonyPatchType)2);
				LiquidStuckFixPlugin.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)
			{
				LiquidStuckFixPlugin.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;
				LiquidStuckFixPlugin.ModLogger.LogInfo((object)("Installed MagicPlugin Character registry guard for MagicPlugin " + version + "."));
			}
			catch (Exception ex)
			{
				harmony.Unpatch((MethodBase)methodInfo, methodInfo2);
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)("MagicPlugin Character registry guard skipped after a patching failure: " + ex.Message));
			}
		}

		private static bool FireProjectileBurstPrefix(Attack __instance, Humanoid ___m_character, ItemData ___m_weapon)
		{
			try
			{
				ProjectileConfiguration projectileConfiguration = _projectileConfiguration;
				if (projectileConfiguration != null)
				{
					ApplyFireProjectileBurstAdjustments(__instance, ___m_character, ___m_weapon, projectileConfiguration);
				}
			}
			catch (Exception ex)
			{
				if (!_reportedProjectileRuntimeError)
				{
					_reportedProjectileRuntimeError = true;
					LiquidStuckFixPlugin.ModLogger.LogWarning((object)("MagicPlugin projectile compatibility failed while applying an adjustment: " + ex.Message));
				}
			}
			return true;
		}

		private static void ApplyFireProjectileBurstAdjustments(Attack attack, Humanoid character, ItemData weapon, ProjectileConfiguration configuration)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			if (attack == null)
			{
				return;
			}
			Player val = (Player)(object)((character is Player) ? character : null);
			if (val == null)
			{
				return;
			}
			SharedData val2 = 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, bool __result)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!__result)
			{
				return;
			}
			try
			{
				TeleportFollowingMagicSummons(__instance, pos, rot);
			}
			catch (Exception ex)
			{
				if (!_reportedTeleportRuntimeError)
				{
					_reportedTeleportRuntimeError = true;
					LiquidStuckFixPlugin.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;
			}
			FieldRef<Character, ZNetView> characterNViewAccessor = _characterNViewAccessor;
			if (characterNViewAccessor == null)
			{
				return false;
			}
			ZNetView val = characterNViewAccessor.Invoke(character);
			if (!Object.op_Implicit((Object)(object)val) || !val.IsValid())
			{
				return false;
			}
			if (!(((Object)((Component)character).gameObject).name ?? "").StartsWith("BMP_", StringComparison.Ordinal) || !character.IsTamed())
			{
				return false;
			}
			Tameable component = ((Component)character).GetComponent<Tameable>();
			FieldRef<Tameable, MonsterAI> tameableMonsterAiAccessor = _tameableMonsterAiAccessor;
			MonsterAI val2 = ((Object.op_Implicit((Object)(object)component) && tameableMonsterAiAccessor != null) ? tameableMonsterAiAccessor.Invoke(component) : null);
			return (Object)(object)(Object.op_Implicit((Object)(object)val2) ? val2.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)
						{
							CreatureRemovalTracker.TryRemoveCharacterHud(val);
						}
					}
				}
			}
			catch (Exception ex)
			{
				ReportRegistryRuntimeError(ex);
			}
		}

		private static void ReportRegistryRuntimeError(Exception ex)
		{
			if (!_reportedRegistryRuntimeError)
			{
				_reportedRegistryRuntimeError = true;
				LiquidStuckFixPlugin.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
				{
				}
				bool num = !flag || TryRestoreExternalPatch(original, externalPatch, patchType);
				failure = "patch replacement failed (" + ex.Message + ").";
				if (!num)
				{
					failure += " The original MagicPlugin patch could not be restored.";
				}
				return false;
			}
		}

		private static bool TryRestoreExternalPatch(MethodInfo original, Patch externalPatch, HarmonyPatchType patchType)
		{
			//IL_00b3: 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)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0032: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			Exception ex = null;
			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 ex2)
			{
				ex = ex2;
			}
			try
			{
				if (FindOwnedPatch(original, patchType, externalPatch.PatchMethod) != null)
				{
					if (ex != null)
					{
						LiquidStuckFixPlugin.ModLogger.LogWarning((object)$"MagicPlugin patch restoration reported an error, but the exact {patchType} was found in the Harmony patch inventory: {ex.Message}");
					}
					return true;
				}
			}
			catch (Exception ex3)
			{
				LiquidStuckFixPlugin.ModLogger.LogError((object)$"Could not verify the restored MagicPlugin {patchType} on {original.DeclaringType?.FullName}.{original.Name}: {ex3}");
				return false;
			}
			LiquidStuckFixPlugin.ModLogger.LogError((object)($"The restored MagicPlugin {patchType} on {original.DeclaringType?.FullName}.{original.Name} was not found in the Harmony patch inventory." + ((ex == null) ? string.Empty : $" Restoration also reported: {ex}")));
			return false;
		}

		private static bool RestoreExternalPatch(PatchReplacement? replacement)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (replacement == null)
			{
				return true;
			}
			try
			{
				if (FindOwnedPatch(replacement.Original, replacement.PatchType, replacement.ExternalPatch.PatchMethod) == null)
				{
					return TryRestoreExternalPatch(replacement.Original, replacement.ExternalPatch, replacement.PatchType);
				}
				return true;
			}
			catch (Exception arg)
			{
				LiquidStuckFixPlugin.ModLogger.LogError((object)$"Failed to restore a replaced MagicPlugin patch while BlastedSwimmingTarredBugFix was shutting down: {arg}");
			}
			return false;
		}

		private static void TryInstallCapability(string capability, Action install)
		{
			try
			{
				install();
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.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;
		}
	}
	internal static class MagicPluginCosmeticZdoPrevention
	{
		private enum LocalizedEffectKind
		{
			None,
			DefaultLifetime,
			ExplicitLifetime
		}

		[Flags]
		private enum CosmeticFeature
		{
			None = 0,
			FlameLaunch = 1,
			ThunderLaunch = 2,
			ThunderHit = 4,
			ArcticLaunch = 8,
			ArcticHit = 0x10,
			ArcticIceblockDestroyed = 0x20,
			IceScepterNovaRing = 0x40,
			All = 0x7F
		}

		[Flags]
		private enum CosmeticCarrierKind
		{
			None = 0,
			FlameStaffLaunch = 1,
			ThunderStaffLaunch = 2,
			ArcticStaffLaunch = 4,
			IceScepterNovaRing = 8,
			ArcticIceblockDestroyed = 0x10
		}

		private readonly struct CosmeticProjectileBurstState
		{
			internal bool WasInside { get; }

			internal CosmeticCarrierKind PreviousMarker { get; }

			internal CosmeticProjectileBurstState(bool wasInside, CosmeticCarrierKind previousMarker)
			{
				WasInside = wasInside;
				PreviousMarker = previousMarker;
			}
		}

		private readonly struct CosmeticProjectileHitState
		{
			internal CosmeticFeature PreviousContext { get; }

			internal CosmeticFeature PreviousSuppressedFeature { get; }

			internal CosmeticProjectileHitState(CosmeticFeature previousContext, CosmeticFeature previousSuppressedFeature)
			{
				PreviousContext = previousContext;
				PreviousSuppressedFeature = previousSuppressedFeature;
			}
		}

		private const string FlameStaffName = "BMP_FlameStaff";

		private const string ThunderStaffName = "BMP_ThunderStaff";

		private const string ArcticStaffName = "BMP_ArcticStaff";

		private const string IceScepterName = "BMP_IceScepter";

		private const string FlameProjectileName = "bmp_flamewand_projectile";

		private const string ThunderProjectileName = "bmp_lightningwand_projectile";

		private const string ArcticProjectileName = "BMP_ArcticStaff_Ice_Projectile";

		private const string ArcticIceblockerName = "BMP_ArcticStaff_Iceblocker";

		private const string IceScepterNovaAoeName = "BMP_DvergerStaffNova_aoe";

		private const string FlameLaunchEffectName = "BMP_Fx_FlameStaff_Launch";

		private const string ThunderLaunchEffectName = "BMP_Fx_ThunderStaff_Launch";

		private const string ArcticLaunchEffectName = "BMP_Fx_ArcticStaff_Iceshard_Launch";

		private const string ThunderExplosionEffectName = "bmp_lightningwand_explosion";

		private const string ArcticHitEffectName = "BMP_Vfx_ArcticStaff_Ice_Hit";

		private const string ColdHitSoundName = "BMP_Sfx_Dragon_Coldball_Explode";

		private const string ArcticDestroyedEffectName = "BMP_Vfx_ArcticStaff_Iceblocker_Destroyed";

		private const string ArcticDestroyedSoundName = "BMP_Sfx_ArcticStaff_Ice_Destroyed";

		private const string IceScepterNovaRingName = "bmp_fx_DvergerMage_Nova_ring";

		private const float LaunchEffectLifetime = 8f;

		private const float ArcticHitEffectLifetime = 8f;

		private const float ColdHitSoundLifetime = 3f;

		private const float ArcticDestroyedEffectLifetime = 5f;

		private const float ArcticDestroyedSoundLifetime = 4f;

		private const float MaximumExplicitCosmeticLifetime = 30f;

		private const float NovaSuppressionTokenLifetime = 3f;

		private static readonly Version MinimumCosmeticPatchVersion = new Version(2, 1, 9);

		private static readonly int FlameProjectileHash = "bmp_flamewand_projectile".GetStableHashCode();

		private static readonly int ThunderProjectileHash = "bmp_lightningwand_projectile".GetStableHashCode();

		private static readonly int ArcticProjectileHash = "BMP_ArcticStaff_Ice_Projectile".GetStableHashCode();

		private static readonly int ArcticIceblockerHash = "BMP_ArcticStaff_Iceblocker".GetStableHashCode();

		private static readonly int IceScepterNovaAoeHash = "BMP_DvergerStaffNova_aoe".GetStableHashCode();

		private static readonly int CosmeticCarrierMarkerHash = "BlastedSwimmingTarredBugFix_MagicCosmeticCarrier".GetStableHashCode();

		private static bool _cosmeticZdoPatchInstalled;

		private static bool _reportedCosmeticRuntimeError;

		private static ZNetScene? _probedCosmeticScene;

		private static CosmeticFeature _cosmeticFeatures;

		private static SharedData? _flameStaffSharedData;

		private static SharedData? _thunderStaffSharedData;

		private static SharedData? _arcticStaffSharedData;

		private static SharedData? _iceScepterSharedData;

		private static EffectList? _flameLaunchEffects;

		private static EffectList? _thunderLaunchEffects;

		private static EffectList? _arcticLaunchEffects;

		private static EffectList? _iceScepterNovaEffects;

		private static GameObject? _flameLaunchEffectPrefab;

		private static GameObject? _thunderLaunchEffectPrefab;

		private static GameObject? _arcticLaunchEffectPrefab;

		private static GameObject? _thunderExplosionEffectPrefab;

		private static GameObject? _arcticHitEffectPrefab;

		private static GameObject? _coldHitSoundPrefab;

		private static GameObject? _arcticDestroyedEffectPrefab;

		private static GameObject? _arcticDestroyedSoundPrefab;

		private static GameObject? _iceScepterNovaRingPrefab;

		private static float _iceScepterNovaRingLifetime;

		private static readonly Dictionary<Character, float> PendingNovaSuppressions = new Dictionary<Character, float>();

		[ThreadStatic]
		private static CosmeticFeature _projectileHitContext;

		[ThreadStatic]
		private static CosmeticFeature _suppressedProjectileHit;

		[ThreadStatic]
		private static bool _insideCosmeticProjectileBurst;

		[ThreadStatic]
		private static CosmeticCarrierKind _suppressedLaunchMarker;

		private static int GetStableHashCode(this string value)
		{
			int num = 5381;
			int num2 = num;
			for (int i = 0; i < value.Length && value[i] != 0; i += 2)
			{
				num = ((num << 5) + num) ^ value[i];
				if (i == value.Length - 1 || value[i + 1] == '\0')
				{
					break;
				}
				num2 = ((num2 << 5) + num2) ^ value[i + 1];
			}
			return num + num2 * 1566083941;
		}

		internal static void Reset()
		{
			_cosmeticZdoPatchInstalled = false;
			_reportedCosmeticRuntimeError = false;
			_probedCosmeticScene = null;
			ClearCosmeticFeatureState();
			_projectileHitContext = CosmeticFeature.None;
			_suppressedProjectileHit = CosmeticFeature.None;
			_insideCosmeticProjectileBurst = false;
			_suppressedLaunchMarker = CosmeticCarrierKind.None;
		}

		internal static void TryInstall(Harmony harmony, string version)
		{
			//IL_0555: Unknown result type (might be due to invalid IL or missing references)
			//IL_055a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0575: Unknown result type (might be due to invalid IL or missing references)
			//IL_057c: Expected O, but got Unknown
			//IL_05b3: Expected O, but got Unknown
			//IL_05c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0603: Unknown result type (might be due to invalid IL or missing references)
			//IL_0608: Unknown result type (might be due to invalid IL or missing references)
			//IL_0619: Expected O, but got Unknown
			//IL_0619: Expected O, but got Unknown
			//IL_0619: Expected O, but got Unknown
			//IL_062d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0632: Unknown result type (might be due to invalid IL or missing references)
			//IL_0642: Expected O, but got Unknown
			//IL_0657: Unknown result type (might be due to invalid IL or missing references)
			//IL_065c: Unknown result type (might be due to invalid IL or missing references)
			//IL_066b: Expected O, but got Unknown
			//IL_067f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0684: Unknown result type (might be due to invalid IL or missing references)
			//IL_0694: Expected O, but got Unknown
			//IL_06a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_06cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_06dc: Expected O, but got Unknown
			//IL_06dc: Expected O, but got Unknown
			//IL_06f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0705: Expected O, but got Unknown
			//IL_071a: Unknown result type (might be due to invalid IL or missing references)
			//IL_071f: Unknown result type (might be due to invalid IL or missing references)
			//IL_072e: Expected O, but got Unknown
			//IL_0743: Unknown result type (might be due to invalid IL or missing references)
			//IL_0748: Unknown result type (might be due to invalid IL or missing references)
			//IL_0757: Expected O, but got Unknown
			//IL_076c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0771: Unknown result type (might be due to invalid IL or missing references)
			//IL_0780: Expected O, but got Unknown
			//IL_0793: Unknown result type (might be due to invalid IL or missing references)
			//IL_0798: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c7: Expected O, but got Unknown
			//IL_07c7: Expected O, but got Unknown
			if (_cosmeticZdoPatchInstalled)
			{
				return;
			}
			if (!TryParseVersion(version, out Version version2) || version2.CompareTo(MinimumCosmeticPatchVersion) < 0)
			{
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)($"MagicPlugin cosmetic peer-ZDO prevention requires MagicPlugin {MinimumCosmeticPatchVersion} or later; " + "MagicPlugin " + version + " keeps its original cosmetic ZDO behavior."));
				return;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNetScene), "Awake", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(Attack), "FireProjectileBurst", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(EffectList), "Create", new Type[6]
			{
				typeof(Vector3),
				typeof(Quaternion),
				typeof(Transform),
				typeof(float),
				typeof(int),
				typeof(ZDOID)
			}, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(ZNetView), "InvokeRPC", new Type[2]
			{
				typeof(string),
				typeof(object[])
			}, (Type[])null);
			MethodInfo methodInfo5 = AccessTools.DeclaredMethod(typeof(ZNetScene), "CreateObject", new Type[1] { typeof(ZDO) }, (Type[])null);
			MethodInfo methodInfo6 = AccessTools.DeclaredMethod(typeof(ZNetScene), "OnZDODestroyed", new Type[1] { typeof(ZDO) }, (Type[])null);
			MethodInfo methodInfo7 = AccessTools.DeclaredMethod(typeof(Projectile), "OnHit", new Type[4]
			{
				typeof(Collider),
				typeof(Vector3),
				typeof(bool),
				typeof(Vector3)
			}, (Type[])null);
			MethodInfo methodInfo8 = AccessTools.DeclaredMethod(typeof(Projectile), "RPC_OnHit", new Type[1] { typeof(long) }, (Type[])null);
			MethodInfo methodInfo9 = AccessTools.DeclaredMethod(typeof(Projectile), "Setup", new Type[6]
			{
				typeof(Character),
				typeof(Vector3),
				typeof(float),
				typeof(HitData),
				typeof(ItemData),
				typeof(ItemData)
			}, (Type[])null);
			MethodInfo methodInfo10 = AccessTools.DeclaredMethod(typeof(Aoe), "Setup", new Type[6]
			{
				typeof(Character),
				typeof(Vector3),
				typeof(float),
				typeof(HitData),
				typeof(ItemData),
				typeof(ItemData)
			}, (Type[])null);
			MethodInfo methodInfo11 = AccessTools.DeclaredMethod(typeof(Destructible), "Awake", Type.EmptyTypes, (Type[])null);
			FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetView), "m_forceDisableInit");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(Projectile), "m_nview");
			FieldInfo fieldInfo3 = AccessTools.Field(typeof(Aoe), "m_nview");
			FieldInfo fieldInfo4 = AccessTools.Field(typeof(Destructible), "m_nview");
			if (methodInfo?.ReturnType != typeof(void) || methodInfo2?.ReturnType != typeof(void) || methodInfo3?.ReturnType != typeof(GameObject[]) || methodInfo4?.ReturnType != typeof(void) || methodInfo5?.ReturnType != typeof(GameObject) || methodInfo6?.ReturnType != typeof(void) || methodInfo7?.ReturnType != typeof(void) || methodInfo8?.ReturnType != typeof(void) || methodInfo9?.ReturnType != typeof(void) || methodInfo10?.ReturnType != typeof(void) || methodInfo11?.ReturnType != typeof(void) || fieldInfo == null || !fieldInfo.IsStatic || fieldInfo.FieldType != typeof(bool) || fieldInfo2?.FieldType != typeof(ZNetView) || fieldInfo3?.FieldType != typeof(ZNetView) || fieldInfo4?.FieldType != typeof(ZNetView))
			{
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)"MagicPlugin cosmetic peer-ZDO prevention skipped: the expected Valheim effect, scene, or projectile structure was not found.");
				return;
			}
			try
			{
				HarmonyMethod val = new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProbeZNetSceneAwakePrefix", (Type[])null)
				{
					priority = 800
				};
				HarmonyMethod val2 = new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProbeZNetSceneAwakePostfix", (Type[])null);
				val2.priority = 0;
				val2.after = new string[3] { "org.bepinex.helpers.ItemManager", "com.jotunn.jotunn", "blacks7ar.MagicPlugin" };
				harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticEffectListCreatePrefix", (Type[])null)
				{
					priority = 0
				}, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticEffectListCreatePostfix", (Type[])null)
				{
					priority = 800
				}, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticEffectListCreateCleanup", (Type[])null)
				{
					priority = 800
				}, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "ProjectileHitRpcPrefix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticNetworkObjectCreatePostfix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticZdoDestroyedPrefix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProjectileHitContextPrefix", (Type[])null)
				{
					priority = 800
				}, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProjectileHitContextFinalizer", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProjectileHitPostfix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProjectileSetupPostfix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo10, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticAoeSetupPostfix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo11, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticIceblockAwakePostfix", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProjectileBurstContextPrefix", (Type[])null)
				{
					priority = 800
				}, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(MagicPluginCosmeticZdoPrevention), "CosmeticProjectileBurstContextFinalizer", (Type[])null)
				{
					priority = 0
				}, (HarmonyMethod)null);
				_cosmeticZdoPatchInstalled = true;
				LiquidStuckFixPlugin.ModLogger.LogInfo((object)("Installed structurally gated MagicPlugin cosmetic peer-ZDO prevention for MagicPlugin " + version + "."));
				ZNetScene instance = ZNetScene.instance;
				if (Object.op_Implicit((Object)(object)instance))
				{
					TryProbeCosmeticFeatures(instance);
				}
			}
			catch (Exception ex)
			{
				_cosmeticZdoPatchInstalled = false;
				_probedCosmeticScene = null;
				ClearCosmeticFeatureState();
				TryUnpatchCosmeticBurstContext(harmony, methodInfo2);
				TryUnpatchCosmeticMethods(harmony, methodInfo, methodInfo3, methodInfo4, methodInfo5, methodInfo6, methodInfo7, methodInfo8, methodInfo9, methodInfo10, methodInfo11);
				LiquidStuckFixPlugin.ModLogger.LogWarning((object)("MagicPlugin cosmetic peer-ZDO prevention skipped after a patching failure: " + ex.Message));
			}
		}

		private static bool TryParseVersion(string value, out Version version)
		{
			int num = value.IndexOfAny(new char[2] { '-', '+' });
			if (Version.TryParse((num >= 0) ? value.Substring(0, num) : value, out Version result))
			{
				version = result;
				return true;
			}
			version = null;
			return false;
		}

		private static void CosmeticProbeZNetSceneAwakePrefix()
		{
			_probedCosmeticScene = null;
			ClearCosmeticFeatureState();
		}

		private static void CosmeticProbeZNetSceneAwakePostfix(ZNetScene __instance)
		{
			TryProbeCosmeticFeatures(__instance);
		}

		private static void TryProbeCosmeticFeatures(ZNetScene scene)
		{
			if (_cosmeticZdoPatchInstalled && Object.op_Implicit((Object)(object)scene) && _probedCosmeticScene != scene)
			{
				_probedCosmeticScene = scene;
				ClearCosmeticFeatureState();
				CosmeticFeature cosmeticFeature = CosmeticFeature.None;
				if (ProbeCosmeticFeature(CosmeticFeature.FlameLaunch, () => TryProbeLaunchFeature(scene, "BMP_FlameStaff", "bmp_flamewand_projectile", FlameProjectileHash, "BMP_Fx_FlameStaff_Launch", ref _flameStaffSharedData, ref _flameLaunchEffects, ref _flameLaunchEffectPrefab)))
				{
					cosmeticFeature |= CosmeticFeature.FlameLaunch;
				}
				if (ProbeCosmeticFeature(CosmeticFeature.ThunderLaunch, () => TryProbeLau