Decompiled source of ValynDiving v0.2.7

plugins/ValynDiving.dll

Decompiled 5 days ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[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("ValynDiving")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.7.0")]
[assembly: AssemblyInformationalVersion("0.2.7")]
[assembly: AssemblyProduct("ValynDiving")]
[assembly: AssemblyTitle("ValynDiving")]
[assembly: AssemblyVersion("0.2.7.0")]
namespace ValynMods.Diving;

internal sealed class BreathHud
{
	private static readonly FieldInfo StaminaRoot = AccessTools.Field(typeof(Hud), "m_staminaBar2Root");

	private static readonly FieldInfo StaminaText = AccessTools.Field(typeof(Hud), "m_staminaText");

	private static readonly Type ImageType = Type.GetType("UnityEngine.UI.Image, UnityEngine.UI");

	private GameObject container;

	private GameObject label;

	private RectTransform panel;

	private RectTransform staminaRoot;

	private RectTransform background;

	private RectTransform fill;

	private Component labelComponent;

	private PropertyInfo labelText;

	private Hud owner;

	internal bool Visible { get; private set; }

	internal void Show(float remaining, float maximum)
	{
		//IL_005b: 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)
		Hud instance = Hud.instance;
		if ((Object)(object)instance == (Object)null)
		{
			Hide();
			return;
		}
		if ((Object)(object)container == (Object)null || (Object)(object)owner != (Object)(object)instance)
		{
			Create(instance);
		}
		if ((Object)(object)container == (Object)null)
		{
			Visible = false;
			return;
		}
		AlignToStamina();
		float x = panel.sizeDelta.x;
		fill.sizeDelta = new Vector2(x * Mathf.Clamp01(remaining / Mathf.Max(1f, maximum)), 15f);
		if ((Object)(object)label != (Object)null && labelText != null)
		{
			labelText.SetValue(labelComponent, "BREATH  " + Mathf.CeilToInt(remaining) + " / " + Mathf.CeilToInt(maximum) + " s");
		}
		container.SetActive(true);
		Visible = container.activeInHierarchy;
	}

	private void Create(Hud hud)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Expected O, but got Unknown
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Expected O, but got Unknown
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: 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_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: 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_01e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_021e: Unknown result type (might be due to invalid IL or missing references)
		Destroy();
		owner = hud;
		ref RectTransform reference = ref staminaRoot;
		object? obj = StaminaRoot?.GetValue(hud);
		reference = (RectTransform)((obj is RectTransform) ? obj : null);
		if ((Object)(object)staminaRoot == (Object)null || (Object)(object)((Transform)staminaRoot).parent == (Object)null || ImageType == null)
		{
			return;
		}
		container = new GameObject("Valyn Breath HUD", new Type[1] { typeof(RectTransform) });
		panel = (RectTransform)container.transform;
		((Transform)panel).SetParent(((Transform)staminaRoot).parent, false);
		background = MakeImage("Breath background", new Color(0.02f, 0.08f, 0.16f, 0.9f));
		fill = MakeImage("Breath fill", new Color(0.05f, 0.55f, 1f, 1f));
		object? obj2 = StaminaText?.GetValue(hud);
		Component val = (Component)((obj2 is Component) ? obj2 : null);
		if ((Object)(object)val != (Object)null)
		{
			label = Object.Instantiate<GameObject>(val.gameObject, (Transform)(object)panel, false);
			((Object)label).name = "Breath seconds";
			labelComponent = label.GetComponent(((object)val).GetType());
			labelText = ((object)labelComponent)?.GetType().GetProperty("text");
			Transform transform = label.transform;
			RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val2 != (Object)null)
			{
				Vector2 val3 = default(Vector2);
				((Vector2)(ref val3))..ctor(0.5f, 0.5f);
				val2.pivot = val3;
				Vector2 anchorMin = (val2.anchorMax = val3);
				val2.anchorMin = anchorMin;
				val2.anchoredPosition = Vector2.zero;
				val2.sizeDelta = new Vector2(300f, 24f);
				((Transform)val2).localScale = Vector3.one;
			}
			Type obj3 = ((object)labelComponent)?.GetType();
			obj3?.GetProperty("color")?.SetValue(labelComponent, Color.white);
			obj3?.GetProperty("fontSize")?.SetValue(labelComponent, 14f);
			obj3?.GetProperty("raycastTarget")?.SetValue(labelComponent, false);
			label.SetActive(true);
		}
		AlignToStamina();
		container.SetActive(false);
	}

	private RectTransform MakeImage(string name, Color color)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		//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_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: 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_004d: 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_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_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: 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_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Expected O, but got Unknown
		//IL_00b1: Expected O, but got Unknown
		GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
		RectTransform val2 = (RectTransform)val.transform;
		((Transform)val2).SetParent((Transform)(object)panel, false);
		Vector2 val3 = default(Vector2);
		((Vector2)(ref val3))..ctor(0f, 0.5f);
		val2.pivot = val3;
		Vector2 anchorMin = (val2.anchorMax = val3);
		val2.anchorMin = anchorMin;
		val2.anchoredPosition = Vector2.zero;
		((Transform)val2).localScale = Vector3.one;
		Component obj = val.AddComponent(ImageType);
		ImageType.GetProperty("color")?.SetValue(obj, color);
		PropertyInfo? property = ImageType.GetProperty("raycastTarget");
		if ((object)property != null)
		{
			property.SetValue(obj, false);
			return val2;
		}
		return val2;
	}

	private void AlignToStamina()
	{
		//IL_0029: 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_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: 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_00a5: 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)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)panel == (Object)null) && !((Object)(object)staminaRoot == (Object)null))
		{
			panel.anchorMin = staminaRoot.anchorMin;
			panel.anchorMax = staminaRoot.anchorMax;
			panel.pivot = staminaRoot.pivot;
			panel.anchoredPosition = staminaRoot.anchoredPosition + new Vector2(0f, -32f);
			((Transform)panel).localScale = ((Transform)staminaRoot).localScale;
			Rect rect = staminaRoot.rect;
			float num = Mathf.Clamp(((Rect)(ref rect)).width, 160f, 320f);
			panel.sizeDelta = new Vector2(num, 15f);
			background.sizeDelta = new Vector2(num, 15f);
		}
	}

	internal void Hide()
	{
		if ((Object)(object)container != (Object)null)
		{
			container.SetActive(false);
		}
		Visible = false;
	}

	internal void Destroy()
	{
		if ((Object)(object)container != (Object)null)
		{
			Object.Destroy((Object)(object)container);
		}
		container = (label = null);
		panel = (staminaRoot = (background = (fill = null)));
		labelComponent = null;
		labelText = null;
		owner = null;
		Visible = false;
	}
}
[BepInPlugin("valyn.mods.diving", "Valyn Diving", "0.2.7")]
public sealed class DivingPlugin : BaseUnityPlugin
{
	internal static ConfigEntry<float> StaminaMultiplier;

