Decompiled source of VoidManager v1.2.2
VoidManager.dll
Decompiled 2 months 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.ComponentModel; 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.Cloud; using CG.Game; using CG.Game.Player; using CG.Game.SpaceObjects.Controllers; using CG.GameLoopStateMachine; using CG.GameLoopStateMachine.GameStates; using CG.Input; using CG.Profile; using CG.Ship.Modules; using CG.Space; using ExitGames.Client.Photon; using Gameplay.Chat; using Gameplay.Quests; using Gameplay.Terminals; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using ResourceAssets; using Steamworks; using ToolClasses; using UI.Chat; using UI.Core; using UI.Matchmaking; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using UnityEngine.UIElements; using VoidManager.Callbacks; using VoidManager.Chat.Additions; using VoidManager.Chat.Router; using VoidManager.Content; using VoidManager.CustomGUI; using VoidManager.LobbyPlayerList; using VoidManager.MPModChecks; using VoidManager.MPModChecks.Patches; using VoidManager.ModMessages; using VoidManager.Progression; 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("Void Crew Modding Team")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Manages mods for multiplayer, gives users Mod controls via GUI (when provided by the mod, default keybind F5), provides API for developers, and minor Chat improvements.")] [assembly: AssemblyFileVersion("1.2.2.0")] [assembly: AssemblyInformationalVersion("1.2.2+f0c1490f65ae244e783f63915249ea71bbc5a26c")] [assembly: AssemblyProduct("VoidManager")] [assembly: AssemblyTitle("Manages mods for multiplayer, gives users Mod controls via GUI (when provided by the mod, default keybind F5), provides API for developers, and minor Chat improvements.")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.2.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("VoidCrewModdingTeam.VoidManager", "Void Manager", "1.2.2")] [BepInProcess("Void Crew.exe")] public class BepinPlugin : BaseUnityPlugin { public class Bindings { public static ConfigEntry<TextAnchor> ModInfoTextAnchor; public 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> DisplayPlayerModList; internal static ConfigEntry<bool> DisplayPlayerSettingsMenus; internal static ConfigEntry<string> UnspecifiedModListOverride; internal static Dictionary<string, MultiplayerType> ModOverrideDictionary; internal static ConfigEntry<PunLogLevel> PunLoggingSettingLevel; internal static ConfigEntry<DebugLevel> PunDebugLogLevel; 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(','); 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(":host", StringComparison.CurrentCultureIgnoreCase)) { ModOverrideDictionary.Add(text.Substring(0, text.Length - 5), MultiplayerType.Host); } 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("VoidCrewModdingTeam.VoidManager"); internal static ManualLogSource Log; private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) instance = this; Log = ((BaseUnityPlugin)this).Logger; ModdingUtils.SessionModdingType = (ModdingType)1; try { Harmony.PatchAll(); } catch (Exception ex) { Log.LogError((object)ex); } Craftables.Instance = new Craftables(); Unlocks.Instance = new Unlocks(); Events.Instance = new Events(); 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 Void Manager) for which you would like to override the MPType. \nAvailable MPTypes: client,host,all \nFormat: 'ModNameOrGUID:MPType', delineated by ','. \nEx: Void Manager:all,Better Scoop:Host \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.DisplayPlayerModList = ((BaseUnityPlugin)this).Config.Bind<bool>("Menu", "Player Mod List", false, "Display in the Player List GUI"); Bindings.DisplayPlayerSettingsMenus = ((BaseUnityPlugin)this).Config.Bind<bool>("Menu", "Player Settings Menus", true, "Display in the Player List GUI"); Bindings.PunLoggingSettingLevel = ((BaseUnityPlugin)this).Config.Bind<PunLogLevel>("Debug", "PunLogLevel", (PunLogLevel)0, (ConfigDescription)null); Bindings.PunDebugLogLevel = ((BaseUnityPlugin)this).Config.Bind<DebugLevel>("Debug", "PunDebugLevel", (DebugLevel)1, (ConfigDescription)null); ((Object)Chainloader.ManagerObject).hideFlags = (HideFlags)61; Events.Instance.ChatWindowOpened += ChatHistory.OnChatOpened; Events.Instance.ChatWindowOpened += CursorUnlock.OnChatOpened; Events.Instance.ChatWindowOpened += AutoComplete.OnChatOpened; Events.Instance.ChatWindowClosed += ChatHistory.OnChatClosed; Events.Instance.ChatWindowClosed += CursorUnlock.OnChatClosed; Events.Instance.ChatWindowClosed += AutoComplete.OnChatClosed; Events.Instance.LateUpdate += ChatHistory.Tick; Events.Instance.LateUpdate += AutoComplete.Tick; Events.Instance.JoinedRoom += PublicCommandHandler.RefreshPublicCommandCache; Events.Instance.ClientModlistRecieved += PublicCommandHandler.RefreshPublicCommandCache; Events.Instance.MasterClientSwitched += PublicCommandHandler.RefreshPublicCommandCache; Events.Instance.PlayerEnteredRoom += AutoComplete.RefreshPlayerList; Events.Instance.PlayerLeftRoom += AutoComplete.RefreshPlayerList; Events.Instance.JoinedRoom += AutoComplete.RefreshPlayerList; Log.LogInfo((object)"VoidCrewModdingTeam.VoidManager Initialized."); } } 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; } public class PlayerPropertiesEventArgs : EventArgs { public Player player; public Hashtable changedProperties; } public class RoomPropertiesEventArgs : EventArgs { public Hashtable changedProperties; } [HarmonyPatch(typeof(GameSessionManager), "HostGameSession")] private class HostStartSessionPatch { private static void Postfix() { Instance.OnHostStartSession(); } } [HarmonyPatch(typeof(GameSessionManager), "JoinGameSession")] private class JoinSessionPatch { private static void Postfix() { Instance.OnJoinedSession(); } } [HarmonyPatch(typeof(TextChatVE))] private class TextChatVEPatch { [HarmonyPostfix] [HarmonyPatch("ShowInput")] private static void ShowChatWindow() { Instance.ChatWindowOpened(Instance, EventArgs.Empty); } [HarmonyPostfix] [HarmonyPatch("HideInput")] private static void HideChatWindow() { Instance.ChatWindowClosed(Instance, EventArgs.Empty); } } [HarmonyPatch(typeof(ClientGame), "LateUpdate")] private static class ClientGamePatch { private static void Postfix() { Instance.LateUpdate(Instance, EventArgs.Empty); } } 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; public event EventHandler HostCreateRoom; public event EventHandler JoinedSession; public event EventHandler<PlayerPropertiesEventArgs> PlayerPropertiesUpdate; public event EventHandler<RoomPropertiesEventArgs> RoomPropertiesUpdate; public event EventHandler ChatWindowOpened; public event EventHandler ChatWindowClosed; public event EventHandler LateUpdate; internal void OnPlayerEnteredRoom(Player joiningPlayer) { if (((Dictionary<object, object>)(object)joiningPlayer.CustomProperties).TryGetValue((object)"Mods", out object value)) { BepinPlugin.Log.LogInfo((object)("Found mod info in player custom props " + joiningPlayer.NickName)); BepinPlugin.Log.LogInfo((object)NetworkedPeerManager.GetModListAsString(NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])value).ModData)); } else { BepinPlugin.Log.LogInfo((object)("Didn't Found mod info in player custom props " + joiningPlayer.NickName)); } ProgressionHandler.OnPlayerJoin(joiningPlayer); MPModCheckManager.Instance.PlayerJoined(joiningPlayer); LobbyPlayerListManager.Instance.UpdateLobbyPlayers(); this.PlayerEnteredRoom?.Invoke(this, new PlayerEventArgs { player = joiningPlayer }); } internal void OnPlayerLeftRoom(Player leavingPlayer) { if (GUIMain.Instance.selectedPlayer == leavingPlayer) { GUIMain.Instance.SelectPlayer(null); } LobbyPlayerListManager.Instance.UpdateLobbyPlayers(); this.PlayerLeftRoom?.Invoke(this, new PlayerEventArgs { player = leavingPlayer }); NetworkedPeerManager.Instance.PlayerLeftRoom(leavingPlayer); } internal void OnJoinedRoom() { MPModCheckManager.Instance.JoinedRoom(); PluginHandler.SessionWasEscalated = false; this.JoinedRoom?.Invoke(this, EventArgs.Empty); } internal void OnLeftRoom() { NetworkedPeerManager.Instance.LeftRoom(); this.LeftRoom?.Invoke(this, EventArgs.Empty); } internal void OnMasterClientSwitched(Player newMasterClient) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 if (PhotonNetwork.LocalPlayer.IsMasterClient) { MPModCheckManager.Instance.UpdateLobbyProperties(); } ProgressionHandler.OnHostChange(newMasterClient); bool isLocal = newMasterClient.IsLocal; this.MasterClientSwitched?.Invoke(this, new PlayerEventArgs { player = newMasterClient }); PluginHandler.InternalSessionChanged(CallType.HostChange, (isLocal && (int)ModdingUtils.SessionModdingType == 2) || MPModCheckManager.IsMod_Session(), isLocal, newMasterClient); } internal void OnHostVerifiedClient(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); PluginHandler.InternalSessionChanged(CallType.HostStartSession, MPModCheckManager.IsMod_Session(), isMasterClient: true); } internal void OnHostCreateRoom() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 this.HostCreateRoom?.Invoke(this, EventArgs.Empty); PluginHandler.CreatedRoomAsHost = true; PluginHandler.InternalSessionChanged(CallType.HostCreateRoom, (int)ModdingUtils.SessionModdingType == 2, isMasterClient: true); } internal void OnJoinedSession() { this.JoinedSession?.Invoke(this, EventArgs.Empty); PluginHandler.CreatedRoomAsHost = false; PluginHandler.InternalSessionChanged(CallType.Joining, MPModCheckManager.IsMod_Session(), isMasterClient: false, PhotonNetwork.MasterClient); } internal void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { if (((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"RP_PR") || ((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"RP_FR")) { LobbyPlayerListManager.Instance.UpdateLobbyPlayers(); } this.PlayerPropertiesUpdate?.Invoke(this, new PlayerPropertiesEventArgs { player = targetPlayer, changedProperties = changedProps }); } internal void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { this.RoomPropertiesUpdate?.Invoke(this, new RoomPropertiesEventArgs { changedProperties = propertiesThatChanged }); } } public class MyPluginInfo { public const string PLUGIN_GUID = "VoidCrewModdingTeam.VoidManager"; public const string PLUGIN_NAME = "VoidManager"; public const string USERS_PLUGIN_NAME = "Void Manager"; public const string PLUGIN_VERSION = "1.2.2"; public const string PLUGIN_DESCRIPTION = "Manages mods for multiplayer, gives users Mod controls via GUI (when provided by the mod, default keybind F5), provides API for developers, and minor Chat improvements."; public const string PLUGIN_ORIGINAL_AUTHOR = "VoidCrewModdingTeam"; public const string PLUGIN_AUTHORS = "Mest, Dragon, and 18107"; public const string PLUGIN_THUNDERSTORE_ID = "VoidCrewModdingTeam/VoidManager"; } internal static class PluginHandler { internal static bool CreatedRoomAsHost; internal static bool SessionWasEscalated; 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() { //IL_0176: Unknown result type (might be due to invalid IL or missing references) 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 == "VoidCrewModdingTeam.VoidManager") { CommandHandler.DiscoverCommands(assembly, name); CommandHandler.DiscoverPublicCommands(assembly, name); ModMessageHandler.DiscoverModMessages(assembly, value2); continue; } try { 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); if (voidPlugin.BepinPlugin.Metadata.GUID == "NoUnrepairableDamage") { BepinPlugin.Log.LogInfo((object)"NoUnrepairableDamage mod detected, Registering Session Mod."); ModdingUtils.SessionModdingType = (ModdingType)2; } } 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.Unmanaged); } voidPlugin.VersionInfo = FileVersionInfo.GetVersionInfo(value2.Location); voidPlugin.ModHash = GetFileHash(value2.Location); voidPlugin.BepinPlugin = value2; GUIMain.Instance.DiscoverNonVoidManagerMod(voidPlugin); GeneratedVoidPlugins.Add(gUID, voidPlugin); } } catch (Exception arg) { BepinPlugin.Log.LogError((object)$"Error loading mod '{name}'\n{arg}"); } } GUIMain.Instance.settings = (from v in GUIMain.Instance.settings orderby v is VManSettings descending, v.Name() select v).ToList(); GUIMain.Instance.mods.Sort((VoidPlugin plugin1, VoidPlugin plugin2) => plugin1.BepinPlugin.Metadata.Name.CompareTo(plugin2.BepinPlugin.Metadata.Name)); 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)string.Format("Discovered {0} {1} plugin(s) from {2} mod(s)", ActiveVoidPlugins.Count, "VoidManager", ActiveBepinPlugins.Count - 1)); } public static byte[] GetFileHash(string fileLocation) { using SHA256 sHA = SHA256.Create(); return sHA.ComputeHash(File.ReadAllBytes(fileLocation)); } internal static void InternalSessionChanged(CallType callType, bool isMod_Session, bool isMasterClient, Player Host = null) { Dictionary<VoidPlugin, SessionChangedInput> dictionary = new Dictionary<VoidPlugin, SessionChangedInput>(); bool flag = false; SessionChangedInput sessionChangedInput = default(SessionChangedInput); sessionChangedInput.CallType = callType; sessionChangedInput.IsHost = isMasterClient; sessionChangedInput.HostHasMod = isMasterClient; sessionChangedInput.CreatedRoomAsHost = CreatedRoomAsHost; sessionChangedInput.StartedSessionAsHost = CreatedRoomAsHost || GameSessionManager.Instance.StartedSessionAsHost; sessionChangedInput.IsMod_Session = isMod_Session; if (BepinPlugin.Bindings.DebugMode.Value) { BepinPlugin.Log.LogInfo((object)$"OnSessionChanged callback\ncallType: {sessionChangedInput.CallType}, isHost: {sessionChangedInput.IsHost}, IsModSession: {sessionChangedInput.IsMod_Session}, CreatedRoomAsHost: {sessionChangedInput.CreatedRoomAsHost}, StartedSessionAshost: {sessionChangedInput.StartedSessionAsHost}"); } foreach (KeyValuePair<string, VoidPlugin> activeVoidPlugin in ActiveVoidPlugins) { if (!isMasterClient) { sessionChangedInput.HostHasMod = NetworkedPeerManager.Instance.NetworkedPeerHasMod(Host, activeVoidPlugin.Key); } if (!isMod_Session) { if (!activeVoidPlugin.Value.OnSessionChange(sessionChangedInput).SetMod_Session) { dictionary.Add(activeVoidPlugin.Value, sessionChangedInput); continue; } flag = true; isMod_Session = true; } else { activeVoidPlugin.Value.OnSessionChange(sessionChangedInput); } } if (!(flag && isMasterClient)) { return; } if (BepinPlugin.Bindings.DebugMode.Value) { BepinPlugin.Log.LogInfo((object)"Mod requested Incriment to Mod_Session"); } ModdingUtils.RegisterSessionMod(); foreach (KeyValuePair<VoidPlugin, SessionChangedInput> item in dictionary) { SessionChangedInput value = item.Value; value.IsMod_Session = true; item.Key.OnSessionChange(value); } } internal static void InternalEscalateSession() { InternalSessionChanged(CallType.SessionEscalated, isMod_Session: true, PhotonNetwork.IsMasterClient, PhotonNetwork.MasterClient); } internal static bool CanEscalateSession() { if (PhotonNetwork.IsMasterClient) { return !SessionWasEscalated; } return false; } internal static void EscalateSession() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (CanEscalateSession()) { Messaging.Echo("Escalating to Mod_Session", local: false); ModdingUtils.RegisterSessionMod(); PhotonNetwork.RaiseEvent((byte)96, (object)null, (RaiseEventOptions)null, SendOptions.SendReliable); InternalEscalateSession(); SessionWasEscalated = true; } } } public struct SessionChangedInput { public bool IsHost; public CallType CallType; public bool CreatedRoomAsHost; public bool StartedSessionAsHost; public bool IsMod_Session; public bool HostHasMod; public SessionChangedInput(bool isHost, CallType callType, bool startedAsHost, bool isMod_Session, bool hostHasMod) { StartedSessionAsHost = false; IsHost = isHost; CallType = callType; CreatedRoomAsHost = startedAsHost; IsMod_Session = isMod_Session; HostHasMod = hostHasMod; } } public enum CallType { HostCreateRoom, HostStartSession, Joining, HostChange, SessionEscalated } public struct SessionChangedReturn { public bool SetMod_Session; } 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 string ThunderstoreID => string.Empty; public virtual MultiplayerType MPType => MultiplayerType.Session; public virtual SessionChangedReturn OnSessionChange(SessionChangedInput input) { SessionChangedReturn result = default(SessionChangedReturn); result.SetMod_Session = false; return result; } } } namespace VoidManager.Utilities { public class Game { private static readonly GUIDUnion _EndlessQuestGUID = new GUIDUnion("57ff22b0dae09944b9fa81fe5c37c470"); public static ClientGame Instance => ClientGame.Current; public static bool InGame => (Object)(object)Instance != (Object)null; public static List<Player> Players { get { if (!InGame) { return new List<Player>(); } return ClientGame.Current.Players; } } public static bool PlayerShipExists { get { ClientGame current = ClientGame.Current; object obj; if (current == null) { obj = null; } else { AbstractPlayerControlledShip playerShip = current.PlayerShip; obj = ((playerShip != null) ? playerShip.Platform : null); } return (Object)obj != (Object)null; } } public static bool InVoid { get { ClientGame current = ClientGame.Current; object obj; if (current == null) { obj = null; } else { AbstractPlayerControlledShip playerShip = current.PlayerShip; if (playerShip == null) { obj = null; } else { GameObject gameObject = ((AbstractCloneStarObject)playerShip).GameObject; obj = ((gameObject != null) ? gameObject.GetComponent<VoidJumpSystem>() : null); } } VoidJumpSystem val = (VoidJumpSystem)obj; if ((Object)(object)val == (Object)null) { return false; } VoidJumpState activeState = val.ActiveState; if ((activeState is VoidJumpTravellingStable || activeState is VoidJumpTravellingUnstable || activeState is VoidJumpInterdiction || activeState is VoidJumpApproachingDestination || activeState is VoidJumpSpinningDown) ? true : false) { return true; } return false; } } public static Player CurrentPilot { get { ClientGame current = ClientGame.Current; object obj; if (current == null) { obj = null; } else { AbstractPlayerControlledShip playerShip = current.PlayerShip; if (playerShip == null) { obj = null; } else { GameObject gameObject = ((Component)playerShip).gameObject; if (gameObject == null) { obj = null; } else { Helm componentInChildren = gameObject.GetComponentInChildren<Helm>(); obj = ((componentInChildren != null) ? componentInChildren.Chair : null); } } } TakeoverChair val = (TakeoverChair)((obj is TakeoverChair) ? obj : null); if ((Object)(object)val == (Object)null || val.IsAvailable) { return null; } return ClientGame.Current.GetPlayerCharacterByActorNumber(((MonoBehaviourPun)val).photonView.Owner.ActorNumber); } } public static GUIDUnion EndlessQuestGUID => _EndlessQuestGUID; public static QuestAsset EndlessQuestAsset => GetQuestAsset(EndlessQuestGUID); 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 bool TryGetQuestAsset(GUIDUnion QuestGUID, out QuestAsset QuestAsset) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) QuestAssetDef val = default(QuestAssetDef); if (((ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>)(object)ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>.Instance).TryGetByGuid(QuestGUID, ref val)) { QuestAsset = ((ResourceAssetDef<QuestAsset>)(object)val).Asset; return true; } BepinPlugin.Log.LogError((object)"Provided QuestGUID did not exist"); QuestAsset = null; return false; } public static QuestAsset GetQuestAsset(GUIDUnion QuestGUID) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return ((ResourceAssetDef<QuestAsset>)(object)((ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>)(object)ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>.Instance).GetAssetDefById(QuestGUID, true)).Asset; } } public class GUITools { public static GUIStyle ButtonMinSizeStyle; internal static string keybindToChange = null; private static readonly Dictionary<object, string> TextFieldStrings = new Dictionary<object, string>(); public static void SettingGroup(string label, ref string settingvalue, Action ApplyFunc) { GUILayout.Label(label, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); settingvalue = GUILayout.TextField(settingvalue, Array.Empty<GUILayoutOption>()); if (PhotonNetwork.IsMasterClient && GUILayout.Button("Apply", ButtonMinSizeStyle, Array.Empty<GUILayoutOption>())) { ApplyFunc?.Invoke(); } GUILayout.EndHorizontal(); } public static bool DrawChangeKeybindButton(string buttonName, ref KeyCode keybind) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected I4, but got Unknown if (string.IsNullOrEmpty(buttonName)) { throw new ArgumentException("buttonName must not be null or empty"); } bool result = false; bool flag = keybindToChange == buttonName; if (flag) { Event current = Event.current; if (current.isKey) { if ((int)current.keyCode == 27) { keybind = (KeyCode)0; result = true; keybindToChange = null; } else { keybind = (KeyCode)(int)current.keyCode; result = true; keybindToChange = null; } } } if (GUILayout.Button(flag ? (buttonName + ": ..... Press ESC to remove") : $"{buttonName}: ({keybind})", Array.Empty<GUILayoutOption>())) { keybindToChange = buttonName; } return result; } public static bool DrawChangeKeybindButton(string buttonName, ref ConfigEntry<KeyCode> keybindConfig) { //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) //IL_0016: Unknown result type (might be due to invalid IL or missing references) KeyCode keybind = keybindConfig.Value; bool flag = DrawChangeKeybindButton(buttonName, ref keybind); if (flag) { keybindConfig.Value = keybind; } return flag; } public static bool DrawButtonSelected(string text, bool selected) { if (selected) { return GUILayout.Button(text, GUIMain._SelectedButtonStyle, Array.Empty<GUILayoutOption>()); } return GUILayout.Button(text, Array.Empty<GUILayoutOption>()); } public static bool DrawCheckbox(string label, ref bool isOn) { bool flag = GUILayout.Toggle(isOn, label, Array.Empty<GUILayoutOption>()); if (flag != isOn) { isOn = flag; return true; } return false; } public static bool DrawCheckbox(string label, ref ConfigEntry<bool> config) { bool flag = GUILayout.Toggle(config.Value, label, Array.Empty<GUILayoutOption>()); if (flag != config.Value) { config.Value = flag; return true; } return false; } public static bool DrawSlider(ref float value, float leftValue, float rightValue) { bool result = false; float num = GUILayout.HorizontalSlider(value, leftValue, rightValue, Array.Empty<GUILayoutOption>()); if (num != value) { result = true; value = num; } return result; } public static bool DrawSlider(ref ConfigEntry<float> entry, float leftValue, float rightValue) { bool result = false; float num = GUILayout.HorizontalSlider(entry.Value, leftValue, rightValue, Array.Empty<GUILayoutOption>()); if (num != entry.Value) { result = true; entry.Value = num; } return result; } public static bool DrawTextField(string label, ref string value, string defaultValue = null, float minWidth = 80f) { bool result = false; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(label + ": ", Array.Empty<GUILayoutOption>()); value = GUILayout.TextField(value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(minWidth) }); GUILayout.FlexibleSpace(); if (GUILayout.Button("Apply", Array.Empty<GUILayoutOption>())) { result = true; } if (defaultValue != null && GUILayout.Button("Reset", Array.Empty<GUILayoutOption>())) { value = defaultValue; result = true; } GUILayout.EndHorizontal(); return result; } public static bool DrawTextField<T>(string label, ref ConfigEntry<T> entry, float minWidth = 80f) { if (!TextFieldStrings.ContainsKey(entry)) { TextFieldStrings.Add(entry, entry.Value.ToString()); } bool result = false; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(label + ": ", Array.Empty<GUILayoutOption>()); TextFieldStrings[entry] = GUILayout.TextField(TextFieldStrings[entry], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(minWidth) }); GUILayout.FlexibleSpace(); if (GUILayout.Button("Apply", Array.Empty<GUILayoutOption>())) { try { entry.Value = (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(TextFieldStrings[entry]); } finally { TextFieldStrings[entry] = entry.Value.ToString(); } result = true; } if (GUILayout.Button("Reset", Array.Empty<GUILayoutOption>())) { entry.Value = (T)((ConfigEntryBase)entry).DefaultValue; TextFieldStrings[entry] = entry.Value.ToString(); result = true; } GUILayout.EndHorizontal(); return result; } public static bool DrawColorPicker(Rect rect, string label, ref Color color, Color resetColor, bool showAlpha = true, float min = 0f, float max = 20f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) bool result = false; GUILayout.BeginArea(rect, "", GUIStyle.op_Implicit("Box")); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(label, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.BeginVertical(GUIStyle.op_Implicit("Box"), Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("R", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) }); float num = GUILayout.HorizontalSlider(color.r, min, max, Array.Empty<GUILayoutOption>()); if (num != color.r) { color.r = num; result = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("G", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) }); num = GUILayout.HorizontalSlider(color.g, min, max, Array.Empty<GUILayoutOption>()); if (num != color.g) { color.g = num; result = true; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("B", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) }); num = GUILayout.HorizontalSlider(color.b, min, max, Array.Empty<GUILayoutOption>()); if (num != color.b) { color.b = num; result = true; } GUILayout.EndHorizontal(); if (showAlpha) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("A", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) }); num = GUILayout.HorizontalSlider(color.a, min, Mathf.Min(max, 1f), Array.Empty<GUILayoutOption>()); if (num != color.a) { color.a = num; result = true; } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); GUILayout.BeginVertical(GUIStyle.op_Implicit("Box"), (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(44f), GUILayout.Height(44f) }); Color color2 = GUI.color; float num2 = Mathf.Max(((Color)(ref color)).maxColorComponent, 1f); GUI.color = new Color(color.r / num2, color.g / num2, color.b / num2, color.a); GUILayout.Label((Texture)new Texture2D(60, 40), Array.Empty<GUILayoutOption>()); GUI.color = color2; GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label($"{color.r:0.00}, {color.g:0.00}, {color.b:0.00}" + (showAlpha ? $", {color.a:0.00}" : ""), Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(66f) })) { color.r = resetColor.r; color.g = resetColor.g; color.b = resetColor.b; color.a = resetColor.a; result = true; } GUILayout.EndHorizontal(); GUILayout.EndArea(); return result; } public static 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; } public static 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 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(); 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}"); } 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 { private static readonly FieldInfo chatUIField = AccessTools.Field(typeof(TextChat), "_chatUI"); private static readonly FieldInfo logViewField = AccessTools.Field(typeof(TextChatVE), "logView"); public static void Notification(string message, long timeoutMs, bool noPrefix = false) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (!((Object)(object)TextChat.Instance == (Object)null)) { TextChatVE val = (TextChatVE)chatUIField.GetValue(TextChat.Instance); ScrollView logView = (ScrollView)logViewField.GetValue(val); Notification(message, noPrefix); VisualElement log = ((VisualElement)logView).ElementAt(((VisualElement)logView).childCount - 1); ((VisualElement)val).schedule.Execute((Action)delegate { ((VisualElement)logView).Remove(log); }).ExecuteLater(timeoutMs); } } public static void Notification(string message, bool noPrefix = false) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) Assembly callingAssembly = Assembly.GetCallingAssembly(); TextChat instance = TextChat.Instance; if (instance != null) { instance.AddLog(new Log((noPrefix ? "" : callingAssembly.FullName.Split(',')[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 { VoipService.Instance.SendTextMessage("[Void Manager]: " + message); } } 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."); } } } public class Tools { private static readonly Dictionary<object, (Action, DateTime)> uniqueTasks = new Dictionary<object, (Action, DateTime)>(); public static void DelayDo(Action action, double delayMs) { DelayDoUnique(new object(), action, delayMs); } public static void DelayDoUnique(object uniqueObject, Action action, double delayMs) { uniqueTasks.Remove(uniqueObject); uniqueTasks.Add(uniqueObject, (action, DateTime.Now.AddMilliseconds(delayMs))); if (uniqueTasks.Count == 1) { Events.Instance.LateUpdate += DoUniqueTasks; } } public static bool CancelDelayDoUnique(object uniqueObject) { return uniqueTasks.Remove(uniqueObject); } private static void DoUniqueTasks(object sender, EventArgs e) { for (int num = uniqueTasks.Count - 1; num >= 0; num--) { KeyValuePair<object, (Action, DateTime)> keyValuePair = uniqueTasks.ElementAt(num); if (keyValuePair.Value.Item2 <= DateTime.Now) { keyValuePair.Value.Item1(); uniqueTasks.Remove(keyValuePair.Key); } } if (uniqueTasks.Count == 0) { Events.Instance.LateUpdate -= DoUniqueTasks; } } } } namespace VoidManager.Progression { internal class ProgressionDisabledGUI : MonoBehaviour { private GameObject PDCanvas; private Rect WindowPos; private static Color invisColor = new Color(0f, 0f, 0f, 0f); private Texture2D Background = GUITools.BuildTexFrom1Color(invisColor); internal static ProgressionDisabledGUI Instance { get; private set; } private void Update() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) WindowPos = new Rect((float)(Screen.width - 200), 0f, 140f, 50f); } private void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown Instance = this; PDCanvas = new GameObject("ModManagerCanvas", new Type[1] { typeof(Canvas) }); Canvas component = PDCanvas.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 1000; ((Component)component).transform.SetAsLastSibling(); Object.DontDestroyOnLoad((Object)(object)PDCanvas); } private void OnGUI() { //IL_0007: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_002e: 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) if (!ProgressionHandler.ProgressionEnabled) { GUI.backgroundColor = invisColor; WindowPos = GUI.Window(999909, WindowPos, new WindowFunction(WindowFunction), "<b><color=#FF3333>Progress Disabled</color></b>"); } } private void WindowFunction(int WindowID) { } } public class ProgressionHandler { private static PropertyInfo ProfileInfo = AccessTools.Property(typeof(PlayerProfile), "Profile"); private static PropertyInfo UnlockedItemsInfo = AccessTools.Property(typeof(PlayerProfile), "UnlockedItems"); private static PropertyInfo PerksInfo = AccessTools.Property(typeof(PlayerProfile), "Perks"); private static PropertyInfo PlayerLoadoutInfo = AccessTools.Property(typeof(PlayerProfile), "PlayerLoadout"); private static PropertyInfo ShipLoadoutsInfo = AccessTools.Property(typeof(PlayerProfile), "ShipLoadouts"); private static PropertyInfo UnseenInfo = AccessTools.Property(typeof(PlayerProfile), "Unseen"); private static PropertyInfo RewardsInfo = AccessTools.Property(typeof(PlayerProfile), "Rewards"); public static bool ProgressionEnabled { get; private set; } = true; public static void DisableProgression(string ModGUID) { BepinPlugin.Log.LogInfo((object)("Recieved progression disable call from " + ModGUID)); Messaging.Echo(ModGUID + " Disabled Progression", !PhotonNetwork.IsMasterClient); InternalDisableProgression(); KickPlayersWithoutDisableProgression(); SendBlockProgression(); } internal static void InternalDisableProgression() { MPModCheckManager.Instance.UpdateHighestLevelOfMPMods(MultiplayerType.All); if (PhotonNetwork.IsMasterClient) { PunSingleton<PhotonService>.Instance.SetCurrentRoomName(PunSingleton<PhotonService>.Instance.GetCurrentRoomName()); } ProgressionEnabled = false; BepinPlugin.Log.LogInfo((object)"Progression Disabled"); } internal static void SendBlockProgression() { //IL_0004: Unknown result type (might be due to invalid IL or missing references) PhotonNetwork.RaiseEvent((byte)95, (object)null, (RaiseEventOptions)null, SendOptions.SendReliable); } internal static void KickPlayersWithoutDisableProgression() { if (!PhotonNetwork.IsMasterClient) { return; } Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (!((Dictionary<object, object>)(object)val.CustomProperties).ContainsKey((object)"Mods")) { Messaging.Echo("Kicking player " + val.NickName + " from session for progression disable while not using Void Manager 1.2.0 or later.", local: false); Messaging.KickMessage("Kicked: Session Progress Disabled", "Detected Void Manager 1.1.8 installed on client. Install latest Void Manager to rejoin session.", val); PhotonNetwork.CloseConnection(val); BepinPlugin.Log.LogMessage((object)("Kicked player " + val.NickName + " from session for Detected Void Manager 1.1.8 while session progress is disabled.")); } } } internal static void EnableProgression() { BepinPlugin.Log.LogInfo((object)"Progression Enabled"); Load(); } private static async void Load() { Messaging.Echo("Working . . . "); PlayerData val = await CloudProfileReader.GetProfile(); ProfileInfo.SetValue(PlayerProfile.Instance, val.Profile); UnlockedItemsInfo.SetValue(PlayerProfile.Instance, val.UnlockedItems); PerksInfo.SetValue(PlayerProfile.Instance, val.Perks); PlayerLoadoutInfo.SetValue(PlayerProfile.Instance, val.PlayerLoadout); ShipLoadoutsInfo.SetValue(PlayerProfile.Instance, val.ShipLoadouts); UnseenInfo.SetValue(PlayerProfile.Instance, val.Unseen); RewardsInfo.SetValue(PlayerProfile.Instance, val.Rewards); Messaging.Echo("Complete."); ProgressionEnabled = true; } internal static void OnPlayerJoin(Player joiningPlayer) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient && !ProgressionEnabled) { if (!((Dictionary<object, object>)(object)joiningPlayer.CustomProperties).ContainsKey((object)"Mods")) { Messaging.Echo("Kicking player " + joiningPlayer.NickName + " from session for using old Void Manager", local: false); Messaging.KickMessage("Kicked: Session Progress Disabled", "Detected Void Manager 1.1.8 installed on client. Install latest Void Manager to rejoin session.", joiningPlayer); PhotonNetwork.CloseConnection(joiningPlayer); BepinPlugin.Log.LogMessage((object)("Kicked player " + joiningPlayer.NickName + " from session for Detected Void Manager 1.1.8 while session progress is disabled.")); } else { RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { joiningPlayer.ActorNumber }; PhotonNetwork.RaiseEvent((byte)95, (object)null, val, SendOptions.SendReliable); } } } internal static void OnHostChange(Player newHost) { if (newHost.IsLocal && !ProgressionEnabled) { Messaging.Echo("New host has progression disabled, disabling progression for others.", local: false); KickPlayersWithoutDisableProgression(); SendBlockProgression(); } } } } namespace VoidManager.Patches { [HarmonyPatch(typeof(PlayerProfileLoader), "Awake")] internal class Initialization { private static MethodInfo PhotonSetupLogging = AccessTools.Method(typeof(PhotonNetwork), "SetupLogging", (Type[])null, (Type[])null); [HarmonyPostfix] public static void PostAwakeInit() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) BepinPlugin.Log.LogInfo((object)"- - - Void Manager Initialization - - -"); ((Object)new GameObject("ModManager", new Type[1] { typeof(GUIMain) })).hideFlags = (HideFlags)61; ((Object)new GameObject("ModList", new Type[1] { typeof(ModListGUI) })).hideFlags = (HideFlags)61; ((Object)new GameObject("ProgressDisabled", new Type[1] { typeof(ProgressionDisabledGUI) })).hideFlags = (HideFlags)61; PluginHandler.DiscoverPlugins(); NetworkedPeerManager.Instance = new NetworkedPeerManager(); MPModCheckManager.Instance = new MPModCheckManager(); LobbyPlayerListManager.Instance = new LobbyPlayerListManager(); ServerSettings photonServerSettings = PhotonNetwork.PhotonServerSettings; if ((Object)(object)photonServerSettings != (Object)null) { photonServerSettings.PunLogging = BepinPlugin.Bindings.PunLoggingSettingLevel.Value; photonServerSettings.AppSettings.NetworkLogging = BepinPlugin.Bindings.PunDebugLogLevel.Value; PhotonSetupLogging.Invoke(null, null); } 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(); } } } [HarmonyPatch(typeof(MatchmakingList), "RoomsUpdated")] internal class MatchmakingListSelectedPatch { private static readonly FieldInfo scrollListField = AccessTools.Field(typeof(MatchmakingList), "scrollList"); private static void Prefix(MatchmakingList __instance, out MatchmakingRoom __state) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown object value = scrollListField.GetValue(__instance); __state = (MatchmakingRoom)AccessTools.Method(value.GetType(), "get_SelectedItem", (Type[])null, (Type[])null).Invoke(value, null); } private static void Postfix(MatchmakingList __instance, MatchmakingRoom __state) { if (__state != null) { object value = scrollListField.GetValue(__instance); List<MatchmakingRoom> source = (List<MatchmakingRoom>)AccessTools.Field(value.GetType(), "source").GetValue(value); MatchmakingRoom val = ((IEnumerable<MatchmakingRoom>)source).FirstOrDefault((Func<MatchmakingRoom, bool>)((MatchmakingRoom room) => room.RoomName == __state.RoomName)); if (val != null) { AccessTools.Method(value.GetType(), "SelectWithoutNotify", (Type[])null, (Type[])null).Invoke(value, new object[1] { val }); } } } } [HarmonyPatch(typeof(CloudLocalProfile), "OnQuit")] internal class CloudLocalProfilePatch { private static bool Prefix() { return ProgressionHandler.ProgressionEnabled; } } [HarmonyPatch(typeof(LocalPlayerProfile), "OnQuit")] internal class LocalPlayerProfilePatch { private static bool Prefix() { return ProgressionHandler.ProgressionEnabled; } } [HarmonyPatch(typeof(CloudSyncController), "Write")] internal class CloudSyncControllerPatch { private static bool Prefix() { return ProgressionHandler.ProgressionEnabled; } } [HarmonyPatch(typeof(GeneralSettings), "Load")] internal class SetDefaultSettingsPatch { private static void Postfix(GeneralSettings __instance) { ((Setting<int>)(object)__instance.JoinModdedGames).SetValue(1, false); } } } namespace VoidManager.MPModChecks { public struct CheckConditions { public MPModDataBlock Mod; public bool HostCheck; public PlayersWithMod PlayersWithMod; public string ClientModVersion; public string HostModVersion; public bool IsMod_Session; public bool HashesMatch; public CheckConditions() { Mod = null; PlayersWithMod = PlayersWithMod.Client; IsMod_Session = false; HostCheck = false; ClientModVersion = string.Empty; HostModVersion = string.Empty; HashesMatch = false; } } public enum PlayersWithMod : byte { Client, Host, Both } public enum CheckFailReason : byte { NoFail, MismatchedVersions, AllClientLacking, AllHostLacking, Session, Custom } public struct FailInfo { public string FailMessage; public CheckFailReason CheckFailReason; internal MPModDataBlock FailingMod; public FailInfo() { CheckFailReason = CheckFailReason.NoFail; FailingMod = null; FailMessage = string.Empty; } } 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, Unmanaged = 4, Client = 8, Host = 14, Session = 20, All = 30 } internal class ModListGUI : MonoBehaviour { private static readonly FieldInfo MatchmakingTerminalField = AccessTools.Field(typeof(MatchmakingTerminal), "matchMakingJoinPanel"); private static readonly FieldInfo MatchListField = AccessTools.Field(typeof(MatchMakingJoinPanel), "MatchList"); private List<MPModDataBlock> mods; private List<LobbyPlayer> LobbyPlayers; private string LastCheckedRoom = string.Empty; internal RoomInfo CurrentRoom; internal TabsRibbon Tabs; private GameObject MLCanvas; private bool GUIActive; private Rect WindowPos; private Vector2 ListScroll = Vector2.zero; internal static ModListGUI Instance { get; private set; } internal ModListGUI() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown Instance = this; MLCanvas = new GameObject("ModListCanvas", new Type[1] { typeof(Canvas) }); Canvas component = MLCanvas.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 1000; ((Component)component).transform.SetAsLastSibling(); Object.DontDestroyOnLoad((Object)(object)MLCanvas); } private void Update() { if (CurrentRoom == null || !((Dictionary<object, object>)(object)CurrentRoom.CustomProperties).ContainsKey((object)"Mods")) { GUIClose(); } else if (Tabs == null || Tabs.ActiveHeader == 0) { GUIOpen(); if (LastCheckedRoom != CurrentRoom.Name) { MPUserDataBlock mPUserDataBlock = NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])CurrentRoom.CustomProperties[(object)"Mods"]); mods = mPUserDataBlock.ModData.Where((MPModDataBlock mod) => (int)mod.MPType > 8).ToList(); mods.Sort(delegate(MPModDataBlock modA, MPModDataBlock modB) { int num = modB.MPType.CompareTo(modA.MPType); return (num != 0) ? num : modA.ModName.CompareTo(modB.ModName); }); if (((Dictionary<object, object>)(object)CurrentRoom.CustomProperties).TryGetValue((object)"plyrs", out object value)) { LobbyPlayers = LobbyPlayerListManager.DeserializePlayerList((byte[])value); } else { LobbyPlayers = new List<LobbyPlayer>(); } LastCheckedRoom = CurrentRoom.Name; GUIOpen(); } } else { GUIClose(); } } private void GUIOpen() { //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) if (!GUIActive) { GUIActive = true; WindowPos = new Rect(0f, (float)Screen.height * 1f / 6f, (float)(Screen.width / 12), (float)Screen.height * 2f / 3f); } } internal void GUIClose() { if (GUIActive) { CurrentRoom = null; LastCheckedRoom = string.Empty; mods = null; GUIActive = false; } } private void OnGUI() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (GUIActive) { GUI.skin = GUIMain.ChangeSkin(); WindowPos = GUI.Window(918107, WindowPos, new WindowFunction(WindowFunction), "<b>Room Info</b>"); } } private void WindowFunction(int windowID) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) if (LobbyPlayers.Count > 0) { GUI.skin.label.alignment = (TextAnchor)4; GUILayout.Label("<b>Players:</b>", Array.Empty<GUILayoutOption>()); GUI.skin.label.alignment = (TextAnchor)3; foreach (LobbyPlayer lobbyPlayer in LobbyPlayers) { string text = ((lobbyPlayer.FavorRank > 0) ? $"<color=orange>{lobbyPlayer.FavorRank}</color>" : lobbyPlayer.Rank.ToString()); GUILayout.Label("- " + lobbyPlayer.Name + " - " + text, Array.Empty<GUILayoutOption>()); } GUILayout.Space(10f); } GUI.skin.label.alignment = (TextAnchor)4; GUILayout.Label("<b>Mod List:</b>", Array.Empty<GUILayoutOption>()); if (mods.Count == 0) { GUILayout.Label("No Mods", Array.Empty<GUILayoutOption>()); return; } ListScroll = GUILayout.BeginScrollView(ListScroll, Array.Empty<GUILayoutOption>()); MultiplayerType mPType = mods[0].MPType; GUILayout.Label(GetMPTypeHeader(mPType) + " Mods:", Array.Empty<GUILayoutOption>()); GUI.skin.label.alignment = (TextAnchor)3; foreach (MPModDataBlock mod in mods) { if (mod.MPType != mPType) { mPType = mod.MPType; GUILayout.Label("", Array.Empty<GUILayoutOption>()); GUI.skin.label.alignment = (TextAnchor)4; GUILayout.Label(GetMPTypeHeader(mPType) + " Mods:", Array.Empty<GUILayoutOption>()); GUI.skin.label.alignment = (TextAnchor)3; } GUILayout.Label("- " + mod.ModName, Array.Empty<GUILayoutOption>()); } GUILayout.EndScrollView(); } private string GetMPTypeHeader(MultiplayerType type) { return type switch { MultiplayerType.Unmanaged => "Unmanaged", MultiplayerType.Client => "Client", MultiplayerType.Host => "<color=#00CC00>Host</color>", MultiplayerType.Session => "<color=#FFFF99>Session</color>", MultiplayerType.All => "<color=#FF3333>Required</color>", _ => "Error - type not found", }; } } [HarmonyPatch(typeof(MatchMakingJoinPanel), "RoomSelected")] internal class OnRoomSelectedPatch { private static void Postfix(MatchmakingRoom room) { if (MatchmakingController.Instance.GetCachedRoomList().TryGetValue(room.RoomId, out var value)) { ModListGUI.Instance.CurrentRoom = value; } } } [HarmonyPatch(typeof(MatchmakingController), "JoinGame")] internal class OnRoomDeselectedPatch { private static void Postfix(RoomJoinStatus __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)__result == 0) { ModListGUI.Instance.Tabs = null; ModListGUI.Instance.GUIClose(); } } } [HarmonyPatch(typeof(MatchMakingMenu), "OnExit")] internal class LeftMatchMakingMenuPatch { private static void Postfix() { ModListGUI.Instance.GUIClose(); } } [HarmonyPatch(typeof(TerminalScreen), "SetPanelActive")] internal class LeftMatchmakingTerminalPatch { private static readonly FieldInfo tabsField = AccessTools.Field(typeof(MatchmakingTerminal), "tabs"); private static void Postfix(TerminalScreen __instance, bool active) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (active) { GameObject gameObject = ((Component)__instance).gameObject; if (((Object)gameObject).name == "MatchmakingTerminal") { ModListGUI.Instance.Tabs = (TabsRibbon)tabsField.GetValue(gameObject.GetComponent<MatchmakingTerminal>()); } } else { ModListGUI.Instance.Tabs = null; ModListGUI.Instance.GUIClose(); } } } public class MPModCheckManager { internal static InRoomCallbacks RoomCallbacksClass; private MPModDataBlock[] MyModList; internal string LastModCheckFailReason; public MultiplayerType HighestLevelOfMPMods { get; private set; } = MultiplayerType.Client; internal byte[] MyModListData { get; private set; } public static MPModCheckManager Instance { get; internal set; } internal MPModCheckManager() { UpdateMyModList(); BuildRoomProperties(); } internal void BuildRoomProperties() { MyModListData = NetworkedPeerManager.SerializeHashlessMPUserData(MyModList); } internal void UpdateLobbyProperties() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0071: Expected O, but got Unknown if (!PhotonNetwork.IsMasterClient) { return; } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { BepinPlugin.Log.LogWarning((object)"Attempted to update lobby properties while room was null"); return; } string[] array = currentRoom.PropertiesListedInLobby; if (!((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).ContainsKey((object)"Mods")) { array = array.Append("Mods").ToArray(); currentRoom.SetPropertiesListedInLobby(array); } Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"Mods", (object)MyModListData); currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); if (!array.Contains("plyrs")) { currentRoom.SetPropertiesListedInLobby(array.Append("plyrs").ToArray()); } LobbyPlayerListManager.Instance.UpdateLobbyPlayers(); } internal void UpdateHighestLevelOfMPMods(MultiplayerType MT) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) switch (MT) { case MultiplayerType.All: if ((int)MT > (int)HighestLevelOfMPMods) { ModdingUtils.SessionModdingType = (ModdingType)2; HighestLevelOfMPMods = MT; BepinPlugin.Log.LogInfo((object)("Incrementing HighestLevelOfMPMods to " + MT)); } break; case MultiplayerType.Session: if ((int)MT > (int)HighestLevelOfMPMods) { ModdingUtils.SessionModdingType = (ModdingType)2; HighestLevelOfMPMods = MT; BepinPlugin.Log.LogInfo((object)("Incrementing HighestLevelOfMPMods to " + MT)); } break; } } public static bool RoomIsModded(RoomInfo room) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 if (!((Dictionary<object, object>)(object)room.CustomProperties).ContainsKey((object)"Mods")) { if (((Dictionary<object, object>)(object)room.CustomProperties).TryGetValue((object)"R_Mod", out object value)) { return (int)(ModdingType)value == 2; } return false; } return true; } public static bool RoomIsModded(Hashtable roomProperties) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 if (!((Dictionary<object, object>)(object)roomProperties).ContainsKey((object)"Mods")) { if (((Dictionary<object, object>)(object)roomProperties).TryGetValue((object)"R_Mod", out object value)) { return (int)(ModdingType)value == 2; } return false; } return true; } 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 == "VoidCrewModdingTeam.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 = array2.Where((MPModDataBlock mod) => mod != null).ToArray(); MyModList = array2; stopwatch.Stop(); BepinPlugin.Log.LogInfo((object)("Finished Building MyModList, time elapsted: " + stopwatch.ElapsedMilliseconds + " ms")); BepinPlugin.Log.LogInfo((object)("MyModList:\n" + NetworkedPeerManager.GetModListAsString(MyModList) + "\n")); } internal void JoinedRoom() { if (PhotonNetwork.IsMasterClient) { return; } if (!Instance.ModChecksClientside(((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties)) { BepinPlugin.Log.LogInfo((object)"Disconnecting from Room"); ((AbstractStateMachine<GameStateMachine>)(object)Singleton<GameStateMachine>.Instance).ChangeState<GSPhotonDisconnected>(); return; } NetworkedPeerManager.SendModlistToHost(MyModList); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (BepinPlugin.Bindings.DebugMode.Value) { if (((Dictionary<object, object>)(object)val.CustomProperties).TryGetValue((object)"Mods", out object value)) { BepinPlugin.Log.LogInfo((object)("Found mod info in player custom props " + val.NickName)); BepinPlugin.Log.LogInfo((object)NetworkedPeerManager.GetModListAsString(NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])value).ModData)); } else { BepinPlugin.Log.LogInfo((object)("Didn't Found mod info in player custom props " + val.NickName)); } } if (!NetworkedPeerManager.Instance.SetNetworkedPeerMods(val) && !val.IsMasterClient) { NetworkedPeerManager.SendModlistToClient(MyModList, val); } } } internal void PlayerJoined(Player JoiningPlayer) { if (PhotonNetwork.IsMasterClient) { ((MonoBehaviour)PunSingleton<PhotonService>.Instance).StartCoroutine(PlayerJoinedChecks(JoiningPlayer)); } else if (!NetworkedPeerManager.Instance.SetNetworkedPeerMods(JoiningPlayer)) { NetworkedPeerManager.SendModlistToClient(MyModList, JoiningPlayer); } } internal static IEnumerator PlayerJoinedChecks(Player JoiningPlayer) { for (int i = 0; i < 50; i++) { yield return (object)new WaitForSeconds(0.2f); if (NetworkedPeerManager.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.\n" + NetworkedPeerManager.GetModListAsStringForChat(Instance.MyModList.Where((MPModDataBlock MDB) => MDB.MPType == MultiplayerType.All).ToArray()), local: false); PhotonNetwork.CloseConnection(JoiningPlayer); } else { Events.Instance.OnHostVerifiedClient(JoiningPlayer); } } public static bool IsMod_Session() { return ModdingUtils.IsCurrentSessionModded(); } internal bool ModChecksClientside(Hashtable RoomProperties, bool inRoom = true) { if (inRoom && PhotonNetwork.IsMasterClient) { return true; } LastModCheckFailReason = string.Empty; BepinPlugin.Log.LogMessage((object)string.Format("Starting Clientside mod checks for room: {0}", RoomProperties[(object)"R_Na"])); bool flag = RoomIsModded(RoomProperties); if (!flag) { if ((int)HighestLevelOfMPMods >= 20) { LastModCheckFailReason = "Host has no mods, but client has Mod_Session or higher mods." + NetworkedPeerManager.GetModListAsString(Instance.MyModList.Where((MPModDataBlock MDB) => (int)MDB.MPType >= 20).ToArray()); 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; } Dictionary<string, CheckConditions> dictionary = new Dictionary<string, CheckConditions>(); MPUserDataBlock mPUserDataBlock = NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])RoomProperties[(object)"Mods"]); MPModDataBlock[] modData = mPUserDataBlock.ModData; BepinPlugin.Log.LogMessage((object)("VoidManager versions - Host: " + mPUserDataBlock.VMVersion + " Client: 1.2.2")); MPModDataBlock[] myModList = MyModList; foreach (MPModDataBlock mPModDataBlock in myModList) { CheckConditions value = new CheckConditions(); value.IsMod_Session = flag; value.HostCheck = false; value.PlayersWithMod = PlayersWithMod.Client; value.Mod = mPModDataBlock; value.ClientModVersion = mPModDataBlock.Version; dictionary.Add(mPModDataBlock.ModGUID, value); } MPModDataBlock[] array = modData; foreach (MPModDataBlock mPModDataBlock2 in array) { if (dictionary.TryGetValue(mPModDataBlock2.ModGUID, out var value2)) { value2.HostModVersion = mPModDataBlock2.Version; value2.PlayersWithMod = PlayersWithMod.Both; dictionary[mPModDataBlock2.ModGUID] = value2; continue; } value2 = new CheckConditions(); value2.IsMod_Session = flag; value2.PlayersWithMod = PlayersWithMod.Host; value2.HostCheck = false; value2.Mod = mPModDataBlock2; value2.HostModVersion = mPModDataBlock2.Version; dictionary.Add(mPModDataBlock2.ModGUID, value2); } List<FailInfo> list = new List<FailInfo>(); List<FailInfo> list2 = new List<FailInfo>(); List<FailInfo> list3 = new List<FailInfo>(); List<FailInfo> list4 = new List<FailInfo>(); List<FailInfo> list5 = new List<FailInfo>(); foreach (CheckConditions value3 in dictionary.Values) { FailInfo item = CheckMod(value3); switch (item.CheckFailReason) { case CheckFailReason.Session: list.Add(item); break; case CheckFailReason.MismatchedVersions: list2.Add(item); break; case CheckFailReason.AllClientLacking: list3.Add(item); break; case CheckFailReason.AllHostLacking: list4.Add(item); break; case CheckFailReason.Custom: list5.Add(item); break; } } string text = string.Empty; if (list.Count > 0) { text += "The following mods require rooms marked as Mod_Session:\n"; foreach (FailInfo item2 in list) { text = text + item2.FailingMod.ModName + "\n"; } } if (list2.Count > 0) { text += "The following mods have mismatched versions:\n"; foreach (FailInfo item3 in list2) { text = text + item3.FailingMod.ModName + "\n"; } } if (list3.Count > 0) { text += "The following mods are required to join the session:\n"; foreach (FailInfo item4 in list3) { text = text + item4.FailingMod.ModName + "\n"; } } if (list4.Count > 0) { text += "The following mods must be uninstalled to join the session:"; foreach (FailInfo item5 in list4) { text = text + "\n" + item5.FailingMod.ModName; } } if (text != string.Empty) { if (inRoom) { KickMessagePatches.KickTitle = "Disconnected: Incompatable mods"; 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) { if (!PhotonNetwork.IsMasterClient) { return; } MPUserDataBlock networkedPeerMods = NetworkedPeerManager.Instance.GetNetworkedPeerMods(joiningPlayer); MPModDataBlock[] modData = networkedPeerMods.ModData; if (BepinPlugin.Bindings.DebugMode.Value) { BepinPlugin.Log.LogInfo((object)("Host checking user mod list\n" + NetworkedPeerManager.GetModListAsString(modData))); } if (BepinPlugin.Bindings.DebugMode.Value) { BepinPlugin.Log.LogInfo((object)("Host mod list:\n" + NetworkedPeerManager.GetModListAsString(MyModList))); } Dictionary<string, CheckConditions> dictionary = new Dictionary<string, CheckConditions>(); bool isMod_Session = IsMod_Session(); MPModDataBlock[] myModList = MyModList; foreach (MPModDataBlock mPModDataBlock in myModList) { CheckConditions value = new CheckConditions(); value.IsMod_Session = isMod_Session; value.HostCheck = true; value.PlayersWithMod = PlayersWithMod.Host; value.Mod = mPModDataBlock; value.HostModVersion = mPModDataBlock.Version; dictionary.Add(mPModDataBlock.ModGUID, value); } MPModDataBlock[] array = modData; foreach (MPModDataBlock mPModDataBlock2 in array) { if (dictionary.TryGetValue(mPModDataBlock2.ModGUID, out var value2)) { if (BepinPlugin.Bindings.DebugMode.Value) { BepinPlugin.Log.LogInfo((object)("Mod '" + mPModDataBlock2.ModName + "' Matched with Client Mod")); } value2.ClientModVersion = mPModDataBlock2.Version; value2.PlayersWithMod = PlayersWithMod.Both; value2.HashesMatch = mPModDataBlock2.Hash.SequenceEqual(value2.Mod.Hash); dictionary[mPModDataBlock2.ModGUID] = value2; } else { value2 = new CheckConditions(); value2.IsMod_Session = isMod_Session; value2.PlayersWithMod = PlayersWithMod.Client; value2.HostCheck = true; value2.Mod = mPModDataBlock2; value2.ClientModVersion = mPModDataBlock2.Version; dictionary.Add(mPModDataBlock2.ModGUID, value2); } } List<FailInfo> list = new List<FailInfo>(); List<FailInfo> list2 = new List<FailInfo>(); List<FailInfo> list3 = new List<FailInfo>(); List<FailInfo> list4 = new List<FailInfo>(); List<FailInfo> list5 = new List<FailInfo>(); foreach (CheckConditions value3 in dictionary.Values) { FailInfo item = CheckMod(value3); switch (item.CheckFailReason) { case CheckFailReason.Session: list.Add(item); break; case CheckFailReason.MismatchedVersions: list2.Add(item); break; case CheckFailReason.AllClientLacking: list3.Add(item); break; case CheckFailReason.AllHostLacking: list4.Add(item); break; case CheckFailReason.Custom: list5.Add(item); break; } } string text = string.Empty; if (list.Count > 0) { text += "The following mods require rooms marked as Mod_Session\n"; foreach (FailInfo item2 in list) { text = text + item2.FailingMod.ModName + "\n"; } } if (list2.Count > 0) { text += "The following mods have mismatched versions:\n"; foreach (FailInfo item3 in list2) { text = text + item3.FailingMod.ModName + "\n"; } } if (list3.Count > 0) { text += "The following mods are required to join the session:\n"; foreach (FailInfo item4 in list3) { text = text + item4.FailingMod.ModName + "\n"; } } if (list4.Count > 0) { text += "The following mods must be uninstalled to join the session:"; foreach (FailInfo item5 in list4) { text = text + "\n" + item5.FailingMod.ModName; } } if (text != string.Empty) { Messaging.Echo("Kicking player " + joiningPlayer.NickName + " from session for incompatable mods.\n" + text, local: false); Messaging.KickMessage("Kicked: Incompatable mods", 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.OnHostVerifiedClient(joiningPlayer); } } internal FailInfo CheckMod(CheckConditions Conditions) { FailInfo result = new FailInfo(); result.FailingMod = Conditions.Mod; switch (Conditions.Mod.MPType) { case MultiplayerType.All: if (Conditions.PlayersWithMod == PlayersWithMod.Both) { if (Conditions.HostModVersion == Conditions.ClientModVersion) { if (Conditions.HashesMatch || !Conditions.HostCheck) { result.CheckFailReason = CheckFailReason.NoFail; break; } BepinPlugin.Log.LogMessage((object)("Mismatched mod hash - " + Conditions.Mod.ModName)); } else { BepinPlugin.Log.LogMessage((object)("Mismatched mod version - Client:" + Conditions.Mod.ModName + "-" + Conditions.ClientModVersion + ", Host:" + Conditions.HostModVersion)); } result.CheckFailReason = CheckFailReason.MismatchedVersions; } else if (Conditions.PlayersWithMod == PlayersWithMod.Client) { result.CheckFailReason = CheckFailReason.AllHostLacking; BepinPlugin.Log.LogMessage((object)("Host is missing the required mod '" + Conditions.Mod.ModName + "'")); } else { result.CheckFailReason = CheckFailReason.AllClientLacking; BepinPlugin.Log.LogMessage((object)("Client is missing the required mod '" + Conditions.Mod.ModName + "'")); } break; case MultiplayerType.Session: if (Conditions.IsMod_Session) { result.CheckFailReason = CheckFailReason.NoFail; break; } BepinPlugin.Log.LogMessage((object)"User attempting to join session with MPType.Session mod."); result.CheckFailReason = CheckFailReason.Session; break; case MultiplayerType.Client: case MultiplayerType.Host: result.CheckFailReason = CheckFailReason.NoFail; break; } return result; } } public class NetworkedPeerManager { internal Dictionary<Player, MPUserDataBlock> NetworkedPeersModLists = new Dictionary<Player, MPUserDataBlock>(); public static NetworkedPeerManager Instance { get; internal set; } public bool IsHostModded() { return GetNetworkedPeerModlistExists(PhotonNetwork.MasterClient); } public MPUserDataBlock GetHostModList() { if (((Dictionary<object, object>)(object)PhotonNetwork.MasterClient.CustomProperties).TryGetValue((object)"Mods", out object value)) { return DeserializeHashlessMPUserData((byte[])value); } if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"Mods", out object value2)) { return DeserializeHashlessMPUserData((byte[])value2); } return null; } public MPUserDataBlock GetNetworkedPeerMods(Player Player) { if (NetworkedPeersModLists.TryGetValue(Player, out var value)) { return value; } if (((Dictionary<object, object>)(object)Player.CustomProperties).TryGetValue((object)"Mods", out object value2)) { MPUserDataBlock value3 = DeserializeHashlessMPUserData((byte[])value2); NetworkedPeersModLists[Player] = value3; 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; } internal void SetNetworkedPeerMods(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")); NetworkedPeersModLists[Player] = modList; Events.Instance.OnClientModlistRecieved(Player); } internal bool SetNetworkedPeerMods(Player Player) { if (!PhotonNetwork.IsMasterClient && ((Dictionary<object, object>)(object)Player.CustomProperties).TryGetValue((object)"Mods", out object value)) { NetworkedPeersModLists[Player] = DeserializeHashlessMPUserData((byte[])value); Events.Instance.OnClientModlistRecieved(Player); return true; } return false; } internal void ClearAllNetworkedPeerMods() { NetworkedPeersModLists.Clear(); } public bool GetNetworkedPeerModlistExists(Player Player) { return NetworkedPeersModLists.ContainsKey(Player); } internal static void SendModlistToClient(MPModDataBlock[] Data, Player Player) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!((Dictionary<object, object>)(object)PhotonNetwork.MasterClient.CustomProperties).ContainsKey((object)"Mods") && !Player.IsLocal) { object[] obj = new object[2] { false, SerializeHashlessMPUserData(Data) }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { Player.ActorNumber }; PhotonNetwork.RaiseEvent((byte)99, (object)obj, val, SendOptions.SendReliable); } } internal static void SendModlistToHost(MPModDataBlock[] Data) { //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(Data) }, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); } } internal static void SendModListToOthers(MPModDataBlock[] Data) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!((Dictionary<object, object>)(object)PhotonNetwork.MasterClient.CustomProperties).ContainsKey((object)"Mods")) { BepinPlugin.Log.LogMessage((object)"sending others"); PhotonNetwork.RaiseEvent((byte)99, (object)new object[2] { false, SerializeHashlessMPUserData(Data) }, (RaiseEventOptions)null, SendOptions.SendReliable); } } internal void LeftRoom() { Instance.ClearAllNetworkedPeerMods(); } internal void PlayerLeftRoom(Player leavingPlayer) { NetworkedPeersModLists.Remove(leavingPlayer); } public static string GetModListAsString(MPModDataBlock[] ModDatas) { string text = string.Empty; foreach (MPModDataBlock mPModDataBlock in ModDatas) { text = text + "\n - " + mPModDataBlock.ModName + " " + mPModDataBlock.Version; } return text; } public static string GetModListAsStringForChat(MPModDataBlock[] ModDatas) { string text = string.Empty; bool flag = true; foreach (MPModDataBlock mPModDataBlock in ModDatas) { if (flag) { flag = false; text = text + " - " + mPModDataBlock.ModName + " " + mPModDataBlock.Version; } else { text = text + "\n - " + mPModDataBlock.ModName + " " + mPModDataBlock.Version; } } return text; } public static byte[] SerializeHashlessMPUserData(MPModDataBlock[] Data) { MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write("1.2.2"); binaryWriter.Write(Data.Length); foreach (MPModDataBlock mPModDataBlock in Data) { 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 static byte[] SerializeHashfullMPUserData(MPModDataBlock[] Data) { MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write("1.2.2"); binaryWriter.Write(Data.Length); foreach (MPModDataBlock mPModDataBlock in Data) { 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; } } } } namespace VoidManager.MPModChecks.Patches { [HarmonyPatch(typeof(PhotonService), "SetCommonPlayerProperties")] internal class SetLocalPlayerPropertiesPatch { private static void Postfix() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown Player localPlayer = PhotonNetwork.LocalPlayer; Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"Mods", (object)MPModCheckManager.Instance.MyModListData); localPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); } } [HarmonyPatch(typeof(PhotonService))] internal class HostGameNamePatch { [HarmonyPatch("SetCurrentRoomName")] private static void Prefix(ref string name) { name = SetGameName(name); } [HarmonyPatch("PhotonCreateRoom")] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown List<CodeInstruction> targetSequence = new List<CodeInstruction> { new CodeInstruction(OpCodes.Ldstr, (object)" Room"), new CodeInstruction(OpCodes.Call, (object)null) }; List<CodeInstruction> list = new List<CodeInstruction>(); list.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HostGameNamePatch), "SetGameName", (Type[])null, (Type[])null))); List<CodeInstruction> patchSequence = list; return HarmonyHelpers.PatchBySequence(instructions, targetSequence, patchSequence, HarmonyHelpers.PatchMode.AFTER, HarmonyHelpers.CheckMode.NONNULL); } public static string SetGameName(string name) { if (MPModCheckManager.Instance.HighestLevelOfMPMods == MultiplayerType.All && !name.StartsWith("[Mods Required]", StringComparison.CurrentCultureIgnoreCase)) { return "[Mods Required] " + name; } return name; } } 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" + KickMessage)); MenuScreenController.Instance.ShowMessagePopup(KickTitle, KickMessage); KickTitle = null; KickMessage = null; } } } internal static string KickTitle; internal static string KickMessage; } [HarmonyPatch(typeof(MatchmakingList), "BindItem")] internal class ModdedRoomTagPatch { public const string ModSessionString = "<b><color=#ff8000>[mod_session] </color></b>"; public const int MSSLength = 44; public const string ModLocalString = "<b><color=#FFD700>[mod_local] </color></b>"; public const int MSLLength = 42; public const string ModsRequiredString = "[Mods Required]"; public static readonly string ModsRequiredLobbyListString = "<b><color=#ff8000>[mod_session] </color></b>[Mods Required]"; private const string RedM = "<b><color=#FF3333>[M]</color></b> "; private const string YellowM = "<b><color=#FFFF99>[M]</color></b> "; private const string GreenM = "<b><color=#00CC00>[M]</color></b> "; [HarmonyPostfix] private static void ModdedRoomPatch(VisualElement item, MatchmakingRoom room) { TextElement val = UQueryExtensions.Q<TextElement>(item, "RoomName", new string[2]); if (val.text.StartsWith(ModsRequiredLobbyListString, StringComparison.CurrentCultureIgnoreCase)) { val.text = val.text.Replace(ModsRequiredLobbyListString, "<b><color=#FF3333>[M]</color></b> "); } else if (val.text.StartsWith("<b><color=#ff8000>[mod_session] </color></b>", StringComparison.CurrentCultureIgnoreCase)) { val.text = val.text.Replace("<b><color=#ff8000>[mod_session] </color></b>", "<b><color=#FFFF99>[M]</color></b> "); } else if (val.text.StartsWith("<b><color=#FFD700>[mod_local] </color></b>", StringComparison.CurrentCult