Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DeepNorthCompat v1.1.0
BepInEx/plugins/DeepNorthCompat/DeepNorthCompat.dll
Decompiled 25 minutes agousing 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; } } }