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.0", "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<TimerBehaviour>();
GameObject val = new GameObject("POGTimerRunner");
Object.DontDestroyOnLoad((Object)val);
((Object)val).hideFlags = (HideFlags)61;
val.AddComponent<TimerBehaviour>();
MelonLogger.Msg("POG Timer 1.0.0 (MelonLoader) loaded.");
}
}
public class TimerBehaviour : MonoBehaviour
{
private const float PollInterval = 0.25f;
private const uint PayloadMagic = 1413959504u;
private static bool s_unnamedHooked;
private static UnnamedMessageDelegate 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;
try
{
EnsureUnnamedHook();
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
{
ClearDisplay();
}
}
private static void EnsureUnnamedHook()
{
if (!s_unnamedHooked)
{
NetworkManager singleton = NetworkManager.Singleton;
if (!((Object)(object)singleton == (Object)null))
{
MethodInfo method = typeof(TimerBehaviour).GetMethod("OnUnnamedModMessage", BindingFlags.Static | BindingFlags.NonPublic);
s_unnamedDelegate = UnnamedMessageDelegate.op_Implicit((Action<ulong, FastBufferReader>)Delegate.CreateDelegate(typeof(UnnamedMessageDelegate), method));
CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
customMessagingManager.OnUnnamedMessage += s_unnamedDelegate;
s_unnamedHooked = true;
MelonLogger.Msg("[POGTimer] Subscribed to Netcode unnamed messages (sync for clients).");
}
}
}
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();
BroadcastUnnamed(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);
BroadcastUnnamed(nm, active: true, Mathf.Max(0f, num), instance.m_playedWarning);
}
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);
}
}
}
}