using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HostUtils.Patches;
using I2.Loc;
using Newtonsoft.Json;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("HostUtils")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HostUtils")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c82bd0f9-281e-4e9c-9f5f-b0331416db5d")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace HostUtils
{
internal class BanlistGUI
{
private Vector2 scroll;
private bool showWindow = false;
private Rect windowRect = new Rect(100f, 100f, 400f, 400f);
public void Update()
{
if (Input.GetKeyDown((KeyCode)283))
{
showWindow = !showWindow;
}
}
public void OnGUI()
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
//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)
Cursor.visible = showWindow;
if (showWindow)
{
windowRect = GUI.Window(1234, windowRect, new WindowFunction(DrawWindow), "Banlist");
}
}
private void DrawWindow(int windowID)
{
//IL_000e: 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_002d: Unknown result type (might be due to invalid IL or missing references)
GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
scroll = GUILayout.BeginScrollView(scroll, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(350f) });
List<BannedPlayer> list = new List<BannedPlayer>();
for (int i = 0; i < HostUtilsBase.Instance.Banlist.bannedPlayers.Count; i++)
{
BannedPlayer bannedPlayer = HostUtilsBase.Instance.Banlist.bannedPlayers.ElementAt(i);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.Label(bannedPlayer.name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(250f) });
if (GUILayout.Button("Unban", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
{
list.Add(bannedPlayer);
}
GUILayout.EndHorizontal();
}
foreach (BannedPlayer item in list)
{
HostUtilsBase.Instance.UnbanPlayer(item);
}
GUILayout.EndScrollView();
if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
{
showWindow = false;
}
GUI.DragWindow();
GUILayout.EndVertical();
}
}
[BepInPlugin("HostUtils", "Host Utils", "0.0.3")]
public class HostUtilsBase : BaseUnityPlugin
{
private const string modGUID = "HostUtils";
private const string modName = "Host Utils";
private const string modVersion = "0.0.3";
private static Harmony harmony = new Harmony("HostUtils");
public static HostUtilsBase Instance;
internal ManualLogSource mls;
public ConfigEntry<bool> AllowSteamPlayers;
public ConfigEntry<bool> AllowPSNPlayers;
public ConfigEntry<bool> AllowXboxLivePlayers;
public ConfigEntry<bool> AllowNintendoPlayers;
public ConfigEntry<bool> AllowAndroidPlayers;
public ConfigEntry<bool> AllowOriginPlayers;
public ConfigEntry<bool> AllowWeGamePlayers;
public Banlist Banlist;
private string filePath = Path.Combine(Paths.PluginPath, "banlist.json");
private BanlistGUI gui;
private void Awake()
{
if (Paths.PluginPath.Substring(1).StartsWith(":/"))
{
filePath = Path.Combine(Paths.PluginPath + "/HostUtils/", "banlist.json");
}
else
{
filePath = Path.Combine(Paths.PluginPath + "\\HostUtils\\", "banlist.json");
}
if ((Object)(object)Instance == (Object)null)
{
Instance = this;
}
mls = Logger.CreateLogSource("HostUtils");
AllowSteamPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Crossplay", "AllowSteamPlayers", true, "Allow or deny players from Steam to join your lobby.");
AllowPSNPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Crossplay", "AllowPSNPlayers", true, "Allow or deny players from PSN to join your lobby.");
AllowXboxLivePlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Crossplay", "AllowXboxLivePlayers", true, "Allow or deny players from XboxLive to join your lobby.");
AllowNintendoPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Crossplay", "AllowNintendoPlayers", true, "Allow or deny players from Nintendo to join your lobby.");
AllowAndroidPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Crossplay", "AllowAndroidPlayers", true, "Allow or deny players from Android to join your lobby.");
AllowOriginPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Crossplay", "AllowOriginPlayers", true, "Allow or deny players from Origin to join your lobby.");
AllowWeGamePlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Crossplay", "AllowWeGamePlayers", true, "Allow or deny players from WeGame to join your lobby.");
gui = new BanlistGUI();
mls.LogInfo((object)"Plugin has been loaded.");
}
private void Start()
{
harmony.PatchAll();
mls.LogInfo((object)"Harmony patches applied.");
Banlist = LoadBanList();
}
private void Update()
{
gui.Update();
}
private void OnGUI()
{
gui.OnGUI();
}
private Banlist LoadBanList()
{
if (File.Exists(filePath))
{
string text = File.ReadAllText(filePath);
return new Banlist(JsonConvert.DeserializeObject<List<BannedPlayer>>(text));
}
((BaseUnityPlugin)this).Logger.LogWarning((object)("No file found to deserialize. Creating new one at \"" + filePath + "\""));
return new Banlist();
}
public void SaveBanList()
{
string contents = JsonConvert.SerializeObject((object)Banlist.bannedPlayers, (Formatting)1);
File.WriteAllText(filePath, contents);
}
public bool IsBanned(string playername, string platform, string id)
{
using (List<BannedPlayer>.Enumerator enumerator = Banlist.bannedPlayers.GetEnumerator())
{
if (enumerator.MoveNext())
{
BannedPlayer current = enumerator.Current;
if (id.Equals(""))
{
return current.platform == platform && playername == current.name;
}
return current.platform == platform && id == current.id;
}
}
return false;
}
public void BanPlayer(string name, string platform, string id)
{
BannedPlayer item = new BannedPlayer(name, platform, id);
Banlist.bannedPlayers.Add(item);
mls.LogInfo((object)(name + " has been banned."));
SaveBanList();
}
public void UnbanPlayer(BannedPlayer bannedPlayer)
{
Banlist.bannedPlayers.Remove(bannedPlayer);
mls.LogInfo((object)(bannedPlayer.name + " has been unbanned."));
SaveBanList();
}
}
}
namespace HostUtils.Patches
{
public class Banlist
{
public List<BannedPlayer> bannedPlayers;
public Banlist()
{
bannedPlayers = new List<BannedPlayer>();
}
public Banlist(List<BannedPlayer> bannedPlayers)
{
this.bannedPlayers = bannedPlayers;
}
}
public class BannedPlayer
{
public string name;
public string id;
public string platform;
public BannedPlayer(string name, string platform, string id)
{
this.name = name;
this.id = id;
this.platform = platform;
}
}
[HarmonyPatch(typeof(TabletOnlinePlayer))]
internal class TabletOnlinePlayerPatch
{
[HarmonyPrefix]
[HarmonyPatch("RefreshKickButton")]
private static bool RefreshKickButtonPatch(TabletOnlinePlayer __instance)
{
if (!LobbyManager.instance.IsHost)
{
return true;
}
((TabletStyledObject)__instance.voteKickButton).SetDisabled(__instance.lobbyPlayer.IsHost);
if (Input.GetKey((KeyCode)304))
{
__instance.kickButtonLabel.text = "Ban";
}
else
{
__instance.kickButtonLabel.Term = "Network/Kick";
}
return false;
}
}
[HarmonyPatch(typeof(LobbyPlayer))]
internal class LobbyPlayerPatch
{
[HarmonyPostfix]
[HarmonyPatch("Start")]
internal static void StartPatched(LobbyPlayer __instance)
{
if (!__instance.IsHost)
{
((MonoBehaviour)HostUtilsBase.Instance).StartCoroutine(WaitForRealInitialized(__instance));
}
}
private static IEnumerator WaitForRealInitialized(LobbyPlayer player)
{
yield return (object)new WaitUntil((Func<bool>)(() => player.playerName != ""));
SocialPlatform platform = player.platform;
string id = player.platformUniqueID;
HostUtilsBase.Instance.mls.LogInfo((object)((Object)(object)HostUtilsBase.Instance != (Object)null));
bool banned = HostUtilsBase.Instance.IsBanned(player.playerName, ((object)(SocialPlatform)(ref platform)).ToString(), id);
bool not_that_platform = (!HostUtilsBase.Instance.AllowSteamPlayers.Value && ((object)(SocialPlatform)(ref platform)).Equals((object)(SocialPlatform)1)) || (!HostUtilsBase.Instance.AllowPSNPlayers.Value && ((object)(SocialPlatform)(ref platform)).Equals((object)(SocialPlatform)2)) || (!HostUtilsBase.Instance.AllowXboxLivePlayers.Value && ((object)(SocialPlatform)(ref platform)).Equals((object)(SocialPlatform)3)) || (!HostUtilsBase.Instance.AllowNintendoPlayers.Value && ((object)(SocialPlatform)(ref platform)).Equals((object)(SocialPlatform)4)) || (!HostUtilsBase.Instance.AllowAndroidPlayers.Value && ((object)(SocialPlatform)(ref platform)).Equals((object)(SocialPlatform)5)) || (!HostUtilsBase.Instance.AllowOriginPlayers.Value && ((object)(SocialPlatform)(ref platform)).Equals((object)(SocialPlatform)6)) || (!HostUtilsBase.Instance.AllowWeGamePlayers.Value && ((object)(SocialPlatform)(ref platform)).Equals((object)(SocialPlatform)7));
if (banned || not_that_platform)
{
string reason = (banned ? "banned" : "wrong platform");
HostUtilsBase.Instance.mls.LogInfo((object)(player.playerName + " was kicked due to reason: " + reason));
LobbyManager.instance.IssueKickMessage(player.networkNumber, (KickReasons)0);
}
else
{
HostUtilsBase.Instance.mls.LogInfo((object)(player.playerName + " logged from " + ((object)(SocialPlatform)(ref platform)).ToString() + " with unique_id=" + id));
}
yield return null;
}
}
[HarmonyPatch(typeof(TabletOnlinePlayersScreen))]
internal class TabletOnlinePlayersScreenPatch
{
private static bool banning;
private static bool lastUpdateShift;
[HarmonyPrefix]
[HarmonyPatch("OnKickPromptConfirm")]
private static bool OnKickPromptConfirmPatch(TabletOnlinePlayersScreen __instance)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
if (LobbyManager.instance.IsHost)
{
FieldInfo field = typeof(TabletOnlinePlayersScreen).GetField("kickedLobbyPlayer", BindingFlags.Instance | BindingFlags.NonPublic);
LobbyPlayer val = (LobbyPlayer)field.GetValue(__instance);
if ((Object)(object)val == (Object)null)
{
return false;
}
if (banning)
{
HostUtilsBase.Instance.BanPlayer(val.playerName, ((object)(SocialPlatform)(ref val.platform)).ToString(), val.platformUniqueID);
}
LobbyManager.instance.IssueKickMessage(val.networkNumber, (KickReasons)0);
__instance.subdialogController.TransitionRightTo((Transform)(object)__instance.mainDialog, (TransitionSound)0, true);
return false;
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch("ShowKickPrompt")]
private static void ShowKickPromptPatch(TabletOnlinePlayersScreen __instance, int kickingPlayerNetworkNumber, LobbyPlayer lobbyPlayer)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
if (LobbyManager.instance.IsHost)
{
FieldInfo field = typeof(TabletOnlinePlayersScreen).GetField("kickedLobbyPlayer", BindingFlags.Instance | BindingFlags.NonPublic);
LobbyPlayer val = (LobbyPlayer)field.GetValue(__instance);
TabletTextLabel promptTextLabel = __instance.promptTextLabel;
TabletTextLabel promptConfirmButtonLabel = __instance.promptConfirmButtonLabel;
if (Input.GetKey((KeyCode)304))
{
banning = true;
promptTextLabel.text = "Are you sure you want to ban " + lobbyPlayer.playerName + "?";
promptConfirmButtonLabel.text = "Ban";
}
else
{
banning = false;
promptTextLabel.text = string.Format(Network.AreyousureKick, lobbyPlayer.playerName);
promptConfirmButtonLabel.Term = "Network/Kick";
}
}
}
[HarmonyPostfix]
[HarmonyPatch("Update")]
private static void UpdatePatch(TabletOnlinePlayersScreen __instance)
{
if (!LobbyManager.instance.IsHost)
{
return;
}
bool key = Input.GetKey((KeyCode)304);
if (lastUpdateShift != key)
{
GameObject gameObject = ((Component)__instance.playerList).gameObject;
TabletOnlinePlayer[] componentsInChildren = gameObject.GetComponentsInChildren<TabletOnlinePlayer>();
foreach (TabletOnlinePlayer val in componentsInChildren)
{
if (!val.lobbyPlayer.IsHost)
{
val.RefreshKickButton();
}
}
}
lastUpdateShift = key;
}
}
}