Decompiled source of LobbyControl Experimental v5.6.0
BepInEx/plugins/LobbyControl.dll
Decompiled a month 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.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using System.Timers; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using HarmonyLib.Public.Patching; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using LobbyCompatibility.Enums; using LobbyCompatibility.Features; using LobbyControl.API; using LobbyControl.Dependency; using LobbyControl.Networking; using LobbyControl.Patches; using LobbyControl.PopUp; using LobbyControl.TerminalCommands; using LobbyControl.Utils; using LobbyControl.Utils.IL; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using MonoMod.RuntimeDetour; using MonoMod.Utils; using Steamworks; using Steamworks.Data; using TMPro; using Unity.Collections; using Unity.Netcode; using Unity.Netcode.Transports.UTP; using UnityEngine; using UnityEngine.Pool; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: AssemblyCompany("mattymatty")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.5.6")] [assembly: AssemblyInformationalVersion("2.5.6+62ddc06d9bbf6a4d6aceee8e57b1b25d40cb621f")] [assembly: AssemblyProduct("LobbyControl")] [assembly: AssemblyTitle("LobbyControl - Plugin")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.5.6.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] internal sealed class IsUnmanagedAttribute : Attribute { } [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 LobbyControl { [BepInPlugin("mattymatty.LobbyControl", "LobbyControl", "2.5.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] internal class LobbyControl : BaseUnityPlugin { internal static class PluginConfig { internal static class SteamLobby { internal static ConfigEntry<bool> AutoLobby; } internal static class SaveLimit { internal static ConfigEntry<bool> Enabled; } internal static class LogSpam { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> CalculatePolygonPath; internal static ConfigEntry<bool> AudioSpatializer; } internal static class JoinQueue { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> ConnectionTimeout; internal static ConfigEntry<int> ConnectionDelay; internal static ConfigEntry<bool> TimeoutPopup; internal static ConfigEntry<bool> ConnectionPopup; } internal static class Networking { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> SyncRadarNames; internal static ConfigEntry<bool> ResetPlayerValues; } internal static void Init(BaseUnityPlugin plugin) { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown ConfigFile config = plugin.Config; config.SaveOnConfigSet = false; SaveLimit.Enabled = config.Bind<bool>("SaveLimit", "enabled", true, "remove the limit to the amount of items that can be saved"); SteamLobby.AutoLobby = config.Bind<bool>("SteamLobby", "auto_lobby", false, "automatically reopen the lobby as soon as you reach orbit"); LogSpam.Enabled = config.Bind<bool>("LogSpam", "enabled", true, "prevent some annoying log spam"); LogSpam.CalculatePolygonPath = config.Bind<bool>("LogSpam", "CalculatePolygonPath", true, "stop pathfinding for dead Enemies"); LogSpam.AudioSpatializer = config.Bind<bool>("LogSpam", "audio_spatializer", true, "disable audio spatialization as there is not spatialization plugin"); JoinQueue.Enabled = config.Bind<bool>("JoinQueue", "enabled", true, "handle joining players as a queue instead of at the same time"); JoinQueue.ConnectionTimeout = config.Bind<int>("JoinQueue", "connection_timeout_ms", 20000, new ConfigDescription("After how much time discard a hanging connection", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10000, int.MaxValue), Array.Empty<object>())); JoinQueue.ConnectionDelay = config.Bind<int>("JoinQueue", "connection_delay_ms", 2000, new ConfigDescription("Delay between each successful connection", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, int.MaxValue), Array.Empty<object>())); JoinQueue.TimeoutPopup = config.Bind<bool>("JoinQueue", "timeout_notification", true, "show a popup when a client fails to join before the timeout"); JoinQueue.ConnectionPopup = config.Bind<bool>("JoinQueue", "connection_notification", false, "show a popup when a client tries to join"); Networking.Enabled = config.Bind<bool>("Networking", "enabled", true, "handle extra actions requested by host"); Networking.SyncRadarNames = config.Bind<bool>("Networking", "sync_radar_names", false, "allow host to reorder radar names to align clients\nWARNING: all clients need to have the mod installed or desyncs might will happen"); Networking.ResetPlayerValues = config.Bind<bool>("Networking", "reset_player_values", true, "allow host to force clients to reset most fields of a playerObject ( fix for invisible players )"); JoinQueue.ConnectionTimeout.SettingChanged += delegate { NetworkManager singleton = NetworkManager.Singleton; if (singleton != null) { singleton.NetworkConfig.ClientConnectionBufferTimeout = JoinQueue.ConnectionTimeout.Value / 1000 * 4; } }; if (LethalConfigProxy.Enabled) { LethalConfigProxy.AddConfig(SaveLimit.Enabled); LethalConfigProxy.AddConfig(SteamLobby.AutoLobby); LethalConfigProxy.AddConfig(LogSpam.Enabled); LethalConfigProxy.AddConfig(LogSpam.CalculatePolygonPath); LethalConfigProxy.AddConfig(LogSpam.AudioSpatializer); LethalConfigProxy.AddConfig(JoinQueue.Enabled); LethalConfigProxy.AddConfig(JoinQueue.ConnectionTimeout); LethalConfigProxy.AddConfig(JoinQueue.ConnectionDelay); LethalConfigProxy.AddConfig(JoinQueue.TimeoutPopup); LethalConfigProxy.AddConfig(JoinQueue.ConnectionPopup); LethalConfigProxy.AddConfig(Networking.Enabled); LethalConfigProxy.AddConfig(Networking.SyncRadarNames); LethalConfigProxy.AddConfig(Networking.ResetPlayerValues); } PropertyInfo property = ((object)config).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic); Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(config, null); dictionary.Clear(); config.Save(); config.SaveOnConfigSet = true; } } public const string GUID = "mattymatty.LobbyControl"; public const string NAME = "LobbyControl"; public const string VERSION = "2.5.6"; public static LobbyControl Instance; internal static ManualLogSource Log; internal static readonly Harmony Harmony = new Harmony("mattymatty.LobbyControl"); public static bool CanModifyLobby = true; public static bool CanSave = true; public static bool AutoSaveEnabled = true; public static readonly List<Hook> Hooks = new List<Hook>(); private static readonly string[] IncompatibleGUIDs = new string[4] { "com.github.tinyhoot.ShipLobby", "twig.latecompany", "McBowie.VeryLateCompany", "com.potatoepet.AdvancedCompany" }; internal static readonly List<PluginInfo> FoundIncompatibilities = new List<PluginInfo>(); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; Instance = this; try { PluginInfo[] array = Chainloader.PluginInfos.Values.Where((PluginInfo p) => IncompatibleGUIDs.Contains(p.Metadata.GUID)).ToArray(); if (array.Length != 0) { StringBuilder stringBuilder = new StringBuilder("LOBBY CONTROL was DISABLED!\nIncompatible:"); FoundIncompatibilities.AddRange(array); PluginInfo[] array2 = array; foreach (PluginInfo val in array2) { Log.LogWarning((object)(val.Metadata.Name + " is incompatible!")); stringBuilder.Append("\n").Append(val.Metadata.Name); } Log.LogError((object)$"{array.Length} incompatible mods found! Disabling!"); PopUpPatch.PopUps.Add(("LC_Incompatibility", stringBuilder.ToString())); Harmony.PatchAll(typeof(PopUpPatch)); return; } if (LobbyCompatibilityChecker.Enabled) { LobbyCompatibilityChecker.Init("mattymatty.LobbyControl", Version.Parse("2.5.6"), 1, 2); } Log.LogInfo((object)"Initializing Configs"); PluginConfig.Init((BaseUnityPlugin)(object)this); CommandManager.Initialize(); LobbyCommand.Init(); Log.LogInfo((object)"Patching Methods"); Harmony.PatchAll(typeof(PopUpPatch)); Harmony.PatchAll(typeof(JoinQueuePatches)); JoinQueuePatches.Init(); Harmony.PatchAll(typeof(LateJoinPatches)); Harmony.PatchAll(typeof(LimitPatcher)); Harmony.PatchAll(typeof(LobbyPatcher)); Harmony.PatchAll(typeof(LogSpamPatches)); Harmony.PatchAll(typeof(NetworkManagerPatch)); Harmony.PatchAll(typeof(SavePatches)); Harmony.PatchAll(typeof(TerminalPatch)); Log.LogInfo((object)"LobbyControl v2.5.6 Loaded!"); } catch (Exception ex) { Log.LogError((object)("Exception while initializing: \n" + ex)); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "mattymatty.LobbyControl"; public const string PLUGIN_NAME = "LobbyControl"; public const string PLUGIN_VERSION = "2.5.6"; } } namespace LobbyControl.Utils { public static class HudUtils { [CompilerGenerated] private sealed class <>c__DisplayClass0_0 { public bool isWarning; internal bool <ShowMessageAfterDelay>b__0() { return HUDManager.Instance.CanTipDisplay(isWarning, false, (string)null); } } [CompilerGenerated] private sealed class <ShowMessageAfterDelay>d__0 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public bool isWarning; public float delay; private <>c__DisplayClass0_0 <>8__1; public string title; public string text; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowMessageAfterDelay>d__0(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass0_0(); <>8__1.isWarning = isWarning; if (delay > 0f) { <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; } goto IL_006c; case 1: <>1__state = -1; goto IL_006c; case 2: { <>1__state = -1; HUDManager.Instance.DisplayTip(title, text, <>8__1.isWarning, false, "LC_Tip1"); return false; } IL_006c: <>2__current = (object)new WaitUntil((Func<bool>)(() => HUDManager.Instance.CanTipDisplay(<>8__1.isWarning, false, (string)null))); <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ShowTipAfterDelay>d__1 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float delay; public string title; public string text; public string saveKey; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowTipAfterDelay>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (delay > 0f) { <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; } goto IL_0050; case 1: <>1__state = -1; goto IL_0050; case 2: { <>1__state = -1; HUDManager.Instance.DisplayTip(title, text, false, true, saveKey); return false; } IL_0050: <>2__current = (object)new WaitUntil((Func<bool>)(() => HUDManager.Instance.CanTipDisplay(false, false, (string)null))); <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [IteratorStateMachine(typeof(<ShowMessageAfterDelay>d__0))] internal static IEnumerator ShowMessageAfterDelay(string title, string text, float delay = 0f, bool isWarning = false) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ShowMessageAfterDelay>d__0(0) { title = title, text = text, delay = delay, isWarning = isWarning }; } [IteratorStateMachine(typeof(<ShowTipAfterDelay>d__1))] internal static IEnumerator ShowTipAfterDelay(string title, string text, float delay, string saveKey) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ShowTipAfterDelay>d__1(0) { title = title, text = text, delay = delay, saveKey = saveKey }; } } public static class RPCUtils { private static readonly MethodInfo BeginSendClientRpc = AccessTools.Method(typeof(NetworkBehaviour), "__beginSendClientRpc", (Type[])null, (Type[])null); private static readonly MethodInfo BeginSendServerRpc = AccessTools.Method(typeof(NetworkBehaviour), "__beginSendServerRpc", (Type[])null, (Type[])null); internal static bool TryGetRpcID(MethodInfo methodInfo, out uint rpcID) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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) Collection<Instruction> instructions = PatchManager.GetMethodPatcher((MethodBase)methodInfo).CopyOriginal().Definition.Body.Instructions; rpcID = 0u; for (int i = 0; i < instructions.Count; i++) { if (instructions[i].OpCode == OpCodes.Ldc_I4 && instructions[i - 1].OpCode == OpCodes.Ldarg_0) { rpcID = (uint)(int)instructions[i].Operand; } if (!(instructions[i].OpCode != OpCodes.Call)) { object operand = instructions[i].Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val != null && (Extensions.Is((MemberReference)(object)val, (MemberInfo)BeginSendClientRpc) || Extensions.Is((MemberReference)(object)val, (MemberInfo)BeginSendServerRpc))) { LobbyControl.Log.LogDebug((object)$"Rpc Id found for {methodInfo.Name}: {rpcID}U"); return true; } } } LobbyControl.Log.LogFatal((object)("Cannot find Rpc ID for " + methodInfo.Name)); return false; } } } namespace LobbyControl.Utils.IL { internal class ILInjector { [CompilerGenerated] private sealed class <GetRelativeInstructions>d__34 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IEnumerator, IDisposable { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; public ILInjector <>4__this; private int offset; public int <>3__offset; private int size; public int <>3__size; private int <i>5__2; CodeInstruction IEnumerator<CodeInstruction>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetRelativeInstructions>d__34(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; ILInjector iLInjector = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <i>5__2 = 0; break; case 1: <>1__state = -1; <i>5__2++; break; } if (<i>5__2 < size) { <>2__current = iLInjector.instructions[iLInjector.index + offset + <i>5__2]; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator() { <GetRelativeInstructions>d__34 <GetRelativeInstructions>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetRelativeInstructions>d__ = this; } else { <GetRelativeInstructions>d__ = new <GetRelativeInstructions>d__34(0) { <>4__this = <>4__this }; } <GetRelativeInstructions>d__.offset = <>3__offset; <GetRelativeInstructions>d__.size = <>3__size; return <GetRelativeInstructions>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<CodeInstruction>)this).GetEnumerator(); } } private const string INVALID = "Injector is invalid"; private List<CodeInstruction> instructions = instructions.ToList(); private ILGenerator generator; private int index; private int matchEnd; public int Index { get { return index; } set { index = value; } } public bool IsValid { get { if (instructions != null) { return IsIndexValid(index); } return false; } } public CodeInstruction Instruction { get { if (!IsIndexInRange(index)) { return null; } return instructions[index]; } set { if (!IsIndexInRange(index)) { throw new InvalidOperationException($"Current index {index} is out of range of instruction count {instructions.Count}"); } instructions[index] = value; } } public CodeInstruction LastMatchedInstruction { get { int num = matchEnd - 1; if (!IsIndexInRange(num)) { return null; } return instructions[num]; } set { int num = matchEnd - 1; if (!IsIndexInRange(num)) { throw new InvalidOperationException($"Last matched index {index} is out of range of instruction count {instructions.Count}"); } instructions[num] = value; } } public ICollection<CodeInstruction> Instructions => instructions.AsReadOnly(); public ILInjector(IEnumerable<CodeInstruction> instructions, ILGenerator generator = null) { this.generator = generator; matchEnd = -1; base..ctor(); } public ILInjector GoToStart() { matchEnd = index; index = 0; return this; } public ILInjector GoToEnd() { matchEnd = index; index = instructions.Count; return this; } public ILInjector Forward(int offset) { if (!IsValid) { return this; } matchEnd = index; index = Math.Clamp(index + offset, -1, instructions.Count); return this; } public ILInjector Back(int offset) { return Forward(-offset); } private void MarkInvalid() { index = -1; matchEnd = -1; } private void Search(bool forward, ILMatcher[] predicates) { if (!IsValid) { return; } int num = 1; if (!forward) { num = -1; index--; } while (forward ? (index < instructions.Count) : (index >= 0)) { if (forward && index + predicates.Length > instructions.Count) { index = instructions.Count; break; } int i; for (i = 0; i < predicates.Length && predicates[i].Matches(instructions[index + i]); i++) { } if (i == predicates.Length) { matchEnd = index + i; return; } index += num; } MarkInvalid(); } public ILInjector Find(params ILMatcher[] predicates) { Search(forward: true, predicates); return this; } public ILInjector ReverseFind(params ILMatcher[] predicates) { Search(forward: false, predicates); return this; } public ILInjector GoToPush(int popIndex) { if (!IsValid) { return this; } matchEnd = index; index--; int num = 0; while (index >= 0) { CodeInstruction instruction = instructions[index]; num += instruction.PushCount(); num -= instruction.PopCount(); if (num >= popIndex) { return this; } index--; } return this; } public ILInjector SkipBranch() { if (Instruction == null) { return this; } if (!(Instruction.operand is Label label)) { throw new InvalidOperationException($"Current instruction is not a branch: {Instruction}"); } return FindLabel(label); } public ILInjector FindLabel(Label label) { if (label == default(Label)) { return this; } matchEnd = index; for (index = 0; index < instructions.Count; index++) { if (instructions[index].labels.Contains(label)) { return this; } } MarkInvalid(); return this; } public ILInjector GoToMatchEnd() { index = matchEnd; return this; } public ILInjector GoToLastMatchedInstruction() { if (!IsIndexValid(matchEnd)) { return this; } index = matchEnd - 1; return this; } private bool IsIndexValid(int index) { return index != -1; } private bool IsIndexInRange(int index) { if (index >= 0) { return index < instructions.Count; } return false; } public CodeInstruction GetRelativeInstruction(int offset) { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } int num = index + offset; if (!IsIndexInRange(num)) { throw new IndexOutOfRangeException($"Offset {offset} would read out of bounds at index {num}"); } return instructions[num]; } public ILInjector SetRelativeInstruction(int offset, CodeInstruction instruction) { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } int num = index + offset; if (!IsIndexInRange(num)) { throw new IndexOutOfRangeException($"Offset {offset} would write out of bounds at index {num}"); } instructions[num] = instruction; return this; } [IteratorStateMachine(typeof(<GetRelativeInstructions>d__34))] public IEnumerable<CodeInstruction> GetRelativeInstructions(int offset, int size) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetRelativeInstructions>d__34(-2) { <>4__this = this, <>3__offset = offset, <>3__size = size }; } public IEnumerable<CodeInstruction> GetRelativeInstructions(int size) { return GetRelativeInstructions(0, size); } private void GetLastMatchRangeAbsolute(out int start, out int end) { start = index; end = matchEnd; if (start > end) { int num = end; int num2 = start; start = num; end = num2; } } private void GetLastMatchRange(out int start, out int size) { GetLastMatchRangeAbsolute(out start, out var end); if (start < 0 || start >= instructions.Count) { throw new InvalidOperationException($"Last match range starts at invalid index {start}"); } if (end < 0 || end > instructions.Count) { throw new InvalidOperationException($"Last match range ends at invalid index {end}"); } size = end - start; } public List<CodeInstruction> GetLastMatch() { GetLastMatchRange(out var start, out var size); return instructions.GetRange(start, size); } public ILInjector DefineLabel(out Label label) { if (generator == null) { throw new InvalidOperationException("No ILGenerator was provided"); } label = generator.DefineLabel(); return this; } public ILInjector AddLabel(out Label label) { DefineLabel(out label); return AddLabel(label); } public ILInjector AddLabel(Label label) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Instruction = new CodeInstruction(Instruction); Instruction.labels.Add(label); return this; } public ILInjector InsertInPlace(params CodeInstruction[] instructions) { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } this.instructions.InsertRange(index, instructions); if (matchEnd >= index) { matchEnd += instructions.Length; } return this; } public ILInjector Insert(params CodeInstruction[] instructions) { InsertInPlace(instructions); index += instructions.Length; return this; } public ILInjector InsertInPlaceAfterBranch(params CodeInstruction[] instructions) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } List<Label> labels = Instruction.labels; Instruction = new CodeInstruction(Instruction); Instruction.labels.Clear(); this.instructions.InsertRange(index, instructions); Instruction.labels.AddRange(labels); if (matchEnd >= index) { matchEnd += instructions.Length; } return this; } public ILInjector InsertAfterBranch(params CodeInstruction[] instructions) { InsertInPlaceAfterBranch(instructions); index += instructions.Length; return this; } public ILInjector RemoveAllPreviousInstructions() { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } instructions.RemoveRange(0, index); matchEnd -= index; if (matchEnd < 0) { matchEnd = 0; } index = 0; return this; } public ILInjector Remove(int count = 1) { if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } instructions.RemoveRange(index, count); if (matchEnd > index) { matchEnd = Math.Max(index, matchEnd - count); } return this; } public ILInjector RemoveLastMatch() { GetLastMatchRange(out var start, out var size); List<Label> labels = instructions[start].labels; instructions.RemoveRange(start, size); index = start; matchEnd = start; instructions[start].labels.AddRange(labels); return this; } public ILInjector ReplaceLastMatch(params CodeInstruction[] replacementInstructions) { if (replacementInstructions.Length == 0) { throw new ArgumentException("Cannot replace a match with an empty array."); } GetLastMatchRange(out var start, out var size); List<Label> labels = instructions[start].labels; instructions.RemoveRange(start, size); instructions.InsertRange(start, replacementInstructions); index = start; matchEnd = start + replacementInstructions.Length; instructions[start].labels.AddRange(labels); return this; } public List<CodeInstruction> ReleaseInstructions() { List<CodeInstruction> result = instructions; instructions = null; return result; } public ILInjector PrintContext(int context, string header = "") { if (!IsValid) { throw new InvalidOperationException("Injector is invalid (" + header + ")"); } StringBuilder stringBuilder = new StringBuilder(header); if (header.Length > 0) { stringBuilder.Append(':'); } stringBuilder.AppendLine(); GetLastMatchRangeAbsolute(out var start, out var end); int num = Math.Min(end + 1 + context, instructions.Count); for (int i = Math.Max(start - context, 0); i < num; i++) { if (end == -1 && i == index) { stringBuilder.Append("╶> "); } else { if (i >= start && i < end) { stringBuilder.Append("│"); } else { stringBuilder.Append(" "); } if (i == index) { stringBuilder.Append("╶> "); } else { stringBuilder.Append(" "); } } stringBuilder.AppendLine($"{i}: {instructions[i]}"); } LobbyControl.Log.LogFatal((object)stringBuilder); return this; } public ILInjector PrintContext(string header = "") { return PrintContext(4, header); } } internal interface ILMatcher { bool Matches(CodeInstruction instruction); ILMatcher CaptureAs(out CodeInstruction variable) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown variable = new CodeInstruction(OpCodes.Nop, (object)null); return new InstructionCapturingMatcher(this, variable); } unsafe ILMatcher CaptureOperandAs<T>(out T operand) where T : unmanaged { operand = default(T); fixed (T* operand2 = &operand) { return new OperandCapturingMatcher<T>(this, operand2); } } static ILMatcher Not(ILMatcher matcher) { return new NotMatcher(matcher); } static ILMatcher Opcode(OpCode opcode) { return new OpcodeMatcher(opcode); } static ILMatcher Opcodes(params OpCode[] opcodes) { return new OpcodesMatcher(opcodes); } static ILMatcher OpcodeOperand(OpCode opcode, object operand) { return new OpcodeOperandMatcher(opcode, operand); } static ILMatcher Instruction(CodeInstruction instruction) { return new InstructionMatcher(instruction); } static ILMatcher Ldarg(int? arg = null) { return new LdargMatcher(arg); } static ILMatcher Ldloc(int? loc = null) { return new LdlocMatcher(loc); } static ILMatcher Stloc(int? loc = null) { return new StlocMatcher(loc); } static ILMatcher Ldc(int? value = null) { return new LdcI32Matcher(value); } static ILMatcher Branch() { return new BranchMatcher(); } static ILMatcher Ldfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Ldfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Ldfld, field); } static ILMatcher Ldsfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Ldsfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Ldsfld, field); } static ILMatcher Stfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Stfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Stfld, field); } static ILMatcher Stsfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Stsfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Stsfld, field); } static ILMatcher Callvirt(MethodBase method, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (method == null) { LobbyControl.Log.LogWarning((object)$"Method passed to ILMatcher.Callvirt() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})"); } return OpcodeOperand(OpCodes.Callvirt, method); } static ILMatcher Call(MethodBase method, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (method == null) { LobbyControl.Log.LogWarning((object)$"Method passed to ILMatcher.Call() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})"); } return OpcodeOperand(OpCodes.Call, method); } static ILMatcher Predicate(Func<CodeInstruction, bool> predicate) { return new PredicateMatcher(predicate); } static ILMatcher Predicate(Func<FieldInfo, bool> predicate) { return new PredicateMatcher((CodeInstruction insn) => insn.operand is FieldInfo arg && predicate(arg)); } } internal class NotMatcher : ILMatcher { private readonly ILMatcher matcher; public NotMatcher(ILMatcher matcher) { this.matcher = matcher; base..ctor(); } public bool Matches(CodeInstruction instruction) { return !matcher.Matches(instruction); } } internal class OpcodeMatcher : ILMatcher { private readonly OpCode opcode; public OpcodeMatcher(OpCode opcode) { this.opcode = opcode; base..ctor(); } public bool Matches(CodeInstruction instruction) { return instruction.opcode == opcode; } } internal class OpcodesMatcher : ILMatcher { private readonly OpCode[] opcodes; public OpcodesMatcher(OpCode[] opcodes) { this.opcodes = opcodes; base..ctor(); } public bool Matches(CodeInstruction instruction) { return opcodes.Contains(instruction.opcode); } } internal class OpcodeOperandMatcher : ILMatcher { private readonly OpCode opcode; private readonly object operand; public OpcodeOperandMatcher(OpCode opcode, object operand) { this.opcode = opcode; this.operand = operand; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (instruction.opcode == opcode) { return instruction.operand == operand; } return false; } } internal class InstructionMatcher : ILMatcher { private readonly OpCode opcode = instruction.opcode; private readonly object operand = instruction.operand; private readonly Label[] labels = instruction.labels.ToArray(); public InstructionMatcher(CodeInstruction instruction) { } public bool Matches(CodeInstruction instruction) { if (instruction.opcode != opcode) { return false; } if (instruction.operand != operand) { return false; } if (instruction.labels.Count != labels.Length) { return false; } for (int i = 0; i < labels.Length; i++) { if (labels[i] != instruction.labels[i]) { return false; } } return true; } } internal class LdargMatcher : ILMatcher { private readonly int? arg; public LdargMatcher(int? arg) { this.arg = arg; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (!arg.HasValue) { return instruction.GetLdargIndex().HasValue; } return instruction.GetLdargIndex() == arg; } } internal class LdlocMatcher : ILMatcher { private readonly int? loc; public LdlocMatcher(int? loc) { this.loc = loc; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (!loc.HasValue) { return instruction.GetLdlocIndex().HasValue; } return instruction.GetLdlocIndex() == loc; } } internal class StlocMatcher : ILMatcher { private readonly int? loc; public StlocMatcher(int? loc) { this.loc = loc; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (!loc.HasValue) { return instruction.GetStlocIndex().HasValue; } return instruction.GetStlocIndex() == loc; } } internal class LdcI32Matcher : ILMatcher { private readonly int? value; public LdcI32Matcher(int? value) { this.value = value; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (!value.HasValue) { return instruction.GetLdcI32().HasValue; } return instruction.GetLdcI32() == value; } } internal class BranchMatcher : ILMatcher { public bool Matches(CodeInstruction instruction) { Label? label = default(Label?); return CodeInstructionExtensions.Branches(instruction, ref label); } } internal class PredicateMatcher : ILMatcher { private readonly Func<CodeInstruction, bool> predicate; public PredicateMatcher(Func<CodeInstruction, bool> predicate) { this.predicate = predicate; base..ctor(); } public bool Matches(CodeInstruction instruction) { return predicate(instruction); } } internal class InstructionCapturingMatcher : ILMatcher { private readonly ILMatcher matcher; private readonly CodeInstruction variable; public InstructionCapturingMatcher(ILMatcher matcher, CodeInstruction variable) { this.matcher = matcher; this.variable = variable; base..ctor(); } public bool Matches(CodeInstruction instruction) { bool flag = matcher.Matches(instruction); if (flag) { variable.opcode = instruction.opcode; variable.operand = instruction.operand; variable.blocks = instruction.blocks.ToList(); variable.labels = instruction.labels.ToList(); } return flag; } } internal class OperandCapturingMatcher<T> : ILMatcher where T : unmanaged { private readonly ILMatcher matcher; private unsafe readonly T* operand; public unsafe OperandCapturingMatcher(ILMatcher matcher, T* operand) { this.matcher = matcher; this.operand = operand; base..ctor(); } public unsafe bool Matches(CodeInstruction instruction) { bool flag = matcher.Matches(instruction); if (flag) { *operand = (T)instruction.operand; } return flag; } } internal static class InstructionUtilities { public static CodeInstruction MakeLdarg(int index) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown if (index < 256) { return (CodeInstruction)(index switch { 0 => (object)new CodeInstruction(OpCodes.Ldarg_0, (object)null), 1 => (object)new CodeInstruction(OpCodes.Ldarg_1, (object)null), 2 => (object)new CodeInstruction(OpCodes.Ldarg_2, (object)null), 3 => (object)new CodeInstruction(OpCodes.Ldarg_3, (object)null), _ => (object)new CodeInstruction(OpCodes.Ldarg_S, (object)index), }); } return new CodeInstruction(OpCodes.Ldarg, (object)index); } public static int PopCount(this CodeInstruction instruction) { if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Newobj) { MethodBase methodBase = (MethodBase)instruction.operand; int num = methodBase.GetParameters().Length; if (!methodBase.IsStatic) { num++; } return num; } if (instruction.opcode == OpCodes.Ret) { return 1; } return instruction.opcode.StackBehaviourPop switch { StackBehaviour.Pop0 => 0, StackBehaviour.Pop1 => 1, StackBehaviour.Pop1_pop1 => 2, StackBehaviour.Popi => 1, StackBehaviour.Popi_pop1 => 2, StackBehaviour.Popi_popi => 2, StackBehaviour.Popi_popi8 => 2, StackBehaviour.Popi_popi_popi => 3, StackBehaviour.Popi_popr4 => 2, StackBehaviour.Popi_popr8 => 2, StackBehaviour.Popref => 1, StackBehaviour.Popref_pop1 => 2, StackBehaviour.Popref_popi => 2, StackBehaviour.Popref_popi_popi => 3, StackBehaviour.Popref_popi_popi8 => 3, StackBehaviour.Popref_popi_popr4 => 3, StackBehaviour.Popref_popi_popr8 => 3, StackBehaviour.Popref_popi_popref => 3, StackBehaviour.Varpop => throw new NotImplementedException($"Variable pop on non-call instruction '{instruction}'"), StackBehaviour.Popref_popi_pop1 => 3, _ => throw new NotSupportedException($"StackBehaviourPop of {instruction.opcode.StackBehaviourPop} was not a pop for instruction '{instruction}'"), }; } public static int PushCount(this CodeInstruction instruction) { if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Newobj) { if (instruction.operand is MethodInfo methodInfo && methodInfo.ReturnType == typeof(void)) { return 0; } return 1; } return instruction.opcode.StackBehaviourPush switch { StackBehaviour.Push0 => 0, StackBehaviour.Push1 => 1, StackBehaviour.Push1_push1 => 2, StackBehaviour.Pushi => 1, StackBehaviour.Pushi8 => 1, StackBehaviour.Pushr4 => 1, StackBehaviour.Pushr8 => 1, StackBehaviour.Pushref => 1, StackBehaviour.Varpush => throw new NotImplementedException($"Variable push on non-call instruction '{instruction}'"), _ => throw new NotSupportedException($"StackBehaviourPush of {instruction.opcode.StackBehaviourPush} was not a push for instruction '{instruction}'"), }; } public static int? GetLdargIndex(this CodeInstruction instruction) { OpCode opcode = instruction.opcode; if (opcode == OpCodes.Ldarg_0) { return 0; } if (opcode == OpCodes.Ldarg_1) { return 1; } if (opcode == OpCodes.Ldarg_2) { return 2; } if (opcode == OpCodes.Ldarg_3) { return 3; } if (opcode == OpCodes.Ldarg || opcode == OpCodes.Ldarg_S) { return instruction.operand as int?; } return null; } public static int? GetLdlocIndex(this CodeInstruction instruction) { OpCode opcode = instruction.opcode; if (opcode == OpCodes.Ldloc_0) { return 0; } if (opcode == OpCodes.Ldloc_1) { return 1; } if (opcode == OpCodes.Ldloc_2) { return 2; } if (opcode == OpCodes.Ldloc_3) { return 3; } if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S) { return (instruction.operand as LocalBuilder)?.LocalIndex; } return null; } public static int? GetStlocIndex(this CodeInstruction instruction) { OpCode opcode = instruction.opcode; if (opcode == OpCodes.Stloc_0) { return 0; } if (opcode == OpCodes.Stloc_1) { return 1; } if (opcode == OpCodes.Stloc_2) { return 2; } if (opcode == OpCodes.Stloc_3) { return 3; } if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S) { return (instruction.operand as LocalBuilder)?.LocalIndex; } return null; } public static CodeInstruction LdlocToStloc(this CodeInstruction instruction) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown OpCode opcode = instruction.opcode; if (opcode == OpCodes.Ldloc_0) { return new CodeInstruction(OpCodes.Stloc_0, (object)null); } if (opcode == OpCodes.Ldloc_1) { return new CodeInstruction(OpCodes.Stloc_1, (object)null); } if (opcode == OpCodes.Ldloc_2) { return new CodeInstruction(OpCodes.Stloc_2, (object)null); } if (opcode == OpCodes.Ldloc_3) { return new CodeInstruction(OpCodes.Stloc_3, (object)null); } if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S) { return new CodeInstruction(OpCodes.Stloc, instruction.operand); } return null; } public static CodeInstruction StlocToLdloc(this CodeInstruction instruction) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown OpCode opcode = instruction.opcode; if (opcode == OpCodes.Stloc_0) { return new CodeInstruction(OpCodes.Ldloc_0, (object)null); } if (opcode == OpCodes.Stloc_1) { return new CodeInstruction(OpCodes.Ldloc_1, (object)null); } if (opcode == OpCodes.Stloc_2) { return new CodeInstruction(OpCodes.Ldloc_2, (object)null); } if (opcode == OpCodes.Stloc_3) { return new CodeInstruction(OpCodes.Ldloc_3, (object)null); } if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S) { return new CodeInstruction(OpCodes.Ldloc, instruction.operand); } return null; } public static int? GetLdcI32(this CodeInstruction instruction) { OpCode opcode = instruction.opcode; if (opcode == OpCodes.Ldc_I4_M1) { return -1; } if (opcode == OpCodes.Ldc_I4_0) { return 0; } if (opcode == OpCodes.Ldc_I4_1) { return 1; } if (opcode == OpCodes.Ldc_I4_2) { return 2; } if (opcode == OpCodes.Ldc_I4_3) { return 3; } if (opcode == OpCodes.Ldc_I4_4) { return 4; } if (opcode == OpCodes.Ldc_I4_5) { return 5; } if (opcode == OpCodes.Ldc_I4_6) { return 6; } if (opcode == OpCodes.Ldc_I4_7) { return 7; } if (opcode == OpCodes.Ldc_I4_8) { return 8; } if (opcode == OpCodes.Ldc_I4_S) { return instruction.operand as sbyte?; } if (opcode == OpCodes.Ldc_I4) { return instruction.operand as int?; } return null; } } public static class ReflectionExtensions { public static MethodInfo GetGenericMethod(this Type type, string name, Type[] parameters, Type[] genericArgs) { MethodInfo[] methods = type.GetMethods(); MethodInfo[] array = methods; foreach (MethodInfo methodInfo in array) { if (!(methodInfo.Name != name) && methodInfo.IsGenericMethodDefinition) { return methodInfo.MakeGenericMethod(genericArgs); } } return null; } } } namespace LobbyControl.TerminalCommands { public class Command { public TerminalNode previousTerminalNode; public bool awaitingConfirmation { get { return CommandManager.awaitingConfirmationCommand == this; } set { CommandManager.awaitingConfirmationCommand = (value ? this : null); } } public virtual bool IsCommand(string[] args) { return false; } public virtual TerminalNode Execute(string[] args) { return TerminalPatch.CreateTerminalNode("Execute override was not found.\n\n"); } public virtual TerminalNode ExecuteConfirmation(string[] args) { string text = args[0].ToLower(); if ("confirm".Contains(text) && text.Length > 0) { return OnConfirm(args); } if ("deny".Contains(text) && text.Length > 0) { return OnDeny(args); } return OnInvalidInput(args); } protected virtual TerminalNode OnConfirm(string[] args) { return TerminalPatch.CreateTerminalNode("OnConfirm override was not found.\n\n"); } protected virtual TerminalNode OnDeny(string[] args) { return TerminalPatch.CreateTerminalNode("OnDeny override was not found.\n\n"); } protected virtual TerminalNode OnInvalidInput(string[] args) { return previousTerminalNode; } } internal class CommandManager { private static List<Command> commands = new List<Command>(); public static Command awaitingConfirmationCommand; public static void Initialize() { commands = new List<Command> { new LobbyCommand() }; awaitingConfirmationCommand = null; } public static bool TryExecuteCommand(string[] array, out TerminalNode terminalNode) { terminalNode = null; if (awaitingConfirmationCommand != null) { Command command = awaitingConfirmationCommand; terminalNode = command.ExecuteConfirmation(array); command.previousTerminalNode = terminalNode; return true; } Command command2 = GetCommand(array); if (command2 == null) { return false; } terminalNode = command2.Execute(array); command2.previousTerminalNode = terminalNode; return true; } public static void OnLocalDisconnect() { awaitingConfirmationCommand = null; } public static void OnTerminalQuit() { awaitingConfirmationCommand = null; } private static Command GetCommand(string[] args) { Command result = null; commands.ForEach(delegate(Command command) { if (result == null && command.IsCommand(args)) { result = command; } }); return result; } } public class LobbyCommand : Command { [CompilerGenerated] private sealed class <LoadLobbyCoroutine>d__19 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private StartOfRound <startOfRound>5__2; private Terminal <terminal>5__3; private bool <mem>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadLobbyCoroutine>d__19(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <startOfRound>5__2 = null; <terminal>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Expected O, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <startOfRound>5__2 = StartOfRound.Instance; <terminal>5__3 = Object.FindObjectOfType<Terminal>(); <startOfRound>5__2.ResetShip(); VehicleController[] array = Object.FindObjectsOfType<VehicleController>(); VehicleController[] array2 = array; foreach (VehicleController val in array2) { if ((Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)null) { ((NetworkBehaviour)val).NetworkObject.Despawn(false); } } <mem>5__4 = GameNetworkManager.Instance.gameHasStarted; GameNetworkManager.Instance.gameHasStarted = false; foreach (KeyValuePair<int, GameObject> item in StartOfRound.Instance.SpawnedShipUnlockables.ToList()) { UnlockableItem val2 = <startOfRound>5__2.unlockablesList.unlockables[item.Key]; if (val2.alreadyUnlocked && val2.spawnPrefab && !((Object)(object)item.Value == (Object)null)) { NetworkObject component = item.Value.GetComponent<NetworkObject>(); if ((Object)(object)component != (Object)null && component.IsSpawned) { component.Despawn(true); } } } <startOfRound>5__2.SpawnedShipUnlockables.Clear(); <startOfRound>5__2.suitsPlaced = 0; GameNetworkManager.Instance.ResetUnlockablesListValues(false); <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; } case 1: <>1__state = -1; <startOfRound>5__2.SetTimeAndPlanetToSavedSettings(); <startOfRound>5__2.SetMapScreenInfoToCurrentLevel(); <terminal>5__3.Start(); if (<startOfRound>5__2.connectedPlayersAmount >= 1) { RefreshLobby(); } ReloadUnlockables(); <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 2; return true; case 2: <>1__state = -1; <startOfRound>5__2.LoadAttachedVehicle(); <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 3; return true; case 3: <>1__state = -1; <startOfRound>5__2.LoadShipGrabbableItems(); <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 4; return true; case 4: <>1__state = -1; if (<startOfRound>5__2.connectedPlayersAmount >= 1) { <startOfRound>5__2.SyncShipUnlockablesServerRpc(); } GameNetworkManager.Instance.gameHasStarted = <mem>5__4; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string DefaultText = "- status : prints the current lobby status\r\n\r\nSteam:\r\n- open : open the lobby\r\n- close : close the lobby\r\n- private : set lobby to Invite Only\r\n- friend : set lobby to Friends Only\r\n- public : set lobby to Public\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave : toggle autosave for the savefile\r\n- save (name) : save the lobby\r\n- load (name) : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall : drop all items to the ground\r\n"; private const string DefaultTextLAN = "- status : prints the current lobby status\r\n\r\nLAN:\r\n- open : set the lobby to be discoverable\r\n- close : set the lobby to be non-discoverable\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave : toggle autosave for the savefile\r\n- save (name) : save the lobby\r\n- load (name) : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall : drop all items to the ground\r\n"; private static uint? _returnUnlockableFromStorageServerRpcID; private static uint? _onPlayerConnectedClientRpcID; public override bool IsCommand(string[] args) { if (GameNetworkManager.Instance.isHostingGame) { return args[0].Trim().ToLower() == "lobby"; } return false; } public override TerminalNode Execute(string[] args) { TerminalNode node = ScriptableObject.CreateInstance<TerminalNode>(); try { if (Utility.IsNullOrWhiteSpace(args[1])) { return HelpNode(); } switch (args[1]) { case "status": StatusCommand(ref node, args); break; case "open": { if (PerformOrbitCheck(node, out var errorText10)) { return errorText10; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { OpenCommand(ref node, args); } break; } case "close": { if (PerformOrbitCheck(node, out var errorText7)) { return errorText7; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { CloseCommand(ref node, args); } break; } case "private": { if (PerformOrbitCheck(node, out var errorText3)) { return errorText3; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { PrivateCommand(ref node, args); } break; } case "friend": { if (PerformOrbitCheck(node, out var errorText11)) { return errorText11; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { FriendCommand(ref node, args); } break; } case "public": { if (PerformOrbitCheck(node, out var errorText2)) { return errorText2; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { PublicCommand(ref node, args); } break; } case "rename": { if (PerformOrbitCheck(node, out var errorText6)) { return errorText6; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { RenameCommand(ref node, args); } break; } case "autosave": AutoSaveCommand(ref node, args); break; case "save": { if (PerformOrbitCheck(node, out var errorText8)) { return errorText8; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { SaveCommand(ref node, args); } break; } case "load": { if (PerformOrbitCheck(node, out var errorText4)) { return errorText4; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { LoadCommand(ref node, args); } break; } case "switch": { if (PerformOrbitCheck(node, out var errorText9)) { return errorText9; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { SwitchCommand(ref node, args); } break; } case "clear": { if (PerformOrbitCheck(node, out var errorText5)) { return errorText5; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { ClearCommand(ref node, args); } break; } case "dropall": { if (PerformOrbitCheck(node, out var errorText)) { return errorText; } if (!LobbyControl.CanModifyLobby) { node.displayText = "Lobby cannot be changed at the moment\n\n"; } else { DropAllCommand(ref node, args); } break; } case "help": node = HelpNode(); break; default: node = HelpNode(); node.displayText = "Invalid Command, options:\n" + node.displayText; break; } } catch (Exception ex) { LobbyControl.Log.LogError((object)("Exception:\n\n" + ex)); node.displayText = "Exception!\n\n"; } return node; } private static bool StatusCommand(ref TerminalNode node, string[] args) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) GameNetworkManager instance = GameNetworkManager.Instance; bool flag = false; string value = instance.steamLobbyName; string value2; if (instance.disableSteam) { UnityTransport component = ((Component)NetworkManager.Singleton).GetComponent<UnityTransport>(); value2 = ((component.ConnectionData.ServerListenAddress == "0.0.0.0") ? "Public" : "Private"); } else { if (!instance.currentLobby.HasValue) { node.displayText = "Failed to fetch lobby ( was null )\n\n"; return false; } Lobby value3 = instance.currentLobby.Value; flag = LobbyPatcher.IsOpen(value3); LobbyType visibility = LobbyPatcher.GetVisibility(value3); value2 = ((object)(LobbyType)(ref visibility)).ToString(); value = ((Lobby)(ref value3)).GetData("name"); } bool canSave = LobbyControl.CanSave; StringBuilder stringBuilder = new StringBuilder("Lobby Status:"); stringBuilder.Append("\n- File is '").Append(instance.currentSaveFileName).Append("'"); stringBuilder.Append("\n- Name is '").Append(value).Append("'"); if (!instance.disableSteam) { stringBuilder.Append("\n- Status is ").Append(flag ? "Open" : "Closed"); } stringBuilder.Append("\n- Visibility is ").Append(value2); stringBuilder.Append("\n- Saving is ").Append(canSave ? "Automatic" : "Manual"); stringBuilder.Append("\n\n"); node.displayText = stringBuilder.ToString(); node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool OpenCommand(ref TerminalNode node, string[] args) { LobbyControl.Log.LogDebug((object)"Reopening lobby, setting to joinable."); GameNetworkManager instance = GameNetworkManager.Instance; if (instance.disableSteam) { UnityTransport component = ((Component)NetworkManager.Singleton).GetComponent<UnityTransport>(); if (component.ConnectionData.ServerListenAddress != "0.0.0.0") { node.displayText = "Server is limited to local connections\n\n"; return false; } instance.lobbyHostSettings.isLobbyPublic = true; ES3.Save<bool>("HostSettings_Public", instance.lobbyHostSettings.isLobbyPublic, "LCGeneralSaveData"); } else if (!instance.currentLobby.HasValue) { node.displayText = "Failed to fetch lobby ( was null )\n\n"; return false; } instance.SetLobbyJoinable(true); Object.FindObjectOfType<QuickMenuManager>().inviteFriendsTextAlpha.alpha = 1f; string text = "Lobby is now Open"; LobbyControl.Log.LogInfo((object)text); node.displayText = text + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool CloseCommand(ref TerminalNode node, string[] args) { LobbyControl.Log.LogDebug((object)"Closing lobby, setting to not joinable."); GameNetworkManager instance = GameNetworkManager.Instance; if (instance.disableSteam) { UnityTransport component = ((Component)NetworkManager.Singleton).GetComponent<UnityTransport>(); if (component.ConnectionData.ServerListenAddress != "0.0.0.0") { node.displayText = "Server is limited to local connections\n\n"; return false; } instance.lobbyHostSettings.isLobbyPublic = false; ES3.Save<bool>("HostSettings_Public", instance.lobbyHostSettings.isLobbyPublic, "LCGeneralSaveData"); } else if (!instance.currentLobby.HasValue) { node.displayText = "Failed to fetch lobby ( was null )\n\n"; return false; } instance.SetLobbyJoinable(false); Object.FindObjectOfType<QuickMenuManager>().inviteFriendsTextAlpha.alpha = 0f; string text = "Lobby is now Closed"; LobbyControl.Log.LogInfo((object)text); node.displayText = text + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool PrivateCommand(ref TerminalNode node, string[] args) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) LobbyControl.Log.LogDebug((object)"Locking lobby, setting to Private."); GameNetworkManager instance = GameNetworkManager.Instance; if (!instance.currentLobby.HasValue) { node.displayText = "Failed to fetch lobby ( was null )\n\n"; return false; } ES3.Save<bool>("HostSettings_Public", false, "LCGeneralSaveData"); Lobby value = instance.currentLobby.Value; ((Lobby)(ref value)).SetPrivate(); string text = "Lobby is now Private"; LobbyControl.Log.LogInfo((object)text); node.displayText = text + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool FriendCommand(ref TerminalNode node, string[] args) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) LobbyControl.Log.LogDebug((object)"Locking lobby, setting to Friends Only."); GameNetworkManager instance = GameNetworkManager.Instance; if (!instance.currentLobby.HasValue) { node.displayText = "Failed to fetch lobby ( was null )\n\n"; return false; } ES3.Save<bool>("HostSettings_Public", false, "LCGeneralSaveData"); Lobby value = instance.currentLobby.Value; ((Lobby)(ref value)).SetFriendsOnly(); string text = "Lobby is now Friends Only"; LobbyControl.Log.LogInfo((object)text); node.displayText = text + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool PublicCommand(ref TerminalNode node, string[] args) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) LobbyControl.Log.LogDebug((object)"Unlocking lobby, setting to Public."); GameNetworkManager instance = GameNetworkManager.Instance; if (!instance.currentLobby.HasValue) { node.displayText = "Failed to fetch lobby ( was null )\n\n"; return false; } ES3.Save<bool>("HostSettings_Public", true, "LCGeneralSaveData"); Lobby value = instance.currentLobby.Value; ((Lobby)(ref value)).SetPublic(); string text = "Lobby is now Public"; LobbyControl.Log.LogInfo((object)text); node.displayText = text + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool RenameCommand(ref TerminalNode node, string[] args) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if (Utility.IsNullOrWhiteSpace(args[2])) { node.displayText = "Lobby name cannot be null\n\n"; return false; } string text = args[2]; if (text.Length > 40) { text = text.Substring(0, 40); } LobbyControl.Log.LogDebug((object)("Renaming lobby: \"" + text + "\"")); GameNetworkManager instance = GameNetworkManager.Instance; if (!instance.disableSteam && !instance.currentLobby.HasValue) { node.displayText = "Failed to fetch lobby ( was null )\n\n"; return false; } instance.lobbyHostSettings.lobbyName = text; instance.steamLobbyName = instance.lobbyHostSettings.lobbyName; if (instance.currentLobby.HasValue) { Lobby value = instance.currentLobby.Value; ((Lobby)(ref value)).SetData("name", instance.steamLobbyName); } ES3.Save<string>("HostSettings_Name", instance.steamLobbyName, "LCGeneralSaveData"); string text2 = "Lobby renamed to \"" + text + "\""; LobbyControl.Log.LogInfo((object)text2); node.displayText = text2 + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool AutoSaveCommand(ref TerminalNode node, string[] args) { LobbyControl.Log.LogDebug((object)"Toggling AutoSave"); LobbyControl.CanSave = (LobbyControl.AutoSaveEnabled = !LobbyControl.AutoSaveEnabled); string text = "AutoSaving is now " + (LobbyControl.CanSave ? "On" : "Off"); LobbyControl.Log.LogInfo((object)text); node.displayText = text + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool SaveCommand(ref TerminalNode node, string[] args) { if (StartOfRound.Instance.isChallengeFile) { node.displayText = "Cannot Edit Challenge Save\n\n"; return false; } LobbyControl.Log.LogDebug((object)"Saving Lobby"); GameNetworkManager instance = GameNetworkManager.Instance; string currentSaveFileName = instance.currentSaveFileName; if (!Utility.IsNullOrWhiteSpace(args[2])) { string text = args[2]; if (text.Length > 20) { text = text.Substring(0, 20); } instance.currentSaveFileName = text; } if (currentSaveFileName != instance.currentSaveFileName) { ES3.CopyFile(currentSaveFileName, instance.currentSaveFileName); } LobbyControl.CanSave = true; HUDManager.Instance.saveDataIconAnimatorB.SetTrigger("save"); instance.SaveGameValues(); string text2 = "Lobby Saved to " + instance.currentSaveFileName; LobbyControl.CanSave = LobbyControl.AutoSaveEnabled; instance.currentSaveFileName = currentSaveFileName; LobbyControl.Log.LogInfo((object)text2); node.displayText = text2 + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool LoadCommand(ref TerminalNode node, string[] args) { if (StartOfRound.Instance.isChallengeFile) { node.displayText = "Cannot Edit Challenge Save\n\n"; return false; } LobbyControl.Log.LogDebug((object)"Reloading Lobby"); GameNetworkManager instance = GameNetworkManager.Instance; if (!Utility.IsNullOrWhiteSpace(args[2])) { string text = args[2]; if (text.Length > 20) { text = text.Substring(0, 20); } instance.currentSaveFileName = text; } string text2 = "Lobby '" + instance.currentSaveFileName + "' loaded"; ((MonoBehaviour)StartOfRound.Instance).StartCoroutine(LoadLobbyCoroutine()); LobbyControl.AutoSaveEnabled = (LobbyControl.CanSave = ES3.Load<bool>("LC_SavingMethod", GameNetworkManager.Instance.currentSaveFileName, true)); LobbyControl.Log.LogInfo((object)text2); node.displayText = text2 + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool SwitchCommand(ref TerminalNode node, string[] args) { if (StartOfRound.Instance.isChallengeFile) { node.displayText = "Cannot Edit Challenge Save\n\n"; return false; } LobbyControl.Log.LogDebug((object)"Switching Lobby"); GameNetworkManager instance = GameNetworkManager.Instance; if (Utility.IsNullOrWhiteSpace(args[2])) { node.displayText = "You need to specify a destination for the swap!"; return false; } string text = args[2]; if (text.Length > 20) { text = text.Substring(0, 20); } instance.currentSaveFileName = text; string text2 = "Lobby is now saving to '" + instance.currentSaveFileName + "'"; node.displayText = text2 + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool ClearCommand(ref TerminalNode node, string[] args) { if (StartOfRound.Instance.isChallengeFile) { node.displayText = "Cannot Edit Challenge Save\n\n"; return false; } LobbyControl.Log.LogDebug((object)"Clearing Lobby"); LobbyControl.CanSave = true; GameNetworkManager.Instance.ResetSavedGameValues(); ES3.DeleteFile(GameNetworkManager.Instance.currentSaveFileName); LobbyControl.CanSave = LobbyControl.AutoSaveEnabled; bool flag = LoadCommand(ref node, new string[3]); if (flag) { node.displayText = "Lobby is now Empty!"; } return flag; } private static bool DropAllCommand(ref TerminalNode node, string[] args) { LobbyControl.Log.LogDebug((object)"Dropping all Items"); string text = "All Items Dropped"; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { val.DropAllHeldItemsAndSync(); } node.displayText = text + "\n\n"; node.maxCharactersToType = node.displayText.Length + 2; return true; } private static bool PerformOrbitCheck(TerminalNode terminalNode, out TerminalNode errorText) { if (!StartOfRound.Instance.inShipPhase) { terminalNode.displayText = "Can only be used while in Orbit\n\n"; errorText = terminalNode; return true; } errorText = null; return false; } private static TerminalNode HelpNode() { TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>(); val.displayText = (GameNetworkManager.Instance.disableSteam ? "- status : prints the current lobby status\r\n\r\nLAN:\r\n- open : set the lobby to be discoverable\r\n- close : set the lobby to be non-discoverable\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave : toggle autosave for the savefile\r\n- save (name) : save the lobby\r\n- load (name) : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall : drop all items to the ground\r\n" : "- status : prints the current lobby status\r\n\r\nSteam:\r\n- open : open the lobby\r\n- close : close the lobby\r\n- private : set lobby to Invite Only\r\n- friend : set lobby to Friends Only\r\n- public : set lobby to Public\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave : toggle autosave for the savefile\r\n- save (name) : save the lobby\r\n- load (name) : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall : drop all items to the ground\r\n"); val.clearPreviousText = true; val.maxCharactersToType = val.displayText.Length + 2; return val; } [IteratorStateMachine(typeof(<LoadLobbyCoroutine>d__19))] private static IEnumerator LoadLobbyCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadLobbyCoroutine>d__19(0); } private static void ReloadUnlockables() { //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016e: 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) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; instance.LoadUnlockables(); try { for (int i = 0; i < instance.unlockablesList.unlockables.Count; i++) { UnlockableItem val = instance.unlockablesList.unlockables[i]; if (val.unlockableType == 0 || !val.alreadyUnlocked) { continue; } LobbyControl.Log.LogDebug((object)(val.unlockableName + " starting")); if (!instance.SpawnedShipUnlockables.ContainsKey(i)) { instance.SpawnUnlockable(i); } PlaceableShipObject val2 = instance.SpawnedShipUnlockables[i].GetComponent<PlaceableShipObject>(); if (val2 == null) { val2 = instance.SpawnedShipUnlockables[i].GetComponentInChildren<PlaceableShipObject>(); } if (val2 != null) { LobbyControl.Log.LogDebug((object)(val.unlockableName + " continuing")); Quaternion val4; if (Object.op_Implicit((Object)(object)val2.parentObjectSecondary)) { Quaternion rotation = ((Component)val2.parentObjectSecondary).transform.rotation; Quaternion rotation2 = ((Component)val2.parentObjectSecondary).transform.rotation; Quaternion rotation3 = ((Component)val2.mainMesh).transform.rotation; Quaternion val3 = rotation * Quaternion.Inverse(rotation2); val4 = val3 * rotation3; val.placedRotation = ((Quaternion)(ref val4)).eulerAngles; Vector3 position = val2.parentObjectSecondary.position; Vector3 val5 = ((Component)val2.parentObjectSecondary).transform.position - ((Component)val2.mainMesh).transform.position; Vector3 val6 = ((Component)val2.mainMesh).transform.position - ((Component)val2.placeObjectCollider).transform.position; val.placedPosition = position - val5 - val6; } else { Quaternion val7 = Quaternion.Euler(val2.parentObject.rotationOffset); Quaternion rotation4 = ((Component)val2.parentObject).transform.rotation; Quaternion rotation5 = ((Component)val2.mainMesh).transform.rotation; Quaternion val8 = val7 * Quaternion.Inverse(rotation4); val4 = val8 * rotation5; val.placedRotation = ((Quaternion)(ref val4)).eulerAngles; Vector3 val9 = ((Component)val2.parentObject).transform.position - ((Component)val2.mainMesh).transform.position; Vector3 val10 = ((Component)val2.mainMesh).transform.position - ((Component)val2.placeObjectCollider).transform.position; val.placedPosition = StartOfRound.Instance.elevatorTransform.TransformPoint(val2.parentObject.positionOffset) - val9 - val10; } } } if (instance.connectedPlayersAmount < 1) { return; } List<ulong> targetClientIds = instance.ClientPlayerList.Keys.ToList(); ClientRpcParams val11 = default(ClientRpcParams); val11.Send = new ClientRpcSendParams { TargetClientIds = targetClientIds }; ClientRpcParams val12 = val11; for (int j = 0; j < instance.unlockablesList.unlockables.Count; j++) { UnlockableItem val13 = instance.unlockablesList.unlockables[j]; if (val13.alreadyUnlocked && !val13.inStorage && _returnUnlockableFromStorageServerRpcID.HasValue) { uint value = _returnUnlockableFromStorageServerRpcID.Value; FastBufferWriter val14 = ((NetworkBehaviour)instance).__beginSendClientRpc(value, val12, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val14, j); ((NetworkBehaviour)instance).__endSendClientRpc(ref val14, value, val12, (RpcDelivery)0); } } instance.SyncShipUnlockablesServerRpc(); } catch (Exception ex) { LobbyControl.Log.LogError((object)ex); } } private static void RefreshLobby() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; List<ulong> list = new List<ulong>(); List<ulong> list2 = new List<ulong>(); for (int i = 0; i < instance.allPlayerObjects.Length; i++) { NetworkObject component = instance.allPlayerObjects[i].GetComponent<NetworkObject>(); if (!component.IsOwnedByServer) { list.Add(component.OwnerClientId); list2.Add(component.OwnerClientId); } else if (i == 0) { list.Add(NetworkManager.Singleton.LocalClientId); } else { list.Add(999uL); } } ClientRpcParams val = default(ClientRpcParams); val.Send = new ClientRpcSendParams { TargetClientIds = list2 }; ClientRpcParams val2 = val; int groupCredits = Object.FindObjectOfType<Terminal>().groupCredits; int profitQuota = TimeOfDay.Instance.profitQuota; int quotaFulfilled = TimeOfDay.Instance.quotaFulfilled; int num = (int)TimeOfDay.Instance.timeUntilDeadline; PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; if (_onPlayerConnectedClientRpcID.HasValue) { uint value = _onPlayerConnectedClientRpcID.Value; FastBufferWriter val3 = ((NetworkBehaviour)instance).__beginSendClientRpc(value, val2, (RpcDelivery)0); BytePacker.WriteValueBitPacked(val3, localPlayerController.actualClientId); BytePacker.WriteValueBitPacked(val3, instance.connectedPlayersAmount - 1); bool flag = true; ((FastBufferWriter)(ref val3)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); ((FastBufferWriter)(ref val3)).WriteValueSafe<ulong>(list.ToArray(), default(ForPrimitives)); BytePacker.WriteValueBitPacked(val3, instance.ClientPlayerList[localPlayerController.actualClientId]); BytePacker.WriteValueBitPacked(val3, groupCredits); BytePacker.WriteValueBitPacked(val3, instance.currentLevelID); BytePacker.WriteValueBitPacked(val3, profitQuota); BytePacker.WriteValueBitPacked(val3, num); BytePacker.WriteValueBitPacked(val3, quotaFulfilled); BytePacker.WriteValueBitPacked(val3, instance.randomMapSeed); ((FastBufferWriter)(ref val3)).WriteValueSafe<bool>(ref instance.isChallengeFile, default(ForPrimitives)); ((NetworkBehaviour)instance).__endSendClientRpc(ref val3, value, val2, (RpcDelivery)0); } } internal static void Init() { MethodInfo methodInfo = AccessTools.Method(typeof(StartOfRound), "ReturnUnlockableFromStorageClientRpc", (Type[])null, (Type[])null); if (RPCUtils.TryGetRpcID(methodInfo, out var rpcID)) { _returnUnlockableFromStorageServerRpcID = rpcID; } MethodInfo methodInfo2 = AccessTools.Method(typeof(StartOfRound), "OnPlayerConnectedClientRpc", (Type[])null, (Type[])null); if (RPCUtils.TryGetRpcID(methodInfo2, out var rpcID2)) { _onPlayerConnectedClientRpcID = rpcID2; } } } } namespace LobbyControl.PopUp { [HarmonyPatch] public class PopUpPatch { public static readonly List<(string objectName, string text)> PopUps = new List<(string, string)>(); [HarmonyPrefix] [HarmonyPatch(typeof(MenuManager), "Awake")] private static void AddPopups(MenuManager __instance) { foreach (var (objectName, text) in PopUps) { AppendPopup(objectName, text); } } private static void AppendPopup(string objectName, string text) { GameObject val = GameObject.Find("/Canvas/MenuContainer/"); GameObject val2 = GameObject.Find("Canvas/MenuContainer/LANWarning/"); if (!((Object)(object)val2 == (Object)null)) { GameObject val3 = Object.Instantiate<GameObject>(val2, val.transform); ((Object)val3).name = objectName; val3.SetActive(true); Transform val4 = val3.transform.Find("Panel/NotificationText"); TextMeshProUGUI component = ((Component)val4).GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).text = text; } } } } namespace LobbyControl.Patches { [HarmonyPatch] internal class JoinQueuePatches { private static bool _allowNewConnection; private static bool _checkpointsInitialized; private static ConnectionCheckpoint _syncAlreadyHeldObjectsCheckpoint; private static ConnectionCheckpoint _sendNewPlayerValuesCheckpoint; private static ConnectionCheckpoint _syncAllPlayerLevelsCheckpoint; private static readonly ConcurrentQueue<(ConnectionApprovalRequest request, ConnectionApprovalResponse response, ulong? steamId)> ConnectionQueue = new ConcurrentQueue<(ConnectionApprovalRequest, ConnectionApprovalResponse, ulong?)>(); private static readonly Timer ConnectionTimer = new Timer { AutoReset = false }; private static readonly Stopwatch ConnectionStopwatch = new Stopwatch(); private static bool _testValue = false; [HarmonyPrefix] [HarmonyPatch(typeof(GameNetworkManager), "Awake")] private static void OnStartup(GameNetworkManager __instance) { if (!_checkpointsInitialized) { _checkpointsInitialized = true; _syncAlreadyHeldObjectsCheckpoint = ConnectionCheckpoint.RegisterCheckpoint((BaseUnityPlugin)(object)LobbyControl.Instance, "SyncAlreadyHeldObjects"); _syncAllPlayerLevelsCheckpoint = ConnectionCheckpoint.RegisterCheckpoint((BaseUnityPlugin)(object)LobbyControl.Instance, "SyncAllPlayerLevels"); if (!__instance.disableSteam) { _sendNewPlayerValuesCheckpoint = ConnectionCheckpoint.RegisterCheckpoint((BaseUnityPlugin)(object)LobbyControl.Instance, "SendNewPlayerValues"); } } } [HarmonyTranspiler] [HarmonyPatch(typeof(GameNetworkManager), "ConnectionApproval")] private static IEnumerable<CodeInstruction> FixConnectionApprovalPrefix(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = instructions.ToList(); Label operand; ILInjector iLInjector = new ILInjector(list).Find(ILMatcher.Call(typeof(GameNetworkManager).GetProperty("Instance")?.GetMethod, "FixConnectionApprovalPrefix", "./Plugin/src/Patches/JoinQueuePatches.cs", 74), ILMatcher.Ldfld(typeof(GameNetworkManager).GetField("gameHasStarted", BindingFlags.Instance | BindingFlags.Public), "FixConnectionApprovalPrefix", "./Plugin/src/Patches/JoinQueuePatches.cs", 75), ILMatcher.Opcode(OpCodes.Brfalse).CaptureOperandAs<Label>(out operand)); if (!iLInjector.IsValid) { LobbyControl.Log.LogWarning((object)"ConnectionApproval patch failed!!"); LobbyControl.Log.LogDebug((object)string.Join("\n", iLInjector.ReleaseInstructions())); return list; } return iLInjector.RemoveLastMatch().FindLabel(operand).RemoveLastMatch() .ReleaseInstructions(); } [HarmonyFinalizer] [HarmonyPatch(typeof(GameNetworkManager), "ConnectionApproval")] [HarmonyPriority(10)] private static Exception ThrottleApprovals(GameNetworkManager __instance, ConnectionApprovalRequest request, ConnectionApprovalResponse response, Exception __exception) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) if (__exception != null) { return __exception; } if (!response.Approved) { return null; } if (!_allowNewConnection) { LobbyControl.Log.LogDebug((object)"connection refused ( ship was landed )."); response.Reason = "Ship has already landed!"; response.Approved = false; return null; } if (!__instance.disableSteam && (!__instance.currentLobby.HasValue || !LobbyPatcher.IsOpen(__instance.currentLobby.Value))) { LobbyControl.Log.LogDebug((object)"connection refused ( lobby was closed )."); response.Reason = "Lobby has been closed!"; response.Approved = false; return null; } if (__instance.gameHasStarted) { LobbyControl.Log.LogDebug((object)"Incoming late connection."); } if (!LobbyControl.PluginConfig.JoinQueue.Enabled.Value) { re