	internal static ConfigEntry<float> BreathSeconds;

	internal static ConfigEntry<float> DescentSpeed;

	internal static ConfigEntry<float> AscentSpeed;

	internal static ConfigEntry<float> DrowningDamage;

	internal static ConfigEntry<bool> BlockWaterRegen;

	internal static ConfigEntry<bool> AllowWadingRegen;

	internal static ConfigEntry<float> BreathSkillBonus;

	internal static ConfigEntry<float> FastSwimMultiplier;

	internal static ConfigEntry<bool> AllowUnderwaterCamera;

	internal static ConfigEntry<bool> EnableSeabedMovement;

	internal static ConfigEntry<float> SeabedSpeedMultiplier;

	internal static ConfigEntry<bool> SteepSeabedAssist;

	private readonly BreathHud breathHud = new BreathHud();

	private bool hudConfirmed;

	private bool hudWarning;

	private float hudMissingTime;

	internal static ManualLogSource ModLog;

	private Harmony harmony;

	private void LateUpdate()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || !DiveState.SwimmingOrSubmerged(localPlayer))
		{
			breathHud.Hide();
			return;
		}
		breathHud.Show(DiveState.Breath, DiveState.Cap(localPlayer));
		if (breathHud.Visible && !hudConfirmed)
		{
			hudConfirmed = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Breath HUD elements active");
		}
		if (!breathHud.Visible && !hudWarning)
		{
			hudMissingTime += Time.deltaTime;
			if (hudMissingTime > 2f)
			{
				hudWarning = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Breath HUD could not attach to the game's stamina HUD elements");
			}
		}
	}

	private void Awake()
	{
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Expected O, but got Unknown
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Expected O, but got Unknown
		ModLog = ((BaseUnityPlugin)this).Logger;
		StaminaMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Stamina", "Swim drain multiplier", 0.85f, "0.85 uses 15% less stamina while swimming.");
		BreathSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Breath", "Underwater seconds", 30f, "Time below the waterline before drowning damage begins.");
		DescentSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "Descent speed", 2.5f, "Vertical speed while holding the game's Crouch action underwater, including its controller binding.");
		AscentSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "Ascent speed", 3f, "Vertical speed while holding the game's Jump action underwater, including its controller binding.");
		DrowningDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Breath", "Drowning damage per second", 5f, "Damage while breath is depleted.");
		BlockWaterRegen = ((BaseUnityPlugin)this).Config.Bind<bool>("Stamina", "No regeneration while in water", true, "Prevents stamina regeneration while swimming or submerged. See Allow regeneration while wading.");
		AllowWadingRegen = ((BaseUnityPlugin)this).Config.Bind<bool>("Stamina", "Allow regeneration while wading", true, "Allows stamina recovery when walking in shallow water with your head above the surface.");
		BreathSkillBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Breath", "Swim skill breath bonus", 1f, "At 100 Swim skill, 1.0 doubles the base breath duration.");
		FastSwimMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "Shift swim speed multiplier", 1.25f, "Hold the game's Run action to swim faster; stamina drain scales with speed.");
		AllowUnderwaterCamera = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "Allow underwater camera", true, "Allows the third-person camera below the water surface while swimming or diving. Set false for the game's normal surface clamp.");
		EnableSeabedMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "Allow movement on seabed", true, "Allow slower horizontal movement when your head is underwater and you touch the ground.");
		SeabedSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "Seabed speed multiplier", 0.55f, new ConfigDescription("Fraction of normal swim speed while moving on the seabed. 0.2-0.95.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 0.95f), Array.Empty<object>()));
		SteepSeabedAssist = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "Steep seabed swim assist", true, "When movement stalls against a steep underwater slope, rise into swimming. Does not climb vertical walls or lift you out of the water.");
		harmony = new Harmony("valyn.mods.diving");
		harmony.PatchAll(typeof(DivingPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Valyn Diving loaded");
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		breathHud.Destroy();
	}
}
[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
internal static class UnderwaterCameraPatch
{
	private static readonly FieldInfo MinWaterDistance = AccessTools.Field(typeof(GameCamera), "m_minWaterDistance");

	private static void Prefix(GameCamera __instance, out float __state)
	{
		__state = float.NaN;
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null) && !(MinWaterDistance == null) && DivingPlugin.AllowUnderwaterCamera.Value && DiveState.SwimmingOrSubmerged(localPlayer) && DiveState.Wet(localPlayer))
		{
			__state = (float)MinWaterDistance.GetValue(__instance);
			MinWaterDistance.SetValue(__instance, -10000f);
		}
	}

	private static void Postfix(GameCamera __instance, float __state)
	{
		if (!float.IsNaN(__state))
		{
			MinWaterDistance.SetValue(__instance, __state);
		}
	}
}
internal static class DiveState
{
	internal static float Breath;

