Decompiled source of VoidManager v1.0.7
VoidManager.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CG; using CG.Client.UserData; using CG.Game; using CG.Game.Player; using CG.GameLoopStateMachine; using CG.GameLoopStateMachine.GameStates; using CG.Input; using CG.Profile; using Client.Utils; using ExitGames.Client.Photon; using Gameplay.Chat; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using ResourceAssets; using ToolClasses; using UI.Chat; using UI.Matchmaking; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using UnityEngine.UIElements; using VivoxUnity; using VoidManager.Callbacks; using VoidManager.Chat.Router; using VoidManager.Content; using VoidManager.CustomGUI; using VoidManager.MPModChecks; using VoidManager.ModMessages; using VoidManager.Utilities; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("VoidManager")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Handles Inputs and Commands")] [assembly: AssemblyFileVersion("1.0.7.0")] [assembly: AssemblyInformationalVersion("1.0.7")] [assembly: AssemblyProduct("VoidManager")] [assembly: AssemblyTitle("VoidManager")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.7.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace VoidManager { [BepInPlugin("VoidManager", "VoidManager", "1.0.7")] [BepInProcess("Void Crew.exe")] public class BepinPlugin : BaseUnityPlugin { internal class Bindings { internal static ConfigEntry<TextAnchor> ModInfoTextAnchor; internal static ConfigEntry<bool> DebugMode; internal static ConfigEntry<float> MenuHeight; internal static ConfigEntry<float> MenuWidth; internal static ConfigEntry<float> MenuListWidth; internal static ConfigEntry<float> PlayerListWidth; internal static ConfigEntry<bool> MenuUnlockCursor; internal static ConfigEntry<KeyboardShortcut> MenuOpenKeybind; internal static KeyboardShortcut OpenMenu = new KeyboardShortcut((KeyCode)286, Array.Empty<KeyCode>()); internal static ConfigEntry<bool> TrustMPTypeUnspecified; internal static ConfigEntry<string> UnspecifiedModListOverride; internal static Dictionary<string, MultiplayerType> ModOverrideDictionary; public static void SetDefault() { ModInfoTextAnchor.Value = (TextAnchor)0; } internal static void LoadModListOverride() { ModOverrideDictionary = new Dictionary<string, MultiplayerType>(); if (UnspecifiedModListOverride.Value == string.Empty) { return; } string[] array = UnspecifiedModListOverride.Value.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text in array2) { if (text.EndsWith(":all", StringComparison.CurrentCultureIgnoreCase)) { ModOverrideDictionary.Add(text.Substring(0, text.Length - 4), MultiplayerType.All); } else if (text.EndsWith(":client", StringComparison.CurrentCultureIgnoreCase)) { ModOverrideDictionary.Add(text.Substring(0, text.Length - 7), MultiplayerType.Client); } else if (text.EndsWith(":h", StringComparison.CurrentCultureIgnoreCase)) { ModOverrideDictionary.Add(text.Substring(0, text.Length - 2), MultiplayerType.Hidden); } else { Log.LogError((object)("Unspecified Mod Override - '" + text + "' is not a valid input.")); } } } } internal static BepinPlugin instance; internal static readonly Harmony Harmony = new Harmony("VoidManager"); internal static ManualLogSource Log; private void Awake() { //IL_0162: Unknown result type (might be due to invalid IL or missing references) instance = this; Log = ((BaseUnityPlugin)this).Logger; Harmony.PatchAll(); Craftables.Instance = new Craftables(); Unlocks.Instance = new Unlocks(); Log.LogInfo((object)"VoidManager Initialized."); Bindings.DebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugMode", false, ""); Bindings.UnspecifiedModListOverride = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Unspecified Mod Overrides", string.Empty, "Insert mods (not configured for VoidManager) for which you would like to override the MPType. Format: 'ModNameOrGUID:ClientOrAll', delineated by ','. Ex: VoidManager:all,Better Scoop:Client \n ModName/GUID can be gathered from log files and F5 menu."); Bindings.ModInfoTextAnchor = ((BaseUnityPlugin)this).Config.Bind<TextAnchor>("Menu", "ModInfoTextAnchor", (TextAnchor)0, ""); Bindings.MenuHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "Height", 0.5f, ""); Bindings.MenuWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "Width", 0.5f, ""); Bindings.MenuListWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "List Width", 0.3f, ""); Bindings.PlayerListWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "Player List Width", 0.3f, ""); Bindings.MenuUnlockCursor = ((BaseUnityPlugin)this).Config.Bind<bool>("Menu", "Unlock Cursor", true, ""); Bindings.MenuOpenKeybind = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Menu", "Open Keybind", Bindings.OpenMenu, ""); Bindings.TrustMPTypeUnspecified = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "TrustMPTypeUnspecified", false, ""); } } internal class DefaultVoidPlugin : VoidPlugin { internal MultiplayerType m_MPType; public override string Author => string.Empty; public override string Description => "Info auto-filled"; public override MultiplayerType MPType => m_MPType; internal DefaultVoidPlugin(MultiplayerType inputMPType) { m_MPType = inputMPType; } } public class Events { public class PlayerEventArgs : EventArgs { public Player player; } [HarmonyPatch(typeof(GameSessionManager), "HostGameSession")] private class HostStartSessionpatch { private static void Postfix() { Instance.OnHostStartSession(); } } public static Events Instance { get; internal set; } public event EventHandler<PlayerEventArgs> PlayerEnteredRoom; public event EventHandler<PlayerEventArgs> PlayerLeftRoom; public event EventHandler JoinedRoom; public event EventHandler LeftRoom; public event EventHandler<PlayerEventArgs> MasterClientSwitched; public event EventHandler<PlayerEventArgs> HostVerifiedClient; public event EventHandler<PlayerEventArgs> ClientModlistRecieved; public event EventHandler HostStartSession; internal void OnPlayerEnteredRoom(Player joiningPlayer) { this.PlayerEnteredRoom?.Invoke(this, new PlayerEventArgs { player = joiningPlayer }); } internal void OnPlayerLeftRoom(Player leavingPlayer) { this.PlayerLeftRoom?.Invoke(this, new PlayerEventArgs { player = leavingPlayer }); } internal void OnJoinedRoom() { this.JoinedRoom?.Invoke(this, EventArgs.Empty); } internal void CallOnLeftRoom() { this.LeftRoom?.Invoke(this, EventArgs.Empty); } internal void CallOnMasterClientSwitched(Player newMasterClient) { this.MasterClientSwitched?.Invoke(this, new PlayerEventArgs { player = newMasterClient }); } internal void CallHostOnClientVerified(Player verifiedPlayer) { this.HostVerifiedClient?.Invoke(this, new PlayerEventArgs { player = verifiedPlayer }); } internal void OnClientModlistRecieved(Player DataSender) { this.ClientModlistRecieved?.Invoke(this, new PlayerEventArgs { player = DataSender }); } internal void OnHostStartSession() { this.HostStartSession?.Invoke(this, EventArgs.Empty); } } [HarmonyPatch(typeof(PlayerProfileLoader), "Awake")] internal class PluginDetectPatch { [HarmonyPostfix] public static void PostAwakeInit() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) BepinPlugin.Log.LogInfo((object)"- - - Void Manager Initialization - - -"); Events.Instance = new Events(); ((Object)new GameObject("ModManager", new Type[1] { typeof(GUIMain) })).hideFlags = (HideFlags)61; PluginHandler.DiscoverPlugins(); MPModCheckManager.Instance = new MPModCheckManager(); BepinPlugin.Log.LogInfo((object)"- - - - - - - - - - - - - - - - - - - -"); } } [HarmonyPatch(typeof(GSMainMenu), "OnEnter")] internal class InitRoomCallbacksPatch { private static bool RoomCallbacksInitialized; [HarmonyPostfix] private static void InitRoomCallbacks() { if (!RoomCallbacksInitialized) { RoomCallbacksInitialized = true; MPModCheckManager.RoomCallbacksClass = new InRoomCallbacks(); } } } internal static class PluginHandler { public static Dictionary<string, PluginInfo> ActiveBepinPlugins => Chainloader.PluginInfos; public static Dictionary<string, VoidPlugin> ActiveVoidPlugins { get; private set; } public static Dictionary<string, VoidPlugin> GeneratedVoidPlugins { get; private set; } internal static void DiscoverPlugins() { BepinPlugin.Bindings.LoadModListOverride(); Dictionary<string, MultiplayerType> modOverrideDictionary = BepinPlugin.Bindings.ModOverrideDictionary; ActiveVoidPlugins = new Dictionary<string, VoidPlugin>(); GeneratedVoidPlugins = new Dictionary<string, VoidPlugin>(); foreach (PluginInfo value2 in Chainloader.PluginInfos.Values) { Assembly assembly = ((object)value2.Instance).GetType().Assembly; string gUID = value2.Metadata.GUID; string name = value2.Metadata.Name; if (gUID == "VoidManager") { CommandHandler.DiscoverCommands(assembly, name); CommandHandler.DiscoverPublicCommands(assembly, name); ModMessageHandler.DiscoverModMessages(assembly, value2); continue; } IEnumerable<Type> source = from t in assembly.GetTypes() where typeof(VoidPlugin).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract select t; if (source.Any()) { VoidPlugin voidPlugin = (VoidPlugin)Activator.CreateInstance(source.First()); voidPlugin.VersionInfo = FileVersionInfo.GetVersionInfo(value2.Location); voidPlugin.ModHash = GetFileHash(value2.Location); voidPlugin.BepinPlugin = value2; CommandHandler.DiscoverCommands(assembly, name); CommandHandler.DiscoverPublicCommands(assembly, name); ModMessageHandler.DiscoverModMessages(assembly, value2); GUIMain.Instance.DiscoverGUIMenus(assembly, voidPlugin); ActiveVoidPlugins.Add(value2.Metadata.GUID, voidPlugin); } else { VoidPlugin voidPlugin; if (modOverrideDictionary.TryGetValue(gUID, out var value) || modOverrideDictionary.TryGetValue(name, out value)) { voidPlugin = new DefaultVoidPlugin(value); BepinPlugin.Log.LogInfo((object)$"Discovered MPType override for {name}. Setting MPType to {value}"); } else { voidPlugin = new DefaultVoidPlugin(MultiplayerType.Unspecified); } voidPlugin.VersionInfo = FileVersionInfo.GetVersionInfo(value2.Location); voidPlugin.ModHash = GetFileHash(value2.Location); voidPlugin.BepinPlugin = value2; GUIMain.Instance.DiscoverNonVManMod(voidPlugin); GeneratedVoidPlugins.Add(gUID, voidPlugin); } } BepinPlugin.Log.LogInfo((object)$"Loaded {CommandHandler.chatCommandCount} local command(s) and {CommandHandler.publicCommandCount} public command(s)"); BepinPlugin.Log.LogInfo((object)$"Loaded {ModMessageHandler.modMessageHandlers.Count()} mod message(s)"); BepinPlugin.Log.LogInfo((object)$"Discovered {ActiveVoidPlugins.Count} VoidManager plugin(s) from {ActiveBepinPlugins.Count - 1} mod(s)"); } public static byte[] GetFileHash(string fileLocation) { using SHA256 sHA = SHA256.Create(); return sHA.ComputeHash(File.ReadAllBytes(fileLocation)); } } public abstract class VoidPlugin { internal FileVersionInfo VersionInfo; internal byte[] ModHash; internal PluginInfo BepinPlugin; public PluginInfo MyBepinPlugin => BepinPlugin; public virtual string Author => VersionInfo?.CompanyName; public virtual string Description => VersionInfo?.FileDescription; public virtual MultiplayerType MPType => MultiplayerType.Unspecified; } public static class MyPluginInfo { public const string PLUGIN_GUID = "VoidManager"; public const string PLUGIN_NAME = "VoidManager"; public const string PLUGIN_VERSION = "1.0.7"; } } namespace VoidManager.Utilities { public class Game { public static ClientGame Instance => ClientGame.Current; public static bool InGame { get { if (!((Object)(object)Instance == (Object)null)) { return true; } return false; } } public static List<Player> Players { get { if (!InGame) { return new List<Player>(); } return ClientGame.Current.Players; } } public static Player LocalPlayer => GetPlayerFromID(PhotonNetwork.LocalPlayer.ActorNumber); public static int GetIDFromPlayer(Player player) { if ((Object)(object)player == (Object)null || (Object)(object)((MonoBehaviourPun)player).photonView == (Object)null || ((MonoBehaviourPun)player).photonView.Owner == null) { return -1; } return ((MonoBehaviourPun)player).photonView.Owner.ActorNumber; } public static Player GetPlayerFromID(int id) { if (!InGame) { return null; } return ClientGame.Current.GetPlayerCharacterByActorNumber(id); } public static Player GetPlayerByName(string playerName) { if (!InGame) { return null; } foreach (Player player in Players) { if (string.Equals(((AbstractCloneStarObject)player).DisplayName, playerName, StringComparison.CurrentCultureIgnoreCase)) { return player; } } return null; } } public static class HarmonyHelpers { public enum CheckMode { ALWAYS, NONNULL, NEVER } public enum PatchMode { BEFORE, AFTER, REPLACE } public static IEnumerable<CodeInstruction> PatchBySequence(IEnumerable<CodeInstruction> instructions, IEnumerable<CodeInstruction> targetSequence, IEnumerable<CodeInstruction> patchSequence, PatchMode patchMode = PatchMode.AFTER, CheckMode checkMode = CheckMode.ALWAYS, bool showDebugOutput = false) { List<CodeInstruction> list = instructions.ToList(); CodeInstruction val = targetSequence.ElementAt(0); int num = targetSequence.Count(); for (int i = 0; i < list.Count; i++) { if (i + num <= list.Count) { bool flag = true; for (int j = 0; j < num && flag; j++) { flag = list[i + j].opcode.Equals(targetSequence.ElementAt(j).opcode); if (checkMode != CheckMode.NEVER) { flag = flag && (((list[i + j].operand == null || checkMode == CheckMode.NONNULL) && targetSequence.ElementAt(j).operand == null) || list[i + j].operand.Equals(targetSequence.ElementAt(j).operand)); } if (showDebugOutput && flag) { BepinPlugin.Log.LogInfo((object)$"[Helper] Found {targetSequence.ElementAt(j).opcode} at {i + j}"); } } if (!flag) { continue; } switch (patchMode) { case PatchMode.BEFORE: case PatchMode.AFTER: { int index = ((patchMode == PatchMode.AFTER) ? (i + num) : i); list.InsertRange(index, patchSequence.Select((CodeInstruction c) => c.FullClone())); break; } case PatchMode.REPLACE: list.RemoveRange(i, num); list.InsertRange(i, patchSequence.Select((CodeInstruction c) => c.FullClone())); break; default: throw new ArgumentException($"[Helper] Argument PatchMode patchMode == {patchMode}; invalid value!"); } break; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[Helper] Failed to patch by sequence: couldn't find target sequence. This might be okay in certain cases."); stringBuilder.AppendLine("[Helper] Stack Trace:"); string[] array = new StackTrace().ToString().Split(new string[3] { "\r\n", "\r", "\n" }, StringSplitOptions.None); for (int k = 0; k < 2; k++) { stringBuilder.AppendLine(array[k]); } BepinPlugin.Log.LogInfo((object)stringBuilder.ToString()); break; } return list.AsEnumerable(); } public static int FindSequence(IEnumerable<CodeInstruction> instructions, IEnumerable<CodeInstruction> targetSequence, CheckMode checkMode = CheckMode.ALWAYS, bool showDebugOutput = false) { List<CodeInstruction> list = instructions.ToList(); CodeInstruction val = targetSequence.ElementAt(0); int num = targetSequence.Count(); for (int i = 0; i < list.Count; i++) { if (i + num <= list.Count) { bool flag = true; for (int j = 0; j < num && flag; j++) { flag = list[i + j].opcode.Equals(targetSequence.ElementAt(j).opcode); if (checkMode != CheckMode.NEVER) { flag = flag && (((list[i + j].operand == null || checkMode == CheckMode.NONNULL) && targetSequence.ElementAt(j).operand == null) || list[i + j].operand.Equals(targetSequence.ElementAt(j).operand)); } if (showDebugOutput && flag) { BepinPlugin.Log.LogInfo((object)$"Found {targetSequence.ElementAt(j).opcode} at {i + j}"); } } if (flag) { return i + num; } continue; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Couldn't find target sequence. This might be okay in certain cases."); stringBuilder.AppendLine("Stack Trace:"); string[] array = new StackTrace().ToString().Split(new string[3] { "\r\n", "\r", "\n" }, StringSplitOptions.None); for (int k = 0; k < 2; k++) { stringBuilder.AppendLine(array[k]); } BepinPlugin.Log.LogInfo((object)stringBuilder.ToString()); break; } return -1; } public static void LogSequence(string label, IEnumerable sequence) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(label); foreach (object item in sequence) { stringBuilder.AppendLine("\t" + item.ToString()); } BepinPlugin.Log.LogInfo((object)stringBuilder.ToString()); } public static CodeInstruction FullClone(this CodeInstruction instruction) { CodeInstruction val = instruction.Clone(); val.labels = instruction.labels.ConvertAll((Label l) => l); val.blocks = instruction.blocks.ConvertAll((ExceptionBlock b) => b.Clone()); return val; } public static ExceptionBlock Clone(this ExceptionBlock block) { //IL_0001: 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_0012: Expected O, but got Unknown return new ExceptionBlock(block.blockType, block.catchType); } } public class Messaging { public static void Notification(string message) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) Assembly callingAssembly = Assembly.GetCallingAssembly(); TextChat.Instance.AddLog(new Log(callingAssembly.FullName.Split(new char[1] { ',' })[0] ?? "", message)); } public static void Echo(string message, bool local = true) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (local) { TextChat.Instance.AddLog(new Log("", message)); } else { VivoxVoiceManager.Instance.SendTextMessage("[Mod Manager]: " + message, (ChannelId)(object)VivoxVoiceManager.Instance.TextChannel, (string)null, (string)null); } } public static void KickMessage(string title, string body, Player player) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient) { BepinPlugin.Log.LogInfo((object)("Sending kick message to " + player.NickName + ": " + title + "::" + body)); object[] obj = new object[2] { title, body }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { player.ActorNumber }; PhotonNetwork.RaiseEvent((byte)97, (object)obj, val, SendOptions.SendUnreliable); } else { BepinPlugin.Log.LogWarning((object)"Cannot send kick message while not master client."); } } } } namespace VoidManager.MPModChecks { internal class KickMessagePatches { [HarmonyPatch(typeof(GSPhotonDisconnected), "OnSceneLoaded")] private class KickedPatch { [HarmonyPostfix] private static void patch(Scene scene) { if (((Scene)(ref scene)).buildIndex == CloneStarConstants.MainMenuSceneIndex && KickTitle != null && KickMessage != null) { BepinPlugin.Log.LogInfo((object)("Pushing Kick Message via info screen. Title:" + KickTitle + " message:\n")); MenuScreenController.Instance.ShowMessagePopup(KickTitle, KickMessage); KickTitle = null; KickMessage = null; } } } internal static string KickTitle; internal static string KickMessage; } [HarmonyPatch(typeof(MatchmakingHandler), "ConvertRoom")] internal class ModdedRoomTagPatch { [HarmonyPostfix] private static void ModdedRoomPatch(RoomInfo pRoom, MatchmakingRoom __result) { if (((Dictionary<object, object>)(object)pRoom.CustomProperties).ContainsKey((object)"Mods")) { __result.RoomName = "<color=yellow>[M]</color> " + __result.RoomName; } } } [HarmonyPatch(typeof(MatchmakingList), "BindItem")] internal class ModdedRoomTagPatch2 { [HarmonyPostfix] private static void RoomNameRichTextPatch(VisualElement item, MatchmakingRoom room) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) ((TextElement)UQueryExtensions.Q(item, "RoomName", (string)null)).enableRichText = true; } } public class MPModCheckManager { internal static InRoomCallbacks RoomCallbacksClass; private MPModDataBlock[] MyModList; private MPModDataBlock[] MyMPUnspecifiedModList; private MPModDataBlock[] MyMPModList; private byte[] RoomProperties; internal Dictionary<Player, MPUserDataBlock> NetworkedPeersModLists = new Dictionary<Player, MPUserDataBlock>(); public string LastModCheckFailReason; public MultiplayerType HighestLevelOfMPMods { get; private set; } public static MPModCheckManager Instance { get; internal set; } internal MPModCheckManager() { UpdateMyModList(); BuildRoomProperties(); } public byte[] GetRoomProperties() { return RoomProperties; } public void BuildRoomProperties() { RoomProperties = SerializeHashlessMPUserData(); } public void UpdateLobbyProperties() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0052: Expected O, but got Unknown if (PhotonNetwork.IsMasterClient) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { BepinPlugin.Log.LogWarning((object)"Attempted to update lobby properties while room was null"); } else if (((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).ContainsKey((object)"Mods")) { Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"Mods", (object)RoomProperties); currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); } } } private void UpdateHighestLevelOfMPMods(MultiplayerType MT) { if (HighestLevelOfMPMods == MultiplayerType.Hidden && MT != 0) { HighestLevelOfMPMods = MT; BepinPlugin.Log.LogInfo((object)("Incrementing HighestLevelOfMPMods to " + MT)); } else if (HighestLevelOfMPMods == MultiplayerType.Client && (int)MT > 3) { HighestLevelOfMPMods = MT; BepinPlugin.Log.LogInfo((object)("Incrementing HighestLevelOfMPMods to " + MT)); } else if (HighestLevelOfMPMods == MultiplayerType.Unspecified && (int)MT > 6) { HighestLevelOfMPMods = MultiplayerType.All; BepinPlugin.Log.LogInfo((object)"Incrementing HighestLevelOfMPMods to MPType.All"); } } private void UpdateMyModList() { BepinPlugin.Log.LogInfo((object)"Building MyModList"); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); KeyValuePair<string, PluginInfo>[] array = Chainloader.PluginInfos.ToArray(); MPModDataBlock[] array2 = new MPModDataBlock[array.Length]; for (int i = 0; i < array.Length; i++) { PluginInfo value = array[i].Value; string gUID = value.Metadata.GUID; if (!(gUID == "VoidManager") && (PluginHandler.ActiveVoidPlugins.TryGetValue(gUID, out var value2) || PluginHandler.GeneratedVoidPlugins.TryGetValue(gUID, out value2)) && value2.MPType != 0) { array2[i] = new MPModDataBlock(gUID, value.Metadata.Name, value.Metadata.Version.ToString(), value2.MPType, string.Empty, value2.ModHash); UpdateHighestLevelOfMPMods(value2.MPType); } } array2 = (MyModList = array2.Where((MPModDataBlock mod) => mod != null).ToArray()); MyMPModList = array2.Where((MPModDataBlock Mod) => Mod.MPType == MultiplayerType.All).ToArray(); MyMPUnspecifiedModList = array2.Where((MPModDataBlock Mod) => Mod.MPType == MultiplayerType.Unspecified).ToArray(); stopwatch.Stop(); BepinPlugin.Log.LogInfo((object)("Finished Building MyModList, time elapsted: " + stopwatch.ElapsedMilliseconds + " ms")); BepinPlugin.Log.LogInfo((object)("MyModList:\n" + GetModListAsString(MyModList) + "\n")); } public byte[] SerializeHashlessMPUserData() { MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write("1.0.7"); binaryWriter.Write(MyModList.Length); for (int i = 0; i < MyModList.Length; i++) { MPModDataBlock mPModDataBlock = MyModList[i]; binaryWriter.Write(mPModDataBlock.ModName); binaryWriter.Write(mPModDataBlock.ModGUID); binaryWriter.Write(mPModDataBlock.Version); binaryWriter.Write((byte)mPModDataBlock.MPType); binaryWriter.Write(mPModDataBlock.DownloadID); } } return memoryStream.ToArray(); } public static MPUserDataBlock DeserializeHashlessMPUserData(byte[] byteData) { MemoryStream memoryStream = new MemoryStream(byteData); memoryStream.Position = 0L; try { using BinaryReader binaryReader = new BinaryReader(memoryStream); string voidManagerVersion = binaryReader.ReadString(); int num = binaryReader.ReadInt32(); MPModDataBlock[] array = new MPModDataBlock[num]; for (int i = 0; i < num; i++) { string modName = binaryReader.ReadString(); string gUID = binaryReader.ReadString(); string version = binaryReader.ReadString(); MultiplayerType mPType = (MultiplayerType)binaryReader.ReadByte(); string downloadID = binaryReader.ReadString(); array[i] = new MPModDataBlock(gUID, modName, version, mPType, downloadID); } memoryStream.Dispose(); return new MPUserDataBlock(voidManagerVersion, array); } catch (Exception ex) { BepinPlugin.Log.LogInfo((object)("Failed to read mod list from Hashless MPUserData, returning null.\n" + ex.Message)); memoryStream.Dispose(); return null; } } public byte[] SerializeHashfullMPUserData() { MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write("1.0.7"); binaryWriter.Write(MyModList.Length); for (int i = 0; i < MyModList.Length; i++) { MPModDataBlock mPModDataBlock = MyModList[i]; binaryWriter.Write(mPModDataBlock.ModName); binaryWriter.Write(mPModDataBlock.ModGUID); binaryWriter.Write(mPModDataBlock.Version); binaryWriter.Write((byte)mPModDataBlock.MPType); binaryWriter.Write(mPModDataBlock.DownloadID); binaryWriter.Write(mPModDataBlock.Hash); } } return memoryStream.ToArray(); } public static MPUserDataBlock DeserializeHashfullMPUserData(byte[] byteData) { MemoryStream memoryStream = new MemoryStream(byteData); memoryStream.Position = 0L; try { using BinaryReader binaryReader = new BinaryReader(memoryStream); string voidManagerVersion = binaryReader.ReadString(); int num = binaryReader.ReadInt32(); MPModDataBlock[] array = new MPModDataBlock[num]; for (int i = 0; i < num; i++) { string modName = binaryReader.ReadString(); string gUID = binaryReader.ReadString(); string version = binaryReader.ReadString(); MultiplayerType mPType = (MultiplayerType)binaryReader.ReadByte(); string downloadID = binaryReader.ReadString(); byte[] hash = binaryReader.ReadBytes(32); array[i] = new MPModDataBlock(gUID, modName, version, mPType, downloadID, hash); } memoryStream.Dispose(); return new MPUserDataBlock(voidManagerVersion, array); } catch (Exception ex) { BepinPlugin.Log.LogInfo((object)("Failed to read mod list from Hashfull MPUserData, returning null.\n" + ex.Message)); memoryStream.Dispose(); return null; } } public static string GetModListAsString(MPModDataBlock[] ModDatas) { string text = string.Empty; foreach (MPModDataBlock mPModDataBlock in ModDatas) { text = text + "\n - " + mPModDataBlock.ModName + " " + mPModDataBlock.Version; } return text; } internal MPUserDataBlock GetHostModList() { if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).ContainsKey((object)"Mods")) { try { return DeserializeHashlessMPUserData((byte[])((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties[(object)"Mods"]); } catch { BepinPlugin.Log.LogError((object)"Failed to Deserialize host mod list."); } } return null; } public MPUserDataBlock GetNetworkedPeerMods(Player Player) { if (NetworkedPeersModLists.TryGetValue(Player, out var value)) { return value; } return null; } public bool NetworkedPeerHasMod(Player Player, string ModGUID) { MPUserDataBlock networkedPeerMods = GetNetworkedPeerMods(Player); if (networkedPeerMods != null) { MPModDataBlock[] modData = networkedPeerMods.ModData; foreach (MPModDataBlock mPModDataBlock in modData) { if (mPModDataBlock.ModGUID == ModGUID) { return true; } } } return false; } public List<Player> NetworkedPeersWithMod(string ModGUID) { List<Player> list = new List<Player>(); foreach (KeyValuePair<Player, MPUserDataBlock> networkedPeersModList in NetworkedPeersModLists) { MPModDataBlock[] modData = networkedPeersModList.Value.ModData; foreach (MPModDataBlock mPModDataBlock in modData) { if (mPModDataBlock.ModGUID == ModGUID) { list.Add(networkedPeersModList.Key); } } } return list; } public void AddNetworkedPeerMods(Player Player, MPUserDataBlock modList) { BepinPlugin.Log.LogMessage((object)("recieved modlist from user '" + Player.NickName + "' with the following info:\nVoidManager Version: " + modList.VMVersion + "\nModList:\n" + GetModListAsString(modList.ModData) + "\n")); if (NetworkedPeersModLists.ContainsKey(Player)) { NetworkedPeersModLists[Player] = modList; return; } NetworkedPeersModLists.Add(Player, modList); Events.Instance.OnClientModlistRecieved(Player); } public void RemoveNetworkedPeerMods(Player Player) { NetworkedPeersModLists.Remove(Player); } internal void ClearAllNetworkedPeerMods() { NetworkedPeersModLists.Clear(); } public bool GetNetworkedPeerModlistExists(Player Player) { return NetworkedPeersModLists.ContainsKey(Player); } private static MPUserDataBlock GetHostModList(RoomInfo room) { if (((Dictionary<object, object>)(object)room.CustomProperties).ContainsKey((object)"modList")) { try { return DeserializeHashlessMPUserData((byte[])room.CustomProperties[(object)"modList"]); } catch { BepinPlugin.Log.LogError((object)"Failed to Deserialize host mod list. Could be an older version of VoidManager"); } } return new MPUserDataBlock(); } internal void SendModlistToClient(Player Player) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!Player.IsLocal) { object[] obj = new object[2] { false, SerializeHashlessMPUserData() }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { Player.ActorNumber }; PhotonNetwork.RaiseEvent((byte)99, (object)obj, val, SendOptions.SendReliable); } } internal void SendModlistToHost() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if (!PhotonNetwork.IsMasterClient) { PhotonNetwork.RaiseEvent((byte)99, (object)new object[2] { true, SerializeHashfullMPUserData() }, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); } } internal void SendModListToOthers() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) BepinPlugin.Log.LogMessage((object)"sending others"); PhotonNetwork.RaiseEvent((byte)99, (object)new object[2] { false, SerializeHashlessMPUserData() }, (RaiseEventOptions)null, SendOptions.SendReliable); } internal void PlayerJoined(Player JoiningPlayer) { if (PhotonNetwork.IsMasterClient) { ((MonoBehaviour)PunSingleton<PhotonService>.Instance).StartCoroutine(PlayerJoinedChecks(JoiningPlayer)); } else { Instance.SendModlistToClient(JoiningPlayer); } } public static IEnumerator PlayerJoinedChecks(Player JoiningPlayer) { for (int i = 0; i < 50; i++) { yield return (object)new WaitForSeconds(0.2f); if (Instance.GetNetworkedPeerModlistExists(JoiningPlayer)) { Instance.ModChecksHostOnClientJoin(JoiningPlayer); yield break; } } if (Instance.HighestLevelOfMPMods == MultiplayerType.All) { BepinPlugin.Log.LogMessage((object)("Kicked player " + JoiningPlayer.NickName + " for not having mods.")); Messaging.Echo("Kicked player " + JoiningPlayer.NickName + " for not having mods.", local: false); PhotonNetwork.CloseConnection(JoiningPlayer); } Events.Instance.CallHostOnClientVerified(JoiningPlayer); } internal bool ModChecksClientside(Hashtable RoomProperties, bool inRoom = true) { LastModCheckFailReason = string.Empty; BepinPlugin.Log.LogMessage((object)string.Format("Starting Clientside mod checks for room: {0}", RoomProperties[(object)"R_Na"])); if (!((Dictionary<object, object>)(object)RoomProperties).ContainsKey((object)"Mods")) { if (HighestLevelOfMPMods == MultiplayerType.All) { LastModCheckFailReason = "Host has no mods, but client has MPType.All mods." + GetModListAsString(MyMPModList); KickMessagePatches.KickTitle = "Disconnected: Incompatable mod list"; KickMessagePatches.KickMessage = LastModCheckFailReason; BepinPlugin.Log.LogMessage((object)("Mod check failed.\n" + LastModCheckFailReason)); return false; } if ((int)HighestLevelOfMPMods >= 6) { LastModCheckFailReason = "Host has no mods, but client has MPType.Unspecified mods." + GetModListAsString(MyMPUnspecifiedModList); KickMessagePatches.KickTitle = "Disconnected: Incompatable mod list"; KickMessagePatches.KickMessage = LastModCheckFailReason; BepinPlugin.Log.LogMessage((object)("Mod check failed.\n" + LastModCheckFailReason)); return false; } BepinPlugin.Log.LogMessage((object)"Clientside mod check passed."); return true; } MPUserDataBlock mPUserDataBlock = DeserializeHashlessMPUserData((byte[])RoomProperties[(object)"Mods"]); MPModDataBlock[] array = mPUserDataBlock.ModData.Where((MPModDataBlock Mod) => Mod.MPType == MultiplayerType.All).ToArray(); BepinPlugin.Log.LogMessage((object)("Void Manager versions - Host: " + mPUserDataBlock.VMVersion + " Client: 1.0.7")); List<string> list = new List<string>(); List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); for (int i = 0; i < MyMPModList.Length; i++) { MPModDataBlock mPModDataBlock = MyMPModList[i]; bool flag = false; for (int j = 0; j < array.Length; j++) { if (mPModDataBlock.ModGUID == array[j].ModGUID) { MPModDataBlock mPModDataBlock2 = array[j]; flag = true; if (mPModDataBlock.Version != mPModDataBlock2.Version) { list.Add("Client:" + mPModDataBlock.ModName + "-" + mPModDataBlock.Version + ", Host:" + mPModDataBlock2.Version); BepinPlugin.Log.LogMessage((object)("Mismatched mod version - " + list.Last() + ". " + ((mPModDataBlock2.DownloadID != string.Empty) ? ("Download Link: " + mPModDataBlock2.DownloadID) : ""))); } break; } } if (!flag) { list3.Add(mPModDataBlock.ModName); BepinPlugin.Log.LogMessage((object)("Host is missing the required mod '" + mPModDataBlock.ModName + "'")); } } foreach (MPModDataBlock mPModDataBlock2 in array) { bool flag2 = false; for (int j = 0; j < MyMPModList.Length; j++) { if (mPModDataBlock2.ModGUID == MyMPModList[j].ModGUID) { flag2 = true; break; } } if (!flag2) { list2.Add(mPModDataBlock2.ModName); BepinPlugin.Log.LogMessage((object)("Client is missing the required mod '" + mPModDataBlock2.ModName + "'")); } } string text = string.Empty; if (list.Count > 0) { text += "The following mods have mismatched versions:\n"; foreach (string item in list) { text = text + item + "\n"; } } if (list2.Count > 0) { text += "The following mods are required to join the session:\n"; foreach (string item2 in list2) { text = text + item2 + "\n"; } } if (list3.Count > 0) { text += "The following mods must be uninstalled to join the session:"; foreach (string item3 in list3) { text = text + "\n" + item3; } } if (text != string.Empty) { if (inRoom) { KickMessagePatches.KickTitle = "Disconnected: Incompatable mod list"; KickMessagePatches.KickMessage = text; } else { LastModCheckFailReason = text; } BepinPlugin.Log.LogMessage((object)("Couldn't join session.\n" + text)); return false; } BepinPlugin.Log.LogMessage((object)"Clientside mod check passed."); return true; } internal void ModChecksHostOnClientJoin(Player joiningPlayer) { MPUserDataBlock networkedPeerMods = GetNetworkedPeerMods(joiningPlayer); MPModDataBlock[] array = networkedPeerMods.ModData.Where((MPModDataBlock Mod) => Mod.MPType == MultiplayerType.All).ToArray(); if (!BepinPlugin.Bindings.TrustMPTypeUnspecified.Value) { MPModDataBlock[] second = networkedPeerMods.ModData.Where((MPModDataBlock Mod) => Mod.MPType == MultiplayerType.Unspecified).ToArray(); array = array.Concat(second).ToArray(); MPModDataBlock[] array2 = MyModList.Concat(MyMPUnspecifiedModList).ToArray(); } else { MPModDataBlock[] array2 = MyModList; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); for (int i = 0; i < MyMPModList.Length; i++) { MPModDataBlock mPModDataBlock = MyMPModList[i]; bool flag = false; for (int j = 0; j < array.Length; j++) { if (mPModDataBlock.ModGUID == array[j].ModGUID) { MPModDataBlock mPModDataBlock2 = array[j]; flag = true; if (mPModDataBlock.Version != mPModDataBlock2.Version) { list.Add("Client:" + mPModDataBlock.ModName + "-" + mPModDataBlock.Version + ", Host:" + mPModDataBlock2.Version); BepinPlugin.Log.LogMessage((object)("Mismatched mod version - " + list.Last() + ". " + ((mPModDataBlock.DownloadID != string.Empty) ? ("Download Link: " + mPModDataBlock.DownloadID) : ""))); } else if (Encoding.ASCII.GetString(mPModDataBlock.Hash) != Encoding.ASCII.GetString(mPModDataBlock2.Hash)) { list.Add("Client:" + mPModDataBlock.ModName + "-" + mPModDataBlock.Version + ", Host: " + mPModDataBlock2.Version); BepinPlugin.Log.LogMessage((object)("Mismatched mod hash - " + list.Last() + " - LocalHash: " + Encoding.ASCII.GetString(mPModDataBlock.Hash) + " IncomingHash: " + Encoding.ASCII.GetString(mPModDataBlock2.Hash) + ". " + ((mPModDataBlock.DownloadID != string.Empty) ? ("Download Link: " + mPModDataBlock.DownloadID) : ""))); } break; } } if (!flag) { list2.Add(mPModDataBlock.ModName); BepinPlugin.Log.LogMessage((object)("Client is missing the required mod '" + mPModDataBlock.ModName + "'")); } } foreach (MPModDataBlock mPModDataBlock2 in array) { bool flag2 = false; for (int j = 0; j < MyMPModList.Length; j++) { if (mPModDataBlock2.ModGUID == MyMPModList[j].ModGUID) { flag2 = true; break; } } if (!flag2) { list3.Add(mPModDataBlock2.ModName); BepinPlugin.Log.LogMessage((object)("Client must uninstall the " + mPModDataBlock2.MPType.ToString() + " Mod '" + mPModDataBlock2.ModName + "'")); } } string text = string.Empty; if (list.Count > 0) { text += "The following mods have mismatched versions:\n"; foreach (string item in list) { text = text + item + "\n"; } } if (list2.Count > 0) { text += "The following mods are required to join the session:\n"; foreach (string item2 in list2) { text = text + item2 + "\n"; } } if (list3.Count > 0) { text += "The following mods must be uninstalled to join the session:"; foreach (string item3 in list3) { text = text + "\n" + item3; } } if (text != string.Empty) { Messaging.Echo("Kicking player " + joiningPlayer.NickName + " from session for incompatable mods.", local: false); Messaging.KickMessage("Kicked: Incompatable mod list", text, joiningPlayer); PhotonNetwork.CloseConnection(joiningPlayer); BepinPlugin.Log.LogMessage((object)("Kicked player " + joiningPlayer.NickName + " from session for incompatable mods.\n" + text)); } else { BepinPlugin.Log.LogMessage((object)("Hostside mod check passed for player " + joiningPlayer.NickName)); Events.Instance.CallHostOnClientVerified(joiningPlayer); } } } public class MPModDataBlock { public string ModGUID { get; } public string ModName { get; } public string Version { get; } public MultiplayerType MPType { get; } public byte[] Hash { get; } public string DownloadID { get; } public MPModDataBlock(string GUID, string ModName, string Version, MultiplayerType MPType, string DownloadID, byte[] Hash) { ModGUID = GUID; this.ModName = ModName; this.Version = Version; this.MPType = MPType; this.Hash = Hash; this.DownloadID = DownloadID; } public MPModDataBlock(string GUID, string ModName, string Version, MultiplayerType MPType, string DownloadID) { ModGUID = GUID; this.ModName = ModName; this.Version = Version; this.MPType = MPType; Hash = new byte[32]; this.DownloadID = DownloadID; } } public class MPUserDataBlock { public string VMVersion { get; } public MPModDataBlock[] ModData { get; } public MPUserDataBlock(string VoidManagerVersion, MPModDataBlock[] ModData) { VMVersion = VoidManagerVersion; this.ModData = ModData; } public MPUserDataBlock() { VMVersion = string.Empty; ModData = null; } } public enum MultiplayerType : byte { Hidden = 0, Client = 3, Unspecified = 6, All = 10 } [HarmonyPatch(typeof(MatchmakingTerminal), "JoinRequested")] internal class OnJoinCheckModsPatch { private static bool Prefix(FailPopup ___failPopup, MatchmakingList ___matchList) { LobbyCallbacks instance = LobbyCallbacks.Instance; if (instance == null || (Object)(object)instance.ActiveTerminal == (Object)null || instance.RoomList == null) { if ((Object)(object)instance.ActiveTerminal == (Object)null) { BepinPlugin.Log.LogInfo((object)"Terminal"); } if (instance.RoomList == null) { BepinPlugin.Log.LogInfo((object)"Roomlist"); } BepinPlugin.Log.LogInfo((object)"Attempted to join room, VoidManager LobbyCallbacks instance, Active Terminal, or RoomList not found"); ___failPopup.Show("VoidManager could not find the room. Please wait a moment then try again. Could also be bugged."); return false; } foreach (RoomInfo room in instance.RoomList) { if (room.Name == ___matchList.GetSelectedRoom().RoomId) { if (!MPModCheckManager.Instance.ModChecksClientside(room.CustomProperties, inRoom: false)) { ___failPopup.Show("VoidManager blocked connection, Modlists incompatable.\n" + MPModCheckManager.Instance.LastModCheckFailReason); return false; } return true; } } BepinPlugin.Log.LogInfo((object)"Attempted to join room, VoidManager could not find the room."); ___failPopup.Show("VoidManager could not find the room. Please wait a moment then try again. Could also be bugged."); return false; } } [HarmonyPatch(typeof(PhotonService), "PhotonCreateRoom")] internal class RoomInfoPatch { private static RoomOptions PatchMethod(RoomOptions RoomOptions) { ((Dictionary<object, object>)(object)RoomOptions.CustomRoomProperties).Add((object)"Mods", (object)MPModCheckManager.Instance.GetRoomProperties()); int num = RoomOptions.CustomRoomPropertiesForLobby.Length; string[] array = new string[num + 1]; int i; for (i = 0; i < num; i++) { array[i] = RoomOptions.CustomRoomPropertiesForLobby[i]; } array[i] = "Mods"; RoomOptions.CustomRoomPropertiesForLobby = array; return RoomOptions; } [HarmonyTranspiler] private static IEnumerable<CodeInstruction> RoomPropertiesPatch(IEnumerable<CodeInstruction> instructions) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); int count = list.Count; for (int num = count - 1; num >= 0; num--) { if (list[num].opcode == OpCodes.Call) { if ((MethodInfo)list[num].operand == AccessTools.Method(typeof(PhotonNetwork), "CreateRoom", (Type[])null, (Type[])null)) { list.Insert(num - 3, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(RoomInfoPatch), "PatchMethod", (Type[])null, (Type[])null))); } else { BepinPlugin.Log.LogError((object)("Failed to patch PhotonService.PhotonCreateRoom. Targeted method appears to have changed. Index: " + num)); } break; } } return list.AsEnumerable(); } } } namespace VoidManager.ModMessages { public abstract class ModMessage { public string GetIdentifier() { return GetType().Namespace + "." + GetType().Name; } public static string GetIdentifier(Type ModMessageType) { return ModMessageType.Namespace + "." + ModMessageType.Name; } public static void Send(string pluginGUID, string handlerIdentifier, Player player, object[] arguments, bool reliable = false) { Send(pluginGUID, handlerIdentifier, (Player[])(object)new Player[1] { player }, arguments, reliable); } public static void Send(string pluginGUID, string handlerIdentifier, Player[] players, object[] arguments, bool reliable = false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) object[] first = new object[2] { pluginGUID, handlerIdentifier }; first = first.Concat(arguments).ToArray(); RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = players.Select((Player player) => player.ActorNumber).ToArray(); PhotonNetwork.RaiseEvent((byte)98, (object)first, val, reliable ? SendOptions.SendReliable : SendOptions.SendUnreliable); } public static void Send(string pluginGUID, string handlerIdentifier, ReceiverGroup recieverGroup, object[] arguments, bool reliable = false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0023: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) object[] first = new object[2] { pluginGUID, handlerIdentifier }; first = first.Concat(arguments).ToArray(); RaiseEventOptions val = new RaiseEventOptions(); val.Receivers = recieverGroup; PhotonNetwork.RaiseEvent((byte)98, (object)first, val, reliable ? SendOptions.SendReliable : SendOptions.SendUnreliable); } public abstract void Handle(object[] arguments, Player sender); } public class ModMessageHandler { public static Dictionary<string, ModMessage> modMessageHandlers = new Dictionary<string, ModMessage>(); public static void DiscoverModMessages(Assembly assembly, PluginInfo bepinPlugin) { Type[] types = assembly.GetTypes(); IEnumerable<Type> enumerable = types.Where((Type t) => typeof(ModMessage).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); int num = 0; foreach (Type item in enumerable) { ModMessage modMessage = (ModMessage)Activator.CreateInstance(item); modMessageHandlers.Add(bepinPlugin.Metadata.GUID + "#" + modMessage.GetIdentifier(), modMessage); num++; } if (num != 0) { BepinPlugin.Log.LogInfo((object)$"[{bepinPlugin.Metadata.Name}] Detected {num} mod messages"); } } } } namespace VoidManager.CustomGUI { internal class GUIMain : MonoBehaviour, IShowCursorSource, IInputActionMapRequest { private GameObject Background; private GameObject MMCanvas; private Image Image; public bool GUIActive; private Rect Window; private byte Tab; private List<VoidPlugin> mods = new List<VoidPlugin>(); private VoidPlugin selectedMod; private List<VoidPlugin> NonVManMods = new List<VoidPlugin>(); private Rect ModListArea; private Vector2 ModListScroll = Vector2.zero; private Rect ModInfoArea; private Vector2 ModInfoScroll = Vector2.zero; private Rect PlayerListArea; private Vector2 PlayerListScroll = Vector2.zero; private Player selectedPlayer; private Rect PlayerModInfoArea; private Vector2 PlayerModInfoScroll = Vector2.zero; private Rect ModSettingsArea; private Vector2 ModSettingsScroll = Vector2.zero; private List<ModSettingsMenu> settings = new List<ModSettingsMenu>(); private ushort selectedSettings = ushort.MaxValue; internal static GUISkin _cachedSkin; private static readonly Color32 _classicMenuBackground = new Color32((byte)32, (byte)32, (byte)32, byte.MaxValue); private static readonly Color32 _classicButtonBackground = new Color32((byte)40, (byte)40, (byte)40, byte.MaxValue); private static readonly Color32 _hoverButtonFromMenu = new Color32((byte)18, (byte)79, (byte)179, byte.MaxValue); private bool ShowingCursor; public static GUIMain Instance { get; internal set; } internal void updateWindowSize() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) float value = BepinPlugin.Bindings.MenuHeight.Value; float value2 = BepinPlugin.Bindings.MenuWidth.Value; float value3 = BepinPlugin.Bindings.MenuListWidth.Value; float value4 = BepinPlugin.Bindings.PlayerListWidth.Value; Window = new Rect((float)Screen.width * 0.5f - (float)Screen.width * value2 / 2f, (float)Screen.height * 0.5f - (float)Screen.height * value / 2f, (float)Screen.width * value2, (float)Screen.height * value); ModListArea = new Rect(6f, 43f, ((Rect)(ref Window)).width * value3, (float)Screen.height * value - 45f); ModInfoArea = new Rect(((Rect)(ref ModListArea)).width + 15f, 43f, (float)Screen.width * value2 - (((Rect)(ref ModListArea)).width + 11f) - 10f, (float)Screen.height * value - 45f); PlayerListArea = new Rect(6f, 43f, ((Rect)(ref Window)).width * value4, (float)Screen.height * value - 45f); PlayerModInfoArea = new Rect(((Rect)(ref PlayerListArea)).width + 15f, 43f, (float)Screen.width * value2 - (((Rect)(ref PlayerListArea)).width + 11f) - 10f, (float)Screen.height * value - 45f); ModSettingsArea = new Rect(6f, 43f, (float)Screen.width * value2 - 12f, (float)Screen.height * value - 45f); } internal GUIMain() { //IL_0017: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) Instance = this; MMCanvas = new GameObject("ModManagerCanvas", new Type[1] { typeof(Canvas) }); Canvas component = MMCanvas.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 1000; ((Component)component).transform.SetAsLastSibling(); Object.DontDestroyOnLoad((Object)(object)MMCanvas); updateWindowSize(); settings.Add(new VManSettings()); Background = new GameObject("GUIMainBG", new Type[1] { typeof(GraphicRaycaster) }); Image = Background.AddComponent<Image>(); ((Graphic)Image).color = Color.clear; Background.transform.SetParent(MMCanvas.transform); Background.SetActive(false); } private void Awake() { Application.SetStackTraceLogType((LogType)3, (StackTraceLogType)0); Application.SetStackTraceLogType((LogType)2, (StackTraceLogType)0); } private void Update() { if (((KeyboardShortcut)(ref BepinPlugin.Bindings.OpenMenu)).IsDown()) { GUIActive = !GUIActive; if (GUIActive) { GUIOpen(); } else { GUIClose(); } } } private void GUIOpen() { if (selectedSettings != ushort.MaxValue) { settings[selectedSettings].OnOpen(); } GUIToggleCursor(enable: true); Background.SetActive(true); } private void GUIClose() { if (selectedSettings != ushort.MaxValue) { settings[selectedSettings].OnClose(); } GUIToggleCursor(enable: false); Background.SetActive(false); } private void OnGUI() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) if (GUIActive) { GUI.skin = ChangeSkin(); Window = GUI.Window(999910, Window, new WindowFunction(WindowFunction), "ModManager"); ((Transform)((Graphic)Image).rectTransform).position = new Vector3(((Rect)(ref Window)).center.x, ((Rect)(ref Window)).center.y * -1f + (float)Screen.height, 0f); ((Graphic)Image).rectTransform.sizeDelta = ((Rect)(ref Window)).size; } } private void WindowFunction(int WindowID) { //IL_0076: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_04a4: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_04ba: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Mod Info", Array.Empty<GUILayoutOption>())) { Tab = 0; } if (GUILayout.Button("Mod Settings", Array.Empty<GUILayoutOption>())) { Tab = 1; } if (GUILayout.Button("Player List", Array.Empty<GUILayoutOption>())) { Tab = 2; } GUILayout.EndHorizontal(); switch (Tab) { case 0: GUILayout.BeginArea(ModListArea); ModListScroll = GUILayout.BeginScrollView(ModListScroll, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("VoidManager", Array.Empty<GUILayoutOption>())) { selectedMod = null; } foreach (VoidPlugin mod in mods) { DrawModButton(mod); } GUI.skin.label.alignment = (TextAnchor)4; GUILayout.Label("<color=yellow>Non-VoidManager Mods</color>", Array.Empty<GUILayoutOption>()); foreach (VoidPlugin nonVManMod in NonVManMods) { DrawModButton(nonVManMod); } GUILayout.Label("Overall MPType: " + GetColoredMPTypeText(MPModCheckManager.Instance.HighestLevelOfMPMods), Array.Empty<GUILayoutOption>()); GUILayout.EndScrollView(); GUILayout.EndArea(); GUI.skin.label.alignment = BepinPlugin.Bindings.ModInfoTextAnchor.Value; GUILayout.BeginArea(ModInfoArea); ModInfoScroll = GUILayout.BeginScrollView(ModInfoScroll, Array.Empty<GUILayoutOption>()); if (selectedMod != null) { BepInPlugin metadata = selectedMod.BepinPlugin.Metadata; GUILayout.Label("Author: " + selectedMod.Author, Array.Empty<GUILayoutOption>()); GUILayout.Label("Name: " + metadata.Name, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Version: {metadata.Version}", Array.Empty<GUILayoutOption>()); if (selectedMod.Description != string.Empty) { GUILayout.Label("Description: " + selectedMod.Description, Array.Empty<GUILayoutOption>()); } GUILayout.Label("MPRequirement: " + GetTextForMPType(selectedMod.MPType), Array.Empty<GUILayoutOption>()); } else { GUI.skin.label.alignment = (TextAnchor)4; GUILayout.Label("VoidManager - BepInEx Plugin Manager for Void Crew.", Array.Empty<GUILayoutOption>()); GUILayout.Label("Provides APIs to developers and multiplayer mod management.", Array.Empty<GUILayoutOption>()); GUILayout.Label("Version: 1.0.7", Array.Empty<GUILayoutOption>()); GUILayout.Label("\n\nDeveloped by Mest and Dragon", Array.Empty<GUILayoutOption>()); GUILayout.Label("Based on the 'Pulsar Mod Loader' developed by Tom Ritcher", Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); if (GUILayout.Button("Github", Array.Empty<GUILayoutOption>())) { Application.OpenURL("https://github.com/Void-Crew-Modding-Team/VoidManager"); } if (GUILayout.Button("Discord", Array.Empty<GUILayoutOption>())) { Application.OpenURL("https://discord.gg/4QhRRBWsJz"); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); GUILayout.EndArea(); break; case 1: GUI.skin.label.alignment = BepinPlugin.Bindings.ModInfoTextAnchor.Value; GUILayout.BeginArea(ModSettingsArea); ModSettingsScroll = GUILayout.BeginScrollView(ModSettingsScroll, Array.Empty<GUILayoutOption>()); if (selectedSettings == ushort.MaxValue) { for (ushort num = 0; num < settings.Count; num++) { if (GUILayout.Button(settings[num].Name(), Array.Empty<GUILayoutOption>())) { settings[num].OnOpen(); selectedSettings = num; break; } } } else if (GUILayout.Button("Back", Array.Empty<GUILayoutOption>())) { settings[selectedSettings].OnClose(); selectedSettings = ushort.MaxValue; } else { settings[selectedSettings].Draw(); } GUILayout.EndScrollView(); GUILayout.EndArea(); break; case 2: { GUI.skin.label.alignment = (TextAnchor)3; GUILayout.BeginArea(PlayerListArea); PlayerListScroll = GUILayout.BeginScrollView(PlayerListScroll, Array.Empty<GUILayoutOption>()); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (!val.IsLocal && GUILayout.Button(val.NickName, Array.Empty<GUILayoutOption>())) { selectedPlayer = val; } } GUILayout.EndScrollView(); GUILayout.EndArea(); GUILayout.BeginArea(PlayerModInfoArea); PlayerModInfoScroll = GUILayout.BeginScrollView(PlayerModInfoScroll, Array.Empty<GUILayoutOption>()); if (selectedPlayer != null) { GUILayout.Label("Player: " + selectedPlayer.NickName + " " + (selectedPlayer.IsMasterClient ? "(Host)" : string.Empty), Array.Empty<GUILayoutOption>()); DrawPlayerModList(selectedPlayer); } GUILayout.EndScrollView(); GUILayout.EndArea(); break; } } GUI.DragWindow(); } private GUISkin ChangeSkin() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_04ed: Unknown result type (might be due to invalid IL or missing references) //IL_0506: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_0521: Unknown result type (might be due to invalid IL or missing references) if (_cachedSkin == null || _cachedSkin.window.active.background == null) { _cachedSkin = GUI.skin; Texture2D val = BuildTexFrom1Color(Color32.op_Implicit(_classicMenuBackground)); _cachedSkin.window.active.background = val; _cachedSkin.window.onActive.background = val; _cachedSkin.window.focused.background = val; _cachedSkin.window.onFocused.background = val; _cachedSkin.window.hover.background = val; _cachedSkin.window.onHover.background = val; _cachedSkin.window.normal.background = val; _cachedSkin.window.onNormal.background = val; _cachedSkin.window.hover.textColor = Color.white; _cachedSkin.window.onHover.textColor = Color.white; Color32 val2 = default(Color32); ((Color32)(ref val2))..ctor(byte.MaxValue, byte.MaxValue, (byte)0, byte.MaxValue); Texture2D val3 = BuildTexFrom1Color(Color32.op_Implicit(_classicButtonBackground)); Texture2D val4 = BuildTexFrom1Color(Color32.op_Implicit(val2)); _cachedSkin.button.active.background = val3; _cachedSkin.button.onActive.background = val3; _cachedSkin.button.focused.background = val3; _cachedSkin.button.onFocused.background = val3; _cachedSkin.button.hover.background = val4; _cachedSkin.button.onHover.background = val4; _cachedSkin.button.normal.background = val3; _cachedSkin.button.onNormal.background = val3; Texture2D background = BuildTexFrom1Color(Color32.op_Implicit(new Color32((byte)47, (byte)79, (byte)79, byte.MaxValue))); _cachedSkin.horizontalSlider.active.background = background; _cachedSkin.horizontalSlider.onActive.background = background; _cachedSkin.horizontalSlider.focused.background = background; _cachedSkin.horizontalSlider.onFocused.background = background; _cachedSkin.horizontalSlider.hover.background = background; _cachedSkin.horizontalSlider.onHover.background = background; _cachedSkin.horizontalSlider.normal.background = background; _cachedSkin.horizontalSlider.onNormal.background = background; Texture2D background2 = BuildTexFrom1Color(Color32.op_Implicit(new Color32((byte)47, (byte)79, (byte)79, byte.MaxValue))); _cachedSkin.horizontalSliderThumb.active.background = background2; _cachedSkin.horizontalSliderThumb.onActive.background = background2; _cachedSkin.horizontalSliderThumb.focused.background = background2; _cachedSkin.horizontalSliderThumb.onFocused.background = background2; _cachedSkin.horizontalSliderThumb.hover.background = background2; _cachedSkin.horizontalSliderThumb.onHover.background = background2; _cachedSkin.horizontalSliderThumb.normal.background = background2; _cachedSkin.horizontalSliderThumb.onNormal.background = background2; Texture2D val5 = BuildTexFromColorArray((Color[])(object)new Color[7] { Color32.op_Implicit(_classicButtonBackground), Color32.op_Implicit(_classicButtonBackground), Color32.op_Implicit(_classicMenuBackground), Color32.op_Implicit(_classicMenuBackground), Color32.op_Implicit(_classicMenuBackground), Color32.op_Implicit(_classicMenuBackground), Color32.op_Implicit(_classicMenuBackground) }, 1, 7); _cachedSkin.textField.active.background = val5; _cachedSkin.textField.onActive.background = val5; _cachedSkin.textField.focused.background = val5; _cachedSkin.textField.onFocused.background = val5; _cachedSkin.textField.hover.background = val5; _cachedSkin.textField.onHover.background = val5; _cachedSkin.textField.normal.background = val5; _cachedSkin.textField.onNormal.background = val5; _cachedSkin.textField.active.textColor = Color32.op_Implicit(val2); _cachedSkin.textField.onActive.textColor = Color32.op_Implicit(val2); _cachedSkin.textField.hover.textColor = Color32.op_Implicit(val2); _cachedSkin.textField.onHover.textColor = Color32.op_Implicit(val2); Object.DontDestroyOnLoad((Object)(object)val); Object.DontDestroyOnLoad((Object)(object)val3); Object.DontDestroyOnLoad((Object)(object)val4); Object.DontDestroyOnLoad((Object)(object)val5); Object.DontDestroyOnLoad((Object)(object)_cachedSkin); } return _cachedSkin; } private static string GetColorTextForMPType(MultiplayerType mptype) { return mptype switch { MultiplayerType.Unspecified => "#FFFF99", MultiplayerType.All => "#FF3333", _ => string.Empty, }; } private static string GetColoredMPTypeText(MultiplayerType mptype) { return mptype switch { MultiplayerType.Client => "<color=#00CC00>Client</color>", MultiplayerType.Unspecified => "<color=#FFFF99>Unspecified</color>", MultiplayerType.All => "<color=#FF3333>All</color>", _ => mptype.ToString(), }; } private static string GetTextForMPType(MultiplayerType mptype) { return mptype switch { MultiplayerType.All => "<color=#FF3333>All</color> - All Clients will be required to install this mod.", MultiplayerType.Client => "<color=#00CC00>Client</color> - This mod is client-side, but might have special behavior.", MultiplayerType.Unspecified => "<color=#FFFF99>Unspecified</color> - This mod has not had it's multiplayer operations specified for VoidManager.\n- If the host has VoidManager and this mod, Connection will be allowed.\n- If the host has VoidManager but not this mod, they can optionally trust Unspecified Mods.\n- If the host does not have VoidManager, Connection will be disallowed.\n- If the local client is hosting, vanilla clients will be allowed to join the session.", _ => mptype.ToString(), }; } private void DrawModButton(VoidPlugin voidPlugin) { if ((int)voidPlugin.MPType > 3) { if (GUILayout.Button("<color=" + GetColorTextForMPType(voidPlugin.MPType) + ">" + voidPlugin.BepinPlugin.Metadata.Name + "</color>", Array.Empty<GUILayoutOption>())) { selectedMod = voidPlugin; } } else if (GUILayout.Button(voidPlugin.BepinPlugin.Metadata.Name, Array.Empty<GUILayoutOption>())) { selectedMod = voidPlugin; } } private void DrawPlayerModList(Player player) { MPUserDataBlock networkedPeerMods = MPModCheckManager.Instance.GetNetworkedPeerMods(player); if (networkedPeerMods != null) { GUILayout.Label("User VoidManager version: " + networkedPeerMods.VMVersion, Array.Empty<GUILayoutOption>()); GUILayout.Label("ModList:", Array.Empty<GUILayoutOption>()); string text = string.Empty; bool flag = true; MPModDataBlock[] modData = networkedPeerMods.ModData; foreach (MPModDataBlock mPModDataBlock in modData) { if (flag) { flag = false; } else { text += "\n"; } text = text + "- " + mPModDataBlock.ModName + " v" + mPModDataBlock.Version + ", MPType: " + GetColoredMPTypeText(mPModDataBlock.MPType); } GUILayout.Label(text, Array.Empty<GUILayoutOption>()); } else { GUILayout.Label("No Mod data.", Array.Empty<GUILayoutOption>()); } } private Texture2D BuildTexFrom1Color(Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_000b: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, color); val.Apply(); return val; } private Texture2D BuildTexFromColorArray(Color[] color, int width, int height) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown Texture2D val = new Texture2D(width, height); val.SetPixels(color); val.Apply(); return val; } public void DiscoverGUIMenus(Assembly assembly, VoidPlugin voidPlugin) { mods.Add(voidPlugin); Type[] types = assembly.GetTypes(); IEnumerable<Type> enumerable = types.Where((Type t) => typeof(ModSettingsMenu).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); bool flag = false; foreach (Type item2 in enumerable) { ModSettingsMenu item = (ModSettingsMenu)Activator.CreateInstance(item2); settings.Add(item); flag = true; } if (flag) { BepinPlugin.Log.LogInfo((object)("[" + voidPlugin.BepinPlugin.Metadata.Name + "] detected settings menu")); } } public void DiscoverNonVManMod(VoidPlugin voidPlugin) { NonVManMods.Add(voidPlugin); } private void GUIToggleCursor(bool enable) { if (BepinPlugin.Bindings.MenuUnlockCursor.Value || (!enable && ShowingCursor)) { ShowingCursor = enable; CursorUtility.ShowCursor((IShowCursorSource)(object)this, enable); if (ShowingCursor) { InputActionMapRequests.AddOrChangeRequestAllMaps((IInputActionMapRequest)(object)this, false); InputActionMapRequests.AddOrChangeRequest((IInputActionMapRequest)(object)this, "GlobalBindings", true); InputActionMapRequests.AddOrChangeRequest((IInputActionMapRequest)(object)this, "Debug", true); } else { InputActionMapRequests.RemoveRequestAllMaps((IInputActionMapRequest)(object)this); } } } } public abstract class ModSettingsMenu { public abstract string Name(); public abstract void Draw(); public virtual void OnOpen() { } public virtual void OnClose() { } } internal class VManSettings : ModSettingsMenu { private string SizeX = string.Empty; private string SizeY = string.Empty; private string ModListSizeX = string.Empty; private string PlayerListSizeX = string.Empty; private string SizeErrString = string.Empty; public override string Name() { return "VoidManager"; } public override void OnOpen() { SizeX = BepinPlugin.Bindings.MenuWidth.Value.ToString(); SizeY = BepinPlugin.Bindings.MenuHeight.Value.ToString(); ModListSizeX = BepinPlugin.Bindings.MenuListWidth.Value.ToString(); PlayerListSizeX = BepinPlugin.Bindings.PlayerListWidth.Value.ToString(); } public override void Draw() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (GUILayout.Button("Debug Mode: " + (BepinPlugin.Bindings.DebugMode.Value ? "Enabled" : "Disabled"), Array.Empty<GUILayoutOption>())) { BepinPlugin.Bindings.DebugMode.Value = !BepinPlugin.Bindings.DebugMode.Value; } GUI.skin.label.alignment = (TextAnchor)0; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); TextAnchor value = BepinPlugin.Bindings.ModInfoTextAnchor.Value; GUILayout.Label("ModInfoTextAnchor: " + ((object)(TextAnchor)(ref value)).ToString(), Array.Empty<GUILayoutOption>()); if (GUILayout.Button("<", Array.Empty<GUILayoutOption>())) { BepinPlugin.Bindings.ModInfoTextAnchor.Value = Enum.GetValues(typeof(TextAnchor)).Cast<TextAnchor>().SkipWhile((TextAnchor e) => e != (TextAnchor)(BepinPlugin.Bindings.ModInfoTextAnchor.Value - 1)) .First(); } if (GUILayout.Button(">", Array.Empty<GUILayoutOption>())) { BepinPlugin.Bindings.ModInfoTextAnchor.Value = Enum.GetValues(typeof(TextAnchor)).Cast<TextAnchor>().SkipWhile((TextAnchor e) => e != BepinPlugin.Bindings.ModInfoTextAnchor.Value) .Skip(1) .First(); } GUILayout.EndHorizontal(); if (GUILayout.Button("Reset to default", Array.Empty<GUILayoutOption>())) { BepinPlugin.Bindings.SetDefault(); } GUILayout.HorizontalSlider(0f, 100f, 100f, Array.Empty<GUILayoutOption>()); GUI.skin.label.alignment = (TextAnchor)4; GUILayout.Label("ModManager Size", Array.Empty<GUILayoutOption>()); GUI.skin.label.alignment = (TextAnchor)5; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Width:", Array.Empty<GUILayoutOption>()); SizeX = GUILayout.TextField(SizeX, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Height:", Array.Empty<GUILayoutOption>()); SizeY = GUILayout.TextField(SizeY, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Modlist Scrollbar Width:", Array.Empty<GUILayoutOption>()); ModListSizeX = GUILayout.TextField(ModListSizeX, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Playerlist Scrollbar Width:", Array.Empty<GUILayoutOption>()); PlayerListSizeX = GUILayout.TextField(PlayerListSizeX, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUI.skin.label.alignment = (TextAnchor)4; if (SizeErrString != string.Empty) { GUILayout.Label("<color=red>" + SizeErrString + "</color>", Array.Empty<GUILayoutOption>()); } if (GUILayout.Button("Apply Size", Array.Empty<GUILayoutOption>())) { if (!float.TryParse(SizeX, out var result) || !float.TryParse(SizeY, out var result2) || !float.TryParse(ModListSizeX, out var result3) || !float.TryParse(PlayerListSizeX, out var result4)) { SizeErrString = "Size values are not numbers"; } else if ((double)result < 0.3) { SizeErrString = "Width value cannot be smaller than .3"; } else if ((double)result2 < 0.3) { SizeErrString = "Hight value cannot be smaller than .3"; } else if ((double)result3 < 0.1) { SizeErrString = "Modlist Scrollbar Width value canot be smaller than .1"; } else if ((double)result4 < 0.1) { SizeErrString = "Modlist Scrollbar Width value canot be smaller than .1"; } else { BepinPlugin.Bindings.MenuHeight.Value = result2; BepinPlugin.Bindings.MenuWidth.Value = result; BepinPlugin.Bindings.MenuListWidth.Value = result3; BepinPlugin.Bindings.PlayerListWidth.Value = result4; SizeErrString = string.Empty; GUIMain.Instance.updateWindowSize(); } } GUILayout.HorizontalSlider(0f, 100f, 100f, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Unlock Cursor While Open: " + (BepinPlugin.Bindings.MenuUnlockCursor.Value ? "Enabled" : "Disabled"), Array.Empty<GUILayoutOption>())) { BepinPlugin.Bindings.MenuUnlockCursor.Value = !BepinPlugin.Bindings.MenuUnlockCursor.Value; } GUILayout.HorizontalSlider(0f, 100f, 100f, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Trust MPType.Unspecified mods: " + (BepinPlugin.Bindings.TrustMPTypeUnspecified.Value ? "Trusted" : "Not Trusted"), Array.Empty<GUILayoutOption>())) { BepinPlugin.Bindings.TrustMPTypeUnspecified.Value = !BepinPlugin.Bindings.TrustMPTypeUnspecified.Value; } } } } namespace VoidManager.Content { public class Craftables { private Dictionary<GUIDUnion, Tuple<string, CraftingRules>> ModifiedRecipes = new Dictionary<GUIDUnion, Tuple<string, CraftingRules>>(); public static Craftables Instance { get; internal set; } public void SetRecipe(GUIDUnion GUID, string CallerID, CraftingRules craftingRules) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (ModifiedRecipes.ContainsKey(GUID)) { BepinPlugin.Log.LogError((object)$"Attempted to modify recipe for object at GUID: {GUID}, however it has already been modified."); return; } CraftableItemDef val = default(CraftableItemDef); if (!((ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>)(object)ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>.Instance).TryGetByGuid(GUID, ref val)) { throw new ArgumentException("An asset with the provided GUID does not exist."); } ModifiedRecipes.Add(GUID, new Tuple<string, CraftingRules>(CallerID, val.crafting)); val.crafting = craftingRules; } public void SetRecipe(string GUID, string CallerID, CraftingRules craftingRules) { //IL_0002: 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) SetRecipe(new GUIDUnion(GUID), CallerID, craftingRules); } public void SetRecipe(int[] GUID, string CallerID, CraftingRules craftingRules) { //IL_0002: 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) SetRecipe(new GUIDUnion(GUID), CallerID, craftingRules); } public void ResetRecipe(GUIDUnion GUID, string CallerID) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (ModifiedRecipes.TryGetValue(GUID, out var value)) { if (value.Item1 != CallerID) { throw new ArgumentException("CallerID must match Assignment CallerID. Maybe another mod changed the same recipe?", "CallerID"); } ((ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>)(object)ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>.Instance).GetAssetDefById(GUID).crafting = value.Item2; ModifiedRecipes.Remove(GUID); } } public void ResetRecipe(string GUID, string CallerID) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ResetRecipe(new GUIDUnion(GUID), CallerID); } public void ResetRecipe(int[] GUID, string CallerID) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ResetRecipe(new GUIDUnion(GUID), CallerID); } public CraftingRules GetRecipe(GUIDUnion GUID) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) return ((ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>)(object)ResourceAssetContainer<CraftingDataContainer, Object, CraftableItemDef>.Instance).GetAssetDefById(GUID).crafting; } public CraftingRules GetRecipe(string GUID) { //IL_0002: 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) return GetRecipe(new GUIDUnion(GUID)); } public CraftingRules GetRecipe(int[] GUID) { //IL_0002: 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) return GetRecipe(new GUIDUnion(GUID)); } } public class Unlocks { private static FieldInfo UnlockOptionsFI = AccessTools.Field(typeof(UnlockItemDef), "unlockOptions"); private Dictionary<GUIDUnion, Tuple<string, UnlockOptions>> ModifiedUnlockOptions = new Dictionary<GUIDUnion, Tuple<string, UnlockOptions>>(); public static Unlocks Instance { get; internal set; } public void SetUnlockOptions(GUIDUnion GUID, string CallerID, UnlockOptions unlockOptions) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (ModifiedUnlockOptions.ContainsKey(GUID)) { BepinPlugin.Log.LogError((object)$"Attempted to modify recipe for object at GUID: {GUID}, however it has already been modified."); return; } UnlockItemDef obj = default(UnlockItemDef); if (!((ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>)(object)ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>.Instance).TryGetByGuid(GUID, ref obj)) { throw new ArgumentException("An asset with the provided GUID does not exist."); } ModifiedUnlockOptions.Add(GUID, new Tuple<string, UnlockOptions>(CallerID, (UnlockOptions)UnlockOptionsFI.GetValue(obj))); UnlockOptionsFI.SetValue(obj, unlockOptions); } public void SetUnlockOptions(string GUID, string CallerID, UnlockOptions unlockOptions) { //IL_0002: 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) SetUnlockOptions(new GUIDUnion(GUID), CallerID, unlockOptions); } public void SetUnlockOptions(int[] GUID, string CallerID, UnlockOptions unlockOptions) { //IL_0002: 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) SetUnlockOptions(new GUIDUnion(GUID), CallerID, unlockOptions); } public void ResetUnlockOptions(GUIDUnion GUID, string CallerID) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (ModifiedUnlockOptions.TryGetValue(GUID, out var value)) { if (value.Item1 != CallerID) { throw new ArgumentException("CallerID must match Assignment CallerID. Maybe another mod changed the same UnlockOptions?", "CallerID"); } UnlockOptionsFI.SetValue(((ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>)(object)ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>.Instance).GetAssetDefById(GUID), value.Item2); ModifiedUnlockOptions.Remove(GUID); } } public void ResetUnlockOptions(string GUID, string CallerID) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ResetUnlockOptions(new GUIDUnion(GUID), CallerID); } public void ResetUnlockOptions(int[] GUID, string CallerID) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ResetUnlockOptions(new GUIDUnion(GUID), CallerID); } public UnlockOptions GetUnlockOptions(GUIDUnion GUID) { //IL_000a: 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) return (UnlockOptions)UnlockOptionsFI.GetValue(((ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>)(object)ResourceAssetContainer<UnlockContainer, Object, UnlockItemDef>.Instance).GetAssetDefById(GUID)); } public UnlockOptions GetUnlockOptions(string GUID) { //IL_0002: 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) return GetUnlockOptions(new GUIDUnion(GUID)); } public UnlockOptions GetUnlockOptions(int[] GUID) { //IL_0002: 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) return GetUnlockOptions(new GUIDUnion(GUID)); } } } namespace VoidManager.Chat { internal class EchoCommand : ChatCommand { public override string[] CommandAliases() { return new string[2] { "echo", "e" }; } public override string Description() { return "Repeats the input text back through the chat box."; } public override string[] UsageExamples() { return new string[1] { "/" + CommandAliases()[0] + " <text>" }; } public override void Execute(string arguments) { Messaging.Echo("Echo: " + arguments); } } internal class HelpCommand : ChatCommand { public override string[] CommandAliases() { return new string[2] { "help", "?" }; } public override string Description() { return "Displays help text for a command, or the list of commands if none specified."; } public override string[] UsageExamples() { return new List<string>(base.UsageExamples()).Concat(new string[2] { "/" + CommandAliases()[0] + " clear", "/" + CommandAliases()[0] + " 3" }).ToArray(); } public override void Execute(string arguments) { int result = 1; if (!string.IsNullOrWhiteSpace(arguments) && !int.TryParse(arguments, out result)) { if (arguments[0] == '/') { arguments = arguments.Substring(1); } ChatCommand command = CommandHandler.GetCommand(arguments.Split(new char[1] { ' ' })[0]); StringBuilder stringBuilder = new StringBuilder(); if (command != null) { stringBuilder.AppendLine("<color=green>/" + command.CommandAliases()[0] + "</color> - " + command.Description()); stringBuilder.AppendLine("Aliases: /" + string.Join(", /", command.CommandAliases())); stringBuilder.AppendLine("Usage: " + command.UsageExamples()[0]); for (int i = 1; i < command.UsageExamples().Length; i++) { stringBuilder.AppendLine(" " + command.UsageExamples()[i]); } } else { stringBuilder.AppendLine("Command /" + arguments + " not found"); } Messaging.Echo(stringBuilder.ToString()); return; } int num = 6; IOrderedEnumerable<ChatCommand> commands = CommandHandler.GetCommands(); int num2 = Mathf.CeilToInt((float)commands.Count() / (float)num); result--; if (result < 0) { result = 0; } StringBuilder stringBuilder2 = new StringBuilder(); stringBuilder2.AppendLine((num2 == 1 && result == 0) ? "<color=green>Command List:</color> :" : $"<color=green>Command List:</color> Page {result + 1} : {num2}"); for (int j = 0; j < num; j++) { int index = j + result * num; if (j + result * num >= commands.Count()) { break; } ChatCommand chatCommand = commands.ElementAt(index); stringBuilder2.AppendLine("/" + chatCommand.CommandAliases()[0] + " - " + chatCommand.Description()); } stringBuilder2.AppendLine("Use <color=green>/help <command></color> for details about a specific command"); Messaging.Echo(stringBuilder2.ToString()); } } internal class ListPlayers : ChatCommand { public override string[] CommandAliases() { return new string[3] { "listplayers", "players", "list" }; } public override string Description() { return "Returns a list of players with their ID's"; } public override string[] UsageExamples() { return new string[1] { "/" + CommandAliases()[0] }; } public override void Execute(string arguments) { if (!PhotonNetwork.InRoom) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[Player List]"); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val != null) { stringBuilder.AppendLine($"{val.ActorNumber} - {val.NickName}"); } } Messaging.Notification(stringBuilder.ToString()); } } internal class PublicHelpCommand : PublicCommand { public override string[] CommandAliases() { return new string[1] { "help" }; } public override string Description() { return "Displays a list of available public commands"; } public override string[] UsageExamples() { return new List<string>(base.UsageExamples()).Concat(new string[2] { "!" + CommandAliases()[0] + " help", "!" + CommandAliases()[0] + " 2" }).ToArray(); } public override void Execute(string arguments, int senderId) { if (!PhotonNetwork.IsMasterClient) { return; } int result = 1; if (!string.IsNullOrWhiteSpace(arguments) && !int.TryParse(arguments, out result)) { if (arguments[0] == '!') { arguments = arguments.Substring(1); } PublicCommand publicCommand = CommandHandler.GetPublicCommand(arguments.Split(new char[1] { ' ' })[0]); StringBuilder stringBuilder = new StringBuilder(); if (publicCommand != null) { stringBuilder.AppendLine("<color=green>!" + publicCommand.CommandAliases()[0] + "</color> - " + publicCommand.Description()); stringBuilder.AppendLine("Aliases: !" + string.Join(", !", publicCommand.CommandAliases())); stringBuilder.AppendLine("Usage: " + publicCommand.UsageExamples()[0]); for (int i = 1; i < publicCommand.UsageExamples().Length; i++) { stringBuilder.AppendLine(" " + publicCommand.UsageExamples()[i]); } } else { stringBuilder.AppendLine("Public Command !" + arguments + " not found"); } Messaging.Echo(stringBuilder.ToString(), local: false); return; } int num = 6; IOrderedEnumerable<PublicCommand> publicCommands = CommandHandler.GetPublicCommands(); int num2 = Mathf.CeilToInt((float)publicCommands.Count() / (float)num); result--; if (result < 0) { result = 0; } StringBuilder stringBuilder2 = new StringBuilder(); stringBuilder2.AppendLine((num2 == 1 && result == 0) ? "<color=green>Public Command List:</color> :" : $"<color=green>Public Command List:</color> Page {result + 1} : {num2}"); for (int j = 0; j < num; j++) { int index = j + result * num; if (j + result * num >= publicCommands.Count()) { break; } PublicCommand publicCommand2 = publicCommands.ElementAt(index); stringBuilder2.AppendLine("!" + publicCommand2.CommandAliases()[0] + " - " + publicCommand2.Description()); } stringBuilder2.AppendLine("Use <color=green>!help <command></color> for details about a specific public command"); Messaging.Echo(stringBuilder2.ToString(), local: false); } } } namespace VoidManager.Chat.Router { public abstract class ChatCommand { public abstract string[] CommandAliases(); public abstract string Description(); public virtual string[] UsageExamples() { return new string[1] { "/" + CommandAliases()[0] }; } public abstract void Execute(string arguments); } public abstract class PublicCommand { public abstract string[] CommandAliases(); public abstract string Description(); public virtual string[] UsageExamples() { return new string[1] { "/" + CommandAliases()[0] }; } public abstract void Execute(string arguments, int Sender); } [HarmonyPatch(typeof(TextChatVE), "GetMessage")] internal class ChatCommandDetectPatch { [HarmonyPostfix] public static void DiscoverChatCommand(ref string __result) { if (__result.StartsWith("/")) { __result = __result.Substring(1); string text = __result.Split(new char[1] { ' ' })[0]; string arguments = __result.Substring(text.Length + ((__result.Split(new char[1] { ' ' }).Count() != 1) ? 1 : 0)); CommandHandler.ExecuteCommandFromAlias(text, arguments); __result = ""; } } } [HarmonyPatch(typeof(TextChat), "IncomingMessage")] internal class PublicCommandDetectPatch { [HarmonyPostfix] public static void DiscoverPublicCommand(Player p, string channelTextMessage) { if (channelTextMessage.StartsWith("!")) { channelTextMessage = channelTextMessage.Substring(1); string text = channelTextMessage.Split(new char[1] { ' ' })[0]; Player playerByName = Game.GetPlayerByName(p.NickName); string text2 = channelTextMessage.Substring(text.Length + ((channelTextMessage.Split(new char[1] { ' ' }).Count() != 1) ? 1 : 0)); BepinPlugin.Log.LogInfo((object)("'!" + text + " " + text2 + "' attempted by " + p.NickName)); CommandHandler.ExecuteCommandFromAlias(text, text2, publicCommand: true, Game.GetIDFromPlayer(playerByName)); } } } internal class CommandHandler { private static Dictionary<string, ChatCommand> chatCommands = new Dictionary<string, ChatCommand>(); private static Dictionary<string, PublicCommand> publicCommands = new Dictionary<string, PublicCommand>(); public static int chatCommandCount => chatCommands.Coun