Decompiled source of FletchersForge v0.1.30

FletchersForge.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("FletchersForge")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Disassemble arrows into shafts and heads; reforge in the field with the Fletcher's knife.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("FletchersForge")]
[assembly: AssemblyTitle("FletchersForge")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FletchersForge
{
	internal static class ArrowAssemblyRegistry
	{
		internal sealed class ArrowPair
		{
			public string ShaftPrefab;

			public string HeadPrefab;

			public string ArrowPrefab;
		}

		private static readonly Dictionary<string, ArrowPair> ArrowToParts = new Dictionary<string, ArrowPair>();

		private static readonly Dictionary<string, string> ShaftHeadToArrow = new Dictionary<string, string>();

		internal static void Initialize()
		{
			Register("ArrowWood", "FF_ShaftStandard", null, "ArrowWood");
			Register("ArrowFire", "FF_ShaftStandard", "FF_HeadFire", "ArrowFire");
			Register("ArrowFlint", "FF_ShaftStandard", "FF_HeadFlint", "ArrowFlint");
			Register("ArrowBronze", "FF_ShaftStandard", "FF_HeadBronze", "ArrowBronze");
			Register("ArrowIron", "FF_ShaftStandard", "FF_HeadIron", "ArrowIron");
			Register("ArrowSilver", "FF_ShaftStandard", "FF_HeadSilver", "ArrowSilver");
			Register("ArrowObsidian", "FF_ShaftStandard", "FF_HeadObsidian", "ArrowObsidian");
			Register("ArrowPoison", "FF_ShaftStandard", "FF_HeadPoison", "ArrowPoison");
			Register("ArrowFrost", "FF_ShaftStandard", "FF_HeadFrost", "ArrowFrost");
			Register("ArrowNeedle", "FF_ShaftNeedle", "FF_HeadNeedle", "ArrowNeedle");
			Register("ArrowCarapace", "FF_ShaftStandard", "FF_HeadCarapace", "ArrowCarapace");
			Register("ArrowCharred", "FF_ShaftAsh", "FF_HeadCharred", "ArrowCharred");
		}

		private static void Register(string arrow, string shaft, string head, string arrowPrefab)
		{
			ArrowToParts[arrow] = new ArrowPair
			{
				ShaftPrefab = shaft,
				HeadPrefab = head,
				ArrowPrefab = arrowPrefab
			};
			ShaftHeadToArrow[Key(shaft, head)] = arrowPrefab;
		}

		internal static bool TryGetParts(string arrowPrefabName, out string shaftPrefab, out string headPrefab)
		{
			shaftPrefab = null;
			headPrefab = null;
			if (!ArrowToParts.TryGetValue(arrowPrefabName, out var value))
			{
				return false;
			}
			shaftPrefab = value.ShaftPrefab;
			headPrefab = value.HeadPrefab;
			return true;
		}

		internal static bool TryGetArrow(string shaftPrefab, string headPrefab, out string arrowPrefab)
		{
			if (ShaftHeadToArrow.TryGetValue(Key(shaftPrefab, headPrefab), out arrowPrefab))
			{
				return true;
			}
			arrowPrefab = null;
			return false;
		}

		internal static bool IsArrowPrefab(string prefabName)
		{
			return ArrowToParts.ContainsKey(prefabName);
		}

		internal static bool IsShaftPrefab(string prefabName)
		{
			if (!(prefabName == "FF_ShaftStandard") && !(prefabName == "FF_ShaftNeedle"))
			{
				return prefabName == "FF_ShaftAsh";
			}
			return true;
		}

		internal static bool IsHeadPrefab(string prefabName)
		{
			return prefabName.StartsWith("FF_Head", StringComparison.Ordinal);
		}

		internal static bool IsKnifePrefab(string prefabName)
		{
			return prefabName == "FF_FletchersKnife";
		}

		private static string Key(string shaft, string head)
		{
			return shaft + "|" + (head ?? string.Empty);
		}
	}
	internal static class ChestSnapHarmony
	{
		internal static void Apply(Harmony harmony)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("ChestSnap.Helpers.SnappointHelper");
			if (type == null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"ChestSnap compat: SnappointHelper type not found.");
				}
				return;
			}
			int num = 0;
			MethodInfo methodInfo = AccessTools.Method(type, "RecreateSnappoints", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ChestSnapCompatPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
				ManualLogSource log2 = FletchersForgePlugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"ChestSnap compat: patched RecreateSnappoints.");
				}
			}
			MethodInfo methodInfo2 = AccessTools.Method(type, "RecreateSnappointsRoutine", (Type[])null, (Type[])null);
			if (methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ChestSnapCompatPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
				ManualLogSource log3 = FletchersForgePlugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)"ChestSnap compat: patched RecreateSnappointsRoutine.");
				}
			}
			Type type2 = type.GetNestedTypes(BindingFlags.NonPublic).FirstOrDefault((Type t) => t.Name == "<>c");
			if (type2 != null)
			{
				MethodInfo methodInfo3 = type2.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "<RecreateSnappointsRoutine>b__2_9");
				if (methodInfo3 != null)
				{
					harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(ChestSnapNullViewPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
					ManualLogSource log4 = FletchersForgePlugin.Log;
					if (log4 != null)
					{
						log4.LogInfo((object)"ChestSnap compat: patched null-view lambda.");
					}
				}
				MethodInfo methodInfo4 = type2.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "<RecreateSnappointsRoutine>b__2_8");
				if (methodInfo4 != null)
				{
					harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(ChestSnapNullArrayPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
					ManualLogSource log5 = FletchersForgePlugin.Log;
					if (log5 != null)
					{
						log5.LogInfo((object)"ChestSnap compat: patched GameObject[] lambda.");
					}
				}
			}
			Type type3 = type.GetNestedTypes(BindingFlags.NonPublic).FirstOrDefault((Type t) => t.Name.StartsWith("<RecreateSnappointsRoutine>d", StringComparison.Ordinal));
			if (type3 != null)
			{
				MethodInfo methodInfo5 = AccessTools.Method(type3, "MoveNext", (Type[])null, (Type[])null);
				if (methodInfo5 != null)
				{
					harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ChestSnapMoveNextFinalizerPatch), "Finalizer", (Type[])null), (HarmonyMethod)null);
					num++;
					ManualLogSource log6 = FletchersForgePlugin.Log;
					if (log6 != null)
					{
						log6.LogInfo((object)"ChestSnap compat: patched MoveNext finalizer.");
					}
				}
			}
			ManualLogSource log7 = FletchersForgePlugin.Log;
			if (log7 != null)
			{
				log7.LogInfo((object)$"ChestSnap compat: {num} patch(es) applied.");
			}
		}
	}
	internal static class ComponentDropVisualUtility
	{
		private static GameObject GetBoxPrefab()
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab("CargoCrate");
			if ((Object)(object)prefab != (Object)null)
			{
				return prefab;
			}
			string[] headDropBoxPrefabFallbacks = ModConstants.HeadDropBoxPrefabFallbacks;
			foreach (string text in headDropBoxPrefabFallbacks)
			{
				prefab = PrefabManager.Instance.GetPrefab(text);
				if ((Object)(object)prefab != (Object)null)
				{
					return prefab;
				}
			}
			return null;
		}

		internal static void ApplyHeadDropVisual(CustomItem item, string sourceArrow)
		{
			if (!((Object)(object)((item != null) ? item.ItemDrop : null) == (Object)null))
			{
				ApplyShipwreckBoxVisual(((Component)item.ItemDrop).gameObject);
			}
		}

		internal static void ApplyShaftDropVisual(CustomItem item, string sourceArrow, bool ashTint = false)
		{
			if (!((Object)(object)((item != null) ? item.ItemDrop : null) == (Object)null))
			{
				ApplyArrowPartDropVisual(((Component)item.ItemDrop).gameObject, sourceArrow, isHead: false, ashTint);
			}
		}

		private static void ApplyShipwreckBoxVisual(GameObject dropPrefab)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			GameObject boxPrefab = GetBoxPrefab();
			if ((Object)(object)boxPrefab == (Object)null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"No box prefab found for head drop visual; keeping iron scrap mesh.");
				}
				return;
			}
			RemoveDropVisual(dropPrefab);
			GameObject val = new GameObject("FF_DropVisual");
			val.transform.SetParent(dropPrefab.transform, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one * 0.25f;
			if (!CopyMeshHierarchyFromRoot(boxPrefab.transform, val.transform))
			{
				Object.Destroy((Object)(object)val);
				EnableVanillaDropRenderers(dropPrefab);
				ManualLogSource log2 = FletchersForgePlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("No box mesh copied for " + ((Object)dropPrefab).name + "; keeping iron scrap mesh."));
				}
				return;
			}
			AlignDropVisualToGround(val.transform);
			DisableVanillaDropRenderers(dropPrefab);
			EnsureDropPhysics(dropPrefab);
			ManualLogSource log3 = FletchersForgePlugin.Log;
			if (log3 != null)
			{
				log3.LogInfo((object)$"Applied box drop visual ({0.25f:P0}) for {((Object)dropPrefab).name} from '{((Object)boxPrefab).name}'.");
			}
		}

		private static void ApplyArrowPartDropVisual(GameObject dropPrefab, string sourceArrow, bool isHead, bool ashTint = false)
		{
			GameObject val = (isHead ? IconRigUtility.BuildHeadIconRig(sourceArrow, 1f) : IconRigUtility.BuildShaftIconRig(sourceArrow, ashTint));
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not build drop visual for " + ((Object)dropPrefab).name + " from " + sourceArrow + "."));
				}
				EnableVanillaDropRenderers(dropPrefab);
				return;
			}
			bool num = TryCopyMeshVisual(dropPrefab, val, isHead);
			Object.Destroy((Object)(object)val);
			if (!num)
			{
				EnableVanillaDropRenderers(dropPrefab);
				ManualLogSource log2 = FletchersForgePlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("No mesh copied for drop visual on " + ((Object)dropPrefab).name + "."));
				}
				return;
			}
			DisableVanillaDropRenderers(dropPrefab);
			EnsureDropPhysics(dropPrefab);
			ManualLogSource log3 = FletchersForgePlugin.Log;
			if (log3 != null)
			{
				log3.LogInfo((object)("Applied drop visual for " + ((Object)dropPrefab).name + "."));
			}
		}

		private static void RemoveDropVisual(GameObject dropPrefab)
		{
			Transform val = dropPrefab.transform.Find("FF_DropVisual");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}

		private static bool TryCopyMeshVisual(GameObject dropPrefab, GameObject rig, bool isHead)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			RemoveDropVisual(dropPrefab);
			GameObject val = new GameObject("FF_DropVisual");
			val.transform.SetParent(dropPrefab.transform, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.Euler(0f, 0f, 90f);
			val.transform.localScale = Vector3.one * (isHead ? 0.28f : 0.22f);
			bool flag = false;
			Renderer[] componentsInChildren = rig.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && CopyRendererMesh(val2, val.transform))
				{
					flag = true;
				}
			}
			if (!flag)
			{
				Object.Destroy((Object)(object)val);
			}
			return flag;
		}

		private static bool CopyMeshHierarchyFromRoot(Transform sourceRoot, Transform destRoot)
		{
			bool result = false;
			Renderer[] componentsInChildren = ((Component)sourceRoot).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && CopyRendererMeshRelative(val, sourceRoot, destRoot))
				{
					result = true;
				}
			}
			return result;
		}

		private static bool CopyRendererMeshRelative(Renderer source, Transform sourceRoot, Transform destRoot)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = null;
			if (source is MeshRenderer)
			{
				MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
				if ((Object)(object)component != (Object)null)
				{
					val = component.sharedMesh;
				}
			}
			else
			{
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((source is SkinnedMeshRenderer) ? source : null);
				if (val2 != null)
				{
					val = val2.sharedMesh;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			GameObject val3 = new GameObject(((Object)source).name);
			val3.transform.SetParent(destRoot, false);
			val3.transform.localPosition = sourceRoot.InverseTransformPoint(((Component)source).transform.position);
			val3.transform.localRotation = Quaternion.Inverse(sourceRoot.rotation) * ((Component)source).transform.rotation;
			Vector3 lossyScale = ((Component)source).transform.lossyScale;
			Vector3 lossyScale2 = sourceRoot.lossyScale;
			val3.transform.localScale = new Vector3(SafeDivide(lossyScale.x, lossyScale2.x), SafeDivide(lossyScale.y, lossyScale2.y), SafeDivide(lossyScale.z, lossyScale2.z));
			val3.AddComponent<MeshFilter>().sharedMesh = val;
			((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterials = source.sharedMaterials;
			return true;
		}

		private static bool CopyRendererMesh(Renderer source, Transform parent)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = null;
			if (source is MeshRenderer)
			{
				MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
				if ((Object)(object)component != (Object)null)
				{
					val = component.sharedMesh;
				}
			}
			else
			{
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((source is SkinnedMeshRenderer) ? source : null);
				if (val2 != null)
				{
					val = val2.sharedMesh;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			GameObject val3 = new GameObject(((Object)source).name);
			val3.transform.SetParent(parent, false);
			val3.transform.localPosition = ((Component)source).transform.localPosition;
			val3.transform.localRotation = ((Component)source).transform.localRotation;
			val3.transform.localScale = ((Component)source).transform.localScale;
			val3.AddComponent<MeshFilter>().sharedMesh = val;
			((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterials = source.sharedMaterials;
			return true;
		}

		private static void DisableVanillaDropRenderers(GameObject dropPrefab)
		{
			Transform val = dropPrefab.transform.Find("FF_DropVisual");
			Renderer[] componentsInChildren = dropPrefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val != (Object)null) || !((Component)val2).transform.IsChildOf(val))
				{
					val2.enabled = false;
				}
			}
		}

		private static void EnableVanillaDropRenderers(GameObject dropPrefab)
		{
			Transform val = dropPrefab.transform.Find("FF_DropVisual");
			Renderer[] componentsInChildren = dropPrefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val != (Object)null) || !((Component)val2).transform.IsChildOf(val))
				{
					val2.enabled = true;
				}
			}
		}

		private static void EnsureDropPhysics(GameObject dropPrefab)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			Collider[] componentsInChildren = dropPrefab.GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.enabled = true;
				}
			}
			Rigidbody component = dropPrefab.GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.isKinematic = false;
				component.useGravity = true;
			}
			if ((Object)(object)dropPrefab.GetComponent<Collider>() == (Object)null)
			{
				SphereCollider obj = dropPrefab.AddComponent<SphereCollider>();
				obj.radius = 0.045f;
				obj.center = Vector3.zero;
			}
		}

		private static void AlignDropVisualToGround(Transform visualRoot)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			Renderer[] componentsInChildren = ((Component)visualRoot).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null))
				{
					Bounds bounds = component.sharedMesh.bounds;
					Vector3 val2 = Vector3.Scale(((Bounds)(ref bounds)).extents, ((Component)val).transform.localScale);
					float num2 = (((Component)val).transform.localPosition + Vector3.Scale(((Bounds)(ref bounds)).center, ((Component)val).transform.localScale)).y - val2.y;
					num = Mathf.Min(num, num2);
				}
			}
			if (num < float.MaxValue && !Mathf.Approximately(num, 0f))
			{
				visualRoot.localPosition = new Vector3(0f, 0f - num, 0f);
			}
		}

		private static float SafeDivide(float value, float divisor)
		{
			if (!Mathf.Approximately(divisor, 0f))
			{
				return value / divisor;
			}
			return value;
		}
	}
	internal static class FletchBenchButtonUi
	{
		private const string TakeAllLabelKey = "$inventory_takeall";

		private const string StackAllLabelKey = "$inventory_stackall";

		internal static void Update(InventoryGui gui, bool benchOpen)
		{
			if ((Object)(object)gui == (Object)null)
			{
				return;
			}
			bool flag = !benchOpen && gui.IsContainerOpen();
			bool flag2 = benchOpen && InventoryGui.IsVisible();
			if ((Object)(object)gui.m_takeAllButton != (Object)null)
			{
				((Component)gui.m_takeAllButton).gameObject.SetActive(flag || flag2);
				if (flag2)
				{
					SetButtonLabel(gui.m_takeAllButton, GetReforgeLabel());
				}
				else if (flag)
				{
					RestoreVanillaLabel(gui.m_takeAllButton, "$inventory_takeall", "Take all");
				}
			}
			if ((Object)(object)gui.m_stackAllButton != (Object)null)
			{
				((Component)gui.m_stackAllButton).gameObject.SetActive(flag || flag2);
				if (flag2)
				{
					SetButtonLabel(gui.m_stackAllButton, GetSplitLabel());
				}
				else if (flag)
				{
					RestoreVanillaLabel(gui.m_stackAllButton, "$inventory_stackall", "Place stacks");
				}
			}
		}

		private static string GetReforgeLabel()
		{
			string text = Localization.instance.Localize("$FF_Reforge");
			if (!string.IsNullOrEmpty(text) && !text.StartsWith("$", StringComparison.Ordinal))
			{
				return text;
			}
			return "Reforge";
		}

		private static string GetSplitLabel()
		{
			string text = Localization.instance.Localize("$FF_Split");
			if (!string.IsNullOrEmpty(text) && !text.StartsWith("$", StringComparison.Ordinal))
			{
				return text;
			}
			return "Split";
		}

		private static void RestoreVanillaLabel(Button button, string locKey, string fallback)
		{
			string text = Localization.instance.Localize(locKey);
			if (string.IsNullOrEmpty(text) || text.StartsWith("$", StringComparison.Ordinal))
			{
				text = fallback;
			}
			SetButtonLabel(button, text);
		}

		private static void SetButtonLabel(Button button, string label)
		{
			TMP_Text componentInChildren = ((Component)button).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = label;
			}
		}
	}
	internal static class FletchBenchInventory
	{
		private static Inventory inventory;

		internal static Inventory Inventory => inventory;

		internal static void Initialize()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			if (inventory == null)
			{
				Sprite val = null;
				GameObject prefab = PrefabManager.Instance.GetPrefab("chest");
				Container val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Container>() : null);
				if ((Object)(object)val2 != (Object)null)
				{
					val = val2.m_bkg;
				}
				inventory = new Inventory("$FF_FletchContainer", val, 2, 1);
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Initialized virtual Fletcher bench inventory.");
				}
			}
		}

		internal static void ClearSlots()
		{
			if (inventory != null)
			{
				inventory.RemoveAll();
			}
		}
	}
	[BepInPlugin("hardwire99.fletchersforge", "Fletchers Forge", "0.1.30")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class FletchersForgePlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			if (!ModConfig.Enabled.Value)
			{
				Log.LogInfo((object)"Fletchers Forge is disabled in config.");
				return;
			}
			harmony = new Harmony("hardwire99.fletchersforge");
			harmony.PatchAll(typeof(FletchersForgePlugin).Assembly);
			ChestSnapHarmony.Apply(harmony);
			LocalizationRegistrar.Initialize();
			((Component)this).gameObject.AddComponent<FletchUiBehaviour>();
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
			ItemManager.OnItemsRegisteredFejd += OnItemsRegisteredFejd;
			ItemManager.OnItemsRegistered += OnItemsRegisteredWorld;
			Log.LogInfo((object)"Fletchers Forge 0.1.30 loaded.");
			Log.LogInfo((object)$"Legacy bench prefab hash: {ModConstants.LegacyContainerPrefabHash}");
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
			ItemManager.OnItemsRegisteredFejd -= OnItemsRegisteredFejd;
			ItemManager.OnItemsRegistered -= OnItemsRegisteredWorld;
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private static void OnVanillaPrefabsAvailable()
		{
			ItemRegistrar.RegisterAll();
			RecipeRegistrar.RegisterAll();
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
		}

		private static void OnItemsRegisteredFejd()
		{
			ItemRegistrar.ApplyDeferredIcons();
		}

		private static void OnItemsRegisteredWorld()
		{
			ItemRegistrar.ApplyDeferredIcons();
		}
	}
	internal static class FletchersKnifeConfigurator
	{
		internal static void Configure(SharedData shared)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			shared.m_itemType = (ItemType)19;
			shared.m_toolTier = 0;
			shared.m_weight = 0.25f;
			shared.m_teleportable = true;
			shared.m_maxStackSize = 1;
			shared.m_maxQuality = 1;
			shared.m_value = 0;
			shared.m_useDurability = true;
			shared.m_maxDurability = 1f;
			shared.m_durabilityDrain = 1f;
			shared.m_blockPower = 0f;
			shared.m_blockPowerPerLevel = 0f;
			shared.m_armor = 0f;
			shared.m_armorPerLevel = 0f;
			shared.m_attackStatusEffect = null;
			shared.m_attackStatusEffectChance = 0f;
			shared.m_equipStatusEffect = null;
			shared.m_secondaryAttack = null;
			shared.m_damages = default(DamageTypes);
			shared.m_damages.m_pierce = 1f;
			shared.m_damagesPerLevel = default(DamageTypes);
			GameObject prefab = PrefabManager.Instance.GetPrefab("KnifeCopper");
			ItemDrop val = ((prefab != null) ? prefab.GetComponent<ItemDrop>() : null);
			if (val?.m_itemData?.m_shared?.m_attack == null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Fletcher's knife: KnifeCopper attack template missing.");
				}
			}
			else
			{
				shared.m_attack = CloneAttack(val.m_itemData.m_shared.m_attack);
				shared.m_attack.m_damageMultiplier = 1f;
				shared.m_attack.m_raiseSkillAmount = 0f;
				shared.m_attack.m_attackStamina = 0f;
				shared.m_attack.m_selfDamage = 0;
			}
		}

		private static Attack CloneAttack(Attack source)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			Attack val = new Attack();
			FieldInfo[] fields = typeof(Attack).GetFields(BindingFlags.Instance | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				fieldInfo.SetValue(val, fieldInfo.GetValue(source));
			}
			return val;
		}
	}
	internal static class FletchersKnifeHelper
	{
		private static readonly MethodInfo GetRightItemMethod = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly MethodInfo GetLeftItemMethod = typeof(Humanoid).GetMethod("GetLeftItem", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static bool IsKnifeInHand(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!IsKnife(GetHandItem(player, GetRightItemMethod)))
			{
				return IsKnife(GetHandItem(player, GetLeftItemMethod));
			}
			return true;
		}

		internal static bool IsKnifeEquipped(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (IsKnife(GetHandItem(player, GetRightItemMethod)) || IsKnife(GetHandItem(player, GetLeftItemMethod)))
			{
				return true;
			}
			if (((Humanoid)player).GetInventory() == null)
			{
				return false;
			}
			foreach (ItemData equippedItem in ((Humanoid)player).GetInventory().GetEquippedItems())
			{
				if (IsKnife(equippedItem))
				{
					return true;
				}
			}
			return false;
		}

		private static ItemData GetHandItem(Player player, MethodInfo method)
		{
			if (method == null)
			{
				return null;
			}
			object? obj = method.Invoke(player, null);
			return (ItemData)((obj is ItemData) ? obj : null);
		}

		private static bool IsKnife(ItemData item)
		{
			if ((Object)(object)item?.m_dropPrefab == (Object)null)
			{
				return false;
			}
			return ArrowAssemblyRegistry.IsKnifePrefab(((Object)item.m_dropPrefab).name);
		}
	}
	internal static class FletchLegacyCleanup
	{
		private static readonly int LegacyContainerPrefabHash = ModConstants.LegacyContainerPrefabHash;

		private static readonly int LegacyUnknownPrefabHash = 555343901;

		private static bool fullPurgeCompleted;

		private static readonly MethodInfo HandleDestroyedZdoMethod = AccessTools.Method(typeof(ZDOMan), "HandleDestroyedZDO", (Type[])null, (Type[])null);

		internal static void RunAfterWorldZdosLoaded()
		{
			fullPurgeCompleted = false;
			Run(forceFullPurge: true);
		}

		internal static void Run(bool forceFullPurge = false)
		{
			SanitizeNullZNetViews();
			if (!forceFullPurge && fullPurgeCompleted)
			{
				return;
			}
			int found;
			int remaining;
			int num = PurgeLegacyZdosFromWorldSave(out found, out remaining);
			int num2 = PurgeRuntimeInstances();
			int num3 = PurgeNamedObjects();
			int num4 = SanitizeNullZNetViews();
			if (forceFullPurge || num > 0 || num2 > 0 || num3 > 0)
			{
				fullPurgeCompleted = true;
			}
			ManualLogSource log = FletchersForgePlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)($"Legacy bench cleanup: found {found} ZDO(s), removed {num} from world save, " + $"{remaining} remain in memory, {num2} scene view(s) cleared, {num3} named object(s) destroyed. " + $"Tracked hashes: {LegacyContainerPrefabHash}, {LegacyUnknownPrefabHash}. " + $"IsServer={(Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()}."));
			}
			if (found == 0)
			{
				ManualLogSource log2 = FletchersForgePlugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"No legacy bench ZDOs in world save — phantom bench cleanup is complete for this world.");
				}
			}
			if (num > 0)
			{
				ManualLogSource log3 = FletchersForgePlugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)"Run console command 'save' to persist ZDO removal.");
				}
			}
			else if (found > 0)
			{
				ManualLogSource log4 = FletchersForgePlugin.Log;
				if (log4 != null)
				{
					log4.LogWarning((object)"Legacy bench ZDO(s) were found but could not be removed. Load as world host and try fletcher.cleanup again.");
				}
			}
			if (remaining > 0)
			{
				ManualLogSource log5 = FletchersForgePlugin.Log;
				if (log5 != null)
				{
					log5.LogWarning((object)$"{remaining} legacy bench ZDO(s) still in memory after cleanup. ChestSnap errors may continue until they are removed and saved.");
				}
			}
			if (num4 > 0)
			{
				ManualLogSource log6 = FletchersForgePlugin.Log;
				if (log6 != null)
				{
					log6.LogInfo((object)$"Removed {num4} stale ZNetView entries from ZNetScene for ChestSnap.");
				}
			}
		}

		internal static int SanitizeNullZNetViews()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return 0;
			}
			Dictionary<ZDO, ZNetView> value = Traverse.Create((object)ZNetScene.instance).Field<Dictionary<ZDO, ZNetView>>("m_instances").Value;
			if (value == null)
			{
				return 0;
			}
			List<ZDO> list = new List<ZDO>();
			foreach (KeyValuePair<ZDO, ZNetView> item in value)
			{
				if (item.Key == null || !IsLiveZNetView(item.Value))
				{
					list.Add(item.Key);
				}
			}
			foreach (ZDO item2 in list)
			{
				if (item2 != null)
				{
					value.Remove(item2);
				}
			}
			return list.Count;
		}

		internal static bool IsLiveZNetView(ZNetView view)
		{
			if ((Object)(object)view == (Object)null)
			{
				return false;
			}
			try
			{
				return (Object)(object)((Component)view).gameObject != (Object)null;
			}
			catch (NullReferenceException)
			{
				return false;
			}
		}

		private static int PurgeLegacyZdosFromWorldSave(out int found, out int remaining)
		{
			found = 0;
			remaining = 0;
			if (ZDOMan.instance == null)
			{
				return 0;
			}
			HashSet<ZDO> hashSet = new HashSet<ZDO>();
			CollectZdosByPrefabName("FF_FletchContainer", hashSet);
			CollectZdosByPrefabHash(hashSet);
			found = hashSet.Count;
			int num = 0;
			foreach (ZDO item in hashSet)
			{
				if (ForceDestroyZdo(item))
				{
					num++;
				}
			}
			remaining = CountLegacyZdos();
			return num;
		}

		private static int CountLegacyZdos()
		{
			HashSet<ZDO> hashSet = new HashSet<ZDO>();
			CollectZdosByPrefabName("FF_FletchContainer", hashSet);
			CollectZdosByPrefabHash(hashSet);
			return hashSet.Count;
		}

		private static void CollectZdosByPrefabName(string prefabName, HashSet<ZDO> output)
		{
			if (ZDOMan.instance == null || string.IsNullOrEmpty(prefabName))
			{
				return;
			}
			List<ZDO> list = new List<ZDO>();
			int num = 0;
			while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(prefabName, list, ref num))
			{
				foreach (ZDO item in list)
				{
					if (item != null)
					{
						output.Add(item);
					}
				}
				list.Clear();
			}
			foreach (ZDO item2 in list)
			{
				if (item2 != null)
				{
					output.Add(item2);
				}
			}
		}

		private static void CollectZdosByPrefabHash(HashSet<ZDO> output)
		{
			foreach (ZDO item in EnumerateAllZdos())
			{
				if (item != null)
				{
					int prefab = item.GetPrefab();
					if (prefab == LegacyContainerPrefabHash || prefab == LegacyUnknownPrefabHash)
					{
						output.Add(item);
					}
				}
			}
		}

		private static IEnumerable<ZDO> EnumerateAllZdos()
		{
			if (ZDOMan.instance == null)
			{
				return new List<ZDO>();
			}
			HashSet<ZDO> seen = new HashSet<ZDO>();
			List<ZDO> list = new List<ZDO>();
			Traverse val = Traverse.Create((object)ZDOMan.instance);
			if ((val.Field("m_objectsByID").GetValue() ?? val.Field("m_objectsById").GetValue()) is IDictionary dictionary)
			{
				foreach (object value in dictionary.Values)
				{
					AddUniqueZdo(list, seen, (ZDO)((value is ZDO) ? value : null));
				}
			}
			else
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Legacy cleanup could not read ZDOMan m_objectsByID.");
				}
			}
			if (val.Field("m_objectsByOutsideSector").GetValue() is IDictionary dictionary2)
			{
				foreach (object value2 in dictionary2.Values)
				{
					CollectZdosFromBucket(list, seen, value2);
				}
			}
			if (val.Field("m_objectsBySector").GetValue() is List<ZDO>[] array)
			{
				List<ZDO>[] array2 = array;
				foreach (List<ZDO> bucket in array2)
				{
					CollectZdosFromBucket(list, seen, bucket);
				}
			}
			return list;
		}

		private static void CollectZdosFromBucket(List<ZDO> all, HashSet<ZDO> seen, object bucket)
		{
			if (!(bucket is List<ZDO> list))
			{
				return;
			}
			foreach (ZDO item in list)
			{
				AddUniqueZdo(all, seen, item);
			}
		}

		private static void AddUniqueZdo(List<ZDO> all, HashSet<ZDO> seen, ZDO zdo)
		{
			if (zdo != null && !seen.Contains(zdo))
			{
				seen.Add(zdo);
				all.Add(zdo);
			}
		}

		private static int PurgeRuntimeInstances()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return 0;
			}
			Dictionary<ZDO, ZNetView> value = Traverse.Create((object)ZNetScene.instance).Field<Dictionary<ZDO, ZNetView>>("m_instances").Value;
			if (value == null)
			{
				return 0;
			}
			int num = 0;
			List<ZDO> list = new List<ZDO>();
			foreach (KeyValuePair<ZDO, ZNetView> item in value)
			{
				ZDO key = item.Key;
				ZNetView value2 = item.Value;
				if ((Object)(object)value2 == (Object)null || (Object)(object)((Component)value2).gameObject == (Object)null)
				{
					if (key != null)
					{
						list.Add(key);
					}
					num++;
				}
				else if (key != null && (key.GetPrefab() == LegacyContainerPrefabHash || key.GetPrefab() == LegacyUnknownPrefabHash))
				{
					Object.Destroy((Object)(object)((Component)value2).gameObject);
					list.Add(key);
					num++;
				}
			}
			foreach (ZDO item2 in list)
			{
				value.Remove(item2);
			}
			return num;
		}

		private static int PurgeNamedObjects()
		{
			int num = 0;
			GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
			foreach (GameObject val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string name = ((Object)val).name;
					if (name == "FF_FletchContainer" || name == "FF_FletchWorkbenchRuntime")
					{
						Object.Destroy((Object)(object)val);
						num++;
					}
				}
			}
			return num;
		}

		private static bool ForceDestroyZdo(ZDO zdo)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null || ZDOMan.instance == null)
			{
				return false;
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject val = ZNetScene.instance.FindInstance(zdo.m_uid);
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				Traverse.Create((object)ZNetScene.instance).Field<Dictionary<ZDO, ZNetView>>("m_instances").Value?.Remove(zdo);
			}
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && HandleDestroyedZdoMethod != null)
			{
				HandleDestroyedZdoMethod.Invoke(ZDOMan.instance, new object[1] { zdo.m_uid });
				return ZDOMan.instance.GetZDO(zdo.m_uid) == null;
			}
			if (zdo.IsOwner())
			{
				ZDOMan.instance.DestroyZDO(zdo);
				return true;
			}
			ManualLogSource log = FletchersForgePlugin.Log;
			if (log != null)
			{
				log.LogWarning((object)$"Could not remove legacy bench ZDO {zdo.m_uid} (not owner; load world as host).");
			}
			return false;
		}
	}
	internal static class FletchOperations
	{
		internal static bool TryReforge(Player player, Inventory inv, out string message)
		{
			message = string.Empty;
			if ((Object)(object)player == (Object)null || inv == null)
			{
				message = "No workbench.";
				return false;
			}
			ItemData itemAt = inv.GetItemAt(0, 0);
			ItemData itemAt2 = inv.GetItemAt(1, 0);
			if (itemAt == null)
			{
				message = "Place a shaft or arrow in the first slot.";
				return false;
			}
			string prefabName = (((Object)(object)itemAt.m_dropPrefab != (Object)null) ? ((Object)itemAt.m_dropPrefab).name : string.Empty);
			if (ArrowAssemblyRegistry.IsArrowPrefab(prefabName))
			{
				return TryRehead(player, inv, itemAt, itemAt2, out message);
			}
			if (ArrowAssemblyRegistry.IsShaftPrefab(prefabName))
			{
				return TryAssemble(player, inv, itemAt, itemAt2, out message);
			}
			message = "Invalid item in first slot.";
			return false;
		}

		internal static bool TrySplit(Player player, Inventory inv, out string message)
		{
			message = string.Empty;
			if ((Object)(object)player == (Object)null || inv == null)
			{
				message = "No workbench.";
				return false;
			}
			ItemData itemAt = inv.GetItemAt(0, 0);
			ItemData itemAt2 = inv.GetItemAt(1, 0);
			if (itemAt == null)
			{
				message = "Place arrows in the first slot.";
				return false;
			}
			if (itemAt2 != null)
			{
				message = "Clear the head slot before splitting.";
				return false;
			}
			if (!ArrowAssemblyRegistry.TryGetParts(((Object)(object)itemAt.m_dropPrefab != (Object)null) ? ((Object)itemAt.m_dropPrefab).name : string.Empty, out var shaftPrefab, out var headPrefab))
			{
				message = "That item cannot be split.";
				return false;
			}
			int num = Mathf.Min(20, itemAt.m_stack);
			if (!TryGiveComponents(player, shaftPrefab, headPrefab, num))
			{
				message = "Inventory full.";
				return false;
			}
			itemAt.m_stack -= num;
			if (itemAt.m_stack <= 0)
			{
				inv.RemoveItem(itemAt);
			}
			message = $"Split {num} arrows.";
			return true;
		}

		private static bool TryAssemble(Player player, Inventory inv, ItemData shaftItem, ItemData headItem, out string message)
		{
			message = string.Empty;
			string name = ((Object)shaftItem.m_dropPrefab).name;
			string headPrefab = (((Object)(object)headItem?.m_dropPrefab != (Object)null) ? ((Object)headItem.m_dropPrefab).name : null);
			if (!ArrowAssemblyRegistry.TryGetArrow(name, headPrefab, out var arrowPrefab))
			{
				if (headItem == null)
				{
					message = "Place an arrowhead in the second slot.";
				}
				else
				{
					message = "Those parts do not match.";
				}
				return false;
			}
			int num = Mathf.Min(20, shaftItem.m_stack);
			if (headItem != null)
			{
				num = Mathf.Min(num, headItem.m_stack);
			}
			if (!GiveArrows(player, arrowPrefab, num))
			{
				message = "Inventory full.";
				return false;
			}
			shaftItem.m_stack -= num;
			if (shaftItem.m_stack <= 0)
			{
				inv.RemoveItem(shaftItem);
			}
			if (headItem != null)
			{
				headItem.m_stack -= num;
				if (headItem.m_stack <= 0)
				{
					inv.RemoveItem(headItem);
				}
			}
			message = $"Reforged {num} arrows.";
			return true;
		}

		private static bool TryRehead(Player player, Inventory inv, ItemData arrowItem, ItemData newHeadItem, out string message)
		{
			message = string.Empty;
			if (newHeadItem == null)
			{
				message = "Place a new arrowhead in the second slot.";
				return false;
			}
			if (!ArrowAssemblyRegistry.TryGetParts(((Object)arrowItem.m_dropPrefab).name, out var shaftPrefab, out var headPrefab))
			{
				message = "That arrow cannot be reforged.";
				return false;
			}
			string name = ((Object)newHeadItem.m_dropPrefab).name;
			if (!ArrowAssemblyRegistry.TryGetArrow(shaftPrefab, name, out var arrowPrefab))
			{
				message = "That head does not fit this arrow.";
				return false;
			}
			int num = Mathf.Min(new int[3] { 20, arrowItem.m_stack, newHeadItem.m_stack });
			if (!GiveArrows(player, arrowPrefab, num))
			{
				message = "Inventory full.";
				return false;
			}
			if (!string.IsNullOrEmpty(headPrefab) && !GiveComponents(player, headPrefab, num))
			{
				message = "Inventory full.";
				return false;
			}
			arrowItem.m_stack -= num;
			newHeadItem.m_stack -= num;
			if (arrowItem.m_stack <= 0)
			{
				inv.RemoveItem(arrowItem);
			}
			if (newHeadItem.m_stack <= 0)
			{
				inv.RemoveItem(newHeadItem);
			}
			message = $"Reforged {num} arrows.";
			return true;
		}

		private static bool TryGiveComponents(Player player, string shaftPrefab, string headPrefab, int count)
		{
			if (!GiveComponents(player, shaftPrefab, count))
			{
				return false;
			}
			if (!string.IsNullOrEmpty(headPrefab) && !GiveComponents(player, headPrefab, count))
			{
				return false;
			}
			return true;
		}

		private static bool GiveComponents(Player player, string prefabName, int count)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return false;
			}
			return ((Humanoid)player).GetInventory().AddItem(itemPrefab, count);
		}

		private static bool GiveArrows(Player player, string arrowPrefabName, int count)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(arrowPrefabName);
			if ((Object)(object)itemPrefab == (Object)null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogError((object)("Arrow prefab missing: " + arrowPrefabName));
				}
				return false;
			}
			return ((Humanoid)player).GetInventory().AddItem(itemPrefab, count);
		}
	}
	internal static class FletchSlotRules
	{
		internal static bool CanAccept(int gridX, int gridY, string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return true;
			}
			if (gridX == 0 && gridY == 0)
			{
				if (!ArrowAssemblyRegistry.IsShaftPrefab(prefabName))
				{
					return ArrowAssemblyRegistry.IsArrowPrefab(prefabName);
				}
				return true;
			}
			if (gridX == 1 && gridY == 0)
			{
				return ArrowAssemblyRegistry.IsHeadPrefab(prefabName);
			}
			return false;
		}
	}
	internal sealed class FletchUiBehaviour : MonoBehaviour
	{
		private void OnGUI()
		{
			FletchUiService.DrawBenchOverlay();
		}
	}
	internal static class FletchUiService
	{
		private static bool benchUiOpen;

		private static string statusMessage = string.Empty;

		private static float statusUntil;

		internal static bool IsBenchUiOpen => benchUiOpen;

		internal static bool IsFletchContainerOpen
		{
			get
			{
				if (benchUiOpen && (Object)(object)InventoryGui.instance != (Object)null)
				{
					return InventoryGui.IsVisible();
				}
				return false;
			}
		}

		internal static bool IsFletchInventory(Inventory inventory)
		{
			Inventory inventory2 = FletchBenchInventory.Inventory;
			if (inventory2 != null)
			{
				return inventory2 == inventory;
			}
			return false;
		}

		internal static void Open(Player player)
		{
			if (!FletchersKnifeHelper.IsKnifeInHand(player) || IsFletchContainerOpen)
			{
				return;
			}
			FletchBenchInventory.Initialize();
			if (FletchBenchInventory.Inventory == null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogError((object)"Virtual Fletcher bench is not ready.");
				}
				return;
			}
			if ((Object)(object)InventoryGui.instance == (Object)null)
			{
				ManualLogSource log2 = FletchersForgePlugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)"InventoryGui not available.");
				}
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			FletchBenchInventory.ClearSlots();
			if (InventoryGui.IsVisible())
			{
				instance.Hide();
			}
			InventoryGuiAccess.SetHiddenFrames(instance, 10);
			InventoryGuiAccess.SetAnimatorVisible(instance, visible: true);
			InventoryGuiAccess.SetActiveGroup(instance, 1);
			InventoryGuiAccess.SetFirstContainerUpdate(instance, value: true);
			benchUiOpen = true;
			if ((Object)(object)InventoryGui.instance != (Object)null)
			{
				FletchBenchButtonUi.Update(InventoryGui.instance, benchOpen: true);
			}
			ManualLogSource log3 = FletchersForgePlugin.Log;
			if (log3 != null)
			{
				log3.LogInfo((object)"Opened virtual Fletcher bench UI.");
			}
		}

		internal static void NotifyGuiClosed()
		{
			benchUiOpen = false;
			FletchBenchInventory.ClearSlots();
		}

		internal static void Close()
		{
			if (benchUiOpen || IsFletchContainerOpen)
			{
				benchUiOpen = false;
				FletchBenchInventory.ClearSlots();
				if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible())
				{
					InventoryGui.instance.Hide();
				}
			}
		}

		internal static void TryReforge(Player player)
		{
			if (IsFletchContainerOpen && FletchBenchInventory.Inventory != null)
			{
				FletchOperations.TryReforge(player, FletchBenchInventory.Inventory, out var message);
				SetStatus(message);
			}
		}

		internal static void TrySplit(Player player)
		{
			if (IsFletchContainerOpen && FletchBenchInventory.Inventory != null)
			{
				FletchOperations.TrySplit(player, FletchBenchInventory.Inventory, out var message);
				SetStatus(message);
			}
		}

		internal static void DrawBenchOverlay()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (IsFletchContainerOpen && TryGetContainerScreenRect(out var rect) && Time.time < statusUntil && !string.IsNullOrEmpty(statusMessage))
			{
				GUI.Label(new Rect(((Rect)(ref rect)).x + 12f, ((Rect)(ref rect)).y + ((Rect)(ref rect)).height - 52f, ((Rect)(ref rect)).width - 24f, 20f), statusMessage);
			}
		}

		internal static void SetStatus(string message)
		{
			statusMessage = message;
			statusUntil = Time.time + 3f;
		}

		private static bool TryGetContainerScreenRect(out Rect rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			rect = default(Rect);
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance?.m_container == (Object)null)
			{
				return false;
			}
			RectTransform container = instance.m_container;
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			container.GetWorldCorners(array);
			Canvas componentInParent = ((Component)container).GetComponentInParent<Canvas>();
			Camera val = null;
			if ((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0)
			{
				val = componentInParent.worldCamera;
			}
			Vector2 val2 = RectTransformUtility.WorldToScreenPoint(val, array[0]);
			Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val, array[2]);
			float x = val2.x;
			float num = (float)Screen.height - val3.y;
			float num2 = val3.x - val2.x;
			float num3 = val3.y - val2.y;
			rect = new Rect(x, num, num2, num3);
			if (num2 > 0f)
			{
				return num3 > 0f;
			}
			return false;
		}
	}
	internal static class HeadIconAssets
	{
		private const string IconFolderName = "Icons";

		private const string EmbeddedIconFolder = "EmbeddedIcons";

		private static readonly Dictionary<string, Sprite> Cache = new Dictionary<string, Sprite>();

		private static readonly Dictionary<string, string> SourceCache = new Dictionary<string, string>();

		private static MethodInfo imageConversionLoadImage;

		private static bool loggedEmbeddedResources;

		internal static void ClearCache()
		{
			Cache.Clear();
			SourceCache.Clear();
		}

		internal static bool TryApplyCustomHeadIcon(CustomItem item)
		{
			if ((Object)(object)((item != null) ? item.ItemDrop : null) == (Object)null)
			{
				return false;
			}
			string text = (((Object)(object)item.ItemPrefab != (Object)null) ? ((Object)item.ItemPrefab).name : ((Object)((Component)item.ItemDrop).gameObject).name);
			Sprite orLoad = GetOrLoad(text);
			if ((Object)(object)orLoad == (Object)null)
			{
				return false;
			}
			item.ItemDrop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { orLoad };
			IconRigUtility.SyncIconsToObjectDb(text, item.ItemDrop.m_itemData.m_shared.m_icons);
			string text2 = "custom";
			if (SourceCache.TryGetValue(text, out var value))
			{
				text2 = value;
			}
			ManualLogSource log = FletchersForgePlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Applied {text2} icon for {text} ({((Texture)orLoad.texture).width}x{((Texture)orLoad.texture).height}).");
			}
			return true;
		}

		internal static string GetIconsFolderPath()
		{
			return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Paths.PluginPath, "Icons");
		}

		private static Sprite GetOrLoad(string prefabName)
		{
			if (Cache.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			Sprite val = null;
			string value2 = "none";
			if (ModConfig.UseEmbeddedHeadIcons.Value)
			{
				val = LoadEmbeddedSprite(prefabName);
				if ((Object)(object)val != (Object)null)
				{
					value2 = "embedded DLL";
				}
			}
			if ((Object)(object)val == (Object)null && ModConfig.AllowExternalHeadIconOverrides.Value)
			{
				val = LoadFilesystemSprite(prefabName);
				if ((Object)(object)val != (Object)null)
				{
					value2 = "external Icons folder";
				}
			}
			Cache[prefabName] = val;
			SourceCache[prefabName] = value2;
			return val;
		}

		private static Sprite LoadEmbeddedSprite(string prefabName)
		{
			Assembly assembly = typeof(FletchersForgePlugin).Assembly;
			string value = prefabName + ".png";
			string text = null;
			string[] manifestResourceNames = assembly.GetManifestResourceNames();
			foreach (string text2 in manifestResourceNames)
			{
				if (text2.EndsWith(value, StringComparison.OrdinalIgnoreCase))
				{
					text = text2;
					break;
				}
			}
			if (text == null)
			{
				if (!loggedEmbeddedResources)
				{
					loggedEmbeddedResources = true;
					ManualLogSource log = FletchersForgePlugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("Embedded icon resources: " + string.Join(", ", assembly.GetManifestResourceNames())));
					}
				}
				return null;
			}
			using Stream stream = assembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				return null;
			}
			return CreateSpriteFromPng(ReadAllBytes(stream), prefabName);
		}

		private static Sprite LoadFilesystemSprite(string prefabName)
		{
			string text = Path.Combine(GetIconsFolderPath(), prefabName + ".png");
			if (!File.Exists(text))
			{
				return null;
			}
			try
			{
				return CreateSpriteFromPng(File.ReadAllBytes(text), prefabName);
			}
			catch (IOException ex)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Failed to load icon " + text + ": " + ex.Message));
				}
				return null;
			}
		}

		private static Sprite CreateSpriteFromPng(byte[] bytes, string prefabName)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!TryLoadPng(val, bytes))
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not decode PNG for " + prefabName + "."));
				}
				return null;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		}

		private static byte[] ReadAllBytes(Stream stream)
		{
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private static bool TryLoadPng(Texture2D texture, byte[] bytes)
		{
			MethodInfo methodInfo = GetImageConversionLoadImage();
			if (methodInfo == null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"ImageConversion.LoadImage is unavailable; cannot load PNG icons.");
				}
				return false;
			}
			object[] parameters = ((methodInfo.GetParameters().Length != 3) ? new object[2] { texture, bytes } : new object[3] { texture, bytes, false });
			return (bool)methodInfo.Invoke(null, parameters);
		}

		private static MethodInfo GetImageConversionLoadImage()
		{
			if (imageConversionLoadImage != null)
			{
				return imageConversionLoadImage;
			}
			Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
			if (type == null)
			{
				return null;
			}
			imageConversionLoadImage = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
			{
				typeof(Texture2D),
				typeof(byte[]),
				typeof(bool)
			}, null);
			if (imageConversionLoadImage == null)
			{
				imageConversionLoadImage = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				}, null);
			}
			return imageConversionLoadImage;
		}
	}
	internal static class HeadIconGenerator
	{
		private static readonly Dictionary<string, Color> ArrowTipColors = new Dictionary<string, Color>
		{
			{
				"ArrowFire",
				new Color(0.95f, 0.45f, 0.12f)
			},
			{
				"ArrowFlint",
				new Color(0.55f, 0.52f, 0.48f)
			},
			{
				"ArrowBronze",
				new Color(0.78f, 0.48f, 0.22f)
			},
			{
				"ArrowIron",
				new Color(0.62f, 0.66f, 0.72f)
			},
			{
				"ArrowSilver",
				new Color(0.82f, 0.86f, 0.92f)
			},
			{
				"ArrowObsidian",
				new Color(0.22f, 0.2f, 0.28f)
			},
			{
				"ArrowPoison",
				new Color(0.42f, 0.72f, 0.28f)
			},
			{
				"ArrowFrost",
				new Color(0.45f, 0.78f, 0.95f)
			},
			{
				"ArrowNeedle",
				new Color(0.68f, 0.7f, 0.74f)
			},
			{
				"ArrowCarapace",
				new Color(0.58f, 0.32f, 0.62f)
			},
			{
				"ArrowCharred",
				new Color(0.18f, 0.18f, 0.2f)
			}
		};

		internal static Sprite CreateForArrow(string sourceArrow)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!ArrowTipColors.TryGetValue(sourceArrow, out var value))
			{
				((Color)(ref value))..ctor(0.65f, 0.65f, 0.65f);
			}
			return CreateArrowheadSprite(value);
		}

		private static Sprite CreateArrowheadSprite(Color tipColor)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0f, 0f, 0f, 0f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(tipColor.r * 0.55f, tipColor.g * 0.55f, tipColor.b * 0.55f, 1f);
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					float num = (float)j / 64f;
					float num2 = (float)i / 64f;
					bool flag = num >= 0.38f && num2 >= 0.22f && num <= 0.92f && num2 <= 0.88f && num - 0.38f >= (num2 - 0.22f) * 0.55f;
					bool flag2 = flag && num >= 0.38f && num <= 0.5f;
					val.SetPixel(j, i, flag2 ? val3 : (flag ? tipColor : val2));
				}
			}
			val.Apply();
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		}
	}
	internal static class IconRigUtility
	{
		private static readonly string[] HeadNameTokens = new string[17]
		{
			"head", "tip", "flint", "iron", "bronze", "silver", "obsidian", "fire", "poison", "frost",
			"needle", "carapace", "charred", "resin", "stone", "metal", "arrowhead"
		};

		private static readonly string[] ShaftNameTokens = new string[5] { "shaft", "stick", "wood", "body", "arrowwood" };

		private static readonly string[] FeatherNameTokens = new string[3] { "feather", "fletch", "vane" };

		internal static void ApplyShaftIcon(CustomItem item, string sourceArrow, bool ashTint = false)
		{
			GameObject target = BuildShaftIconRig(sourceArrow, ashTint);
			ApplyRenderedIcon(item, target);
		}

		internal static void ApplyHeadIcon(CustomItem item, string sourceArrow)
		{
			GameObject target = BuildHeadIconRig(sourceArrow);
			ApplyRenderedIcon(item, target);
		}

		internal static void ApplyRenderedIcon(CustomItem item, GameObject target)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((item != null) ? item.ItemDrop : null) == (Object)null || (Object)(object)target == (Object)null)
			{
				return;
			}
			try
			{
				Sprite val = RenderManager.Instance.Render(target, RenderManager.IsometricRotation);
				if ((Object)(object)val != (Object)null)
				{
					item.ItemDrop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { val };
					SyncIconsToObjectDb(((Object)item.ItemPrefab).name, item.ItemDrop.m_itemData.m_shared.m_icons);
					return;
				}
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Icon render returned null for " + ((Object)target).name + "."));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = FletchersForgePlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Icon render failed for " + ((Object)target).name + ": " + ex.Message));
				}
			}
			finally
			{
				if ((Object)(object)target != (Object)(object)((Component)item.ItemDrop).gameObject)
				{
					Object.Destroy((Object)(object)target);
				}
			}
		}

		internal static bool HasUsableIcons(Sprite[] icons)
		{
			if (icons == null || icons.Length == 0)
			{
				return false;
			}
			foreach (Sprite val in icons)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.texture != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		internal static void ApplyHeadIconFromTip(CustomItem item, string sourceArrow)
		{
			if (HeadIconAssets.TryApplyCustomHeadIcon(item))
			{
				return;
			}
			Sprite val = HeadIconGenerator.CreateForArrow(sourceArrow);
			if ((Object)(object)val != (Object)null)
			{
				item.ItemDrop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { val };
				SyncIconsToObjectDb(((Object)item.ItemPrefab).name, item.ItemDrop.m_itemData.m_shared.m_icons);
			}
			else if (!ApplyCroppedArrowTipIcon(item, sourceArrow))
			{
				GameObject val2 = BuildHeadIconRig(sourceArrow);
				if ((Object)(object)val2 != (Object)null)
				{
					ApplyRenderedIcon(item, val2);
					SyncIconsToObjectDb(((Object)item.ItemPrefab).name, item.ItemDrop.m_itemData.m_shared.m_icons);
				}
			}
		}

		internal static bool ApplyCroppedArrowTipIcon(CustomItem item, string sourceArrow)
		{
			if ((Object)(object)((item != null) ? item.ItemDrop : null) == (Object)null)
			{
				return false;
			}
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(sourceArrow) : PrefabManager.Instance.GetPrefab(sourceArrow));
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if (val2?.m_itemData?.m_shared?.m_icons == null || val2.m_itemData.m_shared.m_icons.Length == 0)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("No arrow icon to crop for " + sourceArrow + "."));
				}
				return false;
			}
			Sprite val3 = CropSpriteToArrowTip(val2.m_itemData.m_shared.m_icons[0], sourceArrow);
			if ((Object)(object)val3 == (Object)null)
			{
				return false;
			}
			item.ItemDrop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { val3 };
			SyncIconsToObjectDb(((Object)item.ItemPrefab).name, item.ItemDrop.m_itemData.m_shared.m_icons);
			return true;
		}

		internal static Sprite CropSpriteToArrowTip(Sprite source, string sourceArrow)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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)
			if ((Object)(object)source == (Object)null || (Object)(object)source.texture == (Object)null)
			{
				return null;
			}
			Rect rect = source.rect;
			int num;
			float num2;
			if (sourceArrow != null)
			{
				num = ((sourceArrow.IndexOf("Needle", StringComparison.OrdinalIgnoreCase) >= 0) ? 1 : 0);
				if (num != 0)
				{
					num2 = 0.52f;
					goto IL_0047;
				}
			}
			else
			{
				num = 0;
			}
			num2 = 0.42f;
			goto IL_0047;
			IL_0047:
			float num3 = num2;
			float num4 = ((num != 0) ? 0.22f : 0.3f);
			float num5 = ((num != 0) ? 0.46f : 0.56f);
			float num6 = ((num != 0) ? 0.72f : 0.62f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref rect)).x + ((Rect)(ref rect)).width * num3, ((Rect)(ref rect)).y + ((Rect)(ref rect)).height * num4, ((Rect)(ref rect)).width * num5, ((Rect)(ref rect)).height * num6);
			return Sprite.Create(source.texture, val, new Vector2(0.5f, 0.5f), source.pixelsPerUnit, 0u, (SpriteMeshType)0);
		}

		internal static void SyncIconsToObjectDb(string prefabName, Sprite[] icons)
		{
			if (!((Object)(object)ObjectDB.instance == (Object)null) && icons != null && icons.Length != 0)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if (val?.m_itemData?.m_shared != null)
				{
					val.m_itemData.m_shared.m_icons = icons;
				}
			}
		}

		internal static GameObject BuildShaftIconRig(string sourceArrow, bool ashTint)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab(sourceArrow);
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab);
			((Object)val).name = "IconRig_Shaft_" + sourceArrow;
			PrepareIconRig(val);
			Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)(object)val.transform) && IsHeadPart(((Object)val2).name))
				{
					((Component)val2).gameObject.SetActive(false);
				}
			}
			if (ashTint)
			{
				TintRenderers(val, new Color(0.38f, 0.38f, 0.42f, 1f));
			}
			return val;
		}

		internal static GameObject BuildHeadIconRig(string sourceArrow, float headScale = 1.5f)
		{
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab(sourceArrow);
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab);
			((Object)val).name = "IconRig_Head_" + sourceArrow;
			PrepareIconRig(val);
			Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)(object)val.transform) && (IsShaftPart(((Object)val2).name) || IsFeatherPart(((Object)val2).name)))
				{
					((Component)val2).gameObject.SetActive(false);
				}
			}
			Renderer[] componentsInChildren2 = val.GetComponentsInChildren<Renderer>(true);
			List<Renderer> list = new List<Renderer>();
			Renderer[] array = componentsInChildren2;
			foreach (Renderer val3 in array)
			{
				if ((Object)(object)val3 != (Object)null && ((Component)val3).gameObject.activeInHierarchy)
				{
					list.Add(val3);
				}
			}
			if (list.Count > 1)
			{
				IsolateTipRenderers(list);
			}
			list.Clear();
			array = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val4 in array)
			{
				if ((Object)(object)val4 != (Object)null && ((Component)val4).gameObject.activeInHierarchy)
				{
					list.Add(val4);
				}
			}
			if (list.Count == 0)
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			array = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val5 in array)
			{
				if (!((Object)(object)val5 == (Object)null) && ((Component)val5).gameObject.activeInHierarchy)
				{
					Transform transform = ((Component)val5).transform;
					transform.localScale *= headScale;
				}
			}
			return val;
		}

		private static void IsolateTipRenderers(List<Renderer> renderers)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = renderers[0].bounds;
			for (int i = 1; i < renderers.Count; i++)
			{
				((Bounds)(ref bounds)).Encapsulate(renderers[i].bounds);
			}
			Vector3 primaryAxis = GetPrimaryAxis(((Bounds)(ref bounds)).size);
			float num = float.MaxValue;
			float num2 = float.MinValue;
			Bounds bounds2;
			foreach (Renderer renderer in renderers)
			{
				bounds2 = renderer.bounds;
				float num3 = Vector3.Dot(((Bounds)(ref bounds2)).center - ((Bounds)(ref bounds)).center, primaryAxis);
				num = Mathf.Min(num, num3);
				num2 = Mathf.Max(num2, num3);
			}
			float num4 = num + (num2 - num) * 0.45f;
			foreach (Renderer renderer2 in renderers)
			{
				bounds2 = renderer2.bounds;
				if (Vector3.Dot(((Bounds)(ref bounds2)).center - ((Bounds)(ref bounds)).center, primaryAxis) < num4)
				{
					((Component)renderer2).gameObject.SetActive(false);
				}
			}
		}

		private static Vector3 GetPrimaryAxis(Vector3 size)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (size.y >= size.x && size.y >= size.z)
			{
				return Vector3.up;
			}
			if (size.z >= size.x && size.z >= size.y)
			{
				return Vector3.forward;
			}
			return Vector3.right;
		}

		private static void PrepareIconRig(GameObject rig)
		{
			Collider[] componentsInChildren = rig.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
			Rigidbody[] componentsInChildren2 = rig.GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].isKinematic = true;
			}
			ZNetView[] componentsInChildren3 = rig.GetComponentsInChildren<ZNetView>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				((Behaviour)componentsInChildren3[i]).enabled = false;
			}
		}

		private static void TintRenderers(GameObject rig, Color color)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = rig.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy)
				{
					Material material = val.material;
					if (material.HasProperty("_Color"))
					{
						material.SetColor("_Color", color);
					}
					if (material.HasProperty("_BaseColor"))
					{
						material.SetColor("_BaseColor", color);
					}
				}
			}
		}

		private static bool IsHeadPart(string name)
		{
			string text = name.ToLowerInvariant();
			string[] headNameTokens = HeadNameTokens;
			foreach (string value in headNameTokens)
			{
				if (text.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsShaftPart(string name)
		{
			string text = name.ToLowerInvariant();
			string[] shaftNameTokens = ShaftNameTokens;
			foreach (string value in shaftNameTokens)
			{
				if (text.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsFeatherPart(string name)
		{
			string text = name.ToLowerInvariant();
			string[] featherNameTokens = FeatherNameTokens;
			foreach (string value in featherNameTokens)
			{
				if (text.Contains(value))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class InventoryGuiAccess
	{
		private static readonly MethodInfo SetActiveGroupMethod = typeof(InventoryGui).GetMethod("SetActiveGroup", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static void SetActiveGroup(InventoryGui gui, int index, bool playSound = false)
		{
			if (!((Object)(object)gui == (Object)null) && !(SetActiveGroupMethod == null))
			{
				SetActiveGroupMethod.Invoke(gui, new object[2] { index, playSound });
			}
		}

		internal static void SetAnimatorVisible(InventoryGui gui, bool visible)
		{
			object value = Traverse.Create((object)gui).Field("m_animator").GetValue();
			if (value != null)
			{
				Traverse.Create(value).Method("SetBool", new object[2] { "visible", visible }).GetValue();
			}
		}

		internal static void SetHiddenFrames(InventoryGui gui, int frames)
		{
			Traverse.Create((object)gui).Field("m_hiddenFrames").SetValue((object)frames);
		}

		internal static void SetContainerName(InventoryGui gui, string localizedName)
		{
			object value = Traverse.Create((object)gui).Field("m_containerName").GetValue();
			if (value != null)
			{
				Traverse.Create(value).Property("text", (object[])null).SetValue((object)localizedName);
			}
		}

		internal static ItemData GetDragItem(InventoryGui gui)
		{
			return Traverse.Create((object)gui).Field<ItemData>("m_dragItem").Value;
		}

		internal static bool GetFirstContainerUpdate(InventoryGui gui)
		{
			return Traverse.Create((object)gui).Field<bool>("m_firstContainerUpdate").Value;
		}

		internal static void SetFirstContainerUpdate(InventoryGui gui, bool value)
		{
			Traverse.Create((object)gui).Field("m_firstContainerUpdate").SetValue((object)value);
		}

		internal static void ResetContainerHold(InventoryGui gui)
		{
			Traverse.Create((object)gui).Field("m_containerHoldTime").SetValue((object)0f);
			Traverse.Create((object)gui).Field("m_containerHoldState").SetValue((object)0);
		}
	}
	internal static class ItemRegistrar
	{
		private static CustomItem knifeItem;

		internal static void RegisterAll()
		{
			ArrowAssemblyRegistry.Initialize();
			RegisterShaft("FF_ShaftStandard", "$FF_ShaftStandard", "$FF_ShaftStandard_desc", 0.05f);
			RegisterShaft("FF_ShaftNeedle", "$FF_ShaftNeedle", "$FF_ShaftNeedle_desc", 0.05f, "ArrowNeedle");
			RegisterShaft("FF_ShaftAsh", "$FF_ShaftAsh", "$FF_ShaftAsh_desc", 0.05f, "ArrowWood", ashTint: true);
			RegisterHead("FF_HeadFire", "$FF_HeadFire", "ArrowFire");
			RegisterHead("FF_HeadFlint", "$FF_HeadFlint", "ArrowFlint");
			RegisterHead("FF_HeadBronze", "$FF_HeadBronze", "ArrowBronze");
			RegisterHead("FF_HeadIron", "$FF_HeadIron", "ArrowIron");
			RegisterHead("FF_HeadSilver", "$FF_HeadSilver", "ArrowSilver");
			RegisterHead("FF_HeadObsidian", "$FF_HeadObsidian", "ArrowObsidian");
			RegisterHead("FF_HeadPoison", "$FF_HeadPoison", "ArrowPoison");
			RegisterHead("FF_HeadFrost", "$FF_HeadFrost", "ArrowFrost");
			RegisterHead("FF_HeadNeedle", "$FF_HeadNeedle", "ArrowNeedle");
			RegisterHead("FF_HeadCarapace", "$FF_HeadCarapace", "ArrowCarapace");
			RegisterHead("FF_HeadCharred", "$FF_HeadCharred", "ArrowCharred");
			RegisterKnife();
		}

		internal static void ApplyDeferredIcons()
		{
			HeadIconAssets.ClearCache();
			if (ModConfig.AllowExternalHeadIconOverrides.Value)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("External head icon overrides enabled: " + HeadIconAssets.GetIconsFolderPath()));
				}
			}
			ApplyWoodShaftIcon("FF_ShaftStandard");
			ApplyWoodShaftIcon("FF_ShaftAsh", ashTint: true);
			ApplyShaftIcon("FF_ShaftNeedle", "ArrowNeedle");
			ApplyHeadIcon("FF_HeadFire", "ArrowFire");
			ApplyHeadIcon("FF_HeadFlint", "ArrowFlint");
			ApplyHeadIcon("FF_HeadBronze", "ArrowBronze");
			ApplyHeadIcon("FF_HeadIron", "ArrowIron");
			ApplyHeadIcon("FF_HeadSilver", "ArrowSilver");
			ApplyHeadIcon("FF_HeadObsidian", "ArrowObsidian");
			ApplyHeadIcon("FF_HeadPoison", "ArrowPoison");
			ApplyHeadIcon("FF_HeadFrost", "ArrowFrost");
			ApplyHeadIcon("FF_HeadNeedle", "ArrowNeedle");
			ApplyHeadIcon("FF_HeadCarapace", "ArrowCarapace");
			ApplyHeadIcon("FF_HeadCharred", "ArrowCharred");
			if (knifeItem != null)
			{
				GameObject val = Object.Instantiate<GameObject>(((Component)knifeItem.ItemDrop).gameObject);
				((Object)val).name = "IconRig_FF_FletchersKnife";
				IconRigUtility.ApplyRenderedIcon(knifeItem, val);
				Object.Destroy((Object)(object)val);
			}
			ManualLogSource log2 = FletchersForgePlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)"Applied deferred item icons.");
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				RefreshInventoryIcons(localPlayer);
			}
		}

		private static void RefreshInventoryIcons(Player player)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((Object)(object)allItem?.m_dropPrefab == (Object)null || allItem.m_shared == null)
				{
					continue;
				}
				string name = ((Object)allItem.m_dropPrefab).name;
				if (name.StartsWith("FF_", StringComparison.Ordinal))
				{
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name);
					ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
					if (val?.m_itemData?.m_shared?.m_icons != null && IconRigUtility.HasUsableIcons(val.m_itemData.m_shared.m_icons))
					{
						allItem.m_shared.m_icons = val.m_itemData.m_shared.m_icons;
					}
				}
			}
		}

		private static void RegisterShaft(string prefabName, string locName, string locDesc, float weight, string iconSourceArrow = "ArrowWood", bool ashTint = false)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = locName,
				Description = locDesc
			};
			CustomItem val2 = new CustomItem(prefabName, "IronScrap", val);
			ItemManager.Instance.AddItem(val2);
			ApplyMaterialStats(val2, weight, 100);
			ComponentDropVisualUtility.ApplyShaftDropVisual(val2, iconSourceArrow, ashTint);
			ManualLogSource log = FletchersForgePlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Registered shaft " + prefabName + "."));
			}
		}

		private static void RegisterHead(string prefabName, string locName, string iconSourceArrow)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = locName,
				Description = locName
			};
			CustomItem val2 = new CustomItem(prefabName, "IronScrap", val);
			ItemManager.Instance.AddItem(val2);
			ApplyMaterialStats(val2, 0.05f, 200);
			ComponentDropVisualUtility.ApplyHeadDropVisual(val2, iconSourceArrow);
			ManualLogSource log = FletchersForgePlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Registered head " + prefabName + "."));
			}
		}

		private static void RegisterKnife()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = "$FF_FletchersKnife",
				Description = "$FF_FletchersKnife_desc"
			};
			knifeItem = new CustomItem("FF_FletchersKnife", "KnifeBlackMetal", val);
			FletchersKnifeConfigurator.Configure(knifeItem.ItemDrop.m_itemData.m_shared);
			ApplyKnifeVisuals(((Component)knifeItem.ItemDrop).gameObject);
			ItemManager.Instance.AddItem(knifeItem);
			ManualLogSource log = FletchersForgePlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"Registered Fletcher's knife.");
			}
		}

		private static void ApplyWoodShaftIcon(string prefabName, bool ashTint = false)
		{
			CustomItem item = ItemManager.Instance.GetItem(prefabName);
			if (item != null)
			{
				GameObject val = IconRigUtility.BuildShaftIconRig("ArrowWood", ashTint);
				if (!((Object)(object)val == (Object)null))
				{
					IconRigUtility.ApplyRenderedIcon(item, val);
					Object.Destroy((Object)(object)val);
					IconRigUtility.SyncIconsToObjectDb(prefabName, item.ItemDrop.m_itemData.m_shared.m_icons);
				}
			}
		}

		private static void ApplyShaftIcon(string prefabName, string sourceArrow)
		{
			CustomItem item = ItemManager.Instance.GetItem(prefabName);
			if (item != null)
			{
				GameObject val = IconRigUtility.BuildShaftIconRig(sourceArrow, ashTint: false);
				if (!((Object)(object)val == (Object)null))
				{
					IconRigUtility.ApplyRenderedIcon(item, val);
					Object.Destroy((Object)(object)val);
					IconRigUtility.SyncIconsToObjectDb(prefabName, item.ItemDrop.m_itemData.m_shared.m_icons);
				}
			}
		}

		private static void ApplyHeadIcon(string prefabName, string sourceArrow)
		{
			CustomItem item = ItemManager.Instance.GetItem(prefabName);
			if (item != null)
			{
				IconRigUtility.ApplyHeadIconFromTip(item, sourceArrow);
			}
		}

		private static void ApplyMaterialStats(CustomItem item, float weight, int stackSize)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			SharedData shared = item.ItemDrop.m_itemData.m_shared;
			shared.m_itemType = (ItemType)1;
			shared.m_weight = weight;
			shared.m_maxStackSize = stackSize;
			shared.m_teleportable = true;
			shared.m_value = 0;
		}

		private static void ApplyKnifeVisuals(GameObject knifePrefab)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			Transform val = knifePrefab.transform.Find("attach");
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Fletcher's knife has no attach point; kitbash skipped.");
				}
				return;
			}
			HideBlackmetalBlade(val);
			GameObject prefab = PrefabManager.Instance.GetPrefab("KnifeChitin");
			if ((Object)(object)prefab == (Object)null)
			{
				ManualLogSource log2 = FletchersForgePlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"KnifeChitin prefab not found; kitbash skipped.");
				}
				return;
			}
			Transform val2 = PrefabPathUtility.FindFirstChild(prefab.transform, "attach_skin", "attach", "attach/mesh");
			if ((Object)(object)val2 == (Object)null)
			{
				val2 = PrefabPathUtility.FindRendererChild(prefab.transform);
			}
			if ((Object)(object)val2 == (Object)null)
			{
				ManualLogSource log3 = FletchersForgePlugin.Log;
				if (log3 != null)
				{
					log3.LogWarning((object)"Could not find Abyssal razor blade mesh for kitbash.");
				}
				return;
			}
			GameObject obj = Object.Instantiate<GameObject>(((Component)val2).gameObject, val);
			((Object)obj).name = "FF_AbyssalBlade";
			obj.transform.localPosition = Vector3.zero;
			obj.transform.localRotation = Quaternion.identity;
			obj.transform.localScale = Vector3.one * 0.75f;
			TintBladeCopper(obj.transform);
			ManualLogSource log4 = FletchersForgePlugin.Log;
			if (log4 != null)
			{
				log4.LogInfo((object)"Applied Fletcher's knife blade kitbash.");
			}
		}

		private static void HideBlackmetalBlade(Transform attach)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			Transform val = attach.Find("mesh");
			if ((Object)(object)val != (Object)null && ((Object)val).name != "FF_AbyssalBlade")
			{
				((Component)val).gameObject.SetActive(false);
				return;
			}
			foreach (Transform item in attach)
			{
				Transform val2 = item;
				if (!(((Object)val2).name == "FF_AbyssalBlade") && !((Object)val2).name.ToLowerInvariant().Contains("handle") && (Object)(object)((Component)val2).GetComponent<Renderer>() != (Object)null)
				{
					((Component)val2).gameObject.SetActive(false);
				}
			}
		}

		private static void TintBladeCopper(Transform bladeRoot)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(0.72f, 0.45f, 0.2f, 1f);
			Renderer[] componentsInChildren = ((Component)bladeRoot).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					Material material = val2.material;
					if (material.HasProperty("_Color"))
					{
						material.SetColor("_Color", val);
					}
					if (material.HasProperty("_BaseColor"))
					{
						material.SetColor("_BaseColor", val);
					}
				}
			}
		}
	}
	internal static class LocalizationRegistrar
	{
		internal static void Initialize()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			string text2 = "FF_ModName";
			localization.AddTranslation(ref text, ref text2, "Fletchers Forge");
			text = "English";
			text2 = "FF_FletchersKnife";
			localization.AddTranslation(ref text, ref text2, "Fletcher's knife");
			text = "English";
			text2 = "FF_FletchersKnife_desc";
			localization.AddTranslation(ref text, ref text2, "Field tool for the Fletcher's bench. Hold it ready to open the bench, then reforge or split arrows. Not meant for combat — 1 damage and breaks after one swing.");
			text = "English";
			text2 = "FF_ShaftStandard";
			localization.AddTranslation(ref text, ref text2, "Arrow shaft");
			text = "English";
			text2 = "FF_ShaftStandard_desc";
			localization.AddTranslation(ref text, ref text2, "A wooden arrow shaft with fletching.");
			text = "English";
			text2 = "FF_ShaftNeedle";
			localization.AddTranslation(ref text, ref text2, "Needle arrow shaft");
			text = "English";
			text2 = "FF_ShaftNeedle_desc";
			localization.AddTranslation(ref text, ref text2, "A feathered shaft for needle arrows.");
			text = "English";
			text2 = "FF_ShaftAsh";
			localization.AddTranslation(ref text, ref text2, "Ashwood arrow shaft");
			text = "English";
			text2 = "FF_ShaftAsh_desc";
			localization.AddTranslation(ref text, ref text2, "A dark ashwood shaft with fletching.");
			text = "English";
			text2 = "FF_HeadFire";
			localization.AddTranslation(ref text, ref text2, "Fire arrowhead");
			text = "English";
			text2 = "FF_HeadFlint";
			localization.AddTranslation(ref text, ref text2, "Flint arrowhead");
			text = "English";
			text2 = "FF_HeadBronze";
			localization.AddTranslation(ref text, ref text2, "Bronze arrowhead");
			text = "English";
			text2 = "FF_HeadIron";
			localization.AddTranslation(ref text, ref text2, "Iron arrowhead");
			text = "English";
			text2 = "FF_HeadSilver";
			localization.AddTranslation(ref text, ref text2, "Silver arrowhead");
			text = "English";
			text2 = "FF_HeadObsidian";
			localization.AddTranslation(ref text, ref text2, "Obsidian arrowhead");
			text = "English";
			text2 = "FF_HeadPoison";
			localization.AddTranslation(ref text, ref text2, "Poison arrowhead");
			text = "English";
			text2 = "FF_HeadFrost";
			localization.AddTranslation(ref text, ref text2, "Frost arrowhead");
			text = "English";
			text2 = "FF_HeadNeedle";
			localization.AddTranslation(ref text, ref text2, "Needle arrowhead");
			text = "English";
			text2 = "FF_HeadCarapace";
			localization.AddTranslation(ref text, ref text2, "Carapace arrowhead");
			text = "English";
			text2 = "FF_HeadCharred";
			localization.AddTranslation(ref text, ref text2, "Charred arrowhead");
			text = "English";
			text2 = "FF_FletchContainer";
			localization.AddTranslation(ref text, ref text2, "Fletcher's bench");
			text = "English";
			text2 = "FF_Reforge";
			localization.AddTranslation(ref text, ref text2, "Reforge");
			text = "English";
			text2 = "FF_Split";
			localization.AddTranslation(ref text, ref text2, "Split");
			text = "English";
			text2 = "FF_Preview";
			localization.AddTranslation(ref text, ref text2, "Result");
			text = "English";
			text2 = "FF_OpenBenchHint";
			localization.AddTranslation(ref text, ref text2, "[{0}] Fletcher's bench");
		}
	}
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> UseEmbeddedHeadIcons;

		internal static ConfigEntry<bool> AllowExternalHeadIconOverrides;

		internal static ConfigEntry<KeyCode> ReforgeKey;

		internal static ConfigEntry<KeyCode> SplitKey;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable Fletchers Forge. When false, the mod does not register items, recipes, or UI.");
			UseEmbeddedHeadIcons = config.Bind<bool>("Icons", "UseEmbeddedHeadIcons", true, "Load arrowhead inventory icons bundled inside FletchersForge.dll.");
			AllowExternalHeadIconOverrides = config.Bind<bool>("Icons", "AllowExternalHeadIconOverrides", false, "When true, PNG files in the plugin Icons folder override embedded icons.");
			ReforgeKey = config.Bind<KeyCode>("Controls", "Reforge", (KeyCode)0, "While the Fletcher's bench is open: reforge / assemble / rehead. None disables the hotkey (use the button).");
			SplitKey = config.Bind<KeyCode>("Controls", "Split", (KeyCode)0, "While the Fletcher's bench is open: split arrows. None disables the hotkey (use the button).");
		}
	}
	internal static class ModConstants
	{
		public const string ModGuid = "hardwire99.fletchersforge";

		public const string ModName = "Fletchers Forge";

		public const string ModVersion = "0.1.30";

		public const string HeadDropBoxPrimaryPrefab = "CargoCrate";

		public static readonly string[] HeadDropBoxPrefabFallbacks = new string[2] { "dvergrprops_crate", "shipwreck_karve_chest" };

		public const float HeadDropBoxScale = 0.25f;

		public const string FletchersKnife = "FF_FletchersKnife";

		public const string FletchContainer = "FF_FletchContainer";

		internal static readonly int LegacyContainerPrefabHash = StringExtensionMethods.GetStableHashCode("FF_FletchContainer");

		public const string ShaftStandard = "FF_ShaftStandard";

		public const string ShaftNeedle = "FF_ShaftNeedle";

		public const string ShaftAsh = "FF_ShaftAsh";

		public const string HeadFire = "FF_HeadFire";

		public const string HeadFlint = "FF_HeadFlint";

		public const string HeadBronze = "FF_HeadBronze";

		public const string HeadIron = "FF_HeadIron";

		public const string HeadSilver = "FF_HeadSilver";

		public const string HeadObsidian = "FF_HeadObsidian";

		public const string HeadPoison = "FF_HeadPoison";

		public const string HeadFrost = "FF_HeadFrost";

		public const string HeadNeedle = "FF_HeadNeedle";

		public const string HeadCarapace = "FF_HeadCarapace";

		public const string HeadCharred = "FF_HeadCharred";

		public const float ShaftWeight = 0.05f;

		public const float HeadWeight = 0.05f;

		public const float KnifeWeight = 0.25f;

		public const int ShaftStackSize = 100;

		public const int HeadStackSize = 200;

		public const int BatchSize = 20;
	}
	internal static class ChestSnapCompatPatch
	{
		private static bool sanitizedThisSession;

		internal static void Prefix()
		{
			if (sanitizedThisSession)
			{
				return;
			}
			sanitizedThisSession = true;
			int num = FletchLegacyCleanup.SanitizeNullZNetViews();
			if (num > 0)
			{
				ManualLogSource log = FletchersForgePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"ChestSnap compat: removed {num} stale ZNetView entries before snappoint scan.");
				}
			}
		}
	}
	internal static class ChestSnapMoveNextFinalizerPatch
	{
		private static bool logged;

		internal static Exception Finalizer(Exception __exception)
		{
			if (__exception is NullReferenceException)
			{
				if (!logged)
				{
					logged = true;
					ManualLogSource log = FletchersForgePlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"ChestSnap snappoint scan hit a stale world object and was aborted (harmless).");
					}
				}
				return null;
			}
			return __exception;
		}
	}
	internal static class ChestSnapNullArrayPatch
	{
		internal static void Postfix(ref GameObject[] __result)
		{
			if (__result != null && __result.Length != 0)
			{
				GameObject[] array = __result.Where((GameObject gameObject) => (Object)(object)gameObject != (Object)null).ToArray();
				if (array.Length != __result.Length)
				{
					__result = array;
				}
			}
		}
	}
	internal static class ChestSnapNullViewPatch
	{
		internal static bool Prefix(KeyValuePair<ZDO, ZNetView> g, ref GameObject __result)
		{
			if (!FletchLegacyCleanup.IsLiveZNetView(g.Value))
			{
				__result = null;
				return false;
			}
			return true;
		}
	}
	internal static class PrefabPathUtility
	{
		internal static Transform FindFirstChild(Transform root, params string[] relativePaths)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			foreach (string text in relativePaths)
			{
				Transform val = root.Find(text);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		internal static Transform FindRendererChild(Transform root, bool skipInactive = false)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)(object)root) && (!skipInactive || ((Component)val).gameObject.activeSelf) && (Object)(object)((Component)val).GetComponent<Renderer>() != (Object)null)
				{
					return val;
				}
			}
			return null;
		}
	}
	internal static class RecipeRegistrar
	{
		internal static void RegisterAll()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//