using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
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.InputSystem;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BetterSwimming")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Azumatt")]
[assembly: AssemblyProduct("BetterSwimming")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[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;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class ExtensionMarkerAttribute : Attribute
{
public ExtensionMarkerAttribute(string name)
{
}
}
}
namespace BetterSwimming
{
[HarmonyPatch(typeof(PlayerMovement), "Move")]
internal static class PlayerMovementMovePatch
{
private static PlayerInput? _input;
private static InputAction? _jump;
private static float _nextStroke;
private static float _swimVel;
private static bool _wasSwimming;
internal static void RaiseSwimVel(float velY)
{
_swimVel = Mathf.Max(_swimVel, velY);
_wasSwimming = true;
}
private static void Postfix(PlayerMovement __instance)
{
//IL_0030: 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_00cb: 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_0121: 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)
if (!BetterSwimmingPlugin.IsEnabled || !BetterSwimmingPlugin.IsLocal(__instance))
{
return;
}
if (!__instance._isSwimming || __instance.OnBoat)
{
_wasSwimming = false;
return;
}
Rigidbody rig = __instance._rig;
float num = WaterManager.GetWaterHeight(rig.position) - rig.position.y;
bool flag = BetterSwimmingPlugin.HoldToSwim.Value.IsOn() && JumpHeld();
float num2;
if (flag)
{
num2 = BetterSwimmingPlugin.SwimUpSpeed.Value;
}
else if (__instance._crouchInput)
{
num2 = 0f - BetterSwimmingPlugin.DiveSpeed.Value;
}
else
{
float num3 = num - BetterSwimmingPlugin.FloatDepth.Value;
num2 = ((num3 > 0f) ? Mathf.Min(num3 * 2f, BetterSwimmingPlugin.BuoyancySpeed.Value) : (0f - BetterSwimmingPlugin.SinkSpeed.Value));
}
if (!_wasSwimming)
{
_swimVel = Mathf.Max(rig.linearVelocity.y, -10f);
_wasSwimming = true;
}
_swimVel = Mathf.MoveTowards(_swimVel, num2, BetterSwimmingPlugin.SwimAccel.Value * Time.fixedDeltaTime);
if (!__instance.Grounded || !(num2 <= 0f))
{
Vector3 linearVelocity = rig.linearVelocity;
linearVelocity.y = _swimVel;
rig.linearVelocity = linearVelocity;
StrokeSound(flag);
}
}
private static bool JumpHeld()
{
PlayerInput input = GameInfo.Input;
if (!Object.op_Implicit((Object)(object)input))
{
return false;
}
if ((Object)(object)_input == (Object)(object)input && _jump != null)
{
return _jump.IsPressed();
}
_input = input;
_jump = input.actions["PlayerJump"];
return _jump.IsPressed();
}
private static void StrokeSound(bool swimmingUp)
{
if (!swimmingUp)
{
_nextStroke = 0f;
}
else if (!(Time.time < _nextStroke))
{
_nextStroke = Time.time + BetterSwimmingPlugin.StrokeSoundInterval.Value;
AudioManager.PlayRandomGlobalClip(GameInfo.WaterStepSound, 1, GameInfo.StepSoundCount, true, 0.2f, 0.1f);
}
}
}
[HarmonyPatch(typeof(PlayerMovement), "Jump")]
internal static class PlayerMovementJumpPatch
{
private static bool Prefix(PlayerMovement __instance)
{
//IL_003c: 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_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
if (!BetterSwimmingPlugin.IsEnabled)
{
return true;
}
if (!__instance._isSwimming || __instance.Grounded)
{
return true;
}
if (!BetterSwimmingPlugin.IsLocal(__instance))
{
return true;
}
if (BetterSwimmingPlugin.HoldToSwim.Value.IsOn())
{
Vector3 linearVelocity = __instance._rig.linearVelocity;
linearVelocity.y = Mathf.Max(linearVelocity.y, BetterSwimmingPlugin.StrokeForce.Value);
__instance._rig.linearVelocity = linearVelocity;
return false;
}
if (BetterSwimmingPlugin.UnlimitedStrokes.Value.IsOn())
{
__instance._swimJumpCount = 0;
}
return true;
}
private static void Postfix(PlayerMovement __instance)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
if (BetterSwimmingPlugin.IsEnabled && BetterSwimmingPlugin.IsLocal(__instance) && __instance._isSwimming)
{
PlayerMovementMovePatch.RaiseSwimVel(__instance._rig.linearVelocity.y);
}
}
}
[HarmonyPatch(typeof(PlayerMovement), "UpdateMoveSpeed")]
internal static class PlayerMovementUpdateMoveSpeedPatch
{
private static void Postfix(PlayerMovement __instance)
{
if (BetterSwimmingPlugin.IsEnabled && __instance._isSwimming && BetterSwimmingPlugin.IsLocal(__instance))
{
__instance._curMoveSpeed *= BetterSwimmingPlugin.SwimSpeedMulti.Value;
}
}
}
[HarmonyPatch(typeof(PlayerMovement), "UnderWaterCheck")]
internal static class PlayerMovementUnderWaterCheckPatch
{
private static void Prefix(PlayerMovement __instance)
{
if (BetterSwimmingPlugin.IsEnabled && BetterSwimmingPlugin.IsLocal(__instance))
{
__instance._damageFromWater = BetterSwimmingPlugin.UnderwaterDamage.Value;
__instance._underwaterDamageDelay = BetterSwimmingPlugin.UnderwaterDamageDelay.Value;
}
}
private static void Postfix(PlayerMovement __instance)
{
//IL_002d: 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_0034: 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)
if (BetterSwimmingPlugin.IsEnabled && BetterSwimmingPlugin.IsLocal(__instance) && !BetterSwimmingPlugin.WaveAccurate.Value.IsOff())
{
Vector3 position = __instance._player.Transform.position;
__instance._isSwimming = position.y <= WaterManager.GetWaterHeight(position);
}
}
}
[BepInPlugin("Azumatt.BetterSwimming", "BetterSwimming", "1.0.0")]
public class BetterSwimmingPlugin : BaseUnityPlugin
{
public enum Toggle
{
On = 1,
Off = 0
}
internal const string ModName = "BetterSwimming";
internal const string ModVersion = "1.0.0";
internal const string Author = "Azumatt";
private const string ModGUID = "Azumatt.BetterSwimming";
private static string ConfigFileName = "Azumatt.BetterSwimming.cfg";
private static string ConfigFileFullPath;
internal static string ConnectionError;
private readonly Harmony _harmony = new Harmony("Azumatt.BetterSwimming");
public static readonly ManualLogSource BetterSwimmingLogger;
internal static ConfigEntry<Toggle> ModEnabled;
internal static ConfigEntry<Toggle> HoldToSwim;
internal static ConfigEntry<float> SwimUpSpeed;
internal static ConfigEntry<float> DiveSpeed;
internal static ConfigEntry<float> SwimAccel;
internal static ConfigEntry<float> SwimSpeedMulti;
internal static ConfigEntry<float> FloatDepth;
internal static ConfigEntry<float> BuoyancySpeed;
internal static ConfigEntry<float> SinkSpeed;
internal static ConfigEntry<Toggle> WaveAccurate;
internal static ConfigEntry<Toggle> UnlimitedStrokes;
internal static ConfigEntry<float> StrokeForce;
internal static ConfigEntry<float> StrokeSoundInterval;
internal static ConfigEntry<int> UnderwaterDamage;
internal static ConfigEntry<float> UnderwaterDamageDelay;
internal static bool IsEnabled
{
get
{
ConfigEntry<Toggle> modEnabled = ModEnabled;
if (modEnabled != null)
{
return modEnabled.Value == Toggle.On;
}
return false;
}
}
public void Awake()
{
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Expected O, but got Unknown
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Expected O, but got Unknown
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Expected O, but got Unknown
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Expected O, but got Unknown
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Expected O, but got Unknown
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_0199: Expected O, but got Unknown
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Expected O, but got Unknown
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
//IL_023f: Expected O, but got Unknown
//IL_026d: Unknown result type (might be due to invalid IL or missing references)
//IL_0277: Expected O, but got Unknown
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
//IL_02a5: Expected O, but got Unknown
//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
//IL_02dd: Expected O, but got Unknown
bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
ModEnabled = config("1 - General", "Enabled", Toggle.On, "Turn the whole mod off without unloading it.");
HoldToSwim = config("2 - Swimming", "Hold To Swim Up", Toggle.On, "Hold jump to rise instead of mashing it. Off falls back to vanilla strokes.");
SwimUpSpeed = config("2 - Swimming", "Swim Up Speed", 3.5f, new ConfigDescription("Units per second you climb while holding jump.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>()));
DiveSpeed = config("2 - Swimming", "Dive Speed", 3f, new ConfigDescription("Units per second you go down while holding crouch. Watch the drowning timer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f), Array.Empty<object>()));
SwimAccel = config("2 - Swimming", "Swim Acceleration", 25f, new ConfigDescription("How hard vertical speed chases its target. Has to beat the game's extra gravity, so don't go tiny.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
SwimSpeedMulti = config("2 - Swimming", "Swim Speed Multiplier", 1f, new ConfigDescription("Multiplies horizontal move speed while swimming (you can't sprint in water).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), Array.Empty<object>()));
FloatDepth = config("3 - Buoyancy", "Float Depth", 0.4f, new ConfigDescription("How far under the surface you settle when you're not pressing anything.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
BuoyancySpeed = config("3 - Buoyancy", "Buoyancy Speed", 1.5f, new ConfigDescription("Cap on how fast you get pushed back up to the float depth.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
SinkSpeed = config("3 - Buoyancy", "Sink Speed", 0.35f, new ConfigDescription("Idle drift downwards once you're at the float depth. Vanilla just sinks forever.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
WaveAccurate = config("3 - Buoyancy", "Wave Accurate Water Line", Toggle.On, "Use the Gerstner wave height instead of the flat water plane, so swells actually lift you.");
UnlimitedStrokes = config("4 - Strokes", "Unlimited Strokes", Toggle.On, "Kills the stroke decay. Only matters when Hold To Swim Up is off.");
StrokeForce = config("4 - Strokes", "Stroke Force", 3f, new ConfigDescription("Little kick a jump press gives while Hold To Swim Up is on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f), Array.Empty<object>()));
StrokeSoundInterval = config("4 - Strokes", "Stroke Sound Interval", 0.55f, new ConfigDescription("Seconds between swim sounds while you hold jump. 0 spams it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
UnderwaterDamage = config("5 - Drowning", "Underwater Damage", 10, new ConfigDescription("Damage per half second once your head has been under too long. 0 to never drown.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
UnderwaterDamageDelay = config("5 - Drowning", "Underwater Damage Delay", 2f, new ConfigDescription("Grace period in seconds before the drowning damage starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
Assembly executingAssembly = Assembly.GetExecutingAssembly();
_harmony.PatchAll(executingAssembly);
SetupWatcher();
if (saveOnConfigSet)
{
((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
((BaseUnityPlugin)this).Config.Save();
}
}
private void OnDestroy()
{
((BaseUnityPlugin)this).Config.Save();
}
private void SetupWatcher()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
fileSystemWatcher.Changed += ReadConfigValues;
fileSystemWatcher.Created += ReadConfigValues;
fileSystemWatcher.Renamed += ReadConfigValues;
fileSystemWatcher.IncludeSubdirectories = true;
fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
fileSystemWatcher.EnableRaisingEvents = true;
}
private void ReadConfigValues(object sender, FileSystemEventArgs e)
{
if (!File.Exists(ConfigFileFullPath))
{
return;
}
try
{
((BaseUnityPlugin)this).Config.Reload();
}
catch
{
BetterSwimmingLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
BetterSwimmingLogger.LogError((object)"Please check your config entries for spelling and format!");
}
}
internal static bool IsLocal(PlayerMovement move)
{
if ((Object)(object)Player.LocalPlayer != (Object)null)
{
return (Object)(object)move._player == (Object)(object)Player.LocalPlayer;
}
return false;
}
private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description)
{
return ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, description);
}
private ConfigEntry<T> config<T>(string group, string name, T value, string description)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
}
static BetterSwimmingPlugin()
{
string configPath = Paths.ConfigPath;
char directorySeparatorChar = Path.DirectorySeparatorChar;
ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
ConnectionError = "";
BetterSwimmingLogger = Logger.CreateLogSource("BetterSwimming");
ModEnabled = null;
HoldToSwim = null;
SwimUpSpeed = null;
DiveSpeed = null;
SwimAccel = null;
SwimSpeedMulti = null;
FloatDepth = null;
BuoyancySpeed = null;
SinkSpeed = null;
WaveAccurate = null;
UnlimitedStrokes = null;
StrokeForce = null;
StrokeSoundInterval = null;
UnderwaterDamage = null;
UnderwaterDamageDelay = null;
}
}
public static class ToggleExtensions
{
[SpecialName]
public sealed class <G>$4EFB485ABB76B8E3D0C1BC397C89D8B9
{
[SpecialName]
public static class <M>$C59917F68A58EC5D02708E1A6E1BABC0
{
}
[ExtensionMarker("<M>$C59917F68A58EC5D02708E1A6E1BABC0")]
public bool IsOn()
{
throw null;
}
[ExtensionMarker("<M>$C59917F68A58EC5D02708E1A6E1BABC0")]
public bool IsOff()
{
throw null;
}
}
public static bool IsOn(this BetterSwimmingPlugin.Toggle toggle)
{
return toggle == BetterSwimmingPlugin.Toggle.On;
}
public static bool IsOff(this BetterSwimmingPlugin.Toggle toggle)
{
return toggle == BetterSwimmingPlugin.Toggle.Off;
}
}
}