	internal static float DamageClock;

	internal static float SkillClock;

	internal static bool Diving;

	internal static Player Current;

	private static bool seabedLogged;

	private static bool slopeAssistLogged;

	private static bool hasSeabedPosition;

	private static Vector3 lastSeabedPosition;

	private static float stalledSlopeTime;

	internal static readonly FieldInfo Body = AccessTools.Field(typeof(Character), "m_body");

	internal static readonly FieldInfo Velocity = AccessTools.Field(typeof(Character), "m_currentVel");

	internal static readonly FieldInfo DrainMin = AccessTools.Field(typeof(Player), "m_swimStaminaDrainMinSkill");

	internal static readonly FieldInfo SwimSpeed = AccessTools.Field(typeof(Character), "m_swimSpeed");

	internal static readonly FieldInfo DrainMax = AccessTools.Field(typeof(Player), "m_swimStaminaDrainMaxSkill");

	private static readonly Func<string, bool> GameButton = ResolveGameButton();

	private static readonly Type InputType = Type.GetType("UnityEngine.Input, UnityEngine.InputLegacyModule");

	private static readonly MethodInfo GetKey = InputType?.GetMethod("GetKey", new Type[1] { typeof(KeyCode) });

	internal static readonly PropertyInfo BodyVelocity = Body.FieldType.GetProperty("velocity");

	internal static bool Fast => Action("Run", "JoyRun", (KeyCode)304);

