Decompiled source of GetOutOfTheWater v0.1.0

GetOutOfTheWater.dll

Decompiled 2 hours ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GetOutOfTheWater")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Press Jump while swimming to pull yourself onto nearby ledges, docks, ruins, and boats.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+f8323569655b908c100cdcd250370728bbc335b1")]
[assembly: AssemblyProduct("GetOutOfTheWater")]
[assembly: AssemblyTitle("GetOutOfTheWater")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[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;
		}
	}
}
namespace GetOutOfTheWater
{
	internal static class CharacterAccess
	{
		private static readonly FieldRef<Character, float> SwimTimer = AccessTools.FieldRefAccess<Character, float>("m_swimTimer");

		private static readonly FieldRef<Character, float> LastGroundTouch = AccessTools.FieldRefAccess<Character, float>("m_lastGroundTouch");

		private static readonly FieldRef<Character, float> MaxAirAltitude = AccessTools.FieldRefAccess<Character, float>("m_maxAirAltitude");

		private static readonly FieldRef<Character, Vector3> CurrentVel = AccessTools.FieldRefAccess<Character, Vector3>("m_currentVel");

		private static readonly FieldRef<Character, Vector3> LookDir = AccessTools.FieldRefAccess<Character, Vector3>("m_lookDir");

		private static readonly FieldRef<int> GroundRayMask = AccessTools.StaticFieldRefAccess<int>(AccessTools.Field(typeof(Character), "s_groundRayMask"));

		internal static float GetSwimTimer(Character character)
		{
			return SwimTimer.Invoke(character);
		}

		internal static void SetSwimTimer(Character character, float value)
		{
			SwimTimer.Invoke(character) = value;
		}

		internal static void SetLastGroundTouch(Character character, float value)
		{
			LastGroundTouch.Invoke(character) = value;
		}

		internal static void SetMaxAirAltitude(Character character, float value)
		{
			MaxAirAltitude.Invoke(character) = value;
		}

		internal static void SetCurrentVel(Character character, Vector3 value)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			CurrentVel.Invoke(character) = value;
		}

