using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("WhoamI.LobbyRelayDisplay")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("WhoamI.LobbyRelayDisplay")] [assembly: AssemblyTitle("LobbyRelayDisplay")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Embedded] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Embedded] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Microsoft.CodeAnalysis { [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace LobbyInfoDisplay { [BepInPlugin("com.mymod.lobbyinfodisplay", "Lobby Info Display", "10.5.0")] public class LobbyInfoMod : BaseUnityPlugin { public static LobbyInfoMod Instance; public static ManualLogSource Log; private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Harmony val = new Harmony("com.mymod.lobbyinfodisplay.patch"); val.PatchAll(); UIController.CreateGlobalInstance(); Log.LogInfo((object)"Lobby Info Display v10.5 (真相大白:完美继承 PlayerConnectionLog 字体版) 已加载!"); } } [HarmonyPatch] public class LobbyDataInterceptor { [HarmonyPatch(typeof(SteamMatchmaking), "GetLobbyData")] [HarmonyPrefix] private unsafe static void Prefix_GetLobbyData(CSteamID steamIDLobby) { if (((CSteamID)(ref steamIDLobby)).IsValid() && (Object)(object)UIController.Instance != (Object)null && string.IsNullOrEmpty(UIController.Instance.cachedLobbyId)) { UIController.Instance.cachedLobbyId = ((object)(*(CSteamID*)(&steamIDLobby))/*cast due to .constrained prefix*/).ToString(); } } } public class UIController : MonoBehaviour { [Serializable] private class IpLocationData { public string status = ""; public string country = ""; public string regionName = ""; public string city = ""; public string isp = ""; } public static UIController Instance = null; private Canvas myCanvas; private TextMeshProUGUI statsText; public string cachedLobbyId = ""; private string cachedRelayIp = ""; private string cachedLocation = "查询中..."; private bool hasCachedInfo; private float hideTimer; private float hideDelay = 10f; private bool isShown; private float copySuccessTimer; private bool copySuccess; private float _nextUiUpdateTime; private float _lastFontRetryTime; private string _lastStatsText = ""; private readonly StringBuilder _sb = new StringBuilder(256); private const string C_GREEN = "#90EE90"; private const string C_YELLOW = "#F0E68C"; private const string C_TEXT = "#dfdac2"; private const string C_GREY = "#808080"; private Queue mainThreadActions = new Queue(); private static readonly HttpClient _httpClient = new HttpClient(); public static void CreateGlobalInstance() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("LobbyInfo_UI"); Object.DontDestroyOnLoad((Object)(object)val); Canvas val2 = val.AddComponent(); val2.renderMode = (RenderMode)0; val2.sortingOrder = 9999; CanvasScaler val3 = val.AddComponent(); val3.uiScaleMode = (ScaleMode)1; val3.referenceResolution = new Vector2(1920f, 1080f); Instance = val.AddComponent(); Instance.myCanvas = val2; Instance.InitText(); ((Behaviour)Instance.myCanvas).enabled = false; } } private void InitText() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown GameObject val = new GameObject("LobbyInfo_Text"); val.transform.SetParent(((Component)this).transform, false); ContentSizeFitter val2 = val.AddComponent(); val2.horizontalFit = (FitMode)2; val2.verticalFit = (FitMode)2; statsText = val.AddComponent(); ((TMP_Text)statsText).richText = true; ((Graphic)statsText).raycastTarget = false; ((TMP_Text)statsText).overflowMode = (TextOverflowModes)0; ((TMP_Text)statsText).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)statsText).alignment = (TextAlignmentOptions)257; UpdateLayout(); TrySyncFontFromGame(); } private void TrySyncFontFromGame() { if (!((Object)(object)statsText == (Object)null)) { PlayerConnectionLog val = Object.FindFirstObjectByType(); if ((Object)(object)val != (Object)null && (Object)(object)val.text != (Object)null) { ((TMP_Text)statsText).font = ((TMP_Text)val.text).font; ((TMP_Text)statsText).fontSharedMaterial = ((TMP_Text)val.text).fontSharedMaterial; } } } private void UpdateLayout() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (!((Object)(object)statsText == (Object)null)) { RectTransform rectTransform = ((TMP_Text)statsText).rectTransform; rectTransform.anchorMin = new Vector2(0f, 1f); rectTransform.anchorMax = new Vector2(0f, 1f); rectTransform.pivot = new Vector2(0f, 1f); rectTransform.anchoredPosition = new Vector2(20f, -20f); } } private void Update() { lock (mainThreadActions) { while (mainThreadActions.Count > 0) { mainThreadActions.Dequeue()(); } } if (Time.unscaledTime - _lastFontRetryTime > 0.5f) { _lastFontRetryTime = Time.unscaledTime; if ((Object)(object)((TMP_Text)statsText).font == (Object)null || (((Object)((TMP_Text)statsText).font).name != null && ((Object)((TMP_Text)statsText).font).name.Contains("Liberation"))) { TrySyncFontFromGame(); } } if (PhotonNetwork.InRoom) { if (!hasCachedInfo) { FetchAndCacheInfo(); } if (Input.GetKeyDown((KeyCode)106)) { ShowUI(); } if (isShown && Input.GetKeyDown((KeyCode)99)) { CopyJoinLink(); } } else if (hasCachedInfo) { ResetCache(); } if (isShown && Time.unscaledTime > hideTimer) { HideUI(); } if (copySuccess && Time.unscaledTime > copySuccessTimer) { copySuccess = false; } if (isShown && Time.unscaledTime > _nextUiUpdateTime) { UpdateText(); _nextUiUpdateTime = Time.unscaledTime + 0.2f; } } private void FetchAndCacheInfo() { if (string.IsNullOrEmpty(cachedLobbyId)) { cachedLobbyId = ExtractLobbyId(); } cachedRelayIp = GetRealRelayIp(); hasCachedInfo = true; FetchLocation(cachedRelayIp, delegate(string loc) { cachedLocation = loc; }); ShowUI(); } private void ResetCache() { hasCachedInfo = false; cachedLobbyId = ""; cachedRelayIp = ""; cachedLocation = "查询中..."; HideUI(); } public void ShowUI() { isShown = true; hideTimer = Time.unscaledTime + hideDelay; ((Behaviour)myCanvas).enabled = true; } public void HideUI() { isShown = false; ((Behaviour)myCanvas).enabled = false; } private void CopyJoinLink() { //IL_003b: 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_0048: Expected O, but got Unknown if (!string.IsNullOrEmpty(cachedLobbyId) && cachedLobbyId != "Unknown") { string text = "steam://joinlobby/3527290/" + cachedLobbyId + "/"; try { GUIUtility.systemCopyBuffer = text; TextEditor val = new TextEditor { text = text }; val.SelectAll(); val.Copy(); copySuccess = true; copySuccessTimer = Time.unscaledTime + 2f; } catch (Exception ex) { LobbyInfoMod.Log.LogError((object)("复制失败: " + ex.Message)); } } } private void UpdateText() { string text = (string.IsNullOrEmpty(cachedLobbyId) ? "等待同步..." : cachedLobbyId); string text2 = (string.IsNullOrEmpty(cachedRelayIp) ? "未知" : cachedRelayIp); string text3 = (copySuccess ? "#90EE90" : "#dfdac2"); string text4 = (copySuccess ? "已复制到剪贴板!" : "按 [C] 复制加入链接"); _sb.Clear(); _sb.Append("大厅号: " + text + "\n"); _sb.Append("中继服务器 IP: " + text2 + "\n"); _sb.Append("服务器位置: " + cachedLocation + "\n"); _sb.Append("" + text4 + "\n"); _sb.Append("按 [J] 再次唤起"); string text5 = _sb.ToString(); if (text5 != _lastStatsText) { _lastStatsText = text5; ((TMP_Text)statsText).text = text5; } } private unsafe string ExtractLobbyId() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) try { Type type = Type.GetType("Peak.Network.SteamLobbyAPI, Assembly-CSharp"); if (type != null) { PropertyInfo property = type.GetProperty("LobbyHandler", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value = property.GetValue(null); if (value != null) { PropertyInfo property2 = value.GetType().GetProperty("LobbySteamId", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property2 != null && property2.GetValue(value) is CSteamID val && ((CSteamID)(ref val)).IsValid()) { return ((object)(*(CSteamID*)(&val))/*cast due to .constrained prefix*/).ToString(); } FieldInfo field = value.GetType().GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null && field.GetValue(value) is CSteamID val2 && ((CSteamID)(ref val2)).IsValid()) { return ((object)(*(CSteamID*)(&val2))/*cast due to .constrained prefix*/).ToString(); } } } } } catch (Exception ex) { LobbyInfoMod.Log.LogWarning((object)("精准提取失败: " + ex.Message)); } return "Unknown"; } private string GetRealRelayIp() { try { LoadBalancingPeer loadBalancingPeer = PhotonNetwork.NetworkingClient.LoadBalancingPeer; FieldInfo field = typeof(PhotonPeer).GetField("socket", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(loadBalancingPeer); if (value != null) { FieldInfo field2 = value.GetType().GetField("remoteEndPoint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 != null && field2.GetValue(value) is IPEndPoint iPEndPoint) { return iPEndPoint.Address.ToString(); } FieldInfo field3 = value.GetType().GetField("ipEndpoint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field3 != null && field3.GetValue(value) is IPEndPoint iPEndPoint2) { return iPEndPoint2.Address.ToString(); } } } string text = PhotonNetwork.NetworkingClient.GameServerAddress; if (text.Contains("://")) { text = text.Split(new string[1] { "://" }, StringSplitOptions.None)[1]; } return text.Split(':')[0]; } catch (Exception ex) { LobbyInfoMod.Log.LogWarning((object)("底层 IP 获取失败: " + ex.Message)); } return "未知"; } private void FetchLocation(string ip, Action callback) { if (string.IsNullOrEmpty(ip) || ip == "未知") { callback("未知 IP"); return; } Task.Run(async delegate { try { string requestUri = "http://ip-api.com/json/" + ip + "?lang=zh-CN"; IpLocationData ipLocationData = JsonUtility.FromJson(await _httpClient.GetStringAsync(requestUri)); string loc = "查询失败"; if (ipLocationData != null && ipLocationData.status == "success") { loc = ipLocationData.country ?? "未知"; if (!string.IsNullOrEmpty(ipLocationData.regionName)) { loc = loc + " - " + ipLocationData.regionName; } if (!string.IsNullOrEmpty(ipLocationData.city)) { loc = loc + " - " + ipLocationData.city; } } lock (mainThreadActions) { mainThreadActions.Enqueue(delegate { callback(loc); }); } } catch { lock (mainThreadActions) { mainThreadActions.Enqueue(delegate { callback("网络错误"); }); } } }); } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } }