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 ModEnabled; internal static ConfigEntry HoldToSwim; internal static ConfigEntry SwimUpSpeed; internal static ConfigEntry DiveSpeed; internal static ConfigEntry SwimAccel; internal static ConfigEntry SwimSpeedMulti; internal static ConfigEntry FloatDepth; internal static ConfigEntry BuoyancySpeed; internal static ConfigEntry SinkSpeed; internal static ConfigEntry WaveAccurate; internal static ConfigEntry UnlimitedStrokes; internal static ConfigEntry StrokeForce; internal static ConfigEntry StrokeSoundInterval; internal static ConfigEntry UnderwaterDamage; internal static ConfigEntry UnderwaterDamageDelay; internal static bool IsEnabled { get { ConfigEntry 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(0.5f, 15f), Array.Empty())); 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(0f, 15f), Array.Empty())); 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(1f, 100f), Array.Empty())); 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(0.25f, 3f), Array.Empty())); 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(0f, 3f), Array.Empty())); 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(0f, 10f), Array.Empty())); 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(0f, 5f), Array.Empty())); 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(0f, 15f), Array.Empty())); 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(0f, 3f), Array.Empty())); 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(0, 100), Array.Empty())); UnderwaterDamageDelay = config("5 - Drowning", "Underwater Damage Delay", 2f, new ConfigDescription("Grace period in seconds before the drowning damage starts.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 60f), Array.Empty())); 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 config(string group, string name, T value, ConfigDescription description) { return ((BaseUnityPlugin)this).Config.Bind(group, name, value, description); } private ConfigEntry config(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())); } 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 $4EFB485ABB76B8E3D0C1BC397C89D8B9 { [SpecialName] public static class $C59917F68A58EC5D02708E1A6E1BABC0 { } [ExtensionMarker("$C59917F68A58EC5D02708E1A6E1BABC0")] public bool IsOn() { throw null; } [ExtensionMarker("$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; } } }