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 Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; using Zorro.Core; using Zorro.Core.Serizalization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [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 SimpleTweaks { [HarmonyPatch(typeof(CharacterAnimations), "PlayEmote")] internal static class Patch_BackflipAlwaysSucceed { private const string BackflipEmote = "A_Scout_Emote_BackFlip"; private static readonly FieldInfo CharacterField = AccessTools.Field(typeof(CharacterAnimations), "character"); private static bool Prefix(CharacterAnimations __instance, string emoteName) { if (!Plugin.cfgEnableBackflipAlwaysSucceed.Value) { return true; } if (emoteName != "A_Scout_Emote_BackFlip") { return true; } if (CharacterField == null) { return true; } object? value = CharacterField.GetValue(__instance); Character val = (Character)((value is Character) ? value : null); if (val == null) { return true; } if (val.refs == null || (Object)(object)val.refs.view == (Object)null) { return true; } val.refs.view.RPC("RPCA_PlayRemove", (RpcTarget)0, new object[2] { emoteName, false }); return false; } } internal static class PendingClientSwap { public static bool Active; public static byte HandSlotID; public static byte BackpackSlotID; public static BackpackReference BackpackRef; public static float RequestTime; private const float TimeoutSeconds = 3f; public static void Set(byte handSlotID, byte backpackSlotID, BackpackReference bpRef) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) Active = true; HandSlotID = handSlotID; BackpackSlotID = backpackSlotID; BackpackRef = bpRef; RequestTime = Time.time; } public static void Clear() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Active = false; BackpackRef = default(BackpackReference); } public static bool IsValid() { if (!Active) { return false; } if (Time.time - RequestTime > 3f) { Clear(); return false; } if (!((BackpackReference)(ref BackpackRef)).exists) { Clear(); return false; } return true; } } internal static class BackpackSwapLogic { private static readonly FieldInfo VisualItemsField = AccessTools.Field(typeof(BackpackVisuals), "visualItems"); public static void DoSwapLogic(Character character, byte handSlotID, BackpackReference bpRef, byte bpSlotID) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return; } ItemSlot itemSlot = character.player.GetItemSlot(handSlotID); BackpackData data = ((BackpackReference)(ref bpRef)).GetData(); if (itemSlot != null && data != null) { ItemSlot val = data.itemSlots[bpSlotID]; if (val != null) { Item prefab = itemSlot.prefab; ItemInstanceData data2 = itemSlot.data; Item prefab2 = val.prefab; ItemInstanceData data3 = val.data; val.SetItem(prefab, data2); itemSlot.SetItem(prefab2, data3); ClearBackpackVisualSlot(bpRef, bpSlotID); SyncInventory(character); SyncBackpack(bpRef); ((BackpackReference)(ref bpRef)).GetVisuals().RefreshVisuals(); } } } private static void ClearBackpackVisualSlot(BackpackReference bpRef, byte slotID) { BackpackVisuals visuals = ((BackpackReference)(ref bpRef)).GetVisuals(); if ((Object)(object)visuals == (Object)null) { return; } if (visuals.spawnedVisualItems.TryGetValue(slotID, out var value)) { if ((Object)(object)value != (Object)null) { PhotonNetwork.Destroy(((Component)value).gameObject); } visuals.spawnedVisualItems.Remove(slotID); } if (VisualItemsField != null) { object value2 = VisualItemsField.GetValue(visuals); value2?.GetType().GetMethod("Remove", new Type[1] { typeof(byte) })?.Invoke(value2, new object[1] { slotID }); } } private static void SyncInventory(Character character) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) byte[] array = IBinarySerializable.ToManagedArray(new InventorySyncData(character.player.itemSlots, character.player.backpackSlot, character.player.tempFullSlot)); ((MonoBehaviourPun)character.player).photonView.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2] { array, false }); } private static void SyncBackpack(BackpackReference bpRef) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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) if ((int)bpRef.type == 0) { bpRef.view.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { ((BackpackReference)(ref bpRef)).GetItemInstanceData() }); } } public static void RefreshHandVisual(Character character, byte handSlotID) { //IL_0053: 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) if (!character.IsLocal) { return; } CharacterItems val = character.refs?.items; if (!((Object)(object)val == (Object)null)) { if (handSlotID == 250) { ((MonoBehaviourPun)val).photonView.RPC("DestroyHeldItemRpc", (RpcTarget)0, Array.Empty()); val.EquipSlot(Optionable.Some(handSlotID)); } else { val.EquipSlot(Optionable.Some(handSlotID)); } } } } [HarmonyPatch(typeof(Item), "Interact")] internal static class BackpackSwapPatch { private static bool Prefix(Item __instance, Character interactor) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //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_00f9: 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) PendingClientSwap.Clear(); if (!Plugin.cfgEnableBackpackSwap.Value) { return true; } if ((int)__instance.itemState != 2) { return true; } if (!__instance.backpackReference.IsSome) { return true; } if ((Object)(object)interactor.data.currentItem == (Object)null) { return true; } if (interactor.refs.items.lastEquippedSlotTime + 0.25f > Time.time) { return false; } if (!interactor.refs.items.currentSelectedSlot.IsSome) { return true; } byte value = interactor.refs.items.currentSelectedSlot.Value; if ((Object)(object)interactor.data.currentItem != (Object)null && !interactor.data.currentItem.UIData.canPocket) { return true; } if (interactor.data.isClimbing && !__instance.UIData.canPocket) { return true; } var (b, bpRef) = __instance.backpackReference.Value; if (PhotonNetwork.IsMasterClient) { BackpackSwapLogic.DoSwapLogic(interactor, value, bpRef, b); BackpackSwapLogic.RefreshHandVisual(interactor, value); ((Component)__instance).gameObject.SetActive(false); return false; } if (!interactor.player.HasEmptySlot(__instance.itemID)) { return true; } if (interactor.data.isClimbingAnything) { return true; } PendingClientSwap.Set(value, b, bpRef); return true; } } [HarmonyPatch(typeof(CharacterItems), "OnPickupAccepted")] internal static class BackpackSwapCompletePatch { private static void Prefix(CharacterItems __instance, byte slotID) { //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_0059: 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_009a: 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_00d8: Unknown result type (might be due to invalid IL or missing references) if (!PendingClientSwap.IsValid()) { return; } byte handSlotID = PendingClientSwap.HandSlotID; byte backpackSlotID = PendingClientSwap.BackpackSlotID; BackpackReference backpackRef = PendingClientSwap.BackpackRef; PendingClientSwap.Clear(); if (slotID == handSlotID) { return; } Character component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsLocal) { return; } ItemSlot itemSlot = component.player.GetItemSlot(handSlotID); if (itemSlot != null && !itemSlot.IsEmpty()) { if ((int)backpackRef.type == 0) { backpackRef.view.RPC("RPCAddItemToBackpack", (RpcTarget)0, new object[3] { ((MonoBehaviourPun)component.player).photonView, handSlotID, backpackSlotID }); } else { backpackRef.view.RPC("RPCAddItemToCharacterBackpack", (RpcTarget)0, new object[3] { ((MonoBehaviourPun)component.player).photonView, handSlotID, backpackSlotID }); } component.player.EmptySlot(Optionable.Some(handSlotID)); } } } [HarmonyPatch(typeof(Character), "UpdateVariablesFixed")] internal static class Patch_DeathRegeneration { private static void Postfix(Character __instance) { if (!Plugin.cfgEnableDeathRegeneration.Value || !((MonoBehaviourPun)__instance).photonView.IsMine) { return; } CharacterData data = __instance.data; if (!((Object)(object)data == (Object)null) && data.fullyPassedOut && !((Object)(object)data.carrier == (Object)null) && !__instance.refs.afflictions.willZombify && !__instance.input.interactIsPressed) { float num = Mathf.Max(0f, Plugin.cfgDeathRegenerationRate.Value); if (!(num <= 0f)) { data.deathTimer = Mathf.Max(0f, data.deathTimer - num * Time.fixedDeltaTime / 60f); } } } } internal static class HungerOverflowState { private static readonly FieldInfo IncrementalField = AccessTools.Field(typeof(CharacterAfflictions), "currentIncrementalStatuses"); private static float _capturedHunger = 0f; public static Character GetConsumer(ItemActionBase action) { if ((Object)(object)action == (Object)null) { return null; } Item component = ((Component)action).GetComponent(); if (!((Object)(object)component != (Object)null)) { return null; } return component.holderCharacter; } public static void CaptureBefore(Character character) { _capturedHunger = 0f; if (!((Object)(object)character == (Object)null) && character.IsLocal) { CharacterAfflictions val = character.refs?.afflictions; if (!((Object)(object)val == (Object)null)) { _capturedHunger = Mathf.Max(0f, val.GetCurrentStatus((STATUSTYPE)1)); } } } public static void Apply(Character character, float restoreAmount) { if ((Object)(object)character == (Object)null || !character.IsLocal) { return; } float capturedHunger = _capturedHunger; _capturedHunger = 0f; if (restoreAmount <= 0f) { return; } float num = Mathf.Max(0f, restoreAmount - capturedHunger); if (num <= 0f) { return; } CharacterAfflictions val = character.refs?.afflictions; if ((Object)(object)val == (Object)null) { return; } float num2 = val.hungerPerSecond * Ascents.hungerRateMultiplier; if (num2 <= 0f) { return; } float num3 = Mathf.Max(0f, Plugin.cfgHungerOverflowSecondsPerPoint.Value); float num4 = num * 100f * num3; float num5 = num4 * num2; if (!(IncrementalField == null) && IncrementalField.GetValue(val) is float[] array && array.Length > 1) { array[1] = Mathf.Min(array[1], 0f); float value = Plugin.cfgHungerOverflowMaxSeconds.Value; if (value > 0f) { float num6 = 0.025f - value * num2; array[1] = Mathf.Max(array[1] - num5, num6); } else { array[1] -= num5; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)$"[饥饿溢出] 溢出 {num * 100f:0.#} 点(恢复 {restoreAmount * 100f:0.#},已有 {capturedHunger * 100f:0.#})→ 倒计时延长 {num4:0.#} 秒"); } } } } [HarmonyPatch(typeof(Action_RestoreHunger), "RunAction")] internal static class Patch_ActionRestoreHunger_Overflow { private static void Prefix(Action_RestoreHunger __instance) { if (Plugin.cfgEnableHungerOverflow.Value) { HungerOverflowState.CaptureBefore(HungerOverflowState.GetConsumer((ItemActionBase)(object)__instance)); } } private static void Postfix(Action_RestoreHunger __instance) { if (Plugin.cfgEnableHungerOverflow.Value) { HungerOverflowState.Apply(HungerOverflowState.GetConsumer((ItemActionBase)(object)__instance), __instance.restorationAmount); } } } [HarmonyPatch(typeof(Action_ModifyStatus), "RunAction")] internal static class Patch_ActionModifyStatus_Overflow { private static readonly FieldInfo IfSkeletonField = AccessTools.Field(typeof(Action_ModifyStatus), "ifSkeleton"); private static void Prefix(Action_ModifyStatus __instance, ref bool __state) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 __state = false; if (!Plugin.cfgEnableHungerOverflow.Value) { __state = true; } else if ((int)__instance.statusType != 1 || __instance.changeAmount >= 0f) { __state = true; } else if (IfSkeletonField != null && (bool)IfSkeletonField.GetValue(__instance)) { __state = true; } else { HungerOverflowState.CaptureBefore(HungerOverflowState.GetConsumer((ItemActionBase)(object)__instance)); } } private static void Postfix(Action_ModifyStatus __instance, bool __state) { if (!__state) { HungerOverflowState.Apply(HungerOverflowState.GetConsumer((ItemActionBase)(object)__instance), Mathf.Abs(__instance.changeAmount)); } } } internal static class PeakStatsExCompat { private const string PeakStatsExTypeName = "PeakStatsEx.StaminaInfoPatch"; private static readonly FieldInfo IncrementalField = AccessTools.Field(typeof(CharacterAfflictions), "currentIncrementalStatuses"); public static void Apply(Harmony harmony) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown Type type = AccessTools.TypeByName("PeakStatsEx.StaminaInfoPatch"); if (type == null) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"PeakStatsEx 未加载,跳过饥饿倒计时显示兼容补丁。"); } return; } MethodInfo methodInfo = AccessTools.Method(type, "GetHungerIncrementalStatus", (Type[])null, (Type[])null); if (methodInfo == null) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"PeakStatsEx 已加载,但未找到 GetHungerIncrementalStatus,跳过兼容补丁。"); } return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(PeakStatsExCompat), "PostfixNegativeIncremental", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ManualLogSource log3 = Plugin.Log; if (log3 != null) { log3.LogInfo((object)"已应用 PeakStatsEx 饥饿倒计时显示兼容补丁。"); } } private static void PostfixNegativeIncremental(CharacterAfflictions afflictions, ref float __result) { if (!((Object)(object)afflictions == (Object)null) && !(IncrementalField == null) && IncrementalField.GetValue(afflictions) is float[] array && array.Length > 1) { float num = array[1]; if (num < 0f) { __result = num; } } } } [BepInPlugin("com.simpletweaks.peak", "SimpleTweaks", "1.1.0")] [BepInProcess("PEAK.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static ConfigEntry cfgEnableHungerOverflow; internal static ConfigEntry cfgHungerOverflowSecondsPerPoint; internal static ConfigEntry cfgHungerOverflowMaxSeconds; internal static ConfigEntry cfgEnableBackpackSwap; internal static ConfigEntry cfgEnableBackflipAlwaysSucceed; internal static ConfigEntry cfgEnableDeathRegeneration; internal static ConfigEntry cfgDeathRegenerationRate; internal static ManualLogSource Log; private void Awake() { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; cfgEnableHungerOverflow = ((BaseUnityPlugin)this).Config.Bind("Hunger", "EnableHungerOverflow", true, "饥饿溢出延长计时开关。吃食物时,超过当前饥饿值的恢复量会按比例延长下一次变饿的倒计时。"); cfgHungerOverflowSecondsPerPoint = ((BaseUnityPlugin)this).Config.Bind("Hunger", "HungerOverflowSecondsPerPoint", 10f, "每溢出 1 点饥饿值(1%)延长饥饿倒计时的秒数。默认 10 秒。"); cfgHungerOverflowMaxSeconds = ((BaseUnityPlugin)this).Config.Bind("Hunger", "HungerOverflowMaxSeconds", 120f, "饥饿倒计时延长后的上限(秒)。无论溢出多少,倒计时都不会超过此值,默认 120 秒(2 分钟)。0 表示不限制。"); cfgEnableBackpackSwap = ((BaseUnityPlugin)this).Config.Bind("Backpack", "EnableBackpackSwap", true, "背包物品替换开关。手上已有物品时点击背包中物品,会将手中物品与背包物品互换位置。"); cfgEnableBackflipAlwaysSucceed = ((BaseUnityPlugin)this).Config.Bind("Emote", "EnableBackflipAlwaysSucceed", true, "后空翻 100% 成功开关。原版后空翻有 50% 概率失败倒地,开启后必定成功落地。"); cfgEnableDeathRegeneration = ((BaseUnityPlugin)this).Config.Bind("Death", "EnableDeathRegeneration", true, "死亡计时回复开关。本地玩家被其他玩家背着时,死亡计时(昏迷倒计时)会缓慢回复。"); cfgDeathRegenerationRate = ((BaseUnityPlugin)this).Config.Bind("Death", "DeathRegenerationRate", 1f, "死亡计时回复速率(相对原版消耗速率)。1.0 = 与消耗同速回复(默认);0.5 = 回复速度是消耗速度的一半。0 或负数表示不回复。"); Harmony val = new Harmony("com.simpletweaks.peak"); val.PatchAll(); PeakStatsExCompat.Apply(val); Log.LogInfo((object)"SimpleTweaks v1.1.0 已加载"); } } internal static class PluginInfo { public const string PLUGIN_GUID = "com.simpletweaks.peak"; public const string PLUGIN_NAME = "SimpleTweaks"; public const string PLUGIN_VERSION = "1.1.0"; } }