Decompiled source of Hunter Legacy v1.1.10

plugins/Hunter_Legacy.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using AzuEPI;
using AzuEPI.Core.Slots;
using AzuExtendedPlayerInventory;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Distant_Origins.Shared;
using HarmonyLib;
using ItemManager;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using PieceManager;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: AssemblyFileVersion("1.1.10")]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyProduct("Hunter_Legacy")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("Hunter_Legacy")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Dreanegade")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.10.0")]
[module: <fefa00b8-4670-491f-a1f5-78b8f8d51136>RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<ecbcddbf-827a-4f41-96e9-b18e7c919305>Embedded]
	internal sealed class <ecbcddbf-827a-4f41-96e9-b18e7c919305>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	[<ecbcddbf-827a-4f41-96e9-b18e7c919305>Embedded]
	internal sealed class <e209b2dd-032d-4991-9c16-f6cc011fed23>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <e209b2dd-032d-4991-9c16-f6cc011fed23>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <e209b2dd-032d-4991-9c16-f6cc011fed23>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[<ecbcddbf-827a-4f41-96e9-b18e7c919305>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class <63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[<ecbcddbf-827a-4f41-96e9-b18e7c919305>Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	[CompilerGenerated]
	internal sealed class <fefa00b8-4670-491f-a1f5-78b8f8d51136>RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public <fefa00b8-4670-491f-a1f5-78b8f8d51136>RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
[HarmonyPatch(typeof(ArcheryTarget), "Start")]
public static class ArcheryTargetCustomProjectile
{
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	public class BoltPair
	{
		public string itemDropName;

		public string projectileName;

		public BoltPair(string item, string proj)
		{
			itemDropName = item;
			projectileName = proj;
		}
	}

	private static readonly List<BoltPair> CustomBolts = new List<BoltPair>
	{
		new BoltPair("BoltFlint_DO", "projectile_bolt_flint_DO"),
		new BoltPair("BoltStone_DO", "projectile_bolt_stone_DO"),
		new BoltPair("BoltObsidian_DO", "projectile_bolt_obsidian_DO"),
		new BoltPair("BoltCrystal_DO", "projectile_bolt_crystal_DO"),
		new BoltPair("BoltMarble_DO", "projectile_bolt_marble_DO"),
		new BoltPair("BoltGrausten_DO", "projectile_bolt_grausten_DO"),
		new BoltPair("ArrowStone_DO", "projectile_arrow_stone_DO"),
		new BoltPair("ArrowCrystal_DO", "projectile_arrow_crystal_DO"),
		new BoltPair("ArrowMarble_DO", "projectile_arrow_marble_DO"),
		new BoltPair("ArrowGrausten_DO", "projectile_arrow_grausten_DO"),
		new BoltPair("PelletStone_DO", "projectile_pellet_stone_DO"),
		new BoltPair("PelletObsidian_DO", "projectile_pellet_obsidian_DO"),
		new BoltPair("PelletMarble_DO", "projectile_pellet_marble_DO"),
		new BoltPair("PelletGrausten_DO", "projectile_pellet_grausten_DO")
	};

	private static void Postfix(ArcheryTarget __instance)
	{
		if ((Object)(object)ZNetScene.instance == (Object)null)
		{
			Debug.LogError((object)"ArcheryTargetCustomProjectile: ZNetScene is null! Cannot register custom bolts.");
			return;
		}
		foreach (BoltPair customBolt in CustomBolts)
		{
			string itemDropName = customBolt.itemDropName;
			string projectileName = customBolt.projectileName;
			GameObject prefab = ZNetScene.instance.GetPrefab(itemDropName);
			if ((Object)(object)prefab == (Object)null)
			{
				Debug.LogWarning((object)("ArcheryTargetCustomProjectile: ItemDrop '" + itemDropName + "' not found."));
				continue;
			}
			ItemDrop component = prefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				Debug.LogWarning((object)("ArcheryTargetCustomProjectile: '" + itemDropName + "' has no ItemDrop component."));
				continue;
			}
			GameObject prefab2 = ZNetScene.instance.GetPrefab(projectileName);
			if ((Object)(object)prefab2 == (Object)null)
			{
				Debug.LogWarning((object)("ArcheryTargetCustomProjectile: Projectile '" + projectileName + "' not found."));
				continue;
			}
			if ((Object)(object)component.m_itemData.m_shared.m_attack.m_attackProjectile == (Object)null || ((Object)component.m_itemData.m_shared.m_attack.m_attackProjectile).name != projectileName)
			{
				component.m_itemData.m_shared.m_attack.m_attackProjectile = prefab2;
				Debug.Log((object)("ArcheryTargetCustomProjectile: Assigned projectile '" + projectileName + "' to ItemDrop '" + itemDropName + "'."));
			}
			if (!__instance.m_returnAmmo.Contains(component))
			{
				__instance.m_returnAmmo.Add(component);
				Debug.Log((object)("ArcheryTargetCustomProjectile: Added '" + itemDropName + "' to ArcheryTarget return ammo."));
			}
		}
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
internal sealed class ConfigurationManagerAttributes
{
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);

	public bool? ShowRangeAsPercent;

	public Action<ConfigEntryBase> CustomDrawer;

	public CustomHotkeyDrawerFunc CustomHotkeyDrawer;

	public bool? Browsable;

	public string Category;

	public object DefaultValue;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;

	public bool? ReadOnly;

	public bool? IsAdvanced;

	public Func<object, string> ObjToStr;

	public Func<string, object> StrToObj;
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
public static class ExtraTooltip
{
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	private static class DevLog
	{
		public const bool Enabled = false;
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	public enum TooltipAttackSlot
	{
		Main,
		Secondary
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	private class TooltipLinkDef
	{
		public readonly string[] ItemPrefabNames;

		public readonly TooltipAttackSlot AttackSlot;

		public readonly List<TooltipEntry> Entries;

		public TooltipLinkDef(string itemPrefabName, TooltipAttackSlot attackSlot, string statusEffectPrefabName)
			: this(new string[1] { itemPrefabName }, attackSlot, new TooltipSELine(statusEffectPrefabName))
		{
		}

		public TooltipLinkDef(string[] itemPrefabNames, TooltipAttackSlot attackSlot, string statusEffectPrefabName)
			: this(itemPrefabNames, attackSlot, new TooltipSELine(statusEffectPrefabName))
		{
		}

		public TooltipLinkDef(string itemPrefabName, TooltipAttackSlot attackSlot, params TooltipEntry[] entries)
			: this(new string[1] { itemPrefabName }, attackSlot, entries)
		{
		}

		public TooltipLinkDef(string[] itemPrefabNames, TooltipAttackSlot attackSlot, params TooltipEntry[] entries)
		{
			ItemPrefabNames = itemPrefabNames ?? Array.Empty<string>();
			AttackSlot = attackSlot;
			Entries = ((entries != null) ? new List<TooltipEntry>(entries) : new List<TooltipEntry>());
		}

		public bool ContainsItem(string itemPrefabName)
		{
			if (string.IsNullOrEmpty(itemPrefabName))
			{
				return false;
			}
			string[] itemPrefabNames = ItemPrefabNames;
			for (int i = 0; i < itemPrefabNames.Length; i++)
			{
				if (itemPrefabNames[i] == itemPrefabName)
				{
					return true;
				}
			}
			return false;
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	private abstract class TooltipEntry
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		public abstract string Build(string itemPrefabName, int qualityLevel, float skillLevel);
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	private class TooltipSELine : TooltipEntry
	{
		private readonly string StatusEffectPrefabName;

		public TooltipSELine(string statusEffectPrefabName)
		{
			StatusEffectPrefabName = statusEffectPrefabName;
		}

		public override string Build(string itemPrefabName, int qualityLevel, float skillLevel)
		{
			StatusEffect val = FindStatusEffect(StatusEffectPrefabName);
			if ((Object)(object)val == (Object)null)
			{
				DLog("StatusEffect not found: " + StatusEffectPrefabName + " for item " + itemPrefabName + ".");
				return "";
			}
			string text = BuildVanillaStatusEffectTooltip(val, qualityLevel, skillLevel);
			if (string.IsNullOrEmpty(text))
			{
				DLog("Tooltip skipped for " + itemPrefabName + ": empty tooltip from " + StatusEffectPrefabName + ".");
				return "";
			}
			return text;
		}
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	private class TooltipTextLine : TooltipEntry
	{
		private readonly string TextKeyOrText;

		private readonly string Color;

		public TooltipTextLine(string textKeyOrText, string color = null)
		{
			TextKeyOrText = textKeyOrText;
			Color = color;
		}

		public override string Build(string itemPrefabName, int qualityLevel, float skillLevel)
		{
			return Colorize(Localize(TextKeyOrText), Color);
		}
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	private class TooltipInlineLine : TooltipEntry
	{
		private readonly List<TooltipInlinePart> Parts;

		public TooltipInlineLine(params TooltipInlinePart[] parts)
		{
			Parts = ((parts != null) ? new List<TooltipInlinePart>(parts) : new List<TooltipInlinePart>());
		}

		public override string Build(string itemPrefabName, int qualityLevel, float skillLevel)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (TooltipInlinePart part in Parts)
			{
				if (part != null)
				{
					stringBuilder.Append(part.Build());
				}
			}
			return stringBuilder.ToString();
		}
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	private class TooltipInlinePart
	{
		private readonly string TextKeyOrText;

		private readonly string Color;

		public TooltipInlinePart(string textKeyOrText, string color = null)
		{
			TextKeyOrText = textKeyOrText;
			Color = color;
		}

		public string Build()
		{
			return Colorize(Localize(TextKeyOrText), Color);
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	private static class ItemData_GetTooltip_ExtraTooltipPatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(ItemData item, int qualityLevel, bool crafting, float worldLevel, int stackOverride, bool appending, ref string __result)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (item == null || item.m_shared == null)
				{
					return;
				}
				string itemPrefabName = GetItemPrefabName(item);
				if (string.IsNullOrEmpty(itemPrefabName))
				{
					return;
				}
				List<TooltipLinkDef> defsForItem = GetDefsForItem(itemPrefabName);
				if (defsForItem.Count != 0)
				{
					float skillLevel = 0f;
					if ((Object)(object)Player.m_localPlayer != (Object)null)
					{
						skillLevel = ((Character)Player.m_localPlayer).GetSkillLevel(item.m_shared.m_skillType);
					}
					StringBuilder stringBuilder = new StringBuilder();
					AppendEntriesForSlot(stringBuilder, defsForItem, itemPrefabName, TooltipAttackSlot.Main, qualityLevel, skillLevel);
					AppendEntriesForSlot(stringBuilder, defsForItem, itemPrefabName, TooltipAttackSlot.Secondary, qualityLevel, skillLevel);
					if (stringBuilder.Length <= 0)
					{
						DLog("Tooltip skipped for " + itemPrefabName + ": no valid extra tooltip was generated.");
						return;
					}
					__result = __result + "\n\n" + stringBuilder.ToString().TrimEnd(Array.Empty<char>());
					DLog("Extra tooltip added for " + itemPrefabName + ".");
				}
			}
			catch (Exception arg)
			{
				DLog($"ERROR while adding extra tooltip: {arg}");
			}
		}
	}

	private const string MainAttackHeaderColor = "#FFC654";

	private const string SecondaryAttackHeaderColor = "#FFC654";

	private const string VanillaSENameColor = "orange";

	private const string HealValueColor = "#C8FF6A";

	private const string MainAttackKey = "$main_attack_DO";

	private const string SecondaryAttackKey = "$secondary_attack_DO";

	private static readonly List<TooltipLinkDef> Defs = new List<TooltipLinkDef>
	{
		new TooltipLinkDef(new string[2] { "BowEvoCoreAshlandsBlood_DO", "CrossbowEvoCoreAshlandsBlood_DO" }, TooltipAttackSlot.Secondary, "SE_BowHeavyBloodBuff_DO"),
		new TooltipLinkDef(new string[3] { "BowGoldenStrider_DO", "BowSapphireFalcon_DO", "BowAshenExile_DO" }, TooltipAttackSlot.Secondary, "SE_BowHeavyBuff_DO"),
		new TooltipLinkDef(new string[13]
		{
			"CrossbowEvoCoreBlackforest_DO", "CrossbowEvoCoreMistlands_DO", "CrossbowEvoCoreMountain_DO", "CrossbowEvoCorePlains_DO", "CrossbowEvoCoreSwamp_DO", "CrossbowDemonHunter_DO", "CrossbowEvoRenegadeAshlandsFrost_DO", "CrossbowEvoRenegadeAshlandsSpirit_DO", "CrossbowEvoRenegadeBlackforest_DO", "CrossbowEvoRenegadeMistlands_DO",
			"CrossbowEvoRenegadeMountain_DO", "CrossbowEvoRenegadePlains_DO", "CrossbowEvoRenegadeSwamp_DO"
		}, TooltipAttackSlot.Secondary, "SE_CrossbowHeavyBuff_DO"),
		new TooltipLinkDef(new string[5] { "SlingshotMeadows_DO", "SlingshotBlackforest_DO", "SlingshotSwamp_DO", "SlingshotPlains_DO", "SlingshotAshlands_DO" }, TooltipAttackSlot.Secondary, new TooltipTextLine("$scatter_shot_DO"))
	};

	private static void AppendEntriesForSlot(StringBuilder sb, List<TooltipLinkDef> itemDefs, string itemPrefabName, TooltipAttackSlot slot, int qualityLevel, float skillLevel)
	{
		bool flag = false;
		foreach (TooltipLinkDef itemDef in itemDefs)
		{
			if (itemDef.AttackSlot != slot)
			{
				continue;
			}
			string value = BuildDefTooltip(itemDef, itemPrefabName, qualityLevel, skillLevel);
			if (string.IsNullOrEmpty(value))
			{
				continue;
			}
			if (!flag)
			{
				if (sb.Length > 0)
				{
					sb.Append("\n\n");
				}
				sb.Append(GetAttackHeader(slot));
				sb.Append("\n");
				flag = true;
			}
			else
			{
				sb.Append("\n\n");
			}
			sb.Append(value);
		}
	}

	private static string BuildDefTooltip(TooltipLinkDef def, string itemPrefabName, int qualityLevel, float skillLevel)
	{
		if (def == null || def.Entries == null || def.Entries.Count == 0)
		{
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder();
		foreach (TooltipEntry entry in def.Entries)
		{
			if (entry == null)
			{
				continue;
			}
			string value = entry.Build(itemPrefabName, qualityLevel, skillLevel);
			if (!string.IsNullOrEmpty(value))
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append("\n");
				}
				stringBuilder.Append(value);
			}
		}
		return stringBuilder.ToString();
	}

	private static string BuildVanillaStatusEffectTooltip(StatusEffect statusEffect, int qualityLevel, float skillLevel)
	{
		if ((Object)(object)statusEffect == (Object)null)
		{
			return "";
		}
		statusEffect.SetLevel(qualityLevel, skillLevel);
		return "<color=orange>" + statusEffect.m_name + "</color>\n" + statusEffect.GetTooltipString();
	}

	private static string GetAttackHeader(TooltipAttackSlot slot)
	{
		return slot switch
		{
			TooltipAttackSlot.Main => Colorize(Localize("$main_attack_DO"), "#FFC654"), 
			TooltipAttackSlot.Secondary => Colorize(Localize("$secondary_attack_DO"), "#FFC654"), 
			_ => "", 
		};
	}

	private static string Colorize(string text, string color)
	{
		if (string.IsNullOrEmpty(text))
		{
			return "";
		}
		if (string.IsNullOrEmpty(color))
		{
			return text;
		}
		return "<color=" + color + ">" + text + "</color>";
	}

	private static string Localize(string keyOrText)
	{
		if (string.IsNullOrEmpty(keyOrText))
		{
			return "";
		}
		if (Localization.instance == null)
		{
			return keyOrText;
		}
		if (keyOrText.StartsWith("$"))
		{
			return Localization.instance.Localize(keyOrText);
		}
		return keyOrText;
	}

	private static List<TooltipLinkDef> GetDefsForItem(string itemPrefabName)
	{
		List<TooltipLinkDef> list = new List<TooltipLinkDef>();
		foreach (TooltipLinkDef def in Defs)
		{
			if (def != null && def.ContainsItem(itemPrefabName))
			{
				list.Add(def);
			}
		}
		return list;
	}

	private static StatusEffect FindStatusEffect(string statusEffectPrefabName)
	{
		if ((Object)(object)ObjectDB.instance == (Object)null)
		{
			return null;
		}
		foreach (StatusEffect statusEffect in ObjectDB.instance.m_StatusEffects)
		{
			if (!((Object)(object)statusEffect == (Object)null))
			{
				if (((Object)statusEffect).name == statusEffectPrefabName)
				{
					return statusEffect;
				}
				if (Utils.GetPrefabName(((Object)statusEffect).name) == statusEffectPrefabName)
				{
					return statusEffect;
				}
			}
		}
		return null;
	}

	private static string GetItemPrefabName(ItemData item)
	{
		if (item == null)
		{
			return "";
		}
		if ((Object)(object)item.m_dropPrefab != (Object)null)
		{
			return Utils.GetPrefabName(((Object)item.m_dropPrefab).name);
		}
		if (item.m_shared != null && !string.IsNullOrEmpty(item.m_shared.m_name))
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(item.m_shared.m_name) : null);
			if ((Object)(object)val != (Object)null)
			{
				return Utils.GetPrefabName(((Object)val).name);
			}
		}
		return "";
	}

	private static void DLog(string message)
	{
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
internal static class CraftingStationBaseLevel
{
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	private sealed class StationDef
	{
		public readonly string PrefabName;

		public readonly int BaseLevel;

		public StationDef(string prefabName, int baseLevel)
		{
			PrefabName = prefabName;
			BaseLevel = baseLevel;
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(CraftingStation), "GetLevel")]
	private static class CraftingStation_GetLevel_Patch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(CraftingStation __instance, ref int __result)
		{
			EnsureInitialized();
			string prefabName = GetPrefabName(__instance);
			if (!string.IsNullOrEmpty(prefabName) && BaseLevels.TryGetValue(prefabName, out var value))
			{
				int extentionCount = __instance.GetExtentionCount(false);
				int val = value + extentionCount;
				int num = __result;
				__result = Math.Max(__result, val);
				if (__result != num)
				{
					Log("Level adjusted | prefab=" + prefabName + " | " + $"baseLevel={value} | " + $"extensions={extentionCount} | " + $"before={num} | " + $"after={__result}");
				}
			}
		}
	}

	private const bool LoggingEnabled = false;

	private static readonly StationDef[] Defs = new StationDef[1]
	{
		new StationDef("HunterTable_DO", 4)
	};

	private static readonly Dictionary<string, int> BaseLevels = new Dictionary<string, int>(StringComparer.Ordinal);

	private static bool _initialized;

	private static void EnsureInitialized()
	{
		if (_initialized)
		{
			return;
		}
		_initialized = true;
		StationDef[] defs = Defs;
		foreach (StationDef stationDef in defs)
		{
			if (stationDef != null && !string.IsNullOrEmpty(stationDef.PrefabName))
			{
				if (stationDef.BaseLevel < 1)
				{
					Log("Invalid def ignored | prefab=" + stationDef.PrefabName + " | " + $"baseLevel={stationDef.BaseLevel}");
					continue;
				}
				BaseLevels[stationDef.PrefabName] = stationDef.BaseLevel;
				Log("Registered | prefab=" + stationDef.PrefabName + " | " + $"baseLevel={stationDef.BaseLevel}");
			}
		}
	}

	private static string GetPrefabName(CraftingStation station)
	{
		if ((Object)(object)station == (Object)null || (Object)(object)((Component)station).gameObject == (Object)null)
		{
			return null;
		}
		string text = ((Object)((Component)station).gameObject).name;
		if (string.IsNullOrEmpty(text))
		{
			return null;
		}
		if (text.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			text = text.Substring(0, text.Length - "(Clone)".Length);
		}
		return text;
	}

	private static void Log(string message)
	{
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
public static class ItemTypeTooltip
{
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	private static class DevLog
	{
		public const bool Enabled = false;
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	private sealed class ItemTypeDef
	{
		public readonly string LocalizationKey;

		public readonly string Color;

		public readonly HashSet<string> PrefabNames;

		public ItemTypeDef(string localizationKey, string color, params string[] prefabNames)
		{
			LocalizationKey = localizationKey;
			Color = color;
			PrefabNames = new HashSet<string>(prefabNames ?? Array.Empty<string>(), StringComparer.Ordinal);
		}
	}

	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	private static class ItemData_GetTooltip_ItemTypeTooltipPatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(ItemData item, int qualityLevel, bool crafting, float worldLevel, int stackOverride, bool appending, ref string __result)
		{
			try
			{
				if (appending || item == null || item.m_shared == null)
				{
					return;
				}
				string itemPrefabName = GetItemPrefabName(item);
				if (string.IsNullOrEmpty(itemPrefabName))
				{
					return;
				}
				ItemTypeDef itemTypeDef = FindDef(itemPrefabName);
				if (itemTypeDef == null)
				{
					return;
				}
				string text = Localize(itemTypeDef.LocalizationKey);
				if (!string.IsNullOrEmpty(text))
				{
					string text2 = "<align=center><color=" + itemTypeDef.Color + ">[ " + text + " ]</color></align>";
					if (string.IsNullOrEmpty(__result))
					{
						__result = text2;
					}
					else
					{
						__result = text2 + "\n" + __result;
					}
					DLog("Added item type '" + itemTypeDef.LocalizationKey + "' to '" + itemPrefabName + "'.");
				}
			}
			catch (Exception arg)
			{
				DLog($"ERROR while adding item type tooltip: {arg}");
			}
		}
	}

	private const string LogPrefix = "[ItemTypeTooltip]";

	private static readonly ItemTypeDef[] Defs = new ItemTypeDef[5]
	{
		new ItemTypeDef("$bow_light_DO", "#63C99A", "BowForestSentinel_DO", "BowFrostpeakHarrier_DO", "BowNocturneArrow_DO", "BowEvoCoreAshlandsLightning_DO"),
		new ItemTypeDef("$bow_medium_DO", "#8cc66b", "BowEvoCoreBlackforest_DO", "BowEvoCoreSwamp_DO", "BowEvoCoreMountain_DO", "BowEvoCorePlains_DO", "BowEvoCoreMistlands_DO", "BowEvoCoreAshlandsNature_DO"),
		new ItemTypeDef("$bow_heavy_DO", "#C5C65D", "BowGoldenStrider_DO", "BowSapphireFalcon_DO", "BowAshenExile_DO", "BowEvoCoreAshlandsBlood_DO"),
		new ItemTypeDef("$crossbow_heavy_DO", "#c6ba5d", "CrossbowEvoCoreAshlandsBlood_DO", "CrossbowEvoCoreBlackforest_DO", "CrossbowEvoCoreMistlands_DO", "CrossbowEvoCoreMountain_DO", "CrossbowEvoCorePlains_DO", "CrossbowEvoCoreSwamp_DO", "CrossbowEvoCoreAshlandsLightning_DO", "CrossbowEvoCoreAshlandsNature_DO", "CrossbowDemonHunter_DO", "CrossbowEvoRenegadeAshlandsFrost_DO", "CrossbowEvoRenegadeAshlandsSpirit_DO", "CrossbowEvoRenegadeBlackforest_DO", "CrossbowEvoRenegadeMistlands_DO", "CrossbowEvoRenegadeMountain_DO", "CrossbowEvoRenegadePlains_DO", "CrossbowEvoRenegadeSwamp_DO"),
		new ItemTypeDef("$offhand_DO", "#78D6C8", "OffhandCrossbowBlackforest_DO", "OffhandCrossbowMountain_DO", "OffhandCrossbowMistlands_DO", "OffhandCrossbowAshlands_DO")
	};

	private static ItemTypeDef FindDef(string prefabName)
	{
		if (string.IsNullOrEmpty(prefabName))
		{
			return null;
		}
		ItemTypeDef[] defs = Defs;
		foreach (ItemTypeDef itemTypeDef in defs)
		{
			if (itemTypeDef != null && itemTypeDef.PrefabNames.Contains(prefabName))
			{
				return itemTypeDef;
			}
		}
		return null;
	}

	private static string Localize(string keyOrText)
	{
		if (string.IsNullOrEmpty(keyOrText))
		{
			return "";
		}
		if (Localization.instance == null)
		{
			return keyOrText;
		}
		if (keyOrText.StartsWith("$"))
		{
			return Localization.instance.Localize(keyOrText);
		}
		return keyOrText;
	}

	private static string GetItemPrefabName(ItemData item)
	{
		if (item == null)
		{
			return "";
		}
		if ((Object)(object)item.m_dropPrefab != (Object)null)
		{
			return Utils.GetPrefabName(((Object)item.m_dropPrefab).name);
		}
		if (item.m_shared != null && !string.IsNullOrEmpty(item.m_shared.m_name))
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(item.m_shared.m_name) : null);
			if ((Object)(object)val != (Object)null)
			{
				return Utils.GetPrefabName(((Object)val).name);
			}
		}
		return "";
	}

	private static void DLog(string message)
	{
	}
}
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
public static class ExtraStats
{
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	private static class DevLog
	{
		public const bool Enabled = false;

		public const bool AttackSpeed = false;

		public const bool WetImmune = false;

		public const bool Tooltips = false;

		public const bool FoodStats = false;
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	public enum ExtraStatType
	{
		Health,
		Stamina,
		Eitr,
		AttackSpeed,
		WetImmune
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	public enum ExtraSourceType
	{
		ItemDrop,
		StatusEffect
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	public class ExtraStatEntry
	{
		public string PrefabName;

		public ExtraStatType StatType;

		public float Value;

		public float? DisplayValue;

		public ExtraSourceType SourceType;

		public ExtraStatEntry(string prefab, ExtraStatType stat, float value, ExtraSourceType source)
		{
			PrefabName = prefab;
			StatType = stat;
			Value = value;
			DisplayValue = null;
			SourceType = source;
		}

		public ExtraStatEntry(string prefab, ExtraStatType stat, float value, float? displayValue, ExtraSourceType source)
		{
			PrefabName = prefab;
			StatType = stat;
			Value = value;
			DisplayValue = displayValue;
			SourceType = source;
		}
	}

	[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	public static class Player_GetTotalFoodValue_ExtraStatsPatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			try
			{
				Inventory inventory = ((Humanoid)__instance).GetInventory();
				if (inventory != null)
				{
					foreach (ItemData equippedItem in inventory.GetEquippedItems())
					{
						if (equippedItem != null && !((Object)(object)equippedItem.m_dropPrefab == (Object)null))
						{
							string name = ((Object)equippedItem.m_dropPrefab).name;
							GetItemDropBonusesForPrefab(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var _);
							if (extraHp != 0f || extraStamina != 0f || extraEitr != 0f)
							{
								num += extraHp;
								num2 += extraStamina;
								num3 += extraEitr;
								DLogFood($"ItemDrop matched for food stats: {name} → +HP {extraHp}, +Stamina {extraStamina}, +Eitr {extraEitr}");
							}
						}
					}
				}
				if (((Character)__instance).m_seman != null && ((Character)__instance).m_seman.m_statusEffects != null)
				{
					foreach (StatusEffect statusEffect in ((Character)__instance).m_seman.m_statusEffects)
					{
						if (!((Object)(object)statusEffect == (Object)null))
						{
							string name2 = ((Object)statusEffect).name;
							GetStatusEffectBonuses(name2, out var extraHp2, out var extraStamina2, out var extraEitr2, out var _, out var _);
							if (extraHp2 != 0f || extraStamina2 != 0f || extraEitr2 != 0f)
							{
								num += extraHp2;
								num2 += extraStamina2;
								num3 += extraEitr2;
								string prefabName = Utils.GetPrefabName(name2);
								DLogFood($"StatusEffect matched for food stats: {name2} (clean={prefabName}) → +HP {extraHp2}, +Stamina {extraStamina2}, +Eitr {extraEitr2}");
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				LogError("Exception in ExtraStats Player.GetTotalFoodValue Postfix: " + ex);
			}
			if (num != 0f || num2 != 0f || num3 != 0f)
			{
				DLogFood($"Total food bonuses applied to player: +HP {num}, +Stamina {num2}, +Eitr {num3}");
				hp += num;
				stamina += num2;
				eitr += num3;
			}
		}
	}

	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[HarmonyPatch]
	public static class ItemData_StaticGetTooltip_ExtraStatsPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(ItemData), "GetTooltip", new Type[6]
			{
				typeof(ItemData),
				typeof(int),
				typeof(bool),
				typeof(float),
				typeof(int),
				typeof(bool)
			}, (Type[])null);
		}

		private static void Postfix(ItemData item, int qualityLevel, bool crafting, float worldLevel, int stackOverride, bool appending, ref string __result)
		{
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
				{
					return;
				}
				string name = ((Object)item.m_dropPrefab).name;
				DLogTooltip("Static GetTooltip Postfix called for " + name + ", " + $"q={qualityLevel}, crafting={crafting}, worldLevel={worldLevel}, " + $"stackOverride={stackOverride}, appending={appending}");
				GetItemDropBonusesForPrefab(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var displayAttackSpeedPercent, out var wetImmune);
				if (extraHp == 0f && extraStamina == 0f && extraEitr == 0f && displayAttackSpeedPercent == 0f && !wetImmune)
				{
					return;
				}
				string text = BuildExtraStatsTooltipBlock(extraHp, extraStamina, extraEitr, displayAttackSpeedPercent, wetImmune);
				if (string.IsNullOrEmpty(text))
				{
					return;
				}
				float num = 0f;
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					num = ((Character)Player.m_localPlayer).GetSkillLevel(item.m_shared.m_skillType);
				}
				string statusEffectTooltip = item.GetStatusEffectTooltip(qualityLevel, num);
				string chainTooltip = item.GetChainTooltip(qualityLevel, num);
				string setStatusEffectTooltip = item.GetSetStatusEffectTooltip(qualityLevel, num);
				int num2 = -1;
				if (!string.IsNullOrEmpty(statusEffectTooltip))
				{
					int num3 = __result.IndexOf(statusEffectTooltip, StringComparison.Ordinal);
					if (num3 >= 0)
					{
						num2 = ((num3 - 2 >= 0 && __result.Substring(num3 - 2, 2) == "\n\n") ? (num3 - 2) : num3);
					}
				}
				if (num2 < 0 && !string.IsNullOrEmpty(chainTooltip))
				{
					int num4 = __result.IndexOf(chainTooltip, StringComparison.Ordinal);
					if (num4 >= 0)
					{
						num2 = ((num4 - 2 >= 0 && __result.Substring(num4 - 2, 2) == "\n\n") ? (num4 - 2) : num4);
					}
				}
				if (num2 < 0)
				{
					int num5 = __result.IndexOf("\n$item_eitrregen_modifier:", StringComparison.Ordinal);
					if (num5 >= 0)
					{
						num2 = num5;
					}
				}
				if (num2 < 0 && !string.IsNullOrEmpty(setStatusEffectTooltip))
				{
					int num6 = __result.IndexOf("\n\n$item_seteffect", StringComparison.Ordinal);
					if (num6 >= 0)
					{
						num2 = num6;
					}
				}
				if (num2 < 0)
				{
					int num7 = __result.IndexOf("\n$item_fulladrenaline:", StringComparison.Ordinal);
					if (num7 >= 0)
					{
						num2 = num7;
					}
				}
				if (num2 >= 0)
				{
					DLogTooltip("Inserting ItemDrop extras before special/effect section for " + name);
					__result = __result.Insert(num2, text);
				}
				else
				{
					DLogTooltip("No special/effect section found, appending ItemDrop extras at end for " + name);
					__result += text;
				}
			}
			catch (Exception ex)
			{
				LogError("Exception in ItemData_StaticGetTooltip_ExtraStatsPatch: " + ex);
			}
		}
	}

	[HarmonyPatch(typeof(SE_Stats), "GetTooltipString")]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	public static class SE_Stats_GetTooltipString_ExtraStatsPatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(SE_Stats __instance, ref string __result)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				string name = ((Object)__instance).name;
				string prefabName = Utils.GetPrefabName(name);
				DLogTooltip("SE GetTooltipString for " + name + " (clean=" + prefabName + ")");
				GetStatusEffectBonuses(name, out var extraHp, out var extraStamina, out var extraEitr, out var _, out var displayAttackSpeedPercent, out var wetImmune);
				if (extraHp == 0f && extraStamina == 0f && extraEitr == 0f && displayAttackSpeedPercent == 0f && !wetImmune)
				{
					return;
				}
				string text = BuildExtraStatsTooltipBlock(extraHp, extraStamina, extraEitr, displayAttackSpeedPercent, wetImmune);
				if (!string.IsNullOrEmpty(text))
				{
					if (text.StartsWith("\n"))
					{
						text = text.Substring(1);
					}
					DLogTooltip($"Appending SE extras for {name} (clean={prefabName}): HP {extraHp}, Stamina {extraStamina}, Eitr {extraEitr}, AttackSpeed(Display)% {displayAttackSpeedPercent}, WetImmune {wetImmune}");
					__result += text;
				}
			}
			catch (Exception ex)
			{
				LogError("Exception in SE_Stats_GetTooltipString_ExtraStatsPatch: " + ex);
			}
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	private sealed class HumanoidState
	{
		public float DesiredSpeed = 1f;

		public float LastAppliedSpeed = 1f;

		public bool HasDesiredSpeed;

		public bool WasInAttack;

		public int ActiveAttackDepth;

		public float ActiveAttackMul = 1f;
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(Humanoid), "StartAttack", new Type[]
	{
		typeof(Character),
		typeof(bool)
	})]
	public static class Humanoid_StartAttack_AttackSpeedPatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		[HarmonyPostfix]
		private static void Postfix(Humanoid __instance, Character target, bool secondaryAttack, ref bool __result)
		{
			EnsureAttackInit();
			if (!__result)
			{
				return;
			}
			HumanoidState attackState = GetAttackState(__instance);
			float num = ComputeTotalAttackSpeedPercentForHumanoid(__instance);
			if (num == 0f)
			{
				attackState.DesiredSpeed = 1f;
				attackState.HasDesiredSpeed = false;
				ApplyAnimSpeed(__instance, attackState, 1f);
				attackState.ActiveAttackDepth = 0;
				attackState.ActiveAttackMul = 1f;
				return;
			}
			float num2 = 1f + num / 100f;
			if (num2 <= 0f || float.IsNaN(num2) || float.IsInfinity(num2))
			{
				attackState.DesiredSpeed = 1f;
				attackState.HasDesiredSpeed = false;
				ApplyAnimSpeed(__instance, attackState, 1f);
				attackState.ActiveAttackDepth = 0;
				attackState.ActiveAttackMul = 1f;
			}
			else
			{
				attackState.DesiredSpeed = num2;
				attackState.HasDesiredSpeed = true;
				ApplyAnimSpeed(__instance, attackState, num2);
				attackState.ActiveAttackDepth++;
				attackState.ActiveAttackMul = num2;
				DLogAttackSpeed($"StartAttack: total AttackSpeed%={num} → mul={num2} (activeDepth={attackState.ActiveAttackDepth})");
			}
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(Attack), "Stop")]
	public static class Attack_Stop_AttackSpeedResetPatch
	{
		[HarmonyPostfix]
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(Attack __instance)
		{
			try
			{
				EnsureAttackInit();
				if (__instance != null)
				{
					Humanoid character = __instance.m_character;
					if (!((Object)(object)character == (Object)null))
					{
						ResetForHumanoid(character);
						DLogAttackSpeed("Attack.Stop: ResetForHumanoid");
					}
				}
			}
			catch (Exception)
			{
			}
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(Humanoid), "UpdateAttack")]
	public static class Humanoid_UpdateAttack_AttackSpeedDtPatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		[HarmonyPrefix]
		private static void Prefix(Humanoid __instance, ref float dt)
		{
			try
			{
				EnsureAttackInit();
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				HumanoidState attackState = GetAttackState(__instance);
				if (attackState.ActiveAttackDepth > 0)
				{
					float activeAttackMul = attackState.ActiveAttackMul;
					if (!(activeAttackMul <= 0f) && !float.IsNaN(activeAttackMul) && !float.IsInfinity(activeAttackMul))
					{
						dt *= activeAttackMul;
					}
				}
			}
			catch (Exception ex)
			{
				LogError("Exception in Humanoid_UpdateAttack_AttackSpeedDtPatch: " + ex);
			}
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(Humanoid), "CustomFixedUpdate")]
	public static class Humanoid_CustomFixedUpdate_AttackSpeedPatch
	{
		[HarmonyPostfix]
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(Humanoid __instance, float fixedDeltaTime)
		{
			EnsureAttackInit();
			HumanoidState attackState = GetAttackState(__instance);
			bool flag = ((Character)__instance).InAttack();
			if (flag)
			{
				if (attackState.HasDesiredSpeed)
				{
					ApplyAnimSpeed(__instance, attackState, attackState.DesiredSpeed);
				}
				else
				{
					ApplyAnimSpeed(__instance, attackState, 1f);
				}
			}
			else if (attackState.WasInAttack)
			{
				ApplyAnimSpeed(__instance, attackState, 1f);
				attackState.HasDesiredSpeed = false;
				attackState.DesiredSpeed = 1f;
			}
			attackState.WasInAttack = flag;
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(Character), "RPC_Stagger")]
	public static class Character_RPC_Stagger_AttackSpeedResetPatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		[HarmonyPostfix]
		private static void Postfix(Character __instance, long sender, Vector3 forceDirection)
		{
			try
			{
				EnsureAttackInit();
				Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null);
				if (!((Object)(object)val == (Object)null))
				{
					ResetForHumanoid(val);
				}
			}
			catch (Exception)
			{
			}
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(Character), "OnDeath")]
	public static class Character_OnDeath_AttackSpeedResetPatch
	{
		[HarmonyPostfix]
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(Character __instance)
		{
			try
			{
				EnsureAttackInit();
				Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null);
				if (!((Object)(object)val == (Object)null))
				{
					ResetForHumanoid(val);
				}
			}
			catch (Exception)
			{
			}
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(Character), "FreezeFrame")]
	public static class Character_FreezeFrame_AttackSpeedScalePatch
	{
		[HarmonyPrefix]
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Prefix(Character __instance, ref float duration)
		{
			try
			{
				EnsureAttackInit();
				if ((Object)(object)__instance == (Object)null || Mathf.Abs(duration - 0.15f) > 0.01f)
				{
					return;
				}
				Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				HumanoidState attackState = GetAttackState(val);
				if (!attackState.HasDesiredSpeed)
				{
					return;
				}
				float desiredSpeed = attackState.DesiredSpeed;
				if (!(desiredSpeed <= 1.001f) && !float.IsNaN(desiredSpeed) && !float.IsInfinity(desiredSpeed))
				{
					float num = duration / desiredSpeed;
					if (num < 0.03f)
					{
						num = 0.03f;
					}
					DLogAttackSpeed($"FreezeFrame scale: {duration:F3} -> {num:F3} (mul={desiredSpeed:F3})");
					duration = num;
				}
			}
			catch (Exception ex)
			{
				LogError("Exception in Character_FreezeFrame_AttackSpeedScalePatch: " + ex);
			}
		}
	}

	[HarmonyPatch(typeof(CharacterAnimEvent), "UpdateFreezeFrame")]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	public static class CharacterAnimEvent_UpdateFreezeFrame_ReapplySpeedPatch
	{
		[HarmonyPostfix]
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static void Postfix(CharacterAnimEvent __instance, float dt)
		{
			try
			{
				EnsureAttackInit();
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				Character componentInParent = ((Component)__instance).GetComponentInParent<Character>();
				Humanoid val = (Humanoid)(object)((componentInParent is Humanoid) ? componentInParent : null);
				if (!((Object)(object)val == (Object)null))
				{
					HumanoidState attackState = GetAttackState(val);
					if (attackState.HasDesiredSpeed && (attackState.ActiveAttackDepth > 0 || ((Character)val).InAttack()))
					{
						ApplyAnimSpeed(val, attackState, attackState.DesiredSpeed);
					}
					else
					{
						ApplyAnimSpeed(val, attackState, 1f);
					}
				}
			}
			catch (Exception ex)
			{
				LogError("Exception in CharacterAnimEvent_UpdateFreezeFrame_ReapplySpeedPatch: " + ex);
			}
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[]
	{
		typeof(int),
		typeof(bool),
		typeof(int),
		typeof(float),
		typeof(short)
	})]
	public static class SEMan_AddStatusEffect_ByHash_WetImmunePatch
	{
		[HarmonyPrefix]
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		private static bool Prefix(SEMan __instance, int nameHash, bool resetTime, int itemLevel, float skillLevel, short variant)
		{
			try
			{
				EnsureWetInit();
				if (nameHash != SEMan.s_statusEffectWet)
				{
					return true;
				}
				Character val = null;
				try
				{
					val = _semanCharacterRef.Invoke(__instance);
				}
				catch (Exception)
				{
					val = null;
				}
				if ((Object)(object)val != (Object)null && HasWetImmune(val))
				{
					DLogWet($"Blocked Wet (AddStatusEffect by hash) due to WetImmune | variant={variant}");
					return false;
				}
			}
			catch (Exception ex2)
			{
				LogError("Exception in SEMan_AddStatusEffect_ByHash_WetImmunePatch: " + ex2);
			}
			return true;
		}
	}

	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
	[HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[]
	{
		typeof(StatusEffect),
		typeof(bool),
		typeof(int),
		typeof(float),
		typeof(short)
	})]
	public static class SEMan_AddStatusEffect_BySE_WetImmunePatch
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
		[HarmonyPrefix]
		private static bool Prefix(SEMan __instance, StatusEffect statusEffect, bool resetTime, int itemLevel, float skillLevel, short variant, ref StatusEffect __result)
		{
			try
			{
				if ((Object)(object)statusEffect == (Object)null)
				{
					return true;
				}
				if (statusEffect.NameHash() != SEMan.s_statusEffectWet)
				{
					return true;
				}
				Character character = statusEffect.m_character;
				if ((Object)(object)character != (Object)null && HasWetImmune(character))
				{
					DLogWet($"Blocked Wet (AddStatusEffect by SE) due to WetImmune | variant={variant}");
					__result = null;
					return false;
				}
			}
			catch (Exception ex)
			{
				LogError("Exception in SEMan_AddStatusEffect_BySE_WetImmunePatch: " + ex);
			}
			return true;
		}
	}

	public static bool DEBUG = false;

	public static readonly List<ExtraStatEntry> ExtraStatsConfig = new List<ExtraStatEntry>
	{
		new ExtraStatEntry("SE_BowHeavyBloodBuff_DO", ExtraStatType.Health, 50f, ExtraSourceType.StatusEffect),
		new ExtraStatEntry("SE_ForestSentinelArmor_DO", ExtraStatType.Stamina, 10f, ExtraSourceType.StatusEffect),
		new ExtraStatEntry("ArmorForestSentinelCape_DO", ExtraStatType.Stamina, 5f, ExtraSourceType.ItemDrop),
		new ExtraStatEntry("ArmorNocturneArrowCape_DO", ExtraStatType.Stamina, 15f, ExtraSourceType.ItemDrop),
		new ExtraStatEntry("ArmorSapphireFalconQuiver_DO", ExtraStatType.Stamina, 15f, ExtraSourceType.ItemDrop),
		new ExtraStatEntry("ArmorDreadRenegadeQuiver_DO", ExtraStatType.Stamina, 15f, ExtraSourceType.ItemDrop)
	};

	private static readonly ConditionalWeakTable<Humanoid, HumanoidState> _attackState = new ConditionalWeakTable<Humanoid, HumanoidState>();

	private static FieldRef<Character, ZSyncAnimation> _zanimRef;

	private static bool _attackInit;

	private const float HitFreeze_Default = 0.15f;

	private const float HitFreeze_Epsilon = 0.01f;

	private const float HitFreeze_Min = 0.03f;

	private static FieldRef<SEMan, Character> _semanCharacterRef;

	private static bool _wetInit;

	private static void LogInfo(string msg)
	{
	}

	private static void LogError(string msg)
	{
	}

	private static void DLogAttackSpeed(string msg)
	{
	}

	private static void DLogWet(string msg)
	{
	}

	private static void DLogTooltip(string msg)
	{
	}

	private static void DLogFood(string msg)
	{
	}

	private static void GetItemDropBonusesForPrefab(string prefabName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out float displayAttackSpeedPercent, out bool wetImmune)
	{
		extraHp = 0f;
		extraStamina = 0f;
		extraEitr = 0f;
		extraAttackSpeedPercent = 0f;
		displayAttackSpeedPercent = 0f;
		wetImmune = false;
		if (string.IsNullOrEmpty(prefabName))
		{
			return;
		}
		for (int i = 0; i < ExtraStatsConfig.Count; i++)
		{
			ExtraStatEntry extraStatEntry = ExtraStatsConfig[i];
			if (extraStatEntry.SourceType == ExtraSourceType.ItemDrop && string.Equals(prefabName, extraStatEntry.PrefabName, StringComparison.OrdinalIgnoreCase))
			{
				switch (extraStatEntry.StatType)
				{
				case ExtraStatType.Health:
					extraHp += extraStatEntry.Value;
					break;
				case ExtraStatType.Stamina:
					extraStamina += extraStatEntry.Value;
					break;
				case ExtraStatType.Eitr:
					extraEitr += extraStatEntry.Value;
					break;
				case ExtraStatType.AttackSpeed:
					extraAttackSpeedPercent += extraStatEntry.Value;
					displayAttackSpeedPercent += (extraStatEntry.DisplayValue.HasValue ? extraStatEntry.DisplayValue.Value : extraStatEntry.Value);
					break;
				case ExtraStatType.WetImmune:
					wetImmune = true;
					break;
				}
			}
		}
	}

	private static void GetItemDropBonusesForPrefab(string prefabName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out bool wetImmune)
	{
		GetItemDropBonusesForPrefab(prefabName, out extraHp, out extraStamina, out extraEitr, out extraAttackSpeedPercent, out var _, out wetImmune);
	}

	private static void GetStatusEffectBonuses(string seRawName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out float displayAttackSpeedPercent, out bool wetImmune)
	{
		extraHp = 0f;
		extraStamina = 0f;
		extraEitr = 0f;
		extraAttackSpeedPercent = 0f;
		displayAttackSpeedPercent = 0f;
		wetImmune = false;
		if (string.IsNullOrEmpty(seRawName))
		{
			return;
		}
		string prefabName = Utils.GetPrefabName(seRawName);
		for (int i = 0; i < ExtraStatsConfig.Count; i++)
		{
			ExtraStatEntry extraStatEntry = ExtraStatsConfig[i];
			if (extraStatEntry.SourceType == ExtraSourceType.StatusEffect && string.Equals(prefabName, extraStatEntry.PrefabName, StringComparison.OrdinalIgnoreCase))
			{
				switch (extraStatEntry.StatType)
				{
				case ExtraStatType.Health:
					extraHp += extraStatEntry.Value;
					break;
				case ExtraStatType.Stamina:
					extraStamina += extraStatEntry.Value;
					break;
				case ExtraStatType.Eitr:
					extraEitr += extraStatEntry.Value;
					break;
				case ExtraStatType.AttackSpeed:
					extraAttackSpeedPercent += extraStatEntry.Value;
					displayAttackSpeedPercent += (extraStatEntry.DisplayValue.HasValue ? extraStatEntry.DisplayValue.Value : extraStatEntry.Value);
					break;
				case ExtraStatType.WetImmune:
					wetImmune = true;
					break;
				}
			}
		}
	}

	private static void GetStatusEffectBonuses(string seRawName, out float extraHp, out float extraStamina, out float extraEitr, out float extraAttackSpeedPercent, out bool wetImmune)
	{
		GetStatusEffectBonuses(seRawName, out extraHp, out extraStamina, out extraEitr, out extraAttackSpeedPercent, out var _, out wetImmune);
	}

	private static string BuildExtraStatsTooltipBlock(float extraHp, float extraStamina, float extraEitr, float displayAttackSpeedPercent, bool wetImmune)
	{
		if (extraHp == 0f && extraStamina == 0f && extraEitr == 0f && displayAttackSpeedPercent == 0f && !wetImmune)
		{
			return string.Empty;
		}
		StringBuilder stringBuilder = new StringBuilder();
		string text = "$health_DO";
		string text2 = "$stamina_DO";
		string text3 = "$eitr_DO";
		string text4 = "$attackspeed_DO";
		string text5 = "$immune_DO";
		string text6 = "$wet_DO";
		if (Localization.instance != null)
		{
			text = Localization.instance.Localize(text);
			text2 = Localization.instance.Localize(text2);
			text3 = Localization.instance.Localize(text3);
			text4 = Localization.instance.Localize(text4);
			text5 = Localization.instance.Localize(text5);
			text6 = Localization.instance.Localize(text6);
		}
		if (extraHp != 0f)
		{
			string arg = ((extraHp >= 0f) ? "+" : "");
			stringBuilder.Append($"\n{text}: <color=#f27979>{arg}{extraHp:F0}</color>");
		}
		if (extraStamina != 0f)
		{
			string arg2 = ((extraStamina >= 0f) ? "+" : "");
			stringBuilder.Append($"\n{text2}: <color=#ffff80>{arg2}{extraStamina:F0}</color>");
		}
		if (extraEitr != 0f)
		{
			string arg3 = ((extraEitr >= 0f) ? "+" : "");
			stringBuilder.Append($"\n{text3}: <color=#8686ee>{arg3}{extraEitr:F0}</color>");
		}
		if (displayAttackSpeedPercent != 0f)
		{
			int num = Mathf.RoundToInt(displayAttackSpeedPercent);
			string arg4 = ((num >= 0) ? "+" : "");
			stringBuilder.Append($"\n{text4}: <color=orange>{arg4}{num}%</color>");
		}
		if (wetImmune)
		{
			stringBuilder.Append("\n" + text5 + ": <color=orange>" + text6 + "</color>");
		}
		return stringBuilder.ToString();
	}

	private static bool HasWetImmune(Character c)
	{
		if ((Object)(object)c == (Object)null)
		{
			return false;
		}
		try
		{
			Player val = (Player)(object)((c is Player) ? c : null);
			if ((Object)(object)val != (Object)null)
			{
				Inventory inventory = ((Humanoid)val).GetInventory();
				if (inventory != null)
				{
					List<ItemData> equippedItems = inventory.GetEquippedItems();
					for (int i = 0; i < equippedItems.Count; i++)
					{
						ItemData val2 = equippedItems[i];
						if (val2 != null && !((Object)(object)val2.m_dropPrefab == (Object)null))
						{
							string name = ((Object)val2.m_dropPrefab).name;
							GetItemDropBonusesForPrefab(name, out var _, out var _, out var _, out var _, out var _, out var wetImmune);
							if (wetImmune)
							{
								DLogWet("WetImmune from ItemDrop: " + name);
								return true;
							}
						}
					}
				}
			}
			if (c.m_seman != null && c.m_seman.m_statusEffects != null)
			{
				List<StatusEffect> statusEffects = c.m_seman.m_statusEffects;
				for (int j = 0; j < statusEffects.Count; j++)
				{
					StatusEffect val3 = statusEffects[j];
					if (!((Object)(object)val3 == (Object)null))
					{
						string name2 = ((Object)val3).name;
						GetStatusEffectBonuses(name2, out var _, out var _, out var _, out var _, out var _, out var wetImmune2);
						if (wetImmune2)
						{
							string prefabName = Utils.GetPrefabName(name2);
							DLogWet("WetImmune from StatusEffect: " + name2 + " (clean=" + prefabName + ")");
							return true;
						}
					}
				}
			}
		}
		catch (Exception ex)
		{
			LogError("Exception in HasWetImmune: " + ex);
		}
		return false;
	}

	private static void EnsureAttackInit()
	{
		if (!_attackInit)
		{
			_attackInit = true;
			_zanimRef = AccessTools.FieldRefAccess<Character, ZSyncAnimation>("m_zanim");
		}
	}

	private static HumanoidState GetAttackState(Humanoid h)
	{
		return _attackState.GetValue(h, (Humanoid _) => new HumanoidState());
	}

	private static void ApplyAnimSpeed(Humanoid h, HumanoidState state, float speed)
	{
		ZSyncAnimation val = null;
		try
		{
			val = _zanimRef.Invoke((Character)(object)h);
		}
		catch (Exception)
		{
			return;
		}
		if (!((Object)(object)val == (Object)null) && !Mathf.Approximately(state.LastAppliedSpeed, speed))
		{
			val.SetSpeed(speed);
			state.LastAppliedSpeed = speed;
		}
	}

	private static void ResetForHumanoid(Humanoid h)
	{
		if (!((Object)(object)h == (Object)null))
		{
			EnsureAttackInit();
			HumanoidState attackState = GetAttackState(h);
			ApplyAnimSpeed(h, attackState, 1f);
			attackState.HasDesiredSpeed = false;
			attackState.DesiredSpeed = 1f;
			attackState.WasInAttack = false;
			attackState.ActiveAttackDepth = 0;
			attackState.ActiveAttackMul = 1f;
		}
	}

	private static float ComputeTotalAttackSpeedPercentForHumanoid(Humanoid h)
	{
		float num = 0f;
		if ((Object)(object)h == (Object)null)
		{
			return 0f;
		}
		try
		{
			Player val = (Player)(object)((h is Player) ? h : null);
			if ((Object)(object)val != (Object)null)
			{
				Inventory inventory = ((Humanoid)val).GetInventory();
				if (inventory != null)
				{
					List<ItemData> equippedItems = inventory.GetEquippedItems();
					for (int i = 0; i < equippedItems.Count; i++)
					{
						ItemData val2 = equippedItems[i];
						if (val2 != null && !((Object)(object)val2.m_dropPrefab == (Object)null))
						{
							string name = ((Object)val2.m_dropPrefab).name;
							GetItemDropBonusesForPrefab(name, out var _, out var _, out var _, out var extraAttackSpeedPercent, out var _, out var _);
							if (extraAttackSpeedPercent != 0f)
							{
								num += extraAttackSpeedPercent;
								DLogAttackSpeed($"AttackSpeed from ItemDrop: {name} → {extraAttackSpeedPercent}%");
							}
						}
					}
				}
			}
			if (((Character)h).m_seman != null && ((Character)h).m_seman.m_statusEffects != null)
			{
				List<StatusEffect> statusEffects = ((Character)h).m_seman.m_statusEffects;
				for (int j = 0; j < statusEffects.Count; j++)
				{
					StatusEffect val3 = statusEffects[j];
					if (!((Object)(object)val3 == (Object)null))
					{
						string name2 = ((Object)val3).name;
						GetStatusEffectBonuses(name2, out var _, out var _, out var _, out var extraAttackSpeedPercent2, out var _, out var _);
						if (extraAttackSpeedPercent2 != 0f)
						{
							num += extraAttackSpeedPercent2;
							string prefabName = Utils.GetPrefabName(name2);
							DLogAttackSpeed($"AttackSpeed from StatusEffect: {name2} (clean={prefabName}) → {extraAttackSpeedPercent2}%");
						}
					}
				}
			}
		}
		catch (Exception ex)
		{
			LogError("Exception in ComputeTotalAttackSpeedPercentForHumanoid: " + ex);
		}
		return num;
	}

	private static void EnsureWetInit()
	{
		if (!_wetInit)
		{
			_wetInit = true;
			_semanCharacterRef = AccessTools.FieldRefAccess<SEMan, Character>("m_character");
		}
	}
}
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
internal static class SAP_Log
{
	private static readonly ManualLogSource _log = Logger.CreateLogSource("SlingshotAmmoPatch");

