Decompiled source of Second Exterior Ship Ladder Fix v0.4.5

BepInEx/plugins/ShipLadderInteractionFix/ShipLadderInteractionFix.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ShipLadderInteractionFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShipLadderInteractionFix")]
[assembly: AssemblyTitle("ShipLadderInteractionFix")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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;
		}
	}
}
[BepInPlugin("bernard.shipladderinteractionfix", "Ship Ladder Interaction Fix", "0.4.5")]
public sealed class ShipLadderInteractionFix : BaseUnityPlugin
{
	public const string PluginGuid = "bernard.shipladderinteractionfix";

	public const string PluginName = "Ship Ladder Interaction Fix";

	public const string PluginVersion = "0.4.5";

	private Harmony _harmony;

	internal static ManualLogSource LogSource;

	private bool _patchMapLogged;

	internal static ShipLadderInteractionFix Instance;

	internal static bool VerboseDiagnostics = false;

	private static readonly HashSet<int> QuietObservationPending = new HashSet<int>();

	private static readonly Dictionary<int, float> QuietObservationLastScheduledAt = new Dictionary<int, float>();

	private static readonly HashSet<int> ReportedCandidates = new HashSet<int>();

	private static readonly HashSet<int> ReportedRepairs = new HashSet<int>();

	private static readonly object ReportLock = new object();

	private static readonly HashSet<int> DetailedGraphLogged = new HashSet<int>();

	private static readonly object DetailLock = new object();

	private void Awake()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		LogSource = ((BaseUnityPlugin)this).Logger;
		Instance = this;
		_harmony = new Harmony("bernard.shipladderinteractionfix");
		_harmony.PatchAll(typeof(ShipLadderInteractionFix).Assembly);
		SceneManager.sceneLoaded += OnSceneLoaded;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded v0.4.5 targeted upper exterior ladder room-gate repair. For the exact OutsideShipRoom0 ladder only, temporarily bypasses player.isInHangarShipRoom during vanilla InteractTrigger.Interact, restores the original value immediately afterward (including exceptions), leaves obstruction/coroutine/climb state to vanilla, and uses compact logs.");
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
		LogSource = null;
		Instance = null;
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		try
		{
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				InspectAndRepair(rootGameObjects[i].transform, "scene-loaded:" + ((Scene)(ref scene)).name);
			}
			if (!_patchMapLogged && ((Scene)(ref scene)).name.IndexOf("SampleSceneRelay", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				_patchMapLogged = true;
				LogHarmonyPatchOwners("InteractTrigger", "Interact", 1);
				LogHarmonyPatchOwners("GameNetcodeStuff.PlayerControllerB", "Interact_performed", -1);
				LogHarmonyPatchOwners("GameNetcodeStuff.PlayerControllerB", "InteractTriggerUseConditionsMet", -1);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Scene scan failed safely: " + ex.GetType().Name + ": " + ex.Message));
		}
	}