	private static Func<string, bool> ResolveGameButton()
	{
		try
		{
			MethodInfo methodInfo = Type.GetType("ZInput, assembly_utils")?.GetMethod("GetButton", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
			if (methodInfo != null)
			{
				return (Func<string, bool>)Delegate.CreateDelegate(typeof(Func<string, bool>), methodInfo);
			}
		}
		catch (Exception ex)
		{
			Debug.LogWarning((object)("Valyn Diving input binding: " + ex));
		}
		Debug.LogWarning((object)"Valyn Diving could not find Valheim's mapped input; keyboard fallback active.");
		return null;
	}

	internal static bool Action(string keyboard, string gamepad, KeyCode fallback)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		if (GameButton == null)
		{
			if (GetKey != null)
			{
				return (bool)GetKey.Invoke(null, new object[1] { fallback });
			}
			return false;
		}
		if (!GameButton(keyboard))
		{
			return GameButton(gamepad);
		}
		return true;
	}

	internal static bool Local(Player player)
	{
		if ((Object)(object)player != (Object)null && ((Character)player).IsOwner())
		{
			return (Object)(object)player == (Object)(object)Player.m_localPlayer;
		}
		return false;
	}

	internal static float Cap(Player player)
	{
		return Mathf.Max(1f, DivingPlugin.BreathSeconds.Value * (1f + Mathf.Max(0f, DivingPlugin.BreathSkillBonus.Value) * ((Character)player).GetSkillFactor((SkillType)103)));
	}

	internal static bool Wet(Player player)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		if (!((Character)player).InWater())
		{
			return ((Character)player).GetLiquidLevel() > ((Component)player).transform.position.y + 0.3f;
		}
		return true;
	}

	internal static bool Underwater(Player player)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		return ((Character)player).GetHeadPoint().y < ((Character)player).GetLiquidLevel() - 0.12f;
	}

	internal static bool SwimmingOrSubmerged(Player player)
	{
		if (!((Character)player).IsSwimming() && !Underwater(player))
		{
			return Diving;
		}
		return true;
	}

	internal static bool BlockRegen(Player player)
	{
		if (Wet(player))
		{
			if (DivingPlugin.AllowWadingRegen.Value)
			{
				return SwimmingOrSubmerged(player);
			}
			return true;
		}
		return false;
	}

	internal static void Reset(Player player)
	{
		Current = player;
		Breath = Cap(player);
		DamageClock = 0f;
		SkillClock = 0f;
		Diving = false;
		hasSeabedPosition = false;
		stalledSlopeTime = 0f;
	}

	internal static void MoveOnSeabed(Player player, float dt)
	{
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: 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_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0320: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
		if (!DivingPlugin.EnableSeabedMovement.Value || !Local(player) || !((Character)player).InWater() || !Underwater(player) || !((Character)player).IsOnGround() || !((Character)player).CanMove() || ((Character)player).IsDead() || ((Character)player).IsAttached() || ((Character)player).IsTeleporting())
		{
			hasSeabedPosition = false;
			stalledSlopeTime = 0f;
			return;
		}
		Vector3 moveDir = ((Character)player).GetMoveDir();
		moveDir.y = 0f;
		if (((Vector3)(ref moveDir)).sqrMagnitude < 0.001f)
		{
			hasSeabedPosition = false;
			stalledSlopeTime = 0f;
			return;
		}
		if (((Vector3)(ref moveDir)).sqrMagnitude > 1f)
		{
			((Vector3)(ref moveDir)).Normalize();
		}
		if (!seabedLogged)
		{
			seabedLogged = true;
			Debug.Log((object)("VALYN DIVING: seabed movement engaged, swimming=" + ((Character)player).IsSwimming()));
		}
		object value = Body.GetValue(player);
		if (value == null)
		{
			return;
		}
		Vector3 val = (Vector3)BodyVelocity.GetValue(value);
		float num = (float)SwimSpeed.GetValue(player) * DivingPlugin.SeabedSpeedMultiplier.Value * (Fast ? Mathf.Max(1f, DivingPlugin.FastSwimMultiplier.Value) : 1f);
		Vector3 position = ((Component)player).transform.position;
		Vector3 lastGroundNormal = ((Character)player).GetLastGroundNormal();
		Vector3 val2 = default(Vector3);
		((Vector3)(ref val2))..ctor(0f - lastGroundNormal.x, 0f, 0f - lastGroundNormal.z);
		if (DivingPlugin.SteepSeabedAssist.Value && lastGroundNormal.y > 0.15f && lastGroundNormal.y < 0.79f && ((Vector3)(ref val2)).sqrMagnitude > 0.01f && Vector3.Dot(moveDir, ((Vector3)(ref val2)).normalized) > 0.45f && hasSeabedPosition && dt > 0f)
		{
			Vector3 val3 = position - lastSeabedPosition;
			val3.y = 0f;
			if (((Vector3)(ref val3)).magnitude < num * dt * 0.3f)
			{
				stalledSlopeTime += dt;
			}
			else
			{
				stalledSlopeTime = 0f;
			}
		}
		else
		{
			stalledSlopeTime = 0f;
		}
		lastSeabedPosition = position;
		hasSeabedPosition = true;
		float num2 = Mathf.Clamp01(dt * 10f);
		val.x = Mathf.Lerp(val.x, moveDir.x * num, num2);
		val.z = Mathf.Lerp(val.z, moveDir.z * num, num2);
		if (stalledSlopeTime > 0.22f && ((Character)player).GetLiquidLevel() - ((Character)player).GetHeadPoint().y > 0.5f)
		{
			val.y = Mathf.Max(val.y, Mathf.Max(0f, DivingPlugin.AscentSpeed.Value) * 0.7f);
			if (!slopeAssistLogged)
			{
				slopeAssistLogged = true;
				Debug.Log((object)"VALYN DIVING: steep seabed swim assist engaged");
			}
		}
		if (Diving && Action("Jump", "JoyJump", (KeyCode)32))
		{
			val.y = Mathf.Max(val.y, Mathf.Max(0f, DivingPlugin.AscentSpeed.Value));
		}
		BodyVelocity.SetValue(value, val);
		Velocity.SetValue(player, val);
	}
}
[HarmonyPatch(typeof(Character), "UpdateSwimming")]
internal static class SwimmingMovementPatch
{
	private static void Prefix(Character __instance, out float __state)
	{
		__state = 0f;
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if (DiveState.Local(val) && DiveState.Fast)
		{
			__state = (float)DiveState.SwimSpeed.GetValue(val);
			DiveState.SwimSpeed.SetValue(val, __state * Mathf.Max(1f, DivingPlugin.FastSwimMultiplier.Value));
		}
	}

