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.Text.Json;
using BoneLib.BoneMenu;
using FusionWhitelist;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Fusion Whitelist", "1.0.0", "lawsms", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("FusionWhitelist")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FusionWhitelist")]
[assembly: AssemblyTitle("FusionWhitelist")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace FusionWhitelist
{
public class Core : MelonMod
{
public override void OnInitializeMelon()
{
WhitelistManager.Load();
WhitelistMenu.Setup();
LabFusionBridge.Subscribe();
MelonLogger.Msg("[FusionWhitelist] Initialized. Whitelist enforcement is " + (WhitelistManager.Data.Enabled ? "ENABLED" : "DISABLED") + ".");
}
public override void OnDeinitializeMelon()
{
LabFusionBridge.Unsubscribe();
}
}
public class WhitelistData
{
public bool Enabled { get; set; }
public List<string> SteamIds { get; set; } = new List<string>();
}
public static class WhitelistManager
{
private static readonly HashSet<ulong> _lookup = new HashSet<ulong>();
public static WhitelistData Data { get; private set; } = new WhitelistData();
private static string FilePath => Path.Combine(MelonEnvironment.UserDataDirectory, "FusionWhitelist.json");
public static IReadOnlyCollection<ulong> AllIds => _lookup;
public static void Load()
{
try
{
if (File.Exists(FilePath))
{
WhitelistData whitelistData = JsonSerializer.Deserialize<WhitelistData>(File.ReadAllText(FilePath));
if (whitelistData != null)
{
Data = whitelistData;
}
}
else
{
Data = new WhitelistData();
Save();
}
}
catch (Exception value)
{
MelonLogger.Error($"[FusionWhitelist] Failed to load whitelist file, using defaults. {value}");
Data = new WhitelistData();
}
RebuildLookup();
}
public static void Save()
{
try
{
string contents = JsonSerializer.Serialize(Data, new JsonSerializerOptions
{
WriteIndented = true
});
Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
File.WriteAllText(FilePath, contents);
}
catch (Exception value)
{
MelonLogger.Error($"[FusionWhitelist] Failed to save whitelist file. {value}");
}
}
private static void RebuildLookup()
{
_lookup.Clear();
foreach (string steamId in Data.SteamIds)
{
if (ulong.TryParse(steamId, out var result))
{
_lookup.Add(result);
}
}
}
public static bool TryAdd(string rawSteamId, out string message)
{
if (!TryParseSteamId(rawSteamId, out var id, out message))
{
return false;
}
if (_lookup.Contains(id))
{
message = $"SteamID {id} is already whitelisted.";
return false;
}
_lookup.Add(id);
Data.SteamIds.Add(id.ToString());
Save();
message = $"Added {id} to the whitelist.";
return true;
}
public static bool TryAddBulk(string rawBlock, out string message)
{
if (string.IsNullOrWhiteSpace(rawBlock))
{
message = "Input is empty.";
return false;
}
string[] array = rawBlock.Split(new char[6] { ',', ';', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
int num = 0;
int num2 = 0;
int num3 = 0;
string[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
if (!TryParseSteamId(array2[i], out var id, out var _))
{
num2++;
continue;
}
if (_lookup.Contains(id))
{
num3++;
continue;
}
_lookup.Add(id);
Data.SteamIds.Add(id.ToString());
num++;
}
if (num > 0)
{
Save();
}
message = $"Added {num}, skipped {num3} duplicate(s), skipped {num2} invalid.";
return num > 0;
}
public static void Reload()
{
Load();
}
public static bool TryRemove(string rawSteamId, out string message)
{
if (!TryParseSteamId(rawSteamId, out var id, out message))
{
return false;
}
if (!_lookup.Contains(id))
{
message = $"SteamID {id} is not on the whitelist.";
return false;
}
_lookup.Remove(id);
Data.SteamIds.RemoveAll((string s) => s == id.ToString());
Save();
message = $"Removed {id} from the whitelist.";
return true;
}
public static bool IsWhitelisted(ulong steamId)
{
return _lookup.Contains(steamId);
}
public static void SetEnabled(bool enabled)
{
Data.Enabled = enabled;
Save();
}
public static bool TryParseSteamId(string raw, out ulong id, out string message)
{
id = 0uL;
message = string.Empty;
if (string.IsNullOrWhiteSpace(raw))
{
message = "SteamID field is empty.";
return false;
}
raw = raw.Trim();
if (!ulong.TryParse(raw, out id))
{
message = "'" + raw + "' is not a valid numeric SteamID64.";
return false;
}
if (id < 76561197960265728L)
{
message = "'" + raw + "' does not look like a valid SteamID64.";
return false;
}
return true;
}
}
public static class WhitelistMenu
{
private static Page _page;
private static FunctionElement _statusElement;
private static FunctionElement _listHeaderElement;
private static readonly List<FunctionElement> _listEntries = new List<FunctionElement>();
private static string _pendingSteamId = string.Empty;
public static void Setup()
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
_page = Page.Root.CreatePage("Fusion Whitelist", Color.cyan, 20, true);
_page.CreateBool("Enable Whitelist", Color.yellow, WhitelistManager.Data.Enabled, (Action<bool>)delegate(bool newValue)
{
WhitelistManager.SetEnabled(newValue);
RefreshStatus();
MelonLogger.Msg($"[FusionWhitelist] Whitelist enforcement set to {newValue}.");
});
_page.CreateString("SteamID Input", Color.white, _pendingSteamId, (Action<string>)delegate(string newValue)
{
_pendingSteamId = newValue;
});
_page.CreateFunction("Add to Whitelist", Color.green, (Action)delegate
{
if (WhitelistManager.TryAddBulk(_pendingSteamId, out var message))
{
MelonLogger.Msg("[FusionWhitelist] " + message);
}
else
{
MelonLogger.Warning("[FusionWhitelist] " + message);
}
RefreshList();
});
_page.CreateFunction("Remove from Whitelist", Color.red, (Action)delegate
{
if (WhitelistManager.TryRemove(_pendingSteamId, out var message))
{
MelonLogger.Msg("[FusionWhitelist] " + message);
}
else
{
MelonLogger.Warning("[FusionWhitelist] " + message);
}
RefreshList();
});
_page.CreateFunction("Reload Whitelist from File", Color.cyan, (Action)delegate
{
WhitelistManager.Reload();
MelonLogger.Msg("[FusionWhitelist] Reloaded whitelist from disk.");
RefreshList();
});
_statusElement = _page.CreateFunction("Status: " + (WhitelistManager.Data.Enabled ? "ENABLED" : "DISABLED"), Color.white, (Action)null);
_listHeaderElement = _page.CreateFunction("--- Whitelisted SteamIDs ---", Color.gray, (Action)delegate
{
PrintListToConsole();
});
RefreshList();
}
private static void RefreshStatus()
{
if (_statusElement != null)
{
((Element)_statusElement).ElementName = "Status: " + (WhitelistManager.Data.Enabled ? "ENABLED" : "DISABLED");
}
}
private static void RefreshList()
{
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
RefreshStatus();
foreach (FunctionElement listEntry in _listEntries)
{
_page.Remove((Element)(object)listEntry);
}
_listEntries.Clear();
foreach (ulong item2 in WhitelistManager.AllIds.OrderBy((ulong x) => x))
{
FunctionElement item = _page.CreateFunction(item2.ToString(), Color.white, (Action)null);
_listEntries.Add(item);
}
PrintListToConsole();
}
private static void PrintListToConsole()
{
MelonLogger.Msg("[FusionWhitelist] ---- Current Whitelist ----");
if (WhitelistManager.AllIds.Count == 0)
{
MelonLogger.Msg("[FusionWhitelist] (empty)");
}
else
{
foreach (ulong item in WhitelistManager.AllIds.OrderBy((ulong x) => x))
{
MelonLogger.Msg($"[FusionWhitelist] {item}");
}
}
MelonLogger.Msg("[FusionWhitelist] ---------------------------");
}
}
public static class LabFusionBridge
{
[CompilerGenerated]
private static class <>O
{
public static UserAccessEvent <0>__CheckShouldAllowConnection;
}
public static void Subscribe()
{
//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: Expected O, but got Unknown
object obj = <>O.<0>__CheckShouldAllowConnection;
if (obj == null)
{
UserAccessEvent val = CheckShouldAllowConnection;
<>O.<0>__CheckShouldAllowConnection = val;
obj = (object)val;
}
MultiplayerHooking.OnShouldAllowConnection += (UserAccessEvent)obj;
}
public static void Unsubscribe()
{
//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: Expected O, but got Unknown
object obj = <>O.<0>__CheckShouldAllowConnection;
if (obj == null)
{
UserAccessEvent val = CheckShouldAllowConnection;
<>O.<0>__CheckShouldAllowConnection = val;
obj = (object)val;
}
MultiplayerHooking.OnShouldAllowConnection -= (UserAccessEvent)obj;
}
private static bool CheckShouldAllowConnection(PlayerID playerId, out string reason)
{
reason = string.Empty;
try
{
if (playerId == null)
{
return true;
}
if (!NetworkInfo.IsHost)
{
return true;
}
if (IsLocalHost(playerId))
{
return true;
}
if (!WhitelistManager.Data.Enabled)
{
return true;
}
ulong platformID = playerId.PlatformID;
if (WhitelistManager.IsWhitelisted(platformID))
{
MelonLogger.Msg($"[FusionWhitelist] Player {platformID} is whitelisted, allowing connection.");
return true;
}
MelonLogger.Warning($"[FusionWhitelist] Player {platformID} is NOT whitelisted. Rejecting connection.");
reason = "You are not whitelisted on this server.";
return false;
}
catch (Exception value)
{
MelonLogger.Error($"[FusionWhitelist] Exception in CheckShouldAllowConnection: {value}");
return true;
}
}
private static bool IsLocalHost(PlayerID playerId)
{
return playerId.IsHost;
}
public static void KickPlayer(PlayerID playerId)
{
NetworkHelper.KickUser(playerId);
}
}
}