	internal static void RunRepair(NetworkObject networkObject, MethodBase spawnMethod)
	{
		if ((Object)(object)networkObject == (Object)null)
		{
			return;
		}
		try
		{
			InspectAndRepair(((Component)networkObject).transform, "before-network-spawn:" + ((spawnMethod == null) ? "unknown" : spawnMethod.Name));
		}
		catch (Exception ex)
		{
			ManualLogSource logSource = LogSource;
			if (logSource != null)
			{
				logSource.LogWarning((object)("Spawn-time ladder scan failed safely: " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}

	private static void InspectAndRepair(Transform root, string context)
	{
		if ((Object)(object)root == (Object)null)
		{
			return;
		}
		InteractTrigger[] componentsInChildren = ((Component)root).GetComponentsInChildren<InteractTrigger>(true);
		foreach (InteractTrigger val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null || !LooksLikeLadderTrigger(((Component)val).transform) || !IsInShipHierarchy(((Component)val).transform))
			{
				continue;
			}
			int instanceID = ((Object)val).GetInstanceID();
			GetHierarchyPath(((Component)val).transform);
			bool enabled = ((Behaviour)val).enabled;
			bool activeInHierarchy = ((Component)val).gameObject.activeInHierarchy;
			if (!enabled)
			{
				((Behaviour)val).enabled = true;
				lock (ReportLock)
				{
					if (ReportedRepairs.Add(instanceID))
					{
						Debug.LogWarning((object)("[ShipLadderInteractionFix] LADDER_DISCOVERY_REPAIRED: " + DescribeLadderIdentity(((Component)val).transform) + "; ActiveInHierarchy=" + activeInHierarchy + "; Context=" + context));
					}
				}
				continue;
			}
			lock (ReportLock)
			{
				if (ReportedCandidates.Add(instanceID))
				{
					Debug.Log((object)("[ShipLadderInteractionFix] LADDER_DISCOVERY: " + DescribeLadderIdentity(((Component)val).transform) + "; ActiveInHierarchy=" + activeInHierarchy + "; Context=" + context));
				}
			}
		}
	}

	internal static bool IsShipLadderTrigger(object triggerObject, out string path)
	{
		path = "<no-transform>";
		if (triggerObject == null)
		{
			return false;
		}
		Component val = (Component)((triggerObject is Component) ? triggerObject : null);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		path = GetHierarchyPath(val.transform);
		if (LooksLikeLadderTrigger(val.transform))
		{
			return IsInShipHierarchy(val.transform);
		}
		return false;
	}

	internal static int GetInstanceId(object obj)
	{
		Component val = (Component)((obj is Component) ? obj : null);
		if (!((Object)(object)val == (Object)null))
		{
			return ((Object)val).GetInstanceID();
		}
		return 0;
	}

	internal static string GetHierarchyPath(Transform transform)
	{
		List<string> list = new List<string>();
		Transform val = transform;
		int num = 0;
		while ((Object)(object)val != (Object)null && num++ < 40)
		{
			list.Add(((Object)val).name ?? "<unnamed>");
			val = val.parent;
		}
		list.Reverse();
		return string.Join("/", list);
	}

	internal static string ClassifyLadder(Transform transform)
	{
		if ((Object)(object)transform == (Object)null)
		{
			return "UNKNOWN_LADDER";
		}
		string hierarchyPath = GetHierarchyPath(transform);
		if (hierarchyPath.IndexOf("/OutsideShipRoom0/", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "SECOND_EXTERIOR_LADDER_CANDIDATE (OutsideShipRoom0 duplicate)";
		}
		if (hierarchyPath.IndexOf("/OutsideShipRoom/", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "PRIMARY_EXTERIOR_LADDER_REFERENCE (OutsideShipRoom)";
		}
		if (hierarchyPath.IndexOf("/LadderShort (1)/", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "SHORT_LADDER_CANDIDATE_2 (LadderShort (1))";
		}
		if (hierarchyPath.IndexOf("/LadderShort/", StringComparison.OrdinalIgnoreCase) >= 0)
		{
			return "SHORT_LADDER_CANDIDATE_1 (LadderShort)";
		}
		return "OTHER_SHIP_LADDER_CANDIDATE";
	}

	internal static string DescribeLadderIdentity(Transform transform)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)transform == (Object)null)
		{
			return "role=UNKNOWN_LADDER; path=<no-transform>";
		}
		Vector3 position = transform.position;
		Vector3 localPosition = transform.localPosition;
		return "role=" + ClassifyLadder(transform) + "; instanceId=" + ((Object)((Component)transform).gameObject).GetInstanceID() + "; worldPos=(" + position.x.ToString("0.000", CultureInfo.InvariantCulture) + "," + position.y.ToString("0.000", CultureInfo.InvariantCulture) + "," + position.z.ToString("0.000", CultureInfo.InvariantCulture) + "); localPos=(" + localPosition.x.ToString("0.000", CultureInfo.InvariantCulture) + "," + localPosition.y.ToString("0.000", CultureInfo.InvariantCulture) + "," + localPosition.z.ToString("0.000", CultureInfo.InvariantCulture) + "); path=" + GetHierarchyPath(transform);
	}

	private void LogHarmonyPatchOwners(string typeName, string methodName, int parameterCount)
	{
		try
		{
			Type type = AccessTools.TypeByName(typeName);
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("PATCH_MAP: target type not found: " + typeName + "::" + methodName));
				return;
			}
			MethodBase methodBase = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name == methodName && (parameterCount < 0 || m.GetParameters().Length == parameterCount)
				orderby m.GetParameters().Length
				select m).FirstOrDefault();
			if (methodBase == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("PATCH_MAP: target method not found: " + typeName + "::" + methodName));
				return;
			}
			object patchInfo = Harmony.GetPatchInfo(methodBase);
			if (patchInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("PATCH_MAP: no Harmony patch info: " + typeName + "::" + methodName));
				return;
			}
			string[] array = new string[4] { "Prefixes", "Postfixes", "Transpilers", "Finalizers" };
			foreach (string text in array)
			{
				IEnumerable enumerable = GetMember(patchInfo, text) as IEnumerable;
				int num2 = 0;
				if (enumerable != null)
				{
					foreach (object item in enumerable)
					{
						num2++;
						object obj = GetMember(item, "PatchMethod") ?? GetMember(item, "patchMethod");
						string text2 = Convert.ToString(GetMember(item, "owner") ?? GetMember(item, "Owner")) ?? "<unknown-owner>";
						string text3 = Convert.ToString(GetMember(item, "priority") ?? GetMember(item, "Priority")) ?? "?";
						string text4 = ((obj is MethodBase methodBase2) ? (methodBase2.DeclaringType?.FullName + "." + methodBase2.Name) : "<unknown-method>");
						((BaseUnityPlugin)this).Logger.LogInfo((object)("PATCH_MAP: target=" + typeName + "::" + methodName + "; kind=" + text + "; owner=" + text2 + "; priority=" + text3 + "; patch=" + text4));
					}
				}
				if (num2 == 0)
				{
					((BaseUnityPlugin)this).Logger.LogDebug((object)("PATCH_MAP: target=" + typeName + "::" + methodName + "; kind=" + text + "; none"));
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("PATCH_MAP failed safely for " + typeName + "::" + methodName + ": " + ex.GetType().Name + ": " + ex.Message));
		}
	}

	private static bool LooksLikeLadderTrigger(Transform transform)
	{
		Transform val = transform;
		int num = 0;
		while ((Object)(object)val != (Object)null && num++ < 8)
		{
			if ((((Object)val).name ?? string.Empty).IndexOf("ladder", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			val = val.parent;
		}
		return false;
	}

	private static bool IsInShipHierarchy(Transform transform)
	{
		Transform val = transform;
		int num = 0;
		while ((Object)(object)val != (Object)null && num++ < 25)
		{
			string text = (((Object)val).name ?? string.Empty).ToLowerInvariant();
			if (text.Contains("hangarship") || text.Contains("ship") || text.Contains("2story") || text.Contains("2-story") || text.Contains("melanie"))
			{
				return true;
			}
			val = val.parent;
		}
		return false;
	}

	internal static object GetMember(object instance, string name)
	{
		if (instance == null || string.IsNullOrEmpty(name))
		{
			return null;
		}
		try
		{
			Type type = instance.GetType();
			while (type != null)
			{
				FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(instance);
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.GetIndexParameters().Length == 0)
				{
					return property.GetValue(instance, null);
				}
				type = type.BaseType;
			}
		}
		catch
		{
		}
		return null;
	}

	internal static bool GetBool(object instance, string name, bool fallback = false)
	{
		object member = GetMember(instance, name);
		if (member is bool)
		{
			return (bool)member;
		}
		return fallback;
	}

	internal static float GetFloat(object instance, string name, float fallback = 0f)
	{
		object member = GetMember(instance, name);
		try
		{
			return (member == null) ? fallback : Convert.ToSingle(member);
		}
		catch
		{
			return fallback;
		}
	}

	internal static bool TrySetBool(object instance, string name, bool value)
	{
		if (instance == null || string.IsNullOrEmpty(name))
		{
			return false;
		}
		try
		{
			Type type = instance.GetType();
			while (type != null)
			{
				FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == typeof(bool))
				{
					if ((bool)field.GetValue(instance) != value)
					{
						field.SetValue(instance, value);
					}
					return true;
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == typeof(bool) && property.CanWrite && property.GetIndexParameters().Length == 0)
				{
					if (!object.Equals(property.GetValue(instance, null), value))
					{
						property.SetValue(instance, value, null);
					}
					return true;
				}
				type = type.BaseType;
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logSource = LogSource;
			if (logSource != null)
			{
				logSource.LogDebug((object)("Could not set " + name + ": " + ex.GetType().Name));
			}
		}
		return false;
	}

	internal static bool TrySetFloat(object instance, string name, float value)
	{
		if (instance == null || string.IsNullOrEmpty(name))
		{
			return false;
		}
		try
		{
			Type type = instance.GetType();
			while (type != null)
			{
				FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == typeof(float))
				{
					field.SetValue(instance, value);
					return true;
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == typeof(float) && property.CanWrite && property.GetIndexParameters().Length == 0)
				{
					property.SetValue(instance, value, null);
					return true;
				}
				type = type.BaseType;
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logSource = LogSource;
			if (logSource != null)
			{
				logSource.LogDebug((object)("Could not set float " + name + ": " + ex.GetType().Name));
			}
		}
		return false;
	}

	internal static string DescribeTrigger(object trigger, object player = null)
	{
		if (trigger == null)
		{
			return "trigger=null";
		}
		Component val = (Component)((trigger is Component) ? trigger : null);
		string text = (((Object)(object)val == (Object)null) ? "role=UNKNOWN_LADDER; path=<no-transform>" : DescribeLadderIdentity(val.transform));
		string[] obj = new string[17]
		{
			text, "; enabled=", null, null, null, null, null, null, null, null,
			null, null, null, null, null, null, null
		};
		Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
		obj[2] = ((val2 != null) ? val2.enabled.ToString() : "n/a");
		obj[3] = "; active=";
		obj[4] = (((Object)(object)val != (Object)null) ? val.gameObject.activeInHierarchy.ToString() : "n/a");
		obj[5] = "; interactable=";
		obj[6] = GetBool(trigger, "interactable").ToString();
		obj[7] = "; isLadder=";
		obj[8] = GetBool(trigger, "isLadder").ToString();
		obj[9] = "; usingLadder=";
		obj[10] = GetBool(trigger, "usingLadder").ToString();
		obj[11] = "; holdInteraction=";
		obj[12] = GetBool(trigger, "holdInteraction").ToString();
		obj[13] = "; oneHandedAllowed=";
		obj[14] = GetBool(trigger, "oneHandedItemAllowed").ToString();
		obj[15] = "; twoHandedAllowed=";
		obj[16] = GetBool(trigger, "twoHandedItemAllowed").ToString();
		string text2 = string.Concat(obj);
		if (player != null)
		{
			text2 = text2 + "; playerClimbing=" + GetBool(player, "isClimbingLadder") + "; playerInSpecialAnimation=" + GetBool(player, "inSpecialInteractAnimation") + "; playerDisableInteract=" + GetBool(player, "disableInteract") + "; playerTyping=" + GetBool(player, "isTypingChat") + "; playerTerminal=" + GetBool(player, "inTerminalMenu") + "; playerJetpack=" + GetBool(player, "jetpackControls") + "; timeSinceSlotSwitch=" + GetFloat(player, "timeSinceSwitchingSlots", -1f).ToString("0.000");
		}
		return text2;
	}

	internal static object ResolvePlayerController(object argument)
	{
		Transform val = (Transform)((argument is Transform) ? argument : null);
		if ((Object)(object)val == (Object)null)
		{
			Component val2 = (Component)((argument is Component) ? argument : null);
			if (val2 != null)
			{
				val = val2.transform;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		try
		{
			Type type = AccessTools.TypeByName("GameNetcodeStuff.PlayerControllerB");
			if (type == null)
			{
				return null;
			}
			Transform val3 = val;
			int num = 0;
			while ((Object)(object)val3 != (Object)null && num++ < 12)
			{
				Component component = ((Component)val3).GetComponent(type);
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
				val3 = val3.parent;
			}
			Object[] array = Object.FindObjectsOfType(type);
			if (array != null)
			{
				Object[] array2 = array;
				foreach (Object val4 in array2)
				{
					if (!(val4 == (Object)null))
					{
						object member = GetMember(val4, "thisPlayerBody");
						Transform val5 = (Transform)((member is Transform) ? member : null);
						if ((Object)(object)val5 != (Object)null && ((Object)(object)val5 == (Object)(object)val || val.IsChildOf(val5) || val5.IsChildOf(val)))
						{
							return val4;
						}
					}
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logSource = LogSource;
			if (logSource != null)
			{
				logSource.LogDebug((object)("Player resolution failed safely: " + ex.GetType().Name));
			}
		}
		return null;
	}

	internal static string DescribeArgument(object argument)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		if (argument == null)
		{
			return "argument=<null>";
		}
		Transform val = (Transform)((argument is Transform) ? argument : null);
		if (val != null)
		{
			Vector3 position = val.position;
			return "argumentType=Transform; argument=" + ((Object)val).name + "#" + ((Object)((Component)val).gameObject).GetInstanceID() + "; position=(" + position.x.ToString("0.000", CultureInfo.InvariantCulture) + "," + position.y.ToString("0.000", CultureInfo.InvariantCulture) + "," + position.z.ToString("0.000", CultureInfo.InvariantCulture) + "); path=" + GetHierarchyPath(val);
		}
		Component val2 = (Component)((argument is Component) ? argument : null);
		if (val2 != null)
		{
			return "argumentType=" + ((object)val2).GetType().FullName + "#" + ((Object)val2).GetInstanceID() + "; path=" + GetHierarchyPath(val2.transform);
		}
		return "argumentType=" + argument.GetType().FullName;
	}

	internal static string DescribePlayer(object player)
	{
		if (player == null)
		{
			return "playerController=<unresolved>";
		}
		object member = GetMember(player, "thisPlayerBody");
		Transform val = (Transform)((member is Transform) ? member : null);
		return "playerControllerType=" + player.GetType().FullName + "#" + GetInstanceId(player) + "; playerBody=" + (((Object)(object)val == (Object)null) ? "<unresolved>" : (((Object)val).name + "#" + ((Object)((Component)val).gameObject).GetInstanceID() + " path=" + GetHierarchyPath(val))) + "; isClimbingLadder=" + GetBool(player, "isClimbingLadder") + "; inSpecialInteractAnimation=" + GetBool(player, "inSpecialInteractAnimation") + "; disableInteract=" + GetBool(player, "disableInteract") + "; isPlayerDead=" + GetBool(player, "isPlayerDead") + "; isPlayerControlled=" + GetBool(player, "isPlayerControlled") + "; isTypingChat=" + GetBool(player, "isTypingChat") + "; inTerminalMenu=" + GetBool(player, "inTerminalMenu") + "; inSpecialMenu=" + GetBool(player, "inSpecialMenu") + "; jetpackControls=" + GetBool(player, "jetpackControls") + "; isHoldingObject=" + GetBool(player, "isHoldingObject") + "; twoHanded=" + GetBool(player, "twoHanded") + "; timeSinceSwitchingSlots=" + GetFloat(player, "timeSinceSwitchingSlots", -1f).ToString("0.000", CultureInfo.InvariantCulture);
	}

	private static bool IsRelevantFieldName(string name)
	{
		return new string[17]
		{
			"ladder", "interact", "anim", "player", "trigger", "position", "transform", "parent", "target", "reference",
			"body", "special", "climb", "cooldown", "hold", "handed", "active"
		}.Any((string term) => name.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0);
	}

	private static string SummarizeFieldValue(object value)
	{
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (value == null)
			{
				return "<null>";
			}
			Object val = (Object)((value is Object) ? value : null);
			if (val != null)
			{
				if (val == (Object)null)
				{
					return "<destroyed Unity object>";
				}
				Component val2 = (Component)(object)((val is Component) ? val : null);
				if (val2 != null)
				{
					return ((object)val2).GetType().FullName + "#" + ((Object)val2).GetInstanceID() + " path=" + GetHierarchyPath(val2.transform);
				}
				GameObject val3 = (GameObject)(object)((val is GameObject) ? val : null);
				if (val3 != null)
				{
					return "GameObject#" + ((Object)val3).GetInstanceID() + " path=" + GetHierarchyPath(val3.transform);
				}
				return ((object)val).GetType().FullName + "#" + val.GetInstanceID() + " name=" + val.name;
			}
			if (value is Vector3 val4)
			{
				return "(" + val4.x.ToString("0.000", CultureInfo.InvariantCulture) + "," + val4.y.ToString("0.000", CultureInfo.InvariantCulture) + "," + val4.z.ToString("0.000", CultureInfo.InvariantCulture) + ")";
			}
			if (value is Array array)
			{
				return value.GetType().GetElementType()?.Name + "[] length=" + array.Length;
			}
			string text = Convert.ToString(value, CultureInfo.InvariantCulture) ?? "<no-string>";
			return (text.Length > 120) ? (text.Substring(0, 117) + "...") : text.Replace("\r", " ").Replace("\n", " ");
		}
		catch
		{
			return "<format-failed>";
		}
	}

	private static string RelevantFields(object target)
	{
		if (target == null)
		{
			return "<null>";
		}
		List<string> list = new List<string>();
		Type type = target.GetType();
		int num = 0;
		while (type != null && type != typeof(object) && num < 100)
		{
			FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!fieldInfo.IsStatic && IsRelevantFieldName(fieldInfo.Name))
				{
					if (num++ >= 100)
					{
						break;
					}
					try
					{
						list.Add(fieldInfo.Name + ":" + fieldInfo.FieldType.Name + "=" + SummarizeFieldValue(fieldInfo.GetValue(target)));
					}
					catch (Exception ex)
					{
						list.Add(fieldInfo.Name + "=<read-failed:" + ex.GetType().Name + ">");
					}
				}
			}
			type = type.BaseType;
		}
		if (list.Count != 0)
		{
			return string.Join(" | ", list);
		}
		return "<no matching fields>";
	}

	internal static void LogLadderSnapshot(object trigger, object argument, string stage)
	{
		if (!VerboseDiagnostics)
		{
			return;
		}
		Component val = (Component)((trigger is Component) ? trigger : null);
		if ((Object)(object)val == (Object)null || !IsShipLadderTrigger(trigger, out var _))
		{
			return;
		}
		object player = ResolvePlayerController(argument);
		ManualLogSource logSource = LogSource;
		if (logSource != null)
		{
			logSource.LogInfo((object)("LADDER_DIAG " + stage + ": " + DescribeTrigger(trigger) + "; " + DescribeArgument(argument) + "; " + DescribePlayer(player)));
		}
		bool flag;
		lock (DetailLock)
		{
			flag = DetailedGraphLogged.Add(((Object)val).GetInstanceID());
		}
		if (!flag)
		{
			return;
		}
		ManualLogSource logSource2 = LogSource;
		if (logSource2 != null)
		{
			logSource2.LogInfo((object)("LADDER_TRIGGER_FIELDS: " + ((object)val).GetType().FullName + "#" + ((Object)val).GetInstanceID() + "; " + RelevantFields(val)));
		}
		List<Transform> list = new List<Transform>();
		HashSet<int> hashSet = new HashSet<int>();
		Transform val2 = val.transform;
		int num = 0;
		while ((Object)(object)val2 != (Object)null && num < 3)
		{
			if (hashSet.Add(((Object)val2).GetInstanceID()))
			{
				list.Add(val2);
			}
			num++;
			val2 = val2.parent;
		}
		Transform val3 = (((Object)(object)val.transform.parent != (Object)null) ? val.transform.parent : val.transform);
		Transform[] componentsInChildren = ((Component)val3).GetComponentsInChildren<Transform>(true);
		foreach (Transform val4 in componentsInChildren)
		{
			if (!((Object)(object)val4 == (Object)null))
			{
				int num2 = 0;
				Transform val5 = val4;
				while ((Object)(object)val5 != (Object)null && (Object)(object)val5 != (Object)(object)val3 && num2 <= 4)
				{
					num2++;
					val5 = val5.parent;
				}
				if ((Object)(object)val5 == (Object)(object)val3 && num2 <= 4 && hashSet.Add(((Object)val4).GetInstanceID()))
				{
					list.Add(val4);
				}
				if (list.Count >= 40)
				{
					break;
				}
			}
		}
		foreach (Transform item2 in list)
		{
			if ((Object)(object)item2 == (Object)null)
			{
				continue;
			}
			Component[] components = ((Component)item2).GetComponents<Component>();
			List<string> list2 = new List<string>();
			Component[] array = components;
			foreach (Component val6 in array)
			{
				object item;
				if (!((Object)(object)val6 == (Object)null))
				{
					string? fullName = ((object)val6).GetType().FullName;
					string text = ((Object)val6).GetInstanceID().ToString();
					Behaviour val7 = (Behaviour)(object)((val6 is Behaviour) ? val6 : null);
					item = fullName + "#" + text + ((val7 != null) ? (";enabled=" + val7.enabled) : "");
				}
				else
				{
					item = "<missing-script>";
				}
				list2.Add((string)item);
			}
			ManualLogSource logSource3 = LogSource;
			if (logSource3 != null)
			{
				logSource3.LogInfo((object)("LADDER_COMPONENT_GRAPH: node=" + GetHierarchyPath(item2) + "#" + ((Object)((Component)item2).gameObject).GetInstanceID() + "; active=" + ((Component)item2).gameObject.activeInHierarchy + "; components=" + string.Join(", ", list2)));
			}
			array = components;
			foreach (Component val8 in array)
			{
				if ((Object)(object)val8 == (Object)null || val8 is Transform || val8 is Collider || val8 is Renderer)
				{
					continue;
				}
				string text2 = ((object)val8).GetType().FullName ?? ((object)val8).GetType().Name;
				if ((Object)(object)val8 == (Object)(object)val || text2.IndexOf("ladder", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("InteractTrigger", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					ManualLogSource logSource4 = LogSource;
					if (logSource4 != null)
					{
						logSource4.LogInfo((object)("LADDER_COMPONENT_FIELDS: " + text2 + "#" + ((Object)val8).GetInstanceID() + "; path=" + GetHierarchyPath(val8.transform) + "; " + RelevantFields(val8)));
					}
				}
			}
		}
	}

	internal void StartDelayedLadderObservation(object trigger, object argument)
	{
		try
		{
			Component val = (Component)((trigger is Component) ? trigger : null);
			if ((Object)(object)val == (Object)null || !IsSecondExteriorLadderTrigger(val))
			{
				return;
			}
			if (VerboseDiagnostics)
			{
				((MonoBehaviour)this).StartCoroutine(ObserveLadderAfterInteraction(val, (Transform)((argument is Transform) ? argument : null)));
				return;
			}
			int instanceID = ((Object)val).GetInstanceID();
			float unscaledTime = Time.unscaledTime;
			if ((!QuietObservationLastScheduledAt.TryGetValue(instanceID, out var value) || !(unscaledTime - value < 1.5f)) && QuietObservationPending.Add(instanceID))
			{
				QuietObservationLastScheduledAt[instanceID] = unscaledTime;
				((MonoBehaviour)this).StartCoroutine(ObserveLadderQuietly(val, (Transform)((argument is Transform) ? argument : null), instanceID));
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogDebug((object)("Could not schedule quiet upper-ladder observation: " + ex.GetType().Name));
		}
	}

	private IEnumerator ObserveLadderQuietly(Component trigger, Transform argumentTransform, int instanceId)
	{
		yield return (object)new WaitForSeconds(1f);
		if ((Object)(object)trigger != (Object)null && IsShipLadderTrigger(trigger, out var _))
		{
			object instance = ResolvePlayerController(argumentTransform);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("LADDER_RESULT after 1.0s: role=" + ClassifyLadder(trigger.transform) + "; usingLadder=" + GetBool(trigger, "usingLadder") + "; isClimbingLadder=" + GetBool(instance, "isClimbingLadder") + "; inSpecialInteractAnimation=" + GetBool(instance, "inSpecialInteractAnimation") + "; active=" + trigger.gameObject.activeInHierarchy + "; interactable=" + GetBool(trigger, "interactable") + "; isLadder=" + GetBool(trigger, "isLadder")));
		}
		QuietObservationPending.Remove(instanceId);
	}

	private IEnumerator ObserveLadderAfterInteraction(Component trigger, Transform argumentTransform)
	{
		yield return null;
		if ((Object)(object)trigger == (Object)null)
		{
			yield break;
		}
		LogDelayedLadderState(trigger, argumentTransform, "next-frame");
		yield return (object)new WaitForSeconds(0.25f);
		if (!((Object)(object)trigger == (Object)null))
		{
			LogDelayedLadderState(trigger, argumentTransform, "plus-0.25s");
			yield return (object)new WaitForSeconds(0.75f);
			if ((Object)(object)trigger != (Object)null)
			{
				LogDelayedLadderState(trigger, argumentTransform, "plus-1.0s");
			}
		}
	}

	private void LogDelayedLadderState(Component trigger, Transform argumentTransform, string stage)
	{
		if (IsShipLadderTrigger(trigger, out var _))
		{
			object player = ResolvePlayerController(argumentTransform);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("LADDER_DELAYED_STATE " + stage + ": " + DescribeTrigger(trigger) + "; " + DescribePlayer(player)));
		}
	}

	internal static bool IsSecondExteriorLadderTrigger(object trigger)
	{
		Component val = (Component)((trigger is Component) ? trigger : null);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		if (!IsShipLadderTrigger(trigger, out var _))
		{
			return false;
		}
		return ClassifyLadder(val.transform).StartsWith("SECOND_EXTERIOR_LADDER_CANDIDATE", StringComparison.Ordinal);
	}

	internal static bool NormalizeShipLadderTrigger(object trigger, string context)
	{
		if (!IsShipLadderTrigger(trigger, out var _))
		{
			return false;
		}
		Behaviour val = (Behaviour)((((trigger is Component) ? trigger : null) is Behaviour) ? ((trigger is Component) ? trigger : null) : null);
		if (val != null && !val.enabled)
		{
			val.enabled = true;
		}
		TrySetBool(trigger, "interactable", value: true);
		TrySetBool(trigger, "isLadder", value: true);
		TrySetBool(trigger, "holdInteraction", value: false);
		TrySetBool(trigger, "oneHandedItemAllowed", value: true);
		TrySetBool(trigger, "twoHandedItemAllowed", value: true);
		if (VerboseDiagnostics)
		{
			ManualLogSource logSource = LogSource;
			if (logSource != null)
			{
				logSource.LogDebug((object)("Normalized focused ship ladder flags (" + context + "): " + DescribeTrigger(trigger)));
			}
		}
		return true;
	}
}
internal static class ShipLadderGateDiagnostics
{
	private static readonly HashSet<int> GeometryLogged = new HashSet<int>();

	private static readonly object GeometryLock = new object();

	private static readonly Dictionary<int, float> ObstructionLogLastAt = new Dictionary<int, float>();

	private static readonly object ObstructionLogLock = new object();

	internal static bool IsTarget(object trigger)
	{
		Component val = (Component)((trigger is Component) ? trigger : null);
		if ((Object)(object)val == (Object)null || !ShipLadderInteractionFix.IsShipLadderTrigger(trigger, out var _))
		{
			return false;
		}
		string text = ShipLadderInteractionFix.ClassifyLadder(val.transform);
		if (!text.StartsWith("PRIMARY_EXTERIOR_LADDER_REFERENCE", StringComparison.Ordinal))
		{
			return text.StartsWith("SECOND_EXTERIOR_LADDER_CANDIDATE", StringComparison.Ordinal);
		}
		return true;
	}

	internal static void LogGateState(object trigger, object playerArgument, string stage, bool includeGeometry)
	{
		try
		{
			Component val = (Component)((trigger is Component) ? trigger : null);
			if (!((Object)(object)val == (Object)null) && IsTarget(trigger))
			{
				object instance = playerArgument;
				if (ShipLadderInteractionFix.GetMember(instance, "thisPlayerBody") == null)
				{
					instance = ShipLadderInteractionFix.ResolvePlayerController(playerArgument);
				}
				object member = ShipLadderInteractionFix.GetMember(instance, "thisPlayerBody");
				Transform t = (Transform)((member is Transform) ? member : null);
				object member2 = ShipLadderInteractionFix.GetMember(instance, "gameplayCamera");
				Component val2 = (Component)((member2 is Component) ? member2 : null);
				object member3 = ShipLadderInteractionFix.GetMember(trigger, "topOfLadderPosition");
				Transform t2 = (Transform)((member3 is Transform) ? member3 : null);
				object member4 = ShipLadderInteractionFix.GetMember(trigger, "bottomOfLadderPosition");
				Transform t3 = (Transform)((member4 is Transform) ? member4 : null);
				object member5 = ShipLadderInteractionFix.GetMember(trigger, "ladderHorizontalPosition");
				Transform t4 = (Transform)((member5 is Transform) ? member5 : null);
				object member6 = ShipLadderInteractionFix.GetMember(trigger, "ladderPlayerPositionNode");
				Transform t5 = (Transform)((member6 is Transform) ? member6 : null);
				object staticMember = GetStaticMember("StartOfRound", "Instance");
				object member7 = ShipLadderInteractionFix.GetMember(instance, "IsOwner");
				string text = "LADDER_VANILLA_GATE_STATE stage=" + stage + "; role=" + ShipLadderInteractionFix.ClassifyLadder(val.transform) + "; triggerPath=" + ShipLadderInteractionFix.GetHierarchyPath(val.transform) + "; triggerOnce=" + ShipLadderInteractionFix.GetBool(trigger, "triggerOnce") + "; hasTriggered=" + ShipLadderInteractionFix.GetBool(trigger, "hasTriggered") + "; firingPlayersCutsceneRunning=" + ShipLadderInteractionFix.GetBool(staticMember, "firingPlayersCutsceneRunning") + "; RandomChanceTrigger=" + ShipLadderInteractionFix.GetBool(trigger, "RandomChanceTrigger") + "; randomChancePercentage=" + F(ShipLadderInteractionFix.GetFloat(trigger, "randomChancePercentage", float.NaN)) + "; interactable=" + ShipLadderInteractionFix.GetBool(trigger, "interactable") + "; isPlayingSpecialAnimation=" + ShipLadderInteractionFix.GetBool(trigger, "isPlayingSpecialAnimation") + "; usingLadder=" + ShipLadderInteractionFix.GetBool(trigger, "usingLadder") + "; player.inSpecialInteractAnimation=" + ShipLadderInteractionFix.GetBool(instance, "inSpecialInteractAnimation") + "; player.isClimbingLadder=" + ShipLadderInteractionFix.GetBool(instance, "isClimbingLadder") + "; allowUseWhileInAnimation=" + ShipLadderInteractionFix.GetBool(trigger, "allowUseWhileInAnimation") + "; interactCooldown=" + ShipLadderInteractionFix.GetBool(trigger, "interactCooldown") + "; currentCooldownValue=" + F(ShipLadderInteractionFix.GetFloat(trigger, "currentCooldownValue", float.NaN)) + "; cooldownTime=" + F(ShipLadderInteractionFix.GetFloat(trigger, "cooldownTime", float.NaN)) + "; specialCharacterAnimation=" + ShipLadderInteractionFix.GetBool(trigger, "specialCharacterAnimation") + "; isLadder=" + ShipLadderInteractionFix.GetBool(trigger, "isLadder") + "; player.isInHangarShipRoom=" + ShipLadderInteractionFix.GetBool(instance, "isInHangarShipRoom") + "; player.isInElevator=" + ShipLadderInteractionFix.GetBool(instance, "isInElevator") + "; player.isTestingPlayer=" + ShipLadderInteractionFix.GetBool(instance, "isTestingPlayer") + "; player.isOwner=" + ((member7 == null) ? "<unavailable>" : Convert.ToString(member7)) + "; playerBody=" + Pose(t) + "; gameplayCamera=" + Pose(((Object)(object)val2 == (Object)null) ? null : val2.transform) + "; TopPos=" + Pose(t2) + "; BottomPos=" + Pose(t3) + "; HorizontalPosition=" + Pose(t4) + "; PlayerPositionNode=" + Pose(t5) + "; triggerTransform=" + Pose(val.transform) + "; triggerParent=" + Pose(val.transform.parent) + "; ladderParent=" + Pose(((Object)(object)val.transform.parent == (Object)null) ? null : val.transform.parent.parent);
				ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)text);
				}
				if (includeGeometry)
				{
					LogColliderGeometry(val);
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
			if (logSource2 != null)
			{
				logSource2.LogWarning((object)("LADDER_VANILLA_GATE_STATE diagnostic failed safely: " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}

	internal static void LogObstructionResult(object trigger, object[] args, bool result)
	{
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_02be: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!IsTarget(trigger))
			{
				return;
			}
			if (!ShipLadderInteractionFix.VerboseDiagnostics)
			{
				if (!ShipLadderInteractionFix.IsSecondExteriorLadderTrigger(trigger))
				{
					return;
				}
				Component val = (Component)((trigger is Component) ? trigger : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				float unscaledTime = Time.unscaledTime;
				lock (ObstructionLogLock)
				{
					if (ObstructionLogLastAt.TryGetValue(((Object)val).GetInstanceID(), out var value) && unscaledTime - value < 1f)
					{
						return;
					}
					ObstructionLogLastAt[((Object)val).GetInstanceID()] = unscaledTime;
				}
				ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("LADDER_FIX_OBSTRUCTION_CHECK: result=" + result + "; triggerPath=" + ShipLadderInteractionFix.GetHierarchyPath(val.transform) + "; player room flag was temporarily bypassed only during vanilla Interact; no physics result was modified."));
				}
				return;
			}
			object obj = ((args != null && args.Length != 0) ? args[0] : null);
			object member = ShipLadderInteractionFix.GetMember(trigger, "topOfLadderPosition");
			Transform val2 = (Transform)((member is Transform) ? member : null);
			object member2 = ShipLadderInteractionFix.GetMember(trigger, "ladderPlayerPositionNode");
			Transform val3 = (Transform)((member2 is Transform) ? member2 : null);
			object member3 = ShipLadderInteractionFix.GetMember(obj, "thisPlayerBody");
			Transform val4 = (Transform)((member3 is Transform) ? member3 : null);
			object member4 = ShipLadderInteractionFix.GetMember(obj, "gameplayCamera");
			Component val5 = (Component)((member4 is Component) ? member4 : null);
			bool flag = (Object)(object)val4 != (Object)null && (Object)(object)val2 != (Object)null && val4.position.y >= val2.position.y - 0.5f;
			string text = (flag ? "CAMERA_TO_NODE_PLUS_UP_2_8" : "CAMERA_TO_NODE");
			string text2 = "not-run";
			if (result && (Object)(object)val5 != (Object)null && (Object)(object)val3 != (Object)null)
			{
				Vector3 position = val5.transform.position;
				Vector3 val6 = (flag ? (val3.position + Vector3.up * 2.8f) : val3.position);
				object member5 = ShipLadderInteractionFix.GetMember(GetStaticMember("StartOfRound", "Instance"), "collidersAndRoomMaskAndDefault");
				if (member5 != null)
				{
					int num = Convert.ToInt32(member5);
					RaycastHit val7 = default(RaycastHit);
					bool flag2 = Physics.Linecast(position, val6, ref val7, num, (QueryTriggerInteraction)1);
					string text3 = (((Object)(object)((RaycastHit)(ref val7)).collider == (Object)null) ? "<none>" : ((Object)((RaycastHit)(ref val7)).collider).name);
					string text4 = (((Object)(object)((RaycastHit)(ref val7)).collider == (Object)null) ? "<none>" : ShipLadderInteractionFix.GetHierarchyPath(((Component)((RaycastHit)(ref val7)).collider).transform));
					text2 = "hit=" + flag2 + "; collider=" + text3 + "; colliderPath=" + text4 + "; from=" + V3(position) + "; to=" + V3(val6);
				}
			}
			ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
			if (logSource2 != null)
			{
				logSource2.LogWarning((object)("LADDER_POSITION_OBSTRUCTION_RESULT role=" + ShipLadderInteractionFix.ClassifyLadder(((Component)trigger).transform) + "; result=" + result + "; vanillaRayBranch=" + text + "; repeatedReadOnlyLinecast=" + text2 + "; state is recorded after vanilla moved PlayerPositionNode to its proposed climb position."));
			}
			LogGateState(trigger, obj, "AFTER_LadderPositionObstructed_result=" + result, includeGeometry: false);
		}
		catch (Exception ex)
		{
			ManualLogSource logSource3 = ShipLadderInteractionFix.LogSource;
			if (logSource3 != null)
			{
				logSource3.LogWarning((object)("LADDER_POSITION_OBSTRUCTION_RESULT diagnostic failed safely: " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}

	private static void LogColliderGeometry(Component trigger)
	{
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Unknown result type (might be due to invalid IL or missing references)
		int instanceID = ((Object)trigger).GetInstanceID();
		lock (GeometryLock)
		{
			if (!GeometryLogged.Add(instanceID))
			{
				return;
			}
		}
		Transform val = (((Object)(object)trigger.transform.parent != (Object)null) ? trigger.transform.parent : trigger.transform);
		Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren<Collider>(true);
		ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
		if (logSource != null)
		{
			logSource.LogInfo((object)("LADDER_GEOMETRY_COLLIDERS role=" + ShipLadderInteractionFix.ClassifyLadder(trigger.transform) + "; root=" + ShipLadderInteractionFix.GetHierarchyPath(val) + "; count=" + ((componentsInChildren != null) ? componentsInChildren.Length : 0)));
		}
		if (componentsInChildren == null)
		{
			return;
		}
		int num = Math.Min(componentsInChildren.Length, 50);
		for (int i = 0; i < num; i++)
		{
			Collider val2 = componentsInChildren[i];
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			string text = "shape=" + ((object)val2).GetType().Name;
			BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null);
			if (val3 != null)
			{
				text = text + "; center=" + V3(val3.center) + "; size=" + V3(val3.size);
			}
			else
			{
				SphereCollider val4 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null);
				if (val4 != null)
				{
					text = text + "; center=" + V3(val4.center) + "; radius=" + F(val4.radius);
				}
				else
				{
					CapsuleCollider val5 = (CapsuleCollider)(object)((val2 is CapsuleCollider) ? val2 : null);
					if (val5 != null)
					{
						text = text + "; center=" + V3(val5.center) + "; radius=" + F(val5.radius) + "; height=" + F(val5.height) + "; direction=" + val5.direction;
					}
				}
			}
			string text3;
			try
			{
				Bounds bounds = val2.bounds;
				string text2 = V3(((Bounds)(ref bounds)).center);
				bounds = val2.bounds;
				text3 = "; boundsCenter=" + text2 + "; boundsSize=" + V3(((Bounds)(ref bounds)).size);
			}
			catch (Exception ex)
			{
				text3 = "; bounds=<error:" + ex.GetType().Name + ">";
			}
			ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
			if (logSource2 != null)
			{
				logSource2.LogInfo((object)("LADDER_GEOMETRY_COLLIDER role=" + ShipLadderInteractionFix.ClassifyLadder(trigger.transform) + "; path=" + ShipLadderInteractionFix.GetHierarchyPath(((Component)val2).transform) + "; enabled=" + val2.enabled + "; active=" + ((Component)val2).gameObject.activeInHierarchy + "; isTrigger=" + val2.isTrigger + "; layer=" + ((Component)val2).gameObject.layer + "; layerName=" + LayerMask.LayerToName(((Component)val2).gameObject.layer) + "; " + text + text3));
			}
		}
		if (componentsInChildren.Length > num)
		{
			ManualLogSource logSource3 = ShipLadderInteractionFix.LogSource;
			if (logSource3 != null)
			{
				logSource3.LogInfo((object)("LADDER_GEOMETRY_COLLIDER_LIMIT: omitted=" + (componentsInChildren.Length - num)));
			}
		}
	}

	private static object GetStaticMember(string typeName, string memberName)
	{
		Type type = AccessTools.TypeByName(typeName);
		if (type == null)
		{
			return null;
		}
		while (type != null)
		{
			FieldInfo field = type.GetField(memberName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field.GetValue(null);
			}
			PropertyInfo property = type.GetProperty(memberName, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.GetIndexParameters().Length == 0)
			{
				return property.GetValue(null, null);
			}
			type = type.BaseType;
		}
		return null;
	}

	private static string Pose(Transform t)
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)t == (Object)null)
		{
			return "<null>";
		}
		return "path=" + ShipLadderInteractionFix.GetHierarchyPath(t) + "#" + ((Object)((Component)t).gameObject).GetInstanceID() + "{world=" + V3(t.position) + ";local=" + V3(t.localPosition) + ";worldEuler=" + V3(t.eulerAngles) + ";localEuler=" + V3(t.localEulerAngles) + ";localScale=" + V3(t.localScale) + ";lossyScale=" + V3(t.lossyScale) + "}";
	}

	private static string V3(Vector3 v)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		return "(" + F(v.x) + "," + F(v.y) + "," + F(v.z) + ")";
	}

	private static string F(float v)
	{
		return v.ToString("0.000", CultureInfo.InvariantCulture);
	}
}
[HarmonyPatch]
internal static class ShipLadderPositionObstructionDiagnosticPatch
{
	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("InteractTrigger");
		if (!(type == null))
		{
			return AccessTools.Method(type, "LadderPositionObstructed", (Type[])null, (Type[])null);
		}
		return null;
	}

	[HarmonyPostfix]
	private static void Postfix(object __instance, object[] __args, bool __result)
	{
		ShipLadderGateDiagnostics.LogObstructionResult(__instance, __args, __result);
	}
}
[HarmonyPatch]
internal static class ShipLadderNetworkSpawnPatch
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		return from method in typeof(NetworkObject).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
			where method.DeclaringType == typeof(NetworkObject) && (method.Name == "Spawn" || method.Name == "SpawnWithObservers" || method.Name == "SpawnAsPlayerObject" || method.Name == "SpawnWithOwnership")
			select method;
	}

	[HarmonyPrefix]
	private static void Prefix(NetworkObject __instance, MethodBase __originalMethod)
	{
		ShipLadderInteractionFix.RunRepair(__instance, __originalMethod);
	}
}
[HarmonyPatch]
internal static class ShipLadderTriggerInteractPatch
{
	private sealed class RoomFlagBypassState
	{
		internal object Player;

