Decompiled source of PauseMyServer v1.0.0

BepInEx/plugins/PauseMyServer.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("PauseMyServer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+1ea8ad8df758daf68ff6b614a195c2aad5e4bbec")]
[assembly: AssemblyProduct("PauseMyServer")]
[assembly: AssemblyTitle("PauseMyServer")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PauseMyServer;

[HarmonyPatch(typeof(Game), "Pause")]
internal static class Game_Pause_Patch
{
	[HarmonyPostfix]
	private static void Postfix()
	{
		PauseSync.WantPause = true;
	}
}
[HarmonyPatch(typeof(Game), "Unpause")]
internal static class Game_Unpause_Patch
{
	[HarmonyPostfix]
	private static void Postfix()
	{
		PauseSync.WantPause = false;
	}
}
[HarmonyPatch(typeof(Game), "IsPaused")]
internal static class Game_IsPaused_Patch
{
	[HarmonyPostfix]
	private static void Postfix(ref bool __result)
	{
		if (!__result && PauseSync.ClientPaused && PauseSync.WantPause)
		{
			__result = true;
		}
	}
}
[HarmonyPatch(typeof(ZNet), "UpdateNetTime")]
internal static class ZNet_UpdateNetTime_Patch
{
	[HarmonyPrefix]
	private static bool Prefix()
	{
		return !PauseSync.ServerPaused;
	}
}
[HarmonyPatch(typeof(RandEventSystem), "FixedUpdate")]
internal static class RandEventSystem_FixedUpdate_Patch
{
	[HarmonyPrefix]
	private static bool Prefix()
	{
		return !PauseSync.ServerPaused;
	}
}
[HarmonyPatch(typeof(EnvMan), "UpdateTimeSkip")]
internal static class EnvMan_UpdateTimeSkip_Patch
{
	[HarmonyPrefix]
	private static bool Prefix()
	{
		return !PauseSync.ServerPaused;
	}
}
[HarmonyPatch(typeof(Game), "Start")]
internal static class Game_Start_Patch
{
	[HarmonyPostfix]
	private static void Postfix()
	{
		PauseSync.Reset();
		PauseSync.Register();
	}
}
[HarmonyPatch(typeof(ZNet), "Shutdown")]
internal static class ZNet_Shutdown_Patch
{
	[HarmonyPrefix]
	private static void Prefix()
	{
		PauseSync.Reset();
	}
}
[BepInPlugin("DeathMonger.PauseMyServer", "Pause My Server", "1.0.0")]
public class PauseMyServerMod : BaseUnityPlugin
{
	public const string ModGuid = "DeathMonger.PauseMyServer";

	public const string ModName = "Pause My Server";

	public const string ModVersion = "1.0.0";

	internal static ConfigEntry<bool> ModEnabled;

	internal static ConfigEntry<bool> ShowMessages;

	private readonly Harmony _harmony = new Harmony("DeathMonger.PauseMyServer");

	internal static ManualLogSource Log { get; private set; }

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Mod Enabled", true, "Master toggle for the entire mod. Set to false to disable every patch without removing the DLL. Requires a game restart to take effect.");
		ShowMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Messages", true, "Show a small top-left HUD message when the world is paused, and when it resumes because another player came online while your menu was still open. Client-side only.");
		if (!ModEnabled.Value)
		{
			Log.LogInfo((object)"[PauseMyServer] Mod Enabled = false in config; skipping patches.");
			return;
		}
		_harmony.PatchAll();
		Log.LogInfo((object)"[PauseMyServer] 1.0.0 loaded.");
	}

	private void Update()
	{
		if (ModEnabled.Value)
		{
			PauseSync.Update();
		}
	}

	private void OnDestroy()
	{
		_harmony.UnpatchSelf();
	}

	internal static void Message(string text)
	{
		if (ShowMessages != null && ShowMessages.Value && !((Object)(object)MessageHud.instance == (Object)null))
		{
			MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true);
		}
	}
}
internal static class PauseSync
{
	private const string RpcWant = "PMS_WantPause";

