using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Il2CppGame.Gameplay; using Il2CppInterop.Runtime.Injection; using MelonLoader; using POGMods.Timer; using Unity.Collections; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(PogTimerMelon), "POG Timer", "1.0.1", "largo", "")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("POGTimer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("POGTimer")] [assembly: AssemblyTitle("POGTimer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace POGMods.Timer; public class PogTimerMelon : MelonMod { public override void OnInitializeMelon() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0015: Unknown result type (might be due to invalid IL or missing references) ClassInjector.RegisterTypeInIl2Cpp(); GameObject val = new GameObject("POGTimerRunner"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent(); MelonLogger.Msg("POG Timer 1.0.1 (MelonLoader) loaded."); } } public class TimerBehaviour : MonoBehaviour { private const float PollInterval = 0.25f; private const uint PayloadMagic = 1413959504u; private static bool s_unnamedHooked; private static Action s_unnamedDelegate; private static float s_netRemaining; private static bool s_netPlayedWarning; private static bool s_netRoundActive; private static bool s_hasNetworkSnapshot; private float _pollAccum; private GUIStyle _style; private GUIStyle _shadowStyle; private GUIStyle _smallStyle; private GUIStyle _smallShadowStyle; private string _timerText = ""; private string _phaseText = ""; private bool _loggedHostOnce; public TimerBehaviour(IntPtr ptr) : base(ptr) { } private void Update() { _pollAccum += Time.deltaTime; if (_pollAccum < 0.25f) { return; } _pollAccum = 0f; if (!s_unnamedHooked) { try { EnsureUnnamedHook(); } catch (Exception ex) { MelonLogger.Warning("[POGTimer] Hook failed: " + ex.Message); } } try { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsServer) { TickAuthority(singleton); } else if ((Object)(object)singleton != (Object)null && singleton.IsClient && !singleton.IsServer) { TickRemoteClient(); } else { TickOfflineOrNoNetwork(); } } catch (Exception ex2) { MelonLogger.Error("[POGTimer] Update error: " + ex2.Message + "\n" + ex2.StackTrace); ClearDisplay(); } } private static void EnsureUnnamedHook() { if (!s_unnamedHooked) { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null)) { s_unnamedDelegate = OnUnnamedModMessage; CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; customMessagingManager.OnUnnamedMessage += UnnamedMessageDelegate.op_Implicit(s_unnamedDelegate); s_unnamedHooked = true; MelonLogger.Msg("[POGTimer] Subscribed to Netcode unnamed messages."); } } } private static void OnUnnamedModMessage(ulong senderClientId, FastBufferReader reader) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((!((Object)(object)NetworkManager.Singleton != (Object)null) || !NetworkManager.Singleton.IsServer) && senderClientId == NetworkManager.ServerClientId && ReadUInt32LE(reader) == 1413959504) { float num = BitConverter.UInt32BitsToSingle(ReadUInt32LE(reader)); byte b = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b); s_netRoundActive = (b & 1) != 0; s_netPlayedWarning = (b & 2) != 0; s_netRemaining = num; s_hasNetworkSnapshot = true; } } private static uint ReadUInt32LE(FastBufferReader reader) { byte b = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b); byte b2 = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b2); byte b3 = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b3); byte b4 = default(byte); ((FastBufferReader)(ref reader)).ReadByteSafe(ref b4); return (uint)(b | (b2 << 8) | (b3 << 16) | (b4 << 24)); } private static void WriteHeader(FastBufferWriter writer, uint value) { ((FastBufferWriter)(ref writer)).WriteByteSafe((byte)(value & 0xFFu)); ((FastBufferWriter)(ref writer)).WriteByteSafe((byte)((value >> 8) & 0xFFu)); ((FastBufferWriter)(ref writer)).WriteByteSafe((byte)((value >> 16) & 0xFFu)); ((FastBufferWriter)(ref writer)).WriteByteSafe((byte)((value >> 24) & 0xFFu)); } private static void WriteFloatBits(FastBufferWriter writer, float value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) uint value2 = BitConverter.SingleToUInt32Bits(value); WriteHeader(writer, value2); } private void TickAuthority(NetworkManager nm) { s_hasNetworkSnapshot = false; GameMode_Round instance = GameMode_Round.Instance; if ((Object)(object)instance == (Object)null || !instance.m_gameStarted) { ClearDisplay(); TryBroadcastUnnamed(nm, active: false, 0f, playedWarning: false); return; } float elapsedGameTime = instance.ElapsedGameTime; float roundTime = instance.RoundTime; float num = roundTime - elapsedGameTime; if (!_loggedHostOnce) { MelonLogger.Msg($"[POGTimer] Host round sync: total={roundTime}s, elapsed={elapsedGameTime:F1}s"); _loggedHostOnce = true; } ApplyDisplayFromRound(num, instance.m_playedWarning); TryBroadcastUnnamed(nm, active: true, Mathf.Max(0f, num), instance.m_playedWarning); } private static void TryBroadcastUnnamed(NetworkManager nm, bool active, float remaining, bool playedWarning) { try { BroadcastUnnamed(nm, active, remaining, playedWarning); } catch (Exception ex) { MelonLogger.Warning("[POGTimer] Broadcast skipped: " + ex.Message); } } private static void BroadcastUnnamed(NetworkManager nm, bool active, float remaining, bool playedWarning) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) byte b = 0; if (active) { b = (byte)(b | 1u); } if (playedWarning) { b = (byte)(b | 2u); } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(32, (Allocator)2, -1); try { WriteHeader(val, 1413959504u); WriteFloatBits(val, remaining); ((FastBufferWriter)(ref val)).WriteByteSafe(b); nm.CustomMessagingManager.SendUnnamedMessageToAll(val, (NetworkDelivery)2); } finally { ((FastBufferWriter)(ref val)).Dispose(); } } private void TickRemoteClient() { if (!s_hasNetworkSnapshot || !s_netRoundActive) { ClearDisplay(); } else { ApplyDisplayFromNetwork(s_netRemaining, s_netPlayedWarning); } } private void TickOfflineOrNoNetwork() { s_hasNetworkSnapshot = false; GameMode_Round instance = GameMode_Round.Instance; if ((Object)(object)instance == (Object)null || !instance.m_gameStarted) { ClearDisplay(); return; } float elapsedGameTime = instance.ElapsedGameTime; float remaining = instance.RoundTime - elapsedGameTime; ApplyDisplayFromRound(remaining, instance.m_playedWarning); } private void ApplyDisplayFromRound(float remaining, bool playedWarning) { if (remaining <= 0f) { _timerText = "00:00"; _phaseText = "TIME'S UP"; return; } int value = (int)(remaining / 60f); int value2 = (int)(remaining % 60f); _timerText = $"{value:D2}:{value2:D2}"; if (remaining < 60f) { _phaseText = "HURRY!"; } else if (playedWarning) { _phaseText = "WARNING"; } else { _phaseText = ""; } } private void ApplyDisplayFromNetwork(float remaining, bool playedWarning) { if (remaining <= 0f) { _timerText = "00:00"; _phaseText = "TIME'S UP"; return; } int value = (int)(remaining / 60f); int value2 = (int)(remaining % 60f); _timerText = $"{value:D2}:{value2:D2}"; if (remaining < 60f) { _phaseText = "HURRY!"; } else if (playedWarning) { _phaseText = "WARNING"; } else { _phaseText = ""; } } private void ClearDisplay() { _timerText = ""; _phaseText = ""; } private void OnGUI() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(_timerText)) { if (_style == null) { _style = new GUIStyle(GUI.skin.label); _style.fontSize = 30; _style.fontStyle = (FontStyle)1; _style.alignment = (TextAnchor)2; _style.normal.textColor = Color.white; _shadowStyle = new GUIStyle(_style); _shadowStyle.normal.textColor = new Color(0f, 0f, 0f, 0.7f); _smallStyle = new GUIStyle(GUI.skin.label); _smallStyle.fontSize = 16; _smallStyle.fontStyle = (FontStyle)1; _smallStyle.alignment = (TextAnchor)2; _smallStyle.normal.textColor = new Color(1f, 0.8f, 0.3f); _smallShadowStyle = new GUIStyle(_smallStyle); _smallShadowStyle.normal.textColor = new Color(0f, 0f, 0f, 0.7f); } bool flag = _phaseText == "HURRY!" || _phaseText == "TIME'S UP"; _style.normal.textColor = (flag ? Color.red : Color.white); float num = 200f; float num2 = (float)Screen.width - num - 20f; float num3 = 15f; GUI.Label(new Rect(num2 + 2f, num3 + 2f, num, 40f), _timerText, _shadowStyle); GUI.Label(new Rect(num2, num3, num, 40f), _timerText, _style); if (!string.IsNullOrEmpty(_phaseText)) { GUI.Label(new Rect(num2 + 2f, num3 + 36f, num, 25f), _phaseText, _smallShadowStyle); GUI.Label(new Rect(num2, num3 + 34f, num, 25f), _phaseText, _smallStyle); } } } }