	private static void Postfix(Character __instance, float dt, float __state)
	{
		if (__state > 0f)
		{
			DiveState.SwimSpeed.SetValue(__instance, __state);
		}
		ApplyDiving(__instance, dt);
		DiveState.MoveOnSeabed((Player)(object)((__instance is Player) ? __instance : null), dt);
	}

	private static void ApplyDiving(Character __instance, float dt)
	{
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if (!DiveState.Local(val) || ((Character)val).IsDead() || ((Character)val).IsAttached() || ((Character)val).IsTeleporting())
		{
			return;
		}
		if (!((Character)val).InWater())
		{
			DiveState.Diving = false;
			return;
		}
		bool flag = DiveState.Action("Crouch", "JoyCrouch", (KeyCode)306);
		bool flag2 = DiveState.Action("Jump", "JoyJump", (KeyCode)32);
		float num = ((Character)val).GetLiquidLevel() - ((Component)val).transform.position.y;
		if (!DiveState.Diving && flag && (((Character)val).IsSwimming() || DiveState.Underwater(val)))
		{
			DiveState.Diving = true;
		}
		if (!DiveState.Diving)
		{
			return;
		}
		if (num < 0.35f && !flag && !DiveState.Underwater(val))
		{
			DiveState.Diving = false;
			return;
		}
		float num2 = ((!((Character)val).IsOnGround() || !DiveState.Underwater(val)) ? (flag ? (0f - Mathf.Max(0f, DivingPlugin.DescentSpeed.Value)) : (flag2 ? Mathf.Max(0f, DivingPlugin.AscentSpeed.Value) : 0f)) : (flag2 ? Mathf.Max(0f, DivingPlugin.AscentSpeed.Value) : 0f));
		if (num < 0.5f && num2 > 0f)
		{
			DiveState.Diving = false;
			return;
		}
		object value = DiveState.Body.GetValue(val);
		if (value != null)
		{
			Vector3 val2 = (Vector3)DiveState.BodyVelocity.GetValue(value);
			val2.y = num2;
			DiveState.BodyVelocity.SetValue(value, val2);
			DiveState.Velocity.SetValue(val, val2);
		}
	}
}
[HarmonyPatch(typeof(Character), "UpdateWalking")]
internal static class SeabedWalkingPatch
{
	private static void Postfix(Character __instance, float __0)
	{
		DiveState.MoveOnSeabed((Player)(object)((__instance is Player) ? __instance : null), __0);
	}
}
[HarmonyPatch(typeof(Player), "OnSwimming")]
internal static class SwimStaminaPatch
{
	private static bool Prefix(Player __instance, Vector3 targetVel, float dt, out float[] __state)
	{
		__state = null;
		if (!DiveState.Local(__instance))
		{
			return true;
		}
		if ((Object)(object)DiveState.Current != (Object)(object)__instance)
		{
			DiveState.Reset(__instance);
		}
		float num = (float)DiveState.DrainMin.GetValue(__instance);
		float num2 = (float)DiveState.DrainMax.GetValue(__instance);
		float num3 = Mathf.Clamp(DivingPlugin.StaminaMultiplier.Value, 0f, 1f) * (DiveState.Fast ? Mathf.Max(1f, DivingPlugin.FastSwimMultiplier.Value) : 1f);
		if (((Character)__instance).InWater() && DiveState.Underwater(__instance))
		{
			float skillFactor = ((Character)__instance).GetSkills().GetSkillFactor((SkillType)103);
			float num4 = Mathf.Lerp(num, num2, skillFactor);
			if (((Vector3)(ref targetVel)).sqrMagnitude > 0.01f)
			{
				((Character)__instance).UseStamina(dt * Mathf.Max(0f, num4) * num3);
				DiveState.SkillClock += dt;
				if (DiveState.SkillClock >= 1f)
				{
					DiveState.SkillClock -= 1f;
					((Character)__instance).RaiseSkill((SkillType)103, 1f);
				}
			}
			return false;
		}
		__state = new float[2] { num, num2 };
		DiveState.DrainMin.SetValue(__instance, num * num3);
		DiveState.DrainMax.SetValue(__instance, num2 * num3);
		return true;
	}