		internal static Vector3 GetLookDir(Character character)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return LookDir.Invoke(character);
		}

		internal static int GetGroundRayMask()
		{
			int num = GroundRayMask.Invoke();
			if (num != 0)
			{
				return num;
			}
			return LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "terrain", "blocker", "vehicle" });
		}
	}
	[BepInPlugin("hardwire99.getoutofthewater", "Get Out Of The Water", "0.1.0")]
	public sealed class GetOutOfTheWaterPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			if (!ModConfig.Enabled.Value)
			{
				Log.LogInfo((object)"Get Out Of The Water 0.1.0 is disabled in config.");
				return;
			}
			harmony = new Harmony("hardwire99.getoutofthewater");
			harmony.PatchAll(typeof(GetOutOfTheWaterPlugin).Assembly);
			Log.LogInfo((object)("Get Out Of The Water 0.1.0 loaded (lip-line, dll " + GetDllTimestamp() + ")."));
		}

		private void Update()
		{
			if (!ModConfig.Enabled.Value)
			{
				SwimExitLipLine.Hide();
			}
			else
			{
				SwimExitLipLine.Tick();
			}
		}

		private void OnDestroy()
		{
			SwimExitLipLine.Destroy();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private static string GetDllTimestamp()
		{
			string location = Assembly.GetExecutingAssembly().Location;
			if (!File.Exists(location))
			{
				return "unknown";
			}
			return File.GetLastWriteTime(location).ToString("yyyy-MM-dd HH:mm:ss");
		}
	}
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<float> BaseClimbHeight;

		internal static ConfigEntry<float> JumpClimbBonus;

		internal static ConfigEntry<float> ReachDistance;

		internal static ConfigEntry<float> MantleDuration;

		internal static ConfigEntry<float> StaminaCost;

		internal static ConfigEntry<bool> AllowBoats;

		internal static ConfigEntry<bool> ShowLipLine;

		internal static ConfigEntry<float> SurfaceMaxSubmersion;

		internal static ConfigEntry<float> CooldownSeconds;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable swim-exit on Jump. When false, no Harmony patches run.");
			DebugLogging = config.Bind<bool>("General", "DebugLogging", false, "Log ledge probes and mantle starts to BepInEx.");
			BaseClimbHeight = config.Bind<float>("Mantle", "BaseClimbHeight", 1f, "Pull-up height in meters above the waterline at Jump skill 0. Measured against water level at the instant you press Jump.");
			JumpClimbBonus = config.Bind<float>("Mantle", "JumpClimbBonus", 1f, "Extra meters of pull-up height at Jump skill 100. Scales linearly with Jump.");
			ReachDistance = config.Bind<float>("Mantle", "ReachDistance", 1.5f, "How far ahead to search for a wall or ledge while swimming.");
			MantleDuration = config.Bind<float>("Mantle", "MantleDuration", 0.2f, "Seconds to lerp onto the ledge. Keep short so swim physics cannot pull you back.");
			StaminaCost = config.Bind<float>("Mantle", "StaminaCost", -1f, "Stamina spent on a successful pull-up. Negative uses the vanilla jump stamina cost.");
			AllowBoats = config.Bind<bool>("Mantle", "AllowBoats", true, "Allow pulling onto ships and other vehicle colliders from the water.");
			ShowLipLine = config.Bind<bool>("Mantle", "ShowLipLine", true, "Draw a red/green line on a nearby ledge lip while swimming. Green means Jump would pull you up at the current waterline.");
			SurfaceMaxSubmersion = config.Bind<float>("Mantle", "SurfaceMaxSubmersion", 2.8f, "If water is deeper than this above your feet, Jump is left alone so diving mods can ascend. Also allows at least swimDepth + 0.75m.");
			CooldownSeconds = config.Bind<float>("Mantle", "CooldownSeconds", 0.4f, "Minimum seconds between swim-exit attempts.");
		}

		internal static void Log(string message)
		{
			if (DebugLogging.Value)
			{
				GetOutOfTheWaterPlugin.Log.LogInfo((object)message);
			}
		}
	}
	internal static class ModConstants
	{
		public const string ModGuid = "hardwire99.getoutofthewater";

		public const string ModName = "Get Out Of The Water";

		public const string ModVersion = "0.1.0";

		public const string BuildLabel = "lip-line";
	}
	internal static class SwimExitClimb
	{
		internal static float GetMaxHeight(Character character)
		{
			float num = 0f;
			if ((Object)(object)character != (Object)null)
			{
				num = Mathf.Clamp01(character.GetSkillFactor((SkillType)100));
			}
			return ModConfig.BaseClimbHeight.Value + ModConfig.JumpClimbBonus.Value * num;
		}

		internal static void AwardJumpSkill(Character character)
		{
			character.RaiseSkill((SkillType)100, 1f);
			if (character is Player && (Object)(object)Game.instance != (Object)null)
			{
				Game.instance.IncrementPlayerStat((PlayerStatType)3, 1f);
			}
		}
	}
	internal static class SwimExitLipLine
	{
		private const float HalfWidth = 0.85f;

		private const float LineWidth = 0.07f;

		private const int SampleCount = 7;

		private static readonly Color Reachable = new Color(0.2f, 0.95f, 0.35f, 1f);

		private static readonly Color TooHigh = new Color(0.95f, 0.22f, 0.18f, 1f);

		private static readonly Vector3[] SamplePoints = (Vector3[])(object)new Vector3[7];

		private static LineRenderer line;

		private static Material material;

		internal static void Tick()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.ShowLipLine.Value)
			{
				Hide();
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || SwimExitMantle.IsActive((Character)(object)localPlayer) || !SwimExitMantle.IsEligible((Character)(object)localPlayer))
			{
				Hide();
				return;
			}
			if (!SwimExitProbe.TryFindLip((Character)(object)localPlayer, out var ledge))
			{
				Hide();
				return;
			}
			int num = BuildSamples((Character)(object)localPlayer, ledge);
			if (num < 2)
			{
				Hide();
				return;
			}
			EnsureLine();
			if (!((Object)(object)line == (Object)null))
			{
				Color val = (ledge.InReach ? Reachable : TooHigh);
				line.startColor = val;
				line.endColor = val;
				if ((Object)(object)material != (Object)null)
				{
					material.color = val;
				}
				line.positionCount = num;
				for (int i = 0; i < num; i++)
				{
					line.SetPosition(i, SamplePoints[i]);
				}
				((Renderer)line).enabled = true;
			}
		}

		internal static void Hide()
		{
			if ((Object)(object)line != (Object)null)
			{
				((Renderer)line).enabled = false;
			}
		}

		internal static void Destroy()
		{
			if ((Object)(object)line != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)line).gameObject);
				line = null;
			}
			if ((Object)(object)material != (Object)null)
			{
				Object.Destroy((Object)(object)material);
				material = null;
			}
		}

		private static int BuildSamples(Character character, SwimExitLedge ledge)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.Cross(Vector3.up, ledge.Forward);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = ((Component)character).transform.right;
			}
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return 0;
			}
			((Vector3)(ref val)).Normalize();
			int groundRayMask = CharacterAccess.GetGroundRayMask();
			int result = 0;
			Vector3 val2 = Vector3.up * 0.04f - ledge.Forward * 0.04f;
			RaycastHit val5 = default(RaycastHit);
			for (int i = 0; i < 7; i++)
			{
				float num = (float)i / 6f * 2f - 1f;
				Vector3 val3 = ledge.StandPoint + val * (num * 0.85f) + Vector3.up * 0.45f;
				Vector3 val4 = ledge.StandPoint + val * (num * 0.85f);
				if (Physics.Raycast(val3, Vector3.down, ref val5, 0.9f, groundRayMask, (QueryTriggerInteraction)1) && Mathf.Abs(((RaycastHit)(ref val5)).point.y - ledge.StandPoint.y) < 0.35f)
				{
					val4 = ((RaycastHit)(ref val5)).point;
				}
				SamplePoints[result++] = val4 + val2;
			}
			return result;
		}

		private static void EnsureLine()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			if (!((Object)(object)line != (Object)null))
			{
				Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Hidden/Internal-Colored") ?? Shader.Find("Unlit/Color");
				if ((Object)(object)val == (Object)null)
				{
					ModConfig.Log("Lip line shader not found.");
					return;
				}
				GameObject val2 = new GameObject("GetOutOfTheWater_LipLine");
				Object.DontDestroyOnLoad((Object)val2);
				((Object)val2).hideFlags = (HideFlags)61;
				material = new Material(val)
				{
					color = Reachable,
					hideFlags = (HideFlags)61
				};
				material.SetInt("_ZWrite", 0);
				material.renderQueue = 4000;
				line = val2.AddComponent<LineRenderer>();
				((Renderer)line).sharedMaterial = material;
				line.useWorldSpace = true;
				line.loop = false;
				line.positionCount = 0;
				line.widthMultiplier = 0.07f;
				line.numCapVertices = 2;
				line.numCornerVertices = 2;
				((Renderer)line).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)line).receiveShadows = false;
				((Renderer)line).allowOcclusionWhenDynamic = false;
				line.alignment = (LineAlignment)0;
				line.textureMode = (LineTextureMode)0;
				((Renderer)line).enabled = false;
			}
		}
	}
	internal static class SwimExitMantle
	{
		private static Character active;

		private static Vector3 start;

		private static Vector3 end;

		private static Vector3 forward;

		private static float elapsed;

		private static float duration;

		private static float cooldownUntil;

		internal static bool IsCoolingDown => Time.time < cooldownUntil;

		internal static bool IsActive(Character character)
		{
			return (Object)(object)active == (Object)(object)character;
		}

		internal static bool IsEligible(Character character)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)character != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (!character.IsSwimming() || character.IsDead() || character.InDodge() || character.IsKnockedBack() || character.IsEncumbered())
			{
				return false;
			}
			if (character.IsAttached() || character.IsAttachedToShip() || character.InBed())
			{
				return false;
			}
			float num = character.GetLiquidLevel() - ((Component)character).transform.position.y;
			float num2 = Mathf.Max(ModConfig.SurfaceMaxSubmersion.Value, character.m_swimDepth + 0.75f);
			if (num > num2)
			{
				return false;
			}
			return true;
		}

		internal static bool TryBegin(Character character)
		{
			//IL_00a7: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			if (!IsEligible(character))
			{
				return false;
			}
			if (IsActive(character) || IsCoolingDown)
			{
				return false;
			}
			if (!SwimExitProbe.TryFind(character, out var ledge) || !ledge.InReach)
			{
				return false;
			}
			float num = ModConfig.StaminaCost.Value;
			if (num < 0f)
			{
				num = character.m_jumpStaminaUsage;
			}
			if (num > 0f && !character.HaveStamina(num))
			{
				if ((Object)(object)Hud.instance != (Object)null)
				{
					Hud.instance.StaminaBarEmptyFlash();
				}
				return false;
			}
			if (num > 0f)
			{
				character.UseStamina(num);
			}
			SwimExitClimb.AwardJumpSkill(character);
			Rigidbody component = ((Component)character).GetComponent<Rigidbody>();
			start = (((Object)(object)component != (Object)null) ? component.position : ((Component)character).transform.position);
			end = ledge.StandPoint;
			forward = ledge.Forward;
			elapsed = 0f;
			duration = Mathf.Max(0.05f, ModConfig.MantleDuration.Value);
			active = character;
			cooldownUntil = Time.time + ModConfig.CooldownSeconds.Value;
			CharacterAccess.SetMaxAirAltitude(character, end.y);
			ModConfig.Log($"Mantle start {start} -> {end}");
			return true;
		}

		internal static void Tick(Character character, float dt)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00cc: Unknown result type (might be due to invalid IL or missing references)
			if (IsActive(character))
			{
				elapsed += dt;
				float num = ((duration <= 0f) ? 1f : Mathf.Clamp01(elapsed / duration));
				num = num * num * (3f - 2f * num);
				Vector3 pos = Vector3.Lerp(start, end, num);
				ApplyPosition(character, pos, Vector3.zero);
				if (!(elapsed < duration))
				{
					Vector3 val = forward * 1.6f + Vector3.up * 0.4f;
					ApplyPosition(character, end, val);
					CharacterAccess.SetSwimTimer(character, 1f);
					CharacterAccess.SetLastGroundTouch(character, 0f);
					CharacterAccess.SetMaxAirAltitude(character, end.y);
					CharacterAccess.SetCurrentVel(character, val);
					ModConfig.Log("Mantle complete.");
					active = null;
				}
			}
		}

		internal static void Cancel(Character character)
		{
			if (IsActive(character))
			{
				active = null;
			}
		}

		private static void ApplyPosition(Character character, Vector3 pos, Vector3 velocity)
		{
			//IL_002a: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody component = ((Component)character).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.WakeUp();
				component.position = pos;
				component.linearVelocity = velocity;
			}
			((Component)character).transform.position = pos;
		}
	}
	internal readonly struct SwimExitLedge
	{
		internal Vector3 StandPoint { get; }

		internal Vector3 Forward { get; }

		internal bool InReach { get; }

		internal SwimExitLedge(Vector3 standPoint, Vector3 forward, bool inReach)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			StandPoint = standPoint;
			Forward = forward;
			InReach = inReach;
		}
	}
	internal static class SwimExitProbe
	{
		private const float MinStandNormalY = 0.45f;

		private const float CapsuleSkin = 0.08f;

		private const float CastBack = 0.55f;

		private static readonly float[] DownInsets = new float[4] { 0.18f, 0.35f, 0.55f, 0.8f };

		private static readonly Collider[] OverlapBuffer = (Collider[])(object)new Collider[24];

		private const float MarkerSearchHeight = 4f;

		internal static bool TryFind(Character character, out SwimExitLedge ledge)
		{
			return TryFindInternal(character, requireInReach: true, horizontalOnly: false, out ledge);
		}

		internal static bool TryFindLip(Character character, out SwimExitLedge ledge)
		{
			return TryFindInternal(character, requireInReach: false, horizontalOnly: true, out ledge);
		}

		private static bool TryFindInternal(Character character, bool requireInReach, bool horizontalOnly, out SwimExitLedge ledge)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			ledge = default(SwimExitLedge);
			Vector3 val = Flatten(character.GetMoveDir());
			Vector3 val2 = Flatten(character.GetLookDir());
			Vector3 val3 = Flatten(((Component)character).transform.forward);
			if (!horizontalOnly && TryFindAlongLook(character, requireInReach, out ledge))
			{
				return true;
			}
			if (((Vector3)(ref val)).sqrMagnitude > 0.05f && TryFindInDirection(character, ((Vector3)(ref val)).normalized, requireInReach, out ledge))
			{
				return true;
			}
			if (((Vector3)(ref val2)).sqrMagnitude > 0.05f && TryFindInDirection(character, ((Vector3)(ref val2)).normalized, requireInReach, out ledge))
			{
				return true;
			}
			if (((Vector3)(ref val3)).sqrMagnitude > 0.05f && TryFindInDirection(character, ((Vector3)(ref val3)).normalized, requireInReach, out ledge))
			{
				return true;
			}
			if (requireInReach)
			{
				ModConfig.Log("Probe found no standable ledge.");
			}
			return false;
		}

		private static bool TryFindAlongLook(Character character, bool requireInReach, out SwimExitLedge ledge)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			ledge = default(SwimExitLedge);
			Vector3 lookDir = character.GetLookDir();
			if (((Vector3)(ref lookDir)).sqrMagnitude < 0.01f)
			{
				return false;
			}
			((Vector3)(ref lookDir)).Normalize();
			int num = BuildMask();
			float num2 = ModConfig.ReachDistance.Value + 0.75f;
			Vector3[] array = (Vector3[])(object)new Vector3[2]
			{
				character.GetEyePoint() - lookDir * 0.15f,
				character.GetCenterPoint() - lookDir * 0.15f
			};
			RaycastHit val = default(RaycastHit);
			for (int i = 0; i < array.Length; i++)
			{
				if (Physics.Raycast(array[i], lookDir, ref val, num2, num, (QueryTriggerInteraction)1))
				{
					RaycastHit hit = val;
					Vector3 val2 = Flatten(lookDir);
					Vector3 fallbackDir;
					if (!(((Vector3)(ref val2)).sqrMagnitude > 0.01f))
					{
						fallbackDir = ((Component)character).transform.forward;
					}
					else
					{
						val2 = Flatten(lookDir);
						fallbackDir = ((Vector3)(ref val2)).normalized;
					}
					if (TryResolveHit(character, hit, fallbackDir, requireInReach, out ledge))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool TryFindInDirection(Character character, Vector3 dir, bool requireInReach, out SwimExitLedge ledge)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(0.35f, character.GetLiquidLevel() - ((Component)character).transform.position.y);
			float[] array = new float[5]
			{
				0.45f,
				0.9f,
				Mathf.Max(0.3f, num - 0.25f),
				num,
				num + 0.25f
			};
			for (int i = 0; i < array.Length; i++)
			{
				if (TryCastAtHeight(character, dir, array[i], requireInReach, out ledge))
				{
					return true;
				}
			}
			ledge = default(SwimExitLedge);
			return false;
		}

		private static bool TryCastAtHeight(Character character, Vector3 dir, float originHeight, bool requireInReach, out SwimExitLedge ledge)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//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_003a: 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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			ledge = default(SwimExitLedge);
			int num = BuildMask();
			float num2 = ModConfig.ReachDistance.Value + 0.55f;
			Vector3 val = ((Component)character).transform.position + Vector3.up * originHeight - dir * 0.55f;
			RaycastHit hit = default(RaycastHit);
			if (Physics.Raycast(val, dir, ref hit, num2, num, (QueryTriggerInteraction)1) && TryResolveHit(character, hit, dir, requireInReach, out ledge))
			{
				return true;
			}
			RaycastHit hit2 = default(RaycastHit);
			if (Physics.SphereCast(val, 0.12f, dir, ref hit2, num2, num, (QueryTriggerInteraction)1) && TryResolveHit(character, hit2, dir, requireInReach, out ledge))
			{
				return true;
			}
			return false;
		}

		private static bool TryResolveHit(Character character, RaycastHit hit, Vector3 fallbackDir, bool requireInReach, out SwimExitLedge ledge)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: 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_0170: Unknown result type (might be due to invalid IL or missing references)
			ledge = default(SwimExitLedge);
			if (ShouldIgnore(character, ((RaycastHit)(ref hit)).collider))
			{
				return false;
			}
			Vector3 val = Flatten(-((RaycastHit)(ref hit)).normal);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Flatten(fallbackDir);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Flatten(((Component)character).transform.forward);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return false;
			}
			((Vector3)(ref val)).Normalize();
			if (((RaycastHit)(ref hit)).normal.y >= 0.45f && TryAcceptStand(character, ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).normal, ((RaycastHit)(ref hit)).collider, ((RaycastHit)(ref hit)).collider, val, requireInReach, out ledge))
			{
				return true;
			}
			int num = BuildMask();
			float num2 = (requireInReach ? SwimExitClimb.GetMaxHeight(character) : 4f);
			float liquidLevel = character.GetLiquidLevel();
			float num3 = Mathf.Max(((RaycastHit)(ref hit)).point.y, liquidLevel) + 0.05f;
			RaycastHit val2 = default(RaycastHit);
			for (int i = 0; i < DownInsets.Length; i++)
			{
				if (Physics.Raycast(new Vector3(((RaycastHit)(ref hit)).point.x, num3 + num2 + 0.2f, ((RaycastHit)(ref hit)).point.z) + val * DownInsets[i], Vector3.down, ref val2, num2 + 1.2f, num, (QueryTriggerInteraction)1) && !ShouldIgnore(character, ((RaycastHit)(ref val2)).collider) && TryAcceptStand(character, ((RaycastHit)(ref val2)).point, ((RaycastHit)(ref val2)).normal, ((RaycastHit)(ref val2)).collider, ((RaycastHit)(ref hit)).collider, val, requireInReach, out ledge))
				{
					return true;
				}
			}
			ModConfig.Log("Probe hit " + ((Object)((RaycastHit)(ref hit)).collider).name + " but found no standable top.");
			return false;
		}

		private static bool TryAcceptStand(Character character, Vector3 point, Vector3 normal, Collider standCollider, Collider wallCollider, Vector3 forward, bool requireInReach, out SwimExitLedge ledge)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_0124: 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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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)
			ledge = default(SwimExitLedge);
			if (normal.y < 0.45f)
			{
				return false;
			}
			if (ShouldIgnore(character, standCollider))
			{
				return false;
			}
			float maxHeight = SwimExitClimb.GetMaxHeight(character);
			float liquidLevel = character.GetLiquidLevel();
			float y = ((Component)character).transform.position.y;
			float num = point.y - liquidLevel;
			bool flag = num <= maxHeight;
			if (requireInReach && !flag)
			{
				ModConfig.Log($"Rejected {((Object)standCollider).name}: {num:F2}m above water (max {maxHeight:F2} at current waterline).");
				return false;
			}
			if (point.y < y + 0.05f)
			{
				return false;
			}
			float num2 = Mathf.Max(0f, character.m_swimDepth - 0.4f);
			if (liquidLevel - point.y > num2)
			{
				ModConfig.Log("Rejected " + ((Object)standCollider).name + ": stand point still below swim depth.");
				return false;
			}
			Vector3 val = Flatten(forward);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Flatten(((Component)character).transform.forward);
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = Vector3.forward;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = point + Vector3.up * 0.05f + val * 0.08f;
			if (!HasCapsuleClearance(character, val2, standCollider, wallCollider))
			{
				if (requireInReach)
				{
					ModConfig.Log("Rejected " + ((Object)standCollider).name + ": capsule does not fit.");
					return false;
				}
				flag = false;
			}
			ledge = new SwimExitLedge(val2, val, flag);
			if (requireInReach)
			{
				ModConfig.Log($"Accepted ledge on {((Object)standCollider).name} at {val2} (above water {num:F2}m, jump max {maxHeight:F2}, inReach={flag}).");
			}
			return true;
		}

		private static bool HasCapsuleClearance(Character character, Vector3 standPoint, Collider standCollider, Collider wallCollider)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			CapsuleCollider component = ((Component)character).GetComponent<CapsuleCollider>();
			float num = (((Object)(object)component != (Object)null) ? (component.radius * 0.8f) : 0.25f);
			Vector3 val = standPoint + Vector3.up * (num + 0.08f);
			Vector3 val2 = standPoint + Vector3.up * (1.05f - num);
			if (val2.y <= val.y)
			{
				val2 = val + Vector3.up * 0.2f;
			}
			int num2 = Physics.OverlapCapsuleNonAlloc(val, val2, num, OverlapBuffer, BuildMask(), (QueryTriggerInteraction)1);
			for (int i = 0; i < num2; i++)
			{
				Collider val3 = OverlapBuffer[i];
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)standCollider) && !((Object)(object)val3 == (Object)(object)wallCollider) && !ShouldIgnore(character, val3) && !(val3.ClosestPoint(val).y < standPoint.y + 0.3f))
				{
					return false;
				}
			}
			return true;
		}

		private static bool ShouldIgnore(Character character, Collider collider)
		{
			if ((Object)(object)collider == (Object)null)
			{
				return true;
			}
			if ((Object)(object)((Component)collider).transform == (Object)(object)((Component)character).transform || ((Component)collider).transform.IsChildOf(((Component)character).transform))
			{
				return true;
			}
			if ((Object)(object)((Component)collider).GetComponentInParent<Character>() == (Object)(object)character)
			{
				return true;
			}
			if ((Object)(object)((Component)collider).GetComponentInParent<WaterVolume>() != (Object)null || (Object)(object)((Component)collider).GetComponentInParent<LiquidSurface>() != (Object)null)
			{
				return true;
			}
			if (!ModConfig.AllowBoats.Value && (Object)(object)((Component)collider).GetComponentInParent<Ship>() != (Object)null)
			{
				return true;
			}
			return false;
		}

		private static int BuildMask()
		{
			int groundRayMask = CharacterAccess.GetGroundRayMask();
			groundRayMask |= LayerMask.GetMask(new string[8] { "Default", "static_solid", "Default_small", "piece", "terrain", "blocker", "vehicle", "viewblock" });
			if (!ModConfig.AllowBoats.Value)
			{
				int num = LayerMask.NameToLayer("vehicle");
				if (num >= 0)
				{
					groundRayMask &= ~(1 << num);
				}
			}
			return groundRayMask;
		}

		private static Vector3 Flatten(Vector3 value)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			value.y = 0f;
			return value;
		}
	}
}
namespace GetOutOfTheWater.Patches
{
	[HarmonyPatch(typeof(Character), "Jump")]
	internal static class CharacterJumpPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(Character __instance)
		{
			if (!ModConfig.Enabled.Value)
			{
				return true;
			}
			if (SwimExitMantle.TryBegin(__instance))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateMotion")]
	internal static class CharacterUpdateMotionPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(Character __instance, float dt)
		{
			if (!ModConfig.Enabled.Value || !SwimExitMantle.IsActive(__instance))
			{
				return true;
			}
			if (__instance.IsDead())
			{
				SwimExitMantle.Cancel(__instance);
				return true;
			}
			SwimExitMantle.Tick(__instance, dt);
			return false;
		}
	}
}