Decompiled source of ASKA Fox v0.6.3

BepInEx/plugins/AskaFox/AskaFox.dll

Decompiled a day ago
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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 System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Cinemachine;
using Fusion;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using SSSGame;
using SSSGame.Combat;
using SSSGame.Controllers;
using SSSGame.Localization;
using SSSGame.Network;
using SSSGame.UI;
using SSSGame.Water;
using SandSailorStudio;
using SandSailorStudio.Attributes;
using SandSailorStudio.Inventory;
using SandSailorStudio.Parameters;
using SandSailorStudio.Storage;
using SandSailorStudio.UI;
using SandSailorStudio.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("AskaFox")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AskaFox")]
[assembly: AssemblyTitle("AskaFox")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AskaWolfPrototype
{
	internal sealed class AnimalCarryVisuals
	{
		private sealed class Display
		{
			internal GameObject Source;

			internal GameObject Root;

			internal Transform Parent;

			internal Vector3 Center;

			internal Vector3 SourceScale;

			internal bool Tool;

			internal float RetryAfter;

			internal readonly List<(Renderer source, Renderer copy, bool hidden)> Parts = new List<(Renderer, Renderer, bool)>();

			internal readonly List<Mesh> Baked = new List<Mesh>();
		}

		private readonly Dictionary<int, Display> _shown = new Dictionary<int, Display>();

		private readonly Dictionary<int, GameObject> _wanted = new Dictionary<int, GameObject>();

		private readonly HashSet<int> _tools = new HashSet<int>();

		private readonly List<int> _remove = new List<int>();

		private readonly List<ItemPrefabStackSlot> _slots = new List<ItemPrefabStackSlot>();

		private float _nextScan;

		private static bool Same(ItemContainer a, ItemContainer b)
		{
			if (a != null && b != null)
			{
				return ((Il2CppObjectBase)a).Pointer == ((Il2CppObjectBase)b).Pointer;
			}
			return false;
		}

		private static bool Below(Transform child, Transform root)
		{
			if ((Object)(object)child != (Object)null && (Object)(object)root != (Object)null)
			{
				if (!((Object)(object)child == (Object)(object)root))
				{
					return child.IsChildOf(root);
				}
				return true;
			}
			return false;
		}

		private static bool Restricted(ItemContainer container, CharacterInventory inventory, ItemContainerComponent target = null)
		{
			if (container != null)
			{
				if (!Same(container, (inventory != null) ? inventory.RestrictedCarryContainer : null))
				{
					ItemContainerType containerType = container.containerType;
					if (containerType != null)
					{
						CharacterItemContainerType obj = ((Il2CppObjectBase)containerType).TryCast<CharacterItemContainerType>();
						if (((obj != null) ? new bool?(obj.restrictedCarry) : ((bool?)null)) == true)
						{
							goto IL_005f;
						}
					}
					return (Object)(object)((target != null) ? ((Il2CppObjectBase)target).TryCast<CharacterCarrySlot>() : null) != (Object)null;
				}
				goto IL_005f;
			}
			return false;
			IL_005f:
			return true;
		}

		internal bool Contains(GameObject item)
		{
			if ((Object)(object)item != (Object)null)
			{
				return _wanted.ContainsKey(((Object)item).GetInstanceID());
			}
			return false;
		}

		internal bool Owns(Renderer renderer)
		{
			foreach (Display value in _shown.Values)
			{
				if ((Object)(object)value.Source != (Object)null && (Object)(object)renderer != (Object)null && Below(((Component)renderer).transform, value.Source.transform))
				{
					return true;
				}
			}
			return false;
		}

		internal unsafe void Refresh(Character player, GameObject geometry, EquipmentManager equipment, WolfVisual visual, Action<GameObject> exclude, Action<GameObject> releaseVisibility)
		{
			//IL_0595: Unknown result type (might be due to invalid IL or missing references)
			//IL_059a: Unknown result type (might be due to invalid IL or missing references)
			_wanted.Clear();
			_tools.Clear();
			InventoryComponent inventory = player.Inventory;
			CharacterInventory inventory2 = ((inventory != null) ? ((Il2CppObjectBase)inventory).TryCast<CharacterInventory>() : null);
			PlayerCharacter val = ((Il2CppObjectBase)player).TryCast<PlayerCharacter>();
			Villager val2 = ((Il2CppObjectBase)player).TryCast<Villager>();
			PlayerInteractionAgent val3 = (((Object)(object)val == (Object)null) ? null : FoxCoop.Agent(val));
			if ((Object)(object)val2 == (Object)null)
			{
				if (!((Object)(object)val3 == (Object)null))
				{
					PlayerCharacter character = val3.GetCharacter();
					if (((character != null) ? new int?(((Object)character).GetInstanceID()) : ((int?)null)) == ((Object)player).GetInstanceID())
					{
						goto IL_00a4;
					}
				}
				Release(releaseVisibility);
				return;
			}
			goto IL_00a4;
			IL_00a4:
			Transform root = (((Object)(object)val2 != (Object)null) ? val2.GetGrabbingHand() : val3.grabbingHand);
			Transform root2 = (((Object)(object)val2 != (Object)null) ? val2.GetGrabbingOffHand() : val3.grabbingOffHand);
			if (Time.unscaledTime >= _nextScan)
			{
				_nextScan = Time.unscaledTime + 0.5f;
				_slots.Clear();
				HashSet<int> hashSet = new HashSet<int>();
				GameObject[] array = (GameObject[])(object)new GameObject[2]
				{
					((Component)player).gameObject,
					geometry
				};
				foreach (GameObject val4 in array)
				{
					if (!((Object)(object)val4 != (Object)null))
					{
						continue;
					}
					foreach (ItemPrefabStackSlot componentsInChild in val4.GetComponentsInChildren<ItemPrefabStackSlot>(true))
					{
						if (hashSet.Add(((Object)componentsInChild).GetInstanceID()))
						{
							_slots.Add(componentsInChild);
						}
					}
				}
			}
			foreach (ItemPrefabStackSlot slot in _slots)
			{
				if ((Object)(object)slot == (Object)null || slot._instances == null || !Restricted(((ItemDisplaySlot)slot)._container, inventory2, ((ItemDisplaySlot)slot).target))
				{
					continue;
				}
				Enumerator<DisplayStack> enumerator3 = slot._instances.GetEnumerator();
				while (enumerator3.MoveNext())
				{
					DisplayStack current3 = enumerator3.Current;
					if (((current3 != null) ? current3.item : null) != null && current3.item.count > 0 && Same(current3.item.Container, ((ItemDisplaySlot)slot)._container))
					{
						Want(current3.gameObject);
					}
				}
			}
			if (((equipment != null) ? equipment.equipPoints : null) != null)
			{
				Enumerator<EquipPoint> enumerator4 = equipment.equipPoints.GetEnumerator();
				while (enumerator4.MoveNext())
				{
					EquipPoint current4 = enumerator4.Current;
					EquipmentItem val5 = ((current4 != null) ? current4.GetCurrentItem() : null);
					if (val5 == null || !val5.IsEquipped() || ((Item)val5).count <= 0)
					{
						continue;
					}
					bool flag = false;
					List<EquipPoint> activePoints = val5.GetActivePoints();
					if (activePoints != null)
					{
						Enumerator<EquipPoint> enumerator5 = activePoints.GetEnumerator();
						while (enumerator5.MoveNext())
						{
							EquipPoint current5 = enumerator5.Current;
							if (current5 != null && ((Il2CppObjectBase)current5).Pointer == ((Il2CppObjectBase)current4).Pointer)
							{
								flag = true;
								break;
							}
						}
					}
					if (!flag)
					{
						continue;
					}
					GameObject val6 = val5.GetObject();
					bool flag2 = Below(current4.handle, root) || Below(current4.handle, root2) || Below((val6 != null) ? val6.transform.parent : null, root) || Below((val6 != null) ? val6.transform.parent : null, root2);
					if (!flag2 && ((val3 != null) ? val3.lockableEquipmentIds : null) != null)
					{
						Enumerator<EquipHandleId> enumerator6 = val3.lockableEquipmentIds.GetEnumerator();
						while (enumerator6.MoveNext())
						{
							EquipHandleId current6 = enumerator6.Current;
							if (current4.HasId(current6))
							{
								flag2 = true;
								break;
							}
						}
					}
					bool flag3 = Restricted(((Item)val5).Container, inventory2);
					if (flag2 || flag3)
					{
						Want(val6, !flag3);
					}
				}
			}
			_remove.Clear();
			foreach (KeyValuePair<int, Display> item in _shown)
			{
				if (!_wanted.ContainsKey(item.Key) || NeedsRefresh(item.Value, _tools.Contains(item.Key)))
				{
					Dispose(item.Value, releaseVisibility);
					_remove.Add(item.Key);
				}
			}
			foreach (int item2 in _remove)
			{
				_shown.Remove(item2);
			}
			foreach (KeyValuePair<int, GameObject> item3 in _wanted)
			{
				exclude(item3.Value);
				if (!_shown.ContainsKey(item3.Key))
				{
					Display display = Create(item3.Value, visual.Root.transform, _tools.Contains(item3.Key));
					_shown.Add(item3.Key, display);
					ManualLogSource logger = Plugin.Logger;
					string[] obj = new string[8]
					{
						"Animal continuous mouth display: ",
						((Object)item3.Value).name,
						"; mesh parts=",
						display.Parts.Count.ToString(),
						"; tool=",
						display.Tool.ToString(),
						"; source scale=",
						null
					};
					Vector3 sourceScale = display.SourceScale;
					obj[7] = ((object)(*(Vector3*)(&sourceScale))/*cast due to .constrained prefix*/).ToString();
					logger.LogInfo((object)string.Concat(obj));
				}
			}
		}

		private static bool ValidScale(Vector3 scale)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (float.IsFinite(scale.x) && float.IsFinite(scale.y) && float.IsFinite(scale.z) && Mathf.Abs(scale.x) > 1E-05f && Mathf.Abs(scale.y) > 1E-05f)
			{
				return Mathf.Abs(scale.z) > 1E-05f;
			}
			return false;
		}

		private void Want(GameObject obj, bool tool = false)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)obj == (Object)null) && obj.activeInHierarchy && ValidScale(obj.transform.lossyScale))
			{
				int instanceID = ((Object)obj).GetInstanceID();
				_wanted[instanceID] = obj;
				if (tool)
				{
					_tools.Add(instanceID);
				}
			}
		}

		private static bool NeedsRefresh(Display d, bool tool)
		{
			//IL_004f: 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)
			if ((Object)(object)d.Source == (Object)null || (Object)(object)d.Root == (Object)null || (Object)(object)d.Source.transform.parent != (Object)(object)d.Parent || d.Tool != tool)
			{
				return true;
			}
			Vector3 val = d.Source.transform.lossyScale - d.SourceScale;
			if (((Vector3)(ref val)).sqrMagnitude > 1E-05f)
			{
				return true;
			}
			if (d.Parts.Count == 0)
			{
				return Time.unscaledTime >= d.RetryAfter;
			}
			foreach (var part in d.Parts)
			{
				if ((Object)(object)part.source == (Object)null || (Object)(object)part.copy == (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		private static Display Create(GameObject source, Transform parent, bool tool)
		{
			//IL_002b: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			Display display = new Display
			{
				Source = source,
				Parent = source.transform.parent,
				Tool = tool,
				SourceScale = source.transform.lossyScale,
				RetryAfter = Time.unscaledTime + 0.25f,
				Root = new GameObject("Animal mouth held visual")
			};
			try
			{
				Transform transform = display.Root.transform;
				transform.position = source.transform.position;
				transform.rotation = source.transform.rotation;
				transform.localScale = display.SourceScale;
				bool flag = true;
				Bounds val = default(Bounds);
				foreach (Renderer componentsInChild in source.GetComponentsInChildren<Renderer>(true))
				{
					if (tool && !ValidScale(((Component)componentsInChild).transform.lossyScale))
					{
						continue;
					}
					MeshFilter component = ((Component)componentsInChild).GetComponent<MeshFilter>();
					Mesh val2 = ((component != null) ? component.sharedMesh : null);
					SkinnedMeshRenderer val3 = ((Il2CppObjectBase)componentsInChild).TryCast<SkinnedMeshRenderer>();
					if ((Object)(object)val2 == (Object)null && (Object)(object)val3 != (Object)null)
					{
						val2 = new Mesh();
						val3.BakeMesh(val2);
						display.Baked.Add(val2);
					}
					if (!((Object)(object)val2 == (Object)null))
					{
						GameObject val4 = new GameObject(((Object)((Component)componentsInChild).gameObject).name + " mouth visual")
						{
							layer = (tool ? ((Component)parent).gameObject.layer : ((Component)componentsInChild).gameObject.layer)
						};
						val4.transform.position = ((Component)componentsInChild).transform.position;
						val4.transform.rotation = ((Component)componentsInChild).transform.rotation;
						val4.transform.localScale = ((Component)componentsInChild).transform.lossyScale;
						val4.transform.SetParent(transform, true);
						val4.AddComponent<MeshFilter>().sharedMesh = val2;
						MeshRenderer val5 = val4.AddComponent<MeshRenderer>();
						((Renderer)val5).sharedMaterials = componentsInChild.sharedMaterials;
						((Renderer)val5).shadowCastingMode = componentsInChild.shadowCastingMode;
						((Renderer)val5).receiveShadows = componentsInChild.receiveShadows;
						display.Parts.Add((componentsInChild, (Renderer)(object)val5, componentsInChild.forceRenderingOff));
						if (flag)
						{
							val = ((Renderer)val5).bounds;
							flag = false;
						}
						else
						{
							((Bounds)(ref val)).Encapsulate(((Renderer)val5).bounds);
						}
					}
				}
				display.Center = (flag ? Vector3.zero : transform.InverseTransformPoint(((Bounds)(ref val)).center));
				transform.SetParent(parent, true);
				return display;
			}
			catch
			{
				Dispose(display, null);
				throw;
			}
		}

		internal void Place(Transform mouth)
		{
			//IL_0058: 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_0094: 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_00aa: 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)
			foreach (Display value in _shown.Values)
			{
				if ((Object)(object)value.Root == (Object)null || (Object)(object)value.Source == (Object)null || (Object)(object)mouth == (Object)null)
				{
					continue;
				}
				value.Root.transform.rotation = mouth.rotation * Quaternion.Euler(0f, (float)(value.Tool ? 90 : 180), 0f);
				value.Root.transform.position = mouth.position - value.Root.transform.TransformVector(value.Center);
				foreach (var part in value.Parts)
				{
					if ((Object)(object)part.source != (Object)null && (Object)(object)part.copy != (Object)null)
					{
						part.copy.enabled = value.Tool || (part.source.enabled && ((Component)part.source).gameObject.activeInHierarchy);
						part.copy.forceRenderingOff = false;
						part.source.forceRenderingOff = true;
					}
				}
			}
		}

		private static void Dispose(Display d, Action<GameObject> releaseVisibility)
		{
			if ((Object)(object)d.Source != (Object)null)
			{
				foreach (var part in d.Parts)
				{
					if ((Object)(object)part.source != (Object)null)
					{
						part.source.forceRenderingOff = part.hidden;
					}
				}
				releaseVisibility?.Invoke(d.Source);
			}
			if ((Object)(object)d.Root != (Object)null)
			{
				Object.Destroy((Object)(object)d.Root);
			}
			foreach (Mesh item in d.Baked)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
		}

		internal void Release(Action<GameObject> releaseVisibility)
		{
			foreach (Display value in _shown.Values)
			{
				Dispose(value, releaseVisibility);
			}
			_shown.Clear();
			_wanted.Clear();
			_tools.Clear();
			_slots.Clear();
			_nextScan = 0f;
		}
	}
	internal sealed class AnimalHeldItem
	{
		private GameObject _item;

		private Transform _parent;

		private Vector3 _localPosition;

		private Vector3 _center;

		private Quaternion _localRotation;

		private readonly List<(Renderer renderer, bool hidden)> _renderers = new List<(Renderer, bool)>();

		internal bool Owns(Renderer renderer)
		{
			if ((Object)(object)_item != (Object)null && (Object)(object)renderer != (Object)null)
			{
				if (!((Object)(object)((Component)renderer).gameObject == (Object)(object)_item))
				{
					return ((Component)renderer).transform.IsChildOf(_item.transform);
				}
				return true;
			}
			return false;
		}

		internal bool Observe(GameObject item)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00cb: 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)
			if ((Object)(object)_item == (Object)(object)item)
			{
				return false;
			}
			Release();
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			_item = item;
			Transform transform = item.transform;
			_parent = transform.parent;
			_localPosition = transform.localPosition;
			_localRotation = transform.localRotation;
			bool flag = true;
			Bounds val = default(Bounds);
			foreach (Renderer componentsInChild in item.GetComponentsInChildren<Renderer>(true))
			{
				_renderers.Add((componentsInChild, componentsInChild.forceRenderingOff));
				if (flag)
				{
					val = componentsInChild.bounds;
					flag = false;
				}
				else
				{
					((Bounds)(ref val)).Encapsulate(componentsInChild.bounds);
				}
			}
			_center = (flag ? Vector3.zero : transform.InverseTransformPoint(((Bounds)(ref val)).center));
			Plugin.Logger.LogInfo((object)("Animal temporary item attached: " + ((Object)item).name));
			return true;
		}

		internal void Place(Transform socket, float yaw = 90f)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_006c: 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_0078: 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)
			if ((Object)(object)_item == (Object)null || (Object)(object)socket == (Object)null)
			{
				return;
			}
			if ((Object)(object)_item.transform.parent != (Object)(object)_parent)
			{
				Release();
				return;
			}
			Transform transform = _item.transform;
			transform.rotation = socket.rotation * Quaternion.Euler(0f, yaw, 0f);
			transform.position = socket.position - transform.TransformVector(_center);
			foreach (var renderer in _renderers)
			{
				if ((Object)(object)renderer.renderer != (Object)null)
				{
					renderer.renderer.forceRenderingOff = false;
				}
			}
		}

		internal void Release(bool hide = false)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (Object)(object)_item != (Object)null && (Object)(object)_item.transform.parent == (Object)(object)_parent;
			if (flag)
			{
				_item.transform.localPosition = _localPosition;
				_item.transform.localRotation = _localRotation;
			}
			foreach (var renderer in _renderers)
			{
				if (flag && (Object)(object)renderer.renderer != (Object)null)
				{
					renderer.renderer.forceRenderingOff = hide || renderer.hidden;
				}
			}
			_renderers.Clear();
			_item = null;
			_parent = null;
		}
	}
	[HarmonyPatch]
	internal static class AnimalHandSpawnHook
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from m in AccessTools.GetDeclaredMethods(typeof(ItemInfo))
				where m.Name == "SpawnObject"
				select m;
		}

		private static void Postfix(GameObject __result, Transform parent)
		{
			try
			{
				if ((Object)(object)__result != (Object)null && (Object)(object)parent != (Object)null)
				{
					Plugin.Behaviour?.SpawnedHandProp(__result, parent);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Animal hand prop skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(CraftInteractionDisplay), "BeginCraftingSequence")]
	internal static class AnimalCraftDisplayHook
	{
		private static void Postfix(CraftInteractionDisplay __instance, InteractionSession interactionSession)
		{
			try
			{
				Plugin.Behaviour?.CraftProps(__instance, interactionSession);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Animal craft props skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(EquipmentStackSlot), "_SetupInstance")]
	internal static class AnimalStackDisplayHook
	{
		private static void Postfix(DisplayStack displayStack)
		{
			try
			{
				EquipmentStack val = ((displayStack != null) ? ((Il2CppObjectBase)displayStack).TryCast<EquipmentStack>() : null);
				if (val != null)
				{
					Item item = ((DisplayStack)val).item;
					if (((item != null) ? ((Il2CppObjectBase)item).TryCast<EquipmentItem>() : null) == null)
					{
						Plugin.Behaviour?.StackProp(val._eqManager, ((DisplayStack)val).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Animal stack prop skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(ItemPrefabStackSlot), "_SetupInstance")]
	internal static class AnimalResourceDisplayHook
	{
		private static void Postfix(ItemPrefabStackSlot __instance, DisplayStack displayStack)
		{
			try
			{
				if (displayStack != null)
				{
					Item item = displayStack.item;
					if (((item != null) ? ((Il2CppObjectBase)item).TryCast<EquipmentItem>() : null) == null)
					{
						Plugin.Behaviour?.SlotProp(__instance, displayStack.gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Animal resource prop skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(GatherInteraction), "GatherItemsCharge")]
	internal static class FoxQuickGatherHook
	{
		private static void Postfix(IInteractionAgent interactionAgent, int __result)
		{
			try
			{
				if (__result > 0 && (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)))
				{
					object obj;
					if (interactionAgent == null)
					{
						obj = null;
					}
					else
					{
						PlayerInteractionAgent obj2 = ((Il2CppObjectBase)interactionAgent).TryCast<PlayerInteractionAgent>();
						obj = ((obj2 != null) ? obj2.GetCharacter() : null);
					}
					PlayerCharacter val = (PlayerCharacter)obj;
					if ((Object)(object)val != (Object)null)
					{
						Plugin.Behaviour?.QuickPickup(((Component)val).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox quick gather skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch]
	internal static class FoxTakeItemsHook
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from m in AccessTools.GetDeclaredMethods(typeof(CharacterInventory))
				where m.Name == "TakeItems"
				select m;
		}

		private static void Postfix(CharacterInventory __instance, int __result)
		{
			try
			{
				if (__result > 0)
				{
					Character character = __instance.character;
					PlayerCharacter val = ((character != null) ? ((Il2CppObjectBase)character).TryCast<PlayerCharacter>() : null);
					if ((Object)(object)val != (Object)null)
					{
						Plugin.Behaviour?.QuickPickup(((Component)val).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox take-items animation skipped: " + ex.Message));
			}
		}
	}
	internal enum AnimalPropKind
	{
		Pickup,
		Craft
	}
	internal sealed class AnimalPropLifetime
	{
		internal const float PickupSeconds = 1f;

		private float _expires;

		internal AnimalPropKind Kind { get; private set; }

		internal AnimalPropLifetime(AnimalPropKind kind, float now)
		{
			Kind = kind;
			_expires = now + ((kind == AnimalPropKind.Pickup) ? 1f : 0.25f);
		}

		internal void Observe(AnimalPropKind kind, float now)
		{
			if (kind == AnimalPropKind.Craft)
			{
				Kind = kind;
				_expires = now + 0.25f;
			}
		}

		internal bool Expired(float now)
		{
			return now >= _expires;
		}
	}
	internal sealed class AnimalPropSet
	{
		private sealed class Entry
		{
			internal GameObject Item;

			internal Transform Parent;

			internal AnimalPropLifetime Lifetime;

			internal AnimalHeldItem Binding = new AnimalHeldItem();
		}

		private readonly Dictionary<int, Entry> _items = new Dictionary<int, Entry>();

		private readonly List<int> _expired = new List<int>();

		private readonly Dictionary<int, GameObject> _retired = new Dictionary<int, GameObject>();

		internal void Add(GameObject item, AnimalPropKind kind)
		{
			if ((Object)(object)item == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)item).GetInstanceID();
			if (!_retired.TryGetValue(instanceID, out var value) || !((Object)(object)value == (Object)(object)item) || kind != AnimalPropKind.Pickup)
			{
				if (_items.TryGetValue(instanceID, out var value2))
				{
					value2.Lifetime.Observe(kind, Time.time);
					return;
				}
				Entry entry = new Entry
				{
					Item = item,
					Parent = item.transform.parent,
					Lifetime = new AnimalPropLifetime(kind, Time.time)
				};
				entry.Binding.Observe(item);
				_items[instanceID] = entry;
			}
		}

		internal bool Owns(Renderer renderer)
		{
			foreach (Entry value in _items.Values)
			{
				if (value.Binding.Owns(renderer))
				{
					return true;
				}
			}
			return false;
		}

		internal void Exclude(GameObject item)
		{
			if (!((Object)(object)item == (Object)null))
			{
				int instanceID = ((Object)item).GetInstanceID();
				if (_items.TryGetValue(instanceID, out var value))
				{
					value.Binding.Release();
					_items.Remove(instanceID);
				}
				_retired[instanceID] = item;
			}
		}

		internal void Place(WolfVisual visual, bool working)
		{
			_expired.Clear();
			foreach (KeyValuePair<int, Entry> item in _items)
			{
				Entry value = item.Value;
				if ((Object)(object)value.Item == (Object)null || !value.Item.activeInHierarchy || (Object)(object)value.Item.transform.parent != (Object)(object)value.Parent || value.Lifetime.Expired(Time.time))
				{
					if ((Object)(object)value.Item != (Object)null)
					{
						_retired[item.Key] = value.Item;
					}
					value.Binding.Release(Plugin.HideEquipment.Value);
					_expired.Add(item.Key);
				}
				else
				{
					bool flag = value.Lifetime.Kind == AnimalPropKind.Craft && working;
					value.Binding.Place(visual.ItemSocket(flag), flag ? 90 : 180);
				}
			}
			foreach (int item2 in _expired)
			{
				_items.Remove(item2);
			}
			_expired.Clear();
			foreach (KeyValuePair<int, GameObject> item3 in _retired)
			{
				if ((Object)(object)item3.Value == (Object)null)
				{
					_expired.Add(item3.Key);
				}
			}
			foreach (int item4 in _expired)
			{
				_retired.Remove(item4);
			}
		}

		internal void Release()
		{
			foreach (Entry value in _items.Values)
			{
				value.Binding.Release();
			}
			_items.Clear();
			_retired.Clear();
		}
	}
	internal static class FoxActionMapping
	{
		private static readonly HashSet<string> WorkActions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"Craft", "Gather", "GatherLow", "GatherMiddle", "GatherHigh", "Harvest", "Skinning", "Anvil", "Carpentry", "Build",
			"Shovel", "Till", "Grinding", "Cooking", "Forge", "Bellows", "Painting"
		};

		internal static string Action(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return null;
			}
			string text = name.Trim().TrimStart('_').Replace(" ", "")
				.Replace("_", "");
			if (text.StartsWith("Pickup", StringComparison.OrdinalIgnoreCase))
			{
				return "fox_pickup";
			}
			if (text.Equals("Chop", StringComparison.OrdinalIgnoreCase) || text.Equals("ChopGround", StringComparison.OrdinalIgnoreCase))
			{
				return "wolf_attack1";
			}
			if (!WorkActions.Contains(text))
			{
				return null;
			}
			return "fox_dig";
		}

		internal static bool ImpactHarvest(string moveset)
		{
			return !(moveset?.Contains("Skinning", StringComparison.OrdinalIgnoreCase) ?? false);
		}
	}
	internal static class FoxCamera
	{
		[HarmonyPatch(typeof(InputManager), "UpdateCamera")]
		private static class UpdateCamera
		{
			private static void Postfix(InputManager __instance)
			{
				try
				{
					Refresh(__instance);
				}
				catch (Exception ex)
				{
					Reset();
					Plugin.Logger.LogWarning((object)("Fox camera offset skipped: " + ex.Message));
				}
			}
		}

		private static readonly Dictionary<int, (Cinemachine3rdPersonFollow follow, Vector3 original)> Saved = new Dictionary<int, (Cinemachine3rdPersonFollow, Vector3)>();

		private static InputManager _manager;

		private static void Apply(CameraObject camera)
		{
			//IL_0043: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			Cinemachine3rdPersonFollow val = ((camera != null) ? camera.baseComp : null);
			if (!((Object)(object)val == (Object)null))
			{
				int instanceID = ((Object)val).GetInstanceID();
				if (!Saved.TryGetValue(instanceID, out (Cinemachine3rdPersonFollow, Vector3) value) || (Object)(object)value.Item1 != (Object)(object)val)
				{
					value = (Saved[instanceID] = (val, val.ShoulderOffset));
				}
				Vector3 item = value.Item2;
				item.y += Plugin.CameraHeightOffset.Value;
				val.ShoulderOffset = item;
			}
		}

		internal static void Reset()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			foreach (var value in Saved.Values)
			{
				if ((Object)(object)value.follow != (Object)null)
				{
					value.follow.ShoulderOffset = value.original;
				}
			}
			Saved.Clear();
			_manager = null;
		}

		private static void Refresh(InputManager manager)
		{
			if ((Object)(object)_manager != (Object)(object)manager)
			{
				Reset();
			}
			_manager = manager;
			if (Plugin.Behaviour?.LocalCameraVisual == null || Plugin.CameraHeightOffset.Value == 0f)
			{
				Reset();
				return;
			}
			Apply(manager.normalCamera);
			Apply(manager.aimCamera);
			Apply(manager.climbingCamera);
			Apply(manager.lockCamera);
			Apply(manager.buildCamera);
			Apply(manager.insideBuildingCamera);
			Apply(manager.caveCamera);
		}
	}
	internal sealed class FoxConsumeAnimation
	{
		private string _clip;

		private float _remaining;

		internal bool Active => _remaining > 0f;

		internal static string Classify(string action, string moveset)
		{
			if (string.Equals(action, "Drink", StringComparison.OrdinalIgnoreCase) || (moveset != null && moveset.StartsWith("Moveset_Drink", StringComparison.OrdinalIgnoreCase)))
			{
				return "fox_drink";
			}
			if (string.Equals(action, "Eat", StringComparison.OrdinalIgnoreCase) || (moveset != null && moveset.StartsWith("Moveset_Eat", StringComparison.OrdinalIgnoreCase)))
			{
				return "fox_eat";
			}
			return null;
		}

		internal void Begin(string clip, float duration)
		{
			if (!(clip != "fox_eat") || !(clip != "fox_drink"))
			{
				_clip = clip;
				_remaining = ((float.IsFinite(duration) && duration > 0f) ? Math.Clamp(duration, 1.2f, 5f) : 2.5f);
			}
		}

		internal string Tick(float delta, bool interrupted)
		{
			if (interrupted)
			{
				Reset();
			}
			_remaining = Math.Max(0f, _remaining - Math.Max(0f, delta));
			if (!(_remaining > 0f))
			{
				return null;
			}
			return _clip;
		}

		internal void Reset()
		{
			_clip = null;
			_remaining = 0f;
		}
	}
	internal static class FoxConsumeHooks
	{
		[HarmonyPatch(typeof(Consumable), "_TryPlayConsumeAnimation")]
		private static class ConsumeStarted
		{
			private static void Postfix(Consumable __instance, GameObject owner, bool __result)
			{
				if (__result)
				{
					Notify(__instance, owner);
				}
			}
		}

		[HarmonyPatch(typeof(Consumable), "_ApplyEffect")]
		private static class ConsumeApplied
		{
			private static void Postfix(Consumable __instance, StatusEffectManager sem)
			{
				if ((Object)(object)sem != (Object)null)
				{
					Notify(__instance, ((Component)sem).gameObject);
				}
			}
		}

		[HarmonyPatch(typeof(ConsumableDisplayer), "ShowConsumableItem")]
		private static class ConsumableShown
		{
			private static void Postfix(ConsumableDisplayer __instance)
			{
				try
				{
					Plugin.Behaviour?.ConsumptionDisplay(__instance);
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("Animal food display skipped: " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(ConsumableDisplayer), "_RefreshShowingConsumable")]
		private static class ConsumableRefreshed
		{
			private static void Postfix(ConsumableDisplayer __instance)
			{
				try
				{
					Plugin.Behaviour?.ConsumptionDisplay(__instance);
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("Animal food display refresh skipped: " + ex.Message));
				}
			}
		}

		private static void Notify(Consumable item, GameObject owner)
		{
			try
			{
				if (item == null || (Object)(object)owner == (Object)null)
				{
					return;
				}
				ConsumableInfo consumableInfo = item.ConsumableInfo;
				InteractionMoveset val = ((consumableInfo != null) ? consumableInfo.moveSet : null);
				if (!((Object)(object)val == (Object)null))
				{
					string text = FoxConsumeAnimation.Classify(val.attackActionName, ((Object)val).name);
					if (text != null)
					{
						Plugin.Behaviour?.Consume(owner, text, val.displayDuration);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox consume visual skipped: " + ex.Message));
			}
		}
	}
	internal static class FoxCoop
	{
		[HarmonyPatch(typeof(NetworkRunner), "Fusion_Simulation_ICallbacks_OnReliableData")]
		private static class ReliableData
		{
			private static bool Prefix(NetworkRunner __instance, PlayerRef __0, Il2CppStructArray<byte> __1)
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				if (__1 == null || ((Il2CppArrayBase<byte>)(object)__1).Length < FoxCoopProtocol.Magic.Length)
				{
					return true;
				}
				for (int i = 0; i < FoxCoopProtocol.Magic.Length; i++)
				{
					if (((Il2CppArrayBase<byte>)(object)__1)[i] != FoxCoopProtocol.Magic[i])
					{
						return true;
					}
				}
				try
				{
					if (((Il2CppArrayBase<byte>)(object)__1).Length == 48)
					{
						Receive(__instance, __0, ((IEnumerable<byte>)__1).ToArray());
					}
				}
				catch (Exception ex)
				{
					TransportError(ex);
				}
				return false;
			}
		}

		internal static PlayerManager Manager;

		private static NetworkRunner _runner;

		private static readonly FoxCoopStateBuffer Buffer = new FoxCoopStateBuffer();

		private static readonly Dictionary<int, FoxMovement> Movement = new Dictionary<int, FoxMovement>();

		private static readonly HashSet<int> Seen = new HashSet<int>();

		private static readonly HashSet<int> Warned = new HashSet<int>();

		private static readonly Dictionary<int, float> Waiting = new Dictionary<int, float>();

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

		private static float _nextSend;

		private static float _nextScan;

		private static uint _sequence;

		private static bool _loggedTransportError;

		private static Dictionary<int, (FoxNetState state, float received)> States => Buffer.Entries;

		internal static PlayerCharacter Local
		{
			get
			{
				PlayerEntity instance = PlayerEntity.Instance;
				if (instance == null)
				{
					return null;
				}
				PlayerInteractionAgent agent = instance.Agent;
				if (agent == null)
				{
					return null;
				}
				return agent.GetCharacter();
			}
		}

		internal static PlayerInteractionAgent Agent(PlayerCharacter player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			PlayerManager manager = Manager;
			if (((manager != null) ? manager._players : null) != null)
			{
				foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players)
				{
					if ((Object)(object)((item != null) ? item.playerCharacter : null) == (Object)(object)player)
					{
						IInteractionAgent playerInteractionAgent = item.playerInteractionAgent;
						PlayerInteractionAgent val = ((playerInteractionAgent != null) ? ((Il2CppObjectBase)playerInteractionAgent).TryCast<PlayerInteractionAgent>() : null);
						if ((Object)(object)val != (Object)null)
						{
							return val;
						}
					}
				}
			}
			PlayerEntity instance = PlayerEntity.Instance;
			PlayerInteractionAgent val2 = ((instance != null) ? instance.Agent : null);
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetCharacter() == (Object)(object)player)
			{
				return val2;
			}
			return ((Component)player).GetComponent<PlayerInteractionAgent>() ?? ((Component)player).GetComponentInChildren<PlayerInteractionAgent>(true);
		}

		internal static IEnumerable<PlayerCharacter> Players()
		{
			PlayerManager manager = Manager;
			if (((manager != null) ? manager._players : null) == null)
			{
				yield break;
			}
			foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players)
			{
				if ((Object)(object)((item != null) ? item.playerCharacter : null) != (Object)null && (Object)(object)item.playerObject != (Object)null && item.playerObject.IsValid)
				{
					yield return item.playerCharacter;
				}
			}
		}

		internal static bool MaySimulate(PlayerCharacter player)
		{
			NetworkObject val = ((player != null) ? ((Character)player).NetworkObject : null);
			if ((Object)(object)player != (Object)null)
			{
				if (!((Character)player).HasAuthority)
				{
					if ((Object)(object)val != (Object)null && val.IsValid)
					{
						if (!val.HasStateAuthority)
						{
							return val.HasInputAuthority;
						}
						return true;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		internal static bool TryState(PlayerCharacter player, out FoxNetState state, out float age)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			state = default(FoxNetState);
			age = 0f;
			NetworkObject val = ((player != null) ? ((Character)player).NetworkObject : null);
			if ((Object)(object)val == (Object)null || !val.IsValid)
			{
				return false;
			}
			foreach (var value in States.Values)
			{
				if (value.state.ObjectId == val.Id.Raw)
				{
					state = value.state;
					age = Time.unscaledTime - value.received;
					return true;
				}
			}
			return false;
		}

		internal static void Tick()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Expected O, but got Unknown
			PlayerManager manager = Manager;
			object obj;
			if (manager == null)
			{
				obj = null;
			}
			else
			{
				NetworkSession session = manager._session;
				obj = ((session != null) ? session.runner : null);
			}
			NetworkRunner val = (NetworkRunner)obj;
			if ((Object)(object)val == (Object)null || !val.IsRunning)
			{
				if ((Object)(object)_runner != (Object)null)
				{
					Plugin.Behaviour?.ClearPlayers();
					Reset();
				}
				return;
			}
			bool flag = default(bool);
			PlayerRef val3;
			if ((Object)(object)val != (Object)(object)_runner)
			{
				Plugin.Behaviour?.ClearPlayers();
				Reset();
				_runner = val;
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(51, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Fox co-op session: mode=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<GameMode>(val.GameMode);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", local player=");
					val3 = val.LocalPlayer;
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(((PlayerRef)(ref val3)).RawEncoded);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", protocol=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<byte>((byte)1);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
				}
				logger.LogInfo(val2);
			}
			if (Time.unscaledTime < _nextScan)
			{
				return;
			}
			_nextScan = Time.unscaledTime + 0.25f;
			Seen.Clear();
			foreach (PlayerCharacter item in Players())
			{
				int instanceID = ((Object)item).GetInstanceID();
				Seen.Add(instanceID);
				if (!Movement.TryGetValue(instanceID, out var value))
				{
					value = (Movement[instanceID] = new FoxMovement());
				}
				value.Tick(item);
				if (WolfSelection.IsFox(item) && MaySimulate(item))
				{
					WolfStats.EnsureSimulationProfile(item);
				}
			}
			Removed.Clear();
			foreach (KeyValuePair<int, FoxMovement> item2 in Movement)
			{
				if (!Seen.Contains(item2.Key))
				{
					item2.Value.Dispose();
					Removed.Add(item2.Key);
				}
			}
			foreach (int item3 in Removed)
			{
				Movement.Remove(item3);
			}
			Removed.Clear();
			foreach (KeyValuePair<int, (FoxNetState, float)> state in States)
			{
				if ((Object)(object)Find(state.Key, state.Value.Item1.ObjectId) == (Object)null)
				{
					Removed.Add(state.Key);
				}
			}
			foreach (int item4 in Removed)
			{
				States.Remove(item4);
			}
			PlayerManager manager2 = Manager;
			if (((manager2 != null) ? manager2._players : null) == null || _runner.IsSinglePlayer)
			{
				return;
			}
			foreach (Player item5 in (Il2CppArrayBase<Player>)(object)Manager._players)
			{
				if ((Object)(object)((item5 != null) ? item5.playerObject : null) == (Object)null || !item5.playerObject.IsValid || item5.reference == _runner.LocalPlayer)
				{
					continue;
				}
				val3 = item5.reference;
				int rawEncoded = ((PlayerRef)(ref val3)).RawEncoded;
				float value2;
				if (States.ContainsKey(rawEncoded))
				{
					Waiting.Remove(rawEncoded);
				}
				else if (!Waiting.TryGetValue(rawEncoded, out value2))
				{
					Waiting[rawEncoded] = Time.unscaledTime;
				}
				else if (Time.unscaledTime - value2 > 20f && Warned.Add(rawEncoded))
				{
					ManualLogSource logger2 = Plugin.Logger;
					BepInExWarningLogInterpolatedStringHandler val4 = new BepInExWarningLogInterpolatedStringHandler(111, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Fox co-op: no compatible state from player ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(rawEncoded);
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(". Both players need ASKA Fox ");
						((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>("0.6.3");
						((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("; inspect both logs if it is installed.");
					}
					logger2.LogWarning(val4);
				}
			}
		}

		internal static void Send(WolfController local)
		{
			//IL_005b: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_00f2: Invalid comparison between Unknown and I4
			if ((Object)(object)_runner == (Object)null || !_runner.IsRunning || _runner.IsSinglePlayer || Time.unscaledTime < _nextSend)
			{
				return;
			}
			PlayerCharacter local2 = Local;
			NetworkObject val = ((local2 != null) ? ((Character)local2).NetworkObject : null);
			if ((Object)(object)val == (Object)null || !val.IsValid)
			{
				return;
			}
			PlayerRef localPlayer = _runner.LocalPlayer;
			if ((Object)(object)Find(((PlayerRef)(ref localPlayer)).RawEncoded, val.Id.Raw) != (Object)(object)local2)
			{
				return;
			}
			localPlayer = _runner.LocalPlayer;
			FoxNetState state = local.Snapshot(local2, ((PlayerRef)(ref localPlayer)).RawEncoded, val.Id.Raw, ++_sequence);
			_nextSend = Time.unscaledTime + (state.Visible ? 0.1f : 1f);
			try
			{
				byte[] array = FoxCoopProtocol.Encode(state);
				if (_runner.IsServer || (int)_runner.GameMode == 2)
				{
					localPlayer = _runner.LocalPlayer;
					Broadcast(array, ((PlayerRef)(ref localPlayer)).RawEncoded);
				}
				else
				{
					_runner.SendReliableDataToServer(Il2CppStructArray<byte>.op_Implicit(array));
				}
			}
			catch (Exception ex)
			{
				TransportError(ex);
			}
		}

		private static PlayerCharacter Find(int owner, uint objectId)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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)
			PlayerManager manager = Manager;
			if (((manager != null) ? manager._players : null) == null)
			{
				return null;
			}
			foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players)
			{
				if (item != null)
				{
					PlayerRef reference = item.reference;
					if (((PlayerRef)(ref reference)).RawEncoded == owner && (Object)(object)item.playerObject != (Object)null && item.playerObject.IsValid && item.playerObject.Id.Raw == objectId)
					{
						return item.playerCharacter;
					}
				}
			}
			return null;
		}

		private static void Broadcast(byte[] bytes, int exceptOwner)
		{
			//IL_004f: 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)
			//IL_0066: 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)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			PlayerManager manager = Manager;
			if (((manager != null) ? manager._players : null) == null)
			{
				return;
			}
			foreach (Player item in (Il2CppArrayBase<Player>)(object)Manager._players)
			{
				if ((Object)(object)((item != null) ? item.playerObject : null) != (Object)null && item.playerObject.IsValid && item.reference != _runner.LocalPlayer)
				{
					PlayerRef reference = item.reference;
					if (((PlayerRef)(ref reference)).RawEncoded != exceptOwner)
					{
						_runner.SendReliableDataToPlayer(item.reference, Il2CppStructArray<byte>.op_Implicit(bytes));
					}
				}
			}
		}

		private static void Receive(NetworkRunner runner, PlayerRef sender, byte[] bytes)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Invalid comparison between Unknown and I4
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: 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_00b7: 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_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			if ((Object)(object)runner == (Object)null || (Object)(object)runner != (Object)(object)_runner || !runner.IsRunning)
			{
				return;
			}
			if (!FoxCoopProtocol.TryDecode(bytes, out var state))
			{
				if (Warned.Add(-((PlayerRef)(ref sender)).RawEncoded - 1000))
				{
					Plugin.Logger.LogWarning((object)"Fox co-op rejected incompatible or malformed state. Install matching Fox builds on every peer.");
				}
				return;
			}
			PlayerRef val;
			int num;
			if (!runner.IsServer && (int)runner.GameMode != 2)
			{
				if (!((PlayerRef)(ref sender)).IsNone)
				{
					val = sender;
					PlayerManager manager = Manager;
					PlayerRef? obj;
					if (manager == null)
					{
						obj = null;
					}
					else
					{
						Player masterPlayer = manager.MasterPlayer;
						obj = ((masterPlayer != null) ? new PlayerRef?(masterPlayer.reference) : ((PlayerRef?)null));
					}
					PlayerRef? val2 = obj;
					num = ((val2.HasValue && val == val2.GetValueOrDefault()) ? 1 : 0);
				}
				else
				{
					num = 1;
				}
			}
			else
			{
				num = 0;
			}
			bool serverRelay = (byte)num != 0;
			PlayerCharacter val3 = Find(state.Owner, state.ObjectId);
			if ((Object)(object)val3 == (Object)null)
			{
				return;
			}
			int owner = state.Owner;
			val = runner.LocalPlayer;
			if (owner == ((PlayerRef)(ref val)).RawEncoded || !FoxCoopProtocol.MatchesOwner(((PlayerRef)(ref sender)).RawEncoded, state.Owner, state.ObjectId, state.Owner, ((Character)val3).NetworkObject.Id.Raw, serverRelay) || !Buffer.Accept(state, Time.unscaledTime, out var first))
			{
				return;
			}
			WolfSelection.SetIdentity(val3, state.Fox, new FoxPalette(state.Coat, state.Eye));
			if (first)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(58, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Fox co-op recognized player ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(state.Owner);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", object ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<uint>(state.ObjectId);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(": Fox=");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<bool>(state.Fox);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", coat=");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<byte>(state.Coat);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", eyes=");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<byte>(state.Eye);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(".");
				}
				logger.LogInfo(val4);
			}
			if (runner.IsServer)
			{
				Broadcast(bytes, state.Owner);
			}
		}

		internal static void Reset()
		{
			foreach (FoxMovement value in Movement.Values)
			{
				value.Dispose();
			}
			Movement.Clear();
			States.Clear();
			Seen.Clear();
			Waiting.Clear();
			Warned.Clear();
			_runner = null;
			_nextScan = (_nextSend = 0f);
			_sequence = 0u;
			_loggedTransportError = false;
		}

		private static void TransportError(Exception ex)
		{
			if (!_loggedTransportError)
			{
				_loggedTransportError = true;
				Plugin.Logger.LogError((object)("Fox co-op transport error; local gameplay remains active: " + ex));
			}
		}
	}
	internal readonly record struct FoxNetState(int Owner, uint ObjectId, uint Sequence, bool Fox, bool Visible, byte Coat, byte Eye, byte Clip, uint Animation, float Time, float Yaw, float Hit);
	internal static class FoxCoopProtocol
	{
		internal const byte Version = 1;

		internal const int Size = 48;

		internal static readonly byte[] Magic = new byte[8] { 65, 83, 75, 65, 70, 79, 88, 0 };

		internal static readonly string[] Clips = new string[27]
		{
			"wolf_idle", "wolf_walk", "wolf_trot", "wolf_sprint", "wolf_attack1", "wolf_death", "wolf_dodge", "fox_scurry", "fox_jump_takeoff", "fox_jump_air",
			"fox_jump_fall", "fox_jump_land", "fox_hit", "fox_dig", "fox_pickup", "fox_drink", "fox_eat", "fox_lie_down", "fox_sleep", "fox_wake",
			"fox_sit_down", "fox_sit", "fox_sit_up", "fox_emote_wave", "fox_emote_cheer", "fox_emote_wave_seated", "fox_emote_cheer_seated"
		};

		internal static byte ClipId(string clip)
		{
			int val = Array.IndexOf(Clips, clip);
			return (byte)Math.Max(0, val);
		}

		internal static bool IsOurs(ReadOnlySpan<byte> data)
		{
			if (data.Length >= Magic.Length)
			{
				return data.Slice(0, Magic.Length).SequenceEqual(Magic);
			}
			return false;
		}

		internal static bool Newer(uint incoming, uint current)
		{
			return (int)(incoming - current) > 0;
		}

		internal static bool MatchesOwner(int sender, int claimedOwner, uint claimedObject, int actualOwner, uint actualObject, bool serverRelay)
		{
			if (claimedObject != 0 && claimedObject == actualObject && claimedOwner == actualOwner)
			{
				if (!serverRelay)
				{
					return sender == actualOwner;
				}
				return true;
			}
			return false;
		}

		internal static byte[] Encode(FoxNetState state)
		{
			byte[] array = new byte[48];
			Magic.CopyTo(array, 0);
			array[8] = 1;
			array[9] = (byte)((state.Fox ? 1u : 0u) | (uint)(state.Visible ? 2 : 0));
			array[10] = state.Coat;
			array[11] = state.Eye;
			array[12] = state.Clip;
			BinaryPrimitives.WriteInt32LittleEndian(array.AsSpan(16), state.Owner);
			BinaryPrimitives.WriteUInt32LittleEndian(array.AsSpan(20), state.ObjectId);
			BinaryPrimitives.WriteUInt32LittleEndian(array.AsSpan(24), state.Sequence);
			BinaryPrimitives.WriteUInt32LittleEndian(array.AsSpan(28), state.Animation);
			WriteFloat(array, 32, state.Time);
			WriteFloat(array, 36, state.Yaw);
			WriteFloat(array, 40, state.Hit);
			return array;
		}

		private static void WriteFloat(byte[] bytes, int offset, float value)
		{
			BinaryPrimitives.WriteInt32LittleEndian(bytes.AsSpan(offset), BitConverter.SingleToInt32Bits(value));
		}

		private static float ReadFloat(ReadOnlySpan<byte> bytes, int offset)
		{
			return BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(offset)));
		}

		internal static bool TryDecode(ReadOnlySpan<byte> data, out FoxNetState state)
		{
			state = default(FoxNetState);
			if (data.Length != 48 || !IsOurs(data) || data[8] != 1 || data[9] > 3 || data[10] >= FoxPalette.Coats.Length || data[11] >= FoxPalette.Eyes.Length || data[12] >= Clips.Length)
			{
				return false;
			}
			if (data[13] != 0 || data[14] != 0 || data[15] != 0 || BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(44)) != 0)
			{
				return false;
			}
			int num = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16));
			uint num2 = BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(20));
			float num3 = ReadFloat(data, 32);
			float num4 = ReadFloat(data, 36);
			float num5 = ReadFloat(data, 40);
			if (num <= 0 || num2 == 0 || !float.IsFinite(num3) || num3 < 0f || num3 > 120f || !float.IsFinite(num4) || num4 < 0f || num4 > 360f || !float.IsFinite(num5) || num5 < 0f || num5 > 0.7f)
			{
				return false;
			}
			state = new FoxNetState(num, num2, BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(24)), (data[9] & 1) != 0, (data[9] & 2) != 0, data[10], data[11], data[12], BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(28)), num3, num4, num5);
			return true;
		}
	}
	internal sealed class FoxCoopStateBuffer
	{
		internal readonly Dictionary<int, (FoxNetState state, float received)> Entries = new Dictionary<int, (FoxNetState, float)>();

		internal bool Accept(FoxNetState state, float now, out bool first)
		{
			first = !Entries.TryGetValue(state.Owner, out (FoxNetState, float) value) || value.Item1.ObjectId != state.ObjectId;
			if (!first && !FoxCoopProtocol.Newer(state.Sequence, value.Item1.Sequence))
			{
				return false;
			}
			Entries[state.Owner] = (state, now);
			return true;
		}

		internal void Clear()
		{
			Entries.Clear();
		}
	}
	internal static class FoxCustomization
	{
		[HarmonyPatch(typeof(CharacterSelectionTabPage), "ResetSelectedPreset")]
		private static class ResetFoxColors
		{
			private static bool Prefix(CharacterSelectionTabPage __instance)
			{
				CharacterDisplaySetup selectedCharacterSetup = __instance._selectedCharacterSetup;
				if ((Object)(object)((selectedCharacterSetup != null) ? selectedCharacterSetup.characterDefinition : null) != (Object)(object)WolfSelection.FoxDefinition)
				{
					return true;
				}
				Selected = default(FoxPalette);
				return false;
			}
		}

		internal const string CoatKey = "com.aska.fox.coat.v1";

		internal const string EyeKey = "com.aska.fox.eyes.v1";

		private static ConfigEntry<int> _coat;

		private static ConfigEntry<int> _eye;

		private static readonly Dictionary<int, (PlayerCharacter owner, FoxPalette colors)> Players = new Dictionary<int, (PlayerCharacter, FoxPalette)>();

		internal static FoxPalette? Loaded;

		internal static FoxPalette Selected
		{
			get
			{
				return new FoxPalette(_coat?.Value ?? 0, _eye?.Value ?? 0);
			}
			set
			{
				_coat.Value = value.Coat;
				_eye.Value = value.Eye;
				Loaded = null;
			}
		}

		internal static void Configure(ConfigFile config)
		{
			_coat = config.Bind<int>("Customization", "NewFoxCoat", 0, "New Fox default: 0 Red, 1 Gold, 2 Silver, 3 Arctic, 4 Brown, 5 Black. Saved Fox colors are independent.");
			_eye = config.Bind<int>("Customization", "NewFoxEyes", 0, "New Fox default: 0 Green, 1 Amber, 2 Blue, 3 Brown, 4 Gray, 5 Violet.");
		}

		internal static FoxPalette Read(DataObject record)
		{
			return new FoxPalette(ReadIndex(record, "com.aska.fox.coat.v1"), ReadIndex(record, "com.aska.fox.eyes.v1"));
		}

		private static int ReadIndex(DataObject record, string key)
		{
			DataElement val = default(DataElement);
			if (record == null || !record.TryGetElement(key, ref val))
			{
				return 0;
			}
			int? obj;
			if (val == null)
			{
				obj = null;
			}
			else
			{
				DataElementInt obj2 = ((Il2CppObjectBase)val).TryCast<DataElementInt>();
				obj = ((obj2 != null) ? new int?(obj2.value) : ((int?)null));
			}
			int? num = obj;
			return num.GetValueOrDefault();
		}

		internal static void Write(DataObject record, FoxPalette colors)
		{
			record.AddElement("com.aska.fox.coat.v1", DataElement.op_Implicit(colors.Coat));
			record.AddElement("com.aska.fox.eyes.v1", DataElement.op_Implicit(colors.Eye));
		}

		internal static void Register(PlayerCharacter player)
		{
			Players[((Object)player).GetInstanceID()] = (player, Loaded ?? Selected);
		}

		internal static void Register(PlayerCharacter player, FoxPalette palette)
		{
			Players[((Object)player).GetInstanceID()] = (player, palette);
		}

		internal static void Forget(PlayerCharacter player)
		{
			Players.Remove(((Object)player).GetInstanceID());
		}

		internal static FoxPalette For(PlayerCharacter player)
		{
			if (!((Object)(object)player != (Object)null) || !Players.TryGetValue(((Object)player).GetInstanceID(), out (PlayerCharacter, FoxPalette) value) || !((Object)(object)value.Item1 == (Object)(object)player))
			{
				return Selected;
			}
			return value.Item2;
		}
	}
	internal sealed class FoxCustomizationPanel : IDisposable
	{
		private GameObject _root;

		private IncreaseDecreasePanel _coat;

		private IncreaseDecreasePanel _eye;

		private readonly List<UnityAction> _callbacks = new List<UnityAction>();

		internal FoxCustomizationPanel(CharacterSelectionTabPage page)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00c4: 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)
			try
			{
				IncreaseDecreasePanel val = page.hairStylePanel ?? page.selectedPresetPanel;
				DropdownElement faceAndHairDropdown = page.faceAndHairDropdown;
				Transform val2 = ((faceAndHairDropdown != null) ? ((Component)faceAndHairDropdown).transform.parent : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					throw new InvalidOperationException("Fox customization template/container unavailable.");
				}
				_root = new GameObject("FoxColorCustomization");
				RectTransform obj = _root.AddComponent<RectTransform>();
				((Transform)obj).SetParent(val2, false);
				obj.anchorMin = new Vector2(0f, 1f);
				obj.anchorMax = new Vector2(1f, 1f);
				obj.pivot = new Vector2(0.5f, 1f);
				obj.sizeDelta = new Vector2(-24f, 176f);
				obj.anchoredPosition = new Vector2(0f, -12f);
				LayoutElement obj2 = _root.AddComponent<LayoutElement>();
				obj2.preferredHeight = 176f;
				obj2.minHeight = 176f;
				obj2.flexibleWidth = 1f;
				_coat = Row(val, "FoxCoatColor", -20f, coat: true);
				_eye = Row(val, "FoxEyeColor", -98f, coat: false);
				Refresh();
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		private IncreaseDecreasePanel Row(IncreaseDecreasePanel template, string name, float y, bool coat)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			IncreaseDecreasePanel val = Object.Instantiate<IncreaseDecreasePanel>(template, _root.transform, false);
			((Object)val).name = name;
			((Behaviour)val).enabled = false;
			val.group = null;
			val.AutomaticValueText = false;
			val.m_OnValueChanged = new IncreseDecreaseEvent();
			val.m_OnIncrease = new UnityEvent();
			val.m_OnDecrease = new UnityEvent();
			foreach (LocalizedText componentsInChild in ((Component)val).GetComponentsInChildren<LocalizedText>(true))
			{
				((Behaviour)componentsInChild).enabled = false;
				Object.Destroy((Object)(object)componentsInChild);
			}
			RectTransform component = ((Component)val).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.sizeDelta = new Vector2(-20f, 60f);
			component.anchoredPosition = new Vector2(0f, y);
			LayoutElement component2 = ((Component)val).GetComponent<LayoutElement>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.ignoreLayout = true;
			}
			((Component)val).gameObject.SetActive(true);
			Bind(val.IncreaseButton, delegate
			{
				Change(coat, 1);
			});
			Bind(val.DecreaseButton, delegate
			{
				Change(coat, -1);
			});
			if ((Object)(object)val.ValueText == (Object)null)
			{
				throw new InvalidOperationException("Fox color row has no value label.");
			}
			((TMP_Text)val.ValueText).enableAutoSizing = true;
			((TMP_Text)val.ValueText).fontSizeMin = 14f;
			((TMP_Text)val.ValueText).fontSizeMax = 22f;
			if ((Object)(object)val.Icon != (Object)null)
			{
				((Component)val.Icon).gameObject.SetActive(false);
			}
			if ((Object)(object)val.InputField != (Object)null)
			{
				((Component)val.InputField).gameObject.SetActive(false);
			}
			return val;
		}

		private void Bind(Button button, Action action)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			if ((Object)(object)button == (Object)null)
			{
				throw new InvalidOperationException("Fox color row has no arrow button.");
			}
			((Component)button).gameObject.SetActive(true);
			((Selectable)button).interactable = true;
			button.onClick = new ButtonClickedEvent();
			UnityAction val = UnityAction.op_Implicit(action);
			_callbacks.Add(val);
			((UnityEvent)button.onClick).AddListener(val);
		}

		private void Change(bool coat, int step)
		{
			WolfSelection.Guard("color selection", delegate
			{
				FoxCustomization.Selected = (coat ? FoxCustomization.Selected.ChangeCoat(step) : FoxCustomization.Selected.ChangeEye(step));
				Refresh();
			});
		}

		internal void Refresh()
		{
			FoxPalette selected = FoxCustomization.Selected;
			((TMP_Text)_coat.ValueText).text = "COAT: " + FoxPalette.Coats[selected.Coat];
			((TMP_Text)_eye.ValueText).text = "EYES: " + FoxPalette.Eyes[selected.Eye];
		}

		internal void Show(bool visible)
		{
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(visible);
			}
		}

		public void Dispose()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
			_callbacks.Clear();
		}
	}
	internal sealed class FoxDamageReaction
	{
		internal const float Duration = 0.7f;

		internal float Elapsed { get; private set; } = 0.7f;

		internal bool Active => Elapsed < 0.7f;

		internal bool Trigger(float damage, bool unavailable)
		{
			if (unavailable || !float.IsFinite(damage) || damage <= 0f || (Active && Elapsed < 0.15f))
			{
				return false;
			}
			Elapsed = 0f;
			return true;
		}

		internal void Tick(float delta)
		{
			Elapsed = Math.Min(0.7f, Elapsed + Math.Max(0f, delta));
		}

		internal void Reset()
		{
			Elapsed = 0.7f;
		}
	}
	internal static class FoxFirstPersonCompatibility
	{
		private sealed class LastView
		{
			internal int FoxAnchor;
		}

		private sealed class Swap
		{
			internal Transform Original;

			internal Transform Fox;
		}

		private static FieldInfo _head;

		private static FieldInfo _active;

		private static FieldInfo _stablePosition;

		private static FieldInfo _velocity;

		private static bool _warned;

		private static readonly ConditionalWeakTable<object, LastView> Views = new ConditionalWeakTable<object, LastView>();

		internal static void Install()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			//IL_01c5: Expected O, but got Unknown
			if (!Plugin.FirstPersonCompatibility.Value)
			{
				return;
			}
			Type type = null;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				type = assemblies[i].GetType("AskaFirstPerson.FirstPersonBehaviour", throwOnError: false);
				if (type != null)
				{
					break;
				}
			}
			if (type == null)
			{
				Plugin.Logger.LogInfo((object)"First-person mod absent; Fox camera compatibility is inactive.");
				return;
			}
			Harmony val = new Harmony("com.aska.wolfprototype.firstperson");
			try
			{
				_head = AccessTools.Field(type, "_headBone");
				_active = AccessTools.Field(type, "IsFirstPerson");
				_stablePosition = AccessTools.Field(type, "_stableBasePos");
				_velocity = AccessTools.Field(type, "_smoothVelocity");
				MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "LateUpdate", (Type[])null, (Type[])null);
				if (_head?.FieldType != typeof(Transform) || _head.IsStatic || _active?.FieldType != typeof(bool) || !_active.IsStatic || _stablePosition?.FieldType != typeof(Vector3) || _velocity?.FieldType != typeof(Vector3) || methodInfo == null || methodInfo.ReturnType != typeof(void) || methodInfo.GetParameters().Length != 0)
				{
					throw new InvalidOperationException("The installed first-person mod's camera API has changed.");
				}
				val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(FoxFirstPersonCompatibility), "BeforeCamera", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(FoxFirstPersonCompatibility), "AfterCamera", (Type[])null), (HarmonyMethod)null);
				Plugin.Logger.LogInfo((object)("First-person Fox head compatibility enabled for " + type.Assembly.GetName().Name + ". The mod retains its toggle and camera controls."));
			}
			catch (Exception ex)
			{
				val.UnpatchSelf();
				Plugin.Logger.LogWarning((object)("First-person compatibility disabled; native mod retained: " + ex.Message));
			}
		}

		private static void BeforeCamera(object __instance, out Swap __state)
		{
			//IL_00d0: 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)
			__state = null;
			try
			{
				bool num = (bool)_active.GetValue(null);
				object? value = _head.GetValue(__instance);
				Transform val = (Transform)((value is Transform) ? value : null);
				Transform val2 = ((!num || !Plugin.FirstPersonCompatibility.Value) ? null : Plugin.Behaviour?.LocalCameraVisual?.CameraHead);
				LastView value2 = Views.GetValue(__instance, (object _) => new LastView());
				int num2 = (((Object)(object)val2 != (Object)null) ? ((Object)val2).GetInstanceID() : 0);
				if (value2.FoxAnchor != num2)
				{
					Transform val3 = (((Object)(object)val2 != (Object)null) ? val2 : val);
					if ((Object)(object)val3 != (Object)null)
					{
						_stablePosition.SetValue(__instance, val3.position);
					}
					_velocity.SetValue(__instance, Vector3.zero);
					value2.FoxAnchor = num2;
				}
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val == (Object)null))
				{
					__state = new Swap
					{
						Original = val,
						Fox = val2
					};
					_head.SetValue(__instance, val2);
				}
			}
			catch (Exception ex)
			{
				if (!_warned)
				{
					_warned = true;
					Plugin.Logger.LogWarning((object)("First-person Fox anchor unavailable: " + ex.Message));
				}
			}
		}

		private static Exception AfterCamera(object __instance, Swap __state, Exception __exception)
		{
			if (__state != null)
			{
				try
				{
					object? value = _head.GetValue(__instance);
					if ((Object)((value is Transform) ? value : null) == (Object)(object)__state.Fox)
					{
						_head.SetValue(__instance, __state.Original);
					}
				}
				catch (Exception ex)
				{
					if (!_warned)
					{
						_warned = true;
						Plugin.Logger.LogWarning((object)("First-person head restoration failed: " + ex.Message));
					}
				}
			}
			return __exception;
		}
	}
	internal sealed class FoxFootsteps : IDisposable
	{
		[HarmonyPatch(typeof(AudioSurface), "PlayRandomClip")]
		private static class PawSample
		{
			private static bool Prefix(AudioSurface __instance, AudioSource __1, float __2)
			{
				if ((Object)(object)__1 != (Object)null && Owners.TryGetValue(((Object)__1).GetInstanceID(), out var value))
				{
					return !value.TryPlay(__instance, __1, __2);
				}
				return true;
			}
		}

		private static readonly Dictionary<int, FoxFootsteps> Owners = new Dictionary<int, FoxFootsteps>();

		private readonly Dictionary<int, FootPlantingPlayer> _sources = new Dictionary<int, FootPlantingPlayer>();

		private AudioSurface _paws;

		private FisherYatesRandom _random;

		private float _nextScan;

		private bool _failed;

		private bool _logged;

		internal void Tick(Character player, bool suspended)
		{
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			if (suspended || (Object)(object)player == (Object)null)
			{
				Dispose();
			}
			else
			{
				if (_failed || Time.unscaledTime < _nextScan)
				{
					return;
				}
				_nextScan = Time.unscaledTime + 1f;
				try
				{
					if ((Object)(object)_paws == (Object)null)
					{
						ItemInfo obj = Resources.Load<ItemInfo>("item_population_wolf");
						GameObject obj2 = ((obj != null) ? obj.spawnObject : null);
						FootPlantingPlayer val = ((obj2 != null) ? obj2.GetComponentInChildren<FootPlantingPlayer>(true) : null);
						_paws = ((val != null) ? val.defaultSurface : null);
						if ((Object)(object)_paws == (Object)null || ((Object)_paws).name != "defaultSurfaceDog" || _paws.audioClips == null || _paws.audioClips.Count == 0)
						{
							throw new InvalidOperationException("Native wolf paw clips unavailable.");
						}
						_random = new FisherYatesRandom();
					}
					Unregister();
					foreach (FootPlantingPlayer componentsInChild in ((Component)player).GetComponentsInChildren<FootPlantingPlayer>(true))
					{
						AudioSource footstepAudioSource = componentsInChild.footstepAudioSource;
						if ((Object)(object)footstepAudioSource != (Object)null)
						{
							_sources[((Object)footstepAudioSource).GetInstanceID()] = componentsInChild;
							Owners[((Object)footstepAudioSource).GetInstanceID()] = this;
						}
					}
					if (!_logged && _sources.Count > 0)
					{
						_logged = true;
						ManualLogSource logger = Plugin.Logger;
						bool flag = default(bool);
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(94, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Fox footsteps: ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_paws.audioClips.Count);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" native wolf paw clips on ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(_sources.Count);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" player footstep source(s); original timing retained.");
						}
						logger.LogInfo(val2);
					}
				}
				catch (Exception ex)
				{
					Fail(ex);
				}
			}
		}

		private bool TryPlay(AudioSurface surface, AudioSource source, float volume)
		{
			try
			{
				if (_failed || (Object)(object)_paws == (Object)null || (Object)(object)source == (Object)null || volume <= 0f || !_sources.TryGetValue(((Object)source).GetInstanceID(), out var value) || (Object)(object)value == (Object)null || (Object)(object)value.footstepAudioSource != (Object)(object)source || !((Component)value).gameObject.activeInHierarchy || value.IsUnderwater)
				{
					return false;
				}
				List<AudioClip> audioClips = _paws.audioClips;
				if (audioClips == null || audioClips.Count == 0)
				{
					return false;
				}
				AudioClip val = audioClips[_random.Next(audioClips.Count)];
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				if ((Object)(object)surface.audioMixerGroup != (Object)null)
				{
					source.outputAudioMixerGroup = surface.audioMixerGroup;
				}
				source.PlayOneShot(val, volume);
				return true;
			}
			catch (Exception ex)
			{
				Fail(ex);
				return false;
			}
		}

		private void Fail(Exception ex)
		{
			_failed = true;
			Dispose();
			Plugin.Logger.LogError((object)("Fox paw replacement disabled; native footsteps retained: " + ex));
		}

		private void Unregister()
		{
			foreach (int key in _sources.Keys)
			{
				if (Owners.TryGetValue(key, out var value) && value == this)
				{
					Owners.Remove(key);
				}
			}
			_sources.Clear();
		}

		public void Dispose()
		{
			Unregister();
			_sources.Clear();
			_paws = null;
			_random = null;
			_nextScan = 0f;
			_logged = false;
		}
	}
	internal static class FoxInteractionTracking
	{
		private static readonly Dictionary<IntPtr, (PlayerCharacter player, InteractionSession session)> Sessions = new Dictionary<IntPtr, (PlayerCharacter, InteractionSession)>();

		internal static IEnumerable<InteractionSession> For(PlayerCharacter player)
		{
			foreach (var value in Sessions.Values)
			{
				if ((Object)(object)value.player != (Object)null && (Object)(object)value.player == (Object)(object)player)
				{
					yield return value.session;
				}
			}
		}

		internal static void Track(PlayerInteractionAgent agent, InteractionSession session)
		{
			PlayerCharacter val = ((agent != null) ? agent.GetCharacter() : null);
			if ((Object)(object)val != (Object)null && session != null)
			{
				Sessions[((Il2CppObjectBase)session).Pointer] = (val, session);
			}
		}

		internal static void Forget(PlayerCharacter player)
		{
			List<IntPtr> list = new List<IntPtr>();
			foreach (KeyValuePair<IntPtr, (PlayerCharacter, InteractionSession)> session in Sessions)
			{
				if ((Object)(object)session.Value.Item1 == (Object)null || (Object)(object)session.Value.Item1 == (Object)(object)player)
				{
					list.Add(session.Key);
				}
			}
			foreach (IntPtr item in list)
			{
				Sessions.Remove(item);
			}
		}

		internal static void Release(InteractionSession session)
		{
			if (session != null)
			{
				Sessions.Remove(((Il2CppObjectBase)session).Pointer);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerInteractionAgent), "GetInteractionSession")]
	internal static class FoxSessionRentedHook
	{
		private static void Postfix(PlayerInteractionAgent __instance, InteractionSession __result)
		{
			try
			{
				FoxInteractionTracking.Track(__instance, __result);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox session tracking skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerInteractionAgent), "ClearInteractionSession")]
	internal static class FoxSessionReturnedHook
	{
		private static void Prefix(InteractionSession session)
		{
			FoxInteractionTracking.Release(session);
		}
	}
	internal sealed class FoxMovement : IDisposable
	{
		private CharacterMovement _movement;

		private MovementStats _original;

		private MovementStats _copy;

		private FloatParameterNode _sprintDrain;

		private bool _failed;

		internal void Tick(PlayerCharacter player)
		{
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Expected O, but got Unknown
			if (_failed)
			{
				return;
			}
			try
			{
				CharacterMovement val = ((player != null) ? player.GetCharacterMovement() : null);
				if (!WolfSelection.IsFox(player) || !FoxCoop.MaySimulate(player) || (Object)(object)val == (Object)null || !((Component)player).gameObject.activeInHierarchy || player.IsGhost || val.IsRaven)
				{
					Dispose();
				}
				else
				{
					if ((Object)(object)_movement == (Object)(object)val && (Object)(object)_copy != (Object)null && (Object)(object)val.parameters == (Object)(object)_copy)
					{
						return;
					}
					Dispose();
					if (!((Object)(object)val.parameters == (Object)null))
					{
						MovementStats parameters = val.parameters;
						MovementStats val2 = Object.Instantiate<MovementStats>(parameters);
						_movement = val;
						_original = parameters;
						_copy = val2;
						((Object)val2).name = "AskaFox_MovementProfile";
						val2.speed = 6f;
						val2.sprintMultiplier = 1.6666666f;
						FloatParameterReference sprintStaminaUsage = parameters.sprintStaminaUsage;
						if ((Object)(object)((sprintStaminaUsage != null) ? sprintStaminaUsage.parameter : null) == (Object)null)
						{
							throw new InvalidOperationException("Native sprint drain parameter missing.");
						}
						_sprintDrain = Object.Instantiate<FloatParameterNode>(sprintStaminaUsage.parameter);
						((Object)_sprintDrain).name = "AskaFox_SprintDrain";
						_sprintDrain.SetValue(16f);
						val2.sprintStaminaUsage = new FloatParameterReference
						{
							parameter = _sprintDrain
						};
						val.parameters = val2;
						ManualLogSource logger = Plugin.Logger;
						bool flag = default(bool);
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(76, 4, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Fox movement: base=");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(val2.speed);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", sprint=");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(val2.speed * val2.sprintMultiplier);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", sprint drain=");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(val2.sprintStaminaUsage.Value);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("/s (native=");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<float>(sprintStaminaUsage.Value);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("/s, before discounts).");
						}
						logger.LogInfo(val3);
					}
				}
			}
			catch (Exception ex)
			{
				_failed = true;
				try
				{
					Dispose();
				}
				catch
				{
				}
				Plugin.Logger.LogError((object)("Fox movement override disabled after failure: " + ex));
			}
		}

		public void Dispose()
		{
			if ((Object)(object)_movement != (Object)null && (Object)(object)_copy != (Object)null && (Object)(object)_movement.parameters == (Object)(object)_copy)
			{
				_movement.parameters = _original;
			}
			if ((Object)(object)_copy != (Object)null)
			{
				Object.Destroy((Object)(object)_copy);
			}
			if ((Object)(object)_sprintDrain != (Object)null)
			{
				Object.Destroy((Object)(object)_sprintDrain);
			}
			_sprintDrain = null;
			_movement = null;
			_original = null;
			_copy = null;
		}
	}
	internal sealed class FoxNameTag : IDisposable
	{
		private PlayerNameTag _tag;

		private Transform _parent;

		private Vector3 _position;

		internal static bool Owns(PlayerCharacter player, Renderer renderer)
		{
			PlayerNameTag val = ((player != null) ? player.nameTag : null);
			if ((Object)(object)val == (Object)null || (Object)(object)renderer == (Object)null)
			{
				return false;
			}
			Transform transform = ((Component)renderer).transform;
			if (!((Object)(object)transform == (Object)(object)((Component)val).transform) && !transform.IsChildOf(((Component)val).transform))
			{
				if ((Object)(object)val.nameText != (Object)null)
				{
					if (!((Object)(object)transform == (Object)(object)val.nameText.transform))
					{
						return transform.IsChildOf(val.nameText.transform);
					}
					return true;
				}
				return false;
			}
			return true;
		}

		internal void Tick(PlayerCharacter player, Transform mouth)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0071: 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)
			PlayerNameTag val = ((player != null) ? player.nameTag : null);
			if ((Object)(object)val != (Object)(object)_tag)
			{
				Dispose();
				if ((Object)(object)val != (Object)null)
				{
					_tag = val;
					_parent = ((Component)val).transform.parent;
					_position = ((Component)val).transform.localPosition;
				}
			}
			if (!((Object)(object)_tag == (Object)null) && !((Object)(object)mouth == (Object)null))
			{
				Vector3 position = mouth.position;
				position.y += 0.35f;
				((Component)_tag).transform.position = position;
			}
		}

		public void Dispose()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_tag != (Object)null && (Object)(object)((Component)_tag).transform.parent == (Object)(object)_parent)
			{
				((Component)_tag).transform.localPosition = _position;
			}
			_tag = null;
			_parent = null;
		}
	}
	internal static class FoxNativeDodge
	{
		private static readonly HashSet<int> States = new HashSet<int>
		{
			Animator.StringToHash("Base Layer.OneHandedLocomotion.Roll_OneHandedLocomotion"),
			Animator.StringToHash("Base Layer.OneHandedLocomotion.Dodge"),
			Animator.StringToHash("Base Layer.TwoHandedLocomotion.Roll_TwoHandedLocomotion"),
			Animator.StringToHash("Base Layer.TwoHandedLocomotion.Roll 0"),
			Animator.StringToHash("Base Layer.Bow.Roll_Bow")
		};

		internal static bool Read(Animator animator, out float phase, out int stateHash)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0049: 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)
			phase = 0f;
			stateHash = 0;
			if ((Object)(object)animator == (Object)null || animator.layerCount == 0)
			{
				return false;
			}
			AnimatorStateInfo val = animator.GetCurrentAnimatorStateInfo(0);
			if (animator.IsInTransition(0))
			{
				AnimatorStateInfo nextAnimatorStateInfo = animator.GetNextAnimatorStateInfo(0);
				if (States.Contains(((AnimatorStateInfo)(ref nextAnimatorStateInfo)).fullPathHash))
				{
					val = nextAnimatorStateInfo;
				}
			}
			if (!States.Contains(((AnimatorStateInfo)(ref val)).fullPathHash))
			{
				return false;
			}
			phase = Mathf.Clamp01(((AnimatorStateInfo)(ref val)).normalizedTime);
			stateHash = ((AnimatorStateInfo)(ref val)).fullPathHash;
			return true;
		}
	}
	internal static class FoxNativeEmotes
	{
		private static readonly Dictionary<int, string> States = new Dictionary<int, string>
		{
			[Animator.StringToHash("Actions.Emotes.sit_Emotes")] = "fox_sit_down",
			[Animator.StringToHash("Actions.Emotes.Sit Idle")] = "fox_sit",
			[Animator.StringToHash("Actions.Emotes.Sit Up")] = "fox_sit_up",
			[Animator.StringToHash("Actions.Emotes.Wave")] = "fox_emote_wave",
			[Animator.StringToHash("Actions.Emotes.Cheer")] = "fox_emote_cheer",
			[Animator.StringToHash("UpperBody.Wave Feast")] = "fox_emote_wave_seated",
			[Animator.StringToHash("UpperBody.Cheer Feast")] = "fox_emote_cheer_seated",
			[Animator.StringToHash("UpperBody.Skal Feast")] = "fox_emote_cheer_seated",
			[Animator.StringToHash("UpperBody.Skal")] = "fox_emote_cheer_seated",
			[Animator.StringToHash("Base Layer.SitAtTable.SitAtTable")] = "fox_sit"
		};

		internal static string Read(Animator animator, out float phase)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			phase = 0f;
			if ((Object)(object)animator == (Object)null)
			{
				return null;
			}
			string result = null;
			int num = -1;
			for (int i = 0; i < animator.layerCount; i++)
			{
				if (i > 0 && animator.GetLayerWeight(i) <= 0.001f)
				{
					continue;
				}
				AnimatorStateInfo val = animator.GetCurrentAnimatorStateInfo(i);
				if (animator.IsInTransition(i))
				{
					AnimatorStateInfo nextAnimatorStateInfo = animator.GetNextAnimatorStateInfo(i);
					if (States.ContainsKey(((AnimatorStateInfo)(ref nextAnimatorStateInfo)).fullPathHash))
					{
						val = nextAnimatorStateInfo;
					}
				}
				if (States.TryGetValue(((AnimatorStateInfo)(ref val)).fullPathHash, out var value))
				{
					int num2 = ((!value.StartsWith("fox_emote_")) ? 1 : 2);
					if (num2 > num)
					{
						result = value;
						num = num2;
						phase = ((value == "fox_sit") ? Mathf.Repeat(Mathf.Max(0f, ((AnimatorStateInfo)(ref val)).normalizedTime), 1f) : Mathf.Clamp01(((AnimatorStateInfo)(ref val)).normalizedTime));
					}
				}
			}
			return result;
		}
	}
	internal readonly record struct FoxPalette
	{
		internal int Coat { get; }

		internal int Eye { get; }

		internal static readonly string[] Coats = new string[6] { "Red", "Gold", "Silver", "Arctic", "Brown", "Black" };

		internal static readonly string[] Eyes = new string[6] { "Green", "Amber", "Blue", "Brown", "Gray", "Violet" };

		internal FoxPalette(int coat, int eye)
		{
			Coat = ((coat >= 0 && coat < Coats.Length) ? coat : 0);
			Eye = ((eye >= 0 && eye < Eyes.Length) ? eye : 0);
		}

		internal FoxPalette ChangeCoat(int delta)
		{
			return new FoxPalette((Coat + delta % Coats.Length + Coats.Length) % Coats.Length, Eye);
		}

		internal FoxPalette ChangeEye(int delta)
		{
			return new FoxPalette(Coat, (Eye + delta % Eyes.Length + Eyes.Length) % Eyes.Length);
		}

		[CompilerGenerated]
		private bool PrintMembers(StringBuilder builder)
		{
			return false;
		}
	}
	internal sealed class FoxPickupAnimation
	{
		internal const float Duration = 1.05f;

		private float _remaining;

		internal static bool ShouldInterrupt(bool confirmedTransfer, float speed, bool working, bool blocked)
		{
			if (!blocked)
			{
				if (!confirmedTransfer)
				{
					return speed > 1.2f || working;
				}
				return false;
			}
			return true;
		}

		internal bool Begin()
		{
			if (_remaining > 0f)
			{
				return false;
			}
			_remaining = 1.05f;
			return true;
		}

		internal bool Tick(float delta, bool interrupted)
		{
			if (interrupted)
			{
				Reset();
			}
			_remaining = Math.Max(0f, _remaining - Math.Max(0f, delta));
			return _remaining > 0f;
		}

		internal void Reset()
		{
			_remaining = 0f;
		}
	}
	[HarmonyPatch(typeof(PickupInteractionSession), "_WaitForAction")]
	internal static class FoxPickupHooks
	{
		private static void Postfix(PickupInteractionSession __instance, IEnumerator __result)
		{
			try
			{
				if (__result != null)
				{
					IInteractionAgent agent = ((InteractionSession)__instance).Agent;
					object obj;
					if (agent == null)
					{
						obj = null;
					}
					else
					{
						PlayerInteractionAgent obj2 = ((Il2CppObjectBase)agent).TryCast<PlayerInteractionAgent>();
						obj = ((obj2 != null) ? obj2.GetCharacter() : null);
					}
					PlayerCharacter val = (PlayerCharacter)obj;
					if ((Object)(object)val != (Object)null)
					{
						Plugin.Behaviour?.Pickup(((Component)val).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox pickup visual skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(CharacterGeometry), "TriggerAction")]
	internal static class FoxNativeActionHook
	{
		private static void Postfix(CharacterGeometry __instance, string actionName)
		{
			try
			{
				string text = FoxActionMapping.Action(actionName);
				if (text != null)
				{
					Plugin.Behaviour?.NativeAction(((Component)__instance).gameObject, text);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox action visual skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(PickupCreatureInteractionSession), "_OnTargetMatched")]
	internal static class FoxCreaturePickupHook
	{
		private static void Postfix(PickupCreatureInteractionSession __instance, bool matched)
		{
			try
			{
				if (matched)
				{
					IInteractionAgent agent = ((InteractionSession)__instance).Agent;
					object obj;
					if (agent == null)
					{
						obj = null;
					}
					else
					{
						PlayerInteractionAgent obj2 = ((Il2CppObjectBase)agent).TryCast<PlayerInteractionAgent>();
						obj = ((obj2 != null) ? obj2.GetCharacter() : null);
					}
					PlayerCharacter val = (PlayerCharacter)obj;
					if ((Object)(object)val != (Object)null)
					{
						Plugin.Behaviour?.Pickup(((Component)val).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox creature pickup visual skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerGatherInteractionSession), "BeginAction")]
	internal static class FoxGatherStartedHook
	{
		private static void Postfix(PlayerGatherInteractionSession __instance)
		{
			try
			{
				PlayerInteractionAgent playerAgent = __instance.PlayerAgent;
				PlayerCharacter val = ((playerAgent != null) ? playerAgent.GetCharacter() : null);
				if ((Object)(object)val != (Object)null)
				{
					Plugin.Behaviour?.WorkPulse(((Component)val).gameObject);
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox gather visual skipped: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHarvestInteractionSession), "_OnBeginDamageSwing")]
	internal static class FoxHarvestSwingHook
	{
		private static void Postfix(PlayerHarvestInteractionSession __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			try
			{
				if ((int)((InteractionSession)__instance).SessionState != 2)
				{
					return;
				}
				PlayerInteractionAgent playerAgent = __instance.PlayerAgent;
				PlayerCharacter val = ((playerAgent != null) ? playerAgent.GetCharacter() : null);
				if ((Object)(object)val != (Object)null)
				{
					HarvestInteraction harvestInteraction = __instance.HarvestInteraction;
					object moveset;
					if (harvestInteraction == null)
					{
						moveset = null;
					}
					else
					{
						InteractionMoveset attackMoveset = harvestInteraction.GetAttackMoveset();
						moveset = ((attackMoveset != null) ? ((Object)attackMoveset).name : null);
					}
					if (FoxActionMapping.ImpactHarvest((string)moveset))
					{
						Plugin.Behaviour?.NativeAction(((Component)val).gameObject, "wolf_attack1");
					}
					else
					{
						Plugin.Behaviour?.WorkPulse(((Component)val).gameObject);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Fox harvest visual skipped: " + ex.Message));
			}
		}
	}
	internal static class FoxPortrait
	{
		private static Texture2D _texture;

		private static Sprite _sprite;

		internal static Sprite Get()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_sprite != (Object)null)
			{
				return _sprite;
			}
			using Stream stream = typeof(FoxPortrait).Assembly.GetManifestResourceStream("AskaWolfPrototype.FoxPortrait.png") ?? throw new InvalidOperationException("Embedded Fox portrait is missing.");
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			try
			{
				if (!ImageConversion.LoadImage(val, new Il2CppStructArray<byte>(memoryStream.ToArray()), true))
				{
					throw new InvalidOperationException("Unity could not decode the Fox portrait PNG.");
				}
				((Object)val).name = "AskaWolfPrototype_FoxPortrait";
				((Objec