using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("HitchingPost")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A Valheim mod for hitching post functionality.")]
[assembly: AssemblyFileVersion("1.0.6.0")]
[assembly: AssemblyInformationalVersion("1.0.6+00f5b54960f27d424401f66a2c6e2b019a1ffbfb")]
[assembly: AssemblyProduct("HitchingPost")]
[assembly: AssemblyTitle("HitchingPost")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace malafein.Valheim.HitchingPost
{
[HarmonyPatch]
public static class BeamPatches
{
[HarmonyPatch(typeof(Piece), "Awake")]
[HarmonyPostfix]
private static void Postfix_PieceAwake(Piece __instance)
{
if (HitchingManager.IsBeam(((Component)__instance).gameObject) && (Object)(object)((Component)__instance).GetComponent<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.");
}
}
}
}