Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LobbyControl v2.5.11
BepInEx/plugins/LobbyControl.dll
Decompiled 5 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.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("com.olegknyazev.softmask")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("EasyTextEffects")] [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.Components")] [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.11")] [assembly: AssemblyInformationalVersion("2.5.11+80e4358ced3bae058de4469cf96090d2bdfc3202")] [assembly: AssemblyProduct("LobbyControl")] [assembly: AssemblyTitle("LobbyControl - Plugin")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.5.11.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.11")] [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 { public const string GUID = "mattymatty.LobbyControl"; public const string NAME = "LobbyControl"; public const string VERSION = "2.5.11"; 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.11"), 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.11 Loaded!"); } catch (Exception ex) { Log.LogError((object)("Exception while initializing: \n" + ex)); } } } 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 class JoinQueue { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> MaxSize; 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: 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"); JoinQueue.Enabled = config.Bind<bool>("JoinQueue", "enabled", true, "handle joining players as a queue instead of at the same time"); JoinQueue.MaxSize = config.Bind<int>("JoinQueue", "max_size", 3, new ConfigDescription("max number of players in queue ( if queue is full extra connections will be refused )", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1, 10), Array.Empty<object>())); JoinQueue.ConnectionTimeout = config.Bind<int>("JoinQueue", "connection_timeout_ms", 40000, 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(JoinQueue.Enabled); LethalConfigProxy.AddConfig(JoinQueue.MaxSize); 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 static class MyPluginInfo { public const string PLUGIN_GUID = "mattymatty.LobbyControl"; public const string PLUGIN_NAME = "LobbyControl"; public const string PLUGIN_VERSION = "2.5.11"; } } namespace LobbyControl.Utils { public static class HudUtils { [CompilerGenerated] private sealed class <ShowMessageAfterDelay>d__1 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float delay; public string title; public string text; public bool isWarning; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ShowMessageAfterDelay>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 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, isWarning, false, "LC_Tip1"); return false; } IL_0050: <>2__current = WaitForAnimation; <>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__2 : 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__2(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 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 = WaitForAnimation; <>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(); } } private static readonly WaitUntil WaitForAnimation = new WaitUntil((Func<bool>)delegate { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) AnimatorStateInfo currentAnimatorStateInfo = HUDManager.Instance.tipsPanelAnimator.GetCurrentAnimatorStateInfo(0); return ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime >= 1f; }); [IteratorStateMachine(typeof(<ShowMessageAfterDelay>d__1))] 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__1(0) { title = title, text = text, delay = delay, isWarning = isWarning }; } [IteratorStateMachine(typeof(<ShowTipAfterDelay>d__2))] 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__2(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_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: 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_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: 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_01b8: 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) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: 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_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016f: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_032c: 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, true); } 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 _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 }; internal static ConcurrentDictionary<ulong, bool> DroppedConnections = new ConcurrentDictionary<ulong, bool>(); private static readonly Stopwatch ConnectionStopwatch = new Stopwatch(); private static int QueuedClients => ConnectionQueue.Count + (ConnectionEvents.ConnectingClientId.HasValue ? 1 : 0); internal static void Init() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(StartOfRound), "SyncAlreadyHeldObjectsServerRpc", (Type[])null, (Type[])null); if (RPCUtils.TryGetRpcID(methodInfo, out var rpcID)) { MethodInfo methodInfo2 = AccessTools.Method(typeof(StartOfRound), $"__rpc_handler_{rpcID}", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(JoinQueuePatches), "OnSyncAlreadyHeldObjectsServerRpc", (Type[])null, (Type[])null); LobbyControl.Harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null); } else { LobbyControl.Log.LogFatal((object)"Could not find RPC id for SyncAlreadyHeldObjectsServerRpc"); } methodInfo = AccessTools.Method(typeof(PlayerControllerB), "SendNewPlayerValuesServerRpc", (Type[])null, (Type[])null); if (RPCUtils.TryGetRpcID(methodInfo, out rpcID)) { MethodInfo methodInfo4 = AccessTools.Method(typeof(PlayerControllerB), $"__rpc_handler_{rpcID}", (Type[])null, (Type[])null); MethodInfo methodInfo5 = AccessTools.Method(typeof(JoinQueuePatches), "OnSendNewPlayerValuesServerRpc", (Type[])null, (Type[])null); LobbyControl.Harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo5), (HarmonyMethod)null); } else { LobbyControl.Log.LogFatal((object)"Could not find RPC id for SendNewPlayerValuesServerRpc"); } methodInfo = AccessTools.Method(typeof(HUDManager), "SyncAllPlayerLevelsServerRpc", new Type[2] { typeof(int), typeof(int) }, (Type[])null); if (RPCUtils.TryGetRpcID(methodInfo, out rpcID)) { MethodInfo methodInfo6 = AccessTools.Method(typeof(HUDManager), $"__rpc_handler_{rpcID}", (Type[])null, (Type[])null); MethodInfo methodInfo7 = AccessTools.Method(typeof(JoinQueuePatches), "OnSyncAllPlayerLevelsServerRpc", (Type[])null, (Type[])null); LobbyControl.Harmony.Patch((MethodBase)methodInfo6, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo7), (HarmonyMethod)null); } else { LobbyControl.Log.LogFatal((object)"Could not find RPC id for SyncAllPlayerLevelsServerRpc"); } ConnectionEvents.OnConnectionCompletedServer += OnConnectionCompletedServer; MethodInfo methodInfo8 = AccessTools.Method(typeof(StartOfRound), "StartGame", (Type[])null, (Type[])null); if (methodInfo8 != null) { LobbyControl.Hooks.Add(new Hook((MethodBase)methodInfo8, (Delegate)new Action<Action<StartOfRound>, StartOfRound>(CheckValidStart), new HookConfig { Priority = 999 })); } else { LobbyControl.Log.LogFatal((object)"Cannot apply patch to StartGame"); } }