Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of OfflineCompanions v0.0.1
Companions.dll
Decompiled 4 months ago
The result has been truncated due to the large size, download it to view full contents!
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