Decompiled source of AutoScoreBan v1.0.1

AutoScoreBan.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ComputerysModdingUtilities;
using FishNet;
using FishNet.Connection;
using FishNet.Object;
using HarmonyLib;
using HeathenEngineering.SteamworksIntegration;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: StraftatMod(true)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AutoScoreBan")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Automatically bans players with score below a configurable threshold when hosting")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("AutoScoreBan")]
[assembly: AssemblyTitle("AutoScoreBan")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[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 AutoScoreBan
{
	[BepInPlugin("com.balu.straftat.autoscoreban", "AutoScoreBan", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.balu.straftat.autoscoreban";

		public const string PLUGIN_NAME = "AutoScoreBan";

		public const string PLUGIN_VERSION = "1.0.1";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		public static ConfigEntry<bool> ModEnabled;

		public static ConfigEntry<int> MinScore;

		public static ConfigEntry<bool> IgnoreFriends;

		public static ConfigEntry<bool> BanUnranked;

		public static ConfigEntry<string> BanReason;

		public static ConfigEntry<bool> NotifyInChat;

		private void Awake()
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Whether auto-banning players by score is enabled.");
			MinScore = ((BaseUnityPlugin)this).Config.Bind<int>("Settings", "MinScore", 1000, "Minimum required score. Players with a score below this value will be automatically banned when you host a lobby.");
			IgnoreFriends = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "IgnoreFriends", true, "Ignore Steam friends (never ban them regardless of their score).");
			BanUnranked = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "BanUnranked", true, "Treat players without a leaderboard entry as having 0 score (and ban them if MinScore > 0).");
			BanReason = ((BaseUnityPlugin)this).Config.Bind<string>("Settings", "BanReason", "I'm doing this for your own good", "Kick/ban message displayed to the player upon being banned.");
			NotifyInChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "NotifyInChat", true, "Whether to display an auto-ban notification in the in-game chat / pause log.");
			_harmony = new Harmony("com.balu.straftat.autoscoreban");
			_harmony.PatchAll();
			Log.LogInfo((object)string.Format("[{0}] Plugin initialized successfully! Score threshold: {1}, friends protected: {2}", "AutoScoreBan", MinScore.Value, IgnoreFriends.Value));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public static class ScoreAutoBanManager
	{
		private static readonly Dictionary<ulong, int> CachedScores = new Dictionary<ulong, int>();

		private static readonly HashSet<ulong> InFlightFetches = new HashSet<ulong>();

		private static readonly HashSet<ulong> BannedThisSession = new HashSet<ulong>();

		private static readonly FieldRef<Settings, LeaderboardManager> GetLeaderboardManagerRef = AccessTools.FieldRefAccess<Settings, LeaderboardManager>("leaderboardManager");

		public static bool IsHost()
		{
			//IL_0078: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)InstanceFinder.NetworkManager != (Object)null && InstanceFinder.NetworkManager.IsServer)
				{
					return true;
				}
				if ((Object)(object)ClientInstance.Instance != (Object)null && ((NetworkBehaviour)ClientInstance.Instance).IsServer)
				{
					return true;
				}
				if ((Object)(object)SteamLobby.Instance != (Object)null && SteamLobby.Instance.CurrentLobbyID != 0)
				{
					CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(new CSteamID(SteamLobby.Instance.CurrentLobbyID));
					if (lobbyOwner == SteamUser.GetSteamID())
					{
						return true;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[AutoScoreBan] Error checking host status: " + ex.Message));
			}
			return false;
		}

		public static bool IsFriend(ulong steamId)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			try
			{
				EFriendRelationship friendRelationship = SteamFriends.GetFriendRelationship((CSteamID)steamId);
				return (int)friendRelationship == 3;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)$"[AutoScoreBan] Error checking friend relationship for {steamId}: {ex.Message}");
				return false;
			}
		}

		public static LeaderboardManager GetLeaderboardManager()
		{
			if ((Object)(object)Settings.Instance == (Object)null)
			{
				return null;
			}
			try
			{
				LeaderboardManager val = GetLeaderboardManagerRef.Invoke(Settings.Instance);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			catch
			{
			}
			return ((Component)Settings.Instance).GetComponentInChildren<LeaderboardManager>();
		}

		public static void CheckPlayer(PlayerListItem listItem)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ModEnabled.Value || !IsHost() || (Object)(object)listItem == (Object)null)
			{
				return;
			}
			ulong steamId = listItem.PlayerSteamID;
			if (steamId == 0)
			{
				return;
			}
			ulong num = 0uL;
			try
			{
				num = (ulong)SteamUser.GetSteamID();
			}
			catch
			{
			}
			if (steamId == num)
			{
				return;
			}
			string playerName = listItem.PlayerName ?? $"SteamID_{steamId}";
			if (BannedThisSession.Contains(steamId))
			{
				CachedScores.TryGetValue(steamId, out var value);
				EnsurePlayerKicked(steamId, playerName, value);
			}
			else
			{
				if (Plugin.IgnoreFriends.Value && IsFriend(steamId))
				{
					return;
				}
				if (CachedScores.TryGetValue(steamId, out var value2))
				{
					EvaluateScoreAndBan(steamId, playerName, value2);
				}
				else
				{
					if (InFlightFetches.Contains(steamId))
					{
						return;
					}
					LeaderboardManager leaderboardManager = GetLeaderboardManager();
					if ((Object)(object)leaderboardManager == (Object)null || (Object)(object)leaderboardManager.leaderboard == (Object)null || !leaderboardManager.leaderboard.Valid)
					{
						return;
					}
					InFlightFetches.Add(steamId);
					Plugin.Log.LogInfo((object)$"[AutoScoreBan] Fetching score for player '{playerName}' ({steamId}) from Steam Leaderboard...");
					UserData val = UserData.Get(steamId);
					leaderboardManager.leaderboard.GetEntries((UserData[])(object)new UserData[1] { val }, (Action<LeaderboardEntry[], bool>)delegate(LeaderboardEntry[] results, bool error)
					{
						InFlightFetches.Remove(steamId);
						try
						{
							if (error || results == null || results.Length == 0)
							{
								Plugin.Log.LogInfo((object)$"[AutoScoreBan] Player '{playerName}' ({steamId}) has no entry on leaderboard (error={error}).");
								if (Plugin.BanUnranked.Value)
								{
									CachedScores[steamId] = 0;
									EvaluateScoreAndBan(steamId, playerName, 0);
								}
							}
							else
							{
								int score = results[0].Score;
								int rank = results[0].Rank;
								Plugin.Log.LogInfo((object)$"[AutoScoreBan] Retrieved data for player '{playerName}' ({steamId}): Score={score}, Rank={rank}.");
								CachedScores[steamId] = score;
								EvaluateScoreAndBan(steamId, playerName, score);
							}
						}
						catch (Exception arg)
						{
							Plugin.Log.LogError((object)$"[AutoScoreBan] Error processing score callback for {playerName} ({steamId}): {arg}");
						}
					});
				}
			}
		}

		private static void EvaluateScoreAndBan(ulong steamId, string playerName, int score)
		{
			if (Plugin.ModEnabled.Value && IsHost() && (!Plugin.IgnoreFriends.Value || !IsFriend(steamId)))
			{
				int value = Plugin.MinScore.Value;
				if (score < value && BannedThisSession.Add(steamId))
				{
					ExecuteBan(steamId, playerName, score, value);
				}
			}
		}

		private static void ExecuteBan(ulong steamId, string playerName, int score, int threshold)
		{
			Plugin.Log.LogWarning((object)$"[AutoScoreBan] Auto-banning player '{playerName}' ({steamId}): score {score} < {threshold}.");
			try
			{
				if ((Object)(object)SteamLobby.Instance != (Object)null)
				{
					SteamLobby.Instance.AddLobbyBan(steamId);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[AutoScoreBan] Error in SteamLobby.AddLobbyBan: " + ex.Message));
			}
			if (Plugin.NotifyInChat.Value)
			{
				try
				{
					if ((Object)(object)PauseManager.Instance != (Object)null)
					{
						PauseManager.Instance.WriteLog($"[AutoScoreBan] <color=#ff4444>{playerName}</color> was banned by the host (Score: {score} < {threshold})");
					}
				}
				catch
				{
				}
			}
			EnsurePlayerKicked(steamId, playerName, score);
		}

		private static void EnsurePlayerKicked(ulong steamId, string playerName, int score)
		{
			if ((Object)(object)GameManager.Instance == (Object)null)
			{
				return;
			}
			NetworkConnection val = FindNetworkConnection(steamId);
			if (!(val != (NetworkConnection)null))
			{
				return;
			}
			string text = ((!string.IsNullOrEmpty(Plugin.BanReason.Value)) ? Plugin.BanReason.Value : "I'm doing this for your own good");
			Plugin.Log.LogInfo((object)$"[AutoScoreBan] Kicking network client ConnId={val.ClientId} ({playerName}) with reason: '{text}'");
			try
			{
				GameManager.Instance.CmdKickPlayer(val, text);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[AutoScoreBan] Error calling CmdKickPlayer: " + ex.Message));
			}
		}

		private static NetworkConnection FindNetworkConnection(ulong steamId)
		{
			if (ClientInstance.playerInstances != null)
			{
				foreach (ClientInstance value in ClientInstance.playerInstances.Values)
				{
					if ((Object)(object)value != (Object)null && value.PlayerSteamID == steamId)
					{
						return ((NetworkBehaviour)value).Owner;
					}
				}
			}
			if ((Object)(object)SteamLobby.Instance != (Object)null && SteamLobby.Instance.players != null)
			{
				for (int i = 0; i < SteamLobby.Instance.players.Count; i++)
				{
					NetworkObject val = SteamLobby.Instance.players[i];
					if ((Object)(object)val != (Object)null)
					{
						ClientInstance component = ((Component)val).GetComponent<ClientInstance>();
						if ((Object)(object)component != (Object)null && component.PlayerSteamID == steamId)
						{
							return val.Owner;
						}
					}
				}
			}
			return null;
		}

		public static void OnLeaveLobby()
		{
			BannedThisSession.Clear();
			InFlightFetches.Clear();
			Plugin.Log.LogInfo((object)"[AutoScoreBan] Left lobby: session state cleared.");
		}
	}
	[HarmonyPatch(typeof(PlayerListItem), "SetPlayerValues")]
	public static class PlayerListItem_SetPlayerValues_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(PlayerListItem __instance)
		{
			try
			{
				ScoreAutoBanManager.CheckPlayer(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoScoreBan] Error in SetPlayerValues hook: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "LeaveLobby")]
	public static class SteamLobby_LeaveLobby_Patch
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			try
			{
				ScoreAutoBanManager.OnLeaveLobby();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[AutoScoreBan] Error in LeaveLobby hook: {arg}");
			}
		}
	}
}