Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ManyLives v1.0.0
ManyLives.dll
Decompiled 10 months agousing 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.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(".NETFramework,Version=v4.8", FrameworkDisplayName = "")] [assembly: AssemblyCompany("ManyLives")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+7041b3d7886ea27dabc546a333c8cf4428fa2d4c")] [assembly: AssemblyProduct("live multiple lives")] [assembly: AssemblyTitle("ManyLives")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ManyLives { public class NetworkManager : MonoBehaviourPunCallbacks { public static NetworkManager Instance { get; private set; } private void Awake() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance == (Object)null) { Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); if (!Object.op_Implicit((Object)(object)((MonoBehaviourPun)this).photonView)) { PhotonView val = ((Component)this).gameObject.AddComponent<PhotonView>(); val.ViewID = 999; val.Synchronization = (ViewSynchronization)0; val.ObservedComponents = new List<Component>(); val.OwnershipTransfer = (OwnershipOption)0; } } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } public override void OnJoinedRoom() { ((MonoBehaviourPunCallbacks)this).OnJoinedRoom(); if (Object.op_Implicit((Object)(object)((MonoBehaviourPun)this).photonView) && !((MonoBehaviourPun)this).photonView.IsMine) { Plugin.Log.LogInfo((object)"Taking ownership of NetworkManager PhotonView"); ((MonoBehaviourPun)this).photonView.TransferOwnership(PhotonNetwork.LocalPlayer); } Plugin.Lives = Plugin.MaxLives; Plugin.TotalDeaths = 0; Plugin.hasSetHealth = false; Plugin.Log.LogInfo((object)$"Joined room - Reset lives to {Plugin.Lives}"); } [PunRPC] public void SyncLivesRPC(int lives, int deaths) { Plugin.Lives = lives; Plugin.TotalDeaths = deaths; Plugin.hasSetHealth = false; Plugin.Log.LogInfo((object)$"Received sync - Lives: {lives}, Deaths: {deaths}"); } [PunRPC] public void SetPlayerHealthRPC(int targetHealth) { try { PlayerAvatar val = GameDirector.instance?.PlayerList?.Find((PlayerAvatar p) => p.photonView.IsMine); if ((Object)(object)val != (Object)null && (Object)(object)val.playerHealth != (Object)null) { Traverse val2 = Traverse.Create((object)val.playerHealth); val2.Field("health").SetValue((object)targetHealth); Plugin.Log.LogInfo((object)$"RPC set health to {targetHealth} for local player"); val.playerHealth.Heal(0, true); } } catch (Exception ex) { Plugin.Log.LogError((object)("Error in SetPlayerHealthRPC: " + ex.Message)); } } public void SyncToAll(int lives, int deaths) { if (!SemiFunc.IsMultiplayer() || !PhotonNetwork.IsMasterClient) { return; } try { if (Object.op_Implicit((Object)(object)((MonoBehaviourPun)this).photonView) && ((MonoBehaviourPun)this).photonView.ViewID != 0) { Plugin.Log.LogInfo((object)$"Syncing lives ({lives}) and deaths ({deaths}) with ViewID: {((MonoBehaviourPun)this).photonView.ViewID}"); ((MonoBehaviourPun)this).photonView.RPC("SyncLivesRPC", (RpcTarget)0, new object[2] { lives, deaths }); } else { Plugin.Log.LogError((object)"PhotonView not properly initialized for sync!"); } } catch (Exception ex) { Plugin.Log.LogError((object)("Error syncing lives and deaths: " + ex.Message)); } } public void SetHealthForAll(int targetHealth) { try { if (Object.op_Implicit((Object)(object)((MonoBehaviourPun)this).photonView) && ((MonoBehaviourPun)this).photonView.ViewID != 0) { Plugin.Log.LogInfo((object)$"Setting health to {targetHealth} for all players"); ((MonoBehaviourPun)this).photonView.RPC("SetPlayerHealthRPC", (RpcTarget)0, new object[1] { targetHealth }); } } catch (Exception ex) { Plugin.Log.LogError((object)("Error setting health for all: " + ex.Message)); } } } [BepInPlugin("ManyLives", "live multiple lives", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; public static int MaxLives = 3; public static int Lives = 3; public static int TotalDeaths = 0; public static float HealthMultiplier = 1f; public static bool hasSetHealth = false; private GameObject networkManagerObj; public static Plugin Instance { get; private set; } public void Awake() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Plugin ManyLives is loaded!"); Harmony val = new Harmony("ManyLives"); val.PatchAll(); } public void Start() { ((MonoBehaviour)this).StartCoroutine(CreateNetworkManager()); } private IEnumerator CreateNetworkManager() { yield return null; if ((Object)(object)networkManagerObj == (Object)null) { networkManagerObj = new GameObject("ManyLivesNetworkManager"); networkManagerObj.AddComponent<NetworkManager>(); Object.DontDestroyOnLoad((Object)(object)networkManagerObj); Log.LogInfo((object)"Created NetworkManager"); } } public static bool ShouldHandleGameLogic() { return !SemiFunc.IsMultiplayer() || PhotonNetwork.IsMasterClient; } public static void SyncLivesAndDeaths() { if ((Object)(object)NetworkManager.Instance != (Object)null) { NetworkManager.Instance.SyncToAll(Lives, TotalDeaths); } } } [HarmonyPatch(typeof(PlayerAvatar), "Update")] public static class PlayerAvatar_Update_Patch { private static void Postfix(PlayerAvatar __instance) { if (Plugin.hasSetHealth || Plugin.TotalDeaths <= 0 || (SemiFunc.IsMultiplayer() && !__instance.photonView.IsMine)) { return; } PlayerHealth playerHealth = __instance.playerHealth; if ((Object)(object)playerHealth == (Object)null) { return; } Traverse val = Traverse.Create((object)playerHealth); if (val.Field("healthSet").GetValue<bool>()) { float num = ((Plugin.TotalDeaths == 1) ? 0.5f : 0.01f); int value = val.Field("maxHealth").GetValue<int>(); int num2 = Mathf.Max(1, Mathf.RoundToInt((float)value * num)); Plugin.Log.LogInfo((object)$"Setting health - Max: {value}, Target: {num2}"); if (SemiFunc.IsMultiplayer()) { NetworkManager.Instance?.SetHealthForAll(num2); playerHealth.Heal(0, true); playerHealth.HealOther(0, true); playerHealth.HealOtherRPC(0, true); } else { val.Field("health").SetValue((object)num2); playerHealth.Heal(0, true); playerHealth.HealOther(0, true); playerHealth.HealOtherRPC(0, true); } Plugin.hasSetHealth = true; } } } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] public static class RunManager_ChangeLevel_Patch { private static void Postfix(RunManager __instance, bool _completedLevel, bool _levelFailed) { if (Plugin.ShouldHandleGameLogic()) { if (_levelFailed || (Object)(object)__instance.levelCurrent == (Object)(object)__instance.levelLobby || (Object)(object)__instance.levelCurrent == (Object)(object)__instance.levelLobbyMenu) { Plugin.Log.LogInfo((object)$"Going to {((Object)__instance.levelCurrent).name} - Resetting lives from {Plugin.Lives} to {Plugin.MaxLives}"); Plugin.Lives = Plugin.MaxLives; Plugin.TotalDeaths = 0; Plugin.SyncLivesAndDeaths(); } else { Plugin.Log.LogInfo((object)$"Restarting level - Keeping lives at {Plugin.Lives} and deaths at {Plugin.TotalDeaths}"); Plugin.hasSetHealth = false; } } } } [HarmonyPatch(typeof(RunManager), "Update")] public static class RunManager_Update_Patch { private static void Postfix(RunManager __instance) { if (!Plugin.ShouldHandleGameLogic()) { return; } bool value = Traverse.Create((object)__instance).Field("allPlayersDead").GetValue<bool>(); bool value2 = Traverse.Create((object)__instance).Field("restarting").GetValue<bool>(); if (value && !value2) { Plugin.TotalDeaths++; Plugin.Lives--; Plugin.Log.LogInfo((object)$"All players dead - TotalDeaths: {Plugin.TotalDeaths}, Lives remaining: {Plugin.Lives}"); Plugin.SyncLivesAndDeaths(); if (Plugin.Lives <= 0) { Plugin.Log.LogInfo((object)"No lives remaining - Transitioning to arena"); __instance.ChangeLevel(false, true, (ChangeLevelType)0); } else { Plugin.Log.LogInfo((object)$"Restarting level with {Plugin.Lives} lives remaining"); __instance.ChangeLevel(false, false, (ChangeLevelType)0); } } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "ManyLives"; public const string PLUGIN_NAME = "live multiple lives"; public const string PLUGIN_VERSION = "1.0.0"; } }