Decompiled source of FsOptimizer v1.6.6

FsOptimizer.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using FsOptimizer;
using HarmonyLib;
using Il2CppSLZ.Marrow.SceneStreaming;
using Il2CppSLZ.Marrow.Warehouse;
using LabFusion.Data;
using LabFusion.Entities;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.Representation;
using LabFusion.Senders;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("A Fusion server cleaner/optimizer")]
[assembly: AssemblyDescription("A Fusion server cleaner/optimizer")]
[assembly: AssemblyCompany(null)]
[assembly: AssemblyProduct("FsOptimizer")]
[assembly: AssemblyCopyright("Created by SillyAlex")]
[assembly: AssemblyTrademark(null)]
[assembly: AssemblyFileVersion("1.6.6")]
[assembly: MelonInfo(typeof(global::FsOptimizer.FsOptimizer), "FsOptimizer", "1.6.6", "SillyAlex", "https://github.com/SillyAlexX/FsOptimizer")]
[assembly: MelonColor(255, 37, 150, 190)]
[assembly: MelonGame(null, null)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.6.6.0")]
[module: UnverifiableCode]
namespace FsOptimizer;

public static class ConfigManager
{
	[Serializable]
	public class FsOptimizerConfig
	{
		public bool AutoCleanEnabled { get; set; }

		public float AutoCleanInterval { get; set; } = 300f;


		public bool AdaptiveAutoCleanEnabled { get; set; }

		public bool AntiGriefEnabled { get; set; }

		public int ObjectThreshold { get; set; } = 100;


		public long MemoryThreshold { get; set; } = 1024L;


		public string LastUsedPreset { get; set; } = "Default";

	}

	private static FsOptimizerConfig currentConfig = new FsOptimizerConfig();

	private static string ConfigFilePath => Path.Combine(Paths.ConfigPath, "Config.json");

	public static FsOptimizerConfig Config => currentConfig;

	public static void SaveConfig()
	{
		try
		{
			currentConfig.AutoCleanEnabled = FsOptimizer.autoCleanEnabled?.Value ?? false;
			currentConfig.AutoCleanInterval = FsOptimizer.autoCleanInterval?.Value ?? 300f;
			currentConfig.AdaptiveAutoCleanEnabled = FsOptimizer.adaptiveAutoCleanEnabled?.Value ?? false;
			currentConfig.AntiGriefEnabled = FsOptimizer.AntiGriefEnabled?.Value ?? false;
			string contents = JsonConvert.SerializeObject((object)currentConfig, (Formatting)1);
			File.WriteAllText(ConfigFilePath, contents);
			MelonLogger.Msg("FsOptimizer config saved successfully");
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Failed to save config: " + ex.Message);
		}
	}

	public static void LoadConfig()
	{
		try
		{
			if (File.Exists(ConfigFilePath))
			{
				currentConfig = JsonConvert.DeserializeObject<FsOptimizerConfig>(File.ReadAllText(ConfigFilePath)) ?? new FsOptimizerConfig();
				MelonLogger.Msg("FsOptimizer config loaded successfully");
			}
			else
			{
				SaveConfig();
				MelonLogger.Msg("Created default FsOptimizer config");
			}
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Failed to load config: " + ex.Message);
			currentConfig = new FsOptimizerConfig();
		}
	}

	public static void ApplyConfigToPreferences()
	{
		try
		{
			if (FsOptimizer.autoCleanEnabled != null)
			{
				FsOptimizer.autoCleanEnabled.Value = currentConfig.AutoCleanEnabled;
			}
			if (FsOptimizer.autoCleanInterval != null)
			{
				FsOptimizer.autoCleanInterval.Value = currentConfig.AutoCleanInterval;
			}
			if (FsOptimizer.adaptiveAutoCleanEnabled != null)
			{
				FsOptimizer.adaptiveAutoCleanEnabled.Value = currentConfig.AdaptiveAutoCleanEnabled;
			}
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Failed to apply config: " + ex.Message);
		}
	}
}
public static class Paths
{
	private static string ConfigFolder => Path.Combine(MelonEnvironment.UserDataDirectory, "FsOptimizer");

	public static string ConfigPath => Path.Combine(MelonEnvironment.UserDataDirectory, "FsOptimizer/Config");

	public static void InitFolders()
	{
		try
		{
			MelonLogger.Msg("Creating FsOptimizer folders in: " + MelonEnvironment.UserDataDirectory);
			if (!Directory.Exists(ConfigFolder))
			{
				Directory.CreateDirectory(ConfigFolder);
			}
			if (!Directory.Exists(ConfigPath))
			{
				Directory.CreateDirectory(ConfigPath);
			}
			MelonLogger.Msg("FsOptimizer folders initialized successfully");
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Failed to create FsOptimizer folders: " + ex.Message);
		}
	}
}
public static class BuildInfo
{
	public const string Name = "FsOptimizer";

	public const string Description = "A Fusion server cleaner/optimizer";

	public const string Author = "SillyAlex";

	public const string Company = null;

	public const string Version = "1.6.6";

	public const string DownloadLink = "https://github.com/SillyAlexX/FsOptimizer";
}
public class FsOptimizer : MelonMod
{
	public enum CleanInterval
	{
		Five_Minutes,
		Ten_Minutes,
		Fifteen_Minutes,
		Twenty_Minutes,
		Twenty_Five_Minutes,
		Thirty_Minutes
	}

	[HarmonyPatch(typeof(ConnectionRequestMessage))]
	public static class ConnectionRequestMessagePatch
	{
		[HarmonyPatch("OnHandleMessage")]
		[HarmonyPrefix]
		public static bool OnHandleMessage_Prefix(object __instance, ReceivedMessage received)
		{
			MelonPreferences_Entry<bool> antiGriefEnabled = AntiGriefEnabled;
			if (antiGriefEnabled == null || !antiGriefEnabled.Value)
			{
				return true;
			}
			try
			{
				if (NetworkInfo.IsHost)
				{
					ConnectionRequestData val = ((ReceivedMessage)(ref received)).ReadData<ConnectionRequestData>();
					MelonLogger.Msg($"[AntiGrief] Incoming connection: PlatformID={val.PlatformID}, Version={val.Version}");
				}
				if (NetworkInfo.Layer.RequiresValidId && NetworkInfo.IsSpoofed(((ReceivedMessage)(ref received)).ReadData<ConnectionRequestData>().PlatformID))
				{
					ulong value = NetworkInfo.LastReceivedUser.Value;
					MelonLogger.Warning($"[AntiGrief] Spoofed ID detected! Blocking connection: {value}");
					ShowNotification($"[AntiGrief] Spoofed ID detected! Blocking connection: {value}", (NotificationType)1);
					ConnectionSender.SendConnectionDeny(value, "[AntiGrief]");
					return false;
				}
			}
			catch (Exception arg)
			{
				MelonLogger.Warning($"[AntiGrief] Error processing connection attempt: {arg}");
			}
			return true;
		}
	}

	public static Page MainPage;

	public static MelonPreferences_Category Preferences;

	public static Harmony HarmonyInstance;

	internal static MelonPreferences_Entry<bool> autoCleanEnabled;

	internal static MelonPreferences_Entry<bool> adaptiveAutoCleanEnabled;

	internal static MelonPreferences_Entry<float> autoCleanInterval;

	internal static MelonPreferences_Entry<bool> AntiGriefEnabled;

	private static float lastCleanTime;

	private static float lastAdaptiveCheck;

	public override void OnInitializeMelon()
	{
		Paths.InitFolders();
		Preferences = MelonPreferences.CreateCategory("FsOptimizer");
		autoCleanEnabled = Preferences.CreateEntry<bool>("AutoClean", false, "Auto Clean Enabled", (string)null, false, false, (ValueValidator)null, (string)null);
		autoCleanInterval = Preferences.CreateEntry<float>("AutoCleanInterval", 300f, "Auto Clean Interval (seconds)", (string)null, false, false, (ValueValidator)null, (string)null);
		adaptiveAutoCleanEnabled = Preferences.CreateEntry<bool>("AdaptiveAutoClean", false, "Adaptive Auto Clean Enabled", (string)null, false, false, (ValueValidator)null, (string)null);
		AntiGriefEnabled = Preferences.CreateEntry<bool>("AntiGrief", false, "Anti-Grief Protection Enabled", (string)null, false, false, (ValueValidator)null, (string)null);
		Hooking.OnLevelLoaded += OnLevelLoaded;
		ConfigManager.LoadConfig();
		ConfigManager.ApplyConfigToPreferences();
		((MelonBase)this).LoggerInstance.Msg("FsOptimizer Online");
		SetupMenu();
	}

	public override void OnUpdate()
	{
		if (autoCleanEnabled.Value && NetworkInfo.HasServer && NetworkInfo.IsHost && Time.time - lastCleanTime >= autoCleanInterval.Value)
		{
			PerformAutoClean();
			lastCleanTime = Time.time;
		}
		if (adaptiveAutoCleanEnabled.Value && autoCleanEnabled.Value && NetworkInfo.HasServer && NetworkInfo.IsHost && Time.time - lastAdaptiveCheck >= 30f)
		{
			CheckAndUpdateAdaptiveInterval();
			lastAdaptiveCheck = Time.time;
		}
	}

	private void OnLevelLoaded(LevelInfo info)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		Notifier.Send(new Notification
		{
			Title = NotificationText.op_Implicit("FsOptimizer | Ready"),
			Message = NotificationText.op_Implicit("FsOptimizer has launched successfully!"),
			Type = (NotificationType)3,
			PopupLength = 3f,
			ShowTitleOnPopup = true
		});
		ConfigManager.LoadConfig();
		ConfigManager.ApplyConfigToPreferences();
	}

	public static bool HasFusionPermission(NetworkPlayer player)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Invalid comparison between Unknown and I4
		if (((player != null) ? player.PlayerID : null) == null)
		{
			return false;
		}
		try
		{
			PermissionLevel val = default(PermissionLevel);
			if (MetadataHelper.TryGetPermissionLevel(player.PlayerID, ref val))
			{
				return (int)val >= 1;
			}
		}
		catch (Exception ex)
		{
			MelonLogger.Warning("Failed to check Fusion permissions: " + ex.Message);
			ShowNotification("Failed to check Fusion permissions: " + ex.Message, (NotificationType)2);
		}
		return false;
	}

	public static void CleanServerStyle()
	{
		try
		{
			NetworkPlayer networkPlayer = LocalPlayer.GetNetworkPlayer();
			if (!HasFusionPermission(networkPlayer))
			{
				MelonLogger.Warning(((networkPlayer != null) ? networkPlayer.Username : null) + " tried to clean without permission!");
				ShowNotification("Nuh Uh", (NotificationType)2);
				return;
			}
			foreach (NetworkEntity networkEntity in GetNetworkEntities())
			{
				DespawnActual(networkEntity, despawnEffect: true);
			}
			MelonLogger.Msg("Server clean completed!");
			ShowNotification("Server cleaned", (NotificationType)3);
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Server clean failed: " + ex.Message);
			ShowNotification("Clean failed! Check console", (NotificationType)2);
		}
	}

	public static void DespawnActual(NetworkEntity entity, bool despawnEffect)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Expected O, but got Unknown
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		try
		{
			NetworkPlayer val = ((IEnumerable<NetworkPlayer>)NetworkPlayer.Players).FirstOrDefault((Func<NetworkPlayer, bool>)((NetworkPlayer p) => p != null && p.PlayerID.IsHost));
			if (val == null)
			{
				MelonLogger.Warning("No host player found for despawn.");
				return;
			}
			DespawnResponseData val2 = new DespawnResponseData
			{
				Despawner = new PlayerReference(val.PlayerID),
				Entity = new NetworkEntityReference(entity.ID),
				DespawnEffect = despawnEffect
			};
			MessageRelay.RelayNative<DespawnResponseData>(val2, NativeMessageTag.DespawnResponse, CommonMessageRoutes.ReliableToClients);
			MessageRelay.RelayNative<DespawnResponseData>(val2, NativeMessageTag.DespawnResponse, CommonMessageRoutes.ReliableToOtherClients);
			MessageRelay.RelayNative<DespawnResponseData>(val2, NativeMessageTag.DespawnResponse, CommonMessageRoutes.ReliableToServer);
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Despawn failed: " + ex.Message);
		}
	}

	public static HashSet<NetworkEntity> GetNetworkEntities()
	{
		try
		{
			EntityIDManager<NetworkEntity> iDManager = NetworkEntityManager.IDManager;
			if (iDManager?.RegisteredEntities?.EntityIDLookup == null)
			{
				return new HashSet<NetworkEntity>();
			}
			HashSet<NetworkEntity> playerEntities = (from p in NetworkPlayer.Players
				where ((p != null) ? p.NetworkEntity : null) != null
				select p.NetworkEntity).ToHashSet();
			return iDManager.RegisteredEntities.EntityIDLookup.Keys.Where((NetworkEntity entity) => !playerEntities.Contains(entity)).ToHashSet();
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Failed to get network entities: " + ex.Message);
			return new HashSet<NetworkEntity>();
		}
	}

	private void PerformAutoClean()
	{
		try
		{
			MelonLogger.Msg("Performing auto-clean...");
			PooleeUtilities.DespawnAll();
			CleanProblematicSpawns();
			MelonLogger.Msg("Auto-clean completed");
			ShowNotification("Auto-cleaned server", (NotificationType)3);
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Auto-clean failed: " + ex.Message);
		}
	}

	private void CleanProblematicSpawns()
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		try
		{
			SerializedTransform val = new SerializedTransform(new Vector3(0f, 5f, 0f), Quaternion.identity);
			PooleeUtilities.RequestSpawn("Sileqoenn.DeltaruneFountainMaker.Spawnable.SealallDarkFountains", val, 0u, true);
			PooleeUtilities.RequestSpawn("FragileDeviations.PlantLab.Spawnable.SelfDestructionPartTwo", val, 0u, true);
		}
		catch (Exception ex)
		{
			MelonLogger.Warning("Failed to clean problematic spawns: " + ex.Message);
		}
	}

	private void CheckAndUpdateAdaptiveInterval()
	{
		try
		{
			int count = PlayerIDManager.PlayerIDs.Count;
			float intervalForPlayers = GetIntervalForPlayers(count);
			if (Math.Abs(autoCleanInterval.Value - intervalForPlayers) > 0.1f)
			{
				float value = autoCleanInterval.Value;
				autoCleanInterval.Value = intervalForPlayers;
				MelonLogger.Msg($"Adaptive interval adjusted from {value / 60f:F0}min to {intervalForPlayers / 60f:F0}min for {count} players");
				ShowNotification($"Auto-clean adapted: {intervalForPlayers / 60f:F0}min for {count} players", (NotificationType)0);
			}
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Failed to update adaptive interval: " + ex.Message);
		}
	}

	private float GetIntervalForPlayers(int playerCount)
	{
		if (playerCount >= 8)
		{
			return 600f;
		}
		switch (playerCount)
		{
		case 5:
			return 900f;
		case 3:
		case 4:
			return 1500f;
		default:
			return 1800f;
		}
	}

	private CleanInterval GetIntervalEnum()
	{
		float[] array = new float[6] { 300f, 600f, 900f, 1200f, 1500f, 1800f };
		for (int i = 0; i < array.Length; i++)
		{
			if (Math.Abs(array[i] - autoCleanInterval.Value) < 0.1f)
			{
				return (CleanInterval)i;
			}
		}
		return CleanInterval.Five_Minutes;
	}

	private void ReloadLevel()
	{
		try
		{
			if (SceneStreamer.Session != null && (Object)(object)SceneStreamer.Session.Level != (Object)null)
			{
				LevelCrate level = SceneStreamer.Session.Level;
				Barcode barcode = ((Scannable)level).Barcode;
				MelonLogger.Msg("Reloading level: " + ((Scannable)level).Title + " (" + barcode.ID + ")");
				ShowNotification("Reloading " + ((Scannable)level).Title + "...", (NotificationType)0);
				SceneStreamer.Load(barcode, (Barcode)null);
			}
			else
			{
				MelonLogger.Warning("No active level session found!");
				ShowNotification("No active level found!", (NotificationType)1);
			}
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Level reload failed: " + ex.Message);
			ShowNotification("Level reload failed! Check console", (NotificationType)2);
		}
	}

	private void SetupMenu()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		MainPage = Page.Root.CreatePage("<color=#00CCFF>F</color><color=#00C3FE>s</color><color=#00BBFD>O</color><color=#00B2FD>p</color><color=#00AAFC>t</color><color=#00A1FC>i</color><color=#0099FB>m</color><color=#0090FB>i</color><color=#0088FA>z</color><color=#007FFA>e</color><color=#0077F9>r</color>", Color.white, 0, true);
		MainPage.CreateFunction("Clean Server", Color.green, (Action)delegate
		{
			CleanServer();
		});
		MainPage.CreateFunction("Reload Level", Color.red, (Action)delegate
		{
			ReloadLevel();
		});
		MainPage.CreateFunction("Admin Clean", Color.red, (Action)delegate
		{
			CleanServerStyle();
		});
		MainPage.CreateBool("Auto Clean", Color.cyan, autoCleanEnabled.Value, (Action<bool>)delegate(bool value)
		{
			autoCleanEnabled.Value = value;
			string text6 = (value ? "enabled" : "disabled");
			ShowNotification("Auto clean " + text6, (NotificationType)0);
			MelonLogger.Msg("Auto clean " + text6);
			if (!value && adaptiveAutoCleanEnabled.Value)
			{
				adaptiveAutoCleanEnabled.Value = false;
				ShowNotification("Adaptive auto clean disabled (requires Auto Clean)", (NotificationType)0);
				MelonLogger.Msg("Adaptive auto clean automatically disabled");
			}
		});
		MainPage.CreateBool("Adaptive Auto Clean", Color.magenta, adaptiveAutoCleanEnabled.Value, (Action<bool>)delegate(bool value)
		{
			adaptiveAutoCleanEnabled.Value = value;
			string text5 = (value ? "enabled" : "disabled");
			ShowNotification("Adaptive auto clean " + text5, (NotificationType)0);
			MelonLogger.Msg("Adaptive auto clean " + text5);
			if (value && NetworkInfo.HasServer)
			{
				CheckAndUpdateAdaptiveInterval();
			}
		});
		MainPage.CreateBool("Anti-Grief Protection", Color.yellow, AntiGriefEnabled.Value, (Action<bool>)delegate(bool value)
		{
			AntiGriefEnabled.Value = value;
			string text4 = (value ? "enabled" : "disabled");
			ShowNotification("Anti-Grief Protection " + text4, (NotificationType)0);
			MelonLogger.Msg("Anti-Grief Protection " + text4);
			if (value)
			{
				MelonLogger.Warning("Admin clean may not work with Anti-Grief enabled");
				ShowNotification("Admin clean may not work with Anti-Grief enabled", (NotificationType)1);
			}
		});
		MainPage.CreateEnum("Clean Interval", Color.cyan, (Enum)GetIntervalEnum(), (Action<Enum>)delegate(Enum intervalEnum)
		{
			if (adaptiveAutoCleanEnabled.Value)
			{
				ShowNotification($"Adaptive mode active - current interval: {autoCleanInterval.Value / 60f:F0} minutes", (NotificationType)0);
			}
			else
			{
				float[] array = new float[6] { 300f, 600f, 900f, 1200f, 1500f, 1800f };
				int num = Convert.ToInt32(intervalEnum);
				autoCleanInterval.Value = array[num];
				ShowNotification($"Manual interval set to {array[num] / 60f} minutes", (NotificationType)0);
				MelonLogger.Msg($"Manual auto clean interval set to {array[num]} seconds");
			}
		});
		MainPage.CreateFunction("Show Current Status", Color.white, (Action)delegate
		{
			string text = (autoCleanEnabled.Value ? "enabled" : "disabled");
			string text2 = (adaptiveAutoCleanEnabled.Value ? "enabled" : "disabled");
			string text3 = (AntiGriefEnabled.Value ? "enabled" : "disabled");
			int count = PlayerIDManager.PlayerIDs.Count;
			ShowNotification($"Auto: {text} | Adaptive: {text2} | Interval: {autoCleanInterval.Value / 60f:F0}min | Anti-Grief: {text3} | Players: {count}", (NotificationType)0);
		});
		MainPage.CreateFunction("Save Config", Color.white, (Action)delegate
		{
			ConfigManager.SaveConfig();
			ShowNotification("Configuration saved successfully!", (NotificationType)3);
		});
	}

	private void CleanServer()
	{
		if (!ValidateServerConnection())
		{
			return;
		}
		try
		{
			PooleeUtilities.DespawnAll();
			CleanProblematicSpawns();
			MelonLogger.Msg("Server cleaned!");
			ShowNotification("Server cleaned", (NotificationType)3);
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Clean server failed: " + ex.Message);
			ShowNotification("Clean failed! Check console for details", (NotificationType)2);
		}
	}

	private bool ValidateServerConnection()
	{
		if (!NetworkInfo.HasServer)
		{
			MelonLogger.Warning("Not connected to Fusion server");
			ShowNotification("Not connected to Fusion server!", (NotificationType)2);
			return false;
		}
		if (!NetworkInfo.IsHost)
		{
			MelonLogger.Warning("User is not the server host");
			ShowNotification("You must be the server host!", (NotificationType)2);
			return false;
		}
		return true;
	}

	public override void OnApplicationQuit()
	{
		ConfigManager.SaveConfig();
	}

	private string FormatBytes(long bytes)
	{
		if (bytes < 1024)
		{
			return $"{bytes} B";
		}
		if (bytes < 1048576)
		{
			return $"{bytes / 1024} KB";
		}
		return $"{bytes / 1048576} MB";
	}

	private static void ShowNotification(string message, NotificationType type)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: 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_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		try
		{
			Notifier.Send(new Notification
			{
				Title = NotificationText.op_Implicit("FsOptimizer"),
				Message = NotificationText.op_Implicit(message),
				Type = type,
				PopupLength = 3f,
				ShowTitleOnPopup = true
			});
		}
		catch (Exception ex)
		{
			MelonLogger.Error("Failed to show notification: " + ex.Message);
		}
	}
}