		internal bool OriginalValue;

		internal bool Restored;
	}

	private static int _lastFrame = -1;

	private static int _lastTriggerId;

	private static bool _lastOriginalRan;

	private static bool _lastCallObserved;

	internal static bool WasCalledThisFrame(object trigger)
	{
		if (_lastFrame == Time.frameCount && _lastTriggerId == ShipLadderInteractionFix.GetInstanceId(trigger))
		{
			return _lastCallObserved;
		}
		return false;
	}

	internal static bool OriginalRanThisFrame(object trigger)
	{
		if (WasCalledThisFrame(trigger))
		{
			return _lastOriginalRan;
		}
		return false;
	}

	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("InteractTrigger");
		if (type == null)
		{
			return null;
		}
		return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo method) => method.Name == "Interact" && method.GetParameters().Length == 1);
	}

	[HarmonyPrefix]
	[HarmonyPriority(800)]
	private static void Prefix(object __instance, object __0, out RoomFlagBypassState __state)
	{
		__state = null;
		if (!ShipLadderInteractionFix.IsShipLadderTrigger(__instance, out var _))
		{
			return;
		}
		_lastFrame = Time.frameCount;
		_lastTriggerId = ShipLadderInteractionFix.GetInstanceId(__instance);
		_lastCallObserved = true;
		_lastOriginalRan = false;
		if (ShipLadderInteractionFix.VerboseDiagnostics)
		{
			ShipLadderInteractionFix.LogLadderSnapshot(__instance, __0, "INTERACT-PREFIX-RAW-BEFORE-NORMALIZE");
		}
		if (ShipLadderInteractionFix.VerboseDiagnostics)
		{
			ShipLadderGateDiagnostics.LogGateState(__instance, __0, "INTERACT_ENTRY_BEFORE_NORMALIZE", includeGeometry: true);
		}
		ShipLadderInteractionFix.NormalizeShipLadderTrigger(__instance, "InteractTrigger.Interact prefix");
		if (ShipLadderInteractionFix.VerboseDiagnostics)
		{
			ShipLadderGateDiagnostics.LogGateState(__instance, __0, "INTERACT_ENTRY_AFTER_NORMALIZE", includeGeometry: false);
		}
		if (!ShipLadderInteractionFix.IsSecondExteriorLadderTrigger(__instance))
		{
			return;
		}
		object obj = ShipLadderInteractionFix.ResolvePlayerController(__0);
		if (obj == null)
		{
			ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
			if (logSource != null)
			{
				logSource.LogWarning((object)"LADDER_ROOM_GATE_BYPASS_SKIPPED: upper ladder matched but PlayerControllerB could not be resolved; vanilla behavior left unchanged.");
			}
			return;
		}
		object member = ShipLadderInteractionFix.GetMember(obj, "IsOwner");
		if (!(member is bool) || !(bool)member)
		{
			return;
		}
		bool flag = ShipLadderInteractionFix.GetBool(obj, "isInHangarShipRoom");
		if (!flag)
		{
			return;
		}
		if (!ShipLadderInteractionFix.TrySetBool(obj, "isInHangarShipRoom", value: false))
		{
			ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
			if (logSource2 != null)
			{
				logSource2.LogWarning((object)"LADDER_ROOM_GATE_BYPASS_FAILED: could not temporarily change the upper-ladder room gate; vanilla behavior left unchanged.");
			}
			return;
		}
		__state = new RoomFlagBypassState
		{
			Player = obj,
			OriginalValue = flag,
			Restored = false
		};
		ManualLogSource logSource3 = ShipLadderInteractionFix.LogSource;
		if (logSource3 != null)
		{
			logSource3.LogInfo((object)"LADDER_ROOM_GATE_BYPASS applied: exact upper exterior ladder only; player.isInHangarShipRoom=True->False for this vanilla Interact call; restoration scheduled immediately after.");
		}
	}

	private static bool RestoreRoomFlag(RoomFlagBypassState state)
	{
		if (state == null)
		{
			return true;
		}
		if (state.Restored)
		{
			return true;
		}
		bool num = ShipLadderInteractionFix.TrySetBool(state.Player, "isInHangarShipRoom", state.OriginalValue);
		if (num)
		{
			state.Restored = true;
		}
		return num;
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	private static void Postfix(object __instance, object __0, bool __runOriginal, RoomFlagBypassState __state)
	{
		bool flag = RestoreRoomFlag(__state);
		if (!ShipLadderInteractionFix.IsShipLadderTrigger(__instance, out var path))
		{
			return;
		}
		_lastFrame = Time.frameCount;
		_lastTriggerId = ShipLadderInteractionFix.GetInstanceId(__instance);
		_lastCallObserved = true;
		_lastOriginalRan = __runOriginal;
		if (ShipLadderInteractionFix.IsSecondExteriorLadderTrigger(__instance))
		{
			object instance = ((__state != null) ? __state.Player : ShipLadderInteractionFix.ResolvePlayerController(__0));
			ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
			if (logSource != null)
			{
				logSource.LogInfo((object)("LADDER_FIX_INTERACT_RESULT: originalRan=" + __runOriginal + "; roomGateBypassApplied=" + (__state != null) + "; roomFlagRestored=" + ((__state == null) ? "not-needed" : flag.ToString()) + "; player.isInHangarShipRoom=" + ShipLadderInteractionFix.GetBool(instance, "isInHangarShipRoom") + "; usingLadder=" + ShipLadderInteractionFix.GetBool(__instance, "usingLadder") + "; isClimbingLadder=" + ShipLadderInteractionFix.GetBool(instance, "isClimbingLadder") + "; inSpecialInteractAnimation=" + ShipLadderInteractionFix.GetBool(instance, "inSpecialInteractAnimation") + "; path=" + path));
			}
			ShipLadderInteractionFix.Instance?.StartDelayedLadderObservation(__instance, __0);
		}
		else if (ShipLadderInteractionFix.VerboseDiagnostics)
		{
			object player = ShipLadderInteractionFix.ResolvePlayerController(__0);
			ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
			if (logSource2 != null)
			{
				logSource2.LogInfo((object)("LADDER_INTERACT_METHOD_RETURNED: originalRan=" + __runOriginal + ": " + ShipLadderInteractionFix.DescribeTrigger(__instance) + "; " + ShipLadderInteractionFix.DescribeArgument(__0) + "; " + ShipLadderInteractionFix.DescribePlayer(player)));
			}
		}
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(RoomFlagBypassState __state, Exception __exception)
	{
		if (__state != null && !RestoreRoomFlag(__state))
		{
			ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
			if (logSource != null)
			{
				logSource.LogWarning((object)"LADDER_ROOM_GATE_RESTORE_FAILED: couldn't restore the original isInHangarShipRoom value after Interact; inspect the next log before further testing.");
			}
		}
		return __exception;
	}
}
[HarmonyPatch]
internal static class ShipLadderPlayerInputGuard
{
	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("GameNetcodeStuff.PlayerControllerB");
		if (!(type == null))
		{
			return AccessTools.Method(type, "Interact_performed", (Type[])null, (Type[])null);
		}
		return null;
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	private static void Postfix(object __instance, object __0)
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!WasPerformed(__0))
			{
				return;
			}
			object member = ShipLadderInteractionFix.GetMember(__instance, "hoveringOverTrigger");
			if (!ShipLadderInteractionFix.IsShipLadderTrigger(member, out var path))
			{
				return;
			}
			ShipLadderInteractionFix.NormalizeShipLadderTrigger(member, "PlayerControllerB.Interact_performed postfix");
			if (ShipLadderInteractionFix.VerboseDiagnostics)
			{
				ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("PLAYER PRESSED INTERACT ON " + ShipLadderInteractionFix.ClassifyLadder(((Component)member).transform) + ": " + ShipLadderInteractionFix.DescribeTrigger(member, __instance)));
				}
			}
			if (ShipLadderInteractionFix.GetBool(__instance, "isClimbingLadder"))
			{
				return;
			}
			if (ShipLadderInteractionFix.GetBool(__instance, "isPlayerDead") || (!ShipLadderInteractionFix.GetBool(__instance, "isPlayerControlled") && !ShipLadderInteractionFix.GetBool(__instance, "isTestingPlayer")) || ShipLadderInteractionFix.GetBool(__instance, "inSpecialMenu") || ShipLadderInteractionFix.GetBool(__instance, "inTerminalMenu") || ShipLadderInteractionFix.GetBool(__instance, "isTypingChat") || ShipLadderInteractionFix.GetBool(__instance, "jetpackControls") || ShipLadderInteractionFix.GetBool(__instance, "disablingJetpackControls") || ShipLadderInteractionFix.GetMember(__instance, "inAnimationWithEnemy") != null || ShipLadderInteractionFix.GetFloat(__instance, "timeSinceSwitchingSlots", 1f) < 0.2f)
			{
				if (ShipLadderInteractionFix.VerboseDiagnostics)
				{
					ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
					if (logSource2 != null)
					{
						logSource2.LogInfo((object)"Ladder fallback not attempted because a vanilla safety gate is active.");
					}
				}
				return;
			}
			object member2 = ShipLadderInteractionFix.GetMember(__instance, "IsOwner");
			if (member2 is bool && !(bool)member2)
			{
				return;
			}
			if (ShipLadderTriggerInteractPatch.WasCalledThisFrame(member))
			{
				if (ShipLadderInteractionFix.IsSecondExteriorLadderTrigger(member) && !ShipLadderInteractionFix.GetBool(member, "usingLadder") && !ShipLadderInteractionFix.GetBool(__instance, "isClimbingLadder") && !ShipLadderInteractionFix.GetBool(__instance, "inSpecialInteractAnimation") && ShipLadderInteractionFix.VerboseDiagnostics)
				{
					ManualLogSource logSource3 = ShipLadderInteractionFix.LogSource;
					if (logSource3 != null)
					{
						logSource3.LogInfo((object)"No extra upper-ladder interaction was issued; the room-gate repair relies on this original vanilla call only.");
					}
				}
				if (!ShipLadderInteractionFix.VerboseDiagnostics)
				{
					return;
				}
				if (!ShipLadderTriggerInteractPatch.OriginalRanThisFrame(member))
				{
					ManualLogSource logSource4 = ShipLadderInteractionFix.LogSource;
					if (logSource4 != null)
					{
						logSource4.LogWarning((object)("The ladder Interact method was called, but its original body was skipped by a patch. No second call was made to avoid duplicate activation. Path=" + path));
					}
				}
				else
				{
					ManualLogSource logSource5 = ShipLadderInteractionFix.LogSource;
					if (logSource5 != null)
					{
						logSource5.LogInfo((object)("The normal input path did call the ladder Interact method, but climbing was not confirmed in this frame. No duplicate call was made. Path=" + path));
					}
				}
			}
			else if (ShipLadderInteractionFix.VerboseDiagnostics)
			{
				ManualLogSource logSource6 = ShipLadderInteractionFix.LogSource;
				if (logSource6 != null)
				{
					logSource6.LogWarning((object)("Normal input did not call the focused ladder's Interact method; this build does not issue a second call. Path=" + path));
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logSource7 = ShipLadderInteractionFix.LogSource;
			if (logSource7 != null)
			{
				logSource7.LogWarning((object)("Input guard failed safely: " + ex.GetType().Name + ": " + ex.Message));
			}
		}
	}

	private static bool WasPerformed(object context)
	{
		object member = ShipLadderInteractionFix.GetMember(context, "performed");
		if (member is bool)
		{
			return (bool)member;
		}
		object member2 = ShipLadderInteractionFix.GetMember(context, "phase");
		if (member2 != null)
		{
			return string.Equals(Convert.ToString(member2), "Performed", StringComparison.OrdinalIgnoreCase);
		}
		return false;
	}
}
[HarmonyPatch]
internal static class ShipLadderUseConditionsGuard
{
	private static MethodBase TargetMethod()
	{
		Type type = AccessTools.TypeByName("GameNetcodeStuff.PlayerControllerB");
		if (!(type == null))
		{
			return AccessTools.Method(type, "InteractTriggerUseConditionsMet", (Type[])null, (Type[])null);
		}
		return null;
	}

	[HarmonyPrefix]
	private static void Prefix(object __instance)
	{
		try
		{
			object member = ShipLadderInteractionFix.GetMember(__instance, "hoveringOverTrigger");
			if (ShipLadderInteractionFix.VerboseDiagnostics && ShipLadderInteractionFix.IsShipLadderTrigger(member, out var _))
			{
				ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("USE_CONDITIONS_METHOD_ENTERED: trigger=" + ShipLadderInteractionFix.DescribeTrigger(member) + "; " + ShipLadderInteractionFix.DescribePlayer(__instance)));
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
			if (logSource2 != null)
			{
				logSource2.LogDebug((object)("Use-condition prefix diagnostic failed safely: " + ex.GetType().Name));
			}
		}
	}

	[HarmonyPostfix]
	[HarmonyPriority(0)]
	private static void Postfix(object __instance, ref bool __result)
	{
		try
		{
			object member = ShipLadderInteractionFix.GetMember(__instance, "hoveringOverTrigger");
			if (!ShipLadderInteractionFix.IsShipLadderTrigger(member, out var path))
			{
				return;
			}
			if (ShipLadderInteractionFix.VerboseDiagnostics)
			{
				ManualLogSource logSource = ShipLadderInteractionFix.LogSource;
				if (logSource != null)
				{
					logSource.LogInfo((object)("USE_CONDITIONS_RESULT_BEFORE_GUARD: result=" + __result + "; trigger=" + ShipLadderInteractionFix.DescribeTrigger(member) + "; " + ShipLadderInteractionFix.DescribePlayer(__instance)));
				}
			}
			if (ShipLadderInteractionFix.GetBool(__instance, "isPlayerDead") || ShipLadderInteractionFix.GetBool(__instance, "inTerminalMenu") || ShipLadderInteractionFix.GetBool(__instance, "inSpecialMenu") || ShipLadderInteractionFix.GetBool(__instance, "isTypingChat") || ShipLadderInteractionFix.GetBool(__instance, "jetpackControls") || ShipLadderInteractionFix.GetBool(__instance, "disablingJetpackControls"))
			{
				return;
			}
			if (!__result && ShipLadderInteractionFix.VerboseDiagnostics)
			{
				ManualLogSource logSource2 = ShipLadderInteractionFix.LogSource;
				if (logSource2 != null)
				{
					logSource2.LogWarning((object)("Overriding false interaction-use result for focused ship ladder. Path=" + path));
				}
			}
			__result = true;
		}
		catch (Exception ex)
		{
			ManualLogSource logSource3 = ShipLadderInteractionFix.LogSource;
			if (logSource3 != null)
			{
				logSource3.LogDebug((object)("Use-condition guard failed safely: " + ex.GetType().Name));
			}
		}
	}
}