using System;
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 Photon.Realtime;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("HealOnLobbyMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Heals players when entering the lobby")]
[assembly: AssemblyFileVersion("1.0.6.0")]
[assembly: AssemblyInformationalVersion("1.0.6")]
[assembly: AssemblyProduct("HealOnLobbyMod")]
[assembly: AssemblyTitle("HealOnLobbyMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
[BepInPlugin("HealOnLobby", "Heal On Lobby Mod", "1.0.8")]
public class HealOnLobbyMod : BaseUnityPlugin
{
internal static ManualLogSource Log;
internal static ConfigEntry<bool> HealToMaxEnabled;
internal static ConfigEntry<bool> HealByPercentEnabled;
internal static ConfigEntry<int> HealPercentAmount;
internal static ConfigEntry<int> HealAmount;
internal static ConfigEntry<int> HealChance;
public static HealOnLobbyMod Instance { get; private set; }
private void Awake()
{
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Expected O, but got Unknown
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Expected O, but got Unknown
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
HealToMaxEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "1. Heal To Max Health", true, "Heal players to full health in the lobby. Overrides other settings if enabled.");
HealByPercentEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "2. Heal By Percent Enabled", false, "Heal players by a percentage of their max health (if 'Heal To Max Health' is off).");
HealPercentAmount = ((BaseUnityPlugin)this).Config.Bind<int>("1. General", "3. Heal Percent Amount", 50, new ConfigDescription("The percentage (0-100) of max health to restore (used if 'Heal By Percent Enabled' is on).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
HealAmount = ((BaseUnityPlugin)this).Config.Bind<int>("1. General", "4. Heal Amount", 100, "Fixed amount of health to restore (used if both 'Heal To Max Health' and 'Heal By Percent Enabled' are off).");
HealChance = ((BaseUnityPlugin)this).Config.Bind<int>("2. Heal Chance", "Heal Chance", 100, new ConfigDescription("The chance (0-100) that healing will occur when entering the lobby. 100 means healing always happens (if conditions are met).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
new Harmony("HealOnLobby").PatchAll();
Log.LogInfo((object)"HealOnLobbyMod loaded! All configurations loaded.");
}
}
[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
public static class RunManager_ChangeLevel_Patch
{
private const string HealRpcName = "RPC_HealPlayer";
private static void Postfix(RunManager __instance)
{
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Invalid comparison between Unknown and I4
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Invalid comparison between Unknown and I4
//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
string text = null;
string text2 = "Level - Lobby";
try
{
if ((Object)(object)__instance.levelCurrent == (Object)null)
{
HealOnLobbyMod.Log.LogWarning((object)"RunManager.ChangeLevel Postfix: __instance.levelCurrent is null.");
return;
}
text = ((Object)__instance.levelCurrent).name;
HealOnLobbyMod.Log.LogInfo((object)("RunManager.ChangeLevel Postfix: Current level is '" + text + "'"));
if (!(text == text2))
{
return;
}
bool isMasterClient = PhotonNetwork.IsMasterClient;
ClientState networkClientState = PhotonNetwork.NetworkClientState;
HealOnLobbyMod.Log.LogInfo((object)$"Checking conditions: IsMasterClient={isMasterClient}, NetworkClientState={networkClientState}");
bool flag = (int)networkClientState == 14 || (int)networkClientState == 0;
if (isMasterClient || flag)
{
string arg = (isMasterClient ? "Host" : (flag ? "Single-player" : "Unknown"));
HealOnLobbyMod.Log.LogInfo((object)$"Conditions met ({arg}, State: {networkClientState}). Processing healing IMMEDIATELY...");
try
{
int value = HealOnLobbyMod.HealChance.Value;
if ((Object)(object)GameDirector.instance != (Object)null && GameDirector.instance.PlayerList != null)
{
HealOnLobbyMod.Log.LogInfo((object)$"Found {GameDirector.instance.PlayerList.Count} player(s) in list.");
foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
{
if ((Object)(object)player != (Object)null && (Object)(object)player.playerHealth != (Object)null)
{
string text3 = player.playerName ?? "NULL_NAME";
PhotonView component = ((Component)player).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null && isMasterClient)
{
HealOnLobbyMod.Log.LogWarning((object)("Player '" + text3 + "' has no PhotonView. Skipping RPC."));
continue;
}
int health = player.playerHealth.health;
int maxHealth = player.playerHealth.maxHealth;
HealOnLobbyMod.Log.LogInfo((object)$"--- Player '{text3}' (ViewID: {((component != null) ? component.ViewID : 0)}): Health READ as {health}/{maxHealth} ---");
int num = 0;
bool value2 = HealOnLobbyMod.HealToMaxEnabled.Value;
bool value3 = HealOnLobbyMod.HealByPercentEnabled.Value;
int value4 = HealOnLobbyMod.HealPercentAmount.Value;
int value5 = HealOnLobbyMod.HealAmount.Value;
num = (value2 ? (maxHealth - health) : ((!value3) ? Mathf.Min(value5, maxHealth - health) : Mathf.Min(Mathf.CeilToInt((float)maxHealth * ((float)value4 / 100f)), maxHealth - health)));
num = Mathf.Max(0, num);
if (num > 0)
{
HealOnLobbyMod.Log.LogInfo((object)$"Player '{text3}': Calculated HEAL AMOUNT: {num}");
int num2 = Random.Range(1, 101);
bool flag2 = num2 <= value;
HealOnLobbyMod.Log.LogInfo((object)$"Player '{text3}': Heal chance check: Rolled {num2} vs Chance {value}. Allowed: {flag2}");
if (flag2)
{
if (isMasterClient)
{
if ((Object)(object)component != (Object)null)
{
HealOnLobbyMod.Log.LogInfo((object)string.Format("MP Host: Sending RPC '{0}' for player '{1}' (ViewID: {2}) with HEAL AMOUNT {3}.", "RPC_HealPlayer", text3, component.ViewID, num));
component.RPC("RPC_HealPlayer", (RpcTarget)3, new object[1] { num });
}
else
{
HealOnLobbyMod.Log.LogWarning((object)("MP Host: PhotonView became null for player '" + text3 + "' before sending RPC."));
}
}
else if (flag)
{
int num3 = Mathf.Min(num, maxHealth - health);
num3 = Mathf.Max(0, num3);
if (num3 > 0)
{
HealOnLobbyMod.Log.LogInfo((object)$"SP (State: {networkClientState}): Calling playerHealth.Heal directly for player '{text3}' (ViewID: {((component != null) ? component.ViewID : 0)}) with ACTUAL amount {num3}.");
player.playerHealth.Heal(num3, false);
}
else
{
HealOnLobbyMod.Log.LogInfo((object)("SP: Calculated actual heal is 0 for player '" + text3 + "'. Skipping direct call."));
}
}
}
else
{
HealOnLobbyMod.Log.LogInfo((object)$"Player '{text3}' healing skipped due to chance ({num2} > {value}).");
}
}
else
{
HealOnLobbyMod.Log.LogInfo((object)$"Player '{text3}' needs no healing ({health}/{maxHealth}). No action taken.");
}
}
else
{
HealOnLobbyMod.Log.LogWarning((object)"Player entry is null or has no PlayerHealth component.");
}
}
HealOnLobbyMod.Log.LogInfo((object)"Immediate healing processing loop completed.");
}
else
{
HealOnLobbyMod.Log.LogWarning((object)"GameDirector or PlayerList is null.");
}
return;
}
catch (Exception arg2)
{
HealOnLobbyMod.Log.LogError((object)$"Exception occurred during immediate healing processing: {arg2}");
return;
}
}
HealOnLobbyMod.Log.LogInfo((object)$"Client role detected (IsMasterClient: {isMasterClient}, NetworkClientState: {networkClientState}). Waiting for host RPC...");
}
catch (Exception arg3)
{
HealOnLobbyMod.Log.LogError((object)$"Exception occurred in RunManager_ChangeLevel_Patch.Postfix: {arg3}");
}
}
}
[HarmonyPatch(typeof(PlayerAvatar), "Awake")]
public static class PlayerAvatar_Awake_Patch
{
private static void Postfix(PlayerAvatar __instance)
{
try
{
GameObject gameObject = ((Component)__instance).gameObject;
if ((Object)(object)gameObject.GetComponent<PlayerHealSync>() == (Object)null)
{
gameObject.AddComponent<PlayerHealSync>();
HealOnLobbyMod.Log.LogInfo((object)("Added PlayerHealSync component to " + ((Object)gameObject).name));
}
}
catch (Exception arg)
{
HealOnLobbyMod.Log.LogError((object)$"Exception in PlayerAvatar_Awake_Patch.Postfix: {arg}");
}
}
}
public class PlayerHealSync : MonoBehaviourPun
{
private PlayerHealth playerHealth;
private void Awake()
{
playerHealth = ((Component)this).GetComponent<PlayerHealth>();
if ((Object)(object)playerHealth == (Object)null)
{
Debug.LogError((object)"PlayerHealSync: Could not find PlayerHealth component!");
}
}
[PunRPC]
public void RPC_HealPlayer(int healAmount, PhotonMessageInfo info)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
if (!info.Sender.IsMasterClient)
{
PhotonView photonView = ((MonoBehaviourPun)this).photonView;
object arg = ((photonView != null) ? photonView.ViewID : 0);
Player sender = info.Sender;
Debug.LogWarning((object)string.Format("PlayerHealSync (ViewID: {0}): Received RPC_HealPlayer from non-MasterClient {1}. Ignoring.", arg, ((sender != null) ? sender.NickName : null) ?? "N/A"));
return;
}
PhotonView photonView2 = ((MonoBehaviourPun)this).photonView;
object arg2 = ((photonView2 != null) ? photonView2.ViewID : 0);
Player sender2 = info.Sender;
Debug.Log((object)string.Format("PlayerHealSync (ViewID: {0}): RPC_HealPlayer received from {1} with amount {2}.", arg2, ((sender2 != null) ? sender2.NickName : null) ?? "N/A", healAmount));
if ((Object)(object)playerHealth != (Object)null)
{
int health = playerHealth.health;
int maxHealth = playerHealth.maxHealth;
int num = Mathf.Min(healAmount, maxHealth - health);
num = Mathf.Max(0, num);
object[] array = new object[4];
PhotonView photonView3 = ((MonoBehaviourPun)this).photonView;
array[0] = ((photonView3 != null) ? photonView3.ViewID : 0);
array[1] = health;
array[2] = maxHealth;
array[3] = num;
Debug.Log((object)string.Format("PlayerHealSync (ViewID: {0}): Current health is {1}/{2}. Calculated actual heal amount: {3}.", array));
if (num > 0)
{
playerHealth.Heal(num, false);
PhotonView photonView4 = ((MonoBehaviourPun)this).photonView;
Debug.Log((object)$"PlayerHealSync (ViewID: {((photonView4 != null) ? photonView4.ViewID : 0)}): Called playerHealth.Heal({num}). New health should be {Mathf.Min(health + num, maxHealth)}.");
}
else
{
PhotonView photonView5 = ((MonoBehaviourPun)this).photonView;
Debug.Log((object)$"PlayerHealSync (ViewID: {((photonView5 != null) ? photonView5.ViewID : 0)}): Actual heal amount is zero. No heal needed.");
}
}
else
{
PhotonView photonView6 = ((MonoBehaviourPun)this).photonView;
Debug.LogError((object)$"PlayerHealSync (ViewID: {((photonView6 != null) ? photonView6.ViewID : 0)}): Received RPC_HealPlayer but PlayerHealth component is missing!");
}
}
}
namespace HealOnStoreMod
{
public static class PluginInfo
{
public const string PLUGIN_GUID = "HealOnLobbyMod";
public const string PLUGIN_NAME = "HealOnLobbyMod";
public const string PLUGIN_VERSION = "1.0.6";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}