using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BetterStamina.Config;
using GameNetcodeStuff;
using HarmonyLib;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("BetterStamina")]
[assembly: AssemblyDescription("Mod made by flipf17")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BetterStamina")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1c42022e-b386-4342-baf0-67de1b7529e2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BetterStamina
{
[BepInPlugin("FlipMods.BetterStamina", "BetterStamina", "1.3.2")]
public class Plugin : BaseUnityPlugin
{
private Harmony _harmony;
public static Plugin instance;
private void Awake()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
instance = this;
ConfigSettings.BindConfigSettings();
_harmony = new Harmony("BetterStamina");
_harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)"BetterStamina loaded");
}
public static void Log(string message)
{
((BaseUnityPlugin)instance).Logger.LogInfo((object)message);
}
public static void LogError(string message)
{
((BaseUnityPlugin)instance).Logger.LogError((object)message);
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "FlipMods.BetterStamina";
public const string PLUGIN_NAME = "BetterStamina";
public const string PLUGIN_VERSION = "1.3.2";
}
}
namespace BetterStamina.Patches
{
[HarmonyPatch]
public class PlayerPatcher
{
private static float currentSprintMeter;
[HarmonyPatch(typeof(PlayerControllerB), "Update")]
[HarmonyPrefix]
public static void UpdateStaminaPrefix(PlayerControllerB __instance)
{
if (((NetworkBehaviour)__instance).IsOwner && __instance.isPlayerControlled)
{
currentSprintMeter = __instance.sprintMeter;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "Update")]
[HarmonyPostfix]
public static void UpdateStaminaPostfix(PlayerControllerB __instance)
{
if (((NetworkBehaviour)__instance).IsOwner && __instance.isPlayerControlled)
{
float num = __instance.sprintMeter - currentSprintMeter;
if (num < 0f)
{
__instance.sprintMeter = Mathf.Max(currentSprintMeter + num * ConfigSync.instance.staminaConsumptionMultiplier, 0f);
}
else if (num > 0f)
{
__instance.sprintMeter = Mathf.Min(currentSprintMeter + num * ConfigSync.instance.staminaRegenMultiplier, 1f);
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
[HarmonyPrefix]
public static void LateUpdatePrefix(PlayerControllerB __instance)
{
if (((NetworkBehaviour)__instance).IsOwner && __instance.isPlayerControlled)
{
currentSprintMeter = __instance.sprintMeter;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
[HarmonyPostfix]
public static void LateUpdateStaminaPostfix(PlayerControllerB __instance)
{
if (((NetworkBehaviour)__instance).IsOwner && __instance.isPlayerControlled)
{
float num = __instance.sprintMeter - currentSprintMeter;
if (num < 0f)
{
__instance.sprintMeter = Mathf.Max(currentSprintMeter + num * ConfigSync.instance.staminaConsumptionMultiplier, 0f);
}
else if (num > 0f)
{
__instance.sprintMeter = Mathf.Min(currentSprintMeter + num * ConfigSync.instance.staminaRegenMultiplier, 1f);
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "Jump_performed")]
[HarmonyPrefix]
public static void JumpPerformedPrefix(PlayerControllerB __instance)
{
if (((NetworkBehaviour)__instance).IsOwner && __instance.isPlayerControlled)
{
currentSprintMeter = __instance.sprintMeter;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "Jump_performed")]
[HarmonyPostfix]
public static void JumpPerformedPostfix(PlayerControllerB __instance)
{
if (((NetworkBehaviour)__instance).IsOwner && __instance.isPlayerControlled)
{
float num = __instance.sprintMeter - currentSprintMeter;
if (num < 0f)
{
__instance.sprintMeter = Mathf.Max(new float[1] { currentSprintMeter + num * ConfigSync.instance.jumpStaminaConsumptionMultiplier });
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "Update")]
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> SpoofWeightValuesUpdate(IEnumerable<CodeInstruction> instructions)
{
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
FieldInfo field = typeof(PlayerControllerB).GetField("carryWeight", BindingFlags.Instance | BindingFlags.Public);
MethodInfo method = typeof(PlayerPatcher).GetMethod("GetAdjustedWeight", BindingFlags.Static | BindingFlags.Public);
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldfld && (FieldInfo)list[i].operand == field)
{
list[i] = new CodeInstruction(OpCodes.Call, (object)method);
list.RemoveAt(i - 1);
}
}
return list.AsEnumerable();
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
[HarmonyTranspiler]
public static IEnumerable<CodeInstruction> SpoofWeightValuesLateUpdate(IEnumerable<CodeInstruction> instructions)
{
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
FieldInfo field = typeof(PlayerControllerB).GetField("carryWeight", BindingFlags.Instance | BindingFlags.Public);
MethodInfo method = typeof(PlayerPatcher).GetMethod("GetAdjustedWeight", BindingFlags.Static | BindingFlags.Public);
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldfld && (FieldInfo)list[i].operand == field)
{
list[i] = new CodeInstruction(OpCodes.Call, (object)method);
list.RemoveAt(i - 1);
}
}
return list.AsEnumerable();
}
public static float GetAdjustedWeight()
{
return Mathf.Max(((Object)(object)StartOfRound.Instance.localPlayerController != (Object)null) ? (StartOfRound.Instance.localPlayerController.carryWeight * ConfigSync.instance.carryWeightPenaltyMultiplier) : 1f, 1f);
}
}
}
namespace BetterStamina.Config
{
[Serializable]
public static class ConfigSettings
{
public static ConfigEntry<float> staminaRegenMultiplierConfig;
public static ConfigEntry<float> staminaConsumptionMultiplierConfig;
public static ConfigEntry<float> jumpStaminaConsumptionMultiplierConfig;
public static ConfigEntry<float> carryWeightPenaltyMultiplierConfig;
public static ConfigEntry<float> movementSpeedMultiplierConfig;
public static void BindConfigSettings()
{
Plugin.Log("BindingConfigs");
staminaRegenMultiplierConfig = ((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("BetterStamina", "StaminaRegenMultiplier", 1.5f, "Multiplier for how fast your stamina regens.");
staminaConsumptionMultiplierConfig = ((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("BetterStamina", "StaminaConsumptionMultiplier", 0.75f, "Multiplier for how much stamina drains while sprinting.");
jumpStaminaConsumptionMultiplierConfig = ((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("BetterStamina", "JumpStaminaConsumptionMultiplier", 0.75f, "Multiplier for how much stamina jumping consumes.");
carryWeightPenaltyMultiplierConfig = ((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("BetterStamina", "CarryWeightPenaltyMultiplier", 0.5f, "Multiplier for how much your speed/stamina consumption are affected by weight.");
movementSpeedMultiplierConfig = ((BaseUnityPlugin)Plugin.instance).Config.Bind<float>("BetterStamina", "MovementSpeedMultiplier", 1f, "Player movement speed multiplier.");
}
}
[Serializable]
[HarmonyPatch]
public class ConfigSync
{
public static ConfigSync defaultConfig;
public static ConfigSync instance;
public static PlayerControllerB localPlayerController;
public static bool isSynced = false;
private static float defaultMovementSpeed = 4.6f;
public float staminaRegenMultiplier = 1f;
public float staminaConsumptionMultiplier = 1f;
public float jumpStaminaConsumptionMultiplier = 1f;
public float carryWeightPenaltyMultiplier = 1f;
public float movementSpeedMultiplier = 1f;
public static void BuildDefaultConfigSync()
{
instance = new ConfigSync();
}
public static void BuildServerConfigSync()
{
if (defaultConfig == null)
{
defaultConfig = new ConfigSync();
defaultConfig.staminaRegenMultiplier = ConfigSettings.staminaRegenMultiplierConfig.Value;
defaultConfig.staminaConsumptionMultiplier = ConfigSettings.staminaConsumptionMultiplierConfig.Value;
defaultConfig.jumpStaminaConsumptionMultiplier = ConfigSettings.jumpStaminaConsumptionMultiplierConfig.Value;
defaultConfig.carryWeightPenaltyMultiplier = ConfigSettings.carryWeightPenaltyMultiplierConfig.Value;
defaultConfig.movementSpeedMultiplier = ConfigSettings.movementSpeedMultiplierConfig.Value;
instance = defaultConfig;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
[HarmonyPostfix]
public static void InitializeLocalPlayer(PlayerControllerB __instance)
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Expected O, but got Unknown
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Expected O, but got Unknown
localPlayerController = __instance;
if (NetworkManager.Singleton.IsServer)
{
BuildServerConfigSync();
NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("BetterStamina-OnRequestConfigSync", new HandleNamedMessageDelegate(OnReceiveConfigSyncRequest));
OnLocalClientConfigSync();
}
else
{
isSynced = false;
BuildDefaultConfigSync();
NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("BetterStamina-OnReceiveConfigSync", new HandleNamedMessageDelegate(OnReceiveConfigSync));
RequestConfigSync();
}
}
public static void RequestConfigSync()
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
if (NetworkManager.Singleton.IsClient)
{
Plugin.Log("Sending config sync request to server.");
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1);
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BetterStamina-OnRequestConfigSync", 0uL, val, (NetworkDelivery)3);
}
else
{
Plugin.LogError("Failed to send config sync request.");
}
}
public static void OnReceiveConfigSyncRequest(ulong clientId, FastBufferReader reader)
{
//IL_0053: 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_007c: Unknown result type (might be due to invalid IL or missing references)
if (NetworkManager.Singleton.IsServer)
{
Plugin.Log("Receiving config sync request from client with id: " + clientId + ". Sending config sync to client.");
byte[] array = SerializeConfigToByteArray(instance);
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(array.Length + 4, (Allocator)2, -1);
int num = array.Length;
((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0);
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BetterStamina-OnReceiveConfigSync", clientId, val, (NetworkDelivery)3);
}
}
public static void OnReceiveConfigSync(ulong clientId, FastBufferReader reader)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
if (((FastBufferReader)(ref reader)).TryBeginRead(4))
{
int num = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
if (((FastBufferReader)(ref reader)).TryBeginRead(num))
{
Plugin.Log("Receiving config sync from server.");
byte[] data = new byte[num];
((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
instance = DeserializeFromByteArray(data);
OnLocalClientConfigSync();
}
else
{
Plugin.LogError("Error receiving sync from server.");
}
}
else
{
Plugin.LogError("Error receiving bytes length.");
}
}
public static void OnLocalClientConfigSync()
{
localPlayerController.movementSpeed = defaultMovementSpeed * instance.movementSpeedMultiplier;
isSynced = true;
}
public static byte[] SerializeConfigToByteArray(ConfigSync config)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream();
binaryFormatter.Serialize(memoryStream, config);
return memoryStream.ToArray();
}
public static ConfigSync DeserializeFromByteArray(byte[] data)
{
MemoryStream serializationStream = new MemoryStream(data);
BinaryFormatter binaryFormatter = new BinaryFormatter();
return (ConfigSync)binaryFormatter.Deserialize(serializationStream);
}
}
}