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.6
HitchingPost.dll
Decompiled 2 weeks 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; 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<HoverText>() == (Object)null) { HoverText val = ((Component)__instance).gameObject.AddComponent<HoverText>(); 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<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_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<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; SetFollow(creature, ((Component)Player.m_localPlayer).gameObject); TetherController tetherController = ((Component)creature).GetComponent<TetherController>() ?? ((Component)creature).gameObject.AddComponent<TetherController>(); 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<TetherController>(); 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<ZNetView>(); 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<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", ""); } 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(); 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<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 { [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<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.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<KeyboardShortcut> HitchKey { get; private set; } public static ConfigEntry<bool> 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<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.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<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(); 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<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); foreach (ZSyncTransform val4 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val4); } ZNetView[] componentsInChildren3 = m_ropeObject.GetComponentsInChildren<ZNetView>(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<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; } 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<LineRenderer>(); ((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<LineConnect>() != (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<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) { 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<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; 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."); } } } }