	public static void Info(string s)
	{
		_log.LogInfo((object)s);
	}

	public static void Err(string s)
	{
		_log.LogError((object)s);
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
internal static class SAP_Util
{
	private static readonly BindingFlags InstAll = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly FieldInfo FI_weapon = typeof(Attack).GetField("m_weapon", InstAll);

	private static readonly FieldInfo FI_character = typeof(Attack).GetField("m_character", InstAll);

	private static readonly FieldInfo FI_ammoItem = typeof(Attack).GetField("m_ammoItem", InstAll);

	private static readonly FieldInfo FI_lastUsedAmmo = typeof(Attack).GetField("m_lastUsedAmmo", InstAll);

	public static ItemData GetWeapon(Attack atk)
	{
		if (atk == null || FI_weapon == null)
		{
			return null;
		}
		try
		{
			object? value = FI_weapon.GetValue(atk);
			return (ItemData)((value is ItemData) ? value : null);
		}
		catch
		{
			return null;
		}
	}

	public static Humanoid GetCharacter(Attack atk)
	{
		if (atk == null || FI_character == null)
		{
			return null;
		}
		try
		{
			object? value = FI_character.GetValue(atk);
			return (Humanoid)((value is Humanoid) ? value : null);
		}
		catch
		{
			return null;
		}
	}

	public static ItemData GetAmmoItem(Attack atk)
	{
		if (atk == null)
		{
			return null;
		}
		ItemData val = null;
		if (FI_ammoItem != null)
		{
			try
			{
				object? value = FI_ammoItem.GetValue(atk);
				val = (ItemData)((value is ItemData) ? value : null);
			}
			catch
			{
			}
		}
		if (val == null && FI_lastUsedAmmo != null)
		{
			try
			{
				object? value2 = FI_lastUsedAmmo.GetValue(atk);
				val = (ItemData)((value2 is ItemData) ? value2 : null);
			}
			catch
			{
			}
		}
		return val;
	}

	public static string GetPrefabName(ItemData item)
	{
		if (item == null)
		{
			return null;
		}
		if ((Object)(object)item.m_dropPrefab != (Object)null)
		{
			return ((Object)item.m_dropPrefab).name;
		}
		try
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance != (Object)null)
			{
				foreach (GameObject item2 in instance.m_items)
				{
					if (Object.op_Implicit((Object)(object)item2) && item2.GetComponent<ItemDrop>()?.m_itemData?.m_shared == item.m_shared)
					{
						return ((Object)item2).name;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}
}
[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
internal static class SAP_Attack_OnAttackTrigger_Patch
{
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	private static void Postfix(Attack __instance)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Invalid comparison between Unknown and I4
		try
		{
			if (__instance == null || (int)__instance.m_attackType != 2)
			{
				return;
			}
			int projectiles = __instance.m_projectiles;
			if (projectiles <= 1)
			{
				return;
			}
			ItemData weapon = SAP_Util.GetWeapon(__instance);
			if (weapon == null || weapon.m_shared == null || string.IsNullOrEmpty(weapon.m_shared.m_ammoType) || !SSU_Whitelist.Match(SAP_Util.GetPrefabName(weapon)))
			{
				return;
			}
			Humanoid character = SAP_Util.GetCharacter(__instance);
			Player val = (Player)(object)((character is Player) ? character : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			ItemData ammoItem = SAP_Util.GetAmmoItem(__instance);
			if (ammoItem == null)
			{
				return;
			}
			int num = projectiles - 1;
			if (num > 0)
			{
				Inventory inventory = ((Humanoid)val).GetInventory();
				if (inventory != null)
				{
					inventory.RemoveItem(ammoItem, num);
				}
			}
		}
		catch (Exception ex)
		{
			SAP_Log.Err("SlingshotAmmoPatch.OnAttackTrigger error: " + ex.GetType().Name + ": " + ex.Message);
		}
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
internal static class SSU_Log
{
	private static readonly ManualLogSource _log = Logger.CreateLogSource("SlingshotSecondaryUnlock");

	public static void Info(string s)
	{
		_log.LogInfo((object)s);
	}

	public static void Err(string s)
	{
		_log.LogError((object)s);
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
internal static class SSU_Whitelist
{
	private static readonly string[] _names;

	internal static readonly HashSet<string> Names;

	internal static readonly HashSet<int> NameHashes;

	static SSU_Whitelist()
	{
		_names = new string[5] { "SlingshotMeadows_DO", "SlingshotBlackforest_DO", "SlingshotSwamp_DO", "SlingshotPlains_DO", "SlingshotAshlands_DO" };
		Names = new HashSet<string>(StringComparer.Ordinal);
		NameHashes = new HashSet<int>();
		string[] names = _names;
		foreach (string text in names)
		{
			Names.Add(text);
			NameHashes.Add(StringExtensionMethods.GetStableHashCode(text));
		}
	}

	public static bool Match(string prefabName)
	{
		if (string.IsNullOrEmpty(prefabName))
		{
			return false;
		}
		if (Names.Contains(prefabName))
		{
			return true;
		}
		return NameHashes.Contains(StringExtensionMethods.GetStableHashCode(prefabName));
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
internal static class SSU_State
{
	private static readonly Dictionary<int, bool> _secondaryDrawActive = new Dictionary<int, bool>();

	private static int Key(Player p)
	{
		if (!Object.op_Implicit((Object)(object)p))
		{
			return 0;
		}
		return ((Object)p).GetInstanceID();
	}

	public static bool IsSecondaryDrawActive(Player p)
	{
		int key = Key(p);
		bool value;
		return _secondaryDrawActive.TryGetValue(key, out value) && value;
	}

	public static void SetSecondaryDrawActive(Player p, bool active)
	{
		int key = Key(p);
		if (active)
		{
			_secondaryDrawActive[key] = true;
		}
		else
		{
			_secondaryDrawActive.Remove(key);
		}
	}
}
[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
internal static class SSU_Util
{
	private static readonly BindingFlags InstAll = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly MethodInfo MI_UpdateWeaponLoading = typeof(Player).GetMethod("UpdateWeaponLoading", InstAll, null, new Type[2]
	{
		typeof(ItemData),
		typeof(float)
	}, null);

	private static readonly MethodInfo MI_UpdateAttackBowDraw = typeof(Player).GetMethod("UpdateAttackBowDraw", InstAll, null, new Type[2]
	{
		typeof(ItemData),
		typeof(float)
	}, null);

	private static readonly MethodInfo MI_InPlaceMode = typeof(Player).GetMethod("InPlaceMode", InstAll, null, Type.EmptyTypes, null);

	public static string GetPrefabName(ItemData item)
	{
		if (item == null)
		{
			return null;
		}
		if ((Object)(object)item.m_dropPrefab != (Object)null)
		{
			return ((Object)item.m_dropPrefab).name;
		}
		try
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance != (Object)null)
			{
				foreach (GameObject item2 in instance.m_items)
				{
					if (Object.op_Implicit((Object)(object)item2) && item2.GetComponent<ItemDrop>()?.m_itemData?.m_shared == item.m_shared)
					{
						return ((Object)item2).name;
					}
				}
			}
		}
		catch
		{
		}
		return null;
	}

	private static FieldInfo FindField(Type t, string name)
	{
		while (t != null)
		{
			FieldInfo field = t.GetField(name, InstAll);
			if (field != null)
			{
				return field;
			}
			t = t.BaseType;
		}
		return null;
	}

	public static T GetField<[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)] T>(object obj, string name)
	{
		if (obj == null)
		{
			return default(T);
		}
		FieldInfo fieldInfo = FindField(obj.GetType(), name);
		if (fieldInfo == null)
		{
			return default(T);
		}
		object value = fieldInfo.GetValue(obj);
		if (value is T)
		{
			return (T)value;
		}
		try
		{
			return (T)Convert.ChangeType(value, typeof(T));
		}
		catch
		{
			return default(T);
		}
	}

	public static void SetField(object obj, string name, object value)
	{
		if (obj != null)
		{
			FieldInfo fieldInfo = FindField(obj.GetType(), name);
			if (!(fieldInfo == null))
			{
				fieldInfo.SetValue(obj, value);
			}
		}
	}

	private static bool CallBoolNoArgs(object obj, MethodInfo mi)
	{
		if (obj == null || mi == null)
		{
			return false;
		}
		try
		{
			object obj2 = mi.Invoke(obj, Array.Empty<object>());
			bool flag = default(bool);
			int num;
			if (obj2 is bool)
			{
				flag = (bool)obj2;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}
		catch
		{
			return false;
		}
	}

	public static bool InPlaceMode(Player p)
	{
		return CallBoolNoArgs(p, MI_InPlaceMode);
	}

	public static void CallUpdateWeaponLoading(Player p, ItemData weapon, float dt)
	{
		if ((Object)(object)p == (Object)null || MI_UpdateWeaponLoading == null)
		{
			return;
		}
		try
		{
			MI_UpdateWeaponLoading.Invoke(p, new object[2] { weapon, dt });
		}
		catch
		{
		}
	}

	public static void CallUpdateAttackBowDraw(Player p, ItemData weapon, float dt)
	{
		if ((Object)(object)p == (Object)null || MI_UpdateAttackBowDraw == null)
		{
			return;
		}
		try
		{
			MI_UpdateAttackBowDraw.Invoke(p, new object[2] { weapon, dt });
		}
		catch
		{
		}
	}

	public static void HandleLoopingAbort(Player p)
	{
		object field = GetField<object>(p, "m_currentAttack");
		if (field == null || !GetField<bool>(field, "m_loopingAttack"))
		{
			return;
		}
		bool field2 = GetField<bool>(p, "m_currentAttackIsSecondary");
		bool field3 = GetField<bool>(p, "m_attackHold");
		bool field4 = GetField<bool>(p, "m_secondaryAttackHold");
		if (field2 ? field4 : field3)
		{
			return;
		}
		MethodInfo method = field.GetType().GetMethod("Abort", InstAll, null, Type.EmptyTypes, null);
		if (method == null)
		{
			return;
		}
		try
		{
			method.Invoke(field, Array.Empty<object>());
		}
		catch
		{
		}
	}

	public static void HandleSlingshotAttackInput(Player p, float dt)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Invalid comparison between Unknown and I4
		if ((Object)(object)p == (Object)null)
		{
			return;
		}
		ItemData currentWeapon = ((Humanoid)p).GetCurrentWeapon();
		if (currentWeapon == null || currentWeapon.m_shared == null || (int)currentWeapon.m_shared.m_itemType != 4 || !currentWeapon.m_shared.m_attack.m_bowDraw || !SSU_Whitelist.Match(GetPrefabName(currentWeapon)) || InPlaceMode(p))
		{
			return;
		}
		CallUpdateWeaponLoading(p, currentWeapon, dt);
		bool field = GetField<bool>(p, "m_secondaryAttackHold");
		bool field2 = GetField<bool>(p, "m_attackHold");
		bool flag = currentWeapon.m_shared.m_secondaryAttack != null;
		bool flag2;
		if (SSU_State.IsSecondaryDrawActive(p))
		{
			flag2 = true;
		}
		else
		{
			flag2 = flag && field && !field2;
			if (flag2)
			{
				SSU_State.SetSecondaryDrawActive(p, active: true);
			}
		}
		if (flag2)
		{
			SharedData shared = currentWeapon.m_shared;
			Attack attack = shared.m_attack;
			Attack secondaryAttack = shared.m_secondaryAttack;
			if (secondaryAttack == null)
			{
				CallUpdateAttackBowDraw(p, currentWeapon, dt);
			}
			else
			{
				bool field3 = GetField<bool>(p, "m_attackHold");
				try
				{
					shared.m_attack = secondaryAttack;
					SetField(p, "m_attackHold", field);
					CallUpdateAttackBowDraw(p, currentWeapon, dt);
				}
				finally
				{
					shared.m_attack = attack;
					SetField(p, "m_attackHold", field3);
				}
				float field4 = GetField<float>(p, "m_attackDrawTime");
				if (!field && field4 <= 0f)
				{
					SSU_State.SetSecondaryDrawActive(p, active: false);
				}
			}
		}
		else
		{
			CallUpdateAttackBowDraw(p, currentWeapon, dt);
		}
		HandleLoopingAbort(p);
	}
}
[HarmonyPatch(typeof(Player), "PlayerAttackInput")]
internal static class SSU_PlayerAttackInput_Patch
{
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	private static bool Prefix(Player __instance, float dt)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Invalid comparison between Unknown and I4
		try
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon();
			if (currentWeapon == null || currentWeapon.m_shared == null)
			{
				return true;
			}
			if ((int)currentWeapon.m_shared.m_itemType != 4)
			{
				return true;
			}
			if (!SSU_Whitelist.Match(SSU_Util.GetPrefabName(currentWeapon)))
			{
				return true;
			}
			SSU_Util.HandleSlingshotAttackInput(__instance, dt);
			return false;
		}
		catch (Exception ex)
		{
			SSU_Log.Err("SlingshotSecondaryUnlock.PlayerAttackInput error: " + ex.GetType().Name + ": " + ex.Message);
			return true;
		}
	}
}
namespace PieceManager
{
	[PublicAPI]
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	public static class MaterialReplacer
	{
		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
		public enum ShaderType
		{
			PieceShader,
			VegetationShader,
			RockShader,
			RugShader,
			GrassShader,
			CustomCreature,
			UseUnityShader
		}

		private static readonly Dictionary<GameObject, bool> ObjectToSwap;

		private static readonly Dictionary<string, Material> OriginalMaterials;

		private static readonly Dictionary<GameObject, ShaderType> ObjectsForShaderReplace;

		private static readonly HashSet<Shader> CachedShaders;

		private static bool hasRun;

		static MaterialReplacer()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			CachedShaders = new HashSet<Shader>();
			hasRun = false;
			OriginalMaterials = new Dictionary<string, Material>();
			ObjectToSwap = new Dictionary<GameObject, bool>();
			ObjectsForShaderReplace = new Dictionary<GameObject, ShaderType>();
			new Harmony("org.bepinex.helpers.PieceManager").Patch((MethodBase)AccessTools.DeclaredMethod(typeof(ZoneSystem), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(MaterialReplacer), "ReplaceAllMaterialsWithOriginal", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static void RegisterGameObjectForShaderSwap(GameObject go, ShaderType type)
		{
			if (!ObjectsForShaderReplace.ContainsKey(go))
			{
				ObjectsForShaderReplace.Add(go, type);
			}
		}

		public static void RegisterGameObjectForMatSwap(GameObject go, bool isJotunnMock = false)
		{
			if (!ObjectToSwap.ContainsKey(go))
			{
				ObjectToSwap.Add(go, isJotunnMock);
			}
		}

		private static void GetAllMaterials()
		{
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			foreach (Material val in array)
			{
				OriginalMaterials[((Object)val).name] = val;
			}
		}

		[HarmonyPriority(700)]
		private static void ReplaceAllMaterialsWithOriginal()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)SystemInfo.graphicsDeviceType == 4 || hasRun)
			{
				return;
			}
			if (OriginalMaterials.Count == 0)
			{
				GetAllMaterials();
			}
			foreach (KeyValuePair<GameObject, bool> item in ObjectToSwap)
			{
				GameObject key = item.Key;
				bool value = item.Value;
				ProcessGameObjectMaterials(key, value);
			}
			AssetBundle[] array = Resources.FindObjectsOfTypeAll<AssetBundle>();
			foreach (AssetBundle val in array)
			{
				IEnumerable<Shader> enumerable3;
				try
				{
					IEnumerable<Shader> enumerable2;
					if (!val.isStreamedSceneAssetBundle || !Object.op_Implicit((Object)(object)val))
					{
						IEnumerable<Shader> enumerable = val.LoadAllAssets<Shader>();
						enumerable2 = enumerable;
					}
					else
					{
						enumerable2 = from shader in ((IEnumerable<string>)val.GetAllAssetNames()).Select((Func<string, Shader>)val.LoadAsset<Shader>)
							where (Object)(object)shader != (Object)null
							select shader;
					}
					enumerable3 = enumerable2;
				}
				catch (Exception)
				{
					continue;
				}
				if (enumerable3 == null)
				{
					continue;
				}
				foreach (Shader item2 in enumerable3)
				{
					CachedShaders.Add(item2);
				}
			}
			foreach (KeyValuePair<GameObject, ShaderType> item3 in ObjectsForShaderReplace)
			{
				GameObject key2 = item3.Key;
				ShaderType value2 = item3.Value;
				ProcessGameObjectShaders(key2, value2);
			}
			hasRun = true;
		}

		private static void ProcessGameObjectMaterials(GameObject go, bool isJotunnMock)
		{
			Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer obj in componentsInChildren)
			{
				Material[] sharedMaterials = obj.sharedMaterials.Select([<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (Material material) => ReplaceMaterial(material, isJotunnMock)).ToArray();
				obj.sharedMaterials = sharedMaterials;
			}
		}

		private static Material ReplaceMaterial(Material originalMaterial, bool isJotunnMock)
		{
			string text = (isJotunnMock ? "JVLmock_" : "_REPLACE_");
			if (!((Object)originalMaterial).name.StartsWith(text, StringComparison.Ordinal))
			{
				return originalMaterial;
			}
			string text2 = ((Object)originalMaterial).name.Replace(" (Instance)", "").Replace(text, "");
			if (OriginalMaterials.TryGetValue(text2, out var value))
			{
				return value;
			}
			Debug.LogWarning((object)("No suitable material found to replace: " + text2));
			return originalMaterial;
		}

		private static void ProcessGameObjectShaders(GameObject go, ShaderType shaderType)
		{
			Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
				foreach (Material val in sharedMaterials)
				{
					if ((Object)(object)val != (Object)null)
					{
						val.shader = GetShaderForType(val.shader, shaderType, ((Object)val.shader).name);
					}
				}
			}
		}

		private static Shader GetShaderForType(Shader orig, ShaderType shaderType, string originalShaderName)
		{
			return (Shader)(shaderType switch
			{
				ShaderType.PieceShader => FindShaderWithName(orig, "Custom/Piece"), 
				ShaderType.VegetationShader => FindShaderWithName(orig, "Custom/Vegetation"), 
				ShaderType.RockShader => FindShaderWithName(orig, "Custom/StaticRock"), 
				ShaderType.RugShader => FindShaderWithName(orig, "Custom/Rug"), 
				ShaderType.GrassShader => FindShaderWithName(orig, "Custom/Grass"), 
				ShaderType.CustomCreature => FindShaderWithName(orig, "Custom/Creature"), 
				ShaderType.UseUnityShader => FindShaderWithName(orig, ((Object)(object)FindShaderWithName(orig, originalShaderName) != (Object)null) ? originalShaderName : "ToonDeferredShading2017"), 
				_ => FindShaderWithName(orig, "Standard"), 
			});
		}

		public static Shader FindShaderWithName(Shader origShader, string name)
		{
			foreach (Shader cachedShader in CachedShaders)
			{
				if (((Object)cachedShader).name == name)
				{
					return cachedShader;
				}
			}
			return origShader;
		}
	}
	[PublicAPI]
	public enum CraftingTable
	{
		None,
		[InternalName("piece_workbench")]
		Workbench,
		[InternalName("piece_cauldron")]
		Cauldron,
		[InternalName("forge")]
		Forge,
		[InternalName("piece_artisanstation")]
		ArtisanTable,
		[InternalName("piece_stonecutter")]
		StoneCutter,
		[InternalName("piece_magetable")]
		MageTable,
		[InternalName("blackforge")]
		BlackForge,
		[InternalName("piece_preptable")]
		FoodPreparationTable,
		[InternalName("piece_MeadCauldron")]
		MeadKetill,
		Custom
	}
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	public class InternalName : Attribute
	{
		public readonly string internalName;

		public InternalName(string internalName)
		{
			this.internalName = internalName;
		}
	}
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[PublicAPI]
	public class ExtensionList
	{
		public readonly List<ExtensionConfig> ExtensionStations = new List<ExtensionConfig>();

		public void Set(CraftingTable table, int maxStationDistance = 5)
		{
			ExtensionStations.Add(new ExtensionConfig
			{
				Table = table,
				maxStationDistance = maxStationDistance
			});
		}

		public void Set(string customTable, int maxStationDistance = 5)
		{
			ExtensionStations.Add(new ExtensionConfig
			{
				Table = CraftingTable.Custom,
				custom = customTable,
				maxStationDistance = maxStationDistance
			});
		}
	}
	public struct ExtensionConfig
	{
		public CraftingTable Table;

		public float maxStationDistance;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		public string custom;
	}
	[PublicAPI]
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	public class CraftingStationList
	{
		public readonly List<CraftingStationConfig> Stations = new List<CraftingStationConfig>();

		public void Set(CraftingTable table)
		{
			Stations.Add(new CraftingStationConfig
			{
				Table = table
			});
		}

		public void Set(string customTable)
		{
			Stations.Add(new CraftingStationConfig
			{
				Table = CraftingTable.Custom,
				custom = customTable
			});
		}
	}
	public struct CraftingStationConfig
	{
		public CraftingTable Table;

		public int level;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		public string custom;
	}
	[PublicAPI]
	public enum BuildPieceCategory
	{
		Misc = 0,
		Crafting = 1,
		BuildingWorkbench = 2,
		BuildingStonecutter = 3,
		Furniture = 4,
		DeepNorth = 5,
		Feasts = 6,
		Food = 7,
		Meads = 8,
		All = 100,
		Custom = 99
	}
	[PublicAPI]
	public class PieceUsage
	{
		public UsageTagFlags Tags;

		public void Add(UsageTagFlags tag)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Tags |= tag;
		}

		public void Set(UsageTagFlags tags)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Tags = tags;
		}
	}
	[PublicAPI]
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	public class RequiredResourcesList
	{
		public readonly List<Requirement> Requirements = new List<Requirement>();

		public void Add(string item, int amount, bool recover)
		{
			Requirements.Add(new Requirement
			{
				itemName = item,
				amount = amount,
				recover = recover
			});
		}
	}
	public struct Requirement
	{
		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(1)]
		public string itemName;

		public int amount;

		public bool recover;
	}
	public struct SpecialProperties
	{
		[Description("Admins should be the only ones that can build this piece.")]
		public bool AdminOnly;

		[Description("Turns off generating a config for this build piece.")]
		public bool NoConfig;
	}
	[PublicAPI]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	public class BuildingPieceCategory
	{
		public BuildPieceCategory Category;

		public string custom = "";

		public void Set(BuildPieceCategory category)
		{
			Category = category;
		}

		public void Set(string customCategory)
		{
			Category = BuildPieceCategory.Custom;
			custom = customCategory;
		}
	}
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[PublicAPI]
	public class PieceTool
	{
		public readonly HashSet<string> Tools = new HashSet<string>();

		public void Add(string tool)
		{
			Tools.Add(tool);
		}
	}
	[PublicAPI]
	[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
	[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(1)]
	public class BuildPiece
	{
		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
		internal class PieceConfig
		{
			public ConfigEntry<string> craft;

			public ConfigEntry<BuildPieceCategory> category;

			public ConfigEntry<string> customCategory;

			public ConfigEntry<UsageTagFlags> usage;

			public ConfigEntry<string> tools;

			public ConfigEntry<CraftingTable> extensionTable;

			public ConfigEntry<string> customExtentionTable;

			public ConfigEntry<float> maxStationDistance;

			public ConfigEntry<CraftingTable> table;

			public ConfigEntry<string> customTable;
		}

		[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)]
		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
			[UsedImplicitly]
			public string Category;

			[UsedImplicitly]
			[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(new byte[] { 2, 1 })]
			public Action<ConfigEntryBase> CustomDrawer;
		}

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(0)]
		private class SerializedRequirements
		{
			public readonly List<Requirement> Reqs;

			public SerializedRequirements(List<Requirement> reqs)
			{
				Reqs = reqs;
			}

			public SerializedRequirements(string reqs)
			{
				Reqs = reqs.Split(new char[1] { ',' }).Select([<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (string r) =>
				{
					string[] array = r.Split(new char[1] { ':' });
					int result;
					bool result2 = default(bool);
					return new Requirement
					{
						itemName = array[0],
						amount = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result),
						recover = (array.Length <= 2 || !bool.TryParse(array[2], out result2) || result2)
					};
				}).ToList();
			}

			public override string ToString()
			{
				return string.Join(",", Reqs.Select([<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (Requirement r) => $"{r.itemName}:{r.amount}:{r.recover}"));
			}

			[return: <e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
			public static ItemDrop fetchByName(ObjectDB objectDB, string name)
			{
				GameObject itemPrefab = objectDB.GetItemPrefab(name);
				ItemDrop obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)obj == (Object)null)
				{
					Debug.LogWarning((object)(((!string.IsNullOrWhiteSpace(((Object)plugin).name)) ? ("[" + ((Object)plugin).name + "]") : "") + " The required item '" + name + "' does not exist."));
				}
				return obj;
			}

			public static Requirement[] toPieceReqs(SerializedRequirements craft)
			{
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e7: Expected O, but got Unknown
				Dictionary<string, Requirement> dictionary = new Dictionary<string, Requirement>();
				foreach (Requirement item in craft.Reqs.Where((Requirement r) => r.itemName != ""))
				{
					var (text, num) = RequirementResolver?.Invoke(item.itemName, item.amount) ?? (item.itemName, item.amount);
					if (dictionary.TryGetValue(text, out var value))
					{
						Requirement obj = value;
						obj.m_amount += num;
						Requirement obj2 = value;
						obj2.m_recover &= item.recover;
						continue;
					}
					ItemDrop val = fetchByName(ObjectDB.instance, text);
					if (val != null)
					{
						dictionary[text] = new Requirement
						{
							m_amount = num,
							m_resItem = val,
							m_recover = item.recover
						};
					}
				}
				return dictionary.Values.ToArray();
			}
		}

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(new byte[] { 2, 1, 0, 1 })]
		public static Func<string, int, (string itemName, int amount)> RequirementResolver;

