Decompiled source of DeepNorthCompat v1.1.0

BepInEx/plugins/DeepNorthCompat/DeepNorthCompat.dll

Decompiled 25 minutes ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("DeepNorthCompat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("DeepNorthCompat")]
[assembly: AssemblyTitle("DeepNorthCompat")]
[assembly: AssemblyVersion("1.1.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 DeepNorthCompat
{
	public static class BowCalculation
	{
		public const float VanillaReduction = 0.33f;

		public static float Reduction(float configured, bool enabled)
		{
			if (enabled && !(configured <= 0f) && !(configured > 1f) && !float.IsNaN(configured))
			{
				return configured;
			}
			return 0.33f;
		}

		public static float Drain(float baseDrain, float skill, float configured, bool enabled = true)
		{
			return baseDrain - baseDrain * Reduction(configured, enabled) * skill;
		}
	}
	public sealed class ResourceStack<TItem, TSource> where TItem : notnull where TSource : notnull
	{
		public readonly TItem Id;

		public readonly TSource Source;

		public readonly string Name;

		public readonly int Quality;

		public readonly int WorldLevel;

		public readonly int Count;

		public readonly bool Container;

		public readonly int Index;

		public ResourceStack(TItem id, TSource source, string name, int quality, int worldLevel, int count, bool container, int index = 0)
		{
			Id = id;
			Source = source;
			Name = name;
			Quality = quality;
			WorldLevel = worldLevel;
			Count = count;
			Container = container;
			Index = index;
		}
	}
	public sealed class ResourceNeed<TSource>
	{
		public readonly string Name;

		public readonly int MaximumQuality;

		public readonly int Count;

		public readonly Func<TSource, bool> AllowsSource;

		public ResourceNeed(string name, int maximumQuality, int count, Func<TSource, bool> allowsSource)
		{
			Name = name;
			MaximumQuality = maximumQuality;
			Count = count;
			AllowsSource = allowsSource;
		}
	}
	public sealed class Allocation<TItem, TSource> where TItem : notnull where TSource : notnull
	{
		public readonly ResourceStack<TItem, TSource> Stack;

		public readonly int Count;

		public Allocation(ResourceStack<TItem, TSource> stack, int count)
		{
			Stack = stack;
			Count = count;
		}
	}
	public sealed class SelectedIngredient<TItem, TSource> where TItem : notnull where TSource : notnull
	{
		public readonly ResourceNeed<TSource> Need;

		public readonly int Tier;

		public readonly IReadOnlyList<Allocation<TItem, TSource>> Allocations;

		public SelectedIngredient(ResourceNeed<TSource> need, int tier, List<Allocation<TItem, TSource>> allocations)
		{
			Need = need;
			Tier = tier;
			Allocations = allocations.AsReadOnly();
		}
	}
	public sealed class IngredientPlan<TItem, TSource> where TItem : notnull where TSource : notnull
	{
		public readonly IReadOnlyList<SelectedIngredient<TItem, TSource>> Ingredients;

		public IEnumerable<Allocation<TItem, TSource>> Allocations => Ingredients.SelectMany((SelectedIngredient<TItem, TSource> i) => i.Allocations);

		public IngredientPlan(List<SelectedIngredient<TItem, TSource>> ingredients)
		{
			Ingredients = ingredients.AsReadOnly();
		}
	}
	public static class IngredientSelector
	{
		public static IngredientPlan<TItem, TSource>? Select<TItem, TSource>(IReadOnlyList<ResourceStack<TItem, TSource>> stacks, IReadOnlyList<ResourceNeed<TSource>> needs, int worldLevel, bool leaveOne) where TItem : notnull where TSource : notnull
		{
			Dictionary<TItem, int> remaining = stacks.ToDictionary((ResourceStack<TItem, TSource> s) => s.Id, (ResourceStack<TItem, TSource> s) => s.Count);
			List<SelectedIngredient<TItem, TSource>> list = new List<SelectedIngredient<TItem, TSource>>();
			foreach (ResourceNeed<TSource> need in needs)
			{
				if (need.Count <= 0)
				{
					continue;
				}
				List<ResourceStack<TItem, TSource>> candidates = stacks.Where((ResourceStack<TItem, TSource> s) => s.Name == need.Name && s.WorldLevel >= worldLevel && need.AllowsSource(s.Source)).ToList();
				if (Capacity(candidates) < need.Count)
				{
					return null;
				}
				int num = 0;
				int quality;
				for (quality = 1; quality <= need.MaximumQuality; quality++)
				{
					if (need.MaximumQuality <= 1)
					{
						break;
					}
					if (Capacity(candidates.Where((ResourceStack<TItem, TSource> s) => s.Quality == quality)) >= need.Count)
					{
						num = quality;
						break;
					}
				}
				int num2 = need.Count;
				List<Allocation<TItem, TSource>> list2 = new List<Allocation<TItem, TSource>>();
				foreach (ResourceStack<TItem, TSource> stack in candidates)
				{
					if (num > 0 && stack.Quality != num)
					{
						continue;
					}
					int val = remaining[stack.Id];
					if (leaveOne && stack.Container)
					{
						int num3 = candidates.Where((ResourceStack<TItem, TSource> s) => object.Equals(s.Source, stack.Source)).Sum((ResourceStack<TItem, TSource> s) => remaining[s.Id]);
						val = Math.Min(val, Math.Max(0, num3 - 1));
					}
					int num4 = Math.Min(val, num2);
					if (num4 > 0)
					{
						list2.Add(new Allocation<TItem, TSource>(stack, num4));
						remaining[stack.Id] -= num4;
						num2 -= num4;
						if (num2 == 0)
						{
							break;
						}
					}
				}
				if (num2 != 0)
				{
					throw new InvalidOperationException("Selection capacity and allocation disagreed.");
				}
				list.Add(new SelectedIngredient<TItem, TSource>(need, num, list2));
				int Capacity(IEnumerable<ResourceStack<TItem, TSource>> subset)
				{
					return (from s in subset
						group s by s.Source).Sum(delegate(IGrouping<TSource, ResourceStack<TItem, TSource>> group)
					{
						int num5 = group.Sum((ResourceStack<TItem, TSource> s) => remaining[s.Id]);
						if (!leaveOne || !group.First().Container)
						{
							return num5;
						}
						int num6 = candidates.Where((ResourceStack<TItem, TSource> s) => object.Equals(s.Source, group.Key)).Sum((ResourceStack<TItem, TSource> s) => remaining[s.Id]);
						return Math.Min(num5, Math.Max(0, num6 - 1));
					});
				}
			}
			return new IngredientPlan<TItem, TSource>(list);
		}
	}
	public enum ReservationState
	{
		Planned,
		Reserved,
		Committed,
		RolledBack
	}
	public sealed class IngredientReservation<TItem, TSource> where TItem : notnull where TSource : notnull
	{
		private readonly IngredientPlan<TItem, TSource> plan;

		private readonly List<Tuple<ResourceStack<TItem, TSource>, int>> before = new List<Tuple<ResourceStack<TItem, TSource>, int>>();

		public ReservationState State { get; private set; }

		public IngredientReservation(IngredientPlan<TItem, TSource> plan)
		{
			this.plan = plan;
		}

		public bool Reserve(Func<ResourceStack<TItem, TSource>, int> currentCount, Func<Allocation<TItem, TSource>, bool> remove, Action<ResourceStack<TItem, TSource>, int> restore)
		{
			if (State != ReservationState.Planned)
			{
				return false;
			}
			foreach (IGrouping<TItem, Allocation<TItem, TSource>> item in from a in plan.Allocations
				group a by a.Stack.Id)
			{
				ResourceStack<TItem, TSource> stack = item.First().Stack;
				int num = currentCount(stack);
				if (num < item.Sum((Allocation<TItem, TSource> a) => a.Count))
				{
					return false;
				}
				before.Add(Tuple.Create(stack, num));
			}
			try
			{
				foreach (Allocation<TItem, TSource> allocation in plan.Allocations)
				{
					if (!remove(allocation))
					{
						Rollback(restore);
						return false;
					}
				}
				State = ReservationState.Reserved;
				return true;
			}
			catch
			{
				Rollback(restore);
				throw;
			}
		}

		public void Complete(bool outputCreated, Action<ResourceStack<TItem, TSource>, int> restore)
		{
			if (State == ReservationState.Reserved)
			{
				if (outputCreated)
				{
					State = ReservationState.Committed;
				}
				else
				{
					Rollback(restore);
				}
			}
		}

		public void Rollback(Action<ResourceStack<TItem, TSource>, int> restore)
		{
			if (State == ReservationState.Committed || State == ReservationState.RolledBack)
			{
				return;
			}
			foreach (IGrouping<TSource, Tuple<ResourceStack<TItem, TSource>, int>> item in from entry in before
				group entry by entry.Item1.Source)
			{
				foreach (Tuple<ResourceStack<TItem, TSource>, int> item2 in item.OrderBy((Tuple<ResourceStack<TItem, TSource>, int> entry) => entry.Item1.Index))
				{
					restore(item2.Item1, item2.Item2);
				}
			}
			before.Clear();
			State = ReservationState.RolledBack;
		}
	}
	internal static class ExpectedBuilds
	{
		internal const string ImpactfulSkills = "ADE4FD2943A886B9B90C0241CB77EC65A97C1840EF39A906B58BAF3925086706";

		internal const string CraftyBoxes = "432285A08AA0D43BBD89B36330BEDC19CB6EA93AED439E493D0287EDAECEDEB4";

		internal const string AAACrafting = "316C5B47B449B8172627BD48C12830429E38BBD21A704746F86D1053D38D4830";

		internal const string SeaAnimals = "3F57F6AD089D5616A924D5917851A0A7C99715CC0B2062EF23B2FA15D07C721A";

		internal const string AirAnimals = "B29905FFDA5204570D64958CB18D74E08D7CEE8AA361485E1D988B54242F2F85";

		internal const string Valheim = "96CFC004F7F4A6F30D070BEF39EAFD79C466A137121C4665A2F19FB9C15C6127";

		internal const string AzuEpi = "41ED9378929090C5C46363A319C6A1F63F85DCF18DDE2DA1C0CAB49C39DBECFA";
	}
	public static class CompatibilityInstaller
	{
		internal static Action<string> Info = delegate
		{
		};

		internal static Action<string> Warning = delegate
		{
		};

		internal static Action<string> Error = delegate
		{
		};

		public static void Install(Func<string, Assembly?> resolve, Action<string> info, Action<string> warning, Action<string> error)
		{
			Info = info;
			Warning = warning;
			Error = error;
			Assembly impact = resolve("MidnightsFX.ImpactfulSkills");
			Assembly crafty = resolve("Azumatt.AzuCraftyBoxes");
			InstallGroup("Bow", delegate
			{
				if (impact == null)
				{
					Info("Bow: ImpactfulSkills absent; inactive.");
				}
				else if (Guard.KnownServerBuild())
				{
					Info("Bow: client-only patch; inactive on dedicated server.");
				}
				else
				{
					Guard.Build(impact, "ADE4FD2943A886B9B90C0241CB77EC65A97C1840EF39A906B58BAF3925086706");
					Guard.Build(typeof(InventoryGui).Assembly, "96CFC004F7F4A6F30D070BEF39EAFD79C466A137121C4665A2F19FB9C15C6127");
					BowPatch.Install(impact);
				}
			});
			InstallGroup("Drops.SeaAnimals", delegate
			{
				InstallDrops(resolve("marlthon.SeaAnimals"), "3F57F6AD089D5616A924D5917851A0A7C99715CC0B2062EF23B2FA15D07C721A", "SeaAnimals");
			});
			InstallGroup("Drops.AirAnimals", delegate
			{
				InstallDrops(resolve("marlthon.AirAnimals"), "B29905FFDA5204570D64958CB18D74E08D7CEE8AA361485E1D988B54242F2F85", "AirAnimals");
			});
			InstallGroup("Quality", delegate
			{
				if (impact == null || crafty == null)
				{
					Info("Quality: optional mod absent; inactive.");
				}
				else if (Guard.KnownServerBuild())
				{
					Info("Quality: client-only patch; inactive on dedicated server.");
				}
				else
				{
					Guard.Build(impact, "ADE4FD2943A886B9B90C0241CB77EC65A97C1840EF39A906B58BAF3925086706");
					Guard.Build(crafty, "432285A08AA0D43BBD89B36330BEDC19CB6EA93AED439E493D0287EDAECEDEB4");
					Guard.Build(typeof(InventoryGui).Assembly, "96CFC004F7F4A6F30D070BEF39EAFD79C466A137121C4665A2F19FB9C15C6127");
					Assembly assembly = resolve("Azumatt.AzuAntiArthriticCrafting");
					if (assembly != null)
					{
						Guard.Build(assembly, "316C5B47B449B8172627BD48C12830429E38BBD21A704746F86D1053D38D4830");
					}
					QualityPatch.Install(impact, crafty, assembly != null);
				}
			});
			InstallGroup("Preview.AzuEPI", delegate
			{
				if (Guard.KnownServerBuild())
				{
					Info("Preview.AzuEPI: client-only patch; inactive on dedicated server.");
				}
				else
				{
					AzuEpiPreviewPatch.Prepare(resolve("Azumatt.AzuExtendedPlayerInventory"));
				}
			});
			InstallGroup("Simulation", delegate
			{
				SimulationPatch.Prepare(resolve);
			});
			InstallGroup("OwnerSkills", delegate
			{
				OwnerSkillPatch.Prepare(impact, resolve("MVP.Valheim_Serverside_Simulations"));
			});
			InstallGroup("Tune.Client", delegate
			{
				TuneClientPatch.Prepare(resolve("akoozie.valheimtune"));
			});
		}

		public static void Verify()
		{
			DropRangePatch.Verify();
			AzuEpiPreviewPatch.Verify();
			SimulationPatch.Verify();
			OwnerSkillPatch.Verify();
			TuneClientPatch.Verify();
		}

		private static void InstallDrops(Assembly? assembly, string hash, string name)
		{
			if (assembly == null)
			{
				Info("Drops." + name + ": mod absent; inactive.");
				return;
			}
			Guard.Build(assembly, hash);
			DropRangePatch.Install(assembly, name);
		}

		private static void InstallGroup(string name, Action install)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				install();
			}
			catch (Exception arg)
			{
				try
				{
					new Harmony("DeepNorthCompat." + name).UnpatchSelf();
				}
				catch (Exception arg2)
				{
					Error($"{name}: Harmony rollback failed; some hooks may remain active. {arg2}");
				}
				Error(name + ": NOT APPLIED; expected installed implementation changed or patch failed. " + $"Vendor behavior retained. {arg}");
			}
		}
	}
	public static class Guard
	{
		internal static bool KnownServerBuild()
		{
			using SHA256 sHA = SHA256.Create();
			using FileStream inputStream = File.OpenRead(typeof(ZNet).Assembly.Location);
			return BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "") == "7CAB9B49D31EC064591CA80402DD35C566E03B7297CFB7BF4696C38DA4E24D8B";
		}

		public static void Build(Assembly assembly, string expectedHash)
		{
			using SHA256 sHA = SHA256.Create();
			using FileStream inputStream = File.OpenRead(assembly.Location);
			string text = BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "");
			if (text != expectedHash)
			{
				throw new NotSupportedException(assembly.GetName().Name + " build changed; expected " + expectedHash + ", found " + text + ". Re-audit required.");
			}
		}

		internal static Type Type(Assembly assembly, string name)
		{
			return assembly.GetType(name, throwOnError: true);
		}

		internal static MethodInfo Method(Type type, string name, Type returnType, params Type[] parameters)
		{
			MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null);
			if (method == null || method.ReturnType != returnType)
			{
				throw new MissingMethodException(type.FullName, name);
			}
			return method;
		}

		internal static HarmonyMethod Hook(Type type, string name, int priority = 400)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			return new HarmonyMethod(AccessTools.DeclaredMethod(type, name, (Type[])null, (Type[])null))
			{
				priority = priority
			};
		}

		internal static void Registered(MethodBase target)
		{
			CompatibilityInstaller.Info("Registered: " + Name(target));
		}

		internal static string Name(MethodBase target)
		{
			return target.DeclaringType.Assembly.GetName().Name + ":" + target.DeclaringType.FullName + "." + target.Name;
		}
	}
	internal static class AzuEpiPreviewPatch
	{
		internal const string Owner = "Azumatt.AzuExtendedPlayerInventory";

		private const string Namespace = "AzuEPI.Game.PlayerPreview.";

		private const string PatchOwner = "DeepNorthCompat.Preview.AzuEPI";

		private static Assembly? pending;

		private static FieldInfo previewPlayer;

		private static FieldInfo characterAnimator;

		internal static void Prepare(Assembly? assembly)
		{
			pending = null;
			if (assembly == null)
			{
				CompatibilityInstaller.Info("Preview.AzuEPI: optional mod absent; inactive.");
				return;
			}
			Guard.Build(assembly, "41ED9378929090C5C46363A319C6A1F63F85DCF18DDE2DA1C0CAB49C39DBECFA");
			Guard.Build(typeof(Humanoid).Assembly, "96CFC004F7F4A6F30D070BEF39EAFD79C466A137121C4665A2F19FB9C15C6127");
			pending = assembly;
			CompatibilityInstaller.Info("Preview.AzuEPI: 2.6.1 build verified; awaiting vendor Harmony registrations.");
		}

		internal static void Verify()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Expected O, but got Unknown
			Assembly assembly = pending;
			pending = null;
			if (assembly == null)
			{
				return;
			}
			Harmony val = new Harmony("DeepNorthCompat.Preview.AzuEPI");
			List<(MethodInfo, Patch)> list = new List<(MethodInfo, Patch)>();
			try
			{
				(string, Type)[] array = new(string, Type)[2]
				{
					("EquipItem", typeof(bool)),
					("UnequipItem", typeof(void))
				};
				for (int i = 0; i < array.Length; i++)
				{
					(string, Type) tuple = array[i];
					string item = tuple.Item1;
					Type item2 = tuple.Item2;
					MethodInfo methodInfo = Guard.Method(typeof(Humanoid), item, item2, typeof(ItemData), typeof(bool));
					MethodInfo expected = Guard.Method(Guard.Type(assembly, "AzuEPI.Game.PlayerPreview.PreviewInstantRefresh_" + item), "Postfix", typeof(void));
					list.Add((methodInfo, RequirePostfix(methodInfo, expected)));
				}
				RequirePostfix(Guard.Method(typeof(VisEquipment), "UpdateEquipmentVisuals", typeof(void)), Guard.Method(Guard.Type(assembly, "AzuEPI.Game.PlayerPreview.PreviewInstantRefresh_VisEquipmentPatch"), "Postfix", typeof(void), typeof(VisEquipment)));
				RequirePostfix(Guard.Method(typeof(Humanoid), "SetupAnimationState", typeof(void)), Guard.Method(Guard.Type(assembly, "AzuEPI.Game.PlayerPreview.UpdatePlayerPreviewVisuals"), "Postfix", typeof(void), typeof(Humanoid)));
				MethodInfo methodInfo2 = Guard.Method(Guard.Type(assembly, "AzuEPI.Game.PlayerPreview.PlayerPreviewManager"), "UpdatePlayerPreview", typeof(void), typeof(Humanoid));
				previewPlayer = AccessTools.Field(Guard.Type(assembly, "AzuEPI.Game.PlayerPreview.AzuEPICharacterPanel"), "playerPreviewComp");
				characterAnimator = AccessTools.Field(typeof(Character), "m_animator");
				if (previewPlayer?.FieldType != typeof(Player) || characterAnimator?.FieldType != typeof(Animator))
				{
					throw new MissingFieldException("AzuEPI preview stance fields changed.");
				}
				val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, Guard.Hook(typeof(AzuEpiPreviewPatch), "SyncStance", 0), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				foreach (var (methodInfo3, val2) in list)
				{
					val.Unpatch((MethodBase)methodInfo3, val2.PatchMethod);
				}
				CompatibilityInstaller.Info("Preview.AzuEPI: APPLIED; removed the two broad 2.6.1 equipment preview postfixes; weapon stance syncs through the local preview update.");
			}
			catch (Exception arg)
			{
				try
				{
					foreach (var item3 in list)
					{
						var (methodInfo4, patch) = item3;
						if (!AllPatches(methodInfo4).Any((Patch p) => p.PatchMethod == patch.PatchMethod))
						{
							new Harmony("Azumatt.AzuExtendedPlayerInventory").Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(patch.PatchMethod, patch.priority, patch.before, patch.after, (bool?)patch.debug), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						}
					}
					val.UnpatchSelf();
				}
				catch (Exception arg2)
				{
					CompatibilityInstaller.Error($"Preview.AzuEPI: application and rollback failed; inspect Harmony state. {arg} {arg2}");
					return;
				}
				CompatibilityInstaller.Error($"Preview.AzuEPI: NOT APPLIED; vendor hooks retained. {arg}");
			}
		}

		private static void SyncStance(Humanoid __0)
		{
			if (!Object.op_Implicit((Object)(object)__0) || (Object)(object)__0 != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			object? value = previewPlayer.GetValue(null);
			Player val = (Player)((value is Player) ? value : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			object? value2 = characterAnimator.GetValue(__0);
			Animator val2 = (Animator)((value2 is Animator) ? value2 : null);
			object? value3 = characterAnimator.GetValue(val);
			Animator val3 = (Animator)((value3 is Animator) ? value3 : null);
			if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val3))
			{
				int integer = val2.GetInteger("statei");
				float num = val2.GetFloat("statef");
				if (val3.GetInteger("statei") != integer)
				{
					val3.SetInteger("statei", integer);
				}
				if (val3.GetFloat("statef") != num)
				{
					val3.SetFloat("statef", num);
				}
			}
		}

		private static Patch RequirePostfix(MethodInfo target, MethodInfo expected)
		{
			Patch[] array = (from p in AllPatches(target)
				where p.PatchMethod == expected
				select p).ToArray();
			if (array.Length != 1 || array[0].owner != "Azumatt.AzuExtendedPlayerInventory" || !Harmony.GetPatchInfo((MethodBase)target).Postfixes.Contains(array[0]))
			{
				throw new NotSupportedException("Expected one Azumatt.AzuExtendedPlayerInventory postfix " + Guard.Name(expected) + " on " + Guard.Name(target) + ".");
			}
			return array[0];
		}

		private static IEnumerable<Patch> AllPatches(MethodBase target)
		{
			Patches patchInfo = Harmony.GetPatchInfo(target);
			if (patchInfo != null)
			{
				return patchInfo.Prefixes.Concat(patchInfo.Postfixes).Concat(patchInfo.Transpilers).Concat(patchInfo.Finalizers)
					.Concat(patchInfo.ILManipulators);
			}
			return Enumerable.Empty<Patch>();
		}
	}
	internal static class BowPatch
	{
		private static FieldInfo enabled;

		private static FieldInfo reduction;

		internal static void Install(Assembly impact)
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			Type type = Guard.Type(impact, "ImpactfulSkills.ValConfig");
			enabled = AccessTools.Field(type, "EnableWeaponSkill");
			reduction = AccessTools.Field(type, "WeaponSkillBowDrawStaminaCostReduction");
			if (enabled?.FieldType != typeof(ConfigEntry<bool>) || reduction?.FieldType != typeof(ConfigEntry<float>))
			{
				throw new MissingFieldException("ImpactfulSkills bow configuration changed.");
			}
			MethodInfo methodInfo = Guard.Method(Guard.Type(impact, "ImpactfulSkills.patches.WeaponSkill"), "ModifyStaminaDrainCostForBow", typeof(float));
			MethodInfo methodInfo2 = Guard.Method(Guard.Type(impact, "ImpactfulSkills.patches.WeaponSkill+ItemDisplay"), "Postfix", typeof(void), typeof(ItemData), typeof(string).MakeByRefType());
			Guard.Method(typeof(ItemData), "GetDrawStaminaDrain", typeof(float));
			Harmony val = new Harmony("DeepNorthCompat.Bow");
			val.Patch((MethodBase)methodInfo, Guard.Hook(typeof(BowPatch), "Coefficient"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, Guard.Hook(typeof(BowPatch), "Report"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Guard.Registered(methodInfo);
			Guard.Registered(methodInfo2);
		}

		private static bool Coefficient(ref float __result)
		{
			__result = BowCalculation.Reduction(((ConfigEntry<float>)reduction.GetValue(null)).Value, ((ConfigEntry<bool>)enabled.GetValue(null)).Value && (Object)(object)Player.m_localPlayer != (Object)null);
			return false;
		}

		private static void Report(ItemData __0, ref string __1)
		{
			if (!((ConfigEntry<bool>)enabled.GetValue(null)).Value || (Object)(object)Player.m_localPlayer == (Object)null || !__1.Contains("item_staminahold"))
			{
				return;
			}
			float drawStaminaDrain = __0.GetDrawStaminaDrain();
			string[] array = __1.Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].Contains("item_staminahold"))
				{
					array[i] = "$item_staminahold: <color=orange>" + __0.m_shared.m_attack.m_drawStaminaDrain.ToString("0.##", CultureInfo.InvariantCulture) + "</color> <color=yellow>(" + drawStaminaDrain.ToString("0.##", CultureInfo.InvariantCulture) + ")</color>/s";
				}
			}
			__1 = string.Join("\n", array);
		}
	}
	public static class DropRangePatch
	{
		private static readonly Dictionary<MethodBase, bool?> parsers = new Dictionary<MethodBase, bool?>();

		internal static void Install(Assembly assembly, string name)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Type type = Guard.Type(assembly, "CreatureManager.Creature+DropList+SerializedDrops+<>c");
			Type returnType = Guard.Type(assembly, "CreatureManager.Creature+Drop");
			MethodInfo methodInfo = Guard.Method(type, "<.ctor>b__3_2", returnType, typeof(string[]));
			Harmony val = new Harmony("DeepNorthCompat.Drops." + name);
			parsers[methodInfo] = null;
			val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, Guard.Hook(typeof(DropRangePatch), "FixMaximum"), (HarmonyMethod)null, (HarmonyMethod)null);
			Guard.Registered(methodInfo);
		}

		internal static void Verify()
		{
			foreach (KeyValuePair<MethodBase, bool?> parser in parsers)
			{
				if (parser.Value == true)
				{
					CompatibilityInstaller.Info("Verified: " + Guard.Name(parser.Key));
				}
				else if (!parser.Value.HasValue)
				{
					CompatibilityInstaller.Error(Guard.Name(parser.Key) + ": transpiler did not run; parser unchanged.");
				}
			}
		}

		public static IEnumerable<CodeInstruction> FixMaximum(IEnumerable<CodeInstruction> instructions, MethodBase original)
		{
			List<CodeInstruction> list = instructions.ToList();
			List<CodeInstruction> code = ((IEnumerable<CodeInstruction>)list).Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
			MethodInfo parse = typeof(int).GetMethod("TryParse", new Type[2]
			{
				typeof(string),
				typeof(int).MakeByRefType()
			});
			List<int> list2 = (from i in Enumerable.Range(0, code.Count)
				where CodeInstructionExtensions.Calls(code[i], parse)
				select i).ToList();
			if (list2.Count != 2 || list2.Any((int i) => i < 3 || code[i - 2].opcode != OpCodes.Ldelem_Ref || code[i - 3].opcode != OpCodes.Ldc_I4_0))
			{
				CompatibilityInstaller.Error("Drops: CreatureManager range defect no longer matches in " + original.DeclaringType?.Assembly.GetName().Name + "; parser unchanged.");
				if (parsers.ContainsKey(original))
				{
					parsers[original] = false;
				}
				return list;
			}
			code[list2[1] - 3].opcode = OpCodes.Ldc_I4_1;
			if (parsers.ContainsKey(original))
			{
				parsers[original] = true;
			}
			return code;
		}
	}
	internal static class OwnerSkillPatch
	{
		internal sealed class Scope : IDisposable
		{
			private readonly Player? previous;

			internal Scope(Player? player)
			{
				previous = current;
				current = player;
			}

			public void Dispose()
			{
				current = previous;
			}
		}

		internal const string Owner = "DeepNorthCompat.OwnerSkills";

		private const string GrantRpc = "DeepNorthCompat.OwnerSkillXP";

		private const string HelloRpc = "DeepNorthCompat.OwnerSkillHello";

		private const string StatusRpc = "DeepNorthCompat.OwnerSkillStatus";

		private static readonly int ProtocolKey = StringExtensionMethods.GetStableHashCode("DeepNorthCompat.skillProtocol");

		private static readonly int MiningKey = StringExtensionMethods.GetStableHashCode("DeepNorthCompat.mining");

		private static readonly int WoodKey = StringExtensionMethods.GetStableHashCode("DeepNorthCompat.woodcutting");

		private static readonly int AnimalKey = StringExtensionMethods.GetStableHashCode("DeepNorthCompat.animalHandling");

		private static readonly HashSet<(ZDOID, int)> minedAreas = new HashSet<(ZDOID, int)>();

		private static readonly HashSet<ZDOID> missingPlayers = new HashSet<ZDOID>();

		private static Assembly? impact;

		private static bool prepared;

		private static bool server;

		private static bool installed;

		private static bool coreOnServer;

		private static float nextPublish;

		private static float nextHello;

		private static FieldInfo view = null;

		private static FieldInfo animalSkill = null;

		private static FieldInfo animalRange = null;

		private static FieldInfo animalEnabled = null;

		private static FieldInfo miningEnabled = null;

		private static FieldInfo woodEnabled = null;

		private static MethodInfo treeBonus = null;

		[ThreadStatic]
		private static Player? current;

		private static readonly MethodInfo serverId = AccessTools.DeclaredMethod(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null);

		internal static bool Enabled
		{
			get
			{
				if (server && installed)
				{
					return SimulationPatch.Active;
				}
				return false;
			}
		}

		private static SkillType Animal => (SkillType)animalSkill.GetValue(null);

		private static float LootRange => ((ConfigEntry<float>)animalRange.GetValue(null)).Value;

		internal static void Prepare(Assembly? skills, Assembly? fork)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			prepared = false;
			installed = false;
			impact = null;
			if (skills == null)
			{
				CompatibilityInstaller.Info("OwnerSkills: optional mod absent; inactive.");
				return;
			}
			Guard.Build(skills, "ADE4FD2943A886B9B90C0241CB77EC65A97C1840EF39A906B58BAF3925086706");
			try
			{
				Guard.Build(typeof(ZNet).Assembly, "96CFC004F7F4A6F30D070BEF39EAFD79C466A137121C4665A2F19FB9C15C6127");
				server = false;
			}
			catch (NotSupportedException)
			{
				Guard.Build(typeof(ZNet).Assembly, "7CAB9B49D31EC064591CA80402DD35C566E03B7297CFB7BF4696C38DA4E24D8B");
				server = true;
			}
			if (server)
			{
				if (fork == null)
				{
					CompatibilityInstaller.Info("OwnerSkills: dedicated simulation absent; inactive on server.");
					return;
				}
				Guard.Build(fork, "804AE557AD93D44C508EFCB472BE23DCFB5DE80FBFA13F5EC264D2DDB009221A");
			}
			impact = skills;
			view = AccessTools.Field(typeof(Character), "m_nview");
			animalSkill = AccessTools.Field(Guard.Type(skills, "ImpactfulSkills.patches.AnimalWhisper"), "AnimalHandling");
			animalRange = AccessTools.Field(Guard.Type(skills, "ImpactfulSkills.ValConfig"), "AnimalHandlingLootRange");
			animalEnabled = AccessTools.Field(Guard.Type(skills, "ImpactfulSkills.ValConfig"), "EnableAnimalWhisper");
			miningEnabled = AccessTools.Field(Guard.Type(skills, "ImpactfulSkills.ValConfig"), "EnableMining");
			woodEnabled = AccessTools.Field(Guard.Type(skills, "ImpactfulSkills.ValConfig"), "EnableWoodcutting");
			treeBonus = Guard.Method(Guard.Type(skills, "ImpactfulSkills.patches.Woodcutting"), "IncreaseTreeDrops", typeof(void), typeof(TreeBase));
			Harmony val = new Harmony("DeepNorthCompat.OwnerSkills");
			val.Patch((MethodBase)Guard.Method(typeof(Player), "SetLocalPlayer", typeof(void)), (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "Publish"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)Guard.Method(typeof(Player), "FixedUpdate", typeof(void)), (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "PublishPeriodic"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			string[] array = new string[4] { "RaiseSkill", "LowerAllSkills", "Load", "CheatRaiseSkill" };
			foreach (string text in array)
			{
				val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), text, (Type[])null, (Type[])null), (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "PublishAfterSkillChange"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			val.Patch((MethodBase)AccessTools.Constructor(typeof(ZRoutedRpc), new Type[1] { typeof(bool) }, false), (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "RegisterRpc"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null), (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "Reset"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			MethodInfo methodInfo = AccessTools.DeclaredMethod(Guard.Type(skills, "ImpactfulSkills.patches.Mining+Minerock5DestroyPatch"), "Postfix", (Type[])null, (Type[])null);
			val.Patch((MethodBase)methodInfo, Guard.Hook(typeof(OwnerSkillPatch), "OncePerMiningArea"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			prepared = true;
			CompatibilityInstaller.Info("OwnerSkills: state publisher and XP RPC registered; server integration awaits Core verification.");
		}

		internal static void Verify()
		{
			//IL_058c: 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_0034: Expected O, but got Unknown
			if (!prepared || !server || !SimulationPatch.Active || impact == null)
			{
				return;
			}
			List<(MethodBase, Patch, HarmonyPatchType)> list = new List<(MethodBase, Patch, HarmonyPatchType)>();
			try
			{
				Harmony val = new Harmony("DeepNorthCompat.OwnerSkills");
				(Type, string, Type[])[] array = new(Type, string, Type[])[5]
				{
					(typeof(MineRock), "RPC_Hit", new Type[3]
					{
						typeof(long),
						typeof(HitData),
						typeof(int)
					}),
					(typeof(MineRock5), "RPC_Damage", new Type[3]
					{
						typeof(long),
						typeof(HitData),
						typeof(int)
					}),
					(typeof(TreeBase), "RPC_Damage", new Type[2]
					{
						typeof(long),
						typeof(HitData)
					}),
					(typeof(TreeLog), "RPC_Damage", new Type[2]
					{
						typeof(long),
						typeof(HitData)
					}),
					(typeof(Destructible), "RPC_Damage", new Type[2]
					{
						typeof(long),
						typeof(HitData)
					})
				};
				for (int i = 0; i < array.Length; i++)
				{
					(Type, string, Type[]) tuple = array[i];
					Type item = tuple.Item1;
					string item2 = tuple.Item2;
					Type[] item3 = tuple.Item3;
					MethodInfo methodInfo = Guard.Method(item, item2, typeof(void), item3);
					val.Patch((MethodBase)methodInfo, Guard.Hook(typeof(OwnerSkillPatch), "BeginDamage", 800), (HarmonyMethod)null, (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "EndScope"), (HarmonyMethod)null);
				}
				(Type, string, string)[] array2 = new(Type, string, string)[3]
				{
					(typeof(Tameable), "DecreaseRemainingTime", "BeginTaming"),
					(typeof(CharacterDrop), "GenerateDropList", "BeginLoot"),
					(typeof(Tameable), "OnDeath", "BeginSlaughter")
				};
				for (int i = 0; i < array2.Length; i++)
				{
					var (type, text, name) = array2[i];
					val.Patch((MethodBase)AccessTools.DeclaredMethod(type, text, (Type[])null, (Type[])null), Guard.Hook(typeof(OwnerSkillPatch), name, 800), (HarmonyMethod)null, (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "EndScope"), (HarmonyMethod)null);
				}
				val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Character), "CheckDeath", (Type[])null, (Type[])null), Guard.Hook(typeof(OwnerSkillPatch), "DeathReady", 800), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				string[] array3 = new string[8] { "ImpactfulSkills.patches.Mining+MinerockDropsPatch", "ImpactfulSkills.patches.Mining+Minerock5DestroyPatch", "ImpactfulSkills.patches.Mining+IncreaseDropsFromDestructibleRock", "ImpactfulSkills.patches.Woodcutting+IncreaseDropsFromTree", "ImpactfulSkills.patches.Woodcutting+IncreaseDropsFromDestructibleTree", "ImpactfulSkills.patches.AnimalWhisper+IncreaseTamingSpeed", "ImpactfulSkills.patches.AnimalWhisper+ScaleTamedAnimalLoot", "ImpactfulSkills.patches.AnimalWhisper+TamedAnimalSlaughterXP" };
				foreach (string text2 in array3)
				{
					MethodInfo methodInfo2 = AccessTools.DeclaredMethod(Guard.Type(impact, text2), text2.Contains("MinerockDropsPatch") ? "ApplyIncreasedMiningDrops" : ((text2.Contains("IncreaseDropsFromTree") || text2.Contains("Minerock5DestroyPatch") || text2.Contains("ScaleTamedAnimalLoot") || text2.Contains("TamedAnimalSlaughterXP")) ? "Postfix" : "Prefix"), (Type[])null, (Type[])null);
					val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "RewriteContext"), (HarmonyMethod)null, (HarmonyMethod)null);
				}
				array3 = new string[2] { "Mining", "Woodcutting" };
				foreach (string text3 in array3)
				{
					val.Patch((MethodBase)AccessTools.DeclaredMethod(Guard.Type(impact, "ImpactfulSkills.patches." + text3), (text3 == "Mining") ? "IncreaseMiningDrops" : "IncreaseWoodDrops", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "RewriteContext"), (HarmonyMethod)null, (HarmonyMethod)null);
				}
				val.Patch((MethodBase)treeBonus, Guard.Hook(typeof(OwnerSkillPatch), "HasTreeActor"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				(MethodBase, Patch, HarmonyPatchType) item4 = SimulationPatch.ExactHook(typeof(TreeBase), "RPC_Damage", AccessTools.DeclaredMethod(Guard.Type(impact, "ImpactfulSkills.patches.Woodcutting+DamageHandler_Apply_Patch"), "Transpiler", (Type[])null, (Type[])null), "MidnightsFX.ImpactfulSkills", (HarmonyPatchType)3);
				FixTreeAnchor(PatchProcessor.GetOriginalInstructions(item4.Item1, (ILGenerator)null)).ToArray();
				list.Add(item4);
				val.Unpatch(item4.Item1, item4.Item2.PatchMethod);
				val.Patch(item4.Item1, (HarmonyMethod)null, (HarmonyMethod)null, Guard.Hook(typeof(OwnerSkillPatch), "FixTreeAnchor"), (HarmonyMethod)null, (HarmonyMethod)null);
				installed = true;
				CompatibilityInstaller.Info("OwnerSkills: APPLIED; owner-side calculations use replicated actor skills; original formulas and server ownership retained.");
			}
			catch (Exception ex)
			{
				installed = false;
				try
				{
					new Harmony("DeepNorthCompat.OwnerSkills").UnpatchSelf();
					foreach (var item5 in list)
					{
						SimulationPatch.Restore(item5);
					}
				}
				catch (Exception ex2)
				{
					CompatibilityInstaller.Error("OwnerSkills: rollback failed; inspect Harmony state before launch. " + ex2);
				}
				CompatibilityInstaller.Error("OwnerSkills: NOT APPLIED; required launch gate failed. " + ex);
			}
		}

		private static bool Configured(FieldInfo field)
		{
			return ((ConfigEntry<bool>)field.GetValue(null)).Value;
		}

		private static ZDO? PlayerZdo(Player player)
		{
			object? value = view.GetValue(player);
			object? obj = ((value is ZNetView) ? value : null);
			if (obj == null)
			{
				return null;
			}
			return ((ZNetView)obj).GetZDO();
		}

		private unsafe static int Key(SkillType skill)
		{
			//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)skill != 12)
			{
				if ((int)skill != 13)
				{
					if (skill != Animal)
					{
						throw new NotSupportedException("Unexpected owner-side skill " + ((object)(*(SkillType*)(&skill))/*cast due to .constrained prefix*/).ToString());
					}
					return AnimalKey;
				}
				return WoodKey;
			}
			return MiningKey;
		}

		private static void Publish(Player __instance)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected I4, but got Unknown
			//IL_0054: 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)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if (server || !coreOnServer || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			ZDO val = PlayerZdo(__instance);
			if (val == null || val.GetOwner() != ZNet.GetUID())
			{
				return;
			}
			SkillType[] array = (SkillType[])(object)new SkillType[3]
			{
				(SkillType)12,
				(SkillType)13,
				(SkillType)(int)Animal
			};
			foreach (SkillType val2 in array)
			{
				float skillFactor = ((Character)__instance).GetSkillFactor(val2);
				if (!SkillState.ValidFactor(skillFactor))
				{
					throw new InvalidOperationException("Invalid local skill factor.");
				}
				val.Set(Key(val2), skillFactor);
			}
			val.Set(ProtocolKey, 1, false);
		}

		private static void PublishPeriodic(Player __instance)
		{
			if (!server && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !(Time.unscaledTime < nextPublish))
			{
				if (ZRoutedRpc.instance != null && Time.unscaledTime >= nextHello)
				{
					nextHello = Time.unscaledTime + 5f;
					ZRoutedRpc.instance.InvokeRoutedRPC(ServerId(), "DeepNorthCompat.OwnerSkillHello", Array.Empty<object>());
				}
				nextPublish = Time.unscaledTime + 0.25f;
				Publish(__instance);
			}
		}

		private static void PublishAfterSkillChange(Skills __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!server && Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)((Character)localPlayer).GetSkills() == (Object)(object)__instance)
			{
				Publish(localPlayer);
			}
		}

		internal static Player? Actor()
		{
			if (!Enabled)
			{
				return Player.m_localPlayer;
			}
			return current;
		}

		internal static float Factor(Character player, SkillType skill)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0008: 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 (!Enabled)
			{
				return player.GetSkillFactor(skill);
			}
			ZDO val = PlayerZdo((Player)player);
			if (val == null)
			{
				throw new InvalidOperationException("Player has no replicated skill state.");
			}
			return SkillState.RequireFactor(val.GetInt(ProtocolKey, 0), val.GetFloat(Key(skill), float.NaN));
		}

		private static void Raise(Character player, SkillType skill, float amount)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0018: 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_0029: Expected I4, but got Unknown
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled)
			{
				player.RaiseSkill(skill, amount);
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(player.GetZDOID());
			val.Write((int)skill);
			val.Write(amount);
			ZRoutedRpc.instance.InvokeRoutedRPC(player.GetOwner(), "DeepNorthCompat.OwnerSkillXP", new object[1] { val });
		}

		private static long ServerId()
		{
			return (long)serverId.Invoke(ZRoutedRpc.instance, null);
		}

		private static void RegisterRpc(ZRoutedRpc __instance)
		{
			__instance.Register<ZPackage>("DeepNorthCompat.OwnerSkillXP", (Action<long, ZPackage>)GrantXP);
			__instance.Register("DeepNorthCompat.OwnerSkillHello", (Action<long>)Hello);
			__instance.Register<bool>("DeepNorthCompat.OwnerSkillStatus", (Action<long, bool>)Status);
		}

		private static void Hello(long sender)
		{
			if (server)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "DeepNorthCompat.OwnerSkillStatus", new object[1] { Enabled });
			}
		}

		private static void Status(long sender, bool active)
		{
			if (!server && sender == ServerId())
			{
				coreOnServer = active;
				if (active && Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					Publish(Player.m_localPlayer);
				}
			}
		}

		private static void GrantXP(long sender, ZPackage package)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0055: Invalid comparison between I4 and Unknown
			if (!server && coreOnServer && ZRoutedRpc.instance != null && sender == ServerId())
			{
				ZDOID val = package.ReadZDOID();
				int num = package.ReadInt();
				float num2 = package.ReadSingle();
				Player localPlayer = Player.m_localPlayer;
				if (Object.op_Implicit((Object)(object)localPlayer) && val == ((Character)localPlayer).GetZDOID() && num == (int)Animal && num2 >= 0f && !float.IsNaN(num2) && !float.IsInfinity(num2))
				{
					((Character)localPlayer).RaiseSkill((SkillType)num, num2);
				}
			}
		}

		private static Coroutine RunCoroutine(MonoBehaviour original, IEnumerator routine)
		{
			if (!Enabled)
			{
				return original.StartCoroutine(routine);
			}
			return ((MonoBehaviour)Plugin.Instance).StartCoroutine(routine);
		}

		internal static IEnumerable<CodeInstruction> RewriteContext(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo local = AccessTools.Field(typeof(Player), "m_localPlayer");
			MethodInfo factor = AccessTools.Method(typeof(Character), "GetSkillFactor", (Type[])null, (Type[])null);
			MethodInfo raise = AccessTools.Method(typeof(Character), "RaiseSkill", (Type[])null, (Type[])null);
			MethodInfo coroutine = AccessTools.Method(typeof(MonoBehaviour), "StartCoroutine", new Type[1] { typeof(IEnumerator) }, (Type[])null);
			foreach (CodeInstruction instruction in instructions)
			{
				CodeInstruction val = new CodeInstruction(instruction);
				if (val.opcode == OpCodes.Ldsfld && object.Equals(val.operand, local))
				{
					val.opcode = OpCodes.Call;
					val.operand = AccessTools.Method(typeof(OwnerSkillPatch), "Actor", (Type[])null, (Type[])null);
				}
				else if (CodeInstructionExtensions.Calls(val, factor))
				{
					val.opcode = OpCodes.Call;
					val.operand = AccessTools.Method(typeof(OwnerSkillPatch), "Factor", (Type[])null, (Type[])null);
				}
				else if (CodeInstructionExtensions.Calls(val, raise))
				{
					val.opcode = OpCodes.Call;
					val.operand = AccessTools.Method(typeof(OwnerSkillPatch), "Raise", (Type[])null, (Type[])null);
				}
				else if (CodeInstructionExtensions.Calls(val, coroutine))
				{
					val.opcode = OpCodes.Call;
					val.operand = AccessTools.Method(typeof(OwnerSkillPatch), "RunCoroutine", (Type[])null, (Type[])null);
				}
				yield return val;
			}
		}

		private static bool BeginDamage(Component __instance, HitData __1, out Scope? __state)
		{
			__state = null;
			if (!Enabled)
			{
				return true;
			}
			Character obj = ((__1 != null) ? __1.GetAttacker() : null);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			bool flag = __instance is MineRock || __instance is MineRock5;
			bool flag2 = __instance is TreeBase || __instance is TreeLog;
			if (__instance is Destructible)
			{
				int num = (int)AccessTools.Field(typeof(Destructible), "m_destructibleType").GetValue(__instance);
				flag = num == 1;
				flag2 = num == 2;
			}
			if ((Object)(object)val != (Object)null && ((flag && Configured(miningEnabled) && !Ready(val, (SkillType)12)) || (flag2 && Configured(woodEnabled) && !Ready(val, (SkillType)13))))
			{
				return false;
			}
			__state = new Scope(val);
			return true;
		}

		private static bool Ready(Player player, SkillType skill)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Factor((Character)(object)player, skill);
				missingPlayers.Remove(((Character)player).GetZDOID());
				return true;
			}
			catch (InvalidOperationException)
			{
				if (missingPlayers.Add(((Character)player).GetZDOID()))
				{
					CompatibilityInstaller.Error("OwnerSkills: waiting for valid skill state from player " + ((object)((Character)player).GetZDOID()/*cast due to .constrained prefix*/).ToString() + "; resource actions paused before mutation. Check the client's matching compatibility package.");
				}
				return false;
			}
		}

		private static Player? Nearby(Component target, float range)
		{
			return SkillState.Closest(Player.GetAllPlayers(), delegate(Player p)
			{
				//IL_0006: 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)
				//IL_001b: 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)
				Vector3 val = ((Component)p).transform.position - target.transform.position;
				return ((Vector3)(ref val)).sqrMagnitude;
			}, (Player p) => ((Character)p).GetOwner(), range);
		}

		private static bool BeginNearby(Component target, float range, out Scope? state)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			state = null;
			if (!Enabled || !Configured(animalEnabled))
			{
				return true;
			}
			Player val = Nearby(target, range);
			if ((Object)(object)val != (Object)null && !Ready(val, Animal))
			{
				return false;
			}
			state = new Scope(val);
			return true;
		}

		private static bool BeginTaming(Tameable __instance, out Scope? __state)
		{
			return BeginNearby((Component)(object)__instance, 30f, out __state);
		}

		private static void BeginLoot(CharacterDrop __instance, out Scope? __state)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (Enabled && Configured(animalEnabled))
			{
				Character component = ((Component)__instance).GetComponent<Character>();
				Player val = ((Object.op_Implicit((Object)(object)component) && component.IsTamed()) ? Nearby((Component)(object)__instance, LootRange) : null);
				if ((Object)(object)val != (Object)null)
				{
					Factor((Character)(object)val, Animal);
				}
				__state = new Scope(val);
			}
		}

		private static void BeginSlaughter(Tameable __instance, out Scope? __state)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (Enabled && Configured(animalEnabled))
			{
				Character component = ((Component)__instance).GetComponent<Character>();
				Player val = ((Object.op_Implicit((Object)(object)component) && component.IsTamed()) ? Nearby((Component)(object)__instance, LootRange) : null);
				if ((Object)(object)val != (Object)null)
				{
					Factor((Character)(object)val, Animal);
				}
				__state = new Scope(val);
			}
		}

		private static void EndScope(Scope? __state)
		{
			__state?.Dispose();
		}

		private static bool HasTreeActor()
		{
			if (Enabled)
			{
				return (Object)(object)current != (Object)null;
			}
			return true;
		}

		private static bool DeathReady(Character __instance)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || !Configured(animalEnabled) || !__instance.IsTamed() || __instance.IsDead() || __instance.GetHealth() > 0f)
			{
				return true;
			}
			Player val = Nearby((Component)(object)__instance, LootRange);
			if (!((Object)(object)val == (Object)null))
			{
				return Ready(val, Animal);
			}
			return true;
		}

		private static bool OncePerMiningArea(MineRock5 __0, int __2, float __3)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if ((!server && !coreOnServer) || (server && !Enabled))
			{
				return true;
			}
			object? value = AccessTools.Field(typeof(MineRock5), "m_nview").GetValue(__0);
			object? obj = ((value is ZNetView) ? value : null);
			ZDO val = ((obj != null) ? ((ZNetView)obj).GetZDO() : null);
			if (val == null || val.GetOwner() != ServerId())
			{
				return true;
			}
			if (!server)
			{
				return false;
			}
			if (__3 <= 0f && (Object)(object)current != (Object)null)
			{
				return minedAreas.Add((val.m_uid, __2));
			}
			return false;
		}

		private static void TreeDrops(TreeBase tree)
		{
			treeBonus.Invoke(null, new object[1] { tree });
		}

		internal static IEnumerable<CodeInstruction> FixTreeAnchor(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			List<CodeInstruction> codes = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction c) => new CodeInstruction(c))).ToList();
			if (codes.Count < 3)
			{
				throw new NotSupportedException("TreeBase damage body changed; refusing to move drop logic.");
			}
			int[] array = (from i in Enumerable.Range(0, codes.Count - 2)
				where codes[i].opcode == OpCodes.Ldloc_0 && codes[i + 1].opcode == OpCodes.Ldc_R4 && object.Equals(codes[i + 1].operand, 0f) && (codes[i + 2].opcode == OpCodes.Bgt_Un || codes[i + 2].opcode == OpCodes.Bgt_Un_S)
				select i).ToArray();
			if (array.Length != 2)
			{
				throw new NotSupportedException("TreeBase damage health branches changed; refusing to move drop logic.");
			}
			codes.InsertRange(array[1] + 3, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				CodeInstruction.Call(typeof(OwnerSkillPatch), "TreeDrops", (Type[])null, (Type[])null)
			});
			return codes;
		}

		private static void Reset()
		{
			minedAreas.Clear();
			missingPlayers.Clear();
			nextPublish = 0f;
			nextHello = 0f;
			current = null;
			coreOnServer = false;
		}
	}
	internal static class QualityPatch
	{
		internal sealed class Source
		{
			internal readonly Inventory Inventory;

			internal readonly object? Container;

			internal Source(Inventory inventory, object? container)
			{
				Inventory = inventory;
				Container = container;
			}
		}

		private sealed class Craft
		{
			internal readonly Player Player;

			internal readonly Requirement[] Requirements;

			internal readonly int Quality;

			internal readonly int Multiplier;

			internal readonly string Prefab;

			internal readonly IngredientPlan<ItemData, Source> Plan;

			internal readonly IngredientReservation<ItemData, Source> Reservation;

			internal readonly List<ItemData> PlayerItems;

			internal readonly Dictionary<ItemData, int> PlayerCounts;

			internal Craft(Player player, Requirement[] requirements, int quality, int multiplier, string prefab, IngredientPlan<ItemData, Source> plan)
			{
				Player = player;
				Requirements = requirements;
				Quality = quality;
				Multiplier = multiplier;
				Prefab = prefab;
				Plan = plan;
				Reservation = new IngredientReservation<ItemData, Source>(plan);
				PlayerItems = new List<ItemData>(((Humanoid)player).GetInventory().GetAllItems());
				PlayerCounts = PlayerItems.ToDictionary((ItemData item) => item, (ItemData item) => item.m_stack);
			}
		}

		private sealed class Scope
		{
			internal Craft? Previous;

			internal Craft? Created;
		}

		[ThreadStatic]
		private static Craft? current;

		private static FieldInfo amountEnabled;

		private static FieldInfo equipmentEnabled;

		private static FieldInfo range;

		private static FieldInfo leaveOne;

		private static FieldInfo craftRecipe;

		private static FieldInfo craftUpgrade;

		private static FieldInfo multiCrafting;

		private static MethodInfo shouldPrevent;

		private static MethodInfo query;

		private static MethodInfo canPull;

		private static MethodInfo containerInventory;

		private static MethodInfo containerPrefab;

		private static MethodInfo containerSave;

		private static MethodInfo inventoryChanged;

		private static bool previewFailed;

		private static bool Enabled
		{
			get
			{
				if (!((ConfigEntry<bool>)amountEnabled.GetValue(null)).Value)
				{
					return ((ConfigEntry<bool>)equipmentEnabled.GetValue(null)).Value;
				}
				return true;
			}
		}

		private static bool Pulling => !(bool)shouldPrevent.Invoke(null, null);

		private static bool LeavingOne => Convert.ToInt32(((ConfigEntryBase)leaveOne.GetValue(null)).BoxedValue) != 0;

		internal static void Install(Assembly impact, Assembly crafty, bool hasAaa)
		{
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Expected O, but got Unknown
			Type type = Guard.Type(impact, "ImpactfulSkills.ValConfig");
			amountEnabled = RequiredConfig(type, "EnableQualityIngredientScaling", typeof(ConfigEntry<bool>));
			equipmentEnabled = RequiredConfig(type, "ScaleCraftedEquipmentQuality", typeof(ConfigEntry<bool>));
			Type type2 = Guard.Type(crafty, "AzuCraftyBoxes.AzuCraftyBoxesPlugin");
			range = RequiredConfig(type2, "mRange", typeof(ConfigEntry<float>));
			leaveOne = AccessTools.Field(type2, "leaveOne") ?? throw new MissingFieldException("CraftyBoxes.leaveOne");
			Type type3 = Guard.Type(crafty, "AzuCraftyBoxes.Util.Functions.MiscFunctions");
			shouldPrevent = Guard.Method(type3, "ShouldPrevent", typeof(bool));
			canPull = Guard.Method(Guard.Type(crafty, "AzuCraftyBoxes.Util.Functions.Boxes"), "CanItemBePulled", typeof(bool), typeof(string), typeof(string), typeof(string));
			query = Guard.Type(crafty, "AzuCraftyBoxes.Util.Functions.Boxes+QueryFrame").GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Single((MethodInfo m) => m.Name == "Get" && m.IsGenericMethodDefinition)
				.MakeGenericMethod(typeof(Player));
			Type type4 = Guard.Type(crafty, "AzuCraftyBoxes.IContainers.IContainer");
			containerInventory = Guard.Method(type4, "GetInventory", typeof(Inventory));
			containerPrefab = Guard.Method(type4, "GetPrefabName", typeof(string));
			containerSave = Guard.Method(type4, "Save", typeof(void));
			MethodInfo methodInfo = Guard.Method(type3, "ProcessRequirements", typeof(void), typeof(Requirement[]), typeof(int), typeof(Inventory), typeof(List<>).MakeGenericType(type4), typeof(int), typeof(int), typeof(CraftingStation));
			Type type5 = Guard.Type(impact, "ImpactfulSkills.IngredientQuality");
			MethodInfo methodInfo2 = Guard.Method(type5, "SelectTier", typeof(int), typeof(Inventory), typeof(ItemData), typeof(int));
			MethodInfo methodInfo3 = Guard.Method(type5, "SelectTier", typeof(int), typeof(Inventory), typeof(string), typeof(int), typeof(int));
			MethodInfo methodInfo4 = Guard.Method(type5, "PanelCraftMultiplier", typeof(int));
			MethodInfo methodInfo5 = Guard.Method(typeof(InventoryGui), "DoCrafting", typeof(void), typeof(Player));
			MethodInfo methodInfo6 = Guard.Method(typeof(Inventory), "AddItem", typeof(ItemData), typeof(string), typeof(int), typeof(int), typeof(int), typeof(long), typeof(string), typeof(Vector2i), typeof(bool), typeof(bool), typeof(bool));
			craftRecipe = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe");
			craftUpgrade = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem");
			multiCrafting = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting");
			inventoryChanged = Guard.Method(typeof(Inventory), "Changed", typeof(void), typeof(bool), typeof(bool));
			Harmony val = new Harmony("DeepNorthCompat.Quality");
			HarmonyMethod val2 = Guard.Hook(typeof(QualityPatch), "Prepare", 800);
			val2.before = new string[1] { "MidnightsFX.ImpactfulSkills" };
			val.Patch((MethodBase)methodInfo5, val2, (HarmonyMethod)null, (HarmonyMethod)null, Guard.Hook(typeof(QualityPatch), "Finish"), (HarmonyMethod)null);
			val.Patch((MethodBase)methodInfo2, Guard.Hook(typeof(QualityPatch), "PrototypeTier"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)methodInfo3, Guard.Hook(typeof(QualityPatch), "NamedTier"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)methodInfo, Guard.Hook(typeof(QualityPatch), "Consume"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			HarmonyMethod val3 = Guard.Hook(typeof(QualityPatch), "Reserve", 0);
			val3.after = new string[1] { "MidnightsFX.ImpactfulSkills" };
			val.Patch((MethodBase)methodInfo6, val3, Guard.Hook(typeof(QualityPatch), "Added"), (HarmonyMethod)null, Guard.Hook(typeof(QualityPatch), "AddFailed"), (HarmonyMethod)null);
			if (hasAaa)
			{
				val.Patch((MethodBase)methodInfo4, Guard.Hook(typeof(QualityPatch), "PanelMultiplier"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo[] array = new MethodInfo[5] { methodInfo5, methodInfo2, methodInfo3, methodInfo, methodInfo6 };
			for (int num = 0; num < array.Length; num++)
			{
				Guard.Registered(array[num]);
			}
			if (hasAaa)
			{
				Guard.Registered(methodInfo4);
			}
		}

		private static FieldInfo RequiredConfig(Type type, string name, Type expected)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if (fieldInfo == null || fieldInfo.FieldType != expected)
			{
				throw new MissingFieldException(type.FullName, name);
			}
			return fieldInfo;
		}

		private static bool Allowed(Source source, string prefab)
		{
			if (source.Container != null)
			{
				return (bool)canPull.Invoke(null, new object[3]
				{
					containerPrefab.Invoke(source.Container, null),
					prefab,
					""
				});
			}
			return true;
		}

		private static List<ResourceStack<ItemData, Source>> Snapshot(Player player)
		{
			List<Source> list = new List<Source>
			{
				new Source(((Humanoid)player).GetInventory(), null)
			};
			HashSet<Inventory> hashSet = new HashSet<Inventory> { ((Humanoid)player).GetInventory() };
			foreach (object item in (IEnumerable)query.Invoke(null, new object[2]
			{
				player,
				((ConfigEntry<float>)range.GetValue(null)).Value
			}))
			{
				object? obj2 = containerInventory.Invoke(item, null);
				Inventory val = (Inventory)((obj2 is Inventory) ? obj2 : null);
				if (val != null && hashSet.Add(val))
				{
					list.Add(new Source(val, item));
				}
			}
			List<ResourceStack<ItemData, Source>> list2 = new List<ResourceStack<ItemData, Source>>();
			foreach (Source item2 in list)
			{
				for (int i = 0; i < item2.Inventory.GetAllItems().Count; i++)
				{
					ItemData val2 = item2.Inventory.GetAllItems()[i];
					if (val2?.m_shared != null && val2.m_stack > 0)
					{
						list2.Add(new ResourceStack<ItemData, Source>(val2, item2, val2.m_shared.m_name, val2.m_quality, val2.m_worldLevel, val2.m_stack, item2.Container != null, i));
					}
				}
			}
			return list2;
		}

		private static ResourceNeed<Source> Need(Requirement requirement, int amount)
		{
			ItemData itemData = requirement.m_resItem.m_itemData;
			string prefab = ((Object)requirement.m_resItem).name;
			return new ResourceNeed<Source>(itemData.m_shared.m_name, itemData.m_shared.m_maxQuality, amount, (Source source) => Allowed(source, prefab));
		}

		private static bool Prepare(InventoryGui __instance, Player __0, out Scope __state)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			__state = new Scope
			{
				Previous = current
			};
			current = null;
			try
			{
				if (!Enabled || !Pulling || (Object)(object)__0 != (Object)(object)Player.m_localPlayer || __0.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25))
				{
					return true;
				}
				Recipe val = (Recipe)craftRecipe.GetValue(__instance);
				if ((Object)(object)val == (Object)null || val.m_requireOnlyOneIngredient)
				{
					return true;
				}
				CraftingStation station = __0.GetCurrentCraftingStation();
				List<Requirement> source = val.m_resources.Where((Requirement r) => r?.m_resItem?.m_itemData?.m_shared != null && r.m_upgraderResource == ((Object)(object)station != (Object)null && station.m_upgrader)).ToList();
				if (!source.Any((Requirement r) => r.m_resItem.m_itemData.m_shared.m_maxQuality > 1))
				{
					return true;
				}
				ItemData val2 = (ItemData)craftUpgrade.GetValue(__instance);
				int quality = ((val2 == null) ? 1 : (val2.m_quality + 1));
				int multiplier = ((!(bool)multiCrafting.GetValue(__instance)) ? 1 : __instance.m_multiCraftAmount);
				List<ResourceNeed<Source>> needs = source.Select((Requirement r) => Need(r, checked(r.GetAmount(quality) * multiplier))).ToList();
				IngredientPlan<ItemData, Source> ingredientPlan = IngredientSelector.Select(Snapshot(__0), needs, Game.m_worldLevel, LeavingOne);
				if (ingredientPlan == null)
				{
					return false;
				}
				if ((from i in ingredientPlan.Ingredients
					group i by new
					{
						i.Need.Name,
						i.Need.Count
					}).Any(group => group.Select((SelectedIngredient<ItemData, Source> i) => i.Tier).Distinct().Count() > 1))
				{
					throw new NotSupportedException("Repeated identical recipe requirements need different tiers; upstream SelectTier cannot distinguish them.");
				}
				current = new Craft(__0, val.m_resources, quality, multiplier, ((Object)((Component)val.m_item).gameObject).name, ingredientPlan);
				__state.Created = current;
				return true;
			}
			catch (Exception ex)
			{
				CompatibilityInstaller.Error("Quality: craft cancelled before output; no safe ingredient plan. " + ex);
				return false;
			}
		}

		private static Exception? Finish(Exception? __exception, Scope __state)
		{
			try
			{
				Craft created = __state.Created;
				if (created != null && created.Reservation.State == ReservationState.Reserved)
				{
					Rollback(created);
				}
			}
			finally
			{
				current = __state.Previous;
			}
			return __exception;
		}

		private static bool FindTier(Inventory inventory, string name, int amount, out int tier)
		{
			tier = 0;
			if (current == null || inventory != ((Humanoid)current.Player).GetInventory() || current.Reservation.State == ReservationState.Committed || current.Reservation.State == ReservationState.RolledBack)
			{
				return false;
			}
			SelectedIngredient<ItemData, Source> selectedIngredient = current.Plan.Ingredients.FirstOrDefault((SelectedIngredient<ItemData, Source> i) => i.Need.Name == name && i.Need.Count == amount);
			if (selectedIngredient == null)
			{
				return false;
			}
			tier = selectedIngredient.Tier;
			return true;
		}

		private static bool NamedTier(Inventory __0, string __1, int __3, ref int __result)
		{
			if (!FindTier(__0, __1, __3, out var tier))
			{
				return true;
			}
			__result = tier;
			return false;
		}

		private static bool PrototypeTier(Inventory __0, ItemData __1, int __2, ref int __result)
		{
			if (__1 == null)
			{
				return true;
			}
			if (FindTier(__0, __1.m_shared.m_name, __2, out var tier))
			{
				__result = tier;
				return false;
			}
			if (!Enabled || !Pulling || (Object)(object)Player.m_localPlayer == (Object)null || __0 != ((Humanoid)Player.m_localPlayer).GetInventory())
			{
				return true;
			}
			try
			{
				GameObject val = (((Object)(object)__1.m_dropPrefab != (Object)null) ? __1.m_dropPrefab : (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(__1.m_shared) : null));
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				string prefab = ((Object)val).name;
				ResourceNeed<Source> resourceNeed = new ResourceNeed<Source>(__1.m_shared.m_name, __1.m_shared.m_maxQuality, __2, (Source source) => Allowed(source, prefab));
				__result = (IngredientSelector.Select(Snapshot(Player.m_localPlayer), new ResourceNeed<Source>[1] { resourceNeed }, Game.m_worldLevel, LeavingOne)?.Ingredients.FirstOrDefault()?.Tier).GetValueOrDefault();
				return false;
			}
			catch (Exception ex)
			{
				if (!previewFailed)
				{
					CompatibilityInstaller.Warning("Quality preview failed; the crafting panel shows no quality bonus while this persists. Later preview failures are not logged. " + ex);
				}
				previewFailed = true;
				__result = 0;
				return false;
			}
		}

		private static int Count(ResourceStack<ItemData, Source> stack)
		{
			ItemData id = stack.Id;
			if (!stack.Source.Inventory.ContainsItem(id) || id.m_quality != stack.Quality || id.m_worldLevel != stack.WorldLevel || !(id.m_shared.m_name == stack.Name))
			{
				return 0;
			}
			return id.m_stack;
		}

		private static bool Remove(Allocation<ItemData, Source> allocation)
		{
			Source source = allocation.Stack.Source;
			ItemData id = allocation.Stack.Id;
			int num = source.Inventory.GetAllItems().IndexOf(id);
			if (num < 0 || id.m_stack < allocation.Count)
			{
				return false;
			}
			if (id.m_stack == allocation.Count)
			{
				return source.Inventory.RemoveItem(num);
			}
			id.m_stack -= allocation.Count;
			return true;
		}

		private static bool Valid(Craft craft)
		{
			if (craft.Plan.Ingredients.Any((SelectedIngredient<ItemData, Source> ingredient) => ingredient.Allocations.Any((Allocation<ItemData, Source> allocation) => !ingredient.Need.AllowsSource(allocation.Stack.Source))))
			{
				return false;
			}
			if (LeavingOne)
			{
				foreach (var item in from a in craft.Plan.Allocations
					where a.Stack.Container
					group a by new
					{
						a.Stack.Source,
						a.Stack.Name
					})
				{
					if (item.Key.Source.Inventory.CountItems(item.Key.Name, -1, true) <= item.Sum((Allocation<ItemData, Source> a) => a.Count))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static void Restore(ResourceStack<ItemData, Source> stack, int count)
		{
			Source source = stack.Source;
			ItemData id = stack.Id;
			if (!source.Inventory.ContainsItem(id))
			{
				source.Inventory.GetAllItems().Insert(Math.Min(stack.Index, source.Inventory.GetAllItems().Count), id);
			}
			id.m_stack = count;
		}

		private static void Save(Craft craft)
		{
			foreach (object item in craft.Plan.Allocations.Select((Allocation<ItemData, Source> a) => a.Stack.Source.Container).OfType<object>().Distinct())
			{
				containerSave.Invoke(item, null);
			}
			inventoryChanged.Invoke(((Humanoid)craft.Player).GetInventory(), new object[2] { false, false });
		}

		private static void Rollback(Craft craft)
		{
			craft.Reservation.Rollback(Restore);
			List<ItemData> allItems = ((Humanoid)craft.Player).GetInventory().GetAllItems();
			allItems.Clear();
			allItems.AddRange(craft.PlayerItems);
			foreach (KeyValuePair<ItemData, int> playerCount in craft.PlayerCounts)
			{
				playerCount.Key.m_stack = playerCount.Value;
			}
			Save(craft);
		}

		private static bool Reserve(Inventory __instance, string __0, ref bool __9, ref ItemData? __result, out Craft? __state)
		{
			__state = null;
			Craft craft = current;
			if (craft == null || __instance != ((Humanoid)craft.Player).GetInventory() || __0 != craft.Prefab || craft.Reservation.State != ReservationState.Planned)
			{
				return true;
			}
			__state = craft;
			try
			{
				if (!Pulling || !Valid(craft) || !craft.Reservation.Reserve(Count, Remove, Restore))
				{
					Rollback(craft);
					__result = null;
					CompatibilityInstaller.Warning("Quality: ingredients changed; output cancelled without consumption.");
					return false;
				}
				__9 = false;
				return true;
			}
			catch (Exception ex)
			{
				Rollback(craft);
				__result = null;
				CompatibilityInstaller.Error("Quality: ingredient reservation failed; output cancelled. " + ex);
				return false;
			}
		}

		private static void Added(ItemData? __result, Craft? __state)
		{
			if (__state != null && __state.Reservation.State == ReservationState.Reserved)
			{
				if (__result == null)
				{
					Rollback(__state);
					return;
				}
				__state.Reservation.Complete(outputCreated: true, Restore);
				Save(__state);
			}
		}

		private static Exception? AddFailed(Exception? __exception, Craft? __state)
		{
			if (__exception != null && __state != null && __state.Reservation.State == ReservationState.Reserved)
			{
				Rollback(__state);
			}
			return __exception;
		}

		private static bool Consume(Requirement[] __0, int __1, Inventory __2, int __4, int __5)
		{
			Craft craft = current;
			if (craft == null || __0 != craft.Requirements || __1 != craft.Quality || __2 != ((Humanoid)craft.Player).GetInventory() || __4 >= 0 || __5 != craft.Multiplier)
			{
				return true;
			}
			if (craft.Reservation.State == ReservationState.Committed)
			{
				return false;
			}
			if (craft.Reservation.State == ReservationState.Planned && craft.Reservation.Reserve(Count, Remove, Restore))
			{
				craft.Reservation.Complete(outputCreated: true, Restore);
				Save(craft);
				return false;
			}
			throw new InvalidOperationException("Quality ingredient reservation was not committed; refusing a second consumption.");
		}

		private static bool PanelMultiplier(ref int __result)
		{
			__result = 1;
			return false;
		}
	}
	internal static class SimulationPatch
	{
		internal const string ForkGuid = "MVP.Valheim_Serverside_Simulations";

		internal const string CoreOwner = "MVP.Valheim_Serverside_Simulations.Core";

		private const string CompatOwner = "MVP.Valheim_Serverside_Simulations.Compat_ValheimCommunityPatch";

		private const string VpoGuid = "dev.ontrigger.vpo";

		private const string VcpGuid = "MidnightsFX.ValheimCommunityPatch";

		internal const string ForkHash = "804AE557AD93D44C508EFCB472BE23DCFB5DE80FBFA13F5EC264D2DDB009221A";

		internal const string ServerHash = "7CAB9B49D31EC064591CA80402DD35C566E03B7297CFB7BF4696C38DA4E24D8B";

		private const string VpoHash = "614CD643343E2E2D182BA4B50AA8C96D8FEDB8E09A16C6AA0018BAD222D6EE70";

		private const string VcpHash = "1B80C4EACBB831D11ED9C044D40DFE03B5D8E84B9A51D9B6646031C98ADEAF8C";

		private static Assembly? fork;

		private static Assembly? vpo;

		private static Assembly? vcp;

		private static bool pending;

		internal static bool Active { get; private set; }

		internal static void Prepare(Func<string, Assembly?> resolve)
		{
			Active = false;
			fork = resolve("MVP.Valheim_Serverside_Simulations");
			vpo = resolve("dev.ontrigger.vpo");
			vcp = resolve("MidnightsFX.ValheimCommunityPatch");
			pending = fork != null;
			if (fork == null)
			{
				CompatibilityInstaller.Info("Simulation: fork absent; inactive.");
			}
			else
			{
				Guard.Build(fork, "804AE557AD93D44C508EFCB472BE23DCFB5DE80FBFA13F5EC264D2DDB009221A");
			}
		}

		internal static bool CoreActive(Assembly assembly)
		{
			(Type, string, string)[] array = new(Type, string, string)[3]
			{
				(typeof(ZNetScene), "CreateDestroyObjects", "CreateDestroyObjects_Patch"),
				(typeof(ZDOMan), "ReleaseNearbyZDOS", "ZDOMan_ReleaseNearbyZDOS_Patch"),
				(typeof(ZoneSystem), "Update", "ZoneSystem_Update_Patch")
			};
			for (int i = 0; i < array.Length; i++)
			{
				(Type, string, string) tuple = array[i];
				Type item = tuple.Item1;
				string item2 = tuple.Item2;
				string item3 = tuple.Item3;
				Type type = Guard.Type(assembly, "Valheim_Serverside.Features.Core+" + item3);
				MethodInfo hook = AccessTools.DeclaredMethod(type, "Prefix", (Type[])null, (Type[])null);
				Patches patchInfo = Harmony.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(item, item2, (Type[])null, (Type[])null));
				if (patchInfo == null || !patchInfo.Prefixes.Any((Patch p) => p.owner == "MVP.Valheim_Serverside_Simulations.Core" && p.PatchMethod == hook))
				{
					return false;
				}
			}
			return true;
		}

		internal static void Verify()
		{
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Expected O, but got Unknown
			if (!pending || fork == null)
			{
				return;
			}
			pending = false;
			List<(MethodBase, Patch, HarmonyPatchType)> list = new List<(MethodBase, Patch, HarmonyPatchType)>();
			(MethodInfo, MethodInfo)? tuple = null;
			try
			{
				if (!CoreActive(fork))
				{
					CompatibilityInstaller.Info("Simulation: Core not active on this process; object-management patches retained.");
					return;
				}
				Guard.Build(typeof(ZNet).Assembly, "7CAB9B49D31EC064591CA80402DD35C566E03B7297CFB7BF4696C38DA4E24D8B");
				List<(MethodBase, Patch, HarmonyPatchType)> list2 = new List<(MethodBase, Patch, HarmonyPatchType)>();
				(MethodInfo, MethodInfo)? tuple2 = null;
				if (vpo != null)
				{
					Guard.Build(vpo, "614CD643343E2E2D182BA4B50AA8C96D8FEDB8E09A16C6AA0018BAD222D6EE70");
					Type type = Guard.Type(vpo, "ValheimPerformanceOptimizations.Patches.ObjectManagement.ZNetSceneObjectManagementPatch");
					Type type2 = Guard.Type(vpo, "ValheimPerformanceOptimizations.Patches.ObjectManagement.ZDOManReleaseNearbyPatch");
					(Type, string, string, HarmonyPatchType)[] array = new(Type, string, string, HarmonyPatchType)[8]
					{
						(typeof(ZNetScene), "CreateDestroyObjects", "ZNetScene_CreateDestroyObjects_Prefix", (HarmonyPatchType)1),
						(typeof(ZDOMan), "AddToSector", "ZDOMan_AddToSector_Postfix", (HarmonyPatchType)2),
						(typeof(ZDO), "InvalidateSector", "ZDO_InvalidateSector_Postfix", (HarmonyPatchType)2),
						(typeof(ZDOMan), "HandleDestroyedZDO", "ZDOMan_HandleDestroyedZDO_Postfix", (HarmonyPatchType)2),
						(typeof(ZDO), "Deserialize", "ZDO_Deserialize_Postfix", (HarmonyPatchType)2),
						(typeof(ZNetScene), "AddInstance", "ZNetScene_AddInstance_Postfix", (HarmonyPatchType)2),
						(typeof(ZNetScene), "Destroy", "ZNetScene_Destroy_Prefix", (HarmonyPatchType)1),
						(typeof(ZNetScene), "Shutdown", "ZNetScene_Shutdown_Prefix", (HarmonyPatchType)1)
					};
					for (int i = 0; i < array.Length; i++)
					{
						var (type3, name, text, kind) = array[i];
						list2.Add(ExactHook(type3, name, AccessTools.DeclaredMethod(type, text, (Type[])null, (Type[])null), "dev.ontrigger.vpo", kind));
					}
					list2.Add(ExactHook(typeof(ZDOMan), "ReleaseNearbyZDOS", AccessTools.DeclaredMethod(type2, "Prefix", (Type[])null, (Type[])null), "dev.ontrigger.vpo", (HarmonyPatchType)1));
				}
				if (vcp != null)
				{
					Guard.Build(vcp, "1B80C4EACBB831D11ED9C044D40DFE03B5D8E84B9A51D9B6646031C98ADEAF8C");
					Type type4 = Guard.Type(vcp, "ValheimCommunityPatch.Patches.Performance.SceneIdleSkipPatch");
					list2.Add(ExactHook(typeof(ZNetScene), "CreateDestroyObjects", AccessTools.DeclaredMethod(type4, "CreateDestroyObjectsPrefix", (Type[])null, (Type[])null), "MidnightsFX.ValheimCommunityPatch", (HarmonyPatchType)1));
					list2.Add(ExactHook(typeof(ZNetScene), "CreateDestroyObjects", AccessTools.DeclaredMethod(type4, "CreateDestroyObjectsPostfix", (Type[])null, (Type[])null), "MidnightsFX.ValheimCommunityPatch", (HarmonyPatchType)2));
					Type type5 = Guard.Type(fork, "Valheim_Serverside.Features.Compat_ValheimCommunityPatch+ZNetScene_Awake_Patch");
					MethodInfo methodInfo = Guard.Method(typeof(ZNetScene), "Awake", typeof(void));
					MethodInfo hook = Guard.Method(type5, "Postfix", typeof(void));
					if (!All(methodInfo).Any((Patch p) => p.PatchMethod == hook))
					{
						if ((bool)AccessTools.Field(type5, "s_done").GetValue(null))
						{
							throw new NotSupportedException("Fork VCP takeover already ran but its registration is missing.");
						}
						tuple2 = (methodInfo, hook);
					}
					else
					{
						ExactHook(typeof(ZNetScene), "Awake", hook, "MVP.Valheim_Serverside_Simulations.Compat_ValheimCommunityPatch", (HarmonyPatchType)2);
					}
				}
				foreach (var item in list2)
				{
					list.Add(item);
					new Harmony("DeepNorthCompat.Simulation").Unpatch(item.Item1, item.Item2.PatchMethod);
				}
				if (tuple2.HasValue)
				{
					tuple = tuple2;
					new Harmony("MVP.Valheim_Serverside_Simulations.Compat_ValheimCommunityPatch").Patch((MethodBase)tuple.Value.Item1, (HarmonyMethod)null, new HarmonyMethod(tuple.Value.Item2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					ExactHook(typeof(ZNetScene), "Awake", tuple.Value.Item2, "MVP.Valheim_Serverside_Simulations.Compat_ValheimCommunityPatch", (HarmonyPatchType)2);
					CompatibilityInstaller.Info("Simulation: registered the fork's existing VCP takeover after chainloading.");
				}
				if (!CoreActive(fork))
				{
					throw new InvalidOperationException("Core changed during integration.");
				}
				Active = true;
				CompatibilityInstaller.Info($"Simulation: APPLIED; removed {list.Count} exact server-side VPO/VCP hooks; Core retained.");
			}
			catch (Exception ex)
			{
				if (tuple.HasValue)
				{
					try
					{
						new Harmony("MVP.Valheim_Serverside_Simulations.Compat_ValheimCommunityPatch").Unpatch((MethodBase)tuple.Value.Item1, tuple.Value.Item2);
					}
					catch (Exception ex2)
					{
						CompatibilityInstaller.Error("Simulation: fork VCP registration rollback failed. " + ex2);
					}
				}
				foreach (var item2 in list)
				{
					try
					{
						Restore(item2);
					}
					catch (Exception ex3)
					{
						CompatibilityInstaller.Error("Simulation: rollback failed; inspect Harmony state before launch. " + ex3);
					}
				}
				CompatibilityInstaller.Error("Simulation: REJECTED BUILD/REGISTRATIONS; required launch gate failed. " + ex);
			}
		}

		internal static IEnumerable<Patch> All(MethodBase target)
		{
			Patches patchInfo = Harmony.GetPatchInfo(target);
			if (patchInfo != null)
			{
				return patchInfo.Prefixes.Concat(patchInfo.Postfixes).Concat(patchInfo.Transpilers).Concat(patchInfo.Finalizers)
					.Concat(patchInfo.ILManipulators);
			}
			return Enumerable.Empty<Patch>();
		}

		internal static (MethodBase Target, Patch Hook, HarmonyPatchType Kind) ExactHook(Type type, string name, MethodInfo method, string owner, HarmonyPatchType kind)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, (Type[])null, (Type[])null);
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			Patch[] array = (from p in All(methodInfo)
				where p.PatchMethod == method
				select p).ToArray();
			IEnumerable<Patch> enumerable2;
			if (patchInfo != null)
			{
				IEnumerable<Patch> enumerable = (((int)kind == 1) ? patchInfo.Prefixes : (((int)kind == 2) ? patchInfo.Postfixes : patchInfo.Transpilers));
				enumerable2 = enumerable;
			}
			else
			{
				enumerable2 = Enumerable.Empty<Patch>();
			}
			IEnumerable<Patch> source = enumerable2;
			if (array.Length != 1 || array[0].owner != owner || !source.Contains(array[0]))
			{
				throw new NotSupportedException($"Expected one {owner} {kind}: {Guard.Name(method)} on {Guard.Name(methodInfo)}.");
			}
			return (Target: methodInfo, Hook: array[0], Kind: kind);
		}

		internal static void Restore((MethodBase Target, Patch Hook, HarmonyPatchType Kind) hook)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Invalid comparison between Unknown and I4
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Invalid comparison between Unknown and I4
			if (!All(hook.Target).Any((Patch p) => p.PatchMethod == hook.Hook.PatchMethod))
			{
				HarmonyMethod val = new HarmonyMethod(hook.Hook.PatchMethod, hook.Hook.priority, hook.Hook.before, hook.Hook.after, (bool?)hook.Hook.debug);
				Harmony val2 = new Harmony(hook.Hook.owner);
				if ((int)hook.Kind == 1)
				{
					val2.Patch(hook.Target, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				else if ((int)hook.Kind == 2)
				{
					val2.Patch(hook.Target, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				else
				{
					val2.Patch(hook.Target, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}
	}
	internal static class TuneClientPatch
	{
		private static Assembly? pending;

		private const string Guid = "akoozie.valheimtune";

		internal static void Prepare(Assembly? assembly)
		{
			pending = null;
			if (assembly == null)
			{
				CompatibilityInstaller.Info("Tune.Client: optional mod absent; inactive.");
				return;
			}
			Guard.Build(assembly, "8043CD81398FF33CA29FBC75A1D4BDD20BBE950E6BB67D8BF66668C0404A9515");
			pending = assembly;
		}

		internal static void Verify()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			Assembly assembly = pending;
			pending = null;
			if (assembly == null)
			{
				return;
			}
			try
			{
				if (Guard.KnownServerBuild())
				{
					CompatibilityInstaller.Info("Tune.Client: dedicated build; server patches retained.");
					return;
				}
				Guard.Build(typeof(ZNet).Assembly, "96CFC004F7F4A6F30D070BEF39EAFD79C466A137121C4665A2F19FB9C15C6127");
				object? value = AccessTools.Field(Guard.Type(assembly, "ValheimTune.Plugin"), "Instance").GetValue(null);
				object? obj = ((value is BaseUnityPlugin) ? value : null);
				if ((Object)obj == (Object)null)
				{
					throw new InvalidOperationException("ValheimTune instance missing after chainloading.");
				}
				((Behaviour)obj).enabled = false;
				new Harmony("akoozie.valheimtune").UnpatchSelf();
				if (Harmony.GetAllPatchedMethods().Any((MethodBase m) => Harmony.GetPatchInfo(m).Owners.Contains("akoozie.valheimtune")))
				{
					throw new InvalidOperationException("ValheimTune client hooks remain installed.");
				}
				CompatibilityInstaller.Info("Tune.Client: APPLIED; server-only Tune component and its client hooks disabled.");
			}
			catch (Exception ex)
			{
				CompatibilityInstaller.Error("Tune.Client: NOT APPLIED; required launch gate failed. " + ex);
			}
		}
	}
	[BepInPlugin("DeepNorthCompat", "DeepNorthCompat", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "DeepNorthCompat";

		internal static Plugin Instance;

		private void Awake()
		{
			Instance = this;
			CompatibilityInstaller.Install(Resolve, delegate(string message)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)message);
			}, delegate(string message)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)message);
			}, delegate(string message)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)message);
			});
			static Assembly? Resolve(string guid)
			{
				if (!Chainloader.PluginInfos.TryGetValue(guid, out var value))
				{
					return null;
				}
				return ((object)value.Instance)?.GetType().Assembly;
			}
		}

		private void Start()
		{
			CompatibilityInstaller.Verify();
		}
	}
	public static class SkillState
	{
		public const int Protocol = 1;

		public static bool ValidFactor(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value) && value >= 0f)
			{
				return value <= 1f;
			}
			return false;
		}

		public static T? Closest<T>(IEnumerable<T> players, Func<T, float> squaredDistance, Func<T, long> id, float range) where T : class
		{
			return players.Where((T p) => squaredDistance(p) <= range * range).OrderBy(squaredDistance).ThenBy(id)
				.FirstOrDefault();
		}

		public static float RequireFactor(int protocol, float value)
		{
			if (protocol != 1 || !ValidFactor(value))
			{
				throw new InvalidOperationException("Missing or invalid DeepNorthCompat skill state. All players must use the matching compatibility package.");
			}
			return value;
		}
	}
}