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.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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; } } } [BepInPlugin("com.Puppeg.votekick", "VoteKick", "1.0.1")] public class VoteKickPlugin : BaseUnityPlugin { public class VoteSession { public Player Target; public float EndTime; public HashSet Voters = new HashSet(); } internal static ManualLogSource Log; private Harmony harmony; public static PlayerAvatar HostAvatar; public static VoteSession? CurrentVote; public static void StartVote(string starter, Player target) { if (CurrentVote != null) { Log.LogInfo((object)"Vote already active"); return; } CurrentVote = new VoteSession { Target = target, EndTime = Time.time + 30f }; AddVote(starter); HostAvatar.ChatMessageSend("Vote kick started against " + target.NickName + ". Type !yes to vote."); Log.LogInfo((object)("Vote kick started against " + target.NickName)); } public static void AddVote(string voter) { if (CurrentVote != null) { if (CurrentVote.Voters.Contains(voter)) { Log.LogInfo((object)(voter + " already voted")); return; } CurrentVote.Voters.Add(voter); Log.LogInfo((object)$"{voter} voted YES ({CurrentVote.Voters.Count})"); CheckVote(); } } public static void CheckVote() { if (CurrentVote != null && !(Time.time >= CurrentVote.EndTime)) { int num = PhotonNetwork.PlayerList.Length; int num2 = Mathf.CeilToInt((float)num * 0.5f); HostAvatar.ChatMessageSend($"{num2}/{num} voted to kick"); if (CurrentVote.Voters.Count >= num2) { Log.LogInfo((object)("Vote passed against " + CurrentVote.Target.NickName)); EndVote(passed: true); } } } public static void EndVote(bool passed) { if (CurrentVote == null) { return; } if (passed) { foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (SemiFunc.PlayerGetName(player) == CurrentVote.Target.NickName) { PlayerAvatar val = player; NetworkManager.instance.BanPlayer(val); CurrentVote = null; HostAvatar.ChatMessageSend("Player " + CurrentVote.Target.NickName + " has been banned."); return; } } Log.LogInfo((object)("Player " + CurrentVote.Target.NickName + " not found. Can't Ban")); } else { HostAvatar.ChatMessageSend("Vote timed out"); CurrentVote = null; } } private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; harmony = new Harmony("com.yourname.votekick"); harmony.PatchAll(); Log.LogInfo((object)"VoteKick Chat Logger loaded 1.01"); } } public static class PlayerSearch { public static int Levenshtein(string a, string b) { if (string.IsNullOrEmpty(a)) { return b.Length; } if (string.IsNullOrEmpty(b)) { return a.Length; } int[,] array = new int[a.Length + 1, b.Length + 1]; for (int i = 0; i <= a.Length; i++) { for (int j = 0; j <= b.Length; j++) { if (i == 0) { array[i, j] = j; continue; } if (j == 0) { array[i, j] = i; continue; } int num = ((a[i - 1] != b[j - 1]) ? 1 : 0); array[i, j] = Mathf.Min(Mathf.Min(array[i - 1, j] + 1, array[i, j - 1] + 1), array[i - 1, j - 1] + num); } } return array[a.Length, b.Length]; } public static Player FindBestMatch(string input) { input = input.ToLowerInvariant(); Player result = null; int num = int.MaxValue; Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (!string.IsNullOrEmpty(val.NickName)) { string text = val.NickName.ToLowerInvariant(); if (text == input) { return val; } if (text.Contains(input)) { return val; } int num2 = Levenshtein(input, text); if (num2 < num) { num = num2; result = val; } } } if (num <= 3) { return result; } return null; } } public static class ChatCommands { public static void VoteCommand(string _message, string senderName) { if (_message.Length <= "!vote kick ".Length) { VoteKickPlugin.Log.LogInfo((object)"No target specified"); } else if (VoteKickPlugin.CurrentVote == null) { string text = _message.Substring("!vote kick ".Length).Trim(); if (text == PhotonNetwork.MasterClient.NickName) { VoteKickPlugin.Log.LogInfo((object)"Can't kick host"); return; } Player val = PlayerSearch.FindBestMatch(text); if (val != null) { VoteKickPlugin.StartVote(senderName, val); VoteKickPlugin.Log.LogInfo((object)$"[VOTE] {senderName} voted to kick {val}"); } else { VoteKickPlugin.Log.LogDebug((object)("Player " + text + " not found")); } } else { VoteKickPlugin.Log.LogInfo((object)$"Currently voting on {VoteKickPlugin.CurrentVote.Target}, can't start another vote"); } } public static void AgreeCommand(string senderName) { VoteKickPlugin.AddVote(senderName); VoteKickPlugin.Log.LogInfo((object)(senderName + " voted Yes!")); } public static void ResetCommand() { VoteKickPlugin.CurrentVote = null; } } [HarmonyPatch(typeof(PlayerAvatar), "ChatMessageSendRPC")] public static class ChatLoggerPatch { private static void Prefix(PlayerAvatar __instance, string _message, bool crouching, PhotonMessageInfo _info) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient) { VoteKickPlugin.HostAvatar = __instance; Player sender = _info.Sender; string text = ((sender != null) ? sender.NickName : null) ?? "Unknown"; if (_message.StartsWith("!vote kick")) { ChatCommands.VoteCommand(_message, text); } else if (_message.StartsWith("!yes")) { ChatCommands.AgreeCommand(text); } else if (_message.StartsWith("!vote reset") && text == PhotonNetwork.MasterClient.NickName) { ChatCommands.ResetCommand(); } } } } namespace VoteKick { public static class PluginInfo { public const string PLUGIN_GUID = "VoteKick"; public const string PLUGIN_NAME = "VoteKick"; public const string PLUGIN_VERSION = "1.0.0"; } }