Decompiled source of Blasted Swimming Tarred Bug Fix v1.2.0

BlastedSwimmingTarredBugFix.dll

Decompiled 20 hours 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.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[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.0.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 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)
			{
				SafeUnpatch(harmony, methodInfo, methodInfo5);
				SafeUnpatch(harmony, methodInfo2, methodInfo6);
				SafeUnpatch(harmony, methodInfo3, methodInfo7);
				SafeUnpatch(harmony, methodInfo3, methodInfo8);
				SafeUnpatch(harmony, methodInfo4, methodInfo9);
				CreatureRemovalTracker.Clear();
				bool flag = !IsPatchInstalled(methodInfo, methodInfo5) && !IsPatchInstalled(methodInfo2, methodInfo6) && !IsPatchInstalled(methodInfo3, methodInfo7) && !IsPatchInstalled(methodInfo3, methodInfo8) && !IsPatchInstalled(methodInfo4, methodInfo9);
				if (!flag)
				{
					try
					{
						harmony.UnpatchSelf();
					}
					catch
					{
					}
					flag = !IsPatchInstalled(methodInfo, methodInfo5) && !IsPatchInstalled(methodInfo2, methodInfo6) && !IsPatchInstalled(methodInfo3, methodInfo7) && !IsPatchInstalled(methodInfo3, methodInfo8) && !IsPatchInstalled(methodInfo4, methodInfo9);
				}
				if (flag)
				{
					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 = !flag;
			}
		}

		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();
		}

		private static void SafeUnpatch(Harmony harmony, MethodBase original, MethodInfo patch)
		{
			try
			{
				harmony.Unpatch(original, patch);
			}
			catch
			{
			}
		}

		private static bool IsPatchInstalled(MethodBase original, MethodInfo expectedPatch)
		{
			Patches patchInfo = Harmony.GetPatchInfo(original);
			if (patchInfo == null)
			{
				return false;
			}
			if (!ContainsPatch(patchInfo.Prefixes, expectedPatch) && !ContainsPatch(patchInfo.Postfixes, expectedPatch))
			{
				return ContainsPatch(patchInfo.Finalizers, expectedPatch);
			}
			return true;
		}

		private static bool ContainsPatch(IEnumerable<Patch> patches, MethodInfo expectedPatch)
		{
			foreach (Patch patch in patches)
			{
				MethodInfo patchMethod = patch.PatchMethod;
				if ((object)patchMethod == expectedPatch || patchMethod.Equals(expectedPatch))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class CreatureRemovalTracker
	{
		private sealed class PendingRemoval
		{
			internal Character Character { get; }

			internal float ExpiresAt { get; set; }

			internal PendingRemoval(Character character, float expiresAt)
			{
				Character = character;
				ExpiresAt = expiresAt;
			}
		}

		private const float PendingLifetimeSeconds = 15f;

		private const float PruneIntervalSeconds = 1f;

		private static readonly Dictionary<int, PendingRemoval> PendingByInstanceId = new Dictionary<int, PendingRemoval>();

		private static readonly List<int> ExpiredInstanceIds = new List<int>();

		private static float _nextPruneAt;

		internal static void Track(GameObject gameObject)
		{
			if (!Object.op_Implicit((Object)(object)gameObject))
			{
				return;
			}
			Character component = gameObject.GetComponent<Character>();
			if (Object.op_Implicit((Object)(object)component))
			{
				int instanceID = ((Object)component).GetInstanceID();
				float expiresAt = Time.realtimeSinceStartup + 15f;
				if (PendingByInstanceId.TryGetValue(instanceID, out PendingRemoval value) && value.Character == component)
				{
					value.ExpiresAt = expiresAt;
				}
				else
				{
					PendingByInstanceId[instanceID] = new PendingRemoval(component, expiresAt);
				}
			}
		}

		internal static bool IsPending(Character character)
		{
			if (character == null)
			{
				return false;
			}
			int instanceID = ((Object)character).GetInstanceID();
			if (PendingByInstanceId.TryGetValue(instanceID, out PendingRemoval value))
			{
				return value.Character == character;
			}
			return false;
		}

		internal static void Complete(Character character)
		{
			if (character != null)
			{
				int instanceID = ((Object)character).GetInstanceID();
				if (PendingByInstanceId.TryGetValue(instanceID, out PendingRemoval value) && value.Character == character)
				{
					PendingByInstanceId.Remove(instanceID);
				}
			}
		}

		internal static void Update()
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (PendingByInstanceId.Count == 0 || realtimeSinceStartup < _nextPruneAt)
			{
				return;
			}
			_nextPruneAt = realtimeSinceStartup + 1f;
			ExpiredInstanceIds.Clear();
			foreach (KeyValuePair<int, PendingRemoval> item in PendingByInstanceId)
			{
				if (realtimeSinceStartup >= item.Value.ExpiresAt)
				{
					ExpiredInstanceIds.Add(item.Key);
				}
			}
			foreach (int expiredInstanceId in ExpiredInstanceIds)
			{
				PendingByInstanceId.Remove(expiredInstanceId);
			}
			ExpiredInstanceIds.Clear();
		}

		internal static void RepairCharacterReferences(Character character)
		{
			if (character == null)
			{
				return;
			}
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int num = allCharacters.Count - 1; num >= 0; num--)
			{
				if (allCharacters[num] == character)
				{
					allCharacters.RemoveAt(num);
				}
			}
			TryRemoveCharacterHud(character);
		}

		internal static void Clear()
		{
			PendingByInstanceId.Clear();
			ExpiredInstanceIds.Clear();
			_nextPruneAt = 0f;
		}

		private static void TryRemoveCharacterHud(Character character)
		{
			try
			{
				if (Object.op_Implicit((Object)(object)EnemyHud.instance))
				{
					EnemyHud.instance.RemoveCharacterHud(character);
				}
			}
			catch (Exception ex)
			{
				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 enum RejectReason
		{
			TargetTeleporting = 1,
			SourceNoLongerOverlapsTarget
		}

		private readonly struct RejectLogKey : IEquatable<RejectLogKey>
		{
			private readonly int _targetId;

			private readonly int _sourceId;

			private readonly int _liquidType;

			private readonly int _reason;

			public RejectLogKey(Component target, Component source, LiquidType liquidType, RejectReason reason)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected I4, but got Unknown
				_targetId = ((!IsUnityNull(target)) ? ((Object)target).GetInstanceID() : 0);
				_sourceId = ((!IsUnityNull(source)) ? ((Object)source).GetInstanceID() : 0);
				_liquidType = (int)liquidType;
				_reason = (int)reason;
			}

			public bool Equals(RejectLogKey other)
			{
				if (_targetId == other._targetId && _sourceId == other._sourceId && _liquidType == other._liquidType)
				{
					return _reason == other._reason;
				}
				return false;
			}

			public override bool Equals(object? obj)
			{
				if (obj is RejectLogKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((((_targetId * 397) ^ _sourceId) * 397) ^ _liquidType) * 397) ^ _reason;
			}
		}

		private const float NoLiquidLevel = -10000f;

		private const float NoLiquidThreshold = -9999f;

		private const float ActualOverlapPadding = 0.35f;

		private const float PlayerRecoveryProbeInterval = 0.5f;

		private const float RejectedLogInterval = 1f;

		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 Dictionary<RejectLogKey, float> LastRejectLogTimes = new Dictionary<RejectLogKey, float>();

		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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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())
					{
						LogRejectedLiquidLevel(target, level, type, liquidObj, RejectReason.TargetTeleporting);
						return true;
					}
				}
				catch
				{
				}
			}
			if (!SourceStillTouchesTarget(val, target, type))
			{
				shouldClearTarget = !HasActualLiquidOverlap(target, type);
				LogRejectedLiquidLevel(target, level, type, liquidObj, RejectReason.SourceNoLongerOverlapsTarget);
				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() || GetFloat(CharacterLiquidLevel, val, -10000f) <= -9999f)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup < _nextPlayerRecoveryProbeTime))
			{
				_nextPlayerRecoveryProbeTime = realtimeSinceStartup + 0.5f;
				if (!HasActualLiquidOverlap((Component)(object)val, (LiquidType)10))
				{
					ClearCharacter((Character)(object)val, (LiquidType)10, resetCounter: true, forceStopSwimming: true);
					DebugLog("Recovered stale local player liquid state: " + SafeName(val));
				}
			}
		}

		internal static void PurgeStaleEntries(Component source, LiquidType sourceType)
		{
			//IL_005c: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00c2: 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);
							if (!TargetHasActualLiquidOverlap(obj, sourceType))
							{
								ClearTargetLiquid(obj, sourceType, resetCounter: true, forceStopSwimming: true);
							}
						}
						DebugLog($"Purged stale {sourceType} entry from {SafeName(source)} -> {SafeName(obj)}");
					}
					catch (Exception ex)
					{
						LiquidStuckFixPlugin.Log.LogWarning((object)("Failed to purge stale liquid entry from " + SafeName(source) + ": " + 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;
			}
			liquidCounters[num] = Math.Max(0, liquidCounters[num]) + 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;
			}
			liquidCounters[num] = Math.Max(0, liquidCounters[num] - 1);
			result = liquidCounters[num];
			return false;
		}

		internal static void ClearTargetLiquid(object target, LiquidType type, bool resetCounter, bool forceStopSwimming)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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, resetCounter, forceStopSwimming);
				return;
			}
			Floating val2 = (Floating)((target is Floating) ? target : null);
			if (val2 != null && !IsUnityNull(val2))
			{
				ClearFloating(val2, type, resetCounter);
				return;
			}
			IWaterInteractable val3 = (IWaterInteractable)((target is IWaterInteractable) ? target : null);
			if (val3 != null)
			{
				SetInteractableLiquidLevel(val3, -10000f, type, null);
			}
		}

		private static void ClearCharacter(Character character, LiquidType type, bool resetCounter, bool forceStopSwimming)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			ForEachLiquidIndex(type, delegate(int index)
			{
				switch (index)
				{
				case 0:
					SetFloat(CharacterWaterLevel, character, -10000f);
					break;
				case 1:
					SetFloat(CharacterTarLevel, character, -10000f);
					break;
				}
			});
			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 (forceStopSwimming && num3 <= -9999f)
			{
				float num4 = GetFloat(CharacterSwimTimer, character, 999f);
				SetFloat(CharacterSwimTimer, character, Mathf.Max(num4, 1f));
			}
			if (resetCounter)
			{
				ZeroLiquidCounters(character, type);
			}
		}

		private static void ClearFloating(Floating floating, LiquidType type, bool resetCounter)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			ForEachLiquidIndex(type, delegate(int index)
			{
				switch (index)
				{
				case 0:
					SetFloat(FloatingWaterLevel, floating, -10000f);
					break;
				case 1:
					SetFloat(FloatingTarLevel, floating, -10000f);
					break;
				}
			});
			if (resetCounter)
			{
				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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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, includeChildren: true, 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 TargetHasActualLiquidOverlap(object target, LiquidType requestedType)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			Component val = (Component)((target is Component) ? target : null);
			if (val != null && !IsUnityNull(val))
			{
				return HasActualLiquidOverlap(val, requestedType);
			}
			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, includeChildren: true, preferTriggerColliders: true, SourceColliderBuffer, out bounds);
		}

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

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

		private static void GetColliders(Component component, bool includeChildren, List<Collider> buffer)
		{
			buffer.Clear();
			if (includeChildren)
			{
				component.GetComponentsInChildren<Collider>(true, buffer);
			}
			else
			{
				component.GetComponents<Collider>(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 void SetInteractableLiquidLevel(IWaterInteractable interactable, float level, LiquidType type, Component? source)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				interactable.SetLiquidLevel(level, type, source);
			}
			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_001b: Unknown result type (might be due to invalid IL or missing references)
			int[] counters = GetLiquidCounters(target);
			if (counters == null)
			{
				return;
			}
			ForEachLiquidIndex(type, delegate(int index)
			{
				if (index >= 0 && index < counters.Length)
				{
					counters[index] = 0;
				}
			});
		}

		private static void ForEachLiquidIndex(LiquidType type, Action<int> action)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			if ((int)type == 10)
			{
				action(0);
				action(1);
				return;
			}
			int num = (int)type;
			if (num == 0 || num == 1)
			{
				action(num);
			}
		}

		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;
		}

		private static string SafeName(object? obj)
		{
			if (IsUnityNull(obj))
			{
				return "<null>";
			}
			Object val = (Object)((obj is Object) ? obj : null);
			if (val != null)
			{
				return val.name;
			}
			return obj.GetType().Name;
		}

		private static string SafeTypeName(object? obj)
		{
			if (!IsUnityNull(obj))
			{
				return obj.GetType().Name;
			}
			return "<null>";
		}

		private static string SafePosition(Component? component)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (IsUnityNull(component))
			{
				return "<null>";
			}
			try
			{
				Vector3 position = component.transform.position;
				return $"({position.x:0.##}, {position.y:0.##}, {position.z:0.##})";
			}
			catch
			{
				return "<unknown>";
			}
		}

		private static string RejectReasonText(RejectReason reason)
		{
			return reason switch
			{
				RejectReason.TargetTeleporting => "target is teleporting", 
				RejectReason.SourceNoLongerOverlapsTarget => "source no longer overlaps target", 
				_ => reason.ToString(), 
			};
		}

		private static bool ShouldLogRejectedLiquidLevel(Component target, LiquidType type, Component liquidObj, RejectReason reason)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!LiquidStuckFixPlugin.DebugLogging.Value)
			{
				return false;
			}
			if (LastRejectLogTimes.Count > 2048)
			{
				LastRejectLogTimes.Clear();
			}
			RejectLogKey key = new RejectLogKey(target, liquidObj, type, reason);
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (LastRejectLogTimes.TryGetValue(key, out var value) && realtimeSinceStartup - value < 1f)
			{
				return false;
			}
			LastRejectLogTimes[key] = realtimeSinceStartup;
			return true;
		}

		private static void LogRejectedLiquidLevel(Component target, float level, LiquidType type, Component liquidObj, RejectReason reason)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldLogRejectedLiquidLevel(target, type, liquidObj, reason))
			{
				Component obj = TryGetLiquidSourceComponent(liquidObj);
				DebugLog("Rejected SetLiquidLevel: target=" + SafeName(target) + " targetType=" + SafeTypeName(target) + " targetPos=" + SafePosition(target) + " source=" + SafeName(liquidObj) + " sourceType=" + SafeTypeName(liquidObj) + " sourcePos=" + SafePosition(liquidObj) + " recognizedSource=" + SafeName(obj) + " recognizedSourceType=" + SafeTypeName(obj) + " " + $"liquid={type} level={level:0.###} reason={RejectReasonText(reason)}");
			}
		}

		private static void DebugLog(string message)
		{
			if (LiquidStuckFixPlugin.DebugLogging.Value)
			{
				LiquidStuckFixPlugin.Log.LogInfo((object)message);
			}
		}
	}
	[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, resetCounter: true, forceStopSwimming: true);
					}
					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, resetCounter: true, forceStopSwimming: false);
					}
					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, resetCounter: true, forceStopSwimming: true);
			}
			catch (Exception ex)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)("Player.TeleportTo liquid reset failed: " + ex.Message));
			}
		}
	}
	[BepInPlugin("sighsorry.blastedswimmingtarredbugfix", "BlastedSwimmingTarredBugFix", "1.2.0")]
	[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.0";

		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 static readonly ConfigSync SyncedConfig = new ConfigSync("sighsorry.blastedswimmingtarredbugfix")
		{
			DisplayName = "BlastedSwimmingTarredBugFix",
			CurrentVersion = "1.2.0",
			MinimumRequiredVersion = "1.2.0",
			ModRequired = true
		};

		private Harmony? _liquidHarmony;

		private Harmony? _liquidVolumeHarmony;

		private Harmony? _sceneCleanupHarmony;

		private Harmony? _characterLifecycleHarmony;

		private Harmony? _magicPluginHarmony;

		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;

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

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

		private void Update()
		{
			if (_characterLifecycleHarmony != null)
			{
				CreatureRemovalTracker.Update();
			}
		}

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

		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.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "DebugLogging", false, "Log rejected liquid updates, stale purges, and compatibility diagnostics. [Not Synced with Server]");
		}

		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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			RuntimePatchCompatibility.Initialize();
			_liquidHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.LiquidState");
			LiquidStateModule.TryInstall(_liquidHarmony);
			_liquidVolumeHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.LiquidVolumeLifetime");
			LiquidVolumeLifetimeInstaller.TryInstall(_liquidVolumeHarmony);
			_sceneCleanupHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.SceneCleanup");
			SceneCleanupInstaller.TryInstall(_sceneCleanupHarmony);
		}

		private void InstallCompatibilityModules()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			_characterLifecycleHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.CharacterLifecycle");
			try
			{
				CharacterLifecycleCompatibility.TryInstall(_characterLifecycleHarmony);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Character lifecycle compatibility initialization failed safely: {arg}");
			}
			_magicPluginHarmony = new Harmony("sighsorry.blastedswimmingtarredbugfix.MagicPlugin");
			try
			{
				MagicPluginCompatibility.TryInstall(_magicPluginHarmony);
			}
			catch (Exception arg2)
			{
				Log.LogError((object)$"MagicPlugin compatibility initialization failed safely: {arg2}");
			}
		}

		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
			{
				MagicPluginCompatibility.RestoreExternalPatchesAndReset();
				_magicPluginHarmony = null;
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"MagicPlugin compatibility state could not be restored: {arg}");
			}
		}

		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 _projectilePatchInstalled;

		private static bool _teleportPatchInstalled;

		private static bool _registryGuardInstalled;

		private static bool _reportedProjectileRuntimeError;

		private static bool _reportedTeleportRuntimeError;

		private static bool _reportedRegistryRuntimeError;

		private static PatchReplacement? _projectileReplacement;

		private static PatchReplacement? _teleportReplacement;

		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);
			});
		}

		internal static void RestoreExternalPatchesAndReset()
		{
			RestoreExternalPatch(_projectileReplacement);
			RestoreExternalPatch(_teleportReplacement);
			_projectileConfiguration = null;
			_projectileReplacement = null;
			_teleportReplacement = null;
			_characterNViewAccessor = null;
			_tameableMonsterAiAccessor = null;
			_projectilePatchInstalled = false;
			_teleportPatchInstalled = false;
			_registryGuardInstalled = false;
			_reportedProjectileRuntimeError = false;
			_reportedTeleportRuntimeError = false;
			_reportedRegistryRuntimeError = false;
		}

		private static void TryInstallProjectilePatch(Harmony harmony, Assembly magicAssembly, string version)
		{
			if (_projectilePatchInstalled)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Attack), "FireProjectileBurst", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = magicAssembly.GetType("MagicPlugin.Patches.AttackPatch", throwOnError: false)?.GetMethod("FireProjectileBurst_Prefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Attack) }, null);
			if (methodInfo == null || methodInfo2 == null || methodInfo2.ReturnType != typeof(bool))
			{
				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);
			_projectilePatchInstalled = true;
			LiquidStuckFixPlugin.ModLogger.LogInfo((object)("Installed MagicPlugin FireProjectileBurst compatibility for MagicPlugin " + version + "."));
		}

		private static void TryInstallTeleportPatch(Harmony harmony, Assembly magicAssembly, string version)
		{
			if (_teleportPatchInstalled)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Player), "TeleportTo", new Type[3]
			{
				typeof(Vector3),
				typeof(Quaternion),
				typeof(bool)
			}, (Type[])null);
			MethodInfo methodInfo2 = magicAssembly.GetType("MagicPlugin.Patches.PlayerPatch", throwOnError: false)?.GetMethod("TeleportTo_Postfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
			{
				typeof(Player),
				typeof(Vector3).MakeByRefType(),
				typeof(Quaternion).MakeByRefType()
			}, null);
			if (methodInfo == null || methodInfo2 == null || methodInfo2.ReturnType != typeof(void))
			{
				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);
				_teleportPatchInstalled = true;
				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)
						{
							TryRemoveCharacterHud(val);
						}
					}
				}
			}
			catch (Exception ex)
			{
				ReportRegistryRuntimeError(ex);
			}
		}

		private static void TryRemoveCharacterHud(Character character)
		{
			try
			{
				if (Object.op_Implicit((Object)(object)EnemyHud.instance))
				{
					EnemyHud.instance.RemoveCharacterHud(character);
				}
			}
			catch (Exception ex)
			{
				ReportRegistryRuntimeError(ex);
			}
		}

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

		private static void TryRestoreExternalPatch(MethodInfo original, Patch externalPatch, HarmonyPatchType patchType)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			try
			{
				HarmonyMethod val = new HarmonyMethod(externalPatch.PatchMethod)
				{
					priority = externalPatch.priority,
					before = externalPatch.before,
					after = externalPatch.after
				};
				Harmony val2 = new Harmony(externalPatch.owner);
				if ((int)patchType == 1)
				{
					val2.Patch((MethodBase)original, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				else
				{
					val2.Patch((MethodBase)original, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception arg)
			{
				LiquidStuckFixPlugin.ModLogger.LogError((object)$"Failed to restore a MagicPlugin patch after compatibility installation failed: {arg}");
			}
		}

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

		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 RuntimePatchCompatibility
	{
		internal static bool MyPitsDontLeakLoaded { get; private set; }

		internal static bool ScenicLoaded { get; private set; }

		internal static void Initialize()
		{
			MyPitsDontLeakLoaded = Chainloader.PluginInfos.ContainsKey("Azumatt.MyPitsDontLeak");
			ScenicLoaded = Chainloader.PluginInfos.ContainsKey("redseiko.valheim.scenic");
			if (MyPitsDontLeakLoaded)
			{
				LiquidStuckFixPlugin.Log.LogInfo((object)"MyPitsDontLeak detected; skipping the integrated LiquidVolume lifetime patches.");
			}
			if (ScenicLoaded)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)"Scenic detected; skipping the integrated scene cleanup patch. Remove Scenic to use the hardened built-in implementation.");
			}
		}
	}
	internal static class LiquidVolumeLifetimeInstaller
	{
		private static bool _installed;

		internal static void TryInstall(Harmony harmony)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			if (_installed || RuntimePatchCompatibility.MyPitsDontLeakLoaded)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(LiquidVolume), "Awake", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(LiquidVolume), "OnDestroy", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(LiquidVolumeAwakeLifetimePatch), "Transpiler", (Type[])null, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(LiquidVolumeOnDestroyLifetimePatch), "Transpiler", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)"LiquidVolume lifetime compatibility skipped: one or more required methods were not found.");
				return;
			}
			try
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null);
				_installed = true;
				LiquidStuckFixPlugin.Log.LogInfo((object)"Installed LiquidVolume lifetime compatibility.");
			}
			catch (Exception ex)
			{
				SafeUnpatch(harmony, methodInfo, methodInfo3);
				SafeUnpatch(harmony, methodInfo2, methodInfo4);
				bool flag = !IsPatchInstalled(methodInfo, methodInfo3) && !IsPatchInstalled(methodInfo2, methodInfo4);
				if (!flag)
				{
					TryUnpatchSelf(harmony);
					flag = !IsPatchInstalled(methodInfo, methodInfo3) && !IsPatchInstalled(methodInfo2, methodInfo4);
				}
				if (flag)
				{
					LiquidStuckFixPlugin.Log.LogWarning((object)("LiquidVolume lifetime compatibility was rolled back after an installation failure: " + ex.Message));
				}
				else
				{
					LiquidStuckFixPlugin.Log.LogError((object)$"LiquidVolume lifetime compatibility installation failed and rollback was incomplete: {ex}");
				}
				_installed = !flag;
			}
		}

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

		private static void SafeUnpatch(Harmony harmony, MethodBase original, MethodInfo patch)
		{
			try
			{
				harmony.Unpatch(original, patch);
			}
			catch
			{
			}
		}

		private static bool IsPatchInstalled(MethodBase original, MethodInfo expectedPatch)
		{
			Patches patchInfo = Harmony.GetPatchInfo(original);
			if (patchInfo == null)
			{
				return false;
			}
			return ContainsPatch(patchInfo.Transpilers, expectedPatch);
		}

		private static bool ContainsPatch(IEnumerable<Patch> patches, MethodInfo expectedPatch)
		{
			foreach (Patch patch in patches)
			{
				MethodInfo patchMethod = patch.PatchMethod;
				if ((object)patchMethod == expectedPatch || patchMethod.Equals(expectedPatch))
				{
					return true;
				}
			}
			return false;
		}

		private static void TryUnpatchSelf(Harmony harmony)
		{
			try
			{
				harmony.UnpatchSelf();
			}
			catch
			{
			}
		}
	}
	internal static class SceneCleanupInstaller
	{
		private static bool _installed;

		internal static void TryInstall(Harmony harmony)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			if (_installed || RuntimePatchCompatibility.ScenicLoaded)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNetScene), "RemoveObjects", new Type[2]
			{
				typeof(List<ZDO>),
				typeof(List<ZDO>)
			}, (Type[])null);
			FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetScene), "m_instances");
			MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(ZNetSceneRemoveObjectsPatch), "Prefix", (Type[])null, (Type[])null);
			if (methodInfo == null || fieldInfo == null || methodInfo2 == null)
			{
				LiquidStuckFixPlugin.Log.LogWarning((object)"Integrated scene cleanup skipped: one or more required ZNetScene members were not found.");
				return;
			}
			try
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_installed = true;
				LiquidStuckFixPlugin.Log.LogInfo((object)"Installed integrated scene cleanup compatibility.");
			}
			catch (Exception ex)
			{
				SafeUnpatch(harmony, methodInfo, methodInfo2);
				bool flag = !IsPatchInstalled(methodInfo, methodInfo2);
				if (!flag)
				{
					TryUnpatchSelf(harmony);
					flag = !IsPatchInstalled(methodInfo, methodInfo2);
				}
				if (flag)
				{
					LiquidStuckFixPlugin.Log.LogWarning((object)("Integrated scene cleanup was rolled back after an installation failure: " + ex.Message));
				}
				else
				{
					LiquidStuckFixPlugin.Log.LogError((object)$"Integrated scene cleanup installation failed and rollback was incomplete: {ex}");
				}
				_installed = !flag;
			}
		}

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

		private static void SafeUnpatch(Harmony harmony, MethodBase original, MethodInfo patch)
		{
			try
			{
				harmony.Unpatch(original, patch);
			}
			catch
			{
			}
		}

		private static bool IsPatchInstalled(MethodBase original, MethodInfo expectedPatch)
		{
			Patches patchInfo = Harmony.GetPatchInfo(original);
			if (patchInfo == null)
			{
				return false;
			}
			foreach (Patch prefix in patchInfo.Prefixes)
			{
				MethodInfo patchMethod = prefix.PatchMethod;
				if ((object)patchMethod == expectedPatch || patchMethod.Equals(expectedPatch))
				{
					return true;
				}
			}
			return false;
		}

		private static void TryUnpatchSelf(Harmony harmony)
		{
			try
			{
				harmony.UnpatchSelf();
			}
			catch
			{
			}
		}
	}
	internal static class LiquidVolumeLifetime
	{
		private static readonly Type[] NativeArrayConstructorParameters = new Type[3]
		{
			typeof(int),
			typeof(Allocator),
			typeof(NativeArrayOptions)
		};

		internal static Allocator SelectAllocator()
		{
			return (Allocator)4;
		}

		internal static void DisposeRaycastHits(ref NativeArray<RaycastHit> array)
		{
			if (array.IsCreated)
			{
				array.Dispose();
			}
		}

		internal static void DisposeRaycastCommands(ref NativeArray<RaycastCommand> array)
		{
			if (array.IsCreated)
			{
				array.Dispose();
			}
		}

		internal static IEnumerable<CodeInstruction> ReplaceAllocators(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			ConstructorInfo constructorInfo = AccessTools.Constructor(typeof(NativeArray<RaycastHit>), NativeArrayConstructorParameters, false);
			ConstructorInfo constructorInfo2 = AccessTools.Constructor(typeof(NativeArray<RaycastCommand>), NativeArrayConstructorParameters, false);
			MethodInfo methodInfo = AccessTools.Method(typeof(LiquidVolumeLifetime), "SelectAllocator", (Type[])null, (Type[])null);
			if (constructorInfo == null || constructorInfo2 == null || methodInfo == null)
			{
				throw new MissingMethodException("LiquidVolume allocator patch could not find its required NativeArray members.");
			}
			List<int> list2 = FindAllocatorIndices(list, constructorInfo);
			List<int> list3 = FindAllocatorIndices(list, constructorInfo2);
			if (list2.Count != 1 || list3.Count != 1)
			{
				throw new InvalidOperationException("LiquidVolume allocator patch expected one allocation site for each NativeArray type but found " + $"{list2.Count} RaycastHit and {list3.Count} RaycastCommand sites.");
			}
			list[list2[0]].opcode = OpCodes.Call;
			list[list2[0]].operand = methodInfo;
			list[list3[0]].opcode = OpCodes.Call;
			list[list3[0]].operand = methodInfo;
			return list;
		}

		internal static IEnumerable<CodeInstruction> ReplaceDisposals(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(NativeArray<RaycastHit>), "Dispose", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(NativeArray<RaycastCommand>), "Dispose", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(LiquidVolumeLifetime), "DisposeRaycastHits", (Type[])null, (Type[])null);
			MethodInfo methodInfo4 = AccessTools.Method(typeof(LiquidVolumeLifetime), "DisposeRaycastCommands", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null)
			{
				throw new MissingMethodException("LiquidVolume disposal patch could not find its required NativeArray members.");
			}
			List<int> list2 = FindCallIndices(list, methodInfo);
			List<int> list3 = FindCallIndices(list, methodInfo2);
			if (list2.Count != 1 || list3.Count != 1)
			{
				throw new InvalidOperationException("LiquidVolume disposal patch expected one disposal call for each NativeArray type but found " + $"{list2.Count} RaycastHit and {list3.Count} RaycastCommand calls.");
			}
			list[list2[0]].opcode = OpCodes.Call;
			list[list2[0]].operand = methodInfo3;
			list[list3[0]].opcode = OpCodes.Call;
			list[list3[0]].operand = methodInfo4;
			return list;
		}

		private static List<int> FindAllocatorIndices(List<CodeInstruction> codes, ConstructorInfo constructor)
		{
			List<int> list = new List<int>();
			for (int i = 2; i < codes.Count; i++)
			{
				if (!(codes[i].opcode != OpCodes.Newobj) && CodeInstructionExtensions.OperandIs(codes[i], (MemberInfo)constructor))
				{
					int num = i - 2;
					if (CodeInstructionExtensions.LoadsConstant(codes[num], (Enum)(object)(Allocator)3))
					{
						list.Add(num);
					}
				}
			}
			return list;
		}

		private static List<int> FindCallIndices(List<CodeInstruction> codes, MethodInfo method)
		{
			List<int> list = new List<int>();
			for (int i = 0; i < codes.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(codes[i], method))
				{
					list.Add(i);
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(LiquidVolume), "Awake")]
	internal static class LiquidVolumeAwakeLifetimePatch
	{
		internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return LiquidVolumeLifetime.ReplaceAllocators(instructions);
		}
	}
	[HarmonyPatch(typeof(LiquidVolume), "OnDestroy")]
	internal static class LiquidVolumeOnDestroyLifetimePatch
	{
		internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return LiquidVolumeLifetime.ReplaceDisposals(instructions);
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "RemoveObjects", new Type[]
	{
		typeof(List<ZDO>),
		typeof(List<ZDO>)
	})]
	internal static class ZNetSceneRemoveObjectsPatch
	{
		private static readonly List<ZDO> RemovalBuffer = new List<ZDO>();

		internal static bool Prefix(List<ZDO> currentNearObjects, List<ZDO> currentDistantObjects, Dictionary<ZDO, ZNetView> ___m_instances)
		{
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			try
			{
				byte b = (byte)(Time.frameCount & 0xFF);
				MarkCurrentObjects(currentNearObjects, b);
				MarkCurrentObjects(currentDistantObjects, b);
				RemovalBuffer.Clear();
				foreach (KeyValuePair<ZDO, ZNetView> ___m_instance in ___m_instances)
				{
					ZDO key = ___m_instance.Key;
					if (key != null)
					{
						ZNetView value = ___m_instance.Value;
						if ((Object)(object)value == (Object)null || !Object.op_Implicit((Object)(object)value) || key.TempRemoveEarmark != b)
						{
							RemovalBuffer.Add(key);
						}
					}
				}
				ZDOMan instance = ZDOMan.instance;
				foreach (ZDO item in RemovalBuffer)
				{
					___m_instances.TryGetValue(item, out ZNetView value2);
					flag = true;
					if ((Object)(object)value2 != (Object)null && Object.op_Implicit((Object)(object)value2))
					{
						ZDO zDO = value2.GetZDO();
						if (zDO == null)
						{
							Object.Destroy((Object)(object)((Component)value2).gameObject);
						}
						else if (zDO == item)
						{
							value2.ResetZDO();
							Object.Destroy((Object)(object)((Component)value2).gameObject);
						}
						else if (LiquidStuckFixPlugin.DebugLogging.Value)
						{
							LiquidStuckFixPlugin.Log.LogWarning((object)("Removed mismatched ZNetScene entry without destroying its active view: " + $"{item.m_uid} -> {zDO.m_uid}"));
						}
					}
					if (instance != null && !item.Persistent && item.IsOwner())
					{
						instance.DestroyZDO(item);
					}
					item.Created = false;
					___m_instances.Remove(item);
				}
				return false;
			}
			catch (Exception ex)
			{
				string text = (flag ? "stopping this cleanup pass; remaining entries will be retried" : "falling back to vanilla");
				LiquidStuckFixPlugin.Log.LogWarning((object)("Integrated ZNetScene.RemoveObjects cleanup failed; " + text + ": " + ex.Message));
				return !flag;
			}
			finally
			{
				RemovalBuffer.Clear();
			}
		}

		internal static void ResetState()