Please disclose if any significant portion of your mod was created 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 UEXP Dedicated Client v1.0.3
UEXP_Dedicated_Client.dll
Decompiled 21 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Entiffo.UEXPDedicatedClient.Config; using Entiffo.UEXPDedicatedClient.Patches; using Entiffo.UEXPDedicatedClient.Util; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Steamworks; using Steamworks.Data; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("UEXP_Dedicated_Client")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3")] [assembly: AssemblyProduct("UEXP_Dedicated_Client")] [assembly: AssemblyTitle("UEXP_Dedicated_Client")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 Entiffo.UEXPDedicatedClient { [BepInPlugin("Entiffo.UEXP_Dedicated_Client", "UEXP_Dedicated_Client", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGuid = "Entiffo.UEXP_Dedicated_Client"; public const string MoreCompanyGuid = "me.swipez.melonloader.morecompany"; private readonly Harmony _harmony = new Harmony("Entiffo.UEXP_Dedicated_Client"); private static bool _moreCompanyResizePatched; private static bool _moreCompanyUpdateBoxPatched; internal static Plugin Instance { get; private set; } internal static ModConfig Config { get; private set; } internal static ManualLogSource Log { get; private set; } private static bool MoreCompanyGuardsFullyPatched { get { if (_moreCompanyResizePatched) { return _moreCompanyUpdateBoxPatched; } return false; } } internal static bool IsEnabled => Config.Enabled.Value; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Config = new ModConfig(((BaseUnityPlugin)this).Config); try { GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null)) { string name = ((Object)val).name; switch (name) { case "UEXP_PasswordPrompt": case "UEXP_ModsModal": case "UEXP_OrbitQueue": case "UEXP_EventSystem": case "UEXP_GameplayInputRestore": Log.LogWarning((object)("Destroying leftover UI object from older build: " + name)); Object.Destroy((Object)(object)val); break; } } } } catch { } if (!IsEnabled) { Log.LogInfo((object)"UEXP_Dedicated_Client 1.0.3 is DISABLED (General.Enabled=false). Vanilla menus/join. Set Enabled=true and restart for dedicated client features."); return; } Type[] types = typeof(Plugin).Assembly.GetTypes(); foreach (Type type in types) { if (Attribute.GetCustomAttribute(type, typeof(HarmonyPatch)) != null) { try { _harmony.CreateClassProcessor(type).Patch(); } catch (Exception ex) { Log.LogWarning((object)("Harmony skip " + type.Name + ": " + ex.Message)); } } } TryPatchMoreCompanyGuards(); if (Config.EnableQuatSpamProbe.Value) { QuatSpamProbe.EnsureHooked(); } QuatUnityLogFilter.TryPatch(_harmony); OpenBodyCamsGhostGuard.TryPatch(_harmony); try { SteamMatchmaking.OnLobbyEntered += MoreCompanyLobbyMatch.OnSteamLobbyEntered; SteamFriends.OnGameLobbyJoinRequested += delegate(Lobby lobby, SteamId _) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) MoreCompanyLobbyMatch.OnSteamLobbyEntered(lobby); }; } catch (Exception ex2) { Log.LogWarning((object)("Steam lobby crew hooks failed: " + ex2.Message)); } Log.LogInfo((object)"UEXP_Dedicated_Client 1.0.3 loaded. Install on every joiner of a UEXP dedicated lobby."); } private void TryPatchMoreCompanyGuards() { TryPatchMoreCompanyGuardsRetry("Awake"); } internal static void TryPatchMoreCompanyGuardsRetry(string reason) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown if (MoreCompanyGuardsFullyPatched || (Object)(object)Instance == (Object)null) { return; } try { Type type = AccessTools.TypeByName("MoreCompany.MainClass"); if (type == null) { if (reason == "Awake") { Log.LogInfo((object)"MoreCompany not loaded yet — ResizeGuard will retry on dedicated join."); } return; } if (!_moreCompanyResizePatched) { MethodBase methodBase = AccessTools.Method(type, "ResizePlayerCache", (Type[])null, (Type[])null); if (methodBase != null) { Instance._harmony.Patch(methodBase, new HarmonyMethod(typeof(MoreCompanyResizeGuardPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _moreCompanyResizePatched = true; Log.LogInfo((object)("MoreCompany ResizePlayerCache guard patched (" + reason + ").")); } else { Log.LogWarning((object)("MoreCompany ResizePlayerCache not found (" + reason + ").")); } } if (!_moreCompanyUpdateBoxPatched) { Type type2 = AccessTools.TypeByName("MoreCompany.MenuManagerHost"); MethodBase methodBase2 = ((type2 == null) ? null : AccessTools.Method(type2, "UpdateTextBox", new Type[2] { typeof(TMP_InputField), typeof(string) }, (Type[])null)); if (methodBase2 != null) { Instance._harmony.Patch(methodBase2, new HarmonyMethod(typeof(MoreCompanyCrewCountUiGuardPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _moreCompanyUpdateBoxPatched = true; Log.LogInfo((object)("MoreCompany UpdateTextBox guard patched (" + reason + ").")); } else if (type2 != null) { Log.LogWarning((object)("MoreCompany UpdateTextBox not found (" + reason + ") — will retry on dedicated join.")); } } if (!MoreCompanyGuardsFullyPatched && reason != "Awake") { Log.LogWarning((object)("MoreCompany guards incomplete (" + reason + "): " + $"resize={_moreCompanyResizePatched} updateBox={_moreCompanyUpdateBoxPatched}")); } } catch (Exception ex) { Log.LogWarning((object)("MoreCompany manual guards failed (" + reason + "): " + ex.Message)); } } internal static void DebugLog(string message) { if (Config.DebugLogging.Value) { Log.LogInfo((object)message); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Entiffo.UEXP_Dedicated_Client"; public const string PLUGIN_NAME = "UEXP_Dedicated_Client"; public const string PLUGIN_VERSION = "1.0.3"; } } namespace Entiffo.UEXPDedicatedClient.Util { public static class DedicatedLobby { public const string FlagKey = "uexpDedicated"; public const string FlagValue = "1"; public const string VerKey = "uexpDedicatedVer"; public const string ReqClientKey = "uexpReqClient"; public const string MaxKey = "uexpMax"; public const string HumansKey = "uexpHumans"; public const string ModCountKey = "uexpModN"; public const string ModsKey = "uexpMods"; public const string ModsKey2 = "uexpMods2"; public const string HasPassKey = "uexpHasPass"; public const string PassHashKey = "uexpPassHash"; public const string ProfileCodeKey = "uexpProfile"; public const string PhaseKey = "uexpPhase"; public const string MoonKey = "uexpMoon"; public const string RiskKey = "uexpRisk"; public const string WeatherKey = "uexpWeather"; public const string DayKey = "uexpDay"; public const string QuotaKey = "uexpQuota"; public const string TipKey = "uexpTip"; public const string MotdKey = "uexpMotd"; public const string TimeKey = "uexpTime"; public const string QueueableKey = "uexpQueueable"; public const string QueueCountKey = "uexpQueueN"; public const string AdmitKey = "uexpAdmit"; public const string MemberQueueKey = "uexpQ"; public const string QueueDenyKey = "uexpQDeny"; public const string BanHintsKey = "uexpBanHints"; public const string MinLeaveKey = "uexpMinLeave"; private static bool _sessionDedicated; private const string RoleSyncLobbyKey = "uexpRoles"; public static bool SessionLatched => _sessionDedicated; public static bool IsCurrentLobbyDedicated() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (_sessionDedicated) { return true; } try { GameNetworkManager instance = GameNetworkManager.Instance; if ((Object)(object)instance == (Object)null || instance.disableSteam || !instance.currentLobby.HasValue) { return false; } if (!IsDedicatedLobby(instance.currentLobby.Value)) { return false; } MarkSessionDedicated("lobby data"); return true; } catch { return false; } } public static void MarkSessionDedicated(string reason = "") { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (_sessionDedicated) { return; } _sessionDedicated = true; Plugin.DebugLog("Dedicated session latched" + (string.IsNullOrEmpty(reason) ? "" : (" (" + reason + ")")) + "."); try { if (Plugin.Config != null && Plugin.Config.EnableQuatSpamProbe.Value) { QuatSpamProbe.EnsureHooked(); QuatSpamProbe.Arm("dedicated latch" + (string.IsNullOrEmpty(reason) ? "" : (":" + reason))); } OpenBodyCamsGhostGuard.TryPatch(new Harmony("Entiffo.UEXP_Dedicated_Client.obc-retry")); } catch { } } public static void ClearSessionDedicated(string reason = "") { if (!_sessionDedicated) { return; } _sessionDedicated = false; Plugin.DebugLog("Dedicated session cleared" + (string.IsNullOrEmpty(reason) ? "" : (" (" + reason + ")")) + "."); try { QuatSpamProbe.ClearSession(); HostBodyHidePatches.ResetHideLatch(); GhostSeatLateJoinEnforcer.ResetSession(); } catch { } } public static bool IsDedicatedLobby(Lobby lobby) { try { return ((Lobby)(ref lobby)).GetData("uexpDedicated") == "1"; } catch { return false; } } public static bool TryGetClientVersionMismatch(Lobby lobby, out string message) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) message = ""; try { if (!IsDedicatedLobby(lobby)) { return false; } try { ((Lobby)(ref lobby)).Refresh(); } catch { } string text = ReadData(lobby, "uexpReqClient").Trim(); if (string.IsNullOrEmpty(text)) { return false; } string text2 = "1.0.3"; string text3 = ReadData(lobby, "uexpDedicatedVer").Trim(); string text4 = (string.IsNullOrEmpty(text3) ? "" : (" (host " + text3 + ")")); if (!TryCompareVersions(text2, text, out var cmp)) { message = "UEXP Dedicated Client version unreadable.\nYou have v" + text2 + ". This server needs v" + text + text4 + ".\nUpdate the client from the UEXP site (lethal.uexp.org), then rejoin."; return true; } if (cmp < 0) { message = "UEXP Dedicated Client is outdated.\nYou have v" + text2 + ". This server needs v" + text + text4 + ".\nUpdate the client from the UEXP site (lethal.uexp.org), then rejoin."; return true; } if (cmp > 0) { message = "This dedicated host is outdated.\nServer expects client v" + text + text4 + "; you have v" + text2 + ".\nWait until the host administrator updates the server."; return true; } return false; } catch { return false; } } public static string FormatBrowserHostVersionBadge(Lobby lobby) { //IL_0000: 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) try { string text = ReadData(lobby, "uexpDedicatedVer").Trim(); if (string.IsNullOrEmpty(text)) { return ""; } string text2 = "host " + text; string text3 = ReadData(lobby, "uexpReqClient").Trim(); string a = "1.0.3"; if (string.IsNullOrEmpty(text3)) { return "<color=#E8A04A>" + text2 + "</color>"; } if (!TryCompareVersions(a, text3, out var cmp)) { return "<color=#C84A3A>" + text2 + "</color>"; } if (cmp == 0) { return "<color=#6FBF4A>" + text2 + "</color>"; } return "<color=#C84A3A>" + text2 + "</color>"; } catch { return ""; } } private static bool TryCompareVersions(string a, string b, out int cmp) { cmp = 0; try { if (!Version.TryParse(NormalizeVersion(a), out Version result) || !Version.TryParse(NormalizeVersion(b), out Version result2) || result == null || result2 == null) { return false; } cmp = result.CompareTo(result2); return true; } catch { return false; } } private static string NormalizeVersion(string v) { string text = (v ?? "").Trim(); int num = 0; for (int i = 0; i < text.Length; i++) { if (text[i] == '.') { num++; } } return num switch { 0 => text + ".0", 1 => text + ".0", _ => text, }; } public static bool IsQueueableLobby(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { return IsDedicatedLobby(lobby) && ((Lobby)(ref lobby)).GetData("uexpQueueable") == "1"; } catch { return false; } } public static bool IsJoinableListing(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) try { if (!IsDedicatedLobby(lobby)) { return false; } if (((Lobby)(ref lobby)).GetData("started") == "1") { return false; } if (((Lobby)(ref lobby)).GetData("joinable") == "false") { return false; } if (IsQueueableLobby(lobby)) { return true; } int num = DisplayMemberCount(lobby); int num2 = ReadHumanCapacity(lobby); if (num2 > 0 && num >= num2) { return false; } return true; } catch { return false; } } public static int DisplayMemberCount(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return DisplayMemberCountExcludingQueue(lobby); } public static int DisplayMemberCountExcludingQueue(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) try { if (!IsDedicatedLobby(lobby)) { return ((Lobby)(ref lobby)).MemberCount; } string data = ((Lobby)(ref lobby)).GetData("uexpHumans"); if (!string.IsNullOrEmpty(data) && int.TryParse(data, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= 0) { return result; } SteamId id = ((Lobby)(ref lobby)).Owner.Id; int num = 0; foreach (Friend member in ((Lobby)(ref lobby)).Members) { if (SteamId.op_Implicit(member.Id) != SteamId.op_Implicit(id)) { string value = null; try { value = ((Lobby)(ref lobby)).GetMemberData(member, "uexpQ"); } catch { } if (string.IsNullOrEmpty(value)) { num++; } } } return num; } catch { try { string data2 = ((Lobby)(ref lobby)).GetData("uexpHumans"); if (!string.IsNullOrEmpty(data2) && int.TryParse(data2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && result2 >= 0) { return result2; } } catch { } int memberCount = ((Lobby)(ref lobby)).MemberCount; return (memberCount > 0) ? (memberCount - 1) : 0; } } public static int ReadHumanCapacity(Lobby lobby) { try { string data = ((Lobby)(ref lobby)).GetData("uexpMax"); if (!string.IsNullOrEmpty(data) && int.TryParse(data, out var result) && result > 0) { return result; } } catch { } return 3; } public static int ReadQueueCount(Lobby lobby) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) try { string data = ((Lobby)(ref lobby)).GetData("uexpQueueN"); if (!string.IsNullOrEmpty(data) && int.TryParse(data, out var result) && result >= 0) { return result; } } catch { } return CountQueuedMembers(lobby); } public static int CountQueuedMembers(Lobby lobby) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) int num = 0; try { SteamId id = ((Lobby)(ref lobby)).Owner.Id; foreach (Friend member in ((Lobby)(ref lobby)).Members) { if (SteamId.op_Implicit(member.Id) != SteamId.op_Implicit(id)) { string text = null; try { text = ((Lobby)(ref lobby)).GetMemberData(member, "uexpQ"); } catch { continue; } if (!string.IsNullOrEmpty(text)) { num++; } } } } catch { } return num; } public static void ReadLocalQueuePosition(Lobby lobby, long localStamp, out int position, out int total) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) position = 0; total = 0; try { SteamId self = SteamClient.SteamId; SteamId id = ((Lobby)(ref lobby)).Owner.Id; List<(SteamId, long, int)> list = new List<(SteamId, long, int)>(); foreach (Friend member in ((Lobby)(ref lobby)).Members) { if (SteamId.op_Implicit(member.Id) == SteamId.op_Implicit(id)) { continue; } string text = null; try { text = ((Lobby)(ref lobby)).GetMemberData(member, "uexpQ"); } catch { continue; } if (!string.IsNullOrWhiteSpace(text)) { if (!long.TryParse(text.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { result = 0L; } list.Add((member.Id, result, QueuePriorityRank(lobby, SteamId.op_Implicit(member.Id)))); } } list = (from s in list orderby s.Prio, s.Ts, s.Id.Value select s).ToList(); total = list.Count; for (int num = 0; num < list.Count; num++) { if (SteamId.op_Implicit(list[num].Item1) == SteamId.op_Implicit(self)) { position = num + 1; return; } } if (localStamp > 0) { int myPrio = QueuePriorityRank(lobby, SteamId.op_Implicit(self)); int num2 = list.Count<(SteamId, long, int)>(((SteamId Id, long Ts, int Prio) s) => s.Prio < myPrio || (s.Prio == myPrio && (s.Ts < localStamp || (s.Ts == localStamp && s.Id.Value < self.Value)))); position = num2 + 1; total = Math.Max(total + 1, position); } } catch { position = 0; total = 0; } } public static int QueuePriorityRank(Lobby lobby, ulong steamId) { if (steamId == 0L) { return 3; } if (DeveloperRoster.IsDeveloper(steamId)) { return 0; } try { string text = ((Lobby)(ref lobby)).GetData("uexpRoles") ?? ""; if (!string.IsNullOrWhiteSpace(text)) { string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); int num = text2.IndexOf('='); if (num > 0 && ulong.TryParse(text2.Substring(0, num).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result == steamId) { string text3 = text2.Substring(num + 1).Trim().ToLowerInvariant(); if (text3.StartsWith("a")) { return 1; } if (text3.StartsWith("m")) { return 2; } } } } } catch { } return 3; } public static int ReadModCount(Lobby lobby) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) try { string data = ((Lobby)(ref lobby)).GetData("uexpModN"); if (!string.IsNullOrEmpty(data) && int.TryParse(data, out var result)) { return result; } } catch { } string text = ReadModList(lobby); if (string.IsNullOrWhiteSpace(text)) { return 0; } return text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries).Length; } public static string ReadModList(Lobby lobby) { try { string text = ((Lobby)(ref lobby)).GetData("uexpMods") ?? ""; string text2 = ((Lobby)(ref lobby)).GetData("uexpMods2") ?? ""; if (string.IsNullOrEmpty(text)) { return text2 ?? ""; } if (string.IsNullOrEmpty(text2)) { return text; } return text + ";" + text2; } catch { return ""; } } public static string ReadData(Lobby lobby, string key) { try { return ((Lobby)(ref lobby)).GetData(key) ?? ""; } catch { return ""; } } public static string ReadProfileCode(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return ReadData(lobby, "uexpProfile"); } public static string ReadMotd(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return ReadData(lobby, "uexpMotd").Trim(); } public static bool TryGetLocalBanRemaining(Lobby lobby, out TimeSpan remaining, out bool permanent) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) remaining = TimeSpan.Zero; permanent = false; try { string text = ReadData(lobby, "uexpBanHints"); if (string.IsNullOrWhiteSpace(text)) { return false; } ulong num = SteamId.op_Implicit(SteamClient.SteamId); if (num == 0L) { return false; } string value = num.ToString(CultureInfo.InvariantCulture); string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Trim().Split(':'); if (array2.Length == 2 && array2[0].Equals(value, StringComparison.OrdinalIgnoreCase) && long.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { if (result < 0) { permanent = true; remaining = TimeSpan.MaxValue; return true; } DateTimeOffset dateTimeOffset = new DateTimeOffset(result, TimeSpan.Zero); remaining = dateTimeOffset - DateTimeOffset.UtcNow; if (remaining <= TimeSpan.Zero) { return false; } return true; } } } catch { } return false; } public static string FormatBanCountdown(TimeSpan remaining) { if (remaining == TimeSpan.MaxValue || remaining.TotalDays > 3650.0) { return "permanently"; } int num = (int)Math.Ceiling(remaining.TotalMinutes); if (num < 1) { num = 1; } int num2 = num / 60; int num3 = num % 60; if (num2 <= 0) { if (num3 != 1) { return $"{num3} minutes"; } return "1 minute"; } if (num3 == 0) { if (num2 != 1) { return $"{num2} hours"; } return "1 hour"; } return $"{num2}h {num3}m"; } public static string ReadSessionTip(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) string text = ReadData(lobby, "uexpTip").Trim(); string text2 = ReadData(lobby, "uexpPhase"); string text3 = ReadData(lobby, "uexpMoon"); string text4 = ReadData(lobby, "uexpRisk"); string text5 = ReadData(lobby, "uexpWeather"); string text6 = ReadData(lobby, "uexpDay"); string text7 = ReadData(lobby, "uexpQuota"); string text8 = ReadData(lobby, "uexpTime"); bool flag = text.Equals("starting up", StringComparison.OrdinalIgnoreCase) || text.Equals("hosting…", StringComparison.OrdinalIgnoreCase) || text.Equals("hosting...", StringComparison.OrdinalIgnoreCase); bool flag2 = (!string.IsNullOrEmpty(text2) && text2 != "boot") || !string.IsNullOrEmpty(text3) || !string.IsNullOrEmpty(text6) || !string.IsNullOrEmpty(text7) || !string.IsNullOrEmpty(text8); bool flag3 = !string.IsNullOrEmpty(ReadData(lobby, "uexpMax")) || !string.IsNullOrEmpty(ReadData(lobby, "uexpHumans")); if (!string.IsNullOrWhiteSpace(text) && (!flag || !(flag2 || flag3))) { return text; } List<string> list = new List<string>(6); if (text2 == "orbit" || (string.IsNullOrEmpty(text2) && flag3 && !flag2)) { list.Add(string.IsNullOrEmpty(text3) ? "in orbit" : ("orbit · " + text3)); } else if (text2 == "landing") { list.Add(string.IsNullOrEmpty(text3) ? "landing…" : ("landing · " + text3)); if (!string.IsNullOrEmpty(text4)) { list.Add(text4); } } else if (text2 == "moon") { if (!string.IsNullOrEmpty(text3)) { list.Add(text3); } else { list.Add("on moon"); } if (!string.IsNullOrEmpty(text4)) { list.Add(text4); } if (!string.IsNullOrEmpty(text5)) { list.Add(text5); } } else { if (flag && !flag2 && !flag3) { if (text.Length <= 0) { return "starting up"; } return text; } if (flag3) { list.Add("in orbit"); } } if (!string.IsNullOrEmpty(text6)) { list.Add(text6); } if (!string.IsNullOrEmpty(text8)) { list.Add(text8); } if (!string.IsNullOrEmpty(text7)) { list.Add("quota " + text7); } string text9 = string.Join(" · ", list); if (!string.IsNullOrEmpty(text9)) { return text9; } if (!string.IsNullOrEmpty(text)) { return text; } return "in orbit"; } public static bool RequiresPassword(Lobby lobby) { try { return ((Lobby)(ref lobby)).GetData("uexpHasPass") == "1" && !string.IsNullOrEmpty(((Lobby)(ref lobby)).GetData("uexpPassHash")); } catch { return false; } } public static string ExpectedPasswordHash(Lobby lobby) { try { return ((Lobby)(ref lobby)).GetData("uexpPassHash") ?? ""; } catch { return ""; } } } internal static class DeveloperRoster { public const ulong EntiffoSteamId = 76561198051556575uL; private static readonly HashSet<ulong> Ids = new HashSet<ulong> { 76561198051556575uL }; public static bool IsDeveloper(ulong steamId) { if (steamId != 0L) { return Ids.Contains(steamId); } return false; } public static IReadOnlyCollection<ulong> Snapshot() { return Ids; } } } namespace Entiffo.UEXPDedicatedClient.Patches { internal static class AdminOpsClient { public const string HealPrefix = "[UEXP]heal:"; public const string TpPrefix = "[UEXP]tp:"; public const string MutePrefix = "[UEXP]mute:"; public const string WeatherPrefix = "[UEXP]weather:"; public const string QuotaPrefix = "[UEXP]quota:"; private static readonly HashSet<ulong> MutedSteamIds = new HashSet<ulong>(); public static bool TryHandleSystemMessage(string? chatMessage) { if (string.IsNullOrEmpty(chatMessage)) { return false; } if (chatMessage.StartsWith("[UEXP]heal:", StringComparison.Ordinal)) { ApplyHeal(chatMessage.Substring("[UEXP]heal:".Length).Trim()); return true; } if (chatMessage.StartsWith("[UEXP]tp:", StringComparison.Ordinal)) { ApplyTp(chatMessage.Substring("[UEXP]tp:".Length).Trim()); return true; } if (chatMessage.StartsWith("[UEXP]mute:", StringComparison.Ordinal)) { ApplyMute(chatMessage.Substring("[UEXP]mute:".Length).Trim()); return true; } if (chatMessage.StartsWith("[UEXP]weather:", StringComparison.Ordinal)) { ApplyWeather(chatMessage.Substring("[UEXP]weather:".Length).Trim()); return true; } if (chatMessage.StartsWith("[UEXP]quota:", StringComparison.Ordinal)) { ApplyQuota(chatMessage.Substring("[UEXP]quota:".Length).Trim()); return true; } return false; } public static bool TryHandleWarnWhisper(string? chatMessage) { if (string.IsNullOrEmpty(chatMessage)) { return false; } if (!chatMessage.StartsWith("[WARN]@", StringComparison.OrdinalIgnoreCase)) { return false; } string text = chatMessage.Substring("[WARN]@".Length); int num = text.IndexOf('|'); if (num <= 0) { return true; } string s = text.Substring(0, num).Trim(); string text2 = text.Substring(num + 1).Trim(); if (!ulong.TryParse(s, out var result) || result == 0L) { return true; } try { ulong num2 = LocalSteam(); if (num2 != 0L && num2 == result && !string.IsNullOrEmpty(text2)) { HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip("Warning", Truncate(text2, 120), true, false, "UEXP_Warn"); } } } catch { } return true; } public static bool IsSteamMuted(ulong steam) { if (steam != 0L) { return MutedSteamIds.Contains(steam); } return false; } private static void ApplyHeal(string rest) { string[] array = rest.Split(':'); if (array.Length < 1 || !int.TryParse(array[0].Trim(), out var result)) { return; } int num = 100; if (array.Length >= 2 && int.TryParse(array[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && result2 > 0) { num = result2; } StartOfRound instance = StartOfRound.Instance; if (instance?.allPlayerScripts == null || result < 0 || result >= instance.allPlayerScripts.Length) { return; } PlayerControllerB val = instance.allPlayerScripts[result]; if ((Object)(object)val == (Object)null || val.isPlayerDead) { return; } try { val.health = num; val.criticallyInjured = false; val.hasBeenCriticallyInjured = false; val.bleedingHeavily = false; try { val.MakeCriticallyInjured(false); } catch { } if ((Object)(object)val.playerBodyAnimator != (Object)null) { val.playerBodyAnimator.SetBool("Limp", false); } if (((NetworkBehaviour)val).IsOwner) { HUDManager instance2 = HUDManager.Instance; if (instance2 != null) { instance2.UpdateHealthUI(num, false); } } } catch (Exception ex) { Plugin.DebugLog("Client heal: " + ex.Message); } } private static void ApplyTp(string rest) { //IL_0100: Unknown result type (might be due to invalid IL or missing references) string[] array = rest.Split(':'); if (array.Length < 7 || !int.TryParse(array[0], out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4)) { return; } bool isInElevator = array[4] == "1"; bool isInHangarShipRoom = array[5] == "1"; bool isInsideFactory = array[6] == "1"; StartOfRound instance = StartOfRound.Instance; if (instance?.allPlayerScripts == null || result < 0 || result >= instance.allPlayerScripts.Length) { return; } PlayerControllerB val = instance.allPlayerScripts[result]; if ((Object)(object)val == (Object)null || val.isPlayerDead) { return; } try { Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(result2, result3, result4); val.isInElevator = isInElevator; val.isInHangarShipRoom = isInHangarShipRoom; val.isInsideFactory = isInsideFactory; val.TeleportPlayer(val2, false, 0f, false, true); val.teleportingThisFrame = true; } catch (Exception ex) { Plugin.DebugLog("Client tp: " + ex.Message); } } private static void ApplyMute(string rest) { string[] array = rest.Split(':'); if (array.Length >= 2 && ulong.TryParse(array[0].Trim(), out var result) && result != 0L) { if (array[1].Trim() == "1") { MutedSteamIds.Add(result); } else { MutedSteamIds.Remove(result); } ApplyVoiceMuteState(); } } private static void ApplyWeather(string rest) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected I4, but got Unknown if (!Enum.TryParse<LevelWeatherType>(rest, ignoreCase: true, out LevelWeatherType result)) { return; } TimeOfDay instance = TimeOfDay.Instance; StartOfRound instance2 = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return; } try { DisableAllWeatherFully(instance); instance.currentWeatherVariable = 0f; instance.currentWeatherVariable2 = 0f; instance.currentLevelWeather = result; if ((Object)(object)instance2.currentLevel != (Object)null) { instance2.currentLevel.currentWeather = result; } if ((int)result == -1) { StopStormyLightningResidue(); return; } int num = (int)result; if (instance.effects == null || num < 0 || num >= instance.effects.Length) { return; } WeatherEffect val = instance.effects[num]; if (val != null) { val.effectEnabled = true; val.transitioning = false; if ((Object)(object)val.effectObject != (Object)null) { val.effectObject.SetActive(true); } if ((Object)(object)val.effectPermanentObject != (Object)null) { val.effectPermanentObject.SetActive(true); } } } catch (Exception ex) { Plugin.DebugLog("Client weather: " + ex.Message); } } private static void DisableAllWeatherFully(TimeOfDay tod) { if (tod?.effects == null) { return; } try { tod.DisableAllWeather(true); } catch { } for (int i = 0; i < tod.effects.Length; i++) { WeatherEffect val = tod.effects[i]; if (val == null) { continue; } try { val.effectEnabled = false; val.transitioning = false; if ((Object)(object)val.effectObject != (Object)null) { val.effectObject.SetActive(false); } if ((Object)(object)val.effectPermanentObject != (Object)null) { val.effectPermanentObject.SetActive(false); } } catch { } } } private static void StopStormyLightningResidue() { try { StormyWeather val = Object.FindObjectOfType<StormyWeather>(true); if ((Object)(object)val == (Object)null) { return; } try { if ((Object)(object)val.staticElectricityParticle != (Object)null) { val.staticElectricityParticle.Stop(true, (ParticleSystemStopBehavior)0); AudioSource component = ((Component)val.staticElectricityParticle).GetComponent<AudioSource>(); if ((Object)(object)component != (Object)null) { component.Stop(); } } } catch { } if ((Object)(object)((Component)val).gameObject != (Object)null && ((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(false); } } catch (Exception ex) { Plugin.DebugLog("StopStormyLightningResidue: " + ex.Message); } } private static void ApplyQuota(string rest) { if (!int.TryParse(rest, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return; } TimeOfDay instance = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null) { return; } try { instance.profitQuota = result; try { instance.UpdateProfitQuotaCurrentTime(); } catch { } } catch { } } internal static void ApplyVoiceMuteState() { StartOfRound instance = StartOfRound.Instance; SoundManager instance2 = SoundManager.Instance; if (instance?.allPlayerScripts == null || instance2?.playerVoiceVolumes == null) { return; } for (int i = 0; i < instance.allPlayerScripts.Length; i++) { PlayerControllerB val = instance.allPlayerScripts[i]; if (!((Object)(object)val == (Object)null) && val.playerSteamId != 0L && MutedSteamIds.Contains(val.playerSteamId) && i >= 0 && i < instance2.playerVoiceVolumes.Length) { instance2.playerVoiceVolumes[i] = 0f; } } } private static ulong LocalSteam() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null) { return GameNetworkManager.Instance.localPlayerController.playerSteamId; } } catch { } try { return SteamId.op_Implicit(SteamClient.SteamId); } catch { return 0uL; } } private static string Truncate(string s, int max) { if (string.IsNullOrEmpty(s) || s.Length <= max) { return s; } return s.Substring(0, max - 1) + "…"; } } [HarmonyPatch(typeof(HUDManager), "AddChatMessage")] internal static class AdminOpsSignalPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(string chatMessage, string nameOfUserWhoTyped) { if (!Plugin.IsEnabled) { return true; } if (!string.IsNullOrEmpty(nameOfUserWhoTyped)) { return true; } if (AdminOpsClient.TryHandleWarnWhisper(chatMessage)) { return false; } if (AdminOpsClient.TryHandleSystemMessage(chatMessage)) { return false; } return true; } } [HarmonyPatch(typeof(SoundManager), "SetPlayerVoiceFilters")] internal static class MuteVoiceFilterPatch { [HarmonyPrefix] private static void Prefix() { if (Plugin.IsEnabled) { AdminOpsClient.ApplyVoiceMuteState(); } } } [HarmonyPatch] internal static class AutoOnlineLaunchPatches { private static bool _chose; private static bool _settingsLoaded; [HarmonyPatch(typeof(IngamePlayerSettings), "LoadSettingsFromPrefs")] [HarmonyPostfix] private static void LoadSettingsFromPrefs_Postfix(IngamePlayerSettings __instance) { if (!Plugin.IsEnabled || !Plugin.Config.AutoSelectOnlineMode.Value) { return; } _settingsLoaded = true; try { if (__instance.unsavedSettings != null && __instance.settings != null) { __instance.unsavedSettings.CopySettings(__instance.settings); } } catch { } TrySafeOnline("LoadSettingsFromPrefs"); } [HarmonyPatch(typeof(PreInitSceneScript), "Start")] [HarmonyPostfix] private static void Start_Postfix(PreInitSceneScript __instance) { if (Plugin.IsEnabled && Plugin.Config.AutoSelectOnlineMode.Value) { HideLaunchOptionUi(__instance); TrySafeOnline("Start"); } } [HarmonyPatch(typeof(PreInitSceneScript), "SkipToFinalSetting")] [HarmonyPostfix] private static void SkipToFinalSetting_Postfix(PreInitSceneScript __instance) { if (Plugin.IsEnabled && Plugin.Config.AutoSelectOnlineMode.Value) { TrySafeOnline("SkipToFinalSetting"); } } [HarmonyPatch(typeof(PreInitSceneScript), "PressContinueButton")] [HarmonyPostfix] private static void PressContinue_Postfix(PreInitSceneScript __instance) { if (Plugin.IsEnabled && Plugin.Config.AutoSelectOnlineMode.Value) { TrySafeOnline("PressContinue"); } } [HarmonyPatch(typeof(PreInitSceneScript), "ChooseLaunchOption")] [HarmonyPrefix] private static bool ChooseLaunchOption_Prefix(PreInitSceneScript __instance, bool online) { if (!Plugin.IsEnabled) { return true; } return !TryChooseLaunchWithoutSavingSettings(__instance, online, "vanilla-click"); } private static void TrySafeOnline(string reason) { if (_chose) { return; } PreInitSceneScript val = Object.FindObjectOfType<PreInitSceneScript>(); if (!((Object)(object)val == (Object)null)) { HideLaunchOptionUi(val); if (_settingsLoaded && TryChooseLaunchWithoutSavingSettings(val, online: true, reason)) { _chose = true; } } } private static bool TryChooseLaunchWithoutSavingSettings(PreInitSceneScript pre, bool online, string reason) { if ((Object)(object)pre == (Object)null || pre.choseLaunchOption) { return false; } try { IngamePlayerSettings instance = IngamePlayerSettings.Instance; if ((Object)(object)instance != (Object)null) { if (_settingsLoaded && instance.unsavedSettings != null && instance.settings != null) { instance.unsavedSettings.CopySettings(instance.settings); } try { instance.SetLaunchInOnlineMode(online); } catch { } try { instance.SetPlayerFinishedLaunchOptions(); } catch { } } pre.choseLaunchOption = true; try { if ((Object)(object)pre.mainAudio != (Object)null && (Object)(object)pre.selectSFX != (Object)null) { pre.mainAudio.PlayOneShot(pre.selectSFX); } } catch { } Plugin.Log.LogInfo((object)("UEXP_Dedicated_Client: online launch without SaveChangedSettings (" + reason + ").")); if ((Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(LoadSceneDelayed(online)); } else { SceneManager.LoadScene(online ? "InitScene" : "InitSceneLANMode"); } HideLaunchOptionUi(pre); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Safe online launch failed: " + ex.Message)); return false; } } private static IEnumerator LoadSceneDelayed(bool online) { yield return (object)new WaitForSecondsRealtime(0.2f); SceneManager.LoadScene(online ? "InitScene" : "InitSceneLANMode"); } private static void HideLaunchOptionUi(PreInitSceneScript pre) { try { if ((Object)(object)pre.OnlineModeButton != (Object)null) { pre.OnlineModeButton.SetActive(false); } if (pre.LaunchSettingsPanels != null) { GameObject[] launchSettingsPanels = pre.LaunchSettingsPanels; foreach (GameObject val in launchSettingsPanels) { if ((Object)(object)val != (Object)null) { val.SetActive(false); } } } if ((Object)(object)pre.launchSettingsPanelsContainer != (Object)null) { pre.launchSettingsPanelsContainer.SetActive(false); } } catch { } } } internal static class ChatCommandHide { public static bool ShouldHidePlayerMessage(string? chatMessage) { if (string.IsNullOrWhiteSpace(chatMessage)) { return false; } string text = chatMessage.Trim(); if (text.Length == 0 || text[0] != '/') { return false; } string text2 = text.ToLowerInvariant(); if (text2 == "/login" || text2.StartsWith("/login ")) { return true; } bool flag; switch (text2) { case "/help": case "/commands": case "/?": flag = true; break; default: flag = false; break; } if (flag) { return true; } if (text2 == "/logout" || text2 == "/admin" || text2.StartsWith("/admin ")) { return true; } if (text2 == "/kick" || text2.StartsWith("/kick ")) { return true; } if (text2 == "/ban" || text2.StartsWith("/ban ")) { return true; } if (text2 == "/unban" || text2.StartsWith("/unban ")) { return true; } switch (text2) { case "/list": case "/bans": case "/mods": return true; default: if (!text2.StartsWith("/reset ")) { if (text2 == "/save" || text2.StartsWith("/save ")) { return true; } switch (text2) { case "/motd": case "/rules": case "/ping": case "/pong": return true; case "/when": return true; default: if (!text2.StartsWith("/report ")) { if (text2 == "/announce" || text2.StartsWith("/announce ")) { return true; } if (text2 == "/door" || text2.StartsWith("/door ")) { return true; } if (text2 == "/id" || text2.StartsWith("/id ") || text2 == "/ids" || text2.StartsWith("/ids ")) { return true; } if (text2 == "/tp" || text2.StartsWith("/tp ") || text2 == "/bring" || text2.StartsWith("/bring ")) { return true; } if (text2 == "/heal" || text2.StartsWith("/heal ") || text2 == "/healall") { return true; } if (text2 == "/credits" || text2.StartsWith("/credits ") || text2 == "/setquota" || text2.StartsWith("/setquota ") || text2 == "/quota" || text2.StartsWith("/quota ")) { return true; } if (text2 == "/weather" || text2.StartsWith("/weather ")) { return true; } if (text2 == "/mute" || text2.StartsWith("/mute ") || text2 == "/unmute" || text2.StartsWith("/unmute ")) { return true; } if (text2 == "/warn" || text2.StartsWith("/warn ") || text2 == "/warns" || text2.StartsWith("/warns ") || text2 == "/clearwarns" || text2.StartsWith("/clearwarns ")) { return true; } if (text2 == "/mod" || text2.StartsWith("/mod ") || text2 == "/unmod" || text2.StartsWith("/unmod ")) { return true; } if (text2 == "/vote" || text2.StartsWith("/vote ")) { return true; } if (text2 == "/votekick" || text2.StartsWith("/votekick ") || text2 == "/vk" || text2.StartsWith("/vk ")) { return true; } switch (text2) { case "/yes": case "/y": case "/no": case "/n": flag = true; break; default: flag = false; break; } if (flag) { return true; } if (text2 == "/dev" || text2.StartsWith("/dev")) { return true; } return false; } goto case "/report"; case "/report": return true; } } goto case "/reset"; case "/reset": return true; } } } [HarmonyPatch(typeof(HUDManager), "AddChatMessage")] internal static class HideSlashCommandLocalEchoPatch { [HarmonyPrefix] private static bool Prefix(string chatMessage, string nameOfUserWhoTyped) { if (!Plugin.IsEnabled) { return true; } if (string.IsNullOrEmpty(nameOfUserWhoTyped)) { return true; } if (ChatCommandHide.ShouldHidePlayerMessage(chatMessage)) { return false; } return true; } } [HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageClientRpc")] internal static class HideSlashCommandClientRpcPatch { [HarmonyPrefix] private static bool Prefix(string chatMessage) { if (!Plugin.IsEnabled) { return true; } if (ChatCommandHide.ShouldHidePlayerMessage(chatMessage)) { return false; } return true; } } [HarmonyPatch(typeof(GameNetworkManager), "SetConnectionDataBeforeConnecting")] internal static class ConnectionDataHandshakePatch { public const string Token = "uexpC1"; public const string VersionPrefix = "uexpCv"; [HarmonyPostfix] private static void Postfix() { if (!Plugin.IsEnabled) { return; } try { NetworkManager singleton = NetworkManager.Singleton; if (singleton?.NetworkConfig == null) { return; } byte[] connectionData = singleton.NetworkConfig.ConnectionData; if (connectionData == null || connectionData.Length == 0) { return; } string text = Encoding.ASCII.GetString(connectionData); string[] array = text.Split(','); bool flag = false; bool flag2 = false; for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (string.Equals(text2, "uexpC1", StringComparison.Ordinal)) { flag = true; } if (text2.StartsWith("uexpCv", StringComparison.Ordinal)) { flag2 = true; } } string text3 = text; if (!flag) { text3 += ",uexpC1"; } if (!flag2) { text3 += ",uexpCv1.0.3"; } if (!string.Equals(text3, text, StringComparison.Ordinal)) { singleton.NetworkConfig.ConnectionData = Encoding.ASCII.GetBytes(text3); Plugin.DebugLog("ConnectionData handshake appended (uexpC1, uexpCv1.0.3)."); } LogConfigHash(singleton); } catch (Exception ex) { Plugin.DebugLog("ConnectionData handshake failed: " + ex.Message); } } private static void LogConfigHash(NetworkManager nm) { try { ulong config = nm.NetworkConfig.GetConfig(false); int num = nm.NetworkConfig.Prefabs?.NetworkPrefabOverrideLinks?.Count ?? (-1); Plugin.DebugLog($"NGO config hash for this join: {config} prefabLinks={num}."); } catch (Exception ex) { Plugin.DebugLog("Config hash log failed: " + ex.Message); } } } internal static class DedicatedLobbySoftRefresh { private const float IntervalSeconds = 3f; private static Coroutine? _loop; private static SteamLobbyManager? _slm; private static bool _hookedDataChanged; public static void EnsureStarted(SteamLobbyManager slm) { if (Plugin.Config.DedicatedBrowserOnly.Value) { _slm = slm; EnsureDataChangedHook(); if (_loop == null && !((Object)(object)Plugin.Instance == (Object)null)) { _loop = ((MonoBehaviour)Plugin.Instance).StartCoroutine(Loop()); Plugin.DebugLog("Dedicated lobby soft-refresh started (3s)."); } } } public static void Stop() { if (_loop != null && (Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StopCoroutine(_loop); } _loop = null; _slm = null; } private static void EnsureDataChangedHook() { if (_hookedDataChanged) { return; } try { SteamMatchmaking.OnLobbyDataChanged += OnLobbyDataChanged; _hookedDataChanged = true; } catch (Exception ex) { Plugin.DebugLog("OnLobbyDataChanged hook failed: " + ex.Message); } } private static void OnLobbyDataChanged(Lobby lobby) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) try { if (!Plugin.IsEnabled || !Plugin.Config.DedicatedBrowserOnly.Value || !DedicatedLobby.IsDedicatedLobby(lobby)) { return; } SteamLobbyManager val = _slm ?? Object.FindObjectOfType<SteamLobbyManager>(); if ((Object)(object)val?.levelListContainer == (Object)null) { return; } LobbySlot[] componentsInChildren = ((Component)val.levelListContainer).GetComponentsInChildren<LobbySlot>(true); foreach (LobbySlot val2 in componentsInChildren) { if ((Object)(object)val2 == (Object)null) { continue; } try { if (SteamId.op_Implicit(((Lobby)(ref val2.thisLobby)).Id) == SteamId.op_Implicit(((Lobby)(ref lobby)).Id)) { val2.thisLobby = lobby; if ((Object)(object)val2.LobbyName != (Object)null) { ((TMP_Text)val2.LobbyName).text = ""; } } } catch { } } } catch (Exception ex) { Plugin.DebugLog("OnLobbyDataChanged: " + ex.Message); } } private static IEnumerator Loop() { WaitForSecondsRealtime wait = new WaitForSecondsRealtime(3f); while (true) { yield return wait; if (!Plugin.Config.DedicatedBrowserOnly.Value || !MenuOverlayLifecycle.MenuUiAllowed) { break; } SteamLobbyManager val = _slm; if ((Object)(object)val == (Object)null) { val = Object.FindObjectOfType<SteamLobbyManager>(); } if (!((Object)(object)val == (Object)null) && !((Object)(object)val.levelListContainer == (Object)null) && ((Component)val.levelListContainer).gameObject.activeInHierarchy) { try { RefreshVisibleSlots(val); } catch (Exception ex) { Plugin.DebugLog("Soft refresh: " + ex.Message); } } } _loop = null; } private static void RefreshVisibleSlots(SteamLobbyManager slm) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) LobbySlot[] componentsInChildren = ((Component)slm.levelListContainer).GetComponentsInChildren<LobbySlot>(true); int num = 0; int num2 = 0; LobbySlot[] array = componentsInChildren; foreach (LobbySlot val in array) { if ((Object)(object)val == (Object)null) { continue; } try { Lobby thisLobby = val.thisLobby; if (!DedicatedLobby.IsDedicatedLobby(thisLobby)) { continue; } ((Lobby)(ref thisLobby)).Refresh(); num++; if (DedicatedLobby.IsJoinableListing(thisLobby)) { continue; } try { GameObject gameObject = ((Component)val).gameObject; if ((Object)(object)gameObject != (Object)null) { gameObject.SetActive(false); Object.Destroy((Object)(object)gameObject); num2++; } } catch { } } catch { } } if (num > 0) { Plugin.DebugLog($"Soft-refreshed {num} dedicated lobby card(s); dropped {num2}."); } if (num2 > 0) { try { DedicatedServerListReplacePatch.FitListContentHeight(slm); } catch { } } } } [HarmonyPatch(typeof(SteamLobbyManager), "LoadServerList")] internal static class DedicatedSoftRefreshOnLoadPatch { [HarmonyPostfix] private static void Postfix(SteamLobbyManager __instance) { if (Plugin.Config.DedicatedBrowserOnly.Value) { DedicatedLobbySoftRefresh.EnsureStarted(__instance); } } } [HarmonyPatch(typeof(MenuManager), "ClickJoinButton")] internal static class DedicatedSoftRefreshOnOpenPatch { [HarmonyPostfix] private static void Postfix() { if (Plugin.Config.DedicatedBrowserOnly.Value) { SteamLobbyManager val = Object.FindObjectOfType<SteamLobbyManager>(); if ((Object)(object)val != (Object)null) { DedicatedLobbySoftRefresh.EnsureStarted(val); } } } } internal static class DedicatedModsModal { private sealed class ModsModalStatusPump : MonoBehaviour { private void Update() { PumpPendingStatus(); } } [CompilerGenerated] private static class <>O { public static UnityAction <0>__ForceClose; public static UnityAction <1>__CopyProfileCode; public static UnityAction <2>__DownloadModList; } private static GameObject? _root; private static TextMeshProUGUI? _title; private static TextMeshProUGUI? _status; private static RectTransform? _content; private static ScrollRect? _scroll; private static TMP_FontAsset? _font; private static string _serverName = ""; private static string _modsCsv = ""; private static string _profileCode = ""; private static string? _pendingStatus; private static readonly Color PanelBg = new Color(0.07f, 0.075f, 0.08f, 0.98f); private static readonly Color Accent = new Color(0.91f, 0.62f, 0.12f, 1f); private static readonly Color Text = new Color(0.95f, 0.93f, 0.86f, 1f); private static readonly Color Muted = new Color(0.72f, 0.74f, 0.7f, 1f); private static readonly Color RowBg = new Color(0.1f, 0.105f, 0.11f, 1f); private static readonly Color BtnBg = new Color(0.16f, 0.14f, 0.09f, 1f); private static readonly Color ScrollBg = new Color(0.04f, 0.04f, 0.045f, 1f); public static void Show(string serverName, string modsCsv, string profileCode) { if (!MenuOverlayLifecycle.MenuUiAllowed) { Plugin.Log.LogWarning((object)"Mods modal blocked — menu UI not active."); return; } JoinPasswordPrompt.ForceClose(); ForceClose(); _serverName = serverName ?? ""; _modsCsv = modsCsv ?? ""; _profileCode = (profileCode ?? "").Trim(); Build(); if ((Object)(object)_root == (Object)null || (Object)(object)_title == (Object)null || (Object)(object)_content == (Object)null || (Object)(object)_scroll == (Object)null) { return; } ((TMP_Text)_title).text = (string.IsNullOrWhiteSpace(serverName) ? "SERVER MODS" : serverName); ClearContent(); List<string> list = new List<string>(); if (!string.IsNullOrWhiteSpace(modsCsv)) { string[] array = modsCsv.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } } if (!string.IsNullOrEmpty(_profileCode)) { AddRow("r2modman: Import/Update → From code → paste the profile code.", isEmpty: true); AddRow("Code: " + _profileCode, isEmpty: false); } else { AddRow("No profile code yet — host may still be exporting.", isEmpty: true); AddRow("Install the same mods manually, or ask the host for an r2modman code.", isEmpty: true); } if (list.Count == 0) { AddRow("No display mod names published by this host.", isEmpty: true); } else { AddRow($"Installed packages ({list.Count}):", isEmpty: true); for (int j = 0; j < list.Count; j++) { AddRow($"{j + 1}. {list[j]}", isEmpty: false); } } LayoutRebuilder.ForceRebuildLayoutImmediate(_content); Canvas.ForceUpdateCanvases(); _scroll.verticalNormalizedPosition = 1f; _root.SetActive(true); SetStatus(string.IsNullOrEmpty(_profileCode) ? "Download saves a JSON checklist. Prefer a profile code when available." : "Copy code → r2modman Import/Update → From code. Or download .r2z."); Plugin.DebugLog($"Mods modal shown ({list.Count} mods, code={!string.IsNullOrEmpty(_profileCode)})."); } public static void ForceClose() { _title = null; _status = null; _content = null; _scroll = null; _font = null; _serverName = ""; _modsCsv = ""; _profileCode = ""; if (!((Object)(object)_root != (Object)null)) { return; } GameObject root = _root; _root = null; try { GraphicRaycaster[] componentsInChildren = root.GetComponentsInChildren<GraphicRaycaster>(true); foreach (GraphicRaycaster val in componentsInChildren) { if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = false; } } root.SetActive(false); } catch { } Object.Destroy((Object)(object)root); } public static void DestroyIfAny() { ForceClose(); } private static void ClearContent() { if (!((Object)(object)_content == (Object)null)) { for (int num = ((Transform)_content).childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)((Transform)_content).GetChild(num)).gameObject); } } } private static void AddRow(string text, bool isEmpty) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_content == (Object)null)) { GameObject val = new GameObject("ModRow", new Type[3] { typeof(RectTransform), typeof(Image), typeof(LayoutElement) }); val.transform.SetParent((Transform)(object)_content, false); ((Graphic)val.GetComponent<Image>()).color = (isEmpty ? ScrollBg : RowBg); ((Graphic)val.GetComponent<Image>()).raycastTarget = false; LayoutElement component = val.GetComponent<LayoutElement>(); component.minHeight = 34f; component.preferredHeight = 34f; component.flexibleWidth = 1f; TextMeshProUGUI obj = CreateTmp(val.transform, "Label", text, 16f, isEmpty ? Muted : Text, _font, (FontStyles)0); ((TMP_Text)obj).enableWordWrapping = false; ((TMP_Text)obj).overflowMode = (TextOverflowModes)1; ((TMP_Text)obj).alignment = (TextAlignmentOptions)4097; RectTransform rectTransform = ((TMP_Text)obj).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = new Vector2(12f, 2f); rectTransform.offsetMax = new Vector2(-12f, -2f); } } private static void Build() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Expected O, but got Unknown //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Expected O, but got Unknown //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Expected O, but got Unknown //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Expected O, but got Unknown //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_0566: Unknown result type (might be due to invalid IL or missing references) //IL_057f: Unknown result type (might be due to invalid IL or missing references) //IL_0589: Unknown result type (might be due to invalid IL or missing references) //IL_05c1: Unknown result type (might be due to invalid IL or missing references) //IL_05cb: Expected O, but got Unknown //IL_060f: Unknown result type (might be due to invalid IL or missing references) //IL_0615: Expected O, but got Unknown //IL_0641: Unknown result type (might be due to invalid IL or missing references) //IL_065c: Unknown result type (might be due to invalid IL or missing references) //IL_0671: Unknown result type (might be due to invalid IL or missing references) //IL_0686: Unknown result type (might be due to invalid IL or missing references) //IL_069b: Unknown result type (might be due to invalid IL or missing references) //IL_06af: Unknown result type (might be due to invalid IL or missing references) //IL_06d1: Unknown result type (might be due to invalid IL or missing references) //IL_06d8: Expected O, but got Unknown //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_0723: Unknown result type (might be due to invalid IL or missing references) //IL_0752: Unknown result type (might be due to invalid IL or missing references) //IL_0759: Expected O, but got Unknown //IL_0774: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Expected O, but got Unknown _font = FindMenuFont(); _root = ((Component)MenuOverlayLifecycle.CreateOverlayCanvas("UEXP_ModsModal", 6100)).gameObject; Image obj = CreateImage(_root.transform, "Dim", new Color(0.01f, 0.01f, 0.015f, 0.82f)); Stretch(((Graphic)obj).rectTransform); Button obj2 = ((Component)obj).gameObject.AddComponent<Button>(); ((Selectable)obj2).transition = (Transition)0; ButtonClickedEvent onClick = obj2.onClick; object obj3 = <>O.<0>__ForceClose; if (obj3 == null) { UnityAction val = ForceClose; <>O.<0>__ForceClose = val; obj3 = (object)val; } ((UnityEvent)onClick).AddListener((UnityAction)obj3); Image val2 = CreateImage(_root.transform, "Panel", PanelBg); RectTransform rectTransform = ((Graphic)val2).rectTransform; rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = new Vector2(820f, 600f); RectTransform rectTransform2 = ((Graphic)CreateImage(((Component)val2).transform, "Accent", Accent)).rectTransform; rectTransform2.anchorMin = new Vector2(0f, 0f); rectTransform2.anchorMax = new Vector2(0f, 1f); rectTransform2.pivot = new Vector2(0f, 0.5f); rectTransform2.sizeDelta = new Vector2(6f, 0f); SetRect(((TMP_Text)CreateTmp(((Component)val2).transform, "Header", "MOD LIST", 24f, Accent, _font, (FontStyles)1)).rectTransform, 28f, -22f, 420f, 32f); _title = CreateTmp(((Component)val2).transform, "Title", "", 18f, Text, _font, (FontStyles)0); SetRect(((TMP_Text)_title).rectTransform, 28f, -56f, 520f, 28f); Button obj4 = CreateButton(((Component)val2).transform, "Close", "CLOSE", _font); SetRect(((Component)obj4).GetComponent<RectTransform>(), -28f, -20f, 120f, 38f, fromRight: true); ButtonClickedEvent onClick2 = obj4.onClick; object obj5 = <>O.<0>__ForceClose; if (obj5 == null) { UnityAction val3 = ForceClose; <>O.<0>__ForceClose = val3; obj5 = (object)val3; } ((UnityEvent)onClick2).AddListener((UnityAction)obj5); Button obj6 = CreateButton(((Component)val2).transform, "CopyCode", "COPY CODE", _font); SetRect(((Component)obj6).GetComponent<RectTransform>(), 28f, -92f, 150f, 36f); ButtonClickedEvent onClick3 = obj6.onClick; object obj7 = <>O.<1>__CopyProfileCode; if (obj7 == null) { UnityAction val4 = CopyProfileCode; <>O.<1>__CopyProfileCode = val4; obj7 = (object)val4; } ((UnityEvent)onClick3).AddListener((UnityAction)obj7); Button obj8 = CreateButton(((Component)val2).transform, "Download", "DOWNLOAD LIST", _font); SetRect(((Component)obj8).GetComponent<RectTransform>(), 190f, -92f, 180f, 36f); ButtonClickedEvent onClick4 = obj8.onClick; object obj9 = <>O.<2>__DownloadModList; if (obj9 == null) { UnityAction val5 = DownloadModList; <>O.<2>__DownloadModList = val5; obj9 = (object)val5; } ((UnityEvent)onClick4).AddListener((UnityAction)obj9); _status = CreateTmp(((Component)val2).transform, "Status", "", 14f, Muted, _font, (FontStyles)0); SetRect(((TMP_Text)_status).rectTransform, 386f, -92f, 400f, 36f); ((TMP_Text)_status).enableWordWrapping = true; ((TMP_Text)_status).alignment = (TextAlignmentOptions)4097; GameObject val6 = new GameObject("Scroll", new Type[3] { typeof(RectTransform), typeof(Image), typeof(ScrollRect) }); val6.transform.SetParent(((Component)val2).transform, false); Image component = val6.GetComponent<Image>(); ((Graphic)component).color = ScrollBg; ((Graphic)component).raycastTarget = true; RectTransform component2 = val6.GetComponent<RectTransform>(); component2.anchorMin = new Vector2(0f, 0f); component2.anchorMax = new Vector2(1f, 1f); component2.offsetMin = new Vector2(24f, 24f); component2.offsetMax = new Vector2(-48f, -140f); GameObject val7 = new GameObject("Viewport", new Type[3] { typeof(RectTransform), typeof(Image), typeof(RectMask2D) }); val7.transform.SetParent(val6.transform, false); Image component3 = val7.GetComponent<Image>(); ((Graphic)component3).color = new Color(1f, 1f, 1f, 0.02f); ((Graphic)component3).raycastTarget = true; Stretch(val7.GetComponent<RectTransform>()); GameObject val8 = new GameObject("Content", new Type[3] { typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter) }); val8.transform.SetParent(val7.transform, false); _content = val8.GetComponent<RectTransform>(); _content.anchorMin = new Vector2(0f, 1f); _content.anchorMax = new Vector2(1f, 1f); _content.pivot = new Vector2(0.5f, 1f); _content.anchoredPosition = Vector2.zero; _content.sizeDelta = new Vector2(0f, 0f); VerticalLayoutGroup component4 = val8.GetComponent<VerticalLayoutGroup>(); ((LayoutGroup)component4).childAlignment = (TextAnchor)0; ((HorizontalOrVerticalLayoutGroup)component4).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component4).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component4).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)component4).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)component4).spacing = 6f; ((LayoutGroup)component4).padding = new RectOffset(8, 8, 8, 8); ContentSizeFitter component5 = val8.GetComponent<ContentSizeFitter>(); component5.verticalFit = (FitMode)2; component5.horizontalFit = (FitMode)0; GameObject val9 = new GameObject("Scrollbar", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Scrollbar) }); val9.transform.SetParent(((Component)val2).transform, false); ((Graphic)val9.GetComponent<Image>()).color = new Color(0.12f, 0.12f, 0.13f, 1f); RectTransform component6 = val9.GetComponent<RectTransform>(); component6.anchorMin = new Vector2(1f, 0f); component6.anchorMax = new Vector2(1f, 1f); component6.pivot = new Vector2(1f, 0.5f); component6.offsetMin = new Vector2(-40f, 24f); component6.offsetMax = new Vector2(-24f, -140f); GameObject val10 = new GameObject("Sliding Area", new Type[1] { typeof(RectTransform) }); val10.transform.SetParent(val9.transform, false); Stretch(val10.GetComponent<RectTransform>()); val10.GetComponent<RectTransform>().offsetMin = new Vector2(2f, 2f); val10.GetComponent<RectTransform>().offsetMax = new Vector2(-2f, -2f); GameObject val11 = new GameObject("Handle", new Type[2] { typeof(RectTransform), typeof(Image) }); val11.transform.SetParent(val10.transform, false); ((Graphic)val11.GetComponent<Image>()).color = Accent; Stretch(val11.GetComponent<RectTransform>()); Scrollbar component7 = val9.GetComponent<Scrollbar>(); component7.direction = (Direction)2; component7.handleRect = val11.GetComponent<RectTransform>(); ((Selectable)component7).targetGraphic = (Graphic)(object)val11.GetComponent<Image>(); _scroll = val6.GetComponent<ScrollRect>(); _scroll.viewport = val7.GetComponent<RectTransform>(); _scroll.content = _content; _scroll.horizontal = false; _scroll.vertical = true; _scroll.movementType = (MovementType)2; _scroll.scrollSensitivity = 55f; _scroll.verticalScrollbar = component7; _scroll.verticalScrollbarVisibility = (ScrollbarVisibility)0; _scroll.inertia = true; if ((Object)(object)_root.GetComponent<ModsModalStatusPump>() == (Object)null) { _root.AddComponent<ModsModalStatusPump>(); } } internal static void PumpPendingStatus() { string text = Interlocked.Exchange(ref _pendingStatus, null); if (text != null) { SetStatus(text); } } private static void CopyProfileCode() { if (string.IsNullOrEmpty(_profileCode)) { SetStatus("No profile code on this lobby yet."); return; } try { GUIUtility.systemCopyBuffer = _profileCode; SetStatus("Copied. r2modman → Import/Update → From code."); Plugin.Log.LogInfo((object)("Copied r2modman profile code for \"" + _serverName + "\".")); } catch (Exception ex) { SetStatus("Copy failed: " + ex.Message); } } private static void DownloadModList() { string safeName = SanitizeFileName(string.IsNullOrWhiteSpace(_serverName) ? "dedicated" : _serverName); string folder = GetDownloadsFolder(); Directory.CreateDirectory(folder); if (!string.IsNullOrEmpty(_profileCode)) { SetStatus("Downloading r2modman profile…"); string code = _profileCode; string path = Path.Combine(folder, safeName + "-mods.r2z"); ThreadPool.QueueUserWorkItem(delegate { try { byte[] array = DownloadProfileBytes(code); if (array == null || array.Length == 0) { QueueStatus("Download failed — try Copy code instead."); return; } byte[] bytes = DecodeProfilePayload(array); File.WriteAllBytes(path, bytes); WriteCompanionJson(folder, safeName); QueueStatus("Saved " + Path.GetFileName(path) + " — import in r2modman (From file)."); try { Process.Start("explorer.exe", "/select,\"" + path + "\""); } catch { } } catch (Exception ex2) { QueueStatus("Download failed: " + ex2.Message); } }); return; } try { string text = Path.Combine(folder, safeName + "-mods.json"); File.WriteAllText(text, BuildFallbackJson(), Encoding.UTF8); SetStatus("Saved " + Path.GetFileName(text) + " (names only — no profile code)."); try { Process.Start("explorer.exe", "/select,\"" + text + "\""); } catch { } } catch (Exception ex) { SetStatus("Save failed: " + ex.Message); } } private static void WriteCompanionJson(string folder, string safeName) { try { File.WriteAllText(Path.Combine(folder, safeName + "-mods.json"), BuildFallbackJson(), Encoding.UTF8); } catch { } } private static string BuildFallbackJson() { List<string> list = new List<string>(); string[] array = (_modsCsv ?? "").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" \"schema\": \"uexp-r2modman-modlist-v1\","); stringBuilder.AppendLine(" \"game\": \"LethalCompany\","); stringBuilder.AppendLine(" \"serverName\": \"" + EscapeJson(_serverName) + "\","); stringBuilder.AppendLine(" \"profileCode\": \"" + EscapeJson(_profileCode) + "\","); stringBuilder.AppendLine(" \"instructions\": \"Prefer profile code in r2modman Import/Update → From code. JSON display names are not full Thunderstore dependency strings.\","); stringBuilder.AppendLine(" \"displayNames\": ["); for (int j = 0; j < list.Count; j++) { stringBuilder.Append(" \""); stringBuilder.Append(EscapeJson(list[j])); stringBuilder.Append('"'); if (j + 1 < list.Count) { stringBuilder.Append(','); } stringBuilder.AppendLine(); } stringBuilder.AppendLine(" ]"); stringBuilder.AppendLine("}"); return stringBuilder.ToString(); } private static byte[]? DownloadProfileBytes(string code) { HttpWebRequest obj = (HttpWebRequest)WebRequest.Create("https://thunderstore.io/api/experimental/legacyprofile/get/" + Uri.EscapeDataString(code.Trim()) + "/"); obj.Method = "GET"; obj.Timeout = 120000; obj.ReadWriteTimeout = 120000; using HttpWebResponse httpWebResponse = (HttpWebResponse)obj.GetResponse(); using MemoryStream memoryStream = new MemoryStream(); httpWebResponse.GetResponseStream().CopyTo(memoryStream); return memoryStream.ToArray(); } private static byte[] DecodeProfilePayload(byte[] raw) { if (raw.Length >= 2 && raw[0] == 80 && raw[1] == 75) { return raw; } string text = Encoding.UTF8.GetString(raw).Trim(); if (text.StartsWith("#r2modman\n", StringComparison.Ordinal)) { text = text.Substring("#r2modman\n".Length).Trim(); } else if (text.StartsWith("#r2modman\r\n", StringComparison.Ordinal)) { text = text.Substring("#r2modman\r\n".Length).Trim(); } return Convert.FromBase64String(text); } private static string GetDownloadsFolder() { try { string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads"); if (Directory.Exists(text)) { return text; } } catch { } return Path.GetTempPath(); } private static string SanitizeFileName(string name) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { name = name.Replace(oldChar, '_'); } if (name.Length > 40) { name = name.Substring(0, 40); } if (!string.IsNullOrWhiteSpace(name)) { return name.Trim(); } return "dedicated"; } private static string EscapeJson(string s) { return (s ?? "").Replace("\\", "\\\\").Replace("\"", "\\\""); } private static void QueueStatus(string msg) { _pendingStatus = msg; Plugin.Log.LogInfo((object)("Mods download: " + msg)); } private static void SetStatus(string msg) { if ((Object)(object)_status != (Object)null) { ((TMP_Text)_status).text = msg ?? ""; } Plugin.DebugLog("Mods modal: " + msg); } private static TMP_FontAsset? FindMenuFont() { try { TextMeshProUGUI val = Object.FindObjectOfType<TextMeshProUGUI>(); if ((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)null) { return ((TMP_Text)val).font; } } catch { } return TMP_Settings.defaultFontAsset; } private static Image CreateImage(Transform parent, string name, Color color) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(parent, false); Image component = val.GetComponent<Image>(); ((Graphic)component).color = color; return component; } private static TextMeshProUGUI CreateTmp(Transform parent, string name, string text, float size, Color color, TMP_FontAsset? font, FontStyles style) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); if ((Object)(object)font != (Object)null) { ((TMP_Text)val2).font = font; } ((TMP_Text)val2).text = text; ((TMP_Text)val2).fontSize = size; ((Graphic)val2).color = color; ((TMP_Text)val2).fontStyle = style; ((Graphic)val2).raycastTarget = false; return val2; } private static Button CreateButton(Transform parent, string name, string label, TMP_FontAsset? font) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(Image), typeof(Button) }); val.transform.SetParent(parent, false); ((Graphic)val.GetComponent<Image>()).color = BtnBg; Button component = val.GetComponent<Button>(); TextMeshProUGUI obj = CreateTmp(val.transform, "Label", label, 14f, Accent, font, (FontStyles)1); Stretch(((TMP_Text)obj).rectTransform); ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; return component; } private static void Stretch(RectTransform rt) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; } private static void SetRect(RectTransform rt, float x, float y, float w, float h, bool fromRight = false) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) if (fromRight) { rt.anchorMin = new Vector2(1f, 1f); rt.anchorMax = new Vector2(1f, 1f); rt.pivot = new Vector2(1f, 1f); } else { rt.anchorMin = new Vector2(0f, 1f); rt.anchorMax = new Vector2(0f, 1f); rt.pivot = new Vector2(0f, 1f); } rt.anchoredPosition = new Vector2(x, y); rt.sizeDelta = new Vector2(w, h); } } [HarmonyPatch(typeof(SteamLobbyManager), "LoadServerList")] internal static class DedicatedServerListReplacePatch { private static float _savedScrollHeight = -1f; [HarmonyPrefix] private static bool Prefix(SteamLobbyManager __instance) { if (!Plugin.Config.DedicatedBrowserOnly.Value) { return true; } try { if (__instance.loadLobbyListCoroutine != null) { ((MonoBehaviour)__instance).StopCoroutine(__instance.loadLobbyListCoroutine); } } catch { } __instance.refreshServerListTimer = 0f; __instance.loadLobbyListCoroutine = ((MonoBehaviour)__instance).StartCoroutine(LoadDedicatedRoutine(__instance)); return false; } private static IEnumerator LoadDedicatedRoutine(SteamLobbyManager slm) { ClearExistingSlots(slm); if ((Object)(object)slm.serverListBlankText != (Object)null) { ((Component)slm.serverListBlankText).gameObject.SetActive(true); ((TMP_Text)slm.serverListBlankText).text = "Scanning dedicated servers…"; } Task<Lobby[]> publicTask = null; try { LobbyQuery val = SteamMatchmaking.LobbyList; val = ((LobbyQuery)(ref val)).WithKeyValue("uexpDedicated", "1"); val = ((LobbyQuery)(ref val)).FilterDistanceWorldwide(); val = ((LobbyQuery)(ref val)).WithMaxResults(50); publicTask = ((LobbyQuery)(ref val)).RequestAsync(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Dedicated lobby query failed: " + ex.Message)); } float startedAt = Time.realtimeSinceStartup; while (publicTask != null && !publicTask.IsCompleted) { if (Time.realtimeSinceStartup - startedAt > 20f) { Plugin.Log.LogWarning((object)"Dedicated lobby Steam query timed out after 20s."); if ((Object)(object)slm.serverListBlankText != (Object)null) { ((TMP_Text)slm.serverListBlankText).text = "Steam query timed out — try Refresh."; } slm.loadLobbyListCoroutine = null; yield break; } yield return null; } Dictionary<ulong, Lobby> dictionary = new Dictionary<ulong, Lobby>(); try { Lobby[] array = publicTask?.Result; if (array != null) { Lobby[] array2 = array; for (int i = 0; i < array2.Length; i++) { Lobby value = array2[i]; dictionary[((Lobby)(ref value)).Id.Value] = value; } } } catch (Exception ex2) { Plugin.DebugLog("Dedicated query result: " + ex2.Message); } foreach (Lobby item in EnumerateFriendDedicatedLobbies()) { Lobby current = item; dictionary[((Lobby)(ref current)).Id.Value] = current; } List<Lobby> list = (from l in dictionary.Values.Where(IsJoinableDedicatedListing) orderby (!IsPinnedOfficial(l)) ? 1 : 0 select l).ThenBy<Lobby, string>((Lobby l) => SafeName(l), StringComparer.OrdinalIgnoreCase).ToList(); Plugin.DebugLog($"Dedicated browser: {list.Count} lobby(s) after public+friends merge" + ((list.Count > 0 && IsPinnedOfficial(list[0])) ? " (official pinned first)." : ".")); if (list.Count == 0) { if ((Object)(object)slm.serverListBlankText != (Object)null) { ((Component)slm.serverListBlankText).gameObject.SetActive(true); ((TMP_Text)slm.serverListBlankText).text = "No dedicated servers online.\nFriends-only hosts show when that Steam friend is in the lobby."; } FitListContentHeight(slm, 0); slm.loadLobbyListCoroutine = null; yield break; } if ((Object)(object)slm.serverListBlankText != (Object)null) { ((TMP_Text)slm.serverListBlankText).text = ""; ((Component)slm.serverListBlankText).gameObject.SetActive(false); } slm.lobbySlotPositionOffset = 0f; MethodInfo methodInfo = AccessTools.Method(typeof(SteamLobbyManager), "loadLobbyListAndFilter", (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.Log.LogWarning((object)"loadLobbyListAndFilter missing — cannot fill dedicated list."); slm.loadLobbyListCoroutine = null; yield break; } if (methodInfo.Invoke(slm, new object[1] { list.ToArray() }) is IEnumerator enumerator2) { yield return ((MonoBehaviour)slm).StartCoroutine(enumerator2); } yield return null; FitListContentHeight(slm, list.Count); slm.loadLobbyListCoroutine = null; } internal static void FitListContentHeight(SteamLobbyManager slm, int lobbyCount = -1) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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) try { if ((Object)(object)slm.levelListContainer == (Object)null) { return; } Transform levelListContainer = slm.levelListContainer; RectTransform val = (RectTransform)(((object)((levelListContainer is RectTransform) ? levelListContainer : null)) ?? ((object)((Component)slm.levelListContainer).GetComponent<RectTransform>())); if ((Object)(object)val == (Object)null) { return; } float num = 72f; int num2 = lobbyCount; if (num2 < 0) { num2 = 0; for (int i = 0; i < ((Transform)val).childCount; i++) { Transform child = ((Transform)val).GetChild(i); if ((Object)(object)child != (Object)null && (Object)(object)((Component)child).GetComponentInChildren<LobbySlot>(true) != (Object)null) { num2++; } } } float num3 = ((num2 <= 0) ? num : ((float)num2 * num + 4f)); val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(1f, 1f); val.pivot = new Vector2(0.5f, 1f); val.SetSizeWithCurrentAnchors((Axis)1, num3); float num4 = 0f; for (int j = 0; j < ((Transform)val).childCount; j++) { Transform child2 = ((Transform)val).GetChild(j); if (!((Object)(object)child2 == (Object)null) && !((Object)(object)((Component)child2).GetComponentInChildren<LobbySlot>(true) == (Object)null)) { RectTransform val2 = (RectTransform)(((object)((child2 is RectTransform) ? child2 : null)) ?? ((object)((Component)child2).GetComponent<RectTransform>())); if (!((Object)(object)val2 == (Object)null)) { val2.anchorMin = new Vector2(0f, 1f); val2.anchorMax = new Vector2(1f, 1f); val2.pivot = new Vector2(0.5f, 1f); val2.SetSizeWithCurrentAnchors((Axis)1, DedicatedLobbySlotPatches.CardHeight); val2.anchoredPosition = new Vector2(0f, num4); num4 -= num; } } } ScrollRect componentInParent = ((Component)val).GetComponentInParent<ScrollRect>(); if (!((Object)(object)componentInParent != (Object)null)) { return; } componentInParent.verticalNormalizedPosition = 1f; RectTransform component = ((Component)componentInParent).GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { Rect rect; if (_savedScrollHeight < 0f) { rect = component.rect; _savedScrollHeight = ((Rect)(ref rect)).height; } else if (_savedScrollHeight > 10f) { rect = component.rect; if (((Rect)(ref rect)).height + 0.5f < _savedScrollHeight) { component.SetSizeWithCurrentAnchors((Axis)1, _savedScrollHeight); } } } Canvas.ForceUpdateCanvases(); } catch (Exception ex) { Plugin.DebugLog("FitListContentHeight: " + ex.Message); } } private static bool IsJoinableDedicatedListing(Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return DedicatedLobby.IsJoinableListing(lobby); } private static IEnumerable<Lobby> EnumerateFriendDedicatedLobbies() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) List<Lobby> list = new List<Lobby>(); try { foreach (Friend friend in SteamFriends.GetFriends()) { Friend current = friend; try { if (((Friend)(ref current)).IsMe || !((Friend)(ref current)).IsPlayingThisGame) { continue; } FriendGameInfo? gameInfo = ((Friend)(ref current)).GameInfo; if (!gameInfo.HasValue) { continue; } FriendGameInfo value = gameInfo.Value; Lobby? lobby = ((FriendGameInfo)(ref value)).Lobby; if (lobby.HasValue) { Lobby value2 = lobby.Value; try { ((Lobby)(ref value2)).Refresh(); } catch { } if (DedicatedLobby.IsDedicatedLobby(value2)) { list.Add(value2); } } } catch { } } } catch (Exception ex) { Plugin.DebugLog("Friend lobby scan: " + ex.Message); } return list; } private static void ClearExistingSlots(SteamLobbyManager slm) { DedicatedLobbySlotPatches.ClearExtras(); try {