using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Epic.OnlineServices.Lobby; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("BigWalkPublicLobbies")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+914e14154fb5064a739fcebed9b6462f70dbef73")] [assembly: AssemblyProduct("BigWalkPublicLobbies")] [assembly: AssemblyTitle("BigWalkPublicLobbies")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace BigWalkPublicLobbies; public static class LobbyScanner { private static readonly Dictionary Cache = new Dictionary(); private static Task> _lobbyTask; private static Task> _sessionTask; public static void StartRound(bool clearCache, bool includeSession) { if (clearCache) { Cache.Clear(); } try { EOSLobbyManager instance = EOSLobbyManager.Instance; _lobbyTask = (((Object)(object)instance != (Object)null) ? instance.FindPublicLobbies() : null); } catch (Exception ex) { DebugLog.Warn("发起 Lobby 搜索失败: " + ex.Message); _lobbyTask = null; } try { object sessionTask; if (!includeSession) { sessionTask = null; } else { EOSSessionManager instance2 = EOSSessionManager.Instance; sessionTask = ((instance2 != null) ? instance2.FindAllPublicSessions() : null); } _sessionTask = (Task>)sessionTask; } catch (Exception ex2) { DebugLog.Warn("发起 Session 搜索失败: " + ex2.Message); _sessionTask = null; } } public static bool TryFinishRound() { Task> lobbyTask = _lobbyTask; if (lobbyTask == null) { _sessionTask = null; return true; } if (!((Task)lobbyTask).IsCompleted) { return false; } if (_sessionTask != null && !((Task)_sessionTask).IsCompleted) { return false; } if (((Task)lobbyTask).IsFaulted) { AggregateException exception = ((Task)lobbyTask).Exception; object obj; if (exception == null) { obj = null; } else { Exception innerException = ((Exception)exception).InnerException; obj = ((innerException != null) ? innerException.Message : null); } if (obj == null) { AggregateException exception2 = ((Task)lobbyTask).Exception; obj = ((exception2 != null) ? ((Exception)exception2).Message : null); } DebugLog.Warn("Lobby 公开房间搜索失败: " + (string?)obj); } else { try { List result = lobbyTask.Result; if (result != null) { DebugLog.Debug($"[LobbyScanner] Lobby 返回 {result.Count} 条"); for (int i = 0; i < result.Count; i++) { LobbyInfo val = result[i]; if (val != null) { AddOrMerge(new RoomInfo { JoinCode = val.joinCode, WorldName = val.worldName, HostName = val.userName, FromSession = false }); } } } } catch (Exception ex) { DebugLog.Warn("处理 Lobby 搜索结果失败: " + ex.Message); } } Task> sessionTask = _sessionTask; if (sessionTask != null) { if (((Task)sessionTask).IsFaulted) { AggregateException exception3 = ((Task)sessionTask).Exception; object obj2; if (exception3 == null) { obj2 = null; } else { Exception innerException2 = ((Exception)exception3).InnerException; obj2 = ((innerException2 != null) ? innerException2.Message : null); } if (obj2 == null) { AggregateException exception4 = ((Task)sessionTask).Exception; obj2 = ((exception4 != null) ? ((Exception)exception4).Message : null); } DebugLog.Warn("Session 公开房间搜索失败: " + (string?)obj2); } else { try { List result2 = sessionTask.Result; if (result2 != null) { DebugLog.Debug($"[LobbyScanner] Session 返回 {result2.Count} 条"); for (int j = 0; j < result2.Count; j++) { HouseSessionInfo val2 = result2[j]; if (val2 != null) { AddOrMerge(new RoomInfo { JoinCode = val2.joinCode, WorldName = val2.worldName, HostName = val2.userName, FromSession = true }); } } } } catch (Exception ex2) { DebugLog.Warn("处理 Session 搜索结果失败: " + ex2.Message); } } _sessionTask = null; } _lobbyTask = null; return true; } public static List GetRoomsSnapshot() { List list = (from r in Cache.Values where !string.IsNullOrEmpty(r.JoinCode) select new RoomInfo { JoinCode = r.JoinCode, WorldName = r.WorldName, HostName = r.HostName, FromSession = r.FromSession }).OrderBy((RoomInfo r) => r.WorldName, StringComparer.OrdinalIgnoreCase).ToList(); DebugLog.Debug($"[LobbyScanner] 当前缓存累计 {list.Count} 个公开房间"); return list; } private static void AddOrMerge(RoomInfo room) { if (string.IsNullOrEmpty(room.JoinCode)) { return; } if (Cache.TryGetValue(room.JoinCode, out var value)) { if (string.IsNullOrEmpty(value.HostName) && !string.IsNullOrEmpty(room.HostName)) { value.HostName = room.HostName; value.WorldName = (string.IsNullOrEmpty(value.WorldName) ? room.WorldName : value.WorldName); } } else { Cache[room.JoinCode] = room; } } } internal static class LobbyScanPatch { public const uint MaxResults = 200u; public static void Prefix(ref uint maxResults) { if (maxResults < 200) { maxResults = 200u; } } public static void Apply(Harmony harmony) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(EOSLobbyManager), "FindLobbies", new Type[2] { typeof(uint), typeof(Action) }, (Type[])null); if (methodInfo == null) { DebugLog.Error("[Patch] 找不到 EOSLobbyManager.FindLobbies(uint, Action),房间上限保持游戏默认 16(请反馈模组作者)"); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(LobbyScanPatch).GetMethod("Prefix")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); DebugLog.Info($"[Patch] 已 patch EOSLobbyManager.FindLobbies:maxResults → {200}"); } catch (Exception ex) { DebugLog.Error("[Patch] Apply 失败: " + ex); } } } internal static class ModState { public static PublicLobbyPanel Panel; public static TitleMenu TitleMenu; public static GameObject StartButtons; public static int SearchRounds = 3; } internal static class ModText { public static bool IsChinese; private static bool _init; private static TMP_Text _cachedSettingsTmp; public static bool Poll() { bool flag = DetectChinese(); if (!_init || flag != IsChinese) { _init = true; IsChinese = flag; DebugLog.Info("[本地化] 主菜单语言 → 中文=" + (flag ? "是" : "否")); return true; } return false; } public static string T(string zh, string en) { if (!IsChinese) { return en; } return zh; } private static bool DetectChinese() { try { if ((Object)(object)ModState.TitleMenu == (Object)null) { return IsChinese; } if ((Object)(object)_cachedSettingsTmp == (Object)null) { Transform val = FindChildByName(((Component)ModState.TitleMenu).transform, "SettingsButton"); if ((Object)(object)val == (Object)null) { return IsChinese; } _cachedSettingsTmp = ((Component)val).GetComponentInChildren(true); if ((Object)(object)_cachedSettingsTmp == (Object)null) { return IsChinese; } } return ContainsChinese(_cachedSettingsTmp.text); } catch (Exception) { _cachedSettingsTmp = null; return IsChinese; } } public static bool ContainsChinese(string s) { if (string.IsNullOrEmpty(s)) { return false; } foreach (char c in s) { if (c >= '一' && c <= '鿿') { return true; } } return false; } private static Transform FindChildByName(Transform root, string name) { if ((Object)(object)root == (Object)null) { return null; } if (((Object)root).name == name) { return root; } for (int i = 0; i < root.childCount; i++) { Transform val = FindChildByName(root.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } } [BepInPlugin("com.bigwalk.publiclobbies", "BigWalk Public Lobbies", "1.0.2")] public class Plugin : BasePlugin { public const string GUID = "com.bigwalk.publiclobbies"; public const string Name = "BigWalk Public Lobbies"; public const string Version = "1.0.2"; internal static ManualLogSource Log; public override void Load() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown Log = ((BasePlugin)this).Log; DebugLog.Verbose = ((BasePlugin)this).Config.Bind("Debug", "Verbose", false, "打印详细诊断日志(EOS 搜索、UI 结构探测、布局等)").Value; ModState.SearchRounds = ((BasePlugin)this).Config.Bind("Search", "SearchRounds", 3, "点击一次刷新后自动执行的搜索轮数(最高上限,防死循环;轮间无人为等待,间隔仅取决于 EOS 搜索自身耗时)").Value; ((BasePlugin)this).AddComponent(); try { LobbyScanPatch.Apply(new Harmony("com.bigwalk.publiclobbies")); } catch (Exception ex) { DebugLog.Error("Harmony 初始化失败: " + ex); } ModState.Panel = new PublicLobbyPanel(); ModState.Panel.Hide(); DebugLog.Info($"{"BigWalk Public Lobbies"} v{"1.0.2"} 已加载(Verbose 日志={DebugLog.Verbose})。"); } } public class PublicLobbyMod : MonoBehaviour { private TitleMenu _titleMenu; private bool _buttonInjected; private bool _layoutLogged; private bool _structureLogged; private GameObject _buttonTemplate; private GameObject _injectedButton; private TMP_Text _injectedTmp; private float _titleRetryTime; private float _templateRetryTime; private void Update() { if (ModText.Poll()) { ModState.Panel?.RefreshAllTexts(); RefreshMainButtonText(); } if (ModState.Panel != null) { ModState.Panel.Tick(); } if (ModState.Panel != null && ModState.Panel.IsShown && Input.GetKeyDown((KeyCode)27)) { ModState.Panel.Hide(); } if (_buttonInjected) { if ((Object)(object)_injectedButton == (Object)null) { DebugLog.Info("[模组] 公开房间按钮已被销毁(场景切换),等待重新注入"); _buttonInjected = false; } return; } if ((Object)(object)_titleMenu == (Object)null) { if (Time.time < _titleRetryTime) { return; } _titleRetryTime = Time.time + 0.5f; _titleMenu = Object.FindObjectOfType(); if ((Object)(object)_titleMenu == (Object)null) { ModState.TitleMenu = null; ModState.StartButtons = null; return; } } ModState.TitleMenu = _titleMenu; if ((Object)(object)ModState.StartButtons == (Object)null) { Transform val = FindChildByName(((Component)_titleMenu).transform, "StartButtons"); if ((Object)(object)val != (Object)null) { ModState.StartButtons = ((Component)val).gameObject; DebugLog.Debug("[页面] 找到主菜单按钮容器 StartButtons"); } } if (!_layoutLogged) { LogLayout(); _layoutLogged = true; } if ((Object)(object)_buttonTemplate == (Object)null) { if (Time.time < _templateRetryTime) { return; } _templateRetryTime = Time.time + 1f; try { _buttonTemplate = FindJoinMenuButton(_titleMenu); } catch (Exception ex) { DebugLog.Warn("[模组] 查找「加入游戏」模板按钮失败: " + ex.Message); _buttonTemplate = null; } } if (!((Object)(object)_buttonTemplate == (Object)null)) { if (!_structureLogged) { DumpUiStructure(); _structureLogged = true; } TryInjectButton(); } } private void DumpUiStructure() { if (!DebugLog.Verbose) { return; } try { Canvas componentInParent = ((Component)_titleMenu).GetComponentInParent(true); DebugLog.Info("[结构] 主菜单 Canvas: '" + ((componentInParent != null) ? ((Object)componentInParent).name : null) + "'(所有菜单共享)"); DumpTree((componentInParent != null) ? ((Component)componentInParent).transform : null, 0, 4); GameObject buttonTemplate = _buttonTemplate; DumpButtonInfo((buttonTemplate != null) ? buttonTemplate.transform : null, "JoinButton模板"); } catch (Exception ex) { DebugLog.Warn("[结构] 打印失败: " + ex.Message); } } private void DumpTree(Transform t, int depth, int maxDepth) { if (!((Object)(object)t == (Object)null) && depth <= maxDepth) { GameObject gameObject = ((Component)t).gameObject; DebugLog.Info($"[结构] {new string(' ', depth * 2)}{((Object)t).name} active={gameObject.activeInHierarchy} type={((object)t).GetType().Name}"); int childCount = t.childCount; for (int i = 0; i < childCount; i++) { DumpTree(t.GetChild(i), depth + 1, maxDepth); } } } private void DumpButtonInfo(Transform t, string label) { //IL_01fe: 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_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)t == (Object)null) { return; } try { foreach (Component component5 in ((Component)t).GetComponents()) { DebugLog.Info("[结构] " + label + " 组件: " + ((object)component5).GetType().FullName); } Button component = ((Component)t).GetComponent