using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using HarmonyLib; using Mirror; using TMPro; using UnityEngine; using UnityEngine.UI; using YAPYAP; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("speedrunchrono")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("speedrunchrono")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("6cd78860-c1c2-4a61-a3a2-ce05ca1f4adf")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace SpeedrunChrono; public static class ChronoManager { private static readonly Dictionary PlayerTimers = new Dictionary(); private static Pawn localPawn; private static GameObject chronoCanvasObject; private static Canvas chronoCanvas; private static TMP_Text localChronoText; private static bool chronoStarted = false; public static void RegisterPlayer(Pawn pawn) { if ((Object)(object)pawn == (Object)null) { return; } int playerNetId = pawn.PlayerNetId; if (playerNetId >= 0) { if (!PlayerTimers.ContainsKey(playerNetId)) { PlayerTimers[playerNetId] = 0f; Debug.Log((object)("[SpeedrunChrono] Nouveau joueur enregistré : " + pawn.PlayerName + " (" + playerNetId + ")")); } if (((NetworkBehaviour)pawn).isLocalPlayer) { localPawn = pawn; CreateHUD(); Debug.Log((object)"[SpeedrunChrono] Joueur local enregistré."); } } } public static void UnregisterPlayer(Pawn pawn) { if (!((Object)(object)pawn == (Object)null)) { int playerNetId = pawn.PlayerNetId; if (playerNetId >= 0) { PlayerTimers.Remove(playerNetId); } if (((NetworkBehaviour)pawn).isLocalPlayer) { localPawn = null; RemoveHUD(); Debug.Log((object)"[SpeedrunChrono] Joueur local déconnecté."); } } } public static void Update() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Invalid comparison between Unknown and I4 if ((Object)(object)localPawn == (Object)null) { TryFindLocalPawn(); if ((Object)(object)localPawn == (Object)null) { return; } } int playerNetId = localPawn.PlayerNetId; if (playerNetId < 0) { return; } if (!PlayerTimers.ContainsKey(playerNetId)) { PlayerTimers[playerNetId] = 0f; } if (!chronoStarted && (Object)(object)GameManager.Instance != (Object)null) { GameState networkcurrentGameState = GameManager.Instance.NetworkcurrentGameState; if ((int)networkcurrentGameState == 1) { chronoStarted = true; Debug.Log((object)"[SpeedrunChrono] Première nuit détectée : chrono démarré."); } } if (chronoStarted) { PlayerTimers[playerNetId] += Time.deltaTime; } EnsureHUD(); UpdateHUD(); } private static void TryFindLocalPawn() { if ((Object)(object)GameManager.Instance == (Object)null) { return; } Pawn[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Pawn val in array) { if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).isLocalPlayer) { localPawn = val; int playerNetId = val.PlayerNetId; if (playerNetId >= 0 && !PlayerTimers.ContainsKey(playerNetId)) { PlayerTimers[playerNetId] = 0f; } CreateHUD(); Debug.Log((object)("[SpeedrunChrono] Pawn local trouvé automatiquement : " + val.PlayerName)); break; } } } private static void CreateHUD() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)localChronoText != (Object)null) { ((Component)localChronoText).gameObject.SetActive(true); return; } chronoCanvasObject = new GameObject("SpeedrunChronoCanvas"); Object.DontDestroyOnLoad((Object)(object)chronoCanvasObject); chronoCanvas = chronoCanvasObject.AddComponent(); chronoCanvas.renderMode = (RenderMode)0; chronoCanvas.sortingOrder = 32767; CanvasScaler val = chronoCanvasObject.AddComponent(); val.uiScaleMode = (ScaleMode)1; val.referenceResolution = new Vector2(1920f, 1080f); val.screenMatchMode = (ScreenMatchMode)0; val.matchWidthOrHeight = 0.5f; chronoCanvasObject.AddComponent(); GameObject val2 = new GameObject("SpeedrunChronoText"); val2.transform.SetParent(((Component)chronoCanvas).transform, false); localChronoText = (TMP_Text)(object)val2.AddComponent(); TMP_Text val3 = FindGameFont(); if ((Object)(object)val3 != (Object)null) { localChronoText.font = val3.font; localChronoText.fontSize = val3.fontSize; localChronoText.fontStyle = val3.fontStyle; ((Graphic)localChronoText).color = ((Graphic)val3).color; } else { localChronoText.fontSize = 32f; localChronoText.fontStyle = (FontStyles)0; ((Graphic)localChronoText).color = Color.white; } localChronoText.alignment = (TextAlignmentOptions)4097; ((Graphic)localChronoText).raycastTarget = false; localChronoText.textWrappingMode = (TextWrappingModes)0; localChronoText.overflowMode = (TextOverflowModes)0; localChronoText.text = "00:00"; RectTransform rectTransform = localChronoText.rectTransform; rectTransform.anchorMin = new Vector2(0f, 0.5f); rectTransform.anchorMax = new Vector2(0f, 0.5f); rectTransform.pivot = new Vector2(0f, 0.5f); rectTransform.anchoredPosition = new Vector2(30f, 0f); rectTransform.sizeDelta = new Vector2(500f, 100f); localChronoText.enableAutoSizing = false; if (localChronoText.fontSize < 30f) { localChronoText.fontSize = 30f; } ((Component)localChronoText).gameObject.SetActive(true); localChronoText.transform.SetAsLastSibling(); Canvas.ForceUpdateCanvases(); Debug.Log((object)"[SpeedrunChrono] HUD créé indépendamment du HUD du jeu."); } private static TMP_Text FindGameFont() { TMP_Text[] array = Object.FindObjectsByType((FindObjectsSortMode)0); TMP_Text[] array2 = array; foreach (TMP_Text val in array2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.font == (Object)null)) { string text = ((Object)((Component)val).gameObject).name.ToLower(); if (text.Contains("player") || text.Contains("name") || text.Contains("chat") || text.Contains("text")) { return val; } } } TMP_Text[] array3 = array; foreach (TMP_Text val2 in array3) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.font != (Object)null) { return val2; } } return null; } private static void EnsureHUD() { if ((Object)(object)chronoCanvasObject == (Object)null || (Object)(object)chronoCanvas == (Object)null || (Object)(object)localChronoText == (Object)null) { CreateHUD(); } if ((Object)(object)localChronoText != (Object)null && !((Component)localChronoText).gameObject.activeSelf) { ((Component)localChronoText).gameObject.SetActive(true); } } private static void UpdateHUD() { if (!((Object)(object)localChronoText == (Object)null) && !((Object)(object)localPawn == (Object)null)) { int playerNetId = localPawn.PlayerNetId; if (!PlayerTimers.TryGetValue(playerNetId, out var value)) { value = 0f; } int num = Mathf.FloorToInt(value); int num2 = num / 60; int num3 = num % 60; localChronoText.text = $"{num2:00}:{num3:00}"; } } public static void ResetPlayer(int playerId) { if (playerId >= 0) { PlayerTimers[playerId] = 0f; Debug.Log((object)("[SpeedrunChrono] Chrono réinitialisé pour le joueur " + playerId)); UpdateHUD(); } } public static void ResetAll() { PlayerTimers.Clear(); localPawn = null; chronoStarted = false; RemoveHUD(); Debug.Log((object)"[SpeedrunChrono] Tous les chronos ont été réinitialisés."); } private static void RemoveHUD() { if ((Object)(object)chronoCanvasObject != (Object)null) { Object.Destroy((Object)(object)chronoCanvasObject); } chronoCanvasObject = null; chronoCanvas = null; localChronoText = null; } } [BepInPlugin("Xemotal.SpeedrunChrono", "Speedrun Chrono", "1.0.0")] public class SpeedrunChronoPlugin : BaseUnityPlugin { private Harmony harmony; private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown harmony = new Harmony("Xemotal.SpeedrunChrono"); harmony.PatchAll(); Debug.Log((object)"[SpeedrunChrono] Mod chargé."); } private void Update() { ChronoManager.Update(); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } ChronoManager.ResetAll(); } } [HarmonyPatch(typeof(Pawn), "OnStartClient")] public static class PawnStartClientPatch { [HarmonyPostfix] private static void Postfix(Pawn __instance) { if (!((Object)(object)__instance == (Object)null)) { ChronoManager.RegisterPlayer(__instance); } } } [HarmonyPatch(typeof(Pawn), "OnStopClient")] public static class PawnStopClientPatch { [HarmonyPostfix] private static void Postfix(Pawn __instance) { if (!((Object)(object)__instance == (Object)null)) { ChronoManager.UnregisterPlayer(__instance); } } }