using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; 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 Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("zabu")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("zabumod")] [assembly: AssemblyTitle("zabumod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 REPOJP.LowHealthChallengeMod { [BepInPlugin("REPOJP.LowHealthChallenge", "LowHealthChallenge", "1.0.0")] public sealed class LowHealthChallengePlugin : BaseUnityPlugin { [HarmonyPatch(typeof(PlayerAvatar), "ChatMessageSendRPC")] private static class PlayerAvatar_ChatMessageSendRPC_Patch { private static void Postfix(PlayerAvatar __instance, string _message, PhotonMessageInfo _info) { if (Object.op_Implicit((Object)(object)__instance) && __instance.isLocal) { ExecuteCommand(_message); } } } [HarmonyPatch(typeof(PlayerAvatar), "AddToStatsManagerRPC")] private static class PlayerAvatar_AddToStatsManagerRPC_Patch { private static void Postfix(PlayerAvatar __instance) { if (Object.op_Implicit((Object)(object)Instance) && Instance.enableMod.Value && OverrideActive && IsHost() && Object.op_Implicit((Object)(object)__instance)) { ApplyFixedHealthToSinglePlayer(__instance); } } } [HarmonyPatch(typeof(ShopManager), "GetAllItemsFromStatsManager")] private static class ShopManager_GetAllItemsFromStatsManager_Patch { private static void Postfix(ShopManager __instance) { if (Object.op_Implicit((Object)(object)Instance) && Instance.enableMod.Value && Instance.blockHealthUpgradeInShop.Value && IsHost() && Object.op_Implicit((Object)(object)__instance)) { __instance.potentialItemUpgrades.RemoveAll(IsHealthUpgradeItem); } } } [HarmonyPatch(typeof(StatsManager), "Start")] private static class StatsManager_Start_Patch { private static void Postfix() { if (Object.op_Implicit((Object)(object)Instance) && Instance.enableMod.Value) { Instance.NormalizeConfigAndApply("StatsManagerStart"); } } } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] private static class RunManager_ChangeLevel_Patch { private static void Postfix() { if (Object.op_Implicit((Object)(object)Instance) && Instance.enableMod.Value && IsHost()) { ((MonoBehaviour)Instance).StartCoroutine(Instance.DelayedReapplyAfterLevelChange()); } } } [CompilerGenerated] private sealed class d__45 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public LowHealthChallengePlugin <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__45(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; if (!<>4__this.enableMod.Value) { return false; } if (!OverrideActive) { return false; } if (!IsHost()) { return false; } <>4__this.RefreshHealthUpgradeItemsDisabledState(); ApplyFixedHealthToAllPlayers(); if (<>4__this.destroyExistingHealthUpgradeItems.Value) { <>4__this.DestroySpawnedHealthUpgradeItems(); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__35 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public LowHealthChallengePlugin <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__35(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; if (<>4__this.enableMod.Value && IsHost() && <>4__this.destroyExistingHealthUpgradeItems.Value) { <>4__this.DestroySpawnedHealthUpgradeItems(); } break; } <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__34 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public LowHealthChallengePlugin <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__34(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; if (<>4__this.enableMod.Value && OverrideActive && IsHost()) { <>4__this.RefreshHealthUpgradeItemsDisabledState(); if (<>4__this.reapplyHealthOverrideIfChanged.Value) { ApplyFixedHealthToAllPlayers(); } } break; } <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string PluginGuid = "REPOJP.LowHealthChallenge"; public const string PluginName = "LowHealthChallenge"; public const string PluginVersion = "1.0.0"; internal static LowHealthChallengePlugin Instance; internal static ManualLogSource Log; private Harmony harmony; private ConfigEntry enableMod; private ConfigEntry targetHealth; private ConfigEntry blockHealthUpgradeInShop; private ConfigEntry blockHealthUpgradeInWorld; private ConfigEntry destroyExistingHealthUpgradeItems; private ConfigEntry reapplyHealthOverrideIfChanged; private ConfigEntry logRoundedResult; private bool suppressTargetHealthEvent; private Coroutine enforceCoroutine; private Coroutine destroyHealthUpgradeCoroutine; internal static readonly int[] AllowedHealthValues = new int[6] { 0, 20, 40, 60, 80, 100 }; internal static bool OverrideActive; internal static int RoundedHealthValue = 40; internal static int MappedHealthUpgradeValue = -3; private void Awake() { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; enableMod = ((BaseUnityPlugin)this).Config.Bind("General", "EnableMod", true, "Enable or disable this mod"); targetHealth = ((BaseUnityPlugin)this).Config.Bind("Health", "TargetHealth", 40, "Target health input 0-100. This value is always rewritten to the rounded value"); blockHealthUpgradeInShop = ((BaseUnityPlugin)this).Config.Bind("Health Upgrade Blocking", "BlockHealthUpgradeInShop", true, "Remove health upgrade from shop candidates"); blockHealthUpgradeInWorld = ((BaseUnityPlugin)this).Config.Bind("Health Upgrade Blocking", "BlockHealthUpgradeInWorld", true, "Disable health upgrade items in item dictionary"); destroyExistingHealthUpgradeItems = ((BaseUnityPlugin)this).Config.Bind("Health Upgrade Blocking", "DestroyExistingHealthUpgradeItems", true, "Destroy spawned health upgrade items"); reapplyHealthOverrideIfChanged = ((BaseUnityPlugin)this).Config.Bind("Health Upgrade Blocking", "ReapplyHealthOverrideIfChanged", false, "Reapply fixed health if changed"); logRoundedResult = ((BaseUnityPlugin)this).Config.Bind("Debug", "LogRoundedResult", true, "Log rounded result"); targetHealth.SettingChanged += OnTargetHealthSettingChanged; harmony = new Harmony("REPOJP.LowHealthChallenge"); harmony.PatchAll(); NormalizeConfigAndApply("Awake"); enforceCoroutine = ((MonoBehaviour)this).StartCoroutine(EnforceLoop()); destroyHealthUpgradeCoroutine = ((MonoBehaviour)this).StartCoroutine(DestroyHealthUpgradeLoop()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"LowHealthChallenge 1.0.0 loaded"); } private void OnDestroy() { targetHealth.SettingChanged -= OnTargetHealthSettingChanged; if (harmony != null) { harmony.UnpatchSelf(); } } private void OnTargetHealthSettingChanged(object sender, EventArgs e) { if (!suppressTargetHealthEvent) { NormalizeConfigAndApply("ConfigChanged"); } } internal static bool IsHost() { return SemiFunc.IsMasterClientOrSingleplayer(); } internal static bool TryGetSteamId(PlayerAvatar avatar, out string steamId) { steamId = null; if (!Object.op_Implicit((Object)(object)avatar)) { return false; } if (!string.IsNullOrWhiteSpace(avatar.steamID)) { steamId = avatar.steamID; return true; } try { steamId = SemiFunc.PlayerGetSteamID(avatar); } catch { steamId = null; } return !string.IsNullOrWhiteSpace(steamId); } internal static int NormalizeHealthValue(int input) { int num = Mathf.Clamp(input, 0, 100); int num2 = AllowedHealthValues[0]; int num3 = Math.Abs(num - num2); for (int i = 1; i < AllowedHealthValues.Length; i++) { int num4 = AllowedHealthValues[i]; int num5 = Math.Abs(num - num4); if (num5 < num3) { num2 = num4; num3 = num5; } else if (num5 == num3 && num4 > num2) { num2 = num4; num3 = num5; } } return num2; } internal static int MapRoundedHealthToUpgradeValue(int roundedHealth) { return (roundedHealth - 100) / 20; } private void NormalizeConfigAndApply(string source) { if (!enableMod.Value) { OverrideActive = false; return; } int value = targetHealth.Value; int num = NormalizeHealthValue(value); int num2 = MapRoundedHealthToUpgradeValue(num); RoundedHealthValue = num; MappedHealthUpgradeValue = num2; OverrideActive = true; WriteRoundedHealthToConfigIfNeeded(num); if (logRoundedResult.Value) { Log.LogInfo((object)$"[{source}] Requested health: {value}"); Log.LogInfo((object)$"[{source}] Rounded health: {num}"); Log.LogInfo((object)$"[{source}] Mapped health upgrade: {num2}"); } RefreshHealthUpgradeItemsDisabledState(); if (IsHost()) { ApplyFixedHealthToAllPlayers(); } } private void WriteRoundedHealthToConfigIfNeeded(int rounded) { if (targetHealth.Value == rounded) { return; } suppressTargetHealthEvent = true; try { targetHealth.Value = rounded; ((BaseUnityPlugin)this).Config.Save(); } finally { suppressTargetHealthEvent = false; } } internal static void SetTargetHealthFromCommand(int requestedValue) { if (Object.op_Implicit((Object)(object)Instance)) { int num = NormalizeHealthValue(requestedValue); Instance.suppressTargetHealthEvent = true; try { Instance.targetHealth.Value = num; ((BaseUnityPlugin)Instance).Config.Save(); } finally { Instance.suppressTargetHealthEvent = false; } RoundedHealthValue = num; MappedHealthUpgradeValue = MapRoundedHealthToUpgradeValue(num); OverrideActive = true; if (Instance.logRoundedResult.Value) { Log.LogInfo((object)$"[Command] Requested health: {requestedValue}"); Log.LogInfo((object)$"[Command] Rounded health: {num}"); Log.LogInfo((object)$"[Command] Mapped health upgrade: {MappedHealthUpgradeValue}"); } Instance.RefreshHealthUpgradeItemsDisabledState(); if (IsHost()) { ApplyFixedHealthToAllPlayers(); } } } private static void ApplyFixedHealthToAllPlayers() { if (!OverrideActive || !IsHost() || !Object.op_Implicit((Object)(object)GameDirector.instance) || GameDirector.instance.PlayerList == null || !Object.op_Implicit((Object)(object)StatsManager.instance)) { return; } foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { ApplyFixedHealthToSinglePlayer(player); } } private static void ApplyFixedHealthToSinglePlayer(PlayerAvatar avatar) { if (!OverrideActive || !Object.op_Implicit((Object)(object)avatar) || !Object.op_Implicit((Object)(object)StatsManager.instance) || !TryGetSteamId(avatar, out string steamId)) { return; } string text = avatar.playerName; if (string.IsNullOrWhiteSpace(text)) { try { text = SemiFunc.PlayerGetName(avatar); } catch { text = steamId; } } StatsManager.instance.PlayerAdd(steamId, text); SetPlayerUpgradeHealth(steamId, MappedHealthUpgradeValue); int playerHealth = StatsManager.instance.GetPlayerHealth(steamId); int num = ((playerHealth > RoundedHealthValue) ? RoundedHealthValue : playerHealth); num = Mathf.Clamp(num, 0, RoundedHealthValue); StatsManager.instance.SetPlayerHealth(steamId, num, true); ApplyImmediateHealthToAvatar(avatar, num, RoundedHealthValue); } private static void SetPlayerUpgradeHealth(string steamId, int value) { if (!StatsManager.instance.playerUpgradeHealth.ContainsKey(steamId)) { StatsManager.instance.playerUpgradeHealth.Add(steamId, value); } else { StatsManager.instance.playerUpgradeHealth[steamId] = value; } if (Object.op_Implicit((Object)(object)PunManager.instance)) { PunManager.instance.UpdateStat("playerUpgradeHealth", steamId, value); } } private static void ApplyImmediateHealthToAvatar(PlayerAvatar avatar, int currentHealth, int maxHealth) { if (Object.op_Implicit((Object)(object)avatar) && Object.op_Implicit((Object)(object)avatar.playerHealth)) { avatar.playerHealth.maxHealth = maxHealth; avatar.playerHealth.health = Mathf.Clamp(currentHealth, 0, maxHealth); if (Object.op_Implicit((Object)(object)avatar.playerHealth.photonView)) { avatar.playerHealth.photonView.RPC("UpdateHealthRPC", (RpcTarget)1, new object[3] { avatar.playerHealth.health, avatar.playerHealth.maxHealth, false }); } } } [IteratorStateMachine(typeof(d__34))] private IEnumerator EnforceLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__34(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__35))] private IEnumerator DestroyHealthUpgradeLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__35(0) { <>4__this = this }; } private void RefreshHealthUpgradeItemsDisabledState() { if (!enableMod.Value || !IsHost() || !Object.op_Implicit((Object)(object)StatsManager.instance)) { return; } foreach (Item value in StatsManager.instance.itemDictionary.Values) { if (Object.op_Implicit((Object)(object)value) && IsHealthUpgradeItem(value) && blockHealthUpgradeInWorld.Value) { value.disabled = true; } } } private static bool IsHealthUpgradeItem(Item item) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)item)) { return false; } if ((int)item.itemType != 3) { return false; } if (item.prefab == null || !item.prefab.IsValid()) { return false; } GameObject val = null; try { val = item.prefab.Prefab; } catch { val = null; } if (!Object.op_Implicit((Object)(object)val)) { return false; } return (Object)(object)val.GetComponentInChildren(true) != (Object)null; } private void DestroySpawnedHealthUpgradeItems() { if (!destroyExistingHealthUpgradeItems.Value) { return; } ItemUpgradePlayerHealth[] array = Object.FindObjectsOfType(true); ItemUpgradePlayerHealth[] array2 = array; foreach (ItemUpgradePlayerHealth val in array2) { if (!Object.op_Implicit((Object)(object)val)) { continue; } GameObject gameObject = ((Component)val).gameObject; PhotonView componentInParent = gameObject.GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && Object.op_Implicit((Object)(object)((Component)componentInParent).gameObject)) { gameObject = ((Component)componentInParent).gameObject; } try { if (Object.op_Implicit((Object)(object)componentInParent) && PhotonNetwork.InRoom) { PhotonNetwork.Destroy(gameObject); } else { Object.Destroy((Object)(object)gameObject); } } catch { try { Object.Destroy((Object)(object)gameObject); } catch { } } } } internal static void ExecuteCommand(string rawMessage) { if (!Object.op_Implicit((Object)(object)Instance) || !Instance.enableMod.Value || !IsHost() || string.IsNullOrWhiteSpace(rawMessage)) { return; } string text = rawMessage.Trim(); if (string.Equals(text, "/hpnow", StringComparison.OrdinalIgnoreCase)) { Log.LogInfo((object)$"Current TargetHealth(Config): {Instance.targetHealth.Value}"); Log.LogInfo((object)$"Current RoundedHealthValue: {RoundedHealthValue}"); Log.LogInfo((object)$"Current MappedHealthUpgradeValue: {MappedHealthUpgradeValue}"); } else if (string.Equals(text, "/hpreset", StringComparison.OrdinalIgnoreCase)) { SetTargetHealthFromCommand(100); } else if (text.StartsWith("/hpset ", StringComparison.OrdinalIgnoreCase)) { string text2 = text.Substring(7).Trim(); if (!int.TryParse(text2, out var result)) { Log.LogInfo((object)("Invalid /hpset value: " + text2)); } else { SetTargetHealthFromCommand(result); } } } [IteratorStateMachine(typeof(d__45))] private IEnumerator DelayedReapplyAfterLevelChange() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__45(0) { <>4__this = this }; } } }