using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalError.Lang; using LethalError.Properties; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.UI; using YamlDotNet.Serialization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("EasyTextEffects")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LethalError")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+1eec90e856b4196467366d0a29054941b46862d4")] [assembly: AssemblyProduct("LethalError")] [assembly: AssemblyTitle("LethalError")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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; } } } namespace LethalError { public static class ClientPrefabDiff { private static Dictionary map; public static void Init() { BuildMap(); } public static void BuildMap() { map = new Dictionary(); if (LethalErrorPlugin.config?.Mods == null) { return; } foreach (ModConfig mod in LethalErrorPlugin.config.Mods) { if (mod.Prefabs == null) { continue; } foreach (ModConfig.Prefab prefab in mod.Prefabs) { map[prefab.Hash] = (mod.ModName, prefab.PrefabName); } } } public static void Process(List<(uint hash, string name)> serverList) { Init(); HashSet hashSet = NetworkManager.Singleton.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.Select((KeyValuePair p) => p.Key).ToHashSet(); Dictionary dictionary = serverList.ToDictionary<(uint, string), uint, string>(((uint hash, string name) x) => x.hash, ((uint hash, string name) x) => x.name); List list = dictionary.Keys.Except(hashSet).ToList(); List list2 = hashSet.Except(dictionary.Keys).ToList(); if (list.Any() || list2.Any()) { List list3 = ResolveNames(list2, dictionary); List list4 = ResolveNames(list, dictionary); string text = string.Join("\n", list3); string text2 = string.Join("\n", list4); string text3 = LocalText.GetText("ModMismatch2", text, text2); Patches.SetPendingModMismatchDetails(list3, list4); LethalErrorPlugin.ManualLog.LogWarning((object)text3); GameNetworkManager.Instance.Disconnect(); } } private static List ResolveNames(List hashes, Dictionary serverMap) { List list = new List(); foreach (uint hash in hashes) { ulong key = hash; (string, string) value; string value2; string item = ((!map.TryGetValue(key, out value)) ? ((!serverMap.TryGetValue(hash, out value2)) ? $"Unknown Prefab (Hash: {hash})" : ("Unknown Mod: " + value2)) : (value.Item1 + " (" + value.Item2 + ")")); list.Add(item); } return list.Distinct().ToList(); } private static List ResolveExtra(List hashes) { List list = new List(); foreach (uint hash in hashes) { if (TryGetModName(hash, out string modName)) { list.Add(modName); } else { list.Add($"UnknownPrefab({hash})"); } } return list.Distinct().ToList(); } private static bool TryGetModName(ulong hash, out string modName) { foreach (ModConfig mod in LethalErrorPlugin.config.Mods) { foreach (ModConfig.Prefab prefab in mod.Prefabs) { if (prefab.Hash == hash) { modName = mod.ModName; return true; } } } modName = null; return false; } } [BepInPlugin("LethalError", "chuxia.LethalError", "1.0.5")] public class LethalErrorPlugin : BaseUnityPlugin { public static ManualLogSource ManualLog = null; public static readonly Harmony _harmony = new Harmony("chuxia.LethalError"); public static readonly List VanillaPrefabs = new List { 90896466u, 129367788u, 132513440u, 153348683u, 165354329u, 181065763u, 191913935u, 202426003u, 229852873u, 276978119u, 288960001u, 299647201u, 356651644u, 400294665u, 429829681u, 436137808u, 471591979u, 472780805u, 475937833u, 484661369u, 516507517u, 518371223u, 568460665u, 570495721u, 579959996u, 603300103u, 617338154u, 716660581u, 738627960u, 820092154u, 836821693u, 842876279u, 860552555u, 918740636u, 927582704u, 948167977u, 957872028u, 961522418u, 968052384u, 1062544579u, 1093242804u, 1144478515u, 1177294914u, 1190488538u, 1192602505u, 1208569611u, 1261883438u, 1290082603u, 1291577939u, 1324983542u, 1395910455u, 1398893398u, 1434649207u, 1455339477u, 1473878890u, 1519214796u, 1520713927u, 1525346363u, 1538715501u, 1545508553u, 1557375639u, 1562055063u, 1565614057u, 1585670844u, 1636750849u, 1645880361u, 1645994684u, 1669872752u, 1695918524u, 1708429739u, 1719037155u, 1721201679u, 1724127744u, 1727953579u, 1740344223u, 1808998928u, 1900020765u, 1910674915u, 1948025525u, 1974540975u, 1998237813u, 2023383400u, 2030693286u, 2133670236u, 2183144740u, 2234829884u, 2256688011u, 2270722052u, 2275085878u, 2292481783u, 2294211125u, 2353524689u, 2359790209u, 2437831202u, 2452351744u, 2453550126u, 2456900357u, 2470949680u, 2498931702u, 2513027068u, 2555293264u, 2561288184u, 2639144151u, 2661411798u, 2698950182u, 2733512605u, 2744692569u, 2754618432u, 2759639499u, 2784234648u, 2787274700u, 2825665221u, 2831235556u, 2915516243u, 2925526683u, 2949085139u, 2982659526u, 2995307756u, 3016010214u, 3018959210u, 3025586981u, 3036571934u, 3038553182u, 3051401024u, 3053807618u, 3060733885u, 3063950988u, 3074914178u, 3103629558u, 3115962917u, 3164721612u, 3238162239u, 3243961054u, 3299481859u, 3327936545u, 3330146594u, 3342949139u, 3369713594u, 3372165991u, 3419689129u, 3421797719u, 3429983800u, 3433351349u, 3433739795u, 3484633077u, 3499201763u, 3506119446u, 3508245293u, 3565211967u, 3567956311u, 3569922288u, 3583454401u, 3610174872u, 3612841114u, 3727661730u, 3775810923u, 3782272570u, 3804394268u, 3817036674u, 3854849053u, 3871319671u, 3915035863u, 3920935616u, 3943463324u, 3948016949u, 3959212616u, 3962754254u, 4086908256u, 4100675023u, 4119299708u, 4223888841u, 4288067500u, 178332144u, 218316246u, 1011693577u, 1225366653u, 3123575941u, 3706709186u, 3884775518u, 4063793843u }; private FileSystemWatcher _watcher; public static LethalErrorConfig config { get; set; } public static ConfigEntry Debug { get; set; } public static ConfigEntry Lang { get; set; } public static string configPath { get; set; } public void Awake() { Debug = ((BaseUnityPlugin)this).Config.Bind("LethalError", "Debug", false, "Write Mod Prefabs To File"); Lang = ((BaseUnityPlugin)this).Config.Bind("LethalError", "Language", LocalText.Language.Auto, (ConfigDescription)null); string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; string directoryName = Path.GetDirectoryName(configFilePath); string fileName = Path.GetFileName(configFilePath); _watcher = new FileSystemWatcher(directoryName, fileName); _watcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime; _watcher.Changed += delegate { Thread.Sleep(50); try { ((BaseUnityPlugin)this).Config.Reload(); SetLanguage(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Reload config failed: {arg}"); } }; _watcher.EnableRaisingEvents = true; FileInfo fileInfo = new FileInfo(Assembly.GetExecutingAssembly().Location); configPath = Utility.CombinePaths(new string[2] { fileInfo.Directory.FullName, "LethalError.Mods.yml" }); ManualLog = ((BaseUnityPlugin)this).Logger; LoadConfig(); _harmony.PatchAll(typeof(Patches)); _harmony.PatchAll(typeof(TimeoutPatches)); } private static void SetLanguage() { if (Lang.Value == LocalText.Language.Auto) { string text = CultureInfo.CurrentCulture.Name.ToLower(); if (text.StartsWith("zh-")) { LocalText.CurrentLanguage = LocalText.Language.Chinese; } else { LocalText.CurrentLanguage = LocalText.Language.English; } } else { LocalText.CurrentLanguage = Lang.Value; } } private void Lang_SettingChanged(object sender, EventArgs e) { throw new NotImplementedException(); } public static void SaveConfig() { if (config.Mods == null) { config.Mods = new List(); } File.WriteAllText(configPath, SerializeHelper.YamlSerialize(config)); ManualLog.LogInfo((object)$"Save Mods Success({config.Mods.Count}"); } public static void LoadConfig() { if (!File.Exists(configPath)) { config = new LethalErrorConfig { Mods = new List() }; } else { try { config = SerializeHelper.YamlDeserialize(File.ReadAllText(configPath)); } catch (Exception ex) { ManualLog.LogError((object)("Load Yaml Fail!\r\n" + ex.ToString())); config = new LethalErrorConfig(); } } if (config.Mods == null) { config.Mods = new List(); } SetLanguage(); ManualLog.LogInfo((object)$"Load Mods Success({config.Mods.Count})"); } } public static class TimeoutPatches { [HarmonyPatch] private class ApprovalTimeoutPatch { private static MethodBase TargetMethod() { Type type = AccessTools.Inner(typeof(NetworkConnectionManager), "d__56"); return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null); } private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown List list = new List(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(NetworkConnectionManager), "DisconnectClient", new Type[2] { typeof(ulong), typeof(string) }, (Type[])null); for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], methodInfo)) { list.InsertRange(i, (IEnumerable)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ApprovalTimeoutPatch), "OnTimeout", (Type[])null, (Type[])null)) }); break; } } return list; } private static void OnTimeout(object stateMachine) { ulong num = (ulong)AccessTools.Field(stateMachine.GetType(), "clientId").GetValue(stateMachine); if (!Patches.TimeoutClients.Contains(num)) { LethalErrorPlugin.ManualLog.LogInfo((object)$"客户端连接审批超时: {num}"); Patches.TimeoutClients.Add(num); } } } private static MethodBase TargetMethod() { Type type = AccessTools.Inner(typeof(NetworkConnectionManager), "d__56"); return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null); } } public class Patches { public struct PrefabData { public uint hash; public string prefabName; } private class ReassemblyContext { private int _receivedCount; public int TotalBatches { get; private set; } public List<(uint hash, string name)>[] Batches { get; private set; } public ReassemblyContext(int totalBatches) { Reset(totalBatches); } public void Reset(int totalBatches) { TotalBatches = totalBatches; Batches = new List<(uint, string)>[totalBatches]; _receivedCount = 0; } public void StoreBatch(int index, List<(uint hash, string name)> data) { if (index >= 0 && index < TotalBatches && Batches[index] == null) { Batches[index] = data; _receivedCount++; } } public bool IsComplete() { return _receivedCount == TotalBatches; } } private sealed class ModMismatchDetailsWatcher : MonoBehaviour { public GameObject? MenuNotification; private void Update() { if ((Object)(object)MenuNotification == (Object)null || !MenuNotification.activeInHierarchy) { HideModMismatchDetails(); } } } [CompilerGenerated] private sealed class d__14 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ulong clientId; private ulong 5__1; private ulong 5__2; private List 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__14(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; case 1: <>1__state = -1; if (TimeoutClients.Contains(clientId)) { NetworkManager.Singleton.DisconnectClient(clientId, "LethalError|Timeout" + LocalText.GetText("Timeout")); return false; } if (!ClientHash.TryGetValue(clientId, out 5__1)) { NetworkManager.Singleton.DisconnectClient(clientId, (string)null); return false; } 5__2 = NetworkManager.Singleton.NetworkConfig.GetConfig(true); if (5__1 == 5__2) { NetworkManager.Singleton.DisconnectClient(clientId, ""); return false; } 5__3 = NetworkManager.Singleton.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.Select(delegate(KeyValuePair p) { PrefabData result = default(PrefabData); result.hash = p.Key; result.prefabName = ((Object)p.Value.Prefab).name; return result; }).ToList(); SendPrefabList(clientId, 5__3); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 2; return true; case 2: <>1__state = -1; LethalErrorPlugin.ManualLog.LogInfo((object)$"Kick for ModMismatch|Server:{5__2}|Client:{5__1}"); NetworkManager.Singleton.DisconnectClient(clientId, "LethalError|ModMismatch" + LocalText.GetText("ModMismatch")); 5__3 = null; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__56 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public NetworkConnectionManager __instance; public ulong clientId; private object 5__1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__56(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = AccessTools.DeclaredField(typeof(NetworkConnectionManager), "MessageManager").GetValue(__instance); AccessTools.DeclaredMethod(5__1.GetType(), "ProcessSendQueues", (Type[])null, (Type[])null).Invoke(5__1, null); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; AccessTools.DeclaredMethod(typeof(NetworkConnectionManager), "OnClientDisconnectFromServer", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { clientId }); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static HashSet DelayedClients = new HashSet(); public static HashSet TimeoutClients = new HashSet(); private const string MsgPrefabSync = "LethalError_PrefabSync"; private const int SAFE_PAYLOAD_LIMIT = 900; private static readonly Dictionary s_reassemblyCache = new Dictionary(); private const string ModMismatchDetailsPopupName = "LethalError_ModMismatchDetailsPopup"; private static readonly Vector2 ModMismatchDetailsPopupSize = new Vector2(360f, 230f); private const float ModMismatchMenuNotificationShiftX = -90f; private const float ModMismatchDetailsLocalX = 132f; private const float ModMismatchListBottomPadding = 24f; private static List PendingMissingOnServer = new List(); private static List PendingMissingOnClient = new List(); private static bool ShowModMismatchDetailsForNextNotification; private static GameObject? ModMismatchDetailsPopup; private static bool HasOriginalMenuNotificationPosition; private static Vector2 OriginalMenuNotificationPosition; private static Dictionary ClientHash { get; set; } = new Dictionary(); [HarmonyPatch(typeof(NetworkManager), "SetSingleton")] [HarmonyWrapSafe] [HarmonyPostfix] [HarmonyPriority(100)] public static void SetSingleton(NetworkManager __instance) { ClientHash = new Dictionary(); TimeoutClients = new HashSet(); DelayedClients = new HashSet(); } [HarmonyPostfix] [HarmonyPatch(typeof(NetworkManager), "Initialize")] private static void AfterInitialize() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LethalError_PrefabSync", new HandleNamedMessageDelegate(OnReceivePrefabList)); } [HarmonyPostfix] [HarmonyPatch(typeof(GameNetworkManager), "SetInstanceValuesBackToDefault")] public static void SetInstanceValuesBackToDefault() { if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.CustomMessagingManager != null) { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("LethalError_PrefabSync"); } } [HarmonyPatch(typeof(ConnectionRequestMessage), "Deserialize")] [HarmonyWrapSafe] [HarmonyPostfix] public static void Postfix(ConnectionRequestMessage __instance, ref NetworkContext context) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) if (ClientHash.ContainsKey(context.SenderId)) { ClientHash[context.SenderId] = __instance.ConfigHash; } else { ClientHash.Add(context.SenderId, __instance.ConfigHash); } LethalErrorPlugin.ManualLog.LogInfo((object)$"ConfigHash:{__instance.ConfigHash}|SenderId:{context.SenderId}|Server:{NetworkManager.Singleton.NetworkConfig.GetConfig(true)}"); } [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] [HarmonyWrapSafe] public static void ConnectClientToPlayerObject() { //IL_02aa: Unknown result type (might be due to invalid IL or missing references) if (!LethalErrorPlugin.Debug.Value) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); stringBuilder.AppendLine(); stringBuilder.AppendLine($"ProtocolVersion:{NetworkManager.Singleton.NetworkConfig.ProtocolVersion}"); stringBuilder.AppendLine("15.0.0"); stringBuilder.AppendLine($"ForceSamePrefabs:{NetworkManager.Singleton.NetworkConfig.ForceSamePrefabs}"); FileInfo fileInfo = new FileInfo(Assembly.GetExecutingAssembly().Location); ulong config = NetworkManager.Singleton.NetworkConfig.GetConfig(true); string path = Utility.CombinePaths(new string[2] { fileInfo.Directory.FullName, $"{config}.txt" }); StringBuilder stringBuilder2 = new StringBuilder(); ModConfig modConfig = new ModConfig(); modConfig.ModName = "ChangeNameToTheMod"; modConfig.Prefabs = new List(); foreach (KeyValuePair item in NetworkManager.Singleton.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks.OrderBy, uint>((KeyValuePair x) => x.Key)) { uint key = item.Key; if (!LethalErrorPlugin.VanillaPrefabs.Contains(key)) { stringBuilder.AppendLine($"{((Object)item.Value.Prefab).name}:{key}"); modConfig.Prefabs.Add(new ModConfig.Prefab { Hash = key, PrefabName = ((Object)item.Value.Prefab).name, Nullable = false }); } } stringBuilder.AppendLine($"TickRate:{NetworkManager.Singleton.NetworkConfig.TickRate}"); stringBuilder.AppendLine($"ConnectionApproval:{NetworkManager.Singleton.NetworkConfig.ConnectionApproval}"); stringBuilder.AppendLine($"ForceSamePrefabs:{NetworkManager.Singleton.NetworkConfig.ForceSamePrefabs}"); stringBuilder.AppendLine($"EnableSceneManagement:{NetworkManager.Singleton.NetworkConfig.EnableSceneManagement}"); stringBuilder.AppendLine($"EnsureNetworkVariableLengthSafety:{NetworkManager.Singleton.NetworkConfig.EnsureNetworkVariableLengthSafety}"); stringBuilder.AppendLine($"RpcHashSize:{NetworkManager.Singleton.NetworkConfig.RpcHashSize}"); LethalErrorPlugin.ManualLog.LogInfo((object)$"NetworkConfigValue:{config}{stringBuilder.ToString()}"); File.WriteAllText(path, SerializeHelper.YamlSerialize(new LethalErrorConfig { Mods = new List { modConfig } })); } [HarmonyPrefix] [HarmonyPatch(typeof(NetworkConnectionManager), "DisconnectClient")] [HarmonyWrapSafe] public static bool DisconnectClient(NetworkConnectionManager __instance, ulong clientId, string reason) { if ((Object)(object)StartOfRound.Instance != (Object)null && ((NetworkBehaviour)StartOfRound.Instance).IsHost) { LethalErrorPlugin.ManualLog.LogInfo((object)$"DisconnectClient:{clientId} reason:{reason}"); if (!DelayedClients.Contains(clientId) && string.IsNullOrWhiteSpace(reason)) { LethalErrorPlugin.ManualLog.LogInfo((object)"Delay"); ((MonoBehaviour)StartOfRound.Instance).StartCoroutine(DelayedDisconnect(clientId)); DelayedClients.Add(clientId); return false; } } return true; } [IteratorStateMachine(typeof(d__14))] private static IEnumerator DelayedDisconnect(ulong clientId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__14(0) { clientId = clientId }; } public static void SendPrefabList(ulong clientId, List list) { //IL_0051: 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_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) if (list == null || list.Count == 0) { return; } int num = 0; int num2 = 0; FastBufferWriter val = default(FastBufferWriter); while (num2 < list.Count) { int i = 0; int num3 = 0; int num4 = 8; for (; num2 + i < list.Count; i++) { PrefabData prefabData = list[num2 + i]; ((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, 4096); int position; try { BytePacker.WriteValueBitPacked(val, prefabData.hash); BytePacker.WriteValuePacked(val, prefabData.prefabName); position = ((FastBufferWriter)(ref val)).Position; } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } if (i > 0 && num3 + num4 + position > 900) { break; } num3 += position; } if (i == 0) { i = 1; } num2 += i; num++; } num2 = 0; int num5 = 0; FastBufferWriter val2 = default(FastBufferWriter); FastBufferWriter val3 = default(FastBufferWriter); while (num2 < list.Count) { int j = 0; int num6 = 0; int num7 = 8; for (; num2 + j < list.Count; j++) { PrefabData prefabData2 = list[num2 + j]; ((FastBufferWriter)(ref val2))..ctor(1024, (Allocator)2, 4096); int position2; try { BytePacker.WriteValueBitPacked(val2, prefabData2.hash); BytePacker.WriteValuePacked(val2, prefabData2.prefabName); position2 = ((FastBufferWriter)(ref val2)).Position; } finally { ((IDisposable)(FastBufferWriter)(ref val2)).Dispose(); } if (j > 0 && num6 + num7 + position2 > 900) { break; } num6 += position2; } if (j == 0) { j = 1; } ((FastBufferWriter)(ref val3))..ctor(num6 + 20, (Allocator)2, 102400); try { BytePacker.WriteValueBitPacked(val3, j); BytePacker.WriteValueBitPacked(val3, num5); BytePacker.WriteValueBitPacked(val3, num); for (int k = 0; k < j; k++) { PrefabData prefabData3 = list[num2 + k]; BytePacker.WriteValueBitPacked(val3, prefabData3.hash); BytePacker.WriteValuePacked(val3, prefabData3.prefabName); } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LethalError_PrefabSync", clientId, val3, (NetworkDelivery)2); } finally { ((IDisposable)(FastBufferWriter)(ref val3)).Dispose(); } num2 += j; num5++; } } public static void OnReceivePrefabList(ulong senderClientId, FastBufferReader reader) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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) int num = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref num); int index = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref index); int num2 = default(int); ByteUnpacker.ReadValueBitPacked(reader, ref num2); if (!s_reassemblyCache.TryGetValue(senderClientId, out ReassemblyContext value)) { value = new ReassemblyContext(num2); s_reassemblyCache[senderClientId] = value; } if (value.TotalBatches != num2) { value.Reset(num2); } List<(uint, string)> list = new List<(uint, string)>(num); uint item = default(uint); string item2 = default(string); for (int i = 0; i < num; i++) { ByteUnpacker.ReadValueBitPacked(reader, ref item); ByteUnpacker.ReadValuePacked(reader, ref item2); list.Add((item, item2)); } value.StoreBatch(index, list); if (!value.IsComplete()) { return; } List<(uint, string)> list2 = new List<(uint, string)>(); List<(uint, string)>[] batches = value.Batches; foreach (List<(uint, string)> list3 in batches) { if (list3 != null) { list2.AddRange(list3); } } ClientPrefabDiff.Process(list2); s_reassemblyCache.Remove(senderClientId); } public static void SetPendingModMismatchDetails(List missingOnServer, List missingOnClient) { PendingMissingOnServer = missingOnServer?.ToList() ?? new List(); PendingMissingOnClient = missingOnClient?.ToList() ?? new List(); } private static bool HasPendingModMismatchDetails() { return PendingMissingOnServer.Count > 0 || PendingMissingOnClient.Count > 0; } private static void ClearPendingModMismatchDetails() { PendingMissingOnServer = new List(); PendingMissingOnClient = new List(); } [HarmonyPrefix] [HarmonyPatch(typeof(MenuManager), "DisplayMenuNotification")] [HarmonyWrapSafe] public static bool DisplayMenuNotification(ref string notificationText) { ShowModMismatchDetailsForNextNotification = HasPendingModMismatchDetails(); Match match = Regex.Match(notificationText, "(.*?)"); if (match.Success) { string value = match.Groups[1].Value; string[] array = value.Split('|'); if (array.Length >= 2) { string text = array[0]; string text2 = array[1]; string text3 = ((array.Length > 2) ? array[2] : ""); string text4 = text; string text5 = text4; if (text5 == "LethalError") { ShowModMismatchDetailsForNextNotification = string.Equals(text2, "ModMismatch", StringComparison.OrdinalIgnoreCase) && HasPendingModMismatchDetails(); notificationText = LocalText.GetText(text2, text3); return true; } return true; } } return true; } [HarmonyPostfix] [HarmonyPatch(typeof(MenuManager), "DisplayMenuNotification")] [HarmonyWrapSafe] public static void DisplayMenuNotificationPostfix(MenuManager __instance) { if (ShowModMismatchDetailsForNextNotification) { ShowModMismatchDetails(__instance, PendingMissingOnServer, PendingMissingOnClient); ClearPendingModMismatchDetails(); } else { HideModMismatchDetails(); } ShowModMismatchDetailsForNextNotification = false; } private static void ShowModMismatchDetails(MenuManager menuManager, List missingOnServer, List missingOnClient) { //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)menuManager == (Object)null) && !((Object)(object)menuManager.menuNotification == (Object)null) && !((Object)(object)menuManager.menuNotificationText == (Object)null)) { ShiftMenuNotification(menuManager, -90f); Transform transform = menuManager.menuNotification.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); Transform transform2 = menuManager.menuNotification.transform; GameObject val2 = EnsureModMismatchDetailsPopup(menuManager, transform2); TextMeshProUGUI val3 = FindPopupText(val2, "ServerTitle"); TextMeshProUGUI val4 = FindPopupText(val2, "ClientTitle"); TextMeshProUGUI val5 = FindPopupText(val2, "Description"); TextMeshProUGUI val6 = FindPopupText(val2, "ServerList"); TextMeshProUGUI val7 = FindPopupText(val2, "ClientList"); if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val4 == (Object)null) && !((Object)(object)val5 == (Object)null) && !((Object)(object)val6 == (Object)null) && !((Object)(object)val7 == (Object)null)) { ((TMP_Text)val3).text = LocalText.GetText("ModMismatchDetailsHostMissing"); ((TMP_Text)val4).text = LocalText.GetText("ModMismatchDetailsClientMissing"); ((TMP_Text)val5).text = LocalText.GetText("ModMismatchDetailsDescription"); ((TMP_Text)val6).text = FormatModList(missingOnServer); ((TMP_Text)val7).text = FormatModList(missingOnClient); val2.SetActive(true); Canvas.ForceUpdateCanvases(); UpdateModMismatchDetailsLayout(val2, menuManager); AttachModMismatchDetailsWatcher(val2, menuManager.menuNotification); Canvas.ForceUpdateCanvases(); ResizeScrollContent(val6); ResizeScrollContent(val7); Transform transform3 = val2.transform; RectTransform val8 = (RectTransform)(object)((transform3 is RectTransform) ? transform3 : null); ManualLogSource manualLog = LethalErrorPlugin.ManualLog; object[] obj = new object[6] { (val != null) ? ((Object)val).name : null, null, null, null, null, null }; Transform parent = val2.transform.parent; obj[1] = ((parent != null) ? ((Object)parent).name : null); obj[2] = ((val8 != null) ? new Vector3?(((Transform)val8).localPosition) : null); obj[3] = ((val8 != null) ? new Vector2?(val8.sizeDelta) : null); obj[4] = missingOnServer.Count; obj[5] = missingOnClient.Count; manualLog.LogInfo((object)string.Format("Show ModMismatch details popup. Anchor:{0} Parent:{1} Position:{2} Size:{3} Server:{4} Client:{5}", obj)); } } } private static void HideModMismatchDetails() { if ((Object)(object)ModMismatchDetailsPopup != (Object)null) { ModMismatchDetailsPopup.SetActive(false); } RestoreMenuNotificationPosition(); } private static void ShiftMenuNotification(MenuManager menuManager, float offsetX) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0033: Unknown result type (might be due to invalid IL or missing references) Transform transform = menuManager.menuNotification.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (!((Object)(object)val == (Object)null)) { if (!HasOriginalMenuNotificationPosition) { OriginalMenuNotificationPosition = val.anchoredPosition; HasOriginalMenuNotificationPosition = true; } val.anchoredPosition = OriginalMenuNotificationPosition + new Vector2(offsetX, 0f); } } private static void RestoreMenuNotificationPosition() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (HasOriginalMenuNotificationPosition) { MenuManager val = Object.FindObjectOfType(); RectTransform val2 = (RectTransform)(((Object)(object)val != (Object)null && (Object)(object)val.menuNotification != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val2 != (Object)null) { val2.anchoredPosition = OriginalMenuNotificationPosition; } HasOriginalMenuNotificationPosition = false; } } private static void AttachModMismatchDetailsWatcher(GameObject popup, GameObject menuNotification) { ModMismatchDetailsWatcher modMismatchDetailsWatcher = popup.GetComponent(); if ((Object)(object)modMismatchDetailsWatcher == (Object)null) { modMismatchDetailsWatcher = popup.AddComponent(); } modMismatchDetailsWatcher.MenuNotification = menuNotification; } private static Transform ResolveModMismatchDetailsParent(MenuManager menuManager) { Transform transform = menuManager.menuNotification.transform; Transform val = transform.parent ?? transform; while ((Object)(object)val.parent != (Object)null && IsTightUiContainer(val)) { val = val.parent; } return val; } private static bool IsTightUiContainer(Transform transform) { return (Object)(object)((Component)transform).GetComponent