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);
}
}
}