Decompiled source of CloverPitRPC v2.0.1

CloverPitRPC.dll

Decompiled a month ago
using System;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("QOLImprovementsCloverpit")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("QOLImprovementsCloverpit")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7647f865-26ed-4efd-8e2c-eff13b732133")]
[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 QOLImprovementsCloverpit;

[BepInPlugin("com.dylan.cloverpit.discordrpc", "Cloverpit Discord RPC", "2.0.1")]
public class QOLImprovementsPlugin : BaseUnityPlugin
{
	private const string PluginGUID = "com.dylan.cloverpit.discordrpc";

	private const string PluginName = "Cloverpit Discord RPC";

	private const string PluginVersion = "2.0.1";

	internal static ManualLogSource logger;

	private DiscordRpcManager discordManager;

	private void Awake()
	{
		logger = ((BaseUnityPlugin)this).Logger;
		discordManager = ((Component)this).gameObject.AddComponent<DiscordRpcManager>();
		logger.LogInfo((object)"Cloverpit Discord RPC v2.0.1 loaded!");
	}

	private void OnDestroy()
	{
		if ((Object)(object)discordManager != (Object)null)
		{
			Object.Destroy((Object)(object)discordManager);
		}
	}

	private void OnApplicationQuit()
	{
		if ((Object)(object)discordManager != (Object)null)
		{
			discordManager.Shutdown();
		}
	}
}
public class DiscordRpcManager : MonoBehaviour
{
	private const string DISCORD_APP_ID = "1502207417927208980";

	private const float UPDATE_INTERVAL = 3f;

	private bool initialized = false;

	private float lastUpdateTime = 0f;

	private long startTimestamp;

	private static DiscordRpc.EventHandlers discordEventHandlers = new DiscordRpc.EventHandlers
	{
		readyCallback = OnReady,
		disconnectedCallback = OnDisconnected,
		errorCallback = OnError
	};

	private void Start()
	{
		try
		{
			startTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
			DiscordRpc.Initialize("1502207417927208980", ref discordEventHandlers, autoRegister: true, null);
			initialized = true;
			QOLImprovementsPlugin.logger.LogInfo((object)"Discord RPC initialized successfully!");
			UpdatePresence();
		}
		catch (DllNotFoundException)
		{
			QOLImprovementsPlugin.logger.LogError((object)"====================================");
			QOLImprovementsPlugin.logger.LogError((object)"Discord RPC: discord-rpc.dll NOT FOUND!");
			QOLImprovementsPlugin.logger.LogError((object)"====================================");
			QOLImprovementsPlugin.logger.LogError((object)"Please download discord-rpc.dll from:");
			QOLImprovementsPlugin.logger.LogError((object)"https://github.com/discord/discord-rpc/releases");
			QOLImprovementsPlugin.logger.LogError((object)"");
			QOLImprovementsPlugin.logger.LogError((object)"Extract discord-rpc.dll and place it in:");
			QOLImprovementsPlugin.logger.LogError((object)"BepInEx/plugins/discord-rpc.dll");
			QOLImprovementsPlugin.logger.LogError((object)"====================================");
		}
		catch (Exception arg)
		{
			QOLImprovementsPlugin.logger.LogError((object)$"Failed to initialize Discord RPC: {arg}");
		}
	}

	private void Update()
	{
		if (initialized)
		{
			float time = Time.time;
			if (time - lastUpdateTime >= 3f)
			{
				lastUpdateTime = time;
				UpdatePresence();
			}
			DiscordRpc.RunCallbacks();
		}
	}

	private void UpdatePresence()
	{
		try
		{
			Type type = AccessTools.TypeByName("GameplayData");
			Type type2 = AccessTools.TypeByName("GameplayMaster");
			if (type == null || type2 == null)
			{
				return;
			}
			object obj = AccessTools.Field(type2, "instance")?.GetValue(null);
			if (obj == null)
			{
				SetPresence("In Menu", "Preparing to gamble", null, null);
				return;
			}
			string numStr = (AccessTools.Method(type, "CoinsGet", (Type[])null, (Type[])null)?.Invoke(null, null))?.ToString() ?? "0";
			string numStr2 = (AccessTools.Method(type, "DebtGet", (Type[])null, (Type[])null)?.Invoke(null, null))?.ToString() ?? "0";
			string arg = (AccessTools.Method(type, "RoundsLeftToDeadline", (Type[])null, (Type[])null)?.Invoke(null, null))?.ToString() ?? "?";
			object obj2 = AccessTools.Method(type, "DebtIndexGet", (Type[])null, (Type[])null)?.Invoke(null, null);
			int num = 0;
			if (obj2 != null)
			{
				int result;
				if (obj2 is int num2)
				{
					num = num2;
				}
				else if (int.TryParse(obj2.ToString(), out result))
				{
					num = result;
				}
			}
			string state = "\ud83d\udcb0 " + FormatNumber(numStr) + " | \ud83d\udc80 " + FormatNumber(numStr2);
			string details = $"Deadline {num + 1} - {arg} rounds left";
			SetPresence(details, state, "cloverpit_logo", "Cloverpit");
		}
		catch (Exception ex)
		{
			QOLImprovementsPlugin.logger.LogError((object)("Error updating Discord presence: " + ex.GetType().Name + ": " + ex.Message));
			QOLImprovementsPlugin.logger.LogError((object)("Stack trace: " + ex.StackTrace));
		}
	}

	private string FormatNumber(string numStr)
	{
		try
		{
			if (numStr.Contains("E") || numStr.Contains("e"))
			{
				if (double.TryParse(numStr, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
				{
					return result.ToString("0.00E+000", CultureInfo.InvariantCulture);
				}
				return numStr;
			}
			if (numStr.Length > 15)
			{
				string text = numStr.Substring(0, 1);
				string text2 = ((numStr.Length > 3) ? numStr.Substring(1, 2) : numStr.Substring(1));
				int num = numStr.Length - 1;
				double num2 = double.Parse(text + "." + text2);
				return $"{num2:F2}E+{num:D3}";
			}
			if (decimal.TryParse(numStr, NumberStyles.Any, CultureInfo.InvariantCulture, out var result2))
			{
				if (result2 >= 1000000000m)
				{
					return ((double)result2).ToString("0.00E+000", CultureInfo.InvariantCulture);
				}
				if (result2 >= 1000000m)
				{
					return $"{result2 / 1000000m:F2}M";
				}
				if (result2 >= 1000m)
				{
					return $"{result2 / 1000m:F2}K";
				}
				return ((long)result2).ToString();
			}
			return numStr;
		}
		catch
		{
			return numStr ?? "0";
		}
	}

	private void SetPresence(string details, string state, string largeImageKey, string largeImageText)
	{
		DiscordRpc.UpdatePresence(default(DiscordRpc.RichPresence), details, state, largeImageKey, largeImageText, startTimestamp);
	}

	public void Shutdown()
	{
		if (initialized)
		{
			DiscordRpc.Shutdown();
			initialized = false;
			QOLImprovementsPlugin.logger.LogInfo((object)"Discord RPC shutdown");
		}
	}

	private void OnDestroy()
	{
		Shutdown();
	}

	private static void OnReady(ref DiscordRpc.DiscordUser user)
	{
		QOLImprovementsPlugin.logger.LogInfo((object)("Discord RPC connected to user: " + user.username + "#" + user.discriminator));
	}

	private static void OnDisconnected(int errorCode, string message)
	{
		QOLImprovementsPlugin.logger.LogWarning((object)$"Discord RPC disconnected: {errorCode} - {message}");
	}

	private static void OnError(int errorCode, string message)
	{
		QOLImprovementsPlugin.logger.LogError((object)$"Discord RPC error: {errorCode} - {message}");
	}
}
public static class DiscordRpc
{
	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	public delegate void ReadyCallback(ref DiscordUser user);

	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	public delegate void DisconnectedCallback(int errorCode, string message);

	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
	public delegate void ErrorCallback(int errorCode, string message);

	[Serializable]
	public struct EventHandlers
	{
		public ReadyCallback readyCallback;

		public DisconnectedCallback disconnectedCallback;

		public ErrorCallback errorCallback;
	}

	[Serializable]
	public struct RichPresence
	{
		public IntPtr state;

		public IntPtr details;

		public long startTimestamp;

		public long endTimestamp;

		public IntPtr largeImageKey;

		public IntPtr largeImageText;

		public IntPtr smallImageKey;

		public IntPtr smallImageText;

		public IntPtr partyId;

		public int partySize;

		public int partyMax;

		public IntPtr matchSecret;

		public IntPtr joinSecret;

		public IntPtr spectateSecret;

		public bool instance;
	}

	[Serializable]
	public struct DiscordUser
	{
		public string userId;

		public string username;

		public string discriminator;

		public string avatar;
	}

	[DllImport("discord-rpc", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Discord_Initialize")]
	public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId);

	[DllImport("discord-rpc", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Discord_Shutdown")]
	public static extern void Shutdown();

	[DllImport("discord-rpc", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Discord_RunCallbacks")]
	public static extern void RunCallbacks();

	[DllImport("discord-rpc", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Discord_UpdatePresence")]
	private static extern void UpdatePresenceNative(ref RichPresence presence);

	public static void UpdatePresence(RichPresence presence, string details = null, string state = null, string largeImageKey = null, string largeImageText = null, long startTimestamp = 0L, string smallImageKey = null, string smallImageText = null)
	{
		RichPresence richPresence = default(RichPresence);
		richPresence.state = ((state != null) ? Marshal.StringToHGlobalAnsi(state) : IntPtr.Zero);
		richPresence.details = ((details != null) ? Marshal.StringToHGlobalAnsi(details) : IntPtr.Zero);
		richPresence.startTimestamp = startTimestamp;
		richPresence.endTimestamp = 0L;
		richPresence.largeImageKey = ((largeImageKey != null) ? Marshal.StringToHGlobalAnsi(largeImageKey) : IntPtr.Zero);
		richPresence.largeImageText = ((largeImageText != null) ? Marshal.StringToHGlobalAnsi(largeImageText) : IntPtr.Zero);
		richPresence.smallImageKey = ((smallImageKey != null) ? Marshal.StringToHGlobalAnsi(smallImageKey) : IntPtr.Zero);
		richPresence.smallImageText = ((smallImageText != null) ? Marshal.StringToHGlobalAnsi(smallImageText) : IntPtr.Zero);
		richPresence.partyId = IntPtr.Zero;
		richPresence.partySize = 0;
		richPresence.partyMax = 0;
		richPresence.matchSecret = IntPtr.Zero;
		richPresence.joinSecret = IntPtr.Zero;
		richPresence.spectateSecret = IntPtr.Zero;
		richPresence.instance = false;
		RichPresence presence2 = richPresence;
		UpdatePresenceNative(ref presence2);
		if (presence2.state != IntPtr.Zero)
		{
			Marshal.FreeHGlobal(presence2.state);
		}
		if (presence2.details != IntPtr.Zero)
		{
			Marshal.FreeHGlobal(presence2.details);
		}
		if (presence2.largeImageKey != IntPtr.Zero)
		{
			Marshal.FreeHGlobal(presence2.largeImageKey);
		}
		if (presence2.largeImageText != IntPtr.Zero)
		{
			Marshal.FreeHGlobal(presence2.largeImageText);
		}
		if (presence2.smallImageKey != IntPtr.Zero)
		{
			Marshal.FreeHGlobal(presence2.smallImageKey);
		}
		if (presence2.smallImageText != IntPtr.Zero)
		{
			Marshal.FreeHGlobal(presence2.smallImageText);
		}
	}
}