Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HitchingPost v1.0.8
HitchingPost.dll
Decompiled 2 days agousing 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("HitchingPost")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A Valheim mod for hitching post functionality.")] [assembly: AssemblyFileVersion("1.0.8.0")] [assembly: AssemblyInformationalVersion("1.0.8+eefef51dfe4736bffb2514b747a032c01a0ced75")] [assembly: AssemblyProduct("HitchingPost")] [assembly: AssemblyTitle("HitchingPost")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.8.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<HoverText>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<HoverText>().m_text = ""; } } [HarmonyPatch(typeof(HoverText), "GetHoverText")] [HarmonyPostfix] [HarmonyPriority(200)] private static void Postfix_HoverTextBeam(HoverText __instance, ref string __result) { //IL_002d: 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_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) Piece componentInParent = ((Component)__instance).GetComponentInParent<Piece>(); 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<ZNetView>(); 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 + "[<color=yellow><b>" + text + "</b></color>] Tether " + text2 + " here"; } if (!Plugin.DebugMode.Value) { return; } ZNetView component2 = ((Component)componentInParent).GetComponent<ZNetView>(); if (!((Object)(object)component2 != (Object)null) || !component2.IsValid()) { return; } string[] hitchedCreatures = HitchingManager.GetHitchedCreatures(component2); if (hitchedCreatures.Length == 0) { __result += "<size=12>\n[DBG] Tether ID: <color=#0FF><none></color></size>"; return; } string[] array = hitchedCreatures; foreach (string text3 in array) { __result = __result + "<size=12>\n[DBG] Tether ID: <color=#0FF>" + text3 + "</color></size>"; } } [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<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } string[] hitchedCreatures = HitchingManager.GetHitchedCreatures(component); if (hitchedCreatures.Length == 0) { return; } TetherController[] array = Object.FindObjectsOfType<TetherController>(); foreach (TetherController tetherController in array) { ZNetView component2 = ((Component)tetherController).GetComponent<ZNetView>(); 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<Character>(); 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (!__instance.IsTamed()) { return; } Character component = ((Component)__instance).GetComponent<Character>(); 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[<color=yellow><b>" + text + "</b></color>] Unhitch"; } else if (HitchingManager.IsHitchingModeActive && (Object)(object)HitchingManager.HitchTarget == (Object)(object)component) { __result = __result + "\n[<color=yellow><b>" + text + "</b></color>] Cancel Hitching"; } else if (!HitchingManager.IsHitchingModeActive) { __result = __result + "\n[<color=yellow><b>" + text + "</b></color>] Hitch"; } if (Plugin.DebugMode.Value) { ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null && component2.IsValid()) { string @string = component2.GetZDO().GetString("hitchingpost.beam", ""); string text2 = (string.IsNullOrEmpty(@string) ? "<none>" : @string); __result = __result + "<size=12>\n[DBG] Tether ID: <color=#0FF>" + text2 + "</color></size>"; } } } [HarmonyPatch(typeof(Tameable), "Awake")] [HarmonyPostfix] private static void Postfix_TameableAwake(Tameable __instance) { if (!__instance.IsTamed()) { return; } Character component = ((Component)__instance).GetComponent<Character>(); if (!((Object)(object)component == (Object)null) && !(component is Player)) { ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>(); if (!((Object)(object)component2 == (Object)null) && component2.IsValid() && (Object)(object)((Component)__instance).GetComponent<TetherController>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<TetherController>(); } } } [HarmonyPatch(typeof(Tameable), "Tame")] [HarmonyPostfix] private static void Postfix_TameableTame(Tameable __instance) { if ((Object)(object)((Component)__instance).GetComponent<TetherController>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<TetherController>(); } } } 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; ZNetView component = ((Component)creature).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { if (!component.IsOwner()) { component.ClaimOwnership(); } component.GetZDO().Set("hitchingpost.follow", "1"); } SetFollow(creature, ((Component)Player.m_localPlayer).gameObject); (((Component)creature).GetComponent<TetherController>() ?? ((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) { ZNetView component = ((Component)HitchTarget).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { if (!component.IsOwner()) { component.ClaimOwnership(); } component.GetZDO().Set("hitchingpost.follow", ""); } SetStay(HitchTarget); TetherController component2 = ((Component)HitchTarget).GetComponent<TetherController>(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } } IsHitchingModeActive = false; HitchTarget = null; ZLog.Log((object)"[HitchingPost] Hitching mode cancelled"); } public static void HitchToBeam(ZNetView beamNView) { //IL_013d: 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<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { bool num = component.IsOwner(); bool flag = beamNView.IsOwner(); if (!num) { component.ClaimOwnership(); } if (!flag) { beamNView.ClaimOwnership(); } ZDO zDO = component.GetZDO(); beamNView.GetZDO(); string text = Guid.NewGuid().ToString(); zDO.Set("hitchingpost.beam", text); zDO.Set("hitchingpost.follow", ""); 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<TetherController>(); 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<ZNetView>(); 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<ZNetView>(); foreach (ZNetView val in array) { if (val.IsValid() && IsBeam(((Component)val).gameObject) && BeamHasCreature(val, @string)) { RemoveCreatureFromBeam(val, @string); break; } } } zDO.Set("hitchingpost.beam", ""); zDO.Set("hitchingpost.follow", ""); } SetFollow(creature); ZLog.Log((object)("[HitchingPost] " + creature.GetHoverName() + " unhitched")); } public static bool IsHitched(Character creature) { ZNetView component = ((Component)creature).GetComponent<ZNetView>(); 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(); if (!text.Contains("beam") && !text.Contains("pole")) { return text.Contains("post"); } return true; } 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) { return Array.IndexOf(GetHitchedCreatures(beamNView), 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<string> list = new List<string>(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<MonsterAI>(); if ((Object)(object)component != (Object)null) { s_monsterAIFollow.SetValue(component, target); } } private static void SetStay(Character creature) { MonsterAI component = ((Component)creature).GetComponent<MonsterAI>(); if (!((Object)(object)component == (Object)null)) { s_monsterAIFollow.SetValue(component, null); ((BaseAI)component).SetPatrolPoint(); } } } [HarmonyPatch] public static class PlayerPatches { private static readonly MethodInfo s_takeInput = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null); [HarmonyPatch(typeof(Player), "Update")] [HarmonyPostfix] private static void Postfix(Player __instance) { //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) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !(bool)s_takeInput.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<Tameable>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsTamed()) { return; } Character component = ((Component)componentInParent).GetComponent<Character>(); 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<Tameable>(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)((Component)componentInParent).GetComponent<Character>() == (Object)(object)HitchingManager.HitchTarget) { HitchingManager.CancelHitching(); return; } Piece componentInParent2 = hoverGO.GetComponentInParent<Piece>(); if ((Object)(object)componentInParent2 != (Object)null && HitchingManager.IsBeam(((Component)componentInParent2).gameObject)) { ZNetView component = ((Component)componentInParent2).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { HitchingManager.HitchToBeam(component); return; } } HitchingManager.CancelHitching(); } } [BepInPlugin("com.malafein.hitchingpost", "HitchingPost", "1.0.8")] public class Plugin : BaseUnityPlugin { public const string ModGUID = "com.malafein.hitchingpost"; public const string ModName = "HitchingPost"; public const string ModVersion = "1.0.8"; public const string ZDO_KEY_BEAM = "hitchingpost.beam"; public const string ZDO_KEY_CREATURE = "hitchingpost.creature"; public const string ZDO_KEY_FOLLOW = "hitchingpost.follow"; private readonly Harmony harmony = new Harmony("com.malafein.hitchingpost"); public static ConfigEntry<KeyboardShortcut> HitchKey { get; private set; } public static ConfigEntry<bool> DebugMode { get; private set; } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) HitchKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "HitchKey", new KeyboardShortcut((KeyCode)104, Array.Empty<KeyCode>()), "Key to activate hitching mode, tether a creature to a beam, or unhitch a tethered creature."); DebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("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.8 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 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 const int NetworkWaitGiveUp = 15; private float m_updateTimer; private int m_networkWaitTicks; private static GameObject s_vfxHarpoonedPrefab; private static bool s_prefabSearchDone; private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) m_creature = ((Component)this).GetComponent<Character>(); m_nview = ((Component)this).GetComponent<ZNetView>(); 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<ZNetView>()); 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(); 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 if ((Object)(object)m_ropeObject != (Object)null) { UpdateRopeAnchor(); } else { HideRope(); } } private void CreateRope(ZNetView peer) { DestroyRope(); EnsureRopeAnchor(); if (TryCreateLineConnectRope(peer)) { Plugin.DebugLog("Created LineConnect rope on " + m_creature.GetHoverName()); } else { Plugin.WarningLog("Could not create rope on " + m_creature.GetHoverName() + " — vfx_Harpooned unavailable"); } } private void EnsureRopeAnchor() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindVfxHarpoonedPrefab(); if ((Object)(object)val == (Object)null) { return false; } GameObject val2 = new GameObject("HitchingPost_TempHost"); val2.SetActive(false); m_ropeObject = Object.Instantiate<GameObject>(val, val2.transform); ZNetView component = m_ropeObject.GetComponent<ZNetView>(); 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<ParticleSystem>(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<ZSyncTransform>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } ZNetView[] componentsInChildren3 = m_ropeObject.GetComponentsInChildren<ZNetView>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } 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<LineConnect>(); 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; } if ((Object)(object)peer != (Object)null) { m_lineConnect.SetPeer(peer); } m_lineConnect.m_maxDistance = 10f; m_lineConnect.m_dynamicThickness = true; m_lineConnect.m_minThickness = 0.04f; Plugin.DebugLog(string.Format("LineConnect configured: maxDist={0}, peer={1}", m_lineConnect.m_maxDistance, ((Object)(object)peer != (Object)null) ? ((Object)((Component)peer).gameObject).name : "<synced>")); return true; } private void UpdateRopeAnchor() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) UpdateRopeAnchor(); UpdateSlack(); UpdateDebugLabel(); if ((Object)(object)m_ropeObject != (Object)null && !m_ropeObject.activeSelf) { m_ropeObject.SetActive(true); } if (m_nview.IsOwner()) { if ((Object)(object)m_lineConnect != (Object)null && (Object)(object)m_beamNView != (Object)null) { m_lineConnect.SetPeer(m_beamNView); } if (Vector3.Distance(((Component)m_creature).transform.position, ((Component)m_beamNView).transform.position) > 5f) { ApplyPullForce(((Component)m_beamNView).transform.position); } } } private void UpdateSlack() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (!((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 ((Object)(object)m_ropeObject != (Object)null && m_ropeObject.activeSelf) { m_ropeObject.SetActive(false); Plugin.DebugLog("Rope hidden 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)); } DestroyDebugLabel(); } private void OnDestroy() { DestroyRope(); DestroyDebugLabel(); if ((Object)(object)m_ropeAnchor != (Object)null) { Object.Destroy((Object)(object)((Component)m_ropeAnchor).gameObject); } } private void ApplyPullForce(Vector3 beamPos) { //IL_0020: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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) 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; } if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } s_prefabSearchDone = true; GameObject prefab = ZNetScene.instance.GetPrefab("vfx_Harpooned"); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<LineConnect>() != (Object)null) { s_vfxHarpoonedPrefab = prefab; return s_vfxHarpoonedPrefab; } Plugin.WarningLog("vfx_Harpooned not found in ZNetScene — rope will not render"); return null; } private void UpdateDebugLabel() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_016e: 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<TextMesh>(); 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) { return; } Stopwatch stopwatch = Stopwatch.StartNew(); ZNetView[] array = Object.FindObjectsOfType<ZNetView>(); 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; m_networkWaitTicks = 0; 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."); } if (m_networkWaitTicks >= 15 && m_nview.IsOwner()) { Plugin.WarningLog(m_creature.GetHoverName() + " giving up on missing beam " + @string + "; clearing stale tether."); m_nview.GetZDO().Set("hitchingpost.beam", ""); m_networkWaitTicks = 0; } return; } m_networkWaitTicks = 0; if ((Object)(object)m_beamNView != (Object)null) { Plugin.DebugLog($"Tether broke/cleared on {m_creature.GetHoverName()}. IsOwner: {m_nview.IsOwner()}"); m_beamNView = null; DestroyRope(); } if (!string.IsNullOrEmpty(m_nview.GetZDO().GetString("hitchingpost.follow", ""))) { if ((Object)(object)m_ropeObject == (Object)null && (Object)(object)FindVfxHarpoonedPrefab() != (Object)null) { CreateRope(null); Plugin.DebugLog("Created passive follow rope on " + m_creature.GetHoverName()); } } else if ((Object)(object)m_ropeObject != (Object)null) { DestroyRope(); } } } }