Decompiled source of HitchingPost v1.0.0

HitchingPost.dll

Decompiled 20 hours ago
using System;
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.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+2b2f98d834a79399d3776fe9c9d2b97c79b2d8d3")]
[assembly: AssemblyProduct("HitchingPost")]
[assembly: AssemblyTitle("HitchingPost")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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_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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!HitchingManager.IsHitchingModeActive)
			{
				return;
			}
			Piece componentInParent = ((Component)__instance).GetComponentInParent<Piece>();
			if ((Object)(object)componentInParent == (Object)null || !HitchingManager.IsBeam(((Component)componentInParent).gameObject))
			{
				return;
			}
			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";
		}
	}
	[HarmonyPatch]
	public static class CreaturePatches
	{
		[HarmonyPatch(typeof(Tameable), "GetHoverText")]
		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void Postfix_TameableHoverText(Tameable __instance, ref string __result)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			Character component = ((Component)__instance).GetComponent<Character>();
			if (!((Object)(object)component == (Object)null))
			{
				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";
				}
			}
		}

		[HarmonyPatch(typeof(Tameable), "Awake")]
		[HarmonyPostfix]
		private static void Postfix_TameableAwake(Tameable __instance)
		{
			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>();
				}
			}
		}
	}
	public static class HitchingManager
	{
		public const string ZDO_KEY_BEAM = "hitchingpost.beam";

		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);
			ZLog.Log((object)("[HitchingPost] Hitching mode activated for " + creature.m_name));
		}

		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_010b: 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())
			{
				if (!component.IsOwner())
				{
					component.ClaimOwnership();
				}
				if (!beamNView.IsOwner())
				{
					beamNView.ClaimOwnership();
				}
				ZDO zDO = component.GetZDO();
				ZDO zDO2 = beamNView.GetZDO();
				string text = Guid.NewGuid().ToString();
				zDO.Set("hitchingpost.beam", text);
				zDO2.Set("hitchingpost.creature", text);
				ZLog.Log((object)("[HitchingPost] Saved tether GUID: " + text));
				SetStay(HitchTarget);
				TetherController component2 = ((Component)HitchTarget).GetComponent<TetherController>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.ForceBeam(beamNView);
				}
				ZLog.Log((object)$"[HitchingPost] {HitchTarget.m_name} 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", "");
				zDO.Set("hitchingpost.beam", "");
			}
			SetFollow(creature);
			ZLog.Log((object)("[HitchingPost] " + creature.m_name + " 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");
		}

		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)
			{
				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.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGUID = "com.malafein.hitchingpost";

		public const string ModName = "HitchingPost";

		public const string ModVersion = "1.0.0";

		private readonly Harmony harmony = new Harmony("com.malafein.hitchingpost");

		public static ConfigEntry<KeyboardShortcut> HitchKey { 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.");
			ZLog.Log((object)"HitchingPost 1.0.0 is loading...");
			harmony.PatchAll();
			ZLog.Log((object)"HitchingPost loaded!");
		}
	}
	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 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())
			{
				ZLog.Log((object)$"[HitchingPost] TetherController Awake on {m_creature.m_name} (ZDO: {m_nview.GetZDO().m_uid})");
			}
		}

		public void InitHitchingMode(Player player)
		{
			m_playerTarget = ((Component)player).transform;
			m_beamNView = null;
			CreateRope(((Component)player).GetComponent<ZNetView>());
			ZLog.Log((object)("[HitchingPost] InitHitchingMode active on " + m_creature.m_name));
		}

		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;
				ZLog.Log((object)("[HitchingPost] Created authentic LineConnect rope on " + m_creature.m_name));
			}
			else
			{
				CreateFallbackRope();
				m_usingLineConnect = false;
				ZLog.LogWarning((object)("[HitchingPost] Using fallback straight-line rope on " + m_creature.m_name));
			}
		}

		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;
				ZLog.Log((object)$"[HitchingPost] Created rope anchor on {m_creature.m_name} at local height {0.9f}");
			}
		}

		private bool TryCreateLineConnectRope(ZNetView peer)
		{
			//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)
			GameObject val = FindVfxHarpoonedPrefab();
			if ((Object)(object)val == (Object)null || (Object)(object)peer == (Object)null)
			{
				return false;
			}
			m_ropeObject = Object.Instantiate<GameObject>(val, m_ropeAnchor.position, Quaternion.identity, m_ropeAnchor);
			ParticleSystem[] componentsInChildren = m_ropeObject.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val2 in componentsInChildren)
			{
				ZLog.Log((object)("[HitchingPost] Stripping ParticleSystem '" + ((Object)((Component)val2).gameObject).name + "' from rope VFX"));
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
			m_lineConnect = m_ropeObject.GetComponent<LineConnect>();
			if ((Object)(object)m_lineConnect == (Object)null)
			{
				ZLog.LogWarning((object)"[HitchingPost] 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;
			ZLog.Log((object)$"[HitchingPost] 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;
				ZLog.Log((object)"[HitchingPost] 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0084: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			UpdateRopeAnchor();
			UpdateSlack();
			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);
					ZLog.Log((object)("[HitchingPost] Rope hidden on " + m_creature.m_name + " (Beam invalid/null)"));
				}
			}
			else if ((Object)(object)m_fallbackRope != (Object)null && ((Renderer)m_fallbackRope).enabled)
			{
				((Renderer)m_fallbackRope).enabled = false;
				ZLog.Log((object)("[HitchingPost] Rope disabled on " + m_creature.m_name + " (Beam invalid/null)"));
			}
		}

		private void DestroyRope()
		{
			if ((Object)(object)m_ropeObject != (Object)null)
			{
				Object.Destroy((Object)(object)m_ropeObject);
				m_ropeObject = null;
				m_lineConnect = null;
				ZLog.Log((object)("[HitchingPost] Destroyed LineConnect rope on " + m_creature?.m_name));
			}
			if ((Object)(object)m_fallbackRope != (Object)null)
			{
				Object.Destroy((Object)(object)m_fallbackRope);
				m_fallbackRope = null;
				ZLog.Log((object)("[HitchingPost] Destroyed fallback rope on " + m_creature?.m_name));
			}
		}

		private void OnDestroy()
		{
			DestroyRope();
			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;
			}
			ZLog.Log((object)"[HitchingPost] === Begin vfx_Harpooned prefab search ===");
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab("vfx_Harpooned");
				if ((Object)(object)prefab != (Object)null)
				{
					LineConnect component = prefab.GetComponent<LineConnect>();
					if ((Object)(object)component != (Object)null)
					{
						ZLog.Log((object)"[HitchingPost] [Strategy 1] Found vfx_Harpooned via ZNetScene.GetPrefab");
						s_vfxHarpoonedPrefab = prefab;
						return s_vfxHarpoonedPrefab;
					}
					ZLog.LogWarning((object)"[HitchingPost] [Strategy 1] ZNetScene has vfx_Harpooned but no LineConnect component");
				}
				else
				{
					ZLog.Log((object)"[HitchingPost] [Strategy 1] vfx_Harpooned not found in ZNetScene");
				}
			}
			try
			{
				if ((Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_StatusEffects != null)
				{
					ZLog.Log((object)$"[HitchingPost] [Strategy 2] Scanning {ObjectDB.instance.m_StatusEffects.Count} status effects...");
					foreach (StatusEffect statusEffect in ObjectDB.instance.m_StatusEffects)
					{
						if ((Object)(object)statusEffect == (Object)null || (((Object)statusEffect).name.IndexOf("Harpooned", StringComparison.OrdinalIgnoreCase) < 0 && ((Object)statusEffect).name.IndexOf("Harpoon", StringComparison.OrdinalIgnoreCase) < 0))
						{
							continue;
						}
						ZLog.Log((object)("[HitchingPost] [Strategy 2] Found StatusEffect: '" + ((Object)statusEffect).name + "', checking start effects..."));
						if (statusEffect.m_startEffects == null || statusEffect.m_startEffects.m_effectPrefabs == null)
						{
							continue;
						}
						EffectData[] effectPrefabs = statusEffect.m_startEffects.m_effectPrefabs;
						foreach (EffectData val in effectPrefabs)
						{
							if (!((Object)(object)val.m_prefab == (Object)null))
							{
								ZLog.Log((object)("[HitchingPost] [Strategy 2]   Effect prefab: '" + ((Object)val.m_prefab).name + "'"));
								LineConnect component2 = val.m_prefab.GetComponent<LineConnect>();
								if ((Object)(object)component2 != (Object)null)
								{
									ZLog.Log((object)("[HitchingPost] [Strategy 2] SUCCESS — found LineConnect on '" + ((Object)val.m_prefab).name + "' via StatusEffect '" + ((Object)statusEffect).name + "'"));
									s_vfxHarpoonedPrefab = val.m_prefab;
									return s_vfxHarpoonedPrefab;
								}
							}
						}
					}
					ZLog.Log((object)"[HitchingPost] [Strategy 2] No matching StatusEffect with LineConnect found");
				}
			}
			catch (Exception ex)
			{
				ZLog.LogWarning((object)("[HitchingPost] [Strategy 2] Exception scanning StatusEffects: " + ex.Message));
			}
			try
			{
				LineConnect[] array = Resources.FindObjectsOfTypeAll<LineConnect>();
				ZLog.Log((object)$"[HitchingPost] [Strategy 3] Resources scan found {array.Length} LineConnect component(s)");
				LineConnect[] array2 = array;
				foreach (LineConnect val2 in array2)
				{
					ZLog.Log((object)("[HitchingPost] [Strategy 3]   LineConnect on: '" + ((Object)((Component)val2).gameObject).name + "'"));
					if (((Object)((Component)val2).gameObject).name.IndexOf("Harpooned", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)((Component)val2).gameObject).name.IndexOf("harpoon", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						ZLog.Log((object)("[HitchingPost] [Strategy 3] SUCCESS — matched '" + ((Object)((Component)val2).gameObject).name + "'"));
						s_vfxHarpoonedPrefab = ((Component)val2).gameObject;
						return s_vfxHarpoonedPrefab;
					}
				}
				if (array.Length != 0)
				{
					ZLog.LogWarning((object)("[HitchingPost] [Strategy 3] No harpoon-specific LineConnect. Using first available: '" + ((Object)((Component)array[0]).gameObject).name + "'"));
					s_vfxHarpoonedPrefab = ((Component)array[0]).gameObject;
					return s_vfxHarpoonedPrefab;
				}
			}
			catch (Exception ex2)
			{
				ZLog.LogWarning((object)("[HitchingPost] [Strategy 3] Exception during Resources scan: " + ex2.Message));
			}
			ZLog.LogWarning((object)"[HitchingPost] === All strategies exhausted. No LineConnect prefab found. Will use fallback rope. ===");
			s_prefabSearchDone = true;
			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;
				ZLog.Log((object)"[HitchingPost] Created fallback rope material (brown, Sprites/Default)");
				return s_fallbackRopeMaterial;
			}
			ZLog.LogError((object)"[HitchingPost] Failed to create fallback material — Sprites/Default shader not found");
			return null;
		}

		private void SyncZdoState()
		{
			string @string = m_nview.GetZDO().GetString("hitchingpost.beam", "");
			if (string.IsNullOrEmpty(@string))
			{
				if ((Object)(object)m_beamNView != (Object)null)
				{
					ZLog.Log((object)("[HitchingPost] Tether broke/cleared on " + m_creature.m_name + "."));
					m_beamNView = null;
					DestroyRope();
				}
				return;
			}
			if ((Object)(object)m_beamNView != (Object)null && m_beamNView.IsValid())
			{
				string string2 = m_beamNView.GetZDO().GetString("hitchingpost.creature", "");
				if (string2 == @string)
				{
					return;
				}
			}
			ZNetView[] array = Object.FindObjectsOfType<ZNetView>();
			foreach (ZNetView val in array)
			{
				if (val.IsValid() && HitchingManager.IsBeam(((Component)val).gameObject))
				{
					string string3 = val.GetZDO().GetString("hitchingpost.creature", "");
					if (string3 == @string)
					{
						m_beamNView = val;
						CreateRope(val);
						ZLog.Log((object)("[HitchingPost] " + m_creature.m_name + " successfully resolved beam instance by GUID " + @string + "."));
						return;
					}
				}
			}
			m_networkWaitTicks++;
			if (m_networkWaitTicks % 4 == 0)
			{
				ZLog.LogWarning((object)("[HitchingPost] " + m_creature.m_name + " cannot find beam with GUID " + @string + ". Wait for network load."));
			}
		}
	}
}