		internal static readonly List<BuildPiece> registeredPieces = new List<BuildPiece>();

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(new byte[] { 1, 0, 1 })]
		private static readonly Queue<(GameObject prefab, float lightIntensity, Quaternion? camRot)> _snapshotQueue = new Queue<(GameObject, float, Quaternion?)>();

		private static readonly Dictionary<Piece, BuildPiece> pieceMap = new Dictionary<Piece, BuildPiece>();

		internal static Dictionary<BuildPiece, PieceConfig> pieceConfigs = new Dictionary<BuildPiece, PieceConfig>();

		internal List<Conversion> Conversions = new List<Conversion>();

		internal List<ItemConversion> conversions = new List<ItemConversion>();

		[Description("Disables generation of the configs for your pieces. This is global, this turns it off for all pieces in your mod.")]
		public static bool ConfigurationEnabled = true;

		public readonly GameObject Prefab;

		[Description("Specifies the resources needed to craft the piece.\nUse .Add to add resources with their internal ID and an amount.\nUse one .Add for each resource type the building piece should need.")]
		public readonly RequiredResourcesList RequiredItems = new RequiredResourcesList();

		[Description("Sets the category for the building piece.")]
		public readonly BuildingPieceCategory Category = new BuildingPieceCategory();

		[Description("Sets which tags the piece is listed under in the build menu.\nLeave it empty and one gets picked from the category.")]
		public readonly PieceUsage Usage = new PieceUsage();

		[Description("Specifies the tool needed to build your piece.\nUse .Add to add a tool.")]
		public readonly PieceTool Tool = new PieceTool();

		[Description("Specifies the crafting station needed to build your piece.\nUse .Add to add a crafting station, using the CraftingTable enum and a minimum level for the crafting station.")]
		public CraftingStationList Crafting = new CraftingStationList();

		[Description("Makes this piece a station extension")]
		public ExtensionList Extension = new ExtensionList();

		[Description("Change the extended/special properties of your build piece.")]
		public SpecialProperties SpecialProperties;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		[Description("Specifies a config entry which toggles whether a recipe is active.")]
		public ConfigEntryBase RecipeIsActive;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		private LocalizeKey _name;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		private LocalizeKey _description;

		internal string[] activeTools;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		private static object configManager;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		private static Localization _english;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		internal static BaseUnityPlugin _plugin = null;

		private static bool hasConfigSync = true;

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		private static object _configSync;

		public LocalizeKey Name
		{
			get
			{
				LocalizeKey name = _name;
				if (name != null)
				{
					return name;
				}
				Piece component = Prefab.GetComponent<Piece>();
				if (component.m_name.StartsWith("$"))
				{
					_name = new LocalizeKey(component.m_name);
				}
				else
				{
					string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_");
					_name = new LocalizeKey(text).English(component.m_name);
					component.m_name = text;
				}
				return _name;
			}
		}

		public LocalizeKey Description
		{
			get
			{
				LocalizeKey description = _description;
				if (description != null)
				{
					return description;
				}
				Piece component = Prefab.GetComponent<Piece>();
				if (component.m_description.StartsWith("$"))
				{
					_description = new LocalizeKey(component.m_description);
				}
				else
				{
					string text = "$piece_" + ((Object)Prefab).name.Replace(" ", "_") + "_description";
					_description = new LocalizeKey(text).English(component.m_description);
					component.m_description = text;
				}
				return _description;
			}
		}

		private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English"));

		internal static BaseUnityPlugin plugin
		{
			get
			{
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Expected O, but got Unknown
				if (_plugin != null)
				{
					return _plugin;
				}
				IEnumerable<TypeInfo> source;
				try
				{
					source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
				}
				catch (ReflectionTypeLoadException ex)
				{
					source = from t in ex.Types
						where t != null
						select t.GetTypeInfo();
				}
				_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				return _plugin;
			}
		}

		[<e209b2dd-032d-4991-9c16-f6cc011fed23>Nullable(2)]
		private static object configSync
		{
			[<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(2)]
			get
			{
				if (_configSync != null || !hasConfigSync)
				{
					return _configSync;
				}
				Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync");
				if ((object)type != null)
				{
					_configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " PieceManager");
					type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString());
					type.GetProperty("IsLocked").SetValue(_configSync, true);
				}
				else
				{
					hasConfigSync = false;
				}
				return _configSync;
			}
		}

		public BuildPiece(string assetBundleFileName, string prefabName, string folderName = "assets")
			: this(PiecePrefabManager.RegisterAssetBundle(assetBundleFileName, folderName), prefabName)
		{
		}

		public BuildPiece(AssetBundle bundle, string prefabName)
		{
			Prefab = PiecePrefabManager.RegisterPrefab(bundle, prefabName);
			registeredPieces.Add(this);
		}

		internal static void Patch_FejdStartup(FejdStartup __instance)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Expected O, but got Unknown
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Expected O, but got Unknown
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_041f: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_0492: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: Unknown result type (might be due to invalid IL or missing references)
			//IL_049e: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fd: Expected O, but got Unknown
			//IL_0515: Unknown result type (might be due to invalid IL or missing references)
			//IL_051c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0521: Unknown result type (might be due to invalid IL or missing references)
			//IL_0522: Unknown result type (might be due to invalid IL or missing references)
			//IL_0595: Unknown result type (might be due to invalid IL or missing references)
			//IL_059f: Expected O, but got Unknown
			//IL_06f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fd: Expected O, but got Unknown
			//IL_09b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_09c0: Expected O, but got Unknown
			//IL_0763: Unknown result type (might be due to invalid IL or missing references)
			//IL_076d: Expected O, but got Unknown
			//IL_0804: Unknown result type (might be due to invalid IL or missing references)
			//IL_080e: Expected O, but got Unknown
			//IL_0a26: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a30: Expected O, but got Unknown
			//IL_0c2e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c38: Expected O, but got Unknown
			//IL_0cc7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cd1: Expected O, but got Unknown
			Type configManagerType = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault([<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (Assembly a) => a.GetName().Name == "ConfigurationManager")?.GetType("ConfigurationManager.ConfigurationManager");
			configManager = ((configManagerType == null) ? null : Chainloader.ManagerObject.GetComponent(configManagerType));
			foreach (BuildPiece registeredPiece in registeredPieces)
			{
				registeredPiece.activeTools = registeredPiece.Tool.Tools.DefaultIfEmpty("Hammer").ToArray();
				Piece component = registeredPiece.Prefab.GetComponent<Piece>();
				if (registeredPiece.Category.Category != BuildPieceCategory.Custom)
				{
					component.m_category = (PieceCategory)registeredPiece.Category.Category;
				}
				else
				{
					component.m_category = PiecePrefabManager.GetCategory(registeredPiece.Category.custom);
				}
				if ((int)registeredPiece.Usage.Tags != 0)
				{
					component.m_usage = registeredPiece.Usage.Tags;
				}
				else if ((int)component.m_usage == 0)
				{
					component.m_usage = DefaultUsageFor(component.m_category);
				}
				if (registeredPiece.Category.Category == BuildPieceCategory.Custom)
				{
					component.m_usage |= PiecePrefabManager.GetCustomTag(registeredPiece.Category.custom);
				}
			}
			if (!ConfigurationEnabled)
			{
				return;
			}
			bool saveOnConfigSet = plugin.Config.SaveOnConfigSet;
			plugin.Config.SaveOnConfigSet = false;
			foreach (BuildPiece registeredPiece2 in registeredPieces)
			{
				BuildPiece piece = registeredPiece2;
				if (piece.SpecialProperties.NoConfig)
				{
					continue;
				}
				PieceConfig pieceConfig = (pieceConfigs[piece] = new PieceConfig());
				PieceConfig cfg = pieceConfig;
				Piece piecePrefab = piece.Prefab.GetComponent<Piece>();
				string pieceName = piecePrefab.m_name;
				string englishName = new Regex("[=\\n\\t\\\\\"\\'\\[\\]]*").Replace(english.Localize(pieceName), "").Trim();
				string localizedName = Localization.instance.Localize(pieceName).Trim();
				int order = 0;
				cfg.category = config(englishName, "Build Table Category", piece.Category.Category, new ConfigDescription("Build Category where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = (order -= 1),
						Category = localizedName
					}
				}));
				ConfigurationManagerAttributes customTableAttributes = new ConfigurationManagerAttributes
				{
					Order = (order -= 1),
					Browsable = (cfg.category.Value == BuildPieceCategory.Custom),
					Category = localizedName
				};
				cfg.customCategory = config(englishName, "Custom Build Category", piece.Category.custom, new ConfigDescription("", (AcceptableValueBase)null, new object[1] { customTableAttributes }));
				cfg.category.SettingChanged += BuildTableConfigChanged;
				cfg.customCategory.SettingChanged += BuildTableConfigChanged;
				if (cfg.category.Value == BuildPieceCategory.Custom)
				{
					piecePrefab.m_category = PiecePrefabManager.GetCategory(cfg.customCategory.Value);
				}
				else
				{
					piecePrefab.m_category = (PieceCategory)cfg.category.Value;
				}
				UsageTagFlags customTag = (UsageTagFlags)((cfg.category.Value == BuildPieceCategory.Custom) ? ((int)PiecePrefabManager.GetCustomTag(cfg.customCategory.Value)) : 0);
				cfg.usage = config<UsageTagFlags>(englishName, "Build Menu Tags", (UsageTagFlags)(piecePrefab.m_usage & ~customTag), new ConfigDescription("Tags " + localizedName + " is listed under in the build menu.", (AcceptableValueBase)null, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Order = (order -= 1),
						Category = localizedName
					}
				}));
				piecePrefab.m_usage = (UsageTagFlags)(cfg.usage.Value | customTag);
				cfg.usage.SettingChanged += [<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (object _, EventArgs _) =>
				{
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					//IL_0017: Unknown result type (might be due to invalid IL or missing references)
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_001d: Unknown result type (might be due to invalid IL or missing references)
					piecePrefab.m_usage = (UsageTagFlags)(cfg.usage.Value | customTag);
					PiecePrefabManager.RefreshBuildMenu();
				};
				cfg.tools = config(englishName, "Tools", string.Join(", ", piece.activeTools), new ConfigDescription("Comma separated list of tools where " + localizedName + " is available.", (AcceptableValueBase)null, new object[1] { customTableAttributes }));
				piece.activeTools = (from s in cfg.tools.Value.Split(new char[1] { ',' })
					select s.Trim()).ToArray();
				cfg.tools.SettingChanged += [<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (object _, EventArgs _) =>
				{
					Inventory[] source = (from c in Player.s_players.Select([<63ec5df3-c960-443a-a231-8ba5d7dce348>NullableContext(0)] (Player p) => ((Humanoid)p).GetInventory()).Concat(from c in Object.FindObjectsByType<Container>((FindObjectsSortMode)0)
							select c.GetInventory())
						where c != null
						select c).ToArray();
					Dictionary<string, List<PieceTable>> dictionary = (from kv in (from i in (from p in ObjectDB.instance.m_items
								select p.GetComponent<ItemDrop>() into c
								where Object.op_Implicit((Object)(object)c) && Object.op_Implicit((Object)(object)((Component)c).GetComponent<ZNet