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 <DelayedReapplyAfterLevelChange>d__45 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public LowHealthChallengePlugin <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <DelayedReapplyAfterLevelChange>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 <DestroyHealthUpgradeLoop>d__35 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public LowHealthChallengePlugin <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <DestroyHealthUpgradeLoop>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 <EnforceLoop>d__34 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public LowHealthChallengePlugin <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <EnforceLoop>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<bool> enableMod;
private ConfigEntry<int> targetHealth;
private ConfigEntry<bool> blockHealthUpgradeInShop;
private ConfigEntry<bool> blockHealthUpgradeInWorld;
private ConfigEntry<bool> destroyExistingHealthUpgradeItems;
private ConfigEntry<bool> reapplyHealthOverrideIfChanged;
private ConfigEntry<bool> 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<bool>("General", "EnableMod", true, "Enable or disable this mod");
targetHealth = ((BaseUnityPlugin)this).Config.Bind<int>("Health", "TargetHealth", 40, "Target health input 0-100. This value is always rewritten to the rounded value");
blockHealthUpgradeInShop = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Upgrade Blocking", "BlockHealthUpgradeInShop", true, "Remove health upgrade from shop candidates");
blockHealthUpgradeInWorld = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Upgrade Blocking", "BlockHealthUpgradeInWorld", true, "Disable health upgrade items in item dictionary");
destroyExistingHealthUpgradeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Upgrade Blocking", "DestroyExistingHealthUpgradeItems", true, "Destroy spawned health upgrade items");
reapplyHealthOverrideIfChanged = ((BaseUnityPlugin)this).Config.Bind<bool>("Health Upgrade Blocking", "ReapplyHealthOverrideIfChanged", false, "Reapply fixed health if changed");
logRoundedResult = ((BaseUnityPlugin)this).Config.Bind<bool>("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(<EnforceLoop>d__34))]
private IEnumerator EnforceLoop()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <EnforceLoop>d__34(0)
{
<>4__this = this
};
}
[IteratorStateMachine(typeof(<DestroyHealthUpgradeLoop>d__35))]
private IEnumerator DestroyHealthUpgradeLoop()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DestroyHealthUpgradeLoop>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<ItemUpgradePlayerHealth>(true) != (Object)null;
}
private void DestroySpawnedHealthUpgradeItems()
{
if (!destroyExistingHealthUpgradeItems.Value)
{
return;
}
ItemUpgradePlayerHealth[] array = Object.FindObjectsOfType<ItemUpgradePlayerHealth>(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<PhotonView>();
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(<DelayedReapplyAfterLevelChange>d__45))]
private IEnumerator DelayedReapplyAfterLevelChange()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DelayedReapplyAfterLevelChange>d__45(0)
{
<>4__this = this
};
}
}
}