Decompiled source of ServerEmptyStopSave v1.1.1

ServerEmptyStopSave.dll

Decompiled 2 months ago
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ServerEmptyStopSave;

[BepInPlugin("pico.serveremptystopsave", "ServerEmptyStopSave", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
	private enum SaveType
	{
		None,
		FastSave,
		ShortBackup,
		LongBackup,
		ManualOrShutdown
	}

	private static SaveType currentSaveType = SaveType.None;

	private static bool pendingFinalSave = false;

	private static DateTime lastShortBackup = DateTime.UtcNow;

	private static DateTime lastLongBackup = DateTime.UtcNow;

	private static int effectiveShortInterval = 900;

	private static int effectiveLongInterval = 7200;

	private static ManualLogSource ModLog;

	private static ConfigEntry<bool> configEnableLogging;

	private static ConfigEntry<bool> configLogBlockedMessages;

	private static ConfigEntry<bool> configMuteAllSaveMessages;

	private static ConfigEntry<bool> configHideFastSave;

	private static ConfigEntry<bool> configShowShortBackup;

	private static ConfigEntry<bool> configShowLongBackup;

	private static ConfigEntry<bool> configShowManualSave;

	private static ConfigEntry<int> configShortIntervalSeconds;

	private static ConfigEntry<int> configLongIntervalSeconds;

	private static ConfigEntry<string> configFastSaveText;

	private static ConfigEntry<string> configShortBackupText;

	private static ConfigEntry<string> configLongBackupText;

	private static ConfigEntry<string> configManualSaveText;

	private static void Log(string message)
	{
		ModLog.LogInfo((object)("[" + DateTime.Now.ToString("HH:mm:ss") + "] " + message));
	}

	private static int ParseCommandLineArg(string argName, int fallback)
	{
		string[] commandLineArgs = Environment.GetCommandLineArgs();
		for (int i = 0; i < commandLineArgs.Length; i++)
		{
			string text = commandLineArgs[i];
			int result;
			if (string.Equals(text, argName, StringComparison.OrdinalIgnoreCase) && i + 1 < commandLineArgs.Length)
			{
				if (int.TryParse(commandLineArgs[i + 1], out result))
				{
					return result;
				}
			}
			else if (text.StartsWith(argName + "=", StringComparison.OrdinalIgnoreCase))
			{
				string s = text.Substring(argName.Length + 1);
				if (int.TryParse(s, out result))
				{
					return result;
				}
			}
		}
		return fallback;
	}

	private void Awake()
	{
		ModLog = ((BaseUnityPlugin)this).Logger;
		configEnableLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableLogging", true, "Log in console when saves are executed or skipped.");
		configLogBlockedMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "LogBlockedMessages", true, "Log in console whenever an on-screen save notification or countdown is blocked.");
		configMuteAllSaveMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "MuteAllSaveMessages", false, "Master switch: completely disables every save banner and countdown on screen.");
		configHideFastSave = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "HideFastSaveMessage", false, "Hides the frequent periodic autosave banner and its 30s countdown warning.");
		configShowShortBackup = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "ShowShortBackupMessage", false, "Shows a distinct banner when a short backup is taken.");
		configShowLongBackup = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "ShowLongBackupMessage", false, "Shows a distinct banner when a long backup is taken.");
		configShowManualSave = ((BaseUnityPlugin)this).Config.Bind<bool>("Notifications", "ShowManualSaveMessage", true, "Shows an on-screen alert when an admin runs /save or during shutdown.");
		configShortIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Timers", "ShortBackupIntervalSeconds", 900, "Fallback interval in seconds if -backupshort is not passed in the server launch script.");
		configLongIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Timers", "LongBackupIntervalSeconds", 7200, "Fallback interval in seconds if -backuplong is not passed in the server launch script.");
		effectiveShortInterval = ParseCommandLineArg("-backupshort", configShortIntervalSeconds.Value);
		effectiveLongInterval = ParseCommandLineArg("-backuplong", configLongIntervalSeconds.Value);
		configFastSaveText = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "FastSaveText", "World saved", "Text displayed for standard autosaves.");
		configShortBackupText = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "ShortBackupText", "[Short Backup] World saved", "Text displayed when a short-term backup is created.");
		configLongBackupText = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "LongBackupText", "[Long Backup] World saved", "Text displayed when a long-term backup is created.");
		configManualSaveText = ((BaseUnityPlugin)this).Config.Bind<string>("Messages", "ManualSaveText", "[Server] World saved", "Text displayed for manual /save commands and shutdown saves.");
		Harmony.CreateAndPatchAll(typeof(Plugin), (string)null);
		Log("ServerEmptyStopSave v1.1.0 loaded.");
		Log("Active Backup Intervals: Short = " + effectiveShortInterval + "s, Long = " + effectiveLongInterval + "s.");
	}

	[HarmonyPatch(typeof(ZNet), "SaveWorld")]
	[HarmonyPrefix]
	private static bool PrefixSaveWorld(ZNet __instance, bool sync)
	{
		DateTime utcNow = DateTime.UtcNow;
		if (sync)
		{
			currentSaveType = SaveType.ManualOrShutdown;
			if (configEnableLogging.Value)
			{
				Log("Manual save or server shutdown detected - allowing save.");
			}
			return true;
		}
		int nrOfPlayers = __instance.GetNrOfPlayers();
		if (nrOfPlayers > 0)
		{
			pendingFinalSave = true;
			if ((utcNow - lastLongBackup).TotalSeconds >= (double)effectiveLongInterval)
			{
				currentSaveType = SaveType.LongBackup;
				lastLongBackup = utcNow;
				lastShortBackup = utcNow;
			}
			else if ((utcNow - lastShortBackup).TotalSeconds >= (double)effectiveShortInterval)
			{
				currentSaveType = SaveType.ShortBackup;
				lastShortBackup = utcNow;
			}
			else
			{
				currentSaveType = SaveType.FastSave;
			}
			if (configEnableLogging.Value)
			{
				Log("Save triggered (" + currentSaveType.ToString() + ") with " + nrOfPlayers + " player(s) online - saving world.");
			}
			return true;
		}
		if (pendingFinalSave)
		{
			pendingFinalSave = false;
			currentSaveType = SaveType.ManualOrShutdown;
			if (configEnableLogging.Value)
			{
				Log("Server is empty - running final cleanup save for logged-out players.");
			}
			return true;
		}
		if (configEnableLogging.Value)
		{
			Log("Save interval reached, but server is empty (0 players) - autosave skipped.");
		}
		currentSaveType = SaveType.None;
		return false;
	}

	[HarmonyPatch(typeof(ZNet), "SaveWorld")]
	[HarmonyPostfix]
	private static void PostfixSaveWorld()
	{
		currentSaveType = SaveType.None;
	}

	private static bool IsSaveRelatedText(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return false;
		}
		string text2 = text.ToLower();
		return text2.Contains("save") || text2.Contains("saving");
	}

	private static bool SuppressMessage(string text, string reason)
	{
		if (configLogBlockedMessages.Value)
		{
			Log("Suppressed on-screen notification (" + reason + "): \"" + text + "\"");
		}
		return false;
	}

	[HarmonyPatch(typeof(MessageHud), "MessageAll")]
	[HarmonyPrefix]
	private static bool PrefixMessageAll(MessageType type, ref string text)
	{
		if (IsSaveRelatedText(text))
		{
			if (configMuteAllSaveMessages.Value)
			{
				return SuppressMessage(text, "MuteAllSaveMessages");
			}
			if (currentSaveType == SaveType.None)
			{
				DateTime utcNow = DateTime.UtcNow;
				bool flag = (utcNow - lastLongBackup).TotalSeconds >= (double)(effectiveLongInterval - 45);
				bool flag2 = (utcNow - lastShortBackup).TotalSeconds >= (double)(effectiveShortInterval - 45);
				if (flag)
				{
					if (configHideFastSave.Value && !configShowLongBackup.Value)
					{
						return SuppressMessage(text, "Long Backup Countdown");
					}
					text = "[Long Backup] " + text;
					return true;
				}
				if (flag2)
				{
					if (configHideFastSave.Value && !configShowShortBackup.Value)
					{
						return SuppressMessage(text, "Short Backup Countdown");
					}
					text = "[Short Backup] " + text;
					return true;
				}
				if (configHideFastSave.Value)
				{
					return SuppressMessage(text, "Autosave Countdown");
				}
				return true;
			}
			switch (currentSaveType)
			{
			case SaveType.FastSave:
				if (configHideFastSave.Value)
				{
					return SuppressMessage(text, "FastSave Banner");
				}
				text = configFastSaveText.Value;
				break;
			case SaveType.ShortBackup:
				if (configHideFastSave.Value && !configShowShortBackup.Value)
				{
					return SuppressMessage(text, "ShortBackup Banner");
				}
				text = configShortBackupText.Value;
				break;
			case SaveType.LongBackup:
				if (configHideFastSave.Value && !configShowLongBackup.Value)
				{
					return SuppressMessage(text, "LongBackup Banner");
				}
				text = configLongBackupText.Value;
				break;
			case SaveType.ManualOrShutdown:
				if (!configShowManualSave.Value)
				{
					return SuppressMessage(text, "ManualSave Banner");
				}
				text = configManualSaveText.Value;
				break;
			default:
				if (configHideFastSave.Value)
				{
					return SuppressMessage(text, "General Save Banner");
				}
				break;
			}
		}
		return true;
	}
}