using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("HitchingPost")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("A Valheim mod for hitching post functionality.")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyInformationalVersion("1.0.6+00f5b54960f27d424401f66a2c6e2b019a1ffbfb")] [assembly: AssemblyProduct("HitchingPost")] [assembly: AssemblyTitle("HitchingPost")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.6.0")] [module: UnverifiableCode] [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 malafein.Valheim.HitchingPost { [HarmonyPatch] public static class BeamPatches { [HarmonyPatch(typeof(Piece), "Awake")] [HarmonyPostfix] private static void Postfix_PieceAwake(Piece __instance) { if (HitchingManager.IsBeam(((Component)__instance).gameObject) && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { HoverText val = ((Component)__instance).gameObject.AddComponent(); val.m_text = ""; } } [HarmonyPatch(typeof(HoverText), "GetHoverText")] [HarmonyPostfix] [HarmonyPriority(200)] private static void Postfix_HoverTextBeam(HoverText __instance, ref string __result) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) Piece componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null || !HitchingManager.IsBeam(((Component)componentInParent).gameObject)) { return; } if (HitchingManager.IsHitchingModeActive) { KeyboardShortcut value = Plugin.HitchKey.Value; KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey; string text = ((object)(KeyCode)(ref mainKey)).ToString(); string text2 = "creature"; if ((Object)(object)HitchingManager.HitchTarget != (Object)null) { text2 = HitchingManager.HitchTarget.m_name; ZNetView component = ((Component)HitchingManager.HitchTarget).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid()) { string @string = component.GetZDO().GetString("TamedName", ""); text2 = (string.IsNullOrEmpty(@string) ? Localization.instance.Localize(text2) : @string); } else { text2 = Localization.instance.Localize(text2); } } if (!string.IsNullOrEmpty(__result)) { __result += "\n"; } __result = __result + "[" + text + "] Tether " + text2 + " here"; } if (!Plugin.DebugMode.Value) { return; } ZNetView component2 = ((Component)componentInParent).GetComponent(); if (!((Object)(object)component2 != (Object)null) || !component2.IsValid()) { return; } string[] hitchedCreatures = HitchingManager.GetHitchedCreatures(component2); if (hitchedCreatures.Length == 0) { __result += "\n[DBG] Tether ID: "; return; } string[] array = hitchedCreatures; foreach (string text3 in array) { __result = __result + "\n[DBG] Tether ID: " + text3 + ""; } } [HarmonyPatch(typeof(WearNTear), "Destroy")] [HarmonyPrefix] private static void Prefix_WearNTearDestroy(WearNTear __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null || !HitchingManager.IsBeam(((Component)__instance).gameObject)) { return; } ZNetView component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } string[] hitchedCreatures = HitchingManager.GetHitchedCreatures(component); if (hitchedCreatures.Length == 0) { return; } TetherController[] array = Object.FindObjectsOfType(); foreach (TetherController tetherController in array) { ZNetView component2 = ((Component)tetherController).GetComponent(); if (!((Object)(object)component2 != (Object)null) || !component2.IsValid()) { continue; } string @string = component2.GetZDO().GetString("hitchingpost.beam", ""); if (!string.IsNullOrEmpty(@string) && Array.IndexOf(hitchedCreatures, @string) >= 0) { Character component3 = ((Component)tetherController).GetComponent(); if ((Object)(object)component3 != (Object)null) { HitchingManager.Unhitch(component3); } } } } } [HarmonyPatch] public static class CreaturePatches { [HarmonyPatch(typeof(Tameable), "GetHoverText")] [HarmonyPostfix] [HarmonyPriority(200)] private static void Postfix_TameableHoverText(Tameable __instance, ref string __result) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (!__instance.IsTamed()) { return; } Character component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return; } KeyboardShortcut value = Plugin.HitchKey.Value; KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey; string text = ((object)(KeyCode)(ref mainKey)).ToString(); if (HitchingManager.IsHitched(component)) { __result = __result + "\n[" + text + "] Unhitch"; } else if (HitchingManager.IsHitchingModeActive && (Object)(object)HitchingManager.HitchTarget == (Object)(object)component) { __result = __result + "\n[" + text + "] Cancel Hitching"; } else if (!HitchingManager.IsHitchingModeActive) { __result = __result + "\n[" + text + "] Hitch"; } if (Plugin.DebugMode.Value) { ZNetView component2 = ((Component)__instance).GetComponent(); if ((Object)(object)component2 != (Object)null && component2.IsValid()) { string @string = component2.GetZDO().GetString("hitchingpost.beam", ""); string text2 = (string.IsNullOrEmpty(@string) ? "" : @string); __result = __result + "\n[DBG] Tether ID: " + text2 + ""; } } } [HarmonyPatch(typeof(Tameable), "Awake")] [HarmonyPostfix] private static void Postfix_TameableAwake(Tameable __instance) { if (!__instance.IsTamed()) { return; } Character component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && !(component is Player)) { ZNetView component2 = ((Component)__instance).GetComponent(); if (!((Object)(object)component2 == (Object)null) && component2.IsValid() && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Tameable), "Tame")] [HarmonyPostfix] private static void Postfix_TameableTame(Tameable __instance) { if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } public static class HitchingManager { public const float TetherLength = 5f; private static readonly FieldInfo s_monsterAIFollow = AccessTools.Field(typeof(MonsterAI), "m_follow"); public static bool IsHitchingModeActive { get; private set; } public static Character HitchTarget { get; private set; } public static void StartHitching(Character creature) { IsHitchingModeActive = true; HitchTarget = creature; SetFollow(creature, ((Component)Player.m_localPlayer).gameObject); TetherController tetherController = ((Component)creature).GetComponent() ?? ((Component)creature).gameObject.AddComponent(); tetherController.InitHitchingMode(Player.m_localPlayer); Plugin.DebugLog("Hitching mode activated for " + creature.GetHoverName()); } public static void CancelHitching() { if ((Object)(object)HitchTarget != (Object)null) { SetStay(HitchTarget); TetherController component = ((Component)HitchTarget).GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } IsHitchingModeActive = false; HitchTarget = null; ZLog.Log((object)"[HitchingPost] Hitching mode cancelled"); } public static void HitchToBeam(ZNetView beamNView) { //IL_0168: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)HitchTarget == (Object)null || (Object)(object)beamNView == (Object)null) { return; } ZNetView component = ((Component)HitchTarget).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { bool flag = component.IsOwner(); bool flag2 = beamNView.IsOwner(); if (!flag) { component.ClaimOwnership(); } if (!flag2) { beamNView.ClaimOwnership(); } ZDO zDO = component.GetZDO(); ZDO zDO2 = beamNView.GetZDO(); string text = Guid.NewGuid().ToString(); zDO.Set("hitchingpost.beam", text); Plugin.DebugLog("Creature ZDO write readback: '" + zDO.GetString("hitchingpost.beam", "") + "' (expected: '" + text + "')"); AddCreatureToBeam(beamNView, text); Plugin.DebugLog("Beam ZDO creature list after write: '" + beamNView.GetZDO().GetString("hitchingpost.creature", "") + "'"); SetStay(HitchTarget); TetherController component2 = ((Component)HitchTarget).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.ForceBeam(beamNView); } ZLog.Log((object)$"[HitchingPost] {HitchTarget.GetHoverName()} hitched to beam at {((Component)beamNView).transform.position}"); IsHitchingModeActive = false; HitchTarget = null; } } public static void Unhitch(Character creature) { ZNetView component = ((Component)creature).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid()) { if (!component.IsOwner()) { component.ClaimOwnership(); } ZDO zDO = component.GetZDO(); string @string = zDO.GetString("hitchingpost.beam", ""); if (!string.IsNullOrEmpty(@string)) { ZNetView[] array = Object.FindObjectsOfType(); foreach (ZNetView val in array) { if (val.IsValid() && IsBeam(((Component)val).gameObject) && BeamHasCreature(val, @string)) { RemoveCreatureFromBeam(val, @string); break; } } } zDO.Set("hitchingpost.beam", ""); } SetFollow(creature); ZLog.Log((object)("[HitchingPost] " + creature.GetHoverName() + " unhitched")); } public static bool IsHitched(Character creature) { ZNetView component = ((Component)creature).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } return !string.IsNullOrEmpty(component.GetZDO().GetString("hitchingpost.beam", "")); } public static bool IsBeam(GameObject go) { string text = ((Object)go).name.ToLower().Replace("(clone)", "").Trim(); return text.Contains("beam") || text.Contains("pole") || text.Contains("post"); } public static string[] GetHitchedCreatures(ZNetView beamNView) { if ((Object)(object)beamNView == (Object)null || !beamNView.IsValid()) { return new string[0]; } string @string = beamNView.GetZDO().GetString("hitchingpost.creature", ""); if (string.IsNullOrEmpty(@string)) { return new string[0]; } return @string.Split(new char[1] { ',' }); } public static bool BeamHasCreature(ZNetView beamNView, string tetherId) { string[] hitchedCreatures = GetHitchedCreatures(beamNView); return Array.IndexOf(hitchedCreatures, tetherId) >= 0; } public static void AddCreatureToBeam(ZNetView beamNView, string tetherId) { if ((Object)(object)beamNView == (Object)null || !beamNView.IsValid()) { return; } string @string = beamNView.GetZDO().GetString("hitchingpost.creature", ""); if (!string.IsNullOrEmpty(@string)) { if (!BeamHasCreature(beamNView, tetherId)) { beamNView.GetZDO().Set("hitchingpost.creature", @string + "," + tetherId); } } else { beamNView.GetZDO().Set("hitchingpost.creature", tetherId); } } public static void RemoveCreatureFromBeam(ZNetView beamNView, string tetherId) { if (!((Object)(object)beamNView == (Object)null) && beamNView.IsValid() && BeamHasCreature(beamNView, tetherId)) { if (!beamNView.IsOwner()) { beamNView.ClaimOwnership(); } List list = new List(GetHitchedCreatures(beamNView)); list.Remove(tetherId); beamNView.GetZDO().Set("hitchingpost.creature", string.Join(",", list.ToArray())); } } private static void SetFollow(Character creature, GameObject target = null) { MonsterAI component = ((Component)creature).GetComponent(); if ((Object)(object)component != (Object)null) { s_monsterAIFollow.SetValue(component, target); } } private static void SetStay(Character creature) { MonsterAI component = ((Component)creature).GetComponent(); if (!((Object)(object)component == (Object)null)) { s_monsterAIFollow.SetValue(component, null); ((BaseAI)component).SetPatrolPoint(); } } } [HarmonyPatch] public static class PlayerPatches { [HarmonyPatch(typeof(Player), "Update")] [HarmonyPostfix] private static void Postfix(Player __instance) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !(bool)AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null).Invoke(__instance, null)) { return; } KeyboardShortcut value = Plugin.HitchKey.Value; if (!((KeyboardShortcut)(ref value)).IsDown()) { return; } GameObject hoverObject = ((Humanoid)__instance).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { if (HitchingManager.IsHitchingModeActive) { HitchingManager.CancelHitching(); } } else if (!HitchingManager.IsHitchingModeActive) { HandleOutOfHitchingMode(hoverObject); } else { HandleInHitchingMode(hoverObject); } } private static void HandleOutOfHitchingMode(GameObject hoverGO) { Tameable componentInParent = hoverGO.GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsTamed()) { return; } Character component = ((Component)componentInParent).GetComponent(); if (!((Object)(object)component == (Object)null) && !(component is Player)) { if (HitchingManager.IsHitched(component)) { HitchingManager.Unhitch(component); } else { HitchingManager.StartHitching(component); } } } private static void HandleInHitchingMode(GameObject hoverGO) { Tameable componentInParent = hoverGO.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)((Component)componentInParent).GetComponent() == (Object)(object)HitchingManager.HitchTarget) { HitchingManager.CancelHitching(); return; } Piece componentInParent2 = hoverGO.GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null && HitchingManager.IsBeam(((Component)componentInParent2).gameObject)) { ZNetView component = ((Component)componentInParent2).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid()) { HitchingManager.HitchToBeam(component); return; } } HitchingManager.CancelHitching(); } } [BepInPlugin("com.malafein.hitchingpost", "HitchingPost", "1.0.6")] public class Plugin : BaseUnityPlugin { public const string ModGUID = "com.malafein.hitchingpost"; public const string ModName = "HitchingPost"; public const string ModVersion = "1.0.6"; public const string ZDO_KEY_BEAM = "hitchingpost.beam"; public const string ZDO_KEY_CREATURE = "hitchingpost.creature"; private readonly Harmony harmony = new Harmony("com.malafein.hitchingpost"); public static ConfigEntry HitchKey { get; private set; } public static ConfigEntry DebugMode { get; private set; } private void Awake() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) HitchKey = ((BaseUnityPlugin)this).Config.Bind("General", "HitchKey", new KeyboardShortcut((KeyCode)104, Array.Empty()), "Key to activate hitching mode, tether a creature to a beam, or unhitch a tethered creature."); DebugMode = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugMode", false, "When enabled, shows tether GUIDs in hover text and as a floating label along the rope."); ZLog.Log((object)"HitchingPost 1.0.6 is loading..."); harmony.PatchAll(); ZLog.Log((object)"HitchingPost loaded!"); } public static void DebugLog(string message) { if (DebugMode.Value) { ZLog.Log((object)("[HitchingPost] [DEBUG] " + message)); } } public static void WarningLog(string message) { ZLog.LogWarning((object)("[HitchingPost] [WARNING] " + message)); } public static void ErrorLog(string message) { ZLog.LogError((object)("[HitchingPost] [ERROR] " + message)); } } public class TetherController : MonoBehaviour { private static readonly FieldInfo s_characterBody = AccessTools.Field(typeof(Character), "m_body"); private Transform m_playerTarget; private ZNetView m_beamNView; private ZNetView m_nview; private Character m_creature; private GameObject m_ropeObject; private LineConnect m_lineConnect; private Transform m_ropeAnchor; private bool m_usingLineConnect; private LineRenderer m_fallbackRope; private GameObject m_debugLabel; private TextMesh m_debugText; private const float CreatureAttachHeight = 0.9f; private const float PullStrength = 6f; private const float MaxRopeSlack = 0.3f; private float m_updateTimer; private int m_networkWaitTicks = 0; private static GameObject s_vfxHarpoonedPrefab; private static bool s_prefabSearchDone; private static Material s_fallbackRopeMaterial; private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) m_creature = ((Component)this).GetComponent(); m_nview = ((Component)this).GetComponent(); if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { Plugin.DebugLog($"TetherController Awake on {m_creature.GetHoverName()} (ZDO: {m_nview.GetZDO().m_uid})"); } } public void InitHitchingMode(Player player) { m_playerTarget = ((Component)player).transform; m_beamNView = null; CreateRope(((Component)player).GetComponent()); Plugin.DebugLog("InitHitchingMode active on " + m_creature.GetHoverName()); } public void ForceBeam(ZNetView beam) { m_beamNView = beam; m_playerTarget = null; CreateRope(beam); UpdateBeamTether(); } private void FixedUpdate() { if ((Object)(object)m_creature == (Object)null || (Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { return; } if ((Object)(object)m_playerTarget != (Object)null) { if (HitchingManager.IsHitchingModeActive && (Object)(object)HitchingManager.HitchTarget == (Object)(object)m_creature) { UpdateRopeAnchor(); UpdateSlack(); if (!m_usingLineConnect) { DrawFallbackRopeToPlayer(); } return; } m_playerTarget = null; } m_updateTimer += Time.fixedDeltaTime; float num = (((Object)(object)m_beamNView == (Object)null || !m_beamNView.IsValid()) ? 2f : 0.5f); if (m_updateTimer > num) { m_updateTimer = 0f; SyncZdoState(); } if ((Object)(object)m_beamNView != (Object)null && m_beamNView.IsValid()) { UpdateBeamTether(); } else { HideRope(); } } private void CreateRope(ZNetView peer) { DestroyRope(); EnsureRopeAnchor(); if (TryCreateLineConnectRope(peer)) { m_usingLineConnect = true; Plugin.DebugLog("Created authentic LineConnect rope on " + m_creature.GetHoverName()); } else { CreateFallbackRope(); m_usingLineConnect = false; Plugin.WarningLog("Using fallback straight-line rope on " + m_creature.GetHoverName()); } } private void EnsureRopeAnchor() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_ropeAnchor != (Object)null)) { GameObject val = new GameObject("HitchingPost_RopeAnchor"); val.transform.SetParent(((Component)this).transform); val.transform.localPosition = Vector3.up * 0.9f; m_ropeAnchor = val.transform; Plugin.DebugLog($"Created rope anchor on {m_creature.GetHoverName()} at local height {0.9f}"); } } private bool TryCreateLineConnectRope(ZNetView peer) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindVfxHarpoonedPrefab(); if ((Object)(object)val == (Object)null || (Object)(object)peer == (Object)null) { return false; } GameObject val2 = new GameObject("HitchingPost_TempHost"); val2.SetActive(false); m_ropeObject = Object.Instantiate(val, val2.transform); ZNetView component = m_ropeObject.GetComponent(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); Plugin.DebugLog("ZNetView removed before activation (no ZDO registered)"); } else { Plugin.DebugLog("Rope prefab has no ZNetView"); } ParticleSystem[] componentsInChildren = m_ropeObject.GetComponentsInChildren(true); foreach (ParticleSystem val3 in componentsInChildren) { Plugin.DebugLog("Stripping ParticleSystem '" + ((Object)((Component)val3).gameObject).name + "' from rope VFX"); Object.DestroyImmediate((Object)(object)((Component)val3).gameObject); } ZSyncTransform[] componentsInChildren2 = m_ropeObject.GetComponentsInChildren(true); foreach (ZSyncTransform val4 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val4); } ZNetView[] componentsInChildren3 = m_ropeObject.GetComponentsInChildren(true); foreach (ZNetView val5 in componentsInChildren3) { Object.DestroyImmediate((Object)(object)val5); } m_ropeObject.transform.SetParent(m_ropeAnchor); m_ropeObject.transform.localPosition = Vector3.zero; m_ropeObject.transform.localRotation = Quaternion.identity; Object.Destroy((Object)(object)val2); m_lineConnect = m_ropeObject.GetComponent(); if ((Object)(object)m_lineConnect == (Object)null) { Plugin.WarningLog("vfx_Harpooned instance missing LineConnect component"); Object.Destroy((Object)(object)m_ropeObject); m_ropeObject = null; return false; } m_lineConnect.SetPeer(peer); m_lineConnect.m_maxDistance = 10f; m_lineConnect.m_dynamicThickness = true; m_lineConnect.m_minThickness = 0.04f; Plugin.DebugLog($"LineConnect configured: maxDist={m_lineConnect.m_maxDistance}, peer={((Object)((Component)peer).gameObject).name}"); return true; } private void CreateFallbackRope() { if (!((Object)(object)m_fallbackRope != (Object)null)) { m_fallbackRope = ((Component)this).gameObject.AddComponent(); ((Renderer)m_fallbackRope).material = BuildFallbackMaterial(); m_fallbackRope.startWidth = 0.04f; m_fallbackRope.endWidth = 0.04f; m_fallbackRope.positionCount = 2; m_fallbackRope.useWorldSpace = true; ((Renderer)m_fallbackRope).shadowCastingMode = (ShadowCastingMode)0; m_fallbackRope.textureMode = (LineTextureMode)1; Plugin.DebugLog("Created fallback LineRenderer rope"); } } private void UpdateRopeAnchor() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_ropeAnchor != (Object)null) { m_ropeAnchor.localPosition = Vector3.up * 0.9f; } } private void UpdateBeamTether() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00cd: 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_0102: Unknown result type (might be due to invalid IL or missing references) UpdateRopeAnchor(); UpdateSlack(); UpdateDebugLabel(); if (m_usingLineConnect && (Object)(object)m_ropeObject != (Object)null && !m_ropeObject.activeSelf) { m_ropeObject.SetActive(true); } if (!m_usingLineConnect && (Object)(object)m_fallbackRope != (Object)null) { Vector3 position = ((Component)m_beamNView).transform.position; Vector3 from = ((Component)m_creature).transform.position + Vector3.up * 0.9f; DrawFallbackRope(from, position); } if (m_nview.IsOwner()) { float num = Vector3.Distance(((Component)m_creature).transform.position, ((Component)m_beamNView).transform.position); if (num > 5f) { ApplyPullForce(((Component)m_beamNView).transform.position); } } } private void UpdateSlack() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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) if (m_usingLineConnect && !((Object)(object)m_lineConnect == (Object)null)) { float num = 0f; if ((Object)(object)m_beamNView != (Object)null && m_beamNView.IsValid()) { num = Vector3.Distance(((Component)m_creature).transform.position, ((Component)m_beamNView).transform.position); } else if ((Object)(object)m_playerTarget != (Object)null) { num = Vector3.Distance(((Component)m_creature).transform.position, m_playerTarget.position); } float num2 = 5f; float slack = (1f - Utils.LerpStep(num2 / 2f, num2, num)) * 0.3f; m_lineConnect.SetSlack(slack); } } private void HideRope() { if (m_usingLineConnect) { if ((Object)(object)m_ropeObject != (Object)null && m_ropeObject.activeSelf) { m_ropeObject.SetActive(false); Plugin.DebugLog("Rope hidden on " + m_creature.GetHoverName() + " (Beam invalid/null)"); } } else if ((Object)(object)m_fallbackRope != (Object)null && ((Renderer)m_fallbackRope).enabled) { ((Renderer)m_fallbackRope).enabled = false; Plugin.DebugLog("Rope disabled on " + m_creature.GetHoverName() + " (Beam invalid/null)"); } } private void DestroyRope() { if ((Object)(object)m_ropeObject != (Object)null) { Object.DestroyImmediate((Object)(object)m_ropeObject); m_ropeObject = null; m_lineConnect = null; Character creature = m_creature; Plugin.DebugLog("Destroyed LineConnect rope on " + ((creature != null) ? creature.GetHoverName() : null)); } if ((Object)(object)m_fallbackRope != (Object)null) { Object.DestroyImmediate((Object)(object)m_fallbackRope); m_fallbackRope = null; Character creature2 = m_creature; Plugin.DebugLog("Destroyed fallback rope on " + ((creature2 != null) ? creature2.GetHoverName() : null)); } DestroyDebugLabel(); } private void OnDestroy() { DestroyRope(); DestroyDebugLabel(); if ((Object)(object)m_ropeAnchor != (Object)null) { Object.Destroy((Object)(object)((Component)m_ropeAnchor).gameObject); } } private void DrawFallbackRopeToPlayer() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)m_fallbackRope == (Object)null) && !((Object)(object)m_playerTarget == (Object)null)) { DrawFallbackRope(((Component)m_creature).transform.position + Vector3.up * 0.9f, m_playerTarget.position + Vector3.up * 1.2f); } } private void DrawFallbackRope(Vector3 from, Vector3 to) { //IL_0015: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) ((Renderer)m_fallbackRope).enabled = true; m_fallbackRope.SetPosition(0, from); m_fallbackRope.SetPosition(1, to); float num = Vector3.Distance(from, to); if ((Object)(object)((Renderer)m_fallbackRope).material != (Object)null) { ((Renderer)m_fallbackRope).material.mainTextureScale = new Vector2(num * 2f, 1f); } } private void ApplyPullForce(Vector3 beamPos) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_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_006d: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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) object? value = s_characterBody.GetValue(m_creature); Rigidbody val = (Rigidbody)((value is Rigidbody) ? value : null); if (!((Object)(object)val == (Object)null)) { Vector3 val2 = beamPos - ((Component)m_creature).transform.position; Vector3 normalized = ((Vector3)(ref val2)).normalized; float num = Vector3.Distance(((Component)m_creature).transform.position, beamPos) - 5f; float num2 = Vector3.Dot(val.velocity, -normalized); if (num2 > 0f) { val.velocity -= -normalized * num2; } val.velocity += normalized * Mathf.Min(num * 6f * Time.fixedDeltaTime, 3f); } } private static GameObject FindVfxHarpoonedPrefab() { if ((Object)(object)s_vfxHarpoonedPrefab != (Object)null) { return s_vfxHarpoonedPrefab; } if (s_prefabSearchDone) { return null; } s_prefabSearchDone = true; if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject prefab = ZNetScene.instance.GetPrefab("vfx_Harpooned"); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent() != (Object)null) { s_vfxHarpoonedPrefab = prefab; return s_vfxHarpoonedPrefab; } Plugin.WarningLog("vfx_Harpooned not found in ZNetScene — using fallback rope"); return null; } private static Material BuildFallbackMaterial() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s_fallbackRopeMaterial != (Object)null) { return s_fallbackRopeMaterial; } Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val != (Object)null) { Material val2 = new Material(val); val2.color = new Color(0.55f, 0.38f, 0.18f, 1f); s_fallbackRopeMaterial = val2; Plugin.DebugLog("Created fallback rope material (brown, Sprites/Default)"); return s_fallbackRopeMaterial; } Plugin.ErrorLog("Failed to create fallback material — Sprites/Default shader not found"); return null; } private void UpdateDebugLabel() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.DebugMode.Value) { DestroyDebugLabel(); } else if (!((Object)(object)m_beamNView == (Object)null) && m_beamNView.IsValid()) { string @string = m_nview.GetZDO().GetString("hitchingpost.beam", ""); string text = (string.IsNullOrEmpty(@string) ? "???" : @string.Substring(0, Mathf.Min(8, @string.Length))); if ((Object)(object)m_debugLabel == (Object)null) { m_debugLabel = new GameObject("HitchingPost_DebugLabel"); m_debugText = m_debugLabel.AddComponent(); m_debugText.fontSize = 24; m_debugText.characterSize = 0.05f; m_debugText.anchor = (TextAnchor)4; m_debugText.alignment = (TextAlignment)1; m_debugText.color = Color.cyan; } Vector3 val = (((Object)(object)m_ropeAnchor != (Object)null) ? m_ropeAnchor.position : (((Component)this).transform.position + Vector3.up * 0.9f)); m_debugLabel.transform.position = (val + ((Component)m_beamNView).transform.position) * 0.5f; if ((Object)(object)Camera.main != (Object)null) { m_debugLabel.transform.rotation = ((Component)Camera.main).transform.rotation; } m_debugText.text = text; } } private void DestroyDebugLabel() { if ((Object)(object)m_debugLabel != (Object)null) { Object.Destroy((Object)(object)m_debugLabel); m_debugLabel = null; m_debugText = null; } } private void SyncZdoState() { string @string = m_nview.GetZDO().GetString("hitchingpost.beam", ""); if (string.IsNullOrEmpty(@string)) { if ((Object)(object)m_beamNView != (Object)null) { Plugin.DebugLog($"Tether broke/cleared on {m_creature.GetHoverName()}. IsOwner: {m_nview.IsOwner()}"); m_beamNView = null; DestroyRope(); } return; } if ((Object)(object)m_beamNView != (Object)null) { if (!m_beamNView.IsValid()) { } return; } Stopwatch stopwatch = Stopwatch.StartNew(); ZNetView[] array = Object.FindObjectsOfType(); stopwatch.Stop(); Plugin.DebugLog($"SyncZdoState scan: {array.Length} ZNetViews in {stopwatch.ElapsedMilliseconds}ms"); if (stopwatch.ElapsedMilliseconds > 50) { Plugin.WarningLog($"SyncZdoState scan took {stopwatch.ElapsedMilliseconds}ms ({array.Length} ZNetViews) — possible stutter"); } ZNetView[] array2 = array; foreach (ZNetView val in array2) { if (val.IsValid() && HitchingManager.IsBeam(((Component)val).gameObject) && HitchingManager.BeamHasCreature(val, @string)) { m_beamNView = val; CreateRope(val); Plugin.DebugLog(m_creature.GetHoverName() + " successfully resolved beam instance by GUID " + @string + "."); return; } } m_networkWaitTicks++; if (m_networkWaitTicks % 4 == 0) { Plugin.WarningLog(m_creature.GetHoverName() + " cannot find beam with GUID " + @string + ". Wait for network load."); } } } }