Please disclose if any significant portion of your mod was created 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 AUTORESPAWN v1.1.1
BepInEx/plugins/AutoRespawn.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AutoRespawn")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AutoRespawn")] [assembly: AssemblyTitle("AutoRespawn")] [assembly: AssemblyVersion("1.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 AutoRespawn { [BepInPlugin("com.flavi.autorespawn", "Auto Respawn", "1.1.1")] public class AutoRespawnPlugin : BaseUnityPlugin { internal static ManualLogSource LogSource; internal static ConfigEntry<int> RespawnTime; internal static ConfigEntry<int> RespawnHealth; private Harmony harmony; private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown LogSource = ((BaseUnityPlugin)this).Logger; RespawnTime = ((BaseUnityPlugin)this).Config.Bind<int>("Auto Respawn", "Respawn Time", 60, new ConfigDescription("Seconds before a dead player respawns. Chat notices adjust to this value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(30, 120), Array.Empty<object>())); RespawnHealth = ((BaseUnityPlugin)this).Config.Bind<int>("Auto Respawn", "Health After Respawn", 50, new ConfigDescription("Health the player has after being revived.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>())); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Iniciando Auto Respawn 1.1.1."); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Configuración: respawn en " + RespawnTime.Value + " segundos; vida al revivir " + RespawnHealth.Value + ".")); ((BaseUnityPlugin)this).Logger.LogInfo((object)"El primer aviso de chat se enviará después de 5 segundos."); AutoRespawnController.Initialize(); harmony = new Harmony("com.flavi.autorespawn"); try { harmony.PatchAll(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Falló PatchAll de Harmony: " + ex)); throw; } int num = 0; foreach (MethodBase patchedMethod in harmony.GetPatchedMethods()) { num++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Parche activo: " + patchedMethod.DeclaringType.Name + "." + patchedMethod.Name)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Auto Respawn cargado correctamente. Parches: " + num)); } private void OnDestroy() { if (((BaseUnityPlugin)this).Logger != null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Componente BepInEx destruido; los parches Harmony se conservan."); } } } internal static class AutoRespawnController { private const int AnnouncementDelaySeconds = 5; private static readonly HashSet<PlayerAvatar> pending = new HashSet<PlayerAvatar>(); private static readonly HashSet<PlayerAvatar> observedDead = new HashSet<PlayerAvatar>(); private static readonly FieldInfo DeadSetField = AccessTools.Field(typeof(PlayerAvatar), "deadSet"); private static bool deadSetErrorLogged; private static bool zoneCheckErrorLogged; internal static void Initialize() { if (DeadSetField == null) { LogErrorOnce("No se encontró PlayerAvatar.deadSet; la detección desde PlayerAvatar.Update no estará disponible."); } else { LogInfo("Detección preparada desde PlayerAvatar.Update y deadSet."); } } internal static void CheckDeadState(PlayerAvatar player) { if ((Object)(object)player == (Object)null || DeadSetField == null) { return; } bool flag; try { flag = (bool)DeadSetField.GetValue(player); } catch (Exception ex) { LogErrorOnce("No se pudo leer PlayerAvatar.deadSet: " + ex); return; } if (flag) { if (observedDead.Add(player)) { LogInfo("Update del jugador detectó deadSet=true, avatar=" + ((Object)player).GetInstanceID() + "."); OnPlayerDeath(player, "PlayerAvatar.Update/deadSet"); } } else { observedDead.Remove(player); } } internal static void OnPlayerDeath(PlayerAvatar player, string source) { if ((Object)(object)player == (Object)null) { LogWarning("Hook de muerte " + source + " recibió un PlayerAvatar nulo."); return; } observedDead.Add(player); bool flag = SemiFunc.IsMultiplayer(); bool isMasterClient = PhotonNetwork.IsMasterClient; int instanceID = ((Object)player).GetInstanceID(); LogInfo("Muerte detectada por " + source + ", avatar=" + instanceID + ", multiplayer=" + flag + ", masterClient=" + isMasterClient + "."); string disabledLocation = GetDisabledLocation(); if (disabledLocation != null) { pending.Remove(player); LogInfo("Auto Respawn desactivado: muerte en " + disabledLocation + ", avatar=" + instanceID + "."); return; } if (flag && !isMasterClient) { LogInfo("No inicia cuenta atrás para avatar=" + instanceID + " porque este cliente no es el anfitrión."); return; } if (!pending.Add(player)) { LogInfo("Ya había una cuenta atrás pendiente para avatar=" + instanceID + "."); return; } GameDirector instance = GameDirector.instance; if ((Object)(object)instance == (Object)null) { pending.Remove(player); LogError("No se pudo iniciar el contador: GameDirector.instance es nulo."); return; } int value = AutoRespawnPlugin.RespawnTime.Value; int value2 = AutoRespawnPlugin.RespawnHealth.Value; int announcementDelay = 5; LogInfo("Inicia cuenta atrás de " + value + " segundos para avatar=" + instanceID + " usando GameDirector."); ((MonoBehaviour)instance).StartCoroutine(RespawnCountdown(player, value, value2, announcementDelay)); } private static IEnumerator RespawnCountdown(PlayerAvatar player, int countdownSeconds, int targetHealth, int announcementDelay) { int avatarId = (((Object)(object)player != (Object)null) ? ((Object)player).GetInstanceID() : 0); LogInfo("Coroutine de cuenta atrás iniciada para avatar=" + avatarId + ", duración=" + countdownSeconds + " s, vida objetivo=" + targetHealth + " HP, primer aviso después de " + announcementDelay + " s."); List<int> announcements = GetAnnouncementTimes(countdownSeconds, announcementDelay); float num = 0f; for (int i = 0; i < announcements.Count; i++) { int seconds = announcements[i]; float targetElapsed = ((seconds == countdownSeconds) ? announcementDelay : (countdownSeconds - seconds)); float num2 = targetElapsed - num; if (num2 > 0f) { yield return (object)new WaitForSecondsRealtime(num2); num = targetElapsed; } if (!IsCountdownActive(player, avatarId, seconds) || !SendCountdownMessage(player, avatarId, seconds)) { yield break; } } float num3 = (float)countdownSeconds - num; if (num3 > 0f) { yield return (object)new WaitForSecondsRealtime(num3); } if (!IsCountdownActive(player, avatarId, 0)) { pending.Remove(player); LogInfo("La cuenta atrás terminó/canceló antes de revivir avatar=" + avatarId + "."); yield break; } try { player.Revive(false); LogInfo("Revive(false) llamado para avatar=" + avatarId + "."); } catch (Exception ex) { LogError("Revive(false) falló para avatar=" + avatarId + ": " + ex); } LogInfo("Esperando 0.25 s antes de solicitar curación para avatar=" + avatarId + "."); yield return (object)new WaitForSecondsRealtime(0.25f); try { if ((Object)(object)player != (Object)null && (Object)(object)player.playerHealth != (Object)null) { LogInfo("Solicitando HealOther(" + (targetHealth - 1) + ") para avatar=" + avatarId + " con objetivo de " + targetHealth + " HP."); player.playerHealth.HealOther(targetHealth - 1, true); LogInfo("HealOther terminó sin excepción para avatar=" + avatarId + "."); } else { LogWarning("No se aplicó curación: avatar o PlayerHealth nulo para avatar=" + avatarId + "."); } LogInfo("Flujo de revive completado para avatar=" + avatarId + "."); } catch (Exception ex2) { LogError("Falló el flujo de curación para avatar=" + avatarId + ": " + ex2); } bool flag = pending.Remove(player); LogInfo("Limpieza de cuenta atrás para avatar=" + avatarId + "; entrada pendiente eliminada=" + flag + "."); } private static List<int> GetAnnouncementTimes(int countdownSeconds, int announcementDelay) { List<int> list = new List<int> { countdownSeconds }; int[] array = new int[5] { 60, 40, 20, 10, 5 }; foreach (int num in array) { float num2 = countdownSeconds - num; if (num < countdownSeconds && num2 > (float)announcementDelay && !list.Contains(num)) { list.Add(num); } } list.Sort((int left, int right) => right.CompareTo(left)); return list; } private static bool IsCountdownActive(PlayerAvatar player, int avatarId, int seconds) { if ((Object)(object)player != (Object)null && pending.Contains(player)) { string disabledLocation = GetDisabledLocation(); if (disabledLocation == null) { return true; } pending.Remove(player); LogInfo("Cuenta atrás cancelada para avatar=" + avatarId + " al entrar en " + disabledLocation + "."); return false; } if ((Object)(object)player == (Object)null) { pending.Remove(player); } LogInfo("Cuenta atrás detenida para avatar=" + avatarId + " antes del aviso de " + seconds + " segundos."); return false; } private static string GetDisabledLocation() { try { if (SemiFunc.RunIsArena()) { return "arena"; } if (SemiFunc.RunIsShop()) { return "shop"; } } catch (Exception ex) { if (!zoneCheckErrorLogged) { zoneCheckErrorLogged = true; LogWarning("No se pudo comprobar si la zona es arena o tienda: " + ex); } } return null; } private static bool SendCountdownMessage(PlayerAvatar player, int avatarId, int seconds) { if ((Object)(object)player == (Object)null || !pending.Contains(player)) { LogInfo("No se envió el aviso de " + seconds + " segundos porque la cuenta atrás ya no está activa para avatar=" + avatarId + "."); return false; } string text = "Respawn in " + seconds + " seconds"; LogInfo("Enviando aviso de cuenta atrás para avatar=" + avatarId + ": " + text + "."); try { player.ChatMessageSend(text); LogInfo("ChatMessageSend terminó sin excepción para avatar=" + avatarId + ", aviso=" + seconds + " segundos."); return true; } catch (Exception ex) { LogWarning("Falló el aviso de " + seconds + " segundos para avatar=" + avatarId + ": " + ex); return true; } } internal static void OnPlayerRevived(PlayerAvatar player) { if ((Object)(object)player != (Object)null) { bool flag = pending.Remove(player); LogInfo("Hook ReviveRPC para avatar=" + ((Object)player).GetInstanceID() + "; cuenta atrás pendiente eliminada=" + flag + "."); } else { LogWarning("Hook ReviveRPC recibió un PlayerAvatar nulo."); } } private static void LogInfo(string message) { if (AutoRespawnPlugin.LogSource != null) { AutoRespawnPlugin.LogSource.LogInfo((object)message); } } private static void LogWarning(string message) { if (AutoRespawnPlugin.LogSource != null) { AutoRespawnPlugin.LogSource.LogWarning((object)message); } } private static void LogError(string message) { if (AutoRespawnPlugin.LogSource != null) { AutoRespawnPlugin.LogSource.LogError((object)message); } } private static void LogErrorOnce(string message) { if (!deadSetErrorLogged) { deadSetErrorLogged = true; LogError(message); } } } [HarmonyPatch] internal static class PlayerAvatarUpdateDeathPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(PlayerAvatar), "Update", (Type[])null, (Type[])null); } private static void Postfix(PlayerAvatar __instance) { AutoRespawnController.CheckDeadState(__instance); } } [HarmonyPatch] internal static class PlayerDeathPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(PlayerAvatar), "PlayerDeath", new Type[1] { typeof(int) }, (Type[])null); } private static void Postfix(PlayerAvatar __instance) { AutoRespawnController.OnPlayerDeath(__instance, "PlayerDeath"); } } [HarmonyPatch] internal static class PlayerDeathRpcPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(PlayerAvatar), "PlayerDeathRPC", (Type[])null, (Type[])null); } private static void Postfix(PlayerAvatar __instance) { AutoRespawnController.OnPlayerDeath(__instance, "PlayerDeathRPC"); } } [HarmonyPatch] internal static class PlayerDeathDonePatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(PlayerAvatar), "PlayerDeathDone", (Type[])null, (Type[])null); } private static void Prefix(PlayerAvatar __instance) { AutoRespawnController.OnPlayerDeath(__instance, "PlayerDeathDone"); } } [HarmonyPatch] internal static class PlayerRevivePatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(PlayerAvatar), "ReviveRPC", (Type[])null, (Type[])null); } private static void Postfix(PlayerAvatar __instance) { AutoRespawnController.OnPlayerRevived(__instance); } } }