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 SwimTimer = AccessTools.FieldRefAccess("m_swimTimer"); private static readonly FieldRef LastGroundTouch = AccessTools.FieldRefAccess("m_lastGroundTouch"); private static readonly FieldRef MaxAirAltitude = AccessTools.FieldRefAccess("m_maxAirAltitude"); private static readonly FieldRef CurrentVel = AccessTools.FieldRefAccess("m_currentVel"); private static readonly FieldRef LookDir = AccessTools.FieldRefAccess("m_lookDir"); private static readonly FieldRef GroundRayMask = AccessTools.StaticFieldRefAccess(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 Enabled; internal static ConfigEntry DebugLogging; internal static ConfigEntry BaseClimbHeight; internal static ConfigEntry JumpClimbBonus; internal static ConfigEntry ReachDistance; internal static ConfigEntry MantleDuration; internal static ConfigEntry StaminaCost; internal static ConfigEntry AllowBoats; internal static ConfigEntry ShowLipLine; internal static ConfigEntry SurfaceMaxSubmersion; internal static ConfigEntry CooldownSeconds; internal static void Bind(ConfigFile config) { Enabled = config.Bind("General", "Enabled", true, "Enable swim-exit on Jump. When false, no Harmony patches run."); DebugLogging = config.Bind("General", "DebugLogging", false, "Log ledge probes and mantle starts to BepInEx."); BaseClimbHeight = config.Bind("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("Mantle", "JumpClimbBonus", 1f, "Extra meters of pull-up height at Jump skill 100. Scales linearly with Jump."); ReachDistance = config.Bind("Mantle", "ReachDistance", 1.5f, "How far ahead to search for a wall or ledge while swimming."); MantleDuration = config.Bind("Mantle", "MantleDuration", 0.2f, "Seconds to lerp onto the ledge. Keep short so swim physics cannot pull you back."); StaminaCost = config.Bind("Mantle", "StaminaCost", -1f, "Stamina spent on a successful pull-up. Negative uses the vanilla jump stamina cost."); AllowBoats = config.Bind("Mantle", "AllowBoats", true, "Allow pulling onto ships and other vehicle colliders from the water."); ShowLipLine = config.Bind("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("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("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(); ((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(); 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(); 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(); 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() == (Object)(object)character) { return true; } if ((Object)(object)((Component)collider).GetComponentInParent() != (Object)null || (Object)(object)((Component)collider).GetComponentInParent() != (Object)null) { return true; } if (!ModConfig.AllowBoats.Value && (Object)(object)((Component)collider).GetComponentInParent() != (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; } } }