	private static void Postfix(Player __instance, float dt, float[] __state)
	{
		if (DiveState.Local(__instance) && __state != null)
		{
			DiveState.DrainMin.SetValue(__instance, __state[0]);
			DiveState.DrainMax.SetValue(__instance, __state[1]);
		}
	}
}
[HarmonyPatch(typeof(Player), "Update")]
internal static class BreathRecoveryPatch
{
	private static void Postfix(Player __instance)
	{
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Expected O, but got Unknown
		if (!DiveState.Local(__instance))
		{
			return;
		}
		if ((Object)(object)DiveState.Current != (Object)(object)__instance)
		{
			DiveState.Reset(__instance);
		}
		if (((Character)__instance).IsDead())
		{
			return;
		}
		if (!DiveState.Underwater(__instance))
		{
			DiveState.Breath = DiveState.Cap(__instance);
			DiveState.DamageClock = 0f;
			if (!((Character)__instance).InWater())
			{
				DiveState.Diving = false;
			}
			return;
		}
		float deltaTime = Time.deltaTime;
		float num = DiveState.Cap(__instance);
		DiveState.Breath = Mathf.Max(0f, Mathf.Min(num, DiveState.Breath) - deltaTime);
		if (!(DiveState.Breath > 0f))
		{
			DiveState.DamageClock += deltaTime;
			if (!(DiveState.DamageClock < 1f))
			{
				DiveState.DamageClock -= 1f;
				HitData val = new HitData();
				val.m_damage.m_damage = Mathf.Max(0f, DivingPlugin.DrowningDamage.Value);
				((Character)__instance).Damage(val);
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
internal static class WaterStaminaRegenPatch
{
	private static readonly FieldInfo Stamina = AccessTools.Field(typeof(Player), "m_stamina");

	private static bool loggedBlock;

	private static void Prefix(Player __instance, out float __state)
	{
		__state = ((DiveState.Local(__instance) && DivingPlugin.BlockWaterRegen.Value && DiveState.BlockRegen(__instance)) ? __instance.GetStamina() : (-1f));
	}

	private static void Postfix(Player __instance, float __state)
	{
		if (__state < 0f || !DiveState.BlockRegen(__instance) || !(__instance.GetStamina() > __state))
		{
			return;
		}
		Stamina.SetValue(__instance, __state);
		if (!loggedBlock)
		{
			loggedBlock = true;
			ManualLogSource modLog = DivingPlugin.ModLog;
			if (modLog != null)
			{
				modLog.LogInfo((object)"Blocked stamina regeneration while in water");
			}
		}
	}
}