Decompiled source of OfflineCompanions v0.0.1
Companions.dll
Decompiled 4 days 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