	private const string RpcState = "PMS_PauseState";

	private static readonly Dictionary<long, bool> _wants = new Dictionary<long, bool>();

	private static readonly List<long> _gone = new List<long>();

	private static string _pausedBy = "";

	internal static bool WantPause;

	private static bool _sentWant;

	internal static bool ServerPaused { get; private set; }

	internal static bool ClientPaused { get; private set; }

	internal static void Register()
	{
		ZRoutedRpc instance = ZRoutedRpc.instance;
		if (instance != null)
		{
			instance.Register<bool>("PMS_WantPause", (Action<long, bool>)RPC_WantPause);
			instance.Register<bool>("PMS_PauseState", (Action<long, bool>)RPC_PauseState);
		}
	}

	internal static void Reset()
	{
		ServerPaused = false;
		_wants.Clear();
		_pausedBy = "";
		ClientPaused = false;
		WantPause = false;
		_sentWant = false;
	}

	internal static void Update()
	{
		ZNet instance = ZNet.instance;
		if (!((Object)(object)instance == (Object)null) && ZRoutedRpc.instance != null)
		{
			if (instance.IsServer())
			{
				UpdateServer(instance);
			}
			else
			{
				UpdateClient();
			}
		}
	}

	private static void UpdateClient()
	{
		if (WantPause != _sentWant)
		{
			_sentWant = WantPause;
			ZRoutedRpc.instance.InvokeRoutedRPC("PMS_WantPause", new object[1] { WantPause });
		}
	}

	private static void RPC_PauseState(long sender, bool paused)
	{
		ZNet instance = ZNet.instance;
		if ((Object)(object)instance == (Object)null || instance.IsServer())
		{
			return;
		}
		ZNetPeer serverPeer = instance.GetServerPeer();
		if ((serverPeer == null || sender == serverPeer.m_uid) && paused != ClientPaused)
		{
			ClientPaused = paused;
			PauseMyServerMod.Log.LogInfo((object)(paused ? "[PauseMyServer] World paused." : "[PauseMyServer] World resumed."));
			if (paused)
			{
				PauseMyServerMod.Message("World paused");
			}
			else if (WantPause)
			{
				PauseMyServerMod.Message("World resumed: another player is online");
			}
		}
	}

	private static void RPC_WantPause(long sender, bool want)
	{
		ZNet instance = ZNet.instance;
		if (!((Object)(object)instance == (Object)null) && instance.IsServer() && instance.GetPeer(sender) != null)
		{
			_wants[sender] = want;
		}
	}

	private static void UpdateServer(ZNet znet)
	{
		int num = 0;
		long key = 0L;
		string text = "";
		List<ZNetPeer> peers = znet.GetPeers();
		for (int i = 0; i < peers.Count; i++)
		{
			ZNetPeer val = peers[i];
			if (val.IsReady())
			{
				num++;
				key = val.m_uid;
				text = val.m_playerName;
			}
		}
		if (_wants.Count > 0)
		{
			_gone.Clear();
			foreach (long key2 in _wants.Keys)
			{
				if (znet.GetPeer(key2) == null)
				{
					_gone.Add(key2);
				}
			}
			for (int j = 0; j < _gone.Count; j++)
			{
				_wants.Remove(_gone[j]);
			}
		}
		bool value = default(bool);
		bool flag = !((Object)(object)Player.m_localPlayer != (Object)null) && num == 1 && _wants.TryGetValue(key, out value) && value;
		if (flag != ServerPaused)
		{
			ServerPaused = flag;
			if (flag)
			{
				_pausedBy = text;
				PauseMyServerMod.Log.LogInfo((object)("[PauseMyServer] World paused by " + text + "."));
			}
			else
			{
				PauseMyServerMod.Log.LogInfo((object)$"[PauseMyServer] World resumed (was paused by {_pausedBy}; {num} player(s) connected).");
				_pausedBy = "";
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "PMS_PauseState", new object[1] { flag });
		}
	}
}