using System;
using System.Collections.Concurrent;
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 BoneLib.Notifications;
using FusionPersonalBlock;
using Il2CppSLZ.Marrow;
using LabFusion.Entities;
using LabFusion.Extensions;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.Utilities;
using LabFusion.Voice;
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 Personal Block", "1.0.1", "seeleyllp-crypto", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[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 FusionPersonalBlock
{
public sealed class Core : MelonMod
{
[CompilerGenerated]
private static class <>O
{
public static ServerEvent <0>__OnFusionJoinedServer;
public static ServerEvent <1>__OnFusionDisconnected;
public static PlayerUpdate <2>__OnFusionPlayerJoined;
public static PlayerUpdate <3>__OnFusionPlayerLeft;
public static Action<NetworkPlayer> <4>__OnNetworkPlayerRegistered;
public static Action <5>__ShowSelectedPlayer;
public static Action <6>__RefreshPlayerPages;
public static Action <7>__BlockSelectedPlayer;
public static Action <8>__UnblockSelectedPlayer;
public static Action<bool> <9>__SetMuteBlockedPlayers;
public static Action<bool> <10>__SetHideBlockedPlayers;
public static Action<bool> <11>__SetDisableRigGrabbing;
public static Action<bool> <12>__SetAutoLeaveBlockedPlayer;
public static Action <13>__ApplyEffectsNow;
public static Action <14>__LeaveCurrentLobby;
public static Action <15>__ShowBlockStatus;
public static Action <16>__OpenDataFolder;
}
private const string ModVersion = "1.0.1";
private const int MaximumSavedUsers = 500;
private static readonly ConcurrentQueue<Action> MainThreadActions = new ConcurrentQueue<Action>();
private static readonly Dictionary<ulong, bool> OriginalForceHide = new Dictionary<ulong, bool>();
private static readonly Dictionary<ulong, float> OriginalVoiceVolume = new Dictionary<ulong, float>();
private static readonly Dictionary<ulong, bool> OriginalVoiceMuted = new Dictionary<ulong, bool>();
private static readonly Dictionary<ulong, List<GripInteractionState>> DisabledGripStates = new Dictionary<ulong, List<GripInteractionState>>();
private static PersonalBlockSettings _settings = new PersonalBlockSettings();
private static string _dataDirectory = string.Empty;
private static string _settingsPath = string.Empty;
private static Page? _lobbyPlayersPage;
private static Page? _blockedPlayersPage;
private static ulong? _selectedSteamId;
private static string _selectedName = string.Empty;
private static string _pendingAction = string.Empty;
private static ulong? _pendingActionSteamId;
private static DateTimeOffset _pendingActionExpiresUtc;
private static float _effectTimer;
private static bool _autoLeaveQueued;
public override void OnInitializeMelon()
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Expected O, but got Unknown
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Expected O, but got Unknown
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Expected O, but got Unknown
_dataDirectory = Path.Combine(MelonEnvironment.UserDataDirectory, "FusionPersonalBlock");
_settingsPath = Path.Combine(_dataDirectory, "blocked-users.json");
Directory.CreateDirectory(_dataDirectory);
LoadSettings();
BuildBoneMenu();
object obj = <>O.<0>__OnFusionJoinedServer;
if (obj == null)
{
ServerEvent val = OnFusionJoinedServer;
<>O.<0>__OnFusionJoinedServer = val;
obj = (object)val;
}
MultiplayerHooking.OnJoinedServer += (ServerEvent)obj;
object obj2 = <>O.<1>__OnFusionDisconnected;
if (obj2 == null)
{
ServerEvent val2 = OnFusionDisconnected;
<>O.<1>__OnFusionDisconnected = val2;
obj2 = (object)val2;
}
MultiplayerHooking.OnDisconnected += (ServerEvent)obj2;
object obj3 = <>O.<2>__OnFusionPlayerJoined;
if (obj3 == null)
{
PlayerUpdate val3 = OnFusionPlayerJoined;
<>O.<2>__OnFusionPlayerJoined = val3;
obj3 = (object)val3;
}
MultiplayerHooking.OnPlayerJoined += (PlayerUpdate)obj3;
object obj4 = <>O.<3>__OnFusionPlayerLeft;
if (obj4 == null)
{
PlayerUpdate val4 = OnFusionPlayerLeft;
<>O.<3>__OnFusionPlayerLeft = val4;
obj4 = (object)val4;
}
MultiplayerHooking.OnPlayerLeft += (PlayerUpdate)obj4;
NetworkPlayer.OnNetworkPlayerRegistered += OnNetworkPlayerRegistered;
if (NetworkInfo.HasServer)
{
OnFusionJoinedServer();
}
MelonLogger.Msg($"Fusion Personal Block v{"1.0.1"} ready with {_settings.BlockedUsers.Count} saved blocked player(s). All effects are local-only.");
}
public override void OnDeinitializeMelon()
{
//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
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Expected O, but got Unknown
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Expected O, but got Unknown
object obj = <>O.<0>__OnFusionJoinedServer;
if (obj == null)
{
ServerEvent val = OnFusionJoinedServer;
<>O.<0>__OnFusionJoinedServer = val;
obj = (object)val;
}
MultiplayerHooking.OnJoinedServer -= (ServerEvent)obj;
object obj2 = <>O.<1>__OnFusionDisconnected;
if (obj2 == null)
{
ServerEvent val2 = OnFusionDisconnected;
<>O.<1>__OnFusionDisconnected = val2;
obj2 = (object)val2;
}
MultiplayerHooking.OnDisconnected -= (ServerEvent)obj2;
object obj3 = <>O.<2>__OnFusionPlayerJoined;
if (obj3 == null)
{
PlayerUpdate val3 = OnFusionPlayerJoined;
<>O.<2>__OnFusionPlayerJoined = val3;
obj3 = (object)val3;
}
MultiplayerHooking.OnPlayerJoined -= (PlayerUpdate)obj3;
object obj4 = <>O.<3>__OnFusionPlayerLeft;
if (obj4 == null)
{
PlayerUpdate val4 = OnFusionPlayerLeft;
<>O.<3>__OnFusionPlayerLeft = val4;
obj4 = (object)val4;
}
MultiplayerHooking.OnPlayerLeft -= (PlayerUpdate)obj4;
NetworkPlayer.OnNetworkPlayerRegistered -= OnNetworkPlayerRegistered;
RestoreAllLocalEffects();
}
public override void OnUpdate()
{
Action result;
while (MainThreadActions.TryDequeue(out result))
{
try
{
result();
}
catch (Exception value)
{
MelonLogger.Error($"Fusion Personal Block action failed: {value}");
}
}
_effectTimer += Time.unscaledDeltaTime;
if (!(_effectTimer < 0.25f))
{
_effectTimer = 0f;
ApplyAllBlockedEffects();
}
}
private static void BuildBoneMenu()
{
//IL_000a: 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_0048: 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_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0249: Unknown result type (might be due to invalid IL or missing references)
//IL_0275: Unknown result type (might be due to invalid IL or missing references)
//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
Page obj = Page.Root.CreatePage("Fusion Personal Block", Color.magenta, 0, true);
obj.CreateFunction("Show selected player", Color.white, (Action)ShowSelectedPlayer);
_lobbyPlayersPage = obj.CreatePage("Select lobby player", Color.cyan, 0, true);
RefreshLobbyPlayersPage();
obj.CreateFunction("Refresh lobby players", Color.cyan, (Action)RefreshPlayerPages);
obj.CreateFunction("BLOCK selected player (press twice)", Color.red, (Action)BlockSelectedPlayer);
obj.CreateFunction("UNBLOCK selected player (press twice)", Color.green, (Action)UnblockSelectedPlayer);
obj.CreateFunction("Clear pending confirmation", Color.gray, (Action)delegate
{
ClearConfirmation();
});
_blockedPlayersPage = obj.CreatePage("Saved blocked players", Color.red, 0, true);
RefreshBlockedPlayersPage();
Page obj2 = obj.CreatePage("Local block settings", Color.yellow, 0, true);
obj2.CreateBool("Mute blocked players", Color.green, _settings.MuteBlockedPlayers, (Action<bool>)SetMuteBlockedPlayers);
obj2.CreateBool("Hide blocked players", Color.green, _settings.HideBlockedPlayers, (Action<bool>)SetHideBlockedPlayers);
obj2.CreateBool("Disable rig grabbing", Color.green, _settings.DisableRigGrabbing, (Action<bool>)SetDisableRigGrabbing);
obj2.CreateBool("Auto-leave blocked player", Color.red, _settings.AutoLeaveBlockedPlayer, (Action<bool>)SetAutoLeaveBlockedPlayer);
obj2.CreateFunction("Apply local effects now", Color.cyan, (Action)ApplyEffectsNow);
obj2.CreateFunction("Leave current Fusion lobby", Color.red, (Action)LeaveCurrentLobby);
obj.CreateFunction("Show block status", Color.white, (Action)ShowBlockStatus);
obj.CreateFunction("Open saved-list folder", Color.gray, (Action)OpenDataFolder);
}
private static void LoadSettings()
{
_settings = new PersonalBlockSettings();
if (!File.Exists(_settingsPath))
{
return;
}
try
{
PersonalBlockSettings personalBlockSettings = JsonSerializer.Deserialize<PersonalBlockSettings>(File.ReadAllText(_settingsPath), new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
if (personalBlockSettings == null || personalBlockSettings.SchemaVersion != 1)
{
throw new InvalidDataException("schemaVersion must be 1.");
}
PersonalBlockSettings personalBlockSettings2 = personalBlockSettings;
if (personalBlockSettings2.BlockedUsers == null)
{
List<PersonalBlockedUser> list = (personalBlockSettings2.BlockedUsers = new List<PersonalBlockedUser>());
}
personalBlockSettings.BlockedUsers = (from @group in personalBlockSettings.BlockedUsers.Where((PersonalBlockedUser user) => ulong.TryParse(user.SteamId, out var result) && result != 0).GroupBy<PersonalBlockedUser, string>((PersonalBlockedUser user) => user.SteamId, StringComparer.Ordinal)
select @group.First()).Take(500).ToList();
_settings = personalBlockSettings;
}
catch (Exception ex)
{
MelonLogger.Warning("Could not load the personal block list: " + ex.Message);
}
}
private static void SaveSettings()
{
try
{
_settings.SchemaVersion = 1;
string contents = JsonSerializer.Serialize(_settings, new JsonSerializerOptions
{
WriteIndented = true
});
string text = _settingsPath + ".new";
File.WriteAllText(text, contents);
File.Move(text, _settingsPath, overwrite: true);
}
catch (Exception value)
{
MelonLogger.Error($"Could not save the personal block list: {value}");
Warn("The personal block list could not be saved. Check MelonLoader logs.");
}
}
private static bool IsBlocked(ulong steamId)
{
ulong result;
return _settings.BlockedUsers.Any((PersonalBlockedUser user) => ulong.TryParse(user.SteamId, out result) && result == steamId);
}
private static PersonalBlockedUser? FindBlockedUser(ulong steamId)
{
ulong result;
return _settings.BlockedUsers.FirstOrDefault((PersonalBlockedUser user) => ulong.TryParse(user.SteamId, out result) && result == steamId);
}
private static NetworkPlayer? FindNetworkPlayer(ulong steamId)
{
return ((IEnumerable<NetworkPlayer>)NetworkPlayer.Players).FirstOrDefault((Func<NetworkPlayer, bool>)((NetworkPlayer player) => player.PlayerID != null && player.PlayerID.IsValid && player.PlayerID.PlatformID == steamId));
}
private static void OnFusionJoinedServer()
{
_autoLeaveQueued = false;
MainThreadActions.Enqueue(delegate
{
RefreshPlayerPages();
NetworkPlayer val = ((IEnumerable<NetworkPlayer>)NetworkPlayer.Players).FirstOrDefault((Func<NetworkPlayer, bool>)((NetworkPlayer player) => player.PlayerID != null && !player.PlayerID.IsMe && IsBlocked(player.PlayerID.PlatformID)));
if (((val != null) ? val.PlayerID : null) != null && _settings.AutoLeaveBlockedPlayer)
{
Notify("Blocked player detected", val.Username + " is in this lobby. Leaving locally.", (NotificationType)1, 6f);
QueueAutoLeave(val.PlayerID);
}
else
{
ApplyAllBlockedEffects();
}
});
}
private static void OnFusionDisconnected()
{
MainThreadActions.Enqueue(delegate
{
RestoreAllLocalEffects();
_autoLeaveQueued = false;
RefreshPlayerPages();
});
}
private static void OnFusionPlayerJoined(PlayerID playerId)
{
if (playerId == null || playerId.IsMe || !IsBlocked(playerId.PlatformID))
{
return;
}
MainThreadActions.Enqueue(delegate
{
string playerName = GetPlayerName(playerId.PlatformID);
if (_settings.AutoLeaveBlockedPlayer)
{
Notify("Blocked player joined", playerName + " joined. Leaving this lobby locally.", (NotificationType)1, 6f);
QueueAutoLeave(playerId);
}
else
{
ApplyBlockedEffects(playerId.PlatformID);
Notify("Blocked player joined", "Local mute, hide, and interaction settings were applied to " + playerName + ".", (NotificationType)0, 6f);
}
RefreshPlayerPages();
});
}
private static void OnFusionPlayerLeft(PlayerID playerId)
{
if (playerId != null)
{
ulong steamId = playerId.PlatformID;
MainThreadActions.Enqueue(delegate
{
RestorePlayerEffects(steamId);
RefreshPlayerPages();
});
}
}
private static void OnNetworkPlayerRegistered(NetworkPlayer player)
{
if (((player != null) ? player.PlayerID : null) != null && !player.PlayerID.IsMe && IsBlocked(player.PlayerID.PlatformID))
{
ulong steamId = player.PlayerID.PlatformID;
MainThreadActions.Enqueue(delegate
{
ApplyBlockedEffects(steamId);
});
}
}
private static void ApplyAllBlockedEffects()
{
if (!NetworkInfo.HasServer)
{
return;
}
NetworkPlayer[] array = NetworkPlayer.Players.ToArray();
foreach (NetworkPlayer val in array)
{
if (val.PlayerID != null && !val.PlayerID.IsMe)
{
if (IsBlocked(val.PlayerID.PlatformID))
{
ApplyBlockedEffects(val.PlayerID.PlatformID);
}
else
{
RestorePlayerEffects(val.PlayerID.PlatformID);
}
}
}
}
private static void ApplyBlockedEffects(ulong steamId)
{
NetworkPlayer val = FindNetworkPlayer(steamId);
if (((val != null) ? val.PlayerID : null) == null || val.PlayerID.IsMe)
{
return;
}
if (_settings.HideBlockedPlayers)
{
if (!OriginalForceHide.ContainsKey(steamId))
{
OriginalForceHide[steamId] = val.ForceHide;
}
val.ForceHide = true;
}
else
{
RestoreVisibility(steamId, val);
}
if (_settings.MuteBlockedPlayers)
{
IVoiceManager voiceManager = VoiceInfo.VoiceManager;
IVoiceSpeaker val2 = ((voiceManager != null) ? voiceManager.GetSpeaker(val.PlayerID) : null);
if (val2 != null)
{
if (!OriginalVoiceVolume.ContainsKey(steamId))
{
OriginalVoiceVolume[steamId] = val2.Volume;
}
val2.Volume = 0f;
}
RigVoiceSource voiceSource = val.VoiceSource;
if ((Object)(object)((voiceSource != null) ? voiceSource.VoiceSource : null) != (Object)null)
{
if (!OriginalVoiceMuted.ContainsKey(steamId))
{
OriginalVoiceMuted[steamId] = val.VoiceSource.VoiceSource.Muted;
}
val.VoiceSource.VoiceSource.Muted = true;
}
}
else
{
RestoreVoice(steamId, val);
}
if (_settings.DisableRigGrabbing)
{
RigRefs rigRefs = val.RigRefs;
if (rigRefs != null && rigRefs.IsValid)
{
DisableRigInteraction(steamId, val);
return;
}
}
RestoreRigInteraction(steamId);
}
private static void RestorePlayerEffects(ulong steamId)
{
NetworkPlayer player = FindNetworkPlayer(steamId);
RestoreVisibility(steamId, player);
RestoreVoice(steamId, player);
RestoreRigInteraction(steamId);
}
private static void RestoreVisibility(ulong steamId, NetworkPlayer? player)
{
if (OriginalForceHide.Remove(steamId, out var value) && player != null)
{
player.ForceHide = value;
}
}
private static void RestoreVoice(ulong steamId, NetworkPlayer? player)
{
if (OriginalVoiceVolume.Remove(steamId, out var value) && ((player != null) ? player.PlayerID : null) != null)
{
IVoiceManager voiceManager = VoiceInfo.VoiceManager;
IVoiceSpeaker val = ((voiceManager != null) ? voiceManager.GetSpeaker(player.PlayerID) : null);
if (val != null)
{
val.Volume = value;
}
}
if (OriginalVoiceMuted.Remove(steamId, out var value2))
{
object obj;
if (player == null)
{
obj = null;
}
else
{
RigVoiceSource voiceSource = player.VoiceSource;
obj = ((voiceSource != null) ? voiceSource.VoiceSource : null);
}
if ((Object)obj != (Object)null)
{
player.VoiceSource.VoiceSource.Muted = value2;
}
}
}
private static void DisableRigInteraction(ulong steamId, NetworkPlayer player)
{
RigRefs rigRefs = player.RigRefs;
if (((rigRefs != null) ? rigRefs.RigGrips : null) == null)
{
return;
}
if (!DisabledGripStates.TryGetValue(steamId, out List<GripInteractionState> value))
{
value = new List<GripInteractionState>();
DisabledGripStates[steamId] = value;
}
Grip[] rigGrips = player.RigRefs.RigGrips;
foreach (Grip grip in rigGrips)
{
if ((Object)(object)grip == (Object)null)
{
continue;
}
GripInteractionState gripInteractionState = value.FirstOrDefault((GripInteractionState saved) => (Object)(object)saved.Grip == (Object)(object)grip);
if (gripInteractionState == null)
{
gripInteractionState = new GripInteractionState(grip, ((HandReciever)grip).IsEnabled);
value.Add(gripInteractionState);
try
{
foreach (Hand item in grip.attachedHands.ToArray())
{
if ((Object)(object)((item != null) ? item.manager : null) != (Object)null && FusionPlayer.IsLocalPlayer(item.manager))
{
GripExtensions.TryDetach(grip, item);
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("Could not detach a local hand from a blocked rig: " + ex.Message);
}
}
if (((HandReciever)grip).IsEnabled)
{
((HandReciever)grip).DisableInteraction();
}
}
}
private static void RestoreRigInteraction(ulong steamId)
{
if (!DisabledGripStates.Remove(steamId, out List<GripInteractionState> value))
{
return;
}
foreach (GripInteractionState item in value)
{
try
{
if (!((Object)(object)item.Grip == (Object)null))
{
if (item.WasEnabled)
{
((HandReciever)item.Grip).EnableInteraction();
}
else
{
((HandReciever)item.Grip).DisableInteraction();
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("Could not restore a blocked rig interaction state: " + ex.Message);
}
}
}
private static void RestoreAllLocalEffects()
{
ulong[] array = OriginalForceHide.Keys.Concat(OriginalVoiceVolume.Keys).Concat(OriginalVoiceMuted.Keys).Concat(DisabledGripStates.Keys)
.Distinct()
.ToArray();
for (int i = 0; i < array.Length; i++)
{
RestorePlayerEffects(array[i]);
}
OriginalForceHide.Clear();
OriginalVoiceVolume.Clear();
OriginalVoiceMuted.Clear();
DisabledGripStates.Clear();
}
private static void QueueAutoLeave(PlayerID playerId)
{
if (_autoLeaveQueued || playerId == null || !IsBlocked(playerId.PlatformID))
{
return;
}
_autoLeaveQueued = true;
MainThreadActions.Enqueue(delegate
{
try
{
if (NetworkInfo.HasServer && IsBlocked(playerId.PlatformID))
{
NetworkInfo.Layer.Disconnect("Fusion Personal Block: blocked player present");
}
}
catch (Exception value)
{
MelonLogger.Error($"Could not leave the Fusion lobby: {value}");
Warn("Could not leave the Fusion lobby automatically.");
}
finally
{
_autoLeaveQueued = false;
}
});
}
private static void LeaveCurrentLobby()
{
if (!NetworkInfo.HasServer)
{
Warn("You are not connected to a Fusion lobby.");
return;
}
try
{
NetworkInfo.Layer.Disconnect("Fusion Personal Block: local leave");
Notify("Fusion Personal Block", "Left the Fusion lobby locally.", (NotificationType)3, 5f);
}
catch (Exception value)
{
MelonLogger.Error($"Could not leave the Fusion lobby: {value}");
Warn("Could not leave the current Fusion lobby.");
}
}
private static void RefreshPlayerPages()
{
RefreshLobbyPlayersPage();
RefreshBlockedPlayersPage();
}
private static void RefreshLobbyPlayersPage()
{
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_015c: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
if (_lobbyPlayersPage == null)
{
return;
}
_lobbyPlayersPage.RemoveAll();
NetworkPlayer[] array = NetworkPlayer.Players.Where((NetworkPlayer player) => player.PlayerID != null && player.PlayerID.IsValid && !player.PlayerID.IsMe).OrderBy<NetworkPlayer, string>((NetworkPlayer player) => player.Username, StringComparer.OrdinalIgnoreCase).ToArray();
if (!NetworkInfo.HasServer || array.Length == 0)
{
_lobbyPlayersPage.CreateFunction("No other Fusion players found", Color.gray, (Action)delegate
{
Warn("Join a Fusion lobby with another player, then refresh.");
});
return;
}
NetworkPlayer[] array2 = array;
foreach (NetworkPlayer val in array2)
{
ulong steamId = val.PlayerID.PlatformID;
string name = (string.IsNullOrWhiteSpace(val.Username) ? $"Steam {steamId}" : val.Username);
bool flag = IsBlocked(steamId);
_lobbyPlayersPage.CreateFunction(ShortText((flag ? "[BLOCKED]" : "[ALLOWED]") + " " + name, 54), flag ? Color.red : Color.green, (Action)delegate
{
SelectPlayer(steamId, name);
});
}
}
private static void RefreshBlockedPlayersPage()
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
if (_blockedPlayersPage == null)
{
return;
}
_blockedPlayersPage.RemoveAll();
if (_settings.BlockedUsers.Count == 0)
{
_blockedPlayersPage.CreateFunction("No saved blocked players", Color.gray, (Action)delegate
{
Notify("Fusion Personal Block", "Select a lobby player and block them first.", (NotificationType)0, 5f);
});
return;
}
foreach (PersonalBlockedUser item in _settings.BlockedUsers.OrderBy<PersonalBlockedUser, string>((PersonalBlockedUser user) => user.DisplayName, StringComparer.OrdinalIgnoreCase))
{
if (ulong.TryParse(item.SteamId, out var steamId))
{
string name = (string.IsNullOrWhiteSpace(item.DisplayName) ? $"Steam {steamId}" : item.DisplayName);
_blockedPlayersPage.CreateFunction(ShortText("[BLOCKED] " + name, 54), Color.red, (Action)delegate
{
SelectPlayer(steamId, name);
});
}
}
}
private static void SelectPlayer(ulong steamId, string name)
{
if (steamId == PlayerIDManager.LocalPlatformID)
{
Warn("You cannot add your own Steam account to the personal block list.");
return;
}
_selectedSteamId = steamId;
_selectedName = ShortText(name, 80);
ClearConfirmation(showNotification: false);
Notify("Player selected", $"{_selectedName} ({steamId}) is {(IsBlocked(steamId) ? "BLOCKED" : "ALLOWED")}.", (NotificationType)0, 7f);
}
private static void ShowSelectedPlayer()
{
if (!_selectedSteamId.HasValue)
{
Warn("Select someone from the lobby list or saved blocked players first.");
return;
}
Notify("Selected player", $"{_selectedName} | Steam ID {_selectedSteamId.Value} | {(IsBlocked(_selectedSteamId.Value) ? "BLOCKED" : "ALLOWED")}.", (NotificationType)0, 8f);
}
private static bool ConfirmAction(string action)
{
if (!_selectedSteamId.HasValue)
{
return false;
}
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
if (string.Equals(_pendingAction, action, StringComparison.Ordinal) && _pendingActionSteamId == _selectedSteamId && utcNow <= _pendingActionExpiresUtc)
{
ClearConfirmation(showNotification: false);
return true;
}
_pendingAction = action;
_pendingActionSteamId = _selectedSteamId;
_pendingActionExpiresUtc = utcNow.AddSeconds(12.0);
Notify("Confirm local block action", $"Press {action} again within 12 seconds for {_selectedName}.", (NotificationType)1, 8f);
return false;
}
private static void ClearConfirmation(bool showNotification = true)
{
_pendingAction = string.Empty;
_pendingActionSteamId = null;
_pendingActionExpiresUtc = default(DateTimeOffset);
if (showNotification)
{
Notify("Fusion Personal Block", "Pending confirmation cleared.", (NotificationType)0, 4f);
}
}
private static void BlockSelectedPlayer()
{
if (!_selectedSteamId.HasValue)
{
Warn("Select a current Fusion player before blocking.");
}
else if (IsBlocked(_selectedSteamId.Value))
{
Warn("The selected player is already on your personal block list.");
}
else if (_settings.BlockedUsers.Count >= 500)
{
Warn($"The personal block list is limited to {500} entries.");
}
else if (ConfirmAction("BLOCK"))
{
_settings.BlockedUsers.Add(new PersonalBlockedUser
{
SteamId = _selectedSteamId.Value.ToString(),
DisplayName = _selectedName,
AddedUtc = DateTimeOffset.UtcNow
});
SaveSettings();
ApplyBlockedEffects(_selectedSteamId.Value);
RefreshPlayerPages();
Notify("Player blocked locally", "Muted, hidden, and saved " + _selectedName + ". This affects only your game.", (NotificationType)3, 8f);
NetworkPlayer val = FindNetworkPlayer(_selectedSteamId.Value);
if (_settings.AutoLeaveBlockedPlayer && ((val != null) ? val.PlayerID : null) != null)
{
QueueAutoLeave(val.PlayerID);
}
}
}
private static void UnblockSelectedPlayer()
{
if (!_selectedSteamId.HasValue)
{
Warn("Select someone from Saved blocked players before unblocking.");
return;
}
PersonalBlockedUser personalBlockedUser = FindBlockedUser(_selectedSteamId.Value);
if (personalBlockedUser == null)
{
Warn("The selected player is not on your personal block list.");
}
else if (ConfirmAction("UNBLOCK"))
{
_settings.BlockedUsers.Remove(personalBlockedUser);
SaveSettings();
RestorePlayerEffects(_selectedSteamId.Value);
RefreshPlayerPages();
Notify("Player unblocked locally", "Restored local visibility and voice for " + _selectedName + ".", (NotificationType)3, 7f);
}
}
private static void SetMuteBlockedPlayers(bool value)
{
_settings.MuteBlockedPlayers = value;
SaveSettings();
if (!value)
{
ulong[] array = OriginalVoiceVolume.Keys.Concat(OriginalVoiceMuted.Keys).Distinct().ToArray();
foreach (ulong steamId in array)
{
RestoreVoice(steamId, FindNetworkPlayer(steamId));
}
}
ApplyAllBlockedEffects();
}
private static void SetHideBlockedPlayers(bool value)
{
_settings.HideBlockedPlayers = value;
SaveSettings();
if (!value)
{
ulong[] array = OriginalForceHide.Keys.ToArray();
foreach (ulong steamId in array)
{
RestoreVisibility(steamId, FindNetworkPlayer(steamId));
}
}
ApplyAllBlockedEffects();
}
private static void SetDisableRigGrabbing(bool value)
{
_settings.DisableRigGrabbing = value;
SaveSettings();
if (!value)
{
ulong[] array = DisabledGripStates.Keys.ToArray();
for (int i = 0; i < array.Length; i++)
{
RestoreRigInteraction(array[i]);
}
}
else
{
ApplyAllBlockedEffects();
}
Notify("Fusion Personal Block", "Blocked-player rig grabbing is now " + (value ? "disabled" : "allowed") + " locally.", (NotificationType)0, 5f);
}
private static void SetAutoLeaveBlockedPlayer(bool value)
{
_settings.AutoLeaveBlockedPlayer = value;
SaveSettings();
Notify("Fusion Personal Block", "Automatic lobby leave is now " + (value ? "ON" : "OFF") + ".", (NotificationType)0, 5f);
if (value && NetworkInfo.HasServer)
{
NetworkPlayer val = ((IEnumerable<NetworkPlayer>)NetworkPlayer.Players).FirstOrDefault((Func<NetworkPlayer, bool>)((NetworkPlayer player) => player.PlayerID != null && !player.PlayerID.IsMe && IsBlocked(player.PlayerID.PlatformID)));
if (((val != null) ? val.PlayerID : null) != null)
{
QueueAutoLeave(val.PlayerID);
}
}
}
private static void ApplyEffectsNow()
{
ApplyAllBlockedEffects();
Notify("Fusion Personal Block", "Local block effects reapplied to the current lobby.", (NotificationType)3, 5f);
}
private static void ShowBlockStatus()
{
int value = NetworkPlayer.Players.Count((NetworkPlayer player) => player.PlayerID != null && !player.PlayerID.IsMe && IsBlocked(player.PlayerID.PlatformID));
Notify("Fusion Personal Block status", $"{_settings.BlockedUsers.Count} saved; {value} in this lobby. Mute {OnOff(_settings.MuteBlockedPlayers)}, hide {OnOff(_settings.HideBlockedPlayers)}, rig block {OnOff(_settings.DisableRigGrabbing)}, auto-leave {OnOff(_settings.AutoLeaveBlockedPlayer)}.", (NotificationType)0, 10f);
}
private static void OpenDataFolder()
{
try
{
Process.Start(new ProcessStartInfo
{
FileName = _dataDirectory,
UseShellExecute = true
});
}
catch (Exception value)
{
MelonLogger.Error($"Could not open the personal block folder: {value}");
Warn("Could not open the saved-list folder.");
}
}
private static string GetPlayerName(ulong steamId)
{
NetworkPlayer val = FindNetworkPlayer(steamId);
if (val == null || string.IsNullOrWhiteSpace(val.Username))
{
return FindBlockedUser(steamId)?.DisplayName ?? $"Steam {steamId}";
}
return val.Username;
}
private static string ShortText(string value, int maximum)
{
string text = string.Join(" ", (value ?? string.Empty).Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries));
if (text.Length > maximum)
{
return text.Substring(0, Math.Max(1, maximum - 1)) + "…";
}
return text;
}
private static string OnOff(bool value)
{
if (!value)
{
return "OFF";
}
return "ON";
}
private static void Warn(string message)
{
MelonLogger.Warning(message);
Notify("Fusion Personal Block", message, (NotificationType)1, 6f);
}
private static void Notify(string title, string message, NotificationType type, float seconds)
{
//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_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: 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_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
Notifier.Send(new Notification
{
Title = new NotificationText(title),
Message = new NotificationText(message),
ShowTitleOnPopup = true,
PopupLength = seconds,
Type = type
});
}
}
public sealed class PersonalBlockSettings
{
public int SchemaVersion { get; set; } = 1;
public bool MuteBlockedPlayers { get; set; } = true;
public bool HideBlockedPlayers { get; set; } = true;
public bool DisableRigGrabbing { get; set; } = true;
public bool AutoLeaveBlockedPlayer { get; set; } = true;
public List<PersonalBlockedUser> BlockedUsers { get; set; } = new List<PersonalBlockedUser>();
}
public sealed class PersonalBlockedUser
{
public string SteamId { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
public DateTimeOffset AddedUtc { get; set; }
}
public sealed class GripInteractionState
{
public Grip Grip { get; }
public bool WasEnabled { get; }
public GripInteractionState(Grip grip, bool wasEnabled)
{
Grip = grip;
WasEnabled = wasEnabled;
}
}
}