using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("TimerRevive")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("TimerRevive")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("eb16fe60-8e2a-414a-9102-3de2d61c2cda")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace TimerRevive; [BepInPlugin("yazirushi.TimerRevive", "TimerRevive", "1.0.1")] public class TimerRevive : BaseUnityPlugin { public enum Scaling_type { Add, Multiply } public enum Language { English, Japanese } private readonly Harmony harmony = new Harmony("yazirushi.TimerRevive"); internal static ManualLogSource mls; public static ConfigEntry ReviveTime; public static ConfigEntry ScalingType; public static ConfigEntry ScalingValue; public static ConfigEntry UI_Language; public static ConfigEntry UIText_Offset_X; public static ConfigEntry UIText_Offset_Y; public static ConfigEntry UIText_FontSize; public static ConfigEntry UIText_Color; public static ConfigEntry DebugLog; public static Canvas canvas; public static TextMeshProUGUI text; public static void CreateUI() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("TimerReviveCanvas"); canvas = val.AddComponent(); canvas.renderMode = (RenderMode)0; canvas.worldCamera = null; canvas.sortingOrder = 999; canvas.scaleFactor = 1f; CanvasScaler val2 = val.AddComponent(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = new Vector2(1920f, 1080f); val2.matchWidthOrHeight = 1f; val.AddComponent(); Object.DontDestroyOnLoad((Object)(object)val); GameObject val3 = new GameObject("TimerReviveText"); val3.transform.SetParent(val.transform); text = val3.AddComponent(); TMP_FontAsset tekoFont = FontUtil.GetTekoFont(); if ((Object)(object)tekoFont != (Object)null) { ((TMP_Text)text).font = tekoFont; ((TMP_Text)text).fontMaterial = FontUtil.GetTekoMaterial(); } ((TMP_Text)text).enableWordWrapping = false; ((TMP_Text)text).overflowMode = (TextOverflowModes)0; ((TMP_Text)text).alignment = (TextAlignmentOptions)1026; ((TMP_Text)text).rectTransform.anchorMin = new Vector2(1f, 0f); ((TMP_Text)text).rectTransform.anchorMax = new Vector2(1f, 0f); ((TMP_Text)text).rectTransform.pivot = new Vector2(1f, 0f); ((TMP_Text)text).rectTransform.anchoredPosition = Vector2.zero; ((TMP_Text)text).rectTransform.sizeDelta = new Vector2(400f, 200f); if (DebugLog.Value) { mls.LogInfo((object)"CreateUI!"); } } public static void UpdateUI(float time) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) switch (UI_Language.Value) { case Language.English: ((TMP_Text)text).text = $"Revive in {(int)time + 1} seconds"; break; case Language.Japanese: ((TMP_Text)text).text = $"{(int)time + 1}秒後に復活します!"; break; } ((TMP_Text)text).fontSize = UIText_FontSize.Value; ((Graphic)text).color = Color.white; ((TMP_Text)text).rectTransform.anchoredPosition = new Vector2(UIText_Offset_X.Value, UIText_Offset_Y.Value); if (DebugLog.Value) { mls.LogInfo((object)"UpdateUI!"); } } private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown ReviveTime = ((BaseUnityPlugin)this).Config.Bind("Revive Settings", "Revive Time", 30f, new ConfigDescription("Base time required for revival", (AcceptableValueBase)null, Array.Empty())); ScalingType = ((BaseUnityPlugin)this).Config.Bind("Revive Settings", "Scaling Type", Scaling_type.Add, new ConfigDescription("How it increases", (AcceptableValueBase)null, Array.Empty())); ScalingValue = ((BaseUnityPlugin)this).Config.Bind("Revive Settings", "Scaling value", 15f, new ConfigDescription("Increasing value(We recommend reading the README.)", (AcceptableValueBase)null, Array.Empty())); UI_Language = ((BaseUnityPlugin)this).Config.Bind("UI Settings", "Language", Language.English, new ConfigDescription("Language used in UI text", (AcceptableValueBase)null, Array.Empty())); UIText_Offset_X = ((BaseUnityPlugin)this).Config.Bind("UI Settings", "X Offset", 0f, new ConfigDescription("X-axis offset", (AcceptableValueBase)null, Array.Empty())); UIText_Offset_Y = ((BaseUnityPlugin)this).Config.Bind("UI Settings", "Y Offset", 0f, new ConfigDescription("Y-axis offset", (AcceptableValueBase)null, Array.Empty())); UIText_FontSize = ((BaseUnityPlugin)this).Config.Bind("UI Settings", "Text Size", 50f, new ConfigDescription("UI text size", (AcceptableValueBase)null, Array.Empty())); DebugLog = ((BaseUnityPlugin)this).Config.Bind("DebugLog", "EnableLogging", false, new ConfigDescription("Display the logs used during debugging", (AcceptableValueBase)null, Array.Empty())); mls = ((BaseUnityPlugin)this).Logger; mls.LogInfo((object)"Starting TimerRevive..."); harmony.PatchAll(); } } public class FontUtil { private static TMP_FontAsset cachedFont; private static Material cachedMat; public static TMP_FontAsset GetTekoFont() { if ((Object)(object)cachedFont != (Object)null) { return cachedFont; } TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll(); foreach (TMP_FontAsset val in array) { if (((Object)val).name.Contains("Teko") && ((Object)val).name.Contains("SDF")) { cachedFont = val; cachedMat = ((TMP_Asset)val).material; return cachedFont; } } return null; } public static Material GetTekoMaterial() { return cachedMat; } } [HarmonyPatch(typeof(PlayerDeathHead), "Update")] public class TimerUpdate { private class ReviveState { public float reviveTimer = 0f; public float waitTimer = 0f; public int reviveCount = 0; public bool isdead = false; public bool timerReset = false; } private static readonly FieldInfo deathHead = AccessTools.Field(typeof(PlayerAvatar), "playerDeathHead"); private static readonly FieldInfo isDead = AccessTools.Field(typeof(PlayerDeathHead), "triggered"); private static Dictionary reviveStates = new Dictionary(); internal static float reviveTimer_local = 0f; private static float waitTimer_local = 0f; private static int reviveCount_local = 0; private static bool timerReset_local = false; private static bool createdUI = false; public static void Postfix(PlayerDeathHead __instance) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if ((Object)(object)__instance.playerAvatar != (Object)(object)PlayerAvatar.instance) { return; } if (SemiFunc.IsMasterClientOrSingleplayer()) { PlayerAvatar val = null; foreach (PlayerAvatar item in SemiFunc.PlayerGetAll()) { if ((Object)(object)item == (Object)null) { continue; } PlayerDeathHead val2 = (PlayerDeathHead)deathHead.GetValue(item); if ((Object)(object)val2 == (Object)null) { continue; } if ((Object)(object)__instance.playerAvatar == (Object)(object)item) { val = item; } if (!reviveStates.TryGetValue(item, out var value)) { value = new ReviveState { reviveTimer = TimerRevive.ReviveTime.Value, waitTimer = 5f, reviveCount = 0, isdead = false, timerReset = false }; reviveStates.Add(item, value); } value.isdead = (bool)isDead.GetValue(val2); if (!value.isdead) { value.timerReset = false; } else { if (!value.isdead) { continue; } if (!value.timerReset) { value.timerReset = true; switch (TimerRevive.ScalingType.Value) { case TimerRevive.Scaling_type.Add: value.reviveTimer = TimerRevive.ReviveTime.Value + TimerRevive.ScalingValue.Value * (float)value.reviveCount; break; case TimerRevive.Scaling_type.Multiply: value.reviveTimer = TimerRevive.ReviveTime.Value * (float)Math.Pow(TimerRevive.ScalingValue.Value, value.reviveCount); break; } value.waitTimer = 5f; } value.waitTimer -= Time.deltaTime; if (value.waitTimer <= 0f) { value.reviveTimer -= Time.deltaTime; if (value.reviveTimer <= 0f && value.timerReset) { value.timerReset = false; value.reviveCount++; item.Revive(false); } } } } reviveStates.Keys.Where((PlayerAvatar p) => (Object)(object)p == (Object)null || !SemiFunc.PlayerGetAll().Contains(p)).ToList().ForEach(delegate(PlayerAvatar p) { reviveStates.Remove(p); }); if (!((Object)(object)val != (Object)null) || !reviveStates.TryGetValue(val, out var value2)) { return; } if (value2.isdead) { if (value2.waitTimer <= 0f && value2.timerReset) { if (!createdUI) { createdUI = true; TimerRevive.CreateUI(); } if ((Object)(object)TimerRevive.canvas == (Object)null) { createdUI = false; } if ((Object)(object)TimerRevive.canvas != (Object)null) { ((Behaviour)TimerRevive.canvas).enabled = true; } TimerRevive.UpdateUI(value2.reviveTimer); } } else if ((Object)(object)TimerRevive.canvas != (Object)null) { ((Behaviour)TimerRevive.canvas).enabled = false; } } else if ((bool)isDead.GetValue(__instance)) { if (!timerReset_local) { timerReset_local = true; switch (TimerRevive.ScalingType.Value) { case TimerRevive.Scaling_type.Add: reviveTimer_local = TimerRevive.ReviveTime.Value + TimerRevive.ScalingValue.Value * (float)reviveCount_local; break; case TimerRevive.Scaling_type.Multiply: reviveTimer_local = TimerRevive.ReviveTime.Value * (float)Math.Pow(TimerRevive.ScalingValue.Value, reviveCount_local); break; } waitTimer_local = 5f; } waitTimer_local -= Time.deltaTime; if (!(waitTimer_local <= 0f)) { return; } reviveTimer_local -= Time.deltaTime; if (!createdUI) { createdUI = true; TimerRevive.CreateUI(); } if ((Object)(object)TimerRevive.canvas == (Object)null) { createdUI = false; } if ((Object)(object)TimerRevive.canvas != (Object)null) { ((Behaviour)TimerRevive.canvas).enabled = true; } TimerRevive.UpdateUI(reviveTimer_local); if (reviveTimer_local <= 0f && timerReset_local) { timerReset_local = false; if ((Object)(object)TimerRevive.canvas != (Object)null) { ((Behaviour)TimerRevive.canvas).enabled = false; } reviveCount_local++; } } else { timerReset_local = false; if ((Object)(object)TimerRevive.canvas != (Object)null) { ((Behaviour)TimerRevive.canvas).enabled = false; } } } public static void ResetAllReviveCounts() { if (SemiFunc.IsMasterClientOrSingleplayer()) { reviveStates.Clear(); } else { reviveCount_local = 0; } } } [HarmonyPatch(typeof(GameDirector), "gameStateStart")] internal class ReviveCountReset { private static void Postfix(GameDirector __instance) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)__instance.currentState == 2) { TimerUpdate.ResetAllReviveCounts(); if (TimerRevive.DebugLog.Value) { TimerRevive.mls.LogInfo((object)"The state has been reset"); } } } }