Decompiled source of OfflineCompanions v0.0.1

Companions.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Companions
{
	[BepInPlugin("com.profmags.companions", "Offline Companions", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class CompanionsPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.profmags.companions";

		public const string PluginName = "Offline Companions";

		public const string PluginVersion = "0.0.1";

		private static Harmony _harmony;

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyCode> DirectTargetKey;

		private bool _fontFixWarned;

		private void Awake()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Offline Companions v0.0.1 loading...");
			DirectTargetKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "DirectTargetKey", (KeyCode)122, "Press while looking at an enemy to direct companions to focus-fire that target.");
			_harmony = new Harmony("com.profmags.companions");
			try
			{
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				int num = 0;
				foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
				{
					_ = patchedMethod;
					num++;
				}
				Log.LogInfo((object)string.Format("{0} loaded successfully! ({1} methods patched)", "Offline Companions", num));
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"[Companions] Harmony PatchAll failed: {arg}");
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			EnsureTmpDefaultFont("awake");
		}

		private void Start()
		{
			EnsureTmpDefaultFont("start");
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Offline Companions unloaded.");
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			EnsureTmpDefaultFont("scene:" + ((Scene)(ref scene)).name);
		}

		private static bool IsBrokenTmpFont(TMP_FontAsset font)
		{
			if (!((Object)(object)font == (Object)null))
			{
				return ((Object)font).name.IndexOf("LiberationSans", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static TMP_FontAsset FindReplacementTmpFont()
		{
			TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
			foreach (TMP_Text val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					TMP_FontAsset font = val.font;
					if (!IsBrokenTmpFont(font))
					{
						return font;
					}
				}
			}
			TMP_FontAsset[] array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			TMP_FontAsset val2 = null;
			foreach (TMP_FontAsset val3 in array2)
			{
				if (!IsBrokenTmpFont(val3))
				{
					string text = ((Object)val3).name.ToLowerInvariant();
					if (text.Contains("averia") || text.Contains("norse") || text.Contains("valheim"))
					{
						return val3;
					}
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = val3;
					}
				}
			}
			return val2;
		}

		private void EnsureTmpDefaultFont(string source)
		{
			if (!IsBrokenTmpFont(TMP_Settings.defaultFontAsset))
			{
				return;
			}
			TMP_FontAsset val = FindReplacementTmpFont();
			if ((Object)(object)val == (Object)null)
			{
				if (!_fontFixWarned)
				{
					_fontFixWarned = true;
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)"[Fonts] Could not find a replacement TMP font asset yet.");
					}
				}
				return;
			}
			TMP_Settings.defaultFontAsset = val;
			_fontFixWarned = false;
			int num = 0;
			TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
			foreach (TMP_Text val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null) && IsBrokenTmpFont(val2.font))
				{
					val2.font = val;
					num++;
				}
			}
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[Fonts] TMP default font repaired to '{((Object)val).name}' ({source}), reassigned={num}.");
			}
		}
	}
	internal static class ReflectionHelper
	{
		private static readonly FieldInfo _blockingField = AccessTools.Field(typeof(Character), "m_blocking");

		internal static readonly FieldInfo LeftItemField = AccessTools.Field(typeof(Humanoid), "m_leftItem");

		internal static readonly FieldInfo RightItemField = AccessTools.Field(typeof(Humanoid), "m_rightItem");

		private static readonly FieldInfo _blockTimerField = AccessTools.Field(typeof(Humanoid), "m_blockTimer");

		internal static readonly MethodInfo UpdateVisualsMethod = AccessTools.Method(typeof(VisEquipment), "UpdateVisuals", (Type[])null, (Type[])null);

		private static bool _warnedBlocking;

		private static bool _warnedBlockTimer;

		private static readonly FieldInfo _allStationsField = AccessTools.Field(typeof(CraftingStation), "m_allStations");

		private static readonly FieldInfo _projOwnerField = AccessTools.Field(typeof(Projectile), "m_owner");

		internal static bool TrySetBlocking(Character c, bool value)
		{
			if ((Object)(object)c == (Object)null || _blockingField == null)
			{
				WarnOnce(ref _warnedBlocking, "Character.m_blocking");
				return false;
			}
			try
			{
				_blockingField.SetValue(c, value);
				return true;
			}
			catch (Exception)
			{
				WarnOnce(ref _warnedBlocking, "Character.m_blocking");
				return false;
			}
		}

		internal static bool GetBlocking(Character c)
		{
			if ((Object)(object)c == (Object)null || _blockingField == null)
			{
				return false;
			}
			try
			{
				return (bool)_blockingField.GetValue(c);
			}
			catch
			{
				return false;
			}
		}

		internal static ItemData GetLeftItem(Humanoid h)
		{
			if ((Object)(object)h == (Object)null || LeftItemField == null)
			{
				return null;
			}
			try
			{
				object? value = LeftItemField.GetValue(h);
				return (ItemData)((value is ItemData) ? value : null);
			}
			catch
			{
				return null;
			}
		}

		internal static ItemData GetRightItem(Humanoid h)
		{
			if ((Object)(object)h == (Object)null || RightItemField == null)
			{
				return null;
			}
			try
			{
				object? value = RightItemField.GetValue(h);
				return (ItemData)((value is ItemData) ? value : null);
			}
			catch
			{
				return null;
			}
		}

		internal static bool TrySetBlockTimer(Humanoid h, float value)
		{
			if ((Object)(object)h == (Object)null || _blockTimerField == null)
			{
				WarnOnce(ref _warnedBlockTimer, "Humanoid.m_blockTimer");
				return false;
			}
			try
			{
				_blockTimerField.SetValue(h, value);
				return true;
			}
			catch (Exception)
			{
				WarnOnce(ref _warnedBlockTimer, "Humanoid.m_blockTimer");
				return false;
			}
		}

		internal static float GetBlockTimer(Humanoid h)
		{
			if ((Object)(object)h == (Object)null || _blockTimerField == null)
			{
				return -1f;
			}
			try
			{
				return (float)_blockTimerField.GetValue(h);
			}
			catch
			{
				return -1f;
			}
		}

		internal static List<CraftingStation> GetAllCraftingStations()
		{
			if (_allStationsField == null)
			{
				return null;
			}
			try
			{
				return _allStationsField.GetValue(null) as List<CraftingStation>;
			}
			catch
			{
				return null;
			}
		}

		internal static Character GetProjectileOwner(Projectile proj)
		{
			if ((Object)(object)proj == (Object)null || _projOwnerField == null)
			{
				return null;
			}
			try
			{
				object? value = _projOwnerField.GetValue(proj);
				return (Character)((value is Character) ? value : null);
			}
			catch
			{
				return null;
			}
		}

		private static void WarnOnce(ref bool flag, string fieldName)
		{
			if (!flag)
			{
				flag = true;
				CompanionsPlugin.Log.LogWarning((object)("[ReflectionHelper] Failed to access " + fieldName + " — this field may have been renamed in a game update."));
			}
		}
	}
	public static class CompanionManager
	{
		private const string BankDataKey = "TraderSharedBank_Balance";

		public static int GetBankBalance()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return 0;
			}
			if (localPlayer.m_customData.TryGetValue("TraderSharedBank_Balance", out var value) && int.TryParse(value, out var result))
			{
				return result;
			}
			return 0;
		}

		public static bool CanAfford()
		{
			return GetBankBalance() >= 2000;
		}

		public static bool Purchase(CompanionAppearance appearance, CompanionTierDef def = null)
		{
			if (def == null)
			{
				def = CompanionTierData.Companion;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			int num = 2000;
			int bankBalance = GetBankBalance();
			if (bankBalance < num)
			{
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, $"Not enough coins in bank! Need {num:N0}", 0, (Sprite)null, false);
				}
				return false;
			}
			bankBalance -= num;
			localPlayer.m_customData["TraderSharedBank_Balance"] = bankBalance.ToString();
			if (!SpawnCompanion(appearance, def))
			{
				bankBalance += num;
				localPlayer.m_customData["TraderSharedBank_Balance"] = bankBalance.ToString();
				return false;
			}
			MessageHud instance2 = MessageHud.instance;
			if (instance2 != null)
			{
				instance2.ShowMessage((MessageType)2, "Your new " + def.DisplayName.ToLower() + " has arrived!", 0, (Sprite)null, false);
			}
			return true;
		}

		public static void RestoreFollowTargets()
		{
			CompanionSetup[] array = Object.FindObjectsByType<CompanionSetup>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				array[i].RestoreFollowTarget();
			}
		}

		private static bool SpawnCompanion(CompanionAppearance appearance, CompanionTierDef def)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.GetPrefab(def.PrefabName) : null);
			if ((Object)(object)val == (Object)null)
			{
				CompanionsPlugin.Log.LogError((object)("[CompanionManager] Prefab not found: " + def.PrefabName));
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			Vector3 val2 = FindSpawnPosition(((Component)localPlayer).transform.position, 4f);
			Quaternion val3 = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
			GameObject val4 = Object.Instantiate<GameObject>(val, val2, val3);
			ZNetView component = val4.GetComponent<ZNetView>();
			if (((component != null) ? component.GetZDO() : null) == null)
			{
				CompanionsPlugin.Log.LogError((object)"[CompanionManager] ZDO not available after spawn — aborting.");
				Object.Destroy((Object)(object)val4);
				return false;
			}
			ZDO zDO = component.GetZDO();
			zDO.Set(CompanionSetup.AppearanceHash, appearance.Serialize());
			zDO.Set(CompanionSetup.OwnerHash, localPlayer.GetPlayerID().ToString());
			zDO.Persistent = true;
			CompanionSetup component2 = val4.GetComponent<CompanionSetup>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.ApplyAppearance(appearance);
			}
			val4.GetComponent<CompanionAI>()?.SetFollowTarget(((Component)localPlayer).gameObject);
			CompanionsPlugin.Log.LogInfo((object)$"[CompanionManager] Spawned companion for player {localPlayer.GetPlayerID()}");
			return true;
		}

		private static Vector3 FindSpawnPosition(Vector3 origin, float radius)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			float y = default(float);
			for (int i = 0; i < 20; i++)
			{
				Vector2 val = Random.insideUnitCircle * radius;
				Vector3 val2 = origin + new Vector3(val.x, 0f, val.y);
				if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.FindFloor(val2, ref y))
				{
					val2.y = y;
					return val2;
				}
			}
			return origin + Vector3.right * 2f;
		}
	}
	public static class CombatPatches
	{
		[HarmonyPatch(typeof(Humanoid), "BlockAttack")]
		private static class BlockAttack_Patch
		{
			private static void Prefix(Humanoid __instance, HitData hit, Character attacker)
			{
				if (!((Object)(object)((Component)__instance).GetComponent<CompanionSetup>() == (Object)null))
				{
					float blockTimer = ReflectionHelper.GetBlockTimer(__instance);
					string arg = (((Object)(object)attacker != (Object)null) ? attacker.m_name : "unknown");
					float num = ((hit != null) ? hit.GetTotalDamage() : 0f);
					if (blockTimer >= 0f)
					{
						CompanionsPlugin.Log.LogDebug((object)($"[Combat] PARRY — BlockAttack fired! timer={blockTimer:F3}→0 " + $"attacker=\"{arg}\" dmg={num:F0} " + "companion=\"" + ((Character)__instance).m_name + "\""));
						ReflectionHelper.TrySetBlockTimer(__instance, 0f);
					}
					else
					{
						CompanionsPlugin.Log.LogWarning((object)($"[Combat] BlockAttack fired but timer={blockTimer:F3} (not blocking?) " + $"attacker=\"{arg}\" dmg={num:F0} " + "companion=\"" + ((Character)__instance).m_name + "\""));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Character), "GetMaxHealth")]
		private static class GetMaxHealth_Patch
		{
			private static void Postfix(Character __instance, ref float __result)
			{
				BaseAI baseAI = __instance.GetBaseAI();
				if ((Object)(object)baseAI == (Object)null || !(baseAI is CompanionAI))
				{
					return;
				}
				CompanionFood component = ((Component)__instance).GetComponent<CompanionFood>();
				if (!((Object)(object)component == (Object)null))
				{
					float num = 25f;
					float totalHealthBonus = component.TotalHealthBonus;
					float num2 = num + totalHealthBonus;
					if (Time.time - _lastHealthLogTime > 5f)
					{
						_lastHealthLogTime = Time.time;
						CompanionsPlugin.Log.LogDebug((object)($"[Combat] GetMaxHealth — base={num:F0} + food={totalHealthBonus:F1} " + $"= {num2:F1} (vanilla was {__result:F1}) " + "companion=\"" + __instance.m_name + "\""));
					}
					__result = num2;
				}
			}
		}

		private static float _lastHealthLogTime;

		private const float HealthLogInterval = 5f;
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class DirectedTargetPatch
	{
		private static float _cooldown;

		private static bool _holdActive;

		private static float _holdTimer;

		private static bool _holdFired;

		private const float HoldThreshold = 0.4f;

		private static readonly string[] ComeHereLines = new string[3] { "Coming!", "On my way back!", "Right behind you." };

		private static readonly string[] AttackLines = new string[4] { "On it!", "Going in!", "I'll take them down!", "For Odin!" };

		private static readonly string[] CartPullLines = new string[3] { "I'll haul this.", "Got the cart!", "Let me pull." };

		private static readonly string[] CartReleasedLines = new string[3] { "Letting go.", "Cart's free.", "Released!" };

		private static readonly string[] DoorLines = new string[3] { "Getting the door.", "I'll get it.", "Door's open!" };

		private static readonly string[] SitLines = new string[3] { "Nice and warm.", "Good spot to rest.", "I'll sit here." };

		private static readonly string[] SleepLines = new string[3] { "Time for some rest.", "I could use some sleep.", "Wake me if you need me." };

		private static readonly string[] WakeLines = new string[3] { "I'm up!", "Already?", "Right, let's go." };

		private static readonly string[] DepositLines = new string[3] { "Dropping off my haul.", "Storing the goods.", "Lightening my load." };

		private static readonly string[] DepositEmptyLines = new string[2] { "I've got nothing to drop off.", "Already empty." };

		private static readonly string[] HarvestLines = new string[3] { "I'll get that.", "On it!", "Looks like good stuff." };

		private static readonly string[] CancelLines = new string[3] { "Standing by.", "Awaiting orders.", "Ready when you are." };

		private static readonly string[] MoveLines = new string[3] { "Heading over.", "On my way.", "Moving out." };

		private static readonly string[] RepairLines = new string[3] { "I'll fix my gear up.", "Time for repairs.", "This needs some work." };

		private static readonly string[] BoardLines = new string[3] { "Coming aboard!", "All aboard!", "I'll hop on." };

		private static readonly string[] RepairNothingLines = new string[3] { "Nothing to fix here.", "My gear's fine.", "No repairs needed." };

		private static void Postfix(Player __instance)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_054c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || ((Character)__instance).IsDead() || InventoryGui.IsVisible() || Minimap.IsOpen() || Menu.IsVisible() || TextInput.IsVisible() || Console.IsVisible() || StoreGui.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || Hud.IsPieceSelectionVisible())
			{
				return;
			}
			float deltaTime = Time.deltaTime;
			_cooldown -= deltaTime;
			bool flag = ZInput.IsGamepadActive();
			bool flag2 = (flag ? ZInput.GetButtonDown("JoyUse") : Input.GetKeyDown(CompanionsPlugin.DirectTargetKey.Value));
			bool flag3 = (flag ? ZInput.GetButton("JoyUse") : Input.GetKey(CompanionsPlugin.DirectTargetKey.Value));
			if (flag && (flag2 || flag3) && ((Object)(object)((Humanoid)__instance).GetHoverObject() != (Object)null || Hud.InRadial()))
			{
				_holdActive = false;
				_holdTimer = 0f;
				return;
			}
			if (flag2 && _cooldown <= 0f)
			{
				_holdActive = true;
				_holdTimer = 0f;
				_holdFired = false;
			}
			if (_holdActive && flag3)
			{
				_holdTimer += deltaTime;
				if (_holdTimer >= 0.4f && !_holdFired)
				{
					_holdFired = true;
					_cooldown = 0.5f;
					FireComeToMe(__instance, flag);
				}
			}
			else
			{
				if (!_holdActive)
				{
					return;
				}
				_holdActive = false;
				if (_holdFired || _cooldown > 0f)
				{
					return;
				}
				_cooldown = 0.5f;
				string text = (flag ? "gamepad" : "keyboard");
				CompanionsPlugin.Log.LogDebug((object)("[Direct] Command triggered via " + text));
				Camera mainCamera = Utils.GetMainCamera();
				if ((Object)(object)mainCamera == (Object)null)
				{
					return;
				}
				Ray val = default(Ray);
				((Ray)(ref val))..ctor(((Component)mainCamera).transform.position, ((Component)mainCamera).transform.forward);
				int mask = LayerMask.GetMask(new string[12]
				{
					"character", "character_net", "character_ghost", "character_noenv", "Default", "Default_small", "piece", "piece_nonsolid", "static_solid", "terrain",
					"vehicle", "item"
				});
				RaycastHit[] array = Physics.RaycastAll(val, 50f, mask);
				if (array.Length > 1)
				{
					Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
				}
				CompanionsPlugin.Log.LogDebug((object)$"[Direct] Raycast hits={array.Length}, pos={((Component)mainCamera).transform.position:F1}, dir={((Component)mainCamera).transform.forward:F2}");
				CompanionSetup[] setups = Object.FindObjectsByType<CompanionSetup>((FindObjectsSortMode)0);
				string localId = __instance.GetPlayerID().ToString();
				for (int i = 0; i < array.Length; i++)
				{
					Collider collider = ((RaycastHit)(ref array[i])).collider;
					if ((Object)(object)collider == (Object)null)
					{
						continue;
					}
					CompanionsPlugin.Log.LogDebug((object)($"[Direct] Hit[{i}]: \"{((Object)((Component)collider).gameObject).name}\" dist={((RaycastHit)(ref array[i])).distance:F2} " + "layer=" + LayerMask.LayerToName(((Component)collider).gameObject.layer) + " " + $"pos={((RaycastHit)(ref array[i])).point:F2}"));
					Character componentInParent = ((Component)collider).GetComponentInParent<Character>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						if (!((Object)(object)componentInParent == (Object)(object)__instance) && !((Object)(object)((Component)componentInParent).GetComponent<CompanionSetup>() != (Object)null) && !componentInParent.IsDead() && BaseAI.IsEnemy((Character)(object)__instance, componentInParent))
						{
							DirectAttack(setups, localId, componentInParent);
							return;
						}
						continue;
					}
					Vagon componentInParent2 = ((Component)collider).GetComponentInParent<Vagon>();
					if ((Object)(object)componentInParent2 != (Object)null)
					{
						DirectCart(setups, localId, componentInParent2);
						return;
					}
					Door componentInParent3 = ((Component)collider).GetComponentInParent<Door>();
					if ((Object)(object)componentInParent3 != (Object)null)
					{
						DirectDoor(setups, localId, componentInParent3);
						return;
					}
					Fireplace componentInParent4 = ((Component)collider).GetComponentInParent<Fireplace>();
					if ((Object)(object)componentInParent4 != (Object)null)
					{
						DirectSit(setups, localId, componentInParent4);
						return;
					}
					Bed componentInParent5 = ((Component)collider).GetComponentInParent<Bed>();
					if ((Object)(object)componentInParent5 != (Object)null)
					{
						DirectSleep(setups, localId, componentInParent5);
						return;
					}
					CraftingStation componentInParent6 = ((Component)collider).GetComponentInParent<CraftingStation>();
					if ((Object)(object)componentInParent6 != (Object)null)
					{
						DirectRepair(setups, localId, componentInParent6);
						return;
					}
					Ship componentInParent7 = ((Component)collider).GetComponentInParent<Ship>();
					if ((Object)(object)componentInParent7 != (Object)null)
					{
						DirectBoard(setups, localId, componentInParent7);
						return;
					}
					Container componentInParent8 = ((Component)collider).GetComponentInParent<Container>();
					if ((Object)(object)componentInParent8 != (Object)null && (Object)(object)((Component)componentInParent8).GetComponent<CompanionSetup>() == (Object)null)
					{
						DirectDeposit(setups, localId, componentInParent8);
						return;
					}
					GameObject harvestable = GetHarvestable(collider);
					if ((Object)(object)harvestable != (Object)null)
					{
						DirectGatherMode(setups, localId, harvestable);
						return;
					}
					int layer = ((Component)collider).gameObject.layer;
					if (layer == LayerMask.NameToLayer("terrain") || layer == LayerMask.NameToLayer("Default") || layer == LayerMask.NameToLayer("static_solid") || layer == LayerMask.NameToLayer("piece") || layer == LayerMask.NameToLayer("piece_nonsolid"))
					{
						DirectGround(setups, localId, ((RaycastHit)(ref array[i])).point);
						return;
					}
				}
				CancelAll(setups, localId);
			}
		}

		private static void FireComeToMe(Player player, bool isGamepad)
		{
			CompanionSetup[] array = Object.FindObjectsByType<CompanionSetup>((FindObjectsSortMode)0);
			string localId = player.GetPlayerID().ToString();
			CancelAll(array, localId);
			CompanionTalk companionTalk = null;
			CompanionSetup[] array2 = array;
			foreach (CompanionSetup companionSetup in array2)
			{
				if (IsOwned(companionSetup, localId))
				{
					companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					if ((Object)(object)companionTalk != (Object)null)
					{
						break;
					}
				}
			}
			SayRandom(companionTalk, ComeHereLines);
			string text = (isGamepad ? "gamepad hold" : "keyboard hold");
			CompanionsPlugin.Log.LogDebug((object)("[Direct] Come-to-me triggered via " + text));
		}

		private static void DirectAttack(CompanionSetup[] setups, string localId, Character enemy)
		{
			int num = 0;
			CompanionTalk companionTalk = null;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				CompanionAI component = ((Component)companionSetup).GetComponent<CompanionAI>();
				if (!((Object)(object)component == (Object)null))
				{
					CancelExistingActions(companionSetup);
					component.m_targetCreature = enemy;
					component.SetAlerted(alert: true);
					component.DirectedTargetLockTimer = 10f;
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
					num++;
				}
			}
			SayRandom(companionTalk, AttackLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num} companion(s) → attack \"{enemy.m_name}\"");
		}

		private static void DirectCart(CompanionSetup[] setups, string localId, Vagon vagon)
		{
			//IL_0031: 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_0199: 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_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			CompanionsPlugin.Log.LogDebug((object)("[Direct] DirectCart called — vagon=\"" + ((Object)vagon).name + "\" " + $"attachPoint={vagon.m_attachPoint.position:F2} " + $"attachOffset={vagon.m_attachOffset:F2} " + $"detachDist={vagon.m_detachDistance:F2}"));
			CompanionSetup[] array = setups;
			foreach (CompanionSetup companionSetup in array)
			{
				if (!IsOwned(companionSetup, localId))
				{
					continue;
				}
				Character component = ((Component)companionSetup).GetComponent<Character>();
				bool flag = (Object)(object)component != (Object)null && vagon.IsAttached(component);
				CompanionsPlugin.Log.LogDebug((object)$"[Direct] Cart detach check: \"{component?.m_name}\" attached={flag}");
				if (!flag)
				{
					continue;
				}
				Humanoid component2 = ((Component)companionSetup).GetComponent<Humanoid>();
				if ((Object)(object)component2 != (Object)null)
				{
					vagon.Interact(component2, false, false);
					CompanionAI component3 = ((Component)companionSetup).GetComponent<CompanionAI>();
					if ((Object)(object)component3 != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
					{
						component3.SetFollowTarget(((Component)Player.m_localPlayer).gameObject);
					}
					SayRandom(((Component)companionSetup).GetComponent<CompanionTalk>(), CartReleasedLines);
					CompanionsPlugin.Log.LogDebug((object)"[Direct] Companion → detach from cart");
				}
				return;
			}
			CompanionSetup companionSetup2 = null;
			float num = float.MaxValue;
			array = setups;
			foreach (CompanionSetup companionSetup3 in array)
			{
				if (IsOwned(companionSetup3, localId) && companionSetup3.GetIsCommandable())
				{
					float num2 = Vector3.Distance(((Component)companionSetup3).transform.position, ((Component)vagon).transform.position);
					if (num2 < num)
					{
						num = num2;
						companionSetup2 = companionSetup3;
					}
				}
			}
			if ((Object)(object)companionSetup2 == (Object)null)
			{
				CompanionsPlugin.Log.LogWarning((object)"[Direct] DirectCart — no commandable companion found");
				return;
			}
			Humanoid component4 = ((Component)companionSetup2).GetComponent<Humanoid>();
			if ((Object)(object)component4 == (Object)null)
			{
				return;
			}
			CompanionAI component5 = ((Component)companionSetup2).GetComponent<CompanionAI>();
			if ((Object)(object)component5 == (Object)null)
			{
				return;
			}
			CancelExistingActions(companionSetup2);
			Vector3 val = vagon.m_attachPoint.position - vagon.m_attachOffset;
			val.y = ((Component)companionSetup2).transform.position.y;
			float num3 = Vector3.Distance(((Component)companionSetup2).transform.position, val);
			if (num3 < 3f)
			{
				((Component)companionSetup2).transform.position = val;
				Rigidbody component6 = ((Component)companionSetup2).GetComponent<Rigidbody>();
				if ((Object)(object)component6 != (Object)null)
				{
					component6.position = val;
					component6.velocity = Vector3.zero;
				}
				Vector3 val2 = ((Component)vagon).transform.position - ((Component)companionSetup2).transform.position;
				val2.y = 0f;
				if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
				{
					((Component)companionSetup2).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized);
				}
				component5.FreezeTimer = 1f;
				component5.SetFollowTarget(((Component)vagon).gameObject);
				vagon.Interact(component4, false, false);
				CompanionsPlugin.Log.LogDebug((object)$"[Direct] Cart close snap — pos={((Component)companionSetup2).transform.position:F2}");
			}
			else
			{
				component5.SetPendingCart(vagon, component4);
				CompanionsPlugin.Log.LogDebug((object)$"[Direct] Cart navigation started — dist={num3:F1}m");
			}
			SayRandom(((Component)companionSetup2).GetComponent<CompanionTalk>(), CartPullLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] Companion → cart attach (dist={num:F1}m)");
		}

		private static void DirectDoor(CompanionSetup[] setups, string localId, Door door)
		{
			int num = 0;
			CompanionTalk companionTalk = null;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				CancelExistingActions(companionSetup);
				DoorHandler component = ((Component)companionSetup).GetComponent<DoorHandler>();
				if (!((Object)(object)component == (Object)null))
				{
					component.DirectOpenDoor(door);
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
					num++;
				}
			}
			SayRandom(companionTalk, DoorLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num} companion(s) → open door \"{door.m_name}\"");
		}

		private static void DirectSit(CompanionSetup[] setups, string localId, Fireplace fire)
		{
			if (!fire.IsBurning())
			{
				return;
			}
			int num = 0;
			CompanionTalk companionTalk = null;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				CancelExistingActions(companionSetup, cancelRest: false);
				CompanionRest component = ((Component)companionSetup).GetComponent<CompanionRest>();
				if (!((Object)(object)component == (Object)null))
				{
					component.DirectSit(((Component)fire).gameObject);
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
					num++;
				}
			}
			SayRandom(companionTalk, SitLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num} companion(s) → sit near fire");
		}

		private static void DirectSleep(CompanionSetup[] setups, string localId, Bed bed)
		{
			//IL_0031: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			ManualLogSource log = CompanionsPlugin.Log;
			string[] obj = new string[6]
			{
				"[Direct] DirectSleep called — bed=\"",
				((Object)bed).name,
				"\" ",
				$"pos={((Component)bed).transform.position:F2} ",
				"spawnPoint=",
				null
			};
			Transform spawnPoint = bed.m_spawnPoint;
			object obj2;
			if (spawnPoint == null)
			{
				obj2 = null;
			}
			else
			{
				Vector3 position = spawnPoint.position;
				obj2 = ((Vector3)(ref position)).ToString("F2");
			}
			if (obj2 == null)
			{
				obj2 = "null";
			}
			obj[5] = (string)obj2;
			log.LogDebug((object)string.Concat(obj));
			int num = 0;
			int num2 = 0;
			CompanionTalk companionTalk = null;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				CancelExistingActions(companionSetup, cancelRest: false);
				CompanionRest component = ((Component)companionSetup).GetComponent<CompanionRest>();
				if (!((Object)(object)component == (Object)null))
				{
					bool flag = component.IsResting || component.IsNavigating;
					component.DirectSleep(bed);
					bool flag2 = component.IsResting || component.IsNavigating;
					if (!flag && flag2)
					{
						num++;
					}
					else if (flag && !flag2)
					{
						num2++;
					}
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
				}
			}
			if (num2 > 0)
			{
				SayRandom(companionTalk, WakeLines);
			}
			else if (num > 0)
			{
				SayRandom(companionTalk, SleepLines);
			}
			else
			{
				SayRandom(companionTalk, CancelLines);
			}
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] Sleep command — started={num}, wokeUp={num2}");
		}

		private static void DirectDeposit(CompanionSetup[] setups, string localId, Container chest)
		{
			if (chest.GetInventory() == null)
			{
				return;
			}
			int num = 0;
			CompanionTalk companionTalk = null;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				Humanoid component = ((Component)companionSetup).GetComponent<Humanoid>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				Inventory inventory = component.GetInventory();
				if (inventory == null)
				{
					continue;
				}
				bool flag = false;
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					if (!ShouldKeep(allItem, component))
					{
						flag = true;
						break;
					}
				}
				if ((Object)(object)companionTalk == (Object)null)
				{
					companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
				}
				if (flag)
				{
					CancelExistingActions(companionSetup);
					CompanionAI component2 = ((Component)companionSetup).GetComponent<CompanionAI>();
					if (!((Object)(object)component2 == (Object)null))
					{
						component2.SetPendingDeposit(chest, component);
						num++;
					}
				}
			}
			if (num > 0)
			{
				SayRandom(companionTalk, DepositLines);
				CompanionsPlugin.Log.LogDebug((object)$"[Direct] Dispatched {num} companion(s) to deposit in \"{chest.m_name}\"");
			}
			else
			{
				SayRandom(companionTalk, DepositEmptyLines);
				CompanionsPlugin.Log.LogDebug((object)"[Direct] No companions had items to deposit");
			}
		}

		private static void DirectRepair(CompanionSetup[] setups, string localId, CraftingStation station)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			CompanionsPlugin.Log.LogDebug((object)("[Direct] DirectRepair called — station=\"" + station.m_name + "\" " + $"level={station.GetLevel(true)} pos={((Component)station).transform.position:F1}"));
			CompanionTalk companionTalk = null;
			int num = 0;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				RepairController component = ((Component)companionSetup).GetComponent<RepairController>();
				if (!((Object)(object)component == (Object)null))
				{
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
					CancelExistingActions(companionSetup);
					if (component.DirectRepairAt(station))
					{
						num++;
					}
				}
			}
			if (num > 0)
			{
				SayRandom(companionTalk, RepairLines);
				CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num} companion(s) → repair at \"{station.m_name}\"");
			}
			else
			{
				SayRandom(companionTalk, RepairNothingLines);
				CompanionsPlugin.Log.LogDebug((object)("[Direct] No companions can repair at \"" + station.m_name + "\""));
			}
		}

		private static void DirectBoard(CompanionSetup[] setups, string localId, Ship ship)
		{
			//IL_0020: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			CompanionsPlugin.Log.LogDebug((object)("[Direct] DirectBoard called — ship=\"" + ((Object)ship).name + "\" " + $"pos={((Component)ship).transform.position:F2} up={((Component)ship).transform.up:F2}"));
			CompanionTalk companionTalk = null;
			int num = 0;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				CancelExistingActions(companionSetup);
				CompanionAI component = ((Component)companionSetup).GetComponent<CompanionAI>();
				if (!((Object)(object)component == (Object)null))
				{
					Vector3 position = ((Component)companionSetup).transform.position;
					Vector3 val = ((Component)ship).transform.position + ((Component)ship).transform.up * 1.5f;
					((Component)companionSetup).transform.position = val;
					Rigidbody component2 = ((Component)companionSetup).GetComponent<Rigidbody>();
					if ((Object)(object)component2 != (Object)null)
					{
						component2.position = val;
						component2.velocity = Vector3.zero;
					}
					component.SetFollowTarget(((Component)ship).gameObject);
					component.FreezeTimer = 1f;
					Character component3 = ((Component)companionSetup).GetComponent<Character>();
					CompanionsPlugin.Log.LogDebug((object)("[Direct] Board: \"" + (component3?.m_name ?? "?") + "\" " + $"teleported {position:F1} → {val:F1}"));
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
					num++;
				}
			}
			SayRandom(companionTalk, BoardLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num} companion(s) → board ship");
		}

		private static void DirectGatherMode(CompanionSetup[] setups, string localId, GameObject target)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			int num = HarvestController.DetermineHarvestModeStatic(target);
			if (num < 0)
			{
				CompanionsPlugin.Log.LogDebug((object)("[Direct] DirectGatherMode — target \"" + ((Object)target).name + "\" is not harvestable (mode=-1)"));
				return;
			}
			string arg = num switch
			{
				2 => "Stone", 
				1 => "Wood", 
				_ => "Ore", 
			};
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] DirectGatherMode — target=\"{((Object)target).name}\" mode={arg} pos={target.transform.position:F1}");
			CompanionTalk companionTalk = null;
			int num2 = 0;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				CancelExistingActions(companionSetup);
				ZNetView component = ((Component)companionSetup).GetComponent<ZNetView>();
				if (((component != null) ? component.GetZDO() : null) != null)
				{
					component.GetZDO().Set(CompanionSetup.ActionModeHash, num, false);
					HarvestController component2 = ((Component)companionSetup).GetComponent<HarvestController>();
					if ((Object)(object)component2 != (Object)null && num2 == 0)
					{
						component2.SetDirectedTarget(target);
					}
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
					num2++;
				}
			}
			SayRandom(companionTalk, HarvestLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num2} companion(s) → gather mode {arg}");
		}

		private static void DirectGround(CompanionSetup[] setups, string localId, Vector3 point)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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)
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] DirectGround called — point={point:F1}");
			bool flag = false;
			CompanionSetup[] array = setups;
			foreach (CompanionSetup companionSetup in array)
			{
				if (IsOwned(companionSetup, localId) && companionSetup.GetIsCommandable())
				{
					HarvestController component = ((Component)companionSetup).GetComponent<HarvestController>();
					if ((Object)(object)component != (Object)null && component.IsInGatherMode)
					{
						flag = true;
						break;
					}
				}
			}
			if (flag)
			{
				CompanionsPlugin.Log.LogDebug((object)"[Direct] DirectGround — companion(s) in gather mode, exiting gather instead");
				ExitGatherMode(setups, localId);
				return;
			}
			CompanionTalk companionTalk = null;
			int num = 0;
			array = setups;
			foreach (CompanionSetup companionSetup2 in array)
			{
				if (!IsOwned(companionSetup2, localId) || !companionSetup2.GetIsCommandable())
				{
					continue;
				}
				CancelExistingActions(companionSetup2);
				CompanionAI component2 = ((Component)companionSetup2).GetComponent<CompanionAI>();
				if (!((Object)(object)component2 == (Object)null))
				{
					component2.SetMoveTarget(point);
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup2).GetComponent<CompanionTalk>();
					}
					num++;
				}
			}
			SayRandom(companionTalk, MoveLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num} companion(s) → move to {point:F1}");
		}

		private static void ExitGatherMode(CompanionSetup[] setups, string localId)
		{
			CompanionTalk companionTalk = null;
			int num = 0;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId) || !companionSetup.GetIsCommandable())
				{
					continue;
				}
				ZNetView component = ((Component)companionSetup).GetComponent<ZNetView>();
				if (((component != null) ? component.GetZDO() : null) != null)
				{
					int @int = component.GetZDO().GetInt(CompanionSetup.ActionModeHash, 0);
					component.GetZDO().Set(CompanionSetup.ActionModeHash, 0, false);
					Character component2 = ((Component)companionSetup).GetComponent<Character>();
					CompanionsPlugin.Log.LogDebug((object)string.Format("[Direct] ExitGather: \"{0}\" mode {1} → {2}", component2?.m_name ?? "?", @int, 0));
					if ((Object)(object)companionTalk == (Object)null)
					{
						companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
					}
					num++;
				}
			}
			SayRandom(companionTalk, CancelLines);
			CompanionsPlugin.Log.LogDebug((object)$"[Direct] {num} companion(s) exited gather mode → follow");
		}

		private static void CancelAll(CompanionSetup[] setups, string localId)
		{
			CompanionTalk companionTalk = null;
			foreach (CompanionSetup companionSetup in setups)
			{
				if (!IsOwned(companionSetup, localId))
				{
					continue;
				}
				if ((Object)(object)companionTalk == (Object)null)
				{
					companionTalk = ((Component)companionSetup).GetComponent<CompanionTalk>();
				}
				CompanionAI component = ((Component)companionSetup).GetComponent<CompanionAI>();
				if ((Object)(object)component != (Object)null)
				{
					component.DirectedTargetLockTimer = 0f;
					component.CancelPendingCart();
					component.CancelMoveTarget();
					component.CancelPendingDeposit();
					if ((Object)(object)Player.m_localPlayer != (Object)null)
					{
						component.SetFollowTarget(((Component)Player.m_localPlayer).gameObject);
					}
				}
				HarvestController component2 = ((Component)companionSetup).GetComponent<HarvestController>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.CancelDirectedTarget();
				}
				CompanionRest component3 = ((Component)companionSetup).GetComponent<CompanionRest>();
				if ((Object)(object)component3 != (Object)null)
				{
					component3.CancelDirected();
				}
				RepairController component4 = ((Component)companionSetup).GetComponent<RepairController>();
				if ((Object)(object)component4 != (Object)null && component4.IsActive)
				{
					component4.CancelDirected();
				}
			}
			SayRandom(companionTalk, CancelLines);
			CompanionsPlugin.Log.LogDebug((object)"[Direct] Cancelled all directed commands");
		}

		private static void SayRandom(CompanionTalk talk, string[] pool)
		{
			if (!((Object)(object)talk == (Object)null) && pool != null && pool.Length != 0)
			{
				talk.Say(pool[Random.Range(0, pool.Length)]);
			}
		}

		private static bool IsOwned(CompanionSetup setup, string localId)
		{
			ZNetView component = ((Component)setup).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || component.GetZDO() == null)
			{
				return false;
			}
			return component.GetZDO().GetString(CompanionSetup.OwnerHash, "") == localId;
		}

		private static void CancelExistingActions(CompanionSetup setup, bool cancelRest = true)
		{
			string text = ((Component)setup).GetComponent<Character>()?.m_name ?? "?";
			if (cancelRest)
			{
				CompanionRest component = ((Component)setup).GetComponent<CompanionRest>();
				if ((Object)(object)component != (Object)null && (component.IsResting || component.IsNavigating))
				{
					CompanionsPlugin.Log.LogDebug((object)("[Direct] CancelExisting \"" + text + "\": cancelling rest " + $"(resting={component.IsResting} nav={component.IsNavigating})"));
					component.CancelDirected();
				}
			}
			CompanionAI component2 = ((Component)setup).GetComponent<CompanionAI>();
			if ((Object)(object)component2 != (Object)null)
			{
				if ((Object)(object)component2.PendingCartAttach != (Object)null)
				{
					CompanionsPlugin.Log.LogDebug((object)("[Direct] CancelExisting \"" + text + "\": cancelling cart nav"));
				}
				component2.CancelPendingCart();
				if (component2.PendingMoveTarget.HasValue)
				{
					CompanionsPlugin.Log.LogDebug((object)("[Direct] CancelExisting \"" + text + "\": cancelling move-to"));
				}
				component2.CancelMoveTarget();
				if ((Object)(object)component2.PendingDepositContainer != (Object)null)
				{
					CompanionsPlugin.Log.LogDebug((object)("[Direct] CancelExisting \"" + text + "\": cancelling deposit nav"));
				}
				component2.CancelPendingDeposit();
				component2.DirectedTargetLockTimer = 0f;
			}
			HarvestController component3 = ((Component)setup).GetComponent<HarvestController>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.CancelDirectedTarget();
			}
			RepairController component4 = ((Component)setup).GetComponent<RepairController>();
			if ((Object)(object)component4 != (Object)null && component4.IsActive)
			{
				CompanionsPlugin.Log.LogDebug((object)("[Direct] CancelExisting \"" + text + "\": cancelling active repair"));
				component4.CancelDirected();
			}
		}

		internal static bool ShouldKeep(ItemData item, Humanoid humanoid)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Invalid comparison between Unknown and I4
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Invalid comparison between Unknown and I4
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Invalid comparison between Unknown and I4
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Invalid comparison between Unknown and I4
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Invalid comparison between Unknown and I4
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Invalid comparison between Unknown and I4
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Invalid comparison between Unknown and I4
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Invalid comparison between Unknown and I4
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null)
			{
				return true;
			}
			if (humanoid.IsItemEquiped(item))
			{
				return true;
			}
			ItemType itemType = item.m_shared.m_itemType;
			if ((int)itemType == 2 && (item.m_shared.m_food > 0f || item.m_shared.m_foodStamina > 0f || item.m_shared.m_foodEitr > 0f))
			{
				return true;
			}
			if ((int)itemType == 3 || (int)itemType == 14 || (int)itemType == 22 || (int)itemType == 4 || (int)itemType == 15)
			{
				return true;
			}
			if ((int)itemType == 5 || (int)itemType == 6 || (int)itemType == 7 || (int)itemType == 11 || (int)itemType == 12 || (int)itemType == 17 || (int)itemType == 18)
			{
				return true;
			}
			return false;
		}

		private static GameObject GetHarvestable(Collider col)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Invalid comparison between Unknown and I4
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Invalid comparison between Unknown and I4
			TreeBase componentInParent = ((Component)col).GetComponentInParent<TreeBase>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return ((Component)componentInParent).gameObject;
			}
			TreeLog componentInParent2 = ((Component)col).GetComponentInParent<TreeLog>();
			if ((Object)(object)componentInParent2 != (Object)null)
			{
				return ((Component)componentInParent2).gameObject;
			}
			MineRock5 componentInParent3 = ((Component)col).GetComponentInParent<MineRock5>();
			if ((Object)(object)componentInParent3 != (Object)null)
			{
				return ((Component)componentInParent3).gameObject;
			}
			MineRock componentInParent4 = ((Component)col).GetComponentInParent<MineRock>();
			if ((Object)(object)componentInParent4 != (Object)null)
			{
				return ((Component)componentInParent4).gameObject;
			}
			Destructible componentInParent5 = ((Component)col).GetComponentInParent<Destructible>();
			if ((Object)(object)componentInParent5 != (Object)null)
			{
				if ((int)componentInParent5.m_damages.m_chop != 3 && ((Object)((Component)componentInParent5).gameObject).name.IndexOf("stub", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return ((Component)componentInParent5).gameObject;
				}
				if ((int)componentInParent5.m_damages.m_pickaxe != 3 && (int)componentInParent5.m_damages.m_chop == 3)
				{
					return ((Component)componentInParent5).gameObject;
				}
			}
			return null;
		}
	}
	public static class DurabilityPatches
	{
		[HarmonyPatch(typeof(Humanoid), "StartAttack")]
		private static class WeaponDurability_Patch
		{
			private static void Postfix(Humanoid __instance, bool __result)
			{
				if (!__result || (Object)(object)((Component)__instance).GetComponent<CompanionSetup>() == (Object)null)
				{
					return;
				}
				ItemData rightItem = ReflectionHelper.GetRightItem(__instance);
				if (rightItem != null && rightItem.m_shared.m_useDurability)
				{
					float durability = rightItem.m_durability;
					float useDurabilityDrain = rightItem.m_shared.m_useDurabilityDrain;
					rightItem.m_durability -= useDurabilityDrain;
					float maxDurability = rightItem.GetMaxDurability();
					float num = ((maxDurability > 0f) ? (rightItem.m_durability / maxDurability * 100f) : 0f);
					CompanionsPlugin.Log.LogDebug((object)("[Durability] Weapon drain — \"" + rightItem.m_shared.m_name + "\" " + $"durability {durability:F1} → {rightItem.m_durability:F1} / {maxDurability:F0} " + $"({num:F0}%) drain={useDurabilityDrain:F1} " + "companion=\"" + ((Character)__instance).m_name + "\""));
					if (rightItem.m_durability <= 0f)
					{
						rightItem.m_durability = 0f;
						__instance.UnequipItem(rightItem, false);
						CompanionsPlugin.Log.LogWarning((object)("[Durability] Weapon BROKEN — \"" + rightItem.m_shared.m_name + "\" unequipped, companion=\"" + ((Character)__instance).m_name + "\""));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Character), "RPC_Damage")]
		private static class ArmorDurability_Patch
		{
			private static void Prefix(Character __instance, HitData hit)
			{
				CompanionSetup component = ((Component)__instance).GetComponent<CompanionSetup>();
				if (!((Object)(object)component == (Object)null))
				{
					float totalArmor = component.GetTotalArmor();
					if (totalArmor > 0f)
					{
						float totalDamage = hit.GetTotalDamage();
						hit.ApplyArmor(totalArmor);
						float totalDamage2 = hit.GetTotalDamage();
						CompanionsPlugin.Log.LogDebug((object)($"[Durability] Armor reduction — totalArmor={totalArmor:F1} " + $"dmg {totalDamage:F1} → {totalDamage2:F1} " + $"(blocked {totalDamage - totalDamage2:F1}) " + "companion=\"" + __instance.m_name + "\""));
					}
				}
			}

			private static void Postfix(Character __instance, HitData hit)
			{
				if ((Object)(object)((Component)__instance).GetComponent<CompanionSetup>() == (Object)null)
				{
					return;
				}
				Humanoid val = (Humanoid)(object)((__instance is Humanoid) ? __instance : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				List<ItemData> list = new List<ItemData>(4);
				object? obj = _chestItem?.GetValue(val);
				AddIfValid(list, (ItemData)((obj is ItemData) ? obj : null));
				object? obj2 = _legItem?.GetValue(val);
				AddIfValid(list, (ItemData)((obj2 is ItemData) ? obj2 : null));
				object? obj3 = _helmetItem?.GetValue(val);
				AddIfValid(list, (ItemData)((obj3 is ItemData) ? obj3 : null));
				object? obj4 = _shoulderItem?.GetValue(val);
				AddIfValid(list, (ItemData)((obj4 is ItemData) ? obj4 : null));
				if (list.Count == 0)
				{
					CompanionsPlugin.Log.LogDebug((object)("[Durability] No armor with durability equipped — skipping drain companion=\"" + __instance.m_name + "\""));
					return;
				}
				float num = hit.GetTotalPhysicalDamage() + hit.GetTotalElementalDamage();
				if (!(num <= 0f))
				{
					ItemData val2 = list[Random.Range(0, list.Count)];
					float durability = val2.m_durability;
					val2.m_durability = Mathf.Max(0f, val2.m_durability - num);
					float maxDurability = val2.GetMaxDurability();
					float num2 = ((maxDurability > 0f) ? (val2.m_durability / maxDurability * 100f) : 0f);
					CompanionsPlugin.Log.LogDebug((object)("[Durability] Armor drain — \"" + val2.m_shared.m_name + "\" " + $"durability {durability:F1} → {val2.m_durability:F1} / {maxDurability:F0} " + $"({num2:F0}%) dmgTaken={num:F1} " + $"armorPieces={list.Count} companion=\"{__instance.m_name}\""));
					if (val2.m_durability <= 0f)
					{
						val.UnequipItem(val2, false);
						CompanionsPlugin.Log.LogWarning((object)("[Durability] Armor BROKEN — \"" + val2.m_shared.m_name + "\" unequipped, companion=\"" + __instance.m_name + "\""));
					}
				}
			}
		}

		private static readonly FieldInfo _chestItem = AccessTools.Field(typeof(Humanoid), "m_chestItem");

		private static readonly FieldInfo _legItem = AccessTools.Field(typeof(Humanoid), "m_legItem");

		private static readonly FieldInfo _helmetItem = AccessTools.Field(typeof(Humanoid), "m_helmetItem");

		private static readonly FieldInfo _shoulderItem = AccessTools.Field(typeof(Humanoid), "m_shoulderItem");

		private static void AddIfValid(List<ItemData> list, ItemData item)
		{
			if (item != null && item.m_shared != null && item.m_shared.m_useDurability)
			{
				list.Add(item);
			}
		}
	}
	public static class EnemyHudPatches
	{
		private struct CompanionBars
		{
			public GuiBar StaminaBar;

			public GuiBar WeightBar;
		}

		[HarmonyPatch(typeof(EnemyHud), "ShowHud")]
		private static class ShowHud_Patch
		{
			private static void Postfix(EnemyHud __instance, Character c)
			{
				//IL_0095: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)c == (Object)null || (Object)(object)((Component)c).GetComponent<CompanionStamina>() == (Object)null || _bars.ContainsKey(c) || !(Traverse.Create((object)__instance).Field("m_huds").GetValue() is IDictionary dictionary) || !dictionary.Contains(c))
				{
					return;
				}
				GameObject value = Traverse.Create(dictionary[c]).Field("m_gui").GetValue<GameObject>();
				if ((Object)(object)value == (Object)null)
				{
					return;
				}
				Transform val = value.transform.Find("Health");
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Rect rect = ((Component)val).GetComponent<RectTransform>().rect;
				float num = ((Rect)(ref rect)).height;
				if (num <= 0f)
				{
					num = 8f;
				}
				float num2 = num + 2f;
				GuiBar val2 = CreateBar(val, value.transform, "CompanionStamina", StaminaYellow, num2);
				float yOffset = num2 + num + 2f;
				GuiBar val3 = CreateBar(val, value.transform, "CompanionWeight", WeightBrown, yOffset);
				if ((Object)(object)val2 != (Object)null)
				{
					CompanionStamina component = ((Component)c).GetComponent<CompanionStamina>();
					val2.SetValue(component.GetStaminaPercentage());
				}
				if ((Object)(object)val3 != (Object)null)
				{
					Humanoid component2 = ((Component)c).GetComponent<Humanoid>();
					if ((Object)(object)component2 != (Object)null)
					{
						Inventory inventory = component2.GetInventory();
						float value2 = ((inventory != null) ? Mathf.Clamp01(inventory.GetTotalWeight() / 300f) : 0f);
						val3.SetValue(value2);
					}
				}
				_bars[c] = new CompanionBars
				{
					StaminaBar = val2,
					WeightBar = val3
				};
				CompanionsPlugin.Log.LogDebug((object)($"[HUD] Created companion bars — stamina={(Object)(object)val2 != (Object)null} " + $"weight={(Object)(object)val3 != (Object)null} companion=\"{c.m_name}\""));
			}
		}

		[HarmonyPatch(typeof(EnemyHud), "OnDestroy")]
		private static class OnDestroy_Patch
		{
			private static void Postfix()
			{
				_bars.Clear();
			}
		}

		[HarmonyPatch(typeof(EnemyHud), "UpdateHuds")]
		private static class UpdateHuds_Patch
		{
			private static void Postfix()
			{
				List<Character> list = null;
				foreach (KeyValuePair<Character, CompanionBars> bar in _bars)
				{
					if ((Object)(object)bar.Key == (Object)null || ((Object)(object)bar.Value.StaminaBar == (Object)null && (Object)(object)bar.Value.WeightBar == (Object)null))
					{
						if (list == null)
						{
							list = new List<Character>();
						}
						list.Add(bar.Key);
						continue;
					}
					CompanionBars value = bar.Value;
					if ((Object)(object)value.StaminaBar != (Object)null)
					{
						CompanionStamina component = ((Component)bar.Key).GetComponent<CompanionStamina>();
						if ((Object)(object)component != (Object)null)
						{
							value.StaminaBar.SetValue(component.GetStaminaPercentage());
						}
					}
					if ((Object)(object)value.WeightBar != (Object)null)
					{
						Character key = bar.Key;
						Humanoid val = (Humanoid)(object)((key is Humanoid) ? key : null);
						if ((Object)(object)val != (Object)null)
						{
							Inventory inventory = val.GetInventory();
							float value2 = ((inventory != null) ? Mathf.Clamp01(inventory.GetTotalWeight() / 300f) : 0f);
							value.WeightBar.SetValue(value2);
						}
					}
				}
				if (list != null)
				{
					for (int i = 0; i < list.Count; i++)
					{
						CompanionsPlugin.Log.LogDebug((object)"[HUD] Removing stale companion bars — character destroyed or null");
						_bars.Remove(list[i]);
					}
				}
			}
		}

		private static readonly Color StaminaYellow = new Color(1f, 0.8f, 0.1f, 1f);

		private static readonly Color WeightBrown = new Color(0.72f, 0.53f, 0.26f, 1f);

		private static readonly Dictionary<Character, CompanionBars> _bars = new Dictionary<Character, CompanionBars>();

		private static GuiBar CreateBar(Transform healthTransform, Transform guiParent, string name, Color color, float yOffset)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//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_00be: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Object.Instantiate<GameObject>(((Component)healthTransform).gameObject, guiParent);
			((Object)obj).name = name;
			RectTransform component = ((Component)healthTransform).GetComponent<RectTransform>();
			((Transform)obj.GetComponent<RectTransform>()).localPosition = ((Transform)component).localPosition - new Vector3(0f, yOffset, 0f);
			Transform val = obj.transform.Find("health_slow");
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
			}
			Transform val2 = obj.transform.Find("health_fast_friendly");
			if ((Object)(object)val2 != (Object)null)
			{
				((Component)val2).gameObject.SetActive(false);
			}
			Transform val3 = obj.transform.Find("health_fast");
			if ((Object)(object)val3 == (Object)null)
			{
				return null;
			}
			GuiBar component2 = ((Component)val3).GetComponent<GuiBar>();
			if ((Object)(object)component2 == (Object)null)
			{
				return null;
			}
			component2.SetColor(color);
			return component2;
		}
	}
	[HarmonyPatch(typeof(BaseAI), "Follow")]
	internal static class Follow_RunDetection
	{
		private static void Postfix(BaseAI __instance, GameObject go)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!(__instance is CompanionAI))
			{
				return;
			}
			CompanionStamina component = ((Component)__instance).GetComponent<CompanionStamina>();
			if (!((Object)(object)component == (Object)null))
			{
				if ((Object)(object)go == (Object)null)
				{
					component.IsRunning = false;
					return;
				}
				float num = Vector3.Distance(go.transform.position, ((Component)__instance).transform.position);
				component.IsRunning = num > 10f;
			}
		}
	}
	public static class InventoryGuiPatches
	{
		[HarmonyPatch(typeof(InventoryGui), "Show")]
		private static class Show_Patch
		{
			private static void Postfix(Container container)
			{
				_companionContainerOpen = false;
				if ((Object)(object)container == (Object)null)
				{
					CompanionsPlugin.Log.LogDebug((object)"[InvGUI] Show — container=null, skipping");
					return;
				}
				if ((Object)(object)((Component)container).GetComponent<CompanionInteract>() == (Object)null)
				{
					CompanionsPlugin.Log.LogDebug((object)("[InvGUI] Show — container \"" + ((Object)container).name + "\" has no CompanionInteract, skipping"));
					return;
				}
				CompanionSetup component = ((Component)container).GetComponent<CompanionSetup>();
				if ((Object)(object)component == (Object)null)
				{
					CompanionsPlugin.Log.LogWarning((object)("[InvGUI] Show — container \"" + ((Object)container).name + "\" has CompanionInteract but no CompanionSetup!"));
					return;
				}
				_companionContainerOpen = true;
				CompanionsPlugin.Log.LogInfo((object)("[InvGUI] Show — COMPANION container opened for \"" + ((Object)container).name + "\", hiding vanilla panels"));
				HideVanillaPanels();
				CompanionInteractPanel.EnsureInstance();
				CompanionInteractPanel.Instance?.Show(component);
				CompanionsPlugin.Log.LogDebug((object)$"[InvGUI] Show — CompanionInteractPanel visible={CompanionInteractPanel.Instance?.IsVisible}");
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static class Hide_Patch
		{
			private static void Postfix()
			{
				if (_companionContainerOpen)
				{
					CompanionsPlugin.Log.LogInfo((object)"[InvGUI] Hide — closing companion container session");
				}
				_companionContainerOpen = false;
				CompanionInteractPanel.Instance?.Hide();
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static class UpdateContainer_Patch
		{
			private static float _lastLogTime;

			private static bool Prefix(Player player)
			{
				if (!_companionContainerOpen)
				{
					return true;
				}
				InventoryGui instance = InventoryGui.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return true;
				}
				object? obj = _currentContainerField?.GetValue(instance);
				Container val = (Container)((obj is Container) ? obj : null);
				if ((Object)(object)val == (Object)null || !val.IsOwner())
				{
					CompanionsPlugin.Log.LogWarning((object)("[InvGUI] UpdateContainer — companion container lost " + $"(null={(Object)(object)val == (Object)null}, owner={((val != null) ? new bool?(val.IsOwner()) : null)}), " + "falling through to vanilla"));
					_companionContainerOpen = false;
					return true;
				}
				val.SetInUse(true);
				bool flag = (Object)(object)instance.m_container != (Object)null && ((Component)instance.m_container).gameObject.activeSelf;
				bool flag2 = (Object)(object)instance.m_crafting != (Object)null && ((Component)instance.m_crafting).gameObject.activeSelf;
				HideVanillaPanels();
				if ((flag || flag2) && Time.time - _lastLogTime > 2f)
				{
					_lastLogTime = Time.time;
					CompanionsPlugin.Log.LogWarning((object)("[InvGUI] UpdateContainer — vanilla panels were active " + $"(container={flag}, crafting={flag2}), " + "re-hidden"));
				}
				return false;
			}
		}

		private static bool _companionContainerOpen;

		private static readonly FieldInfo _currentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer");

		private static void HideVanillaPanels()
		{
			if (!((Object)(object)InventoryGui.instance == (Object)null))
			{
				if ((Object)(object)InventoryGui.instance.m_container != (Object)null)
				{
					((Component)InventoryGui.instance.m_container).gameObject.SetActive(false);
				}
				if ((Object)(object)InventoryGui.instance.m_crafting != (Object)null)
				{
					((Component)InventoryGui.instance.m_crafting).gameObject.SetActive(false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	public static class PlayerHooks
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			CompanionManager.RestoreFollowTargets();
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	internal static class TakeInput_BlockForCompanionUI
	{
		private static void Postfix(ref bool __result)
		{
			if (!__result)
			{
				return;
			}
			CompanionInteractPanel instance = CompanionInteractPanel.Instance;
			if ((Object)(object)instance != (Object)null && instance.IsVisible)
			{
				__result = false;
				return;
			}
			CompanionRadialMenu instance2 = CompanionRadialMenu.Instance;
			if ((Object)(object)instance2 != (Object)null && instance2.IsVisible)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Projectile), "Setup")]
	internal static class ProjectileSetup_CompanionAccuracy
	{
		private static readonly FieldRef<Projectile, Vector3> _velRef = AccessTools.FieldRefAccess<Projectile, Vector3>("m_vel");

		private static float _lastLogTime;

		private static void Postfix(Projectile __instance, Character owner)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_008a: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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)
			//IL_00fd: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)owner == (Object)null || (Object)(object)((Component)owner).GetComponent<CompanionSetup>() == (Object)null)
			{
				return;
			}
			CompanionAI component = ((Component)owner).GetComponent<CompanionAI>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Character targetCreature = component.m_targetCreature;
			if ((Object)(object)targetCreature == (Object)null || targetCreature.IsDead())
			{
				return;
			}
			Vector3 val = _velRef.Invoke(__instance);
			float num = ((Vector3)(ref val)).magnitude;
			if (!(num < 0.1f))
			{
				if (num < 60f)
				{
					num = 60f;
				}
				Vector3 position = ((Component)__instance).transform.position;
				Vector3 val2 = targetCreature.GetCenterPoint();
				float num2 = Vector3.Distance(position, val2);
				Vector3 velocity = targetCreature.GetVelocity();
				float num3 = num2 / num;
				if (((Vector3)(ref velocity)).magnitude > 0.5f)
				{
					val2 += velocity * num3;
				}
				float num4 = 4.905f * num3 * num3;
				val2.y += num4;
				Vector3 val3 = val2 - position;
				Vector3 normalized = ((Vector3)(ref val3)).normalized;
				_velRef.Invoke(__instance) = normalized * num;
				if (Time.time - _lastLogTime > 1f)
				{
					_lastLogTime = Time.time;
					CompanionsPlugin.Log.LogDebug((object)("[Projectile] Arrow redirected — target=\"" + targetCreature.m_name + "\" " + $"dist={num2:F1} speed={num:F0} travelTime={num3:F2}s " + $"gravDrop={num4:F2} leadMag={((Vector3)(ref velocity)).magnitude * num3:F1} " + $"targetVel={((Vector3)(ref velocity)).magnitude:F1}"));
				}
			}
		}
	}
	public static class StaminaPatches
	{
		[HarmonyPatch(typeof(Character), "UseStamina")]
		private static class UseStamina_Patch
		{
			private static bool Prefix(Character __instance, float stamina)
			{
				CompanionStamina component = ((Component)__instance).GetComponent<CompanionStamina>();
				if ((Object)(object)component == (Object)null)
				{
					return true;
				}
				float stamina2 = component.Stamina;
				component.Drain(stamina);
				CompanionsPlugin.Log.LogDebug((object)($"[Stamina] UseStamina — drained {stamina:F1} " + $"({stamina2:F1} → {component.Stamina:F1} / {component.MaxStamina:F1}) " + "companion=\"" + __instance.m_name + "\""));
				return false;
			}
		}

		[HarmonyPatch(typeof(Character), "HaveStamina")]
		private static class HaveStamina_Patch
		{
			private static bool Prefix(Character __instance, float amount, ref bool __result)
			{
				CompanionStamina component = ((Component)__instance).GetComponent<CompanionStamina>();
				if ((Object)(object)component == (Object)null)
				{
					return true;
				}
				__result = component.Stamina >= amount;
				if (!__result && Time.time - _lastLogTime > 2f)
				{
					_lastLogTime = Time.time;
					CompanionsPlugin.Log.LogDebug((object)($"[Stamina] HaveStamina FAILED — need {amount:F1} " + $"have {component.Stamina:F1} / {component.MaxStamina:F1} " + "companion=\"" + __instance.m_name + "\""));
				}
				return false;
			}
		}

		private static float _lastLogTime;

		private const float LogInterval = 2f;
	}
	public static class TraderUIPatches
	{
		[HarmonyPatch]
		private static class BuildUI_Patch
		{
			private static MethodBase TargetMethod()
			{
				MethodInfo? obj = Type.GetType("TraderOverhaul.TraderUI, TraderOverhaul")?.GetMethod("BuildUI", BindingFlags.Instance | BindingFlags.NonPublic);
				if (obj == null)
				{
					ManualLogSource log = CompanionsPlugin.Log;
					if (log == null)
					{
						return obj;
					}
					log.LogWarning((object)"[TraderUIPatches] BuildUI method not found — patch skipped.");
				}
				return obj;
			}

			private static void Postfix(object __instance)
			{
				try
				{
					CacheReflection();
					InjectCompanionTab(__instance);
				}
				catch (Exception arg)
				{
					CompanionsPlugin.Log.LogError((object)$"[TraderUIPatches] BuildUI postfix error: {arg}");
				}
			}
		}

		[HarmonyPatch]
		private static class SwitchTab_Patch
		{
			private static MethodBase TargetMethod()
			{
				MethodInfo? obj = Type.GetType("TraderOverhaul.TraderUI, TraderOverhaul")?.GetMethod("SwitchTab", BindingFlags.Instance | BindingFlags.NonPublic);
				if (obj == null)
				{
					ManualLogSource log = CompanionsPlugin.Log;
					if (log == null)
					{
						return obj;
					}
					log.LogWarning((object)"[TraderUIPatches] SwitchTab method not found — patch skipped.");
				}
				return obj;
			}

			private static bool Prefix(object __instance, int newTab)
			{
				if (CompanionTabIndex < 0)
				{
					return true;
				}
				CacheReflection();
				if (_activeTabField == null)
				{
					return true;
				}
				if (newTab == CompanionTabIndex)
				{
					if ((int)_activeTabField.GetValue(__instance) == CompanionTabIndex)
					{
						return false;
					}
					ActivateCompanionTab(__instance);
					return false;
				}
				if ((Object)(object)_companionPanel?.Root != (Object)null)
				{
					_companionPanel.Root.SetActive(false);
				}
				return true;
			}
		}

		[HarmonyPatch]
		private static class RefreshTabHighlights_Patch
		{
			private static MethodBase TargetMethod()
			{
				MethodInfo? obj = Type.GetType("TraderOverhaul.TraderUI, TraderOverhaul")?.GetMethod("RefreshTabHighlights", BindingFlags.Instance | BindingFlags.NonPublic);
				if (obj == null)
				{
					ManualLogSource log = CompanionsPlugin.Log;
					if (log == null)
					{
						return obj;
					}
					log.LogWarning((object)"[TraderUIPatches] RefreshTabHighlights method not found — patch skipped.");
				}
				return obj;
			}

			private static void Postfix(object __instance)
			{
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				CacheReflection();
				if (!((Object)(object)_tabCompanions == (Object)null) && !(_activeTabField == null))
				{
					int num = (int)_activeTabField.GetValue(__instance);
					Button component = _tabCompanions.GetComponent<Button>();
					if ((Object)(object)component != (Object)null)
					{
						((Selectable)component).interactable = true;
						((Selectable)component).transition = (Transition)0;
					}
					Image component2 = _tabCompanions.GetComponent<Image>();
					if ((Object)(object)component2 != (Object)null)
					{
						((Graphic)component2).color = (Color)((num == CompanionTabIndex) ? GoldColor : new Color(0.45f, 0.45f, 0.45f, 1f));
					}
				}
			}
		}

		[HarmonyPatch]
		private static class RefreshTabPanels_Patch
		{
			private static MethodBase TargetMethod()
			{
				MethodInfo? obj = Type.GetType("TraderOverhaul.TraderUI, TraderOverhaul")?.GetMethod("RefreshTabPanels", BindingFlags.Instance | BindingFlags.NonPublic);
				if (obj == null)
				{
					ManualLogSource log = CompanionsPlugin.Log;
					if (log == null)
					{
						return obj;
					}
					log.LogWarning((object)"[TraderUIPatches] RefreshTabPanels method not found — patch skipped.");
				}
				return obj;
			}

			private static void Postfix(object __instance)
			{
				CacheReflection();
				if (!((Object)(object)_companionPanel?.Root == (Object)null) && !(_activeTabField == null))
				{
					if ((int)_activeTabField.GetValue(__instance) == CompanionTabIndex)
					{
						ActivateCompanionTab(__instance);
					}
					else
					{
						_companionPanel.Root.SetActive(false);
					}
				}
			}
		}

		[HarmonyPatch]
		private static class Update_Patch
		{
			private static MethodBase TargetMethod()
			{
				MethodInfo? obj = Type.GetType("TraderOverhaul.TraderUI, TraderOverhaul")?.GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic);
				if (obj == null)
				{
					ManualLogSource log = CompanionsPlugin.Log;
					if (log == null)
					{
						return obj;
					}
					log.LogWarning((object)"[TraderUIPatches] Update method not found — patch skipped.");
				}
				return obj;
			}

			private static void Prefix(object __instance, ref int __state)
			{
				CacheReflection();
				__state = ((_activeTabField != null) ? ((int)_activeTabField.GetValue(__instance)) : (-1));
			}

			private static void Postfix(object __instance, int __state)
			{
				if (CompanionTabIndex < 0 || _isVisibleField == null || _activeTabField == null || !(bool)_isVisibleField.GetValue(__instance))
				{
					return;
				}
				int num = (int)_activeTabField.GetValue(__instance);
				object? obj = _searchInputField?.GetValue(__instance);
				TMP_InputField val = (TMP_InputField)((obj is TMP_InputField) ? obj : null);
				if ((Object)(object)val != (Object)null && val.isFocused)
				{
					return;
				}
				if (__state == CompanionTabIndex && num != CompanionTabIndex)
				{
					if (!Input.GetKeyDown((KeyCode)113) && !ZInput.GetButtonDown("JoyTabLeft"))
					{
						ActivateCompanionTab(__instance);
						num = CompanionTabIndex;
					}
				}
				else if (__state == CompanionTabIndex - 1)
				{
					num = (int)_activeTabField.GetValue(__instance);
					if (num == CompanionTabIndex - 1 && (Input.GetKeyDown((KeyCode)101) || ZInput.GetButtonDown("JoyTabRight")))
					{
						ActivateCompanionTab(__instance);
						num = CompanionTabIndex;
					}
				}
				num = (int)_activeTabField.GetValue(__instance);
				if (num == CompanionTabIndex)
				{
					if ((Object)(object)_companionPanel?.Root != (Object)null && !_companionPanel.Root.activeSelf)
					{
						ActivateCompanionTab(__instance);
					}
					_companionPanel?.UpdatePerFrame();
				}
			}
		}

		private static Type _traderUIType;

		private static FieldInfo _mainPanelField;

		private static FieldInfo _buttonTemplateField;

		private static FieldInfo _activeTabField;

		private static FieldInfo _panelWidthField;

		private static FieldInfo _tabBtnHeightField;

		private static FieldInfo _leftColumnField;

		private static FieldInfo _middleColumnField;

		private static FieldInfo _rightColumnField;

		private static FieldInfo _bankContentPanelField;

		private static FieldInfo _searchFilterField;

		private static FieldInfo _searchInputField;

		private static FieldInfo _activeCategoryFilterField;

		private static FieldInfo _joyCategoryFocusIndexField;

		private static FieldInfo _colTopInsetField;

		private static FieldInfo _bottomPadField;

		private static FieldInfo _valheimFontField;

		private static FieldInfo _isVisibleField;

		private static FieldInfo _craftBtnHeightField;

		private static MethodInfo _refreshTabHighlightsMethod;

		private static MethodInfo _updateCategoryFilterVisualsMethod;

		private static GameObject _tabCompanions;

		private static CompanionPanel _companionPanel;

		private static bool _reflectionCached;

		private static readonly Color GoldColor = new Color(0.83f, 0.64f, 0.31f, 1f);

		internal static int CompanionTabIndex { get; private set; } = -1;


		private static void CacheReflection()
		{
			if (_reflectionCached)
			{
				return;
			}
			_traderUIType = Type.GetType("TraderOverhaul.TraderUI, TraderOverhaul");
			if (_traderUIType == null)
			{
				CompanionsPlugin.Log.LogError((object)"[TraderUIPatches] Could not find TraderUI type!");
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic;
			_mainPanelField = _traderUIType.GetField("_mainPanel", bindingAttr);
			_buttonTemplateField = _traderUIType.GetField("_buttonTemplate", bindingAttr);
			_activeTabField = _traderUIType.GetField("_activeTab", bindingAttr);
			_panelWidthField = _traderUIType.GetField("_panelWidth", bindingAttr);
			_tabBtnHeightField = _traderUIType.GetField("_tabBtnHeight", bindingAttr);
			_leftColumnField = _traderUIType.GetField("_leftColumn", bindingAttr);
			_middleColumnField = _traderUIType.GetField("_middleColumn", bindingAttr);
			_rightColumnField = _traderUIType.GetField("_rightColumn", bindingAttr);
			_bankContentPanelField = _traderUIType.GetField("_bankContentPanel", bindingAttr);
			_searchFilterField = _traderUIType.GetField("_searchFilter", bindingAttr);
			_searchInputField = _traderUIType.GetField("_searchInput", bindingAttr);
			_activeCategoryFilterField = _traderUIType.GetField("_activeCategoryFilter", bindingAttr);
			_joyCategoryFocusIndexField = _traderUIType.GetField("_joyCategoryFocusIndex", bindingAttr);
			_colTopInsetField = _traderUIType.GetField("_colTopInset", bindingAttr);
			_bottomPadField = _traderUIType.GetField("_bottomPad", bindingAttr);
			_valheimFontField = _traderUIType.GetField("_valheimFont", bindingAttr);
			_isVisibleField = _traderUIType.GetField("_isVisible", bindingAttr);
			_craftBtnHeightField = _traderUIType.GetField("_craftBtnHeight", bindingAttr);
			_refreshTabHighlightsMethod = _traderUIType.GetMethod("RefreshTabHighlights", bindingAttr);
			_updateCategoryFilterVisualsMethod = _traderUIType.GetMethod("UpdateCategoryFilterVisuals", bindingAttr);
			if (_mainPanelField == null)
			{
				CompanionsPlugin.Log.LogWarning((object)"[TraderUIPatches] _mainPanel field not found.");
			}
			if (_buttonTemplateField == null)
			{
				CompanionsPlugin.Log.LogWarning((object)"[TraderUIPatches] _buttonTemplate field not found.");
			}
			if (_activeTabField == null)
			{
				CompanionsPlugin.Log.LogWarning((object)"[TraderUIPatches] _activeTab field not found.");
			}
			if (_panelWidthField == null)
			{
				CompanionsPlugin.Log.LogWarning((object)"[TraderUIPatches] _panelWidth field not found.");
			}
			_reflectionCached = true;
			CompanionsPlugin.Log.LogInfo((object)"[TraderUIPatches] Reflection cached successfully.");
		}

		private static void InjectCompanionTab(object traderUI)
		{
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Expected O, but got Unknown
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0495: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0520: Unknown result type (might be due to invalid IL or missing references)
			if (_mainPanelField == null || _buttonTemplateField == null || _activeTabField == null || _panelWidthField == null || _tabBtnHeightField == null || _colTopInsetField == null || _bottomPadField == null || _valheimFontField == null)
			{
				CompanionsPlugin.Log.LogError((object)"[TraderUIPatches] Cannot inject companion tab — critical reflection fields are missing.");
				return;
			}
			_companionPanel?.Teardown();
			_companionPanel = null;
			if ((Object)(object)_tabCompanions != (Object)null)
			{
				Object.Destroy((Object)(object)_tabCompanions);
				_tabCompanions = null;
			}
			CompanionTabIndex = -1;
			GameObject val = (GameObject)_mainPanelField.GetValue(traderUI);
			GameObject val2 = (GameObject)_buttonTemplateField.GetValue(traderUI);
			float num = (float)_panelWidthField.GetValue(traderUI);
			float num2 = (float)_tabBtnHeightField.GetValue(traderUI);
			float colTopInset = (float)_colTopInsetField.GetValue(traderUI);
			float bottomPad = (float)_bottomPadField.GetValue(traderUI);
			object? value = _valheimFontField.GetValue(traderUI);
			TMP_FontAsset font = (TMP_FontAsset)((value is TMP_FontAsset) ? value : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return;
			}
			List<GameObject> list = new List<GameObject>();
			for (int i = 0; i < val.transform.childCount; i++)
			{
				GameObject gameObject = ((Component)val.transform.GetChild(i)).gameObject;
				if (((Object)gameObject).name.StartsWith("Tab_") && (Object)(object)gameObject.GetComponent<Button>() != (Object)null)
				{
					list.Add(gameObject);
				}
			}
			int num3 = list.Count + 1;
			CompanionTabIndex = list.Count;
			float num4 = (num - 12f - 4f * (float)(num3 - 1)) / (float)num3;
			float[] array = new float[num3];
			for (int j = 0; j < num3; j++)
			{
				array[j] = 6f + num4 / 2f + (float)j * (num4 + 4f);
			}
			for (int k = 0; k < list.Count; k++)
			{
				ResizeTab(list[k], array[k], num4);
			}
			_tabCompanions = Object.Instantiate<GameObject>(val2, val.transform);
			((Object)_tabCompanions).name = "Tab_Companions";
			_tabCompanions.SetActive(true);
			Button component = _tabCompanions.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				((UnityEventBase)component.onClick).RemoveAllListeners();
				((UnityEvent)component.onClick).AddListener((UnityAction)delegate
				{
					ActivateCompanionTab(traderUI);
				});
				Navigation navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)0;
				((Selectable)component).navigation = navigation;
			}
			TMP_Text componentInChildren = _tabCompanions.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = "Companions";
				((Component)componentInChildren).gameObject.SetActive(true);
			}
			for (int num5 = _tabCompanions.transform.childCount - 1; num5 >= 0; num5--)
			{
				Transform child = _tabCompanions.transform.GetChild(num5);
				if (!((Object)(object)componentInChildren != (Object)null) || (!((Object)(object)((Component)child).gameObject == (Object)(object)((Component)componentInChildren).gameObject) && !componentInChildren.transform.IsChildOf(child)))
				{
					Object.Destroy((Object)(object)((Component)child).gameObject);
				}
			}
			RectTransform component2 = _tabCompanions.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0f, 1f);
			component2.anchorMax = new Vector2(0f, 1f);
			component2.pivot = new Vector2(0.5f, 1f);
			component2.sizeDelta = new Vector2(num4, num2);
			component2.anchoredPosition = new Vector2(array[CompanionTabIndex], -6f);
			float buttonHeight = 30f;
			if (_craftBtnHeightField != null)
			{
				buttonHeight = (float)_craftBtnHeightField.GetValue(traderUI);
			}
			object? obj = _leftColumnField?.GetValue(traderUI);
			object? obj2 = ((obj is RectTransform) ? obj : null);
			object? obj3 = _middleColumnField?.GetValue(traderUI);
			RectTransform val3 = (RectTransform)((obj3 is RectTransform) ? obj3 : null);
			object? obj4 = _rightColumnField?.GetValue(traderUI);
			RectTransform val4 = (RectTransform)((obj4 is RectTransform) ? obj4 : null);
			float leftXL = ((obj2 != null) ? ((RectTransform)obj2).offsetMin.x : 6f);
			float leftXR = ((obj2 != null) ? ((RectTransform)obj2).offsetMax.x : 266f);
			float midXL = ((val3 != null) ? val3.offsetMin.x : 270f);
			float midXR = ((val3 != null) ? val3.offsetMax.x : 610f);
			float rightXL = ((val4 != null) ? val4.offsetMin.x : 614f);
			float rightXR = ((val4 != null) ? val4.offsetMax.x : 874f);
			RectTransform component3 = val.GetComponent<RectTransform>();
			float panelHeight = (((Object)(object)component3 != (Object)null) ? component3.sizeDelta.y : 432f);
			_companionPanel = new CompanionPanel();
			_companionPanel.Build(val.transform, colTopInset, bottomPad, font, val2, buttonHeight, leftXL, leftXR, midXL, midXR, rightXL, rightXR, panelHeight);
			CompanionsPlugin.Log.LogInfo((object)$"[TraderUIPatches] Companion tab injected at index {CompanionTabIndex} ({num3} total tabs).");
		}

		private static void ResizeTab(GameObject tab, float centerX, float width)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)tab == (Object)null))
			{
				RectTransform component = tab.GetComponent<RectTransform>();
				if (!((Object)(object)component == (Object)null))
				{
					component.sizeDelta = new Vector2(width, component.sizeDelta.y);
					component.anchoredPosition = new Vector2(centerX, component.anchoredPosition.y);
				}
			}
		}

		private static void ActivateCompanionTab(object traderUI)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			if (_activeTabField == null || _mainPanelField == null)
			{
				return;
			}
			if ((Object)(object)_companionPanel?.Root == (Object)null)
			{
				CompanionsPlugin.Log.LogWarning((object)"[TraderUIPatches] Companion panel missing during activation, attempting reinject.");
				InjectCompanionTab(traderUI);
				if ((Object)(object)_companionPanel?.Root == (Object)null)
				{
					return;
				}
			}
			bool flag = (int)_activeTabField.GetValue(traderUI) != CompanionTabIndex;
			if (flag)
			{
				_activeTabField.SetValue(traderUI, CompanionTabIndex);
			}
			_searchFilterField?.SetValue(traderUI, "");
			object? obj = _searchInputField?.GetValue(traderUI);
			TMP_InputField val = (TMP_InputField)((obj is TMP_InputField) ? obj : null);
			if ((Object)(object)val != (Object)null)
			{
				val.text = "";
			}
			_activeCategoryFilterField?.SetValue(traderUI, null);
			_joyCategoryFocusIndexField?.SetValue(traderUI, -1);
			_updateCategoryFilterVisualsMethod?.Invoke(traderUI, null);
			RefreshAllTabHighlights(traderUI);
			GameObject val2 = (GameObject)_mainPanelField.GetValue(traderUI);
			string text = (((Object)(object)_companionPanel?.Root != (Object)null) ? ((Object)_companionPanel.Root).name : "");
			for (int i = 0; i < val2.transform.childCount; i++)
			{
				GameObject gameObject = ((Component)val2.transform.GetChild(i)).gameObject;
				if (!((Object)gameObject).name.StartsWith("Tab_") && (!(((Object)gameObject).name == text) || text.Length <= 0))
				{
					gameObject.SetActive(false);
				}
			}
			if ((Object)(object)_companionPanel?.Root != (Object)null)
			{
				bool activeSelf = _companionPanel.Root.activeSelf;
				_companionPanel.Root.SetActive(true);
				if (flag || !activeSelf)
				{
					_companionPanel.Refresh();
				}
			}
			if ((Object)(object)EventSystem.current != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject((GameObject)null);
			}
		}

		private static void RefreshAllTabHighlights(object traderUI)
		{
			_refreshTabHighlightsMethod?.Invoke(traderUI, null);
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	public static class ZNetScenePatch
	{
		[HarmonyPostfix]
		private static void Postfix(ZNetScene __instance)
		{
			CompanionPrefabs.Init(__instance);
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	public static class ContainerAwakePatch
	{
		private static readonly FieldInfo _inventoryField = AccessTools.Field(typeof(Container), "m_inventory");

		private static readonly FieldInfo _invWidthField = AccessTools.Field(typeof(Inventory), "m_width");

		private static readonly FieldInfo _invHeightField = AccessTools.Field(typeof(Inventory), "m_height");

		private static readonly MethodInfo _onContainerChanged = AccessTools.Method(typeof(Container), "OnContainerChanged", (Type[])null, (Type[])null);

		[HarmonyPostfix]
		private static void Postfix(Container __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<CompanionSetup>() == (Object)null)
			{
				return;
			}
			Humanoid component = ((Component)__instance).GetComponent<Humanoid>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component2 != (Object)null && component2.GetZDO() != null && CompanionTierData.IsDvergerVariant(component2.GetZDO().GetPrefab()))
			{
				CompanionsPlugin.Log.LogDebug((object)"[ContainerAwake] Dverger variant — keeping separate inventories");
				return;
			}
			if (((Object)(object)component2 == (Object)null || component2.GetZDO() == null) && ((Object)((Component)__instance).gameObject).name.Contains("Dverger"))
			{
				CompanionsPlugin.Log.LogDebug((object)"[ContainerAwake] Dverger variant (name check) — keeping separate inventories");
				return;
			}
			Inventory inventory = component.GetInventory();
			if (!(_inventoryField == null) && inventory != null)
			{
				int num = ((__instance.m_width > 0) ? __instance.m_width : 4);
				int num2 = ((__instance.m_height > 0) ? __instance.m_height : 8);
				if (_invWidthField != null)
				{
					_invWidthField.SetValue(inventory, num);
				}
				if (_invHeightField != null)
				{
					_invHeightField.SetValue(inventory, num2);
				}
				_inventoryField.SetValue(__instance, inventory);
				if (_onContainerChanged != null)
				{
					Action b = (Action)Delegate.CreateDelegate(typeof(Action), __instance, _onContainerChanged);
					inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, b);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Awake")]
	public static class InventoryGuiAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			CompanionInteractPanel.EnsureInstance();
		}
	}
	public class CombatController : MonoBehaviour
	{
		internal enum CombatPhase
		{
			Idle,
			Melee,
			Ranged,
			Retreat
		}

		private enum MeadType
		{
			Health,
			Stamina
		}

		private const float HealthRetreatPct = 0.3f;

		private const float StaminaRetreatPct = 0.15f;

		private const float HealthRecoverPct = 0.5f;

		private const float Stamin