Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BetterNetworking Valheim v2.3.4
CW_Jesse.BetterNetworking.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Costura; using HarmonyLib; using Steamworks; using UnityEngine; using ZstdSharp; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("CW_Jesse")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("CW_Jesse 2023")] [assembly: AssemblyFileVersion("2.3.2")] [assembly: AssemblyInformationalVersion("2.3.2+b9d42da47b9b3033ec739578a92b112c41e6ba2d")] [assembly: AssemblyProduct("CW_Jesse.BetterNetworking")] [assembly: AssemblyTitle("CW_Jesse.BetterNetworking")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/CW-Jesse/valheim-betternetworking")] [assembly: AssemblyVersion("2.3.2.0")] internal class <Module> { static <Module>() { AssemblyLoader.Attach(); } } namespace CW_Jesse.BetterNetworking { [BepInPlugin("CW_Jesse.BetterNetworking", "Better Networking", "2.3.4")] [BepInIncompatibility("org.bepinex.plugins.network")] [BepInIncompatibility("be.sebastienvercammen.valheim.netcompression")] [BepInIncompatibility("com.github.dalayeth.Networkfix")] [BepInIncompatibility("Steel.ValheimMod")] public class BetterNetworking : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("CW_Jesse.BetterNetworking"); public static ConfigEntry<BN_Logger.Options_Logger_LogLevel> configLogMessages; public static ConfigEntry<BN_Patch_ForceCrossplay.Options_ForceCrossplay> configForceCrossplay; public static ConfigEntry<int> configPlayerLimit; public static ConfigEntry<BN_Patch_Compression.Options_NetworkCompression> configCompressionEnabled; public static ConfigEntry<BN_Patch_UpdateRate.Options_NetworkUpdateRates> configNetworkUpdateRate; public static ConfigEntry<BN_Patch_SendRate.Options_NetworkSendRateMin> configNetworkSendRateMin; public static ConfigEntry<BN_Patch_SendRate.Options_NetworkSendRateMax> configNetworkSendRateMax; public static ConfigEntry<BN_Patch_QueueSize.Options_NetworkQueueSize> configNetworkQueueSize; private void Awake() { BN_Logger.Init(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); BN_Patch_Compression.InitCompressor(); BN_Patch_Compression.InitConfig(((BaseUnityPlugin)this).Config); BN_Patch_UpdateRate.InitConfig(((BaseUnityPlugin)this).Config); BN_Patch_SendRate.InitConfig(((BaseUnityPlugin)this).Config); BN_Patch_QueueSize.InitConfig(((BaseUnityPlugin)this).Config); BN_Patch_DedicatedServer.InitConfig(((BaseUnityPlugin)this).Config); harmony.PatchAll(); } private void OnDestroy() { harmony.UnpatchSelf(); } } [HarmonyPatch] public class BN_Patch_DedicatedServer { private static ConfigFile config; public static void InitConfig(ConfigFile configFile) { config = configFile; } [HarmonyPatch(typeof(ZNet), "IsDedicated")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> DedicatedServerInit(IEnumerable<CodeInstruction> instructions) { bool isDedicated = false; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldc_I4_1) { isDedicated = true; BN_Patch_ForceCrossplay.InitConfig(config); BN_Patch_ChangePlayerLimit.InitConfig(config); } } BN_Utils.isDedicated = isDedicated; return instructions; } } public class BN_Logger { public enum Options_Logger_LogLevel { [Description("Errors/Warnings")] warning, [Description("Errors/Warnings/Messages <b>[default]</b>")] message, [Description("Errors/Warnings/Messages/Info")] info } private static ManualLogSource logger; public static void Init(ManualLogSource logger, ConfigFile config) { BN_Logger.logger = logger; BetterNetworking.configLogMessages = config.Bind<Options_Logger_LogLevel>("Logging", "Log Level", Options_Logger_LogLevel.message, "Better Network's verbosity in console/logs."); } public static void LogError(object data) { logger.LogError(data); } public static void LogWarning(object data) { logger.LogWarning(data); } public static void LogMessage(object data) { if (BetterNetworking.configLogMessages.Value >= Options_Logger_LogLevel.message) { logger.LogMessage(data); } } public static void LogInfo(object data) { if (BetterNetworking.configLogMessages.Value >= Options_Logger_LogLevel.info) { logger.LogInfo(data); } } } internal class BN_Utils { public static bool isDedicated; public static ZNetPeer GetPeer(ZRpc rpc) { foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_rpc == rpc) { return peer; } } return null; } public static ZNetPeer GetPeer(ISocket socket) { foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_socket == socket) { return peer; } } return null; } public static string GetPeerName(ZNetPeer peer) { if (peer == null) { return "[null]"; } if (peer.m_server) { return "[server]"; } return peer.m_playerName + "[" + peer.m_socket.GetHostName() + "]"; } public static string GetPeerName(ISocket socket) { return GetPeerName(GetPeer(socket)); } } [HarmonyPatch] public class BN_Patch_ChangePlayerLimit { [CompilerGenerated] private sealed class <SetPlayerLimit>d__1 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable<CodeInstruction> instructions; public IEnumerable<CodeInstruction> <>3__instructions; private IEnumerator<CodeInstruction> <>7__wrap1; CodeInstruction IEnumerator<CodeInstruction>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SetPlayerLimit>d__1(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = instructions.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; case 2: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { CodeInstruction current = <>7__wrap1.Current; if (BN_Utils.isDedicated && CodeInstructionExtensions.Is(current, OpCodes.Ldc_I4_S, (object)(sbyte)10)) { <>2__current = new CodeInstruction(OpCodes.Ldc_I4_S, (object)(sbyte)BetterNetworking.configPlayerLimit.Value); <>1__state = 1; return true; } <>2__current = current; <>1__state = 2; return true; } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator() { <SetPlayerLimit>d__1 <SetPlayerLimit>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <SetPlayerLimit>d__ = this; } else { <SetPlayerLimit>d__ = new <SetPlayerLimit>d__1(0); } <SetPlayerLimit>d__.instructions = <>3__instructions; return <SetPlayerLimit>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<CodeInstruction>)this).GetEnumerator(); } } public static void InitConfig(ConfigFile config) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown BetterNetworking.configPlayerLimit = config.Bind<int>("Dedicated Server", "Player Limit", 10, new ConfigDescription("Requires restart. Changes player limit for dedicated servers.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 127), Array.Empty<object>())); } [IteratorStateMachine(typeof(<SetPlayerLimit>d__1))] [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> SetPlayerLimit(IEnumerable<CodeInstruction> instructions) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SetPlayerLimit>d__1(-2) { <>3__instructions = instructions }; } } [HarmonyPatch] public class BN_Patch_ForceCrossplay { public enum Options_ForceCrossplay { [Description("Vanilla behaviour <b>[default]</b>")] vanilla, [Description("Crossplay ENABLED")] playfab, [Description("Crossplay DISABLED")] steamworks } public static void InitConfig(ConfigFile config) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown BetterNetworking.configForceCrossplay = config.Bind<Options_ForceCrossplay>("Dedicated Server", "Force Crossplay", Options_ForceCrossplay.vanilla, new ConfigDescription("Requires restart.\nplayfab (crossplay enabled): Forces dedicated servers to use new PlayFab networking stack.\nsteamworks (crossplay disabled): Forces dedicated servers to use Steamworks network stack.\nvanilla: Listen for -crossplay flag.", (AcceptableValueBase)null, Array.Empty<object>())); } [HarmonyPatch(typeof(FejdStartup), "ParseServerArguments")] [HarmonyPostfix] private static void ForceCrossplay() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (BN_Utils.isDedicated) { if (BetterNetworking.configForceCrossplay.Value == Options_ForceCrossplay.playfab) { ZNet.m_onlineBackend = (OnlineBackendType)1; ZPlayFabMatchmaking.LookupPublicIP(); } if (BetterNetworking.configForceCrossplay.Value == Options_ForceCrossplay.steamworks) { ZNet.m_onlineBackend = (OnlineBackendType)0; } } } } [HarmonyPatch] public class BN_Patch_NewConnectionBuffer { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private class StartBufferingOnNewConnection { private static void Postfix(ZNet __instance, ZNetPeer peer) { if (!__instance.IsServer()) { peer.m_rpc.Register<ZPackage>("ZDOData", (Action<ZRpc, ZPackage>)delegate(ZRpc nullPeer, ZPackage package) { packageBuffer.Add(package); }); } } } [HarmonyPatch(typeof(ZDOMan), "AddPeer")] private class SendBufferOnAddPeer { private static void Postfix(ZDOMan __instance, ZNetPeer netPeer) { if (packageBuffer.Count <= 0) { return; } BN_Logger.LogWarning($"Connection buffer: Sending {packageBuffer.Count} buffered packages; Valheim or a mod is trying to send data too early"); foreach (ZPackage item in packageBuffer) { AccessTools.Method(typeof(ZDOMan), "RPC_ZDOData", (Type[])null, (Type[])null).Invoke(__instance, new object[2] { netPeer.m_rpc, item }); } packageBuffer.Clear(); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ClearBufferOnShutdown { private static void Postfix() { packageBuffer.Clear(); } } private static readonly List<ZPackage> packageBuffer = new List<ZPackage>(); } [HarmonyPatch] public class BN_Patch_QueueSize { public enum Options_NetworkQueueSize { [Description("80 KB")] _80KB, [Description("64 KB")] _64KB, [Description("48 KB")] _48KB, [Description("32 KB <b>[default]</b>")] _32KB, [Description("[Valheim default]")] _vanilla } private const int DEFAULT_QUEUE_SIZE = 10240; private const int DEFAULT_MINIMUM_QUEUE_SIZE = 2048; public static void InitConfig(ConfigFile config) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown BetterNetworking.configNetworkQueueSize = config.Bind<Options_NetworkQueueSize>("Networking", "Queue Size", Options_NetworkQueueSize._32KB, new ConfigDescription("The better your upload speed, the higher you can set this.\nHigher options aren't available as they can cause errors in Steam.\nWith compression and 100% update rate, 32 KB spikes upload speeds to 256 KB/s. (32KB*0.4*20/s)---\nIf others experience lag/desync for things <i>around</i> you, increase your queue size.\nIf your <i>character</i> is lagging for others, decrease your update rate and/or queue size.", (AcceptableValueBase)null, Array.Empty<object>())); } [HarmonyPatch(typeof(ZSteamSocket), "GetSendQueueSize")] [HarmonyPostfix] private static void Steamworks_GetSendQueueSize(ref int __result) { switch (BetterNetworking.configNetworkQueueSize.Value) { case Options_NetworkQueueSize._80KB: __result -= 71680; break; case Options_NetworkQueueSize._64KB: __result -= 55296; break; case Options_NetworkQueueSize._48KB: __result -= 38912; break; case Options_NetworkQueueSize._32KB: __result -= 22528; break; } } [HarmonyPatch(typeof(ZPlayFabSocket), "GetSendQueueSize")] [HarmonyPrefix] private static bool PlayFab_GetSendQueueSize(ref int __result, ref InFlightQueue ___m_inFlightQueue) { switch (BetterNetworking.configNetworkQueueSize.Value) { case Options_NetworkQueueSize._80KB: __result = (int)(___m_inFlightQueue.Bytes - 71680); return false; case Options_NetworkQueueSize._64KB: __result = (int)(___m_inFlightQueue.Bytes - 55296); return false; case Options_NetworkQueueSize._48KB: __result = (int)(___m_inFlightQueue.Bytes - 38912); return false; case Options_NetworkQueueSize._32KB: __result = (int)(___m_inFlightQueue.Bytes - 22528); return false; default: return true; } } } [HarmonyPatch] public class BN_Patch_SendRate { public enum Options_NetworkSendRateMin { [Description("1024 KB/s | 8 Mbit/s")] _1024KB, [Description("768 KB/s | 6 Mbit/s")] _768KB, [Description("512 KB/s | 4 Mbit/s")] _512KB, [Description("256 KB/s | 2 Mbit/s <b>[default]</b>")] _256KB, [Description("150 KB/s | 1.2 Mbit/s [Valheim default]")] _150KB } public enum Options_NetworkSendRateMax { [Description("1024 KB/s | 8 Mbit/s <b>[default]</b>")] _1024KB, [Description("768 KB/s | 6 Mbit/s")] _768KB, [Description("512 KB/s | 4 Mbit/s")] _512KB, [Description("256 KB/s | 2 Mbit/s")] _256KB, [Description("150 KB/s | 1.2 Mbit/s [Valheim default]")] _150KB } [HarmonyPatch(typeof(SteamNetworkingUtils))] [HarmonyPatch(typeof(SteamGameServerNetworkingUtils))] private class NetworkSendRate_Patch { public static int SendRateMin => BetterNetworking.configNetworkSendRateMin.Value switch { Options_NetworkSendRateMin._1024KB => 1048576, Options_NetworkSendRateMin._768KB => 786432, Options_NetworkSendRateMin._512KB => 524288, Options_NetworkSendRateMin._256KB => 262144, _ => 153600, }; public static int SendRateMax => BetterNetworking.configNetworkSendRateMax.Value switch { Options_NetworkSendRateMax._1024KB => 1048576, Options_NetworkSendRateMax._768KB => 786432, Options_NetworkSendRateMax._512KB => 524288, Options_NetworkSendRateMax._256KB => 262144, _ => 153600, }; public static void SetSendRateMinFromConfig() { SetSteamNetworkConfig((ESteamNetworkingConfigValue)10, SendRateMin); } public static void SetSendRateMaxFromConfig() { SetSteamNetworkConfig((ESteamNetworkingConfigValue)11, SendRateMax); } public static void SetSendBufferSize() { SetSteamNetworkConfig((ESteamNetworkingConfigValue)9, 524288); } private static int GetSteamNetworkConfig(ESteamNetworkingConfigValue valueType) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) if ((Object)(object)ZNet.instance == (Object)null) { BN_Logger.LogInfo($"Steamworks: Unable to get net config while disconnected: {valueType}"); return -1; } ulong num = 4uL; byte[] value = new byte[num]; GCHandle gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned); try { ESteamNetworkingConfigDataType val = default(ESteamNetworkingConfigDataType); if (BN_Utils.isDedicated) { SteamGameServerNetworkingUtils.GetConfigValue(valueType, (ESteamNetworkingConfigScope)1, IntPtr.Zero, ref val, gCHandle.AddrOfPinnedObject(), ref num); } else { SteamNetworkingUtils.GetConfigValue(valueType, (ESteamNetworkingConfigScope)1, IntPtr.Zero, ref val, gCHandle.AddrOfPinnedObject(), ref num); } } catch { BN_Logger.LogError($"Steamworks: Unable to get net config: {valueType}"); } gCHandle.Free(); return BitConverter.ToInt32(value, 0); } private static void SetSteamNetworkConfig(ESteamNetworkingConfigValue valueType, int value) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_00aa: 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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null) { BN_Logger.LogInfo($"Steamworks: Unable to set net config while disconnected: {valueType}"); return; } int steamNetworkConfig = GetSteamNetworkConfig(valueType); GCHandle gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned); try { if (BN_Utils.isDedicated) { SteamGameServerNetworkingUtils.SetConfigValue(valueType, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle.AddrOfPinnedObject()); } else { SteamNetworkingUtils.SetConfigValue(valueType, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle.AddrOfPinnedObject()); } } catch { BN_Logger.LogError($"Steamworks: Unable to set net config: {valueType}"); } gCHandle.Free(); BN_Logger.LogMessage($"Steamworks: {valueType}: {steamNetworkConfig} -> {GetSteamNetworkConfig(valueType)} (attempted {value})"); } [HarmonyPatch("SetConfigValue")] private static void Prefix(ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, IntPtr scopeObj, ESteamNetworkingConfigDataType eDataType, ref IntPtr pArg) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) BN_Logger.LogInfo($"Steamworks: {eValue}: {GetSteamNetworkConfig(eValue)} -> {Marshal.ReadInt32(pArg)}"); } } [HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")] private class PreventValheimControlOfNetworkRate_Patch { private static void Postfix() { NetworkSendRate_Patch.SetSendRateMinFromConfig(); NetworkSendRate_Patch.SetSendRateMaxFromConfig(); } } private const int DEFAULT_SEND_BUFFER_SIZE = 524288; private const int SEND_BUFFER_SIZE = 524288; public static void InitConfig(ConfigFile config) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown BetterNetworking.configNetworkSendRateMin = config.Bind<Options_NetworkSendRateMin>("Networking (Steamworks)", "Minimum Send Rate", Options_NetworkSendRateMin._256KB, new ConfigDescription("Steamworks: The minimum speed Steam will <i>attempt</i> to send data.\n<b>Lower this below your internet upload speed.</b>\n", (AcceptableValueBase)null, Array.Empty<object>())); BetterNetworking.configNetworkSendRateMax = config.Bind<Options_NetworkSendRateMax>("Networking (Steamworks)", "Maximum Send Rate", Options_NetworkSendRateMax._1024KB, new ConfigDescription("Steamworks: The maximum speed Steam will <i>attempt</i> to send data.\nIf you have a low upload speed, lower this <i>below</i> your internet upload speed.\n", (AcceptableValueBase)null, Array.Empty<object>())); ConfigNetworkSendRateSettings_Listen(); } public static void ConfigNetworkSendRateSettings_Listen() { BetterNetworking.configNetworkSendRateMin.SettingChanged += ConfigNetworkSendRateMin_SettingChanged; BetterNetworking.configNetworkSendRateMax.SettingChanged += ConfigNetworkSendRateMax_SettingChanged; } private static void ConfigNetworkSendRateMin_SettingChanged(object sender, EventArgs e) { if ((int)(BetterNetworking.configNetworkSendRateMin.Value + 1) < (int)BetterNetworking.configNetworkSendRateMax.Value) { BetterNetworking.configNetworkSendRateMax.Value = (Options_NetworkSendRateMax)(BetterNetworking.configNetworkSendRateMin.Value + 1); } NetworkSendRate_Patch.SetSendRateMinFromConfig(); } private static void ConfigNetworkSendRateMax_SettingChanged(object sender, EventArgs e) { if ((int)BetterNetworking.configNetworkSendRateMax.Value > (int)(BetterNetworking.configNetworkSendRateMin.Value + 1)) { BetterNetworking.configNetworkSendRateMin.Value = (Options_NetworkSendRateMin)(BetterNetworking.configNetworkSendRateMax.Value - 1); } NetworkSendRate_Patch.SetSendRateMaxFromConfig(); } } public class BN_Patch_UpdateRate { public enum Options_NetworkUpdateRates { [Description("100% <b>[default]</b>")] _100, [Description("75%")] _75, [Description("50%")] _50 } [HarmonyPatch(typeof(ZDOMan))] private class NetworkUpdateFrequency_Patch { [HarmonyPatch("SendZDOToPeers2")] private static void Prefix(ref float dt) { switch (BetterNetworking.configNetworkUpdateRate.Value) { case Options_NetworkUpdateRates._75: dt *= 0.75f; break; case Options_NetworkUpdateRates._50: dt *= 0.5f; break; } } } public static void InitConfig(ConfigFile config) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown BetterNetworking.configNetworkUpdateRate = config.Bind<Options_NetworkUpdateRates>("Networking", "Update Rate", Options_NetworkUpdateRates._100, new ConfigDescription("Reducing this can help if your upload speed is low.\n100%: 20 updates/second\n75%: 15 updates/second\n50%: 10 updates/second", (AcceptableValueBase)null, Array.Empty<object>())); } } [HarmonyPatch] public class BN_Patch_Compression { public enum Options_NetworkCompression { [Description("Enabled <b>[default]</b>")] @true, [Description("Disabled")] @false } private static string ZSTD_DICT_RESOURCE_NAME = "CW_Jesse.BetterNetworking.dict.small"; private static int ZSTD_LEVEL = 1; private static Compressor compressor; private static Decompressor decompressor; private const string RPC_COMPRESSION_VERSION = "CW_Jesse.BetterNetworking.CompressionVersion"; private const string RPC_COMPRESSION_ENABLED = "CW_Jesse.BetterNetworking.CompressionEnabled"; private const string RPC_COMPRESSION_STARTED = "CW_Jesse.BetterNetworking.CompressedStarted"; public static void InitCompressor() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown byte[] array; using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(ZSTD_DICT_RESOURCE_NAME)) { array = new byte[stream.Length]; stream.Read(array, 0, (int)stream.Length); } compressor = new Compressor(ZSTD_LEVEL); compressor.LoadDictionary(array); decompressor = new Decompressor(); decompressor.LoadDictionary(array); } public static void InitConfig(ConfigFile config) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown BetterNetworking.configCompressionEnabled = config.Bind<Options_NetworkCompression>("Networking", "Compression Enabled", Options_NetworkCompression.@true, new ConfigDescription("Keep this enabled unless comparing difference.\n---\nCrossplay enabled: Increases speed and strength of network compression.\nCrossplay disabled: Adds network compression.", (AcceptableValueBase)null, Array.Empty<object>())); BetterNetworking.configCompressionEnabled.SettingChanged += ConfigCompressionEnabled_SettingChanged; } private static void ConfigCompressionEnabled_SettingChanged(object sender, EventArgs e) { SetCompressionEnabledFromConfig(); } private static void SetCompressionEnabledFromConfig() { bool compressionEnabled; if (BetterNetworking.configCompressionEnabled.Value == Options_NetworkCompression.@true) { compressionEnabled = true; BN_Logger.LogMessage("Compression: Enabling"); } else { compressionEnabled = false; BN_Logger.LogMessage("Compression: Disabling"); } CompressionStatus.ourStatus.compressionEnabled = compressionEnabled; SendCompressionEnabledStatus(); } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPostfix] private static void OnConnect(ref ZNetPeer peer) { CompressionStatus.AddSocket(peer.m_socket); RegisterRPCs(peer); SendCompressionVersion(peer); } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPrefix] private static void OnDisconnectPrefix(ZNetPeer peer) { BN_Logger.LogMessage("Compression: " + BN_Utils.GetPeerName(peer) + " disconnected"); } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPostfix] private static void OnDisconnectPostfix(ZNetPeer peer) { CompressionStatus.RemoveSocket(peer.m_socket); } internal static byte[] Compress(byte[] buffer) { byte[] array = compressor.Wrap((ReadOnlySpan<byte>)buffer).ToArray(); if (BetterNetworking.configLogMessages.Value >= BN_Logger.Options_Logger_LogLevel.info && buffer.Length > 256) { float num = (float)array.Length / (float)buffer.Length * 100f; BN_Logger.LogInfo(string.Format("Compression: Sent {0} B compressed to {1}%", buffer.Length, num.ToString("0"))); } return array; } internal static byte[] Decompress(byte[] compressedBuffer) { byte[] array = decompressor.Unwrap((ReadOnlySpan<byte>)compressedBuffer, int.MaxValue).ToArray(); if (BetterNetworking.configLogMessages.Value >= BN_Logger.Options_Logger_LogLevel.info && array.Length > 256) { float num = (float)compressedBuffer.Length / (float)array.Length * 100f; BN_Logger.LogInfo(string.Format("Compression: Received {0} B compressed to {1}%", array.Length, num.ToString("0"))); } return array; } private static void RegisterRPCs(ZNetPeer peer) { peer.m_rpc.Register<int>("CW_Jesse.BetterNetworking.CompressionVersion", (Action<ZRpc, int>)RPC_CompressionVersion); peer.m_rpc.Register<bool>("CW_Jesse.BetterNetworking.CompressionEnabled", (Action<ZRpc, bool>)RPC_CompressionEnabled); peer.m_rpc.Register<bool>("CW_Jesse.BetterNetworking.CompressedStarted", (Action<ZRpc, bool>)RPC_CompressionStarted); } public static void SendCompressionVersion(ZNetPeer peer) { peer.m_rpc.Invoke("CW_Jesse.BetterNetworking.CompressionVersion", new object[1] { CompressionStatus.ourStatus.version }); } private static void RPC_CompressionVersion(ZRpc rpc, int version) { ZNetPeer peer = BN_Utils.GetPeer(rpc); CompressionStatus.SetVersion(peer.m_socket, version); if (CompressionStatus.ourStatus.version == version) { BN_Logger.LogMessage("Compression: Compatible with " + BN_Utils.GetPeerName(peer)); } else if (CompressionStatus.ourStatus.version > version) { BN_Logger.LogWarning($"Compression: {BN_Utils.GetPeerName(peer)} ({version}) has an older version of Better Networking; they should update"); } else if (version > 0) { BN_Logger.LogError($"Compression: {BN_Utils.GetPeerName(peer)} ({version}) has a newer version of Better Networking; you should update"); } if (CompressionStatus.GetIsCompatibleWith(peer.m_socket)) { SendCompressionEnabledStatus(peer); } } private static void SendCompressionEnabledStatus() { if ((Object)(object)ZNet.instance == (Object)null) { return; } foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (CompressionStatus.GetIsCompatibleWith(peer.m_socket)) { SendCompressionEnabledStatus(peer); } } } private static void SendCompressionEnabledStatus(ZNetPeer peer) { if (!((Object)(object)ZNet.instance == (Object)null)) { peer.m_rpc.Invoke("CW_Jesse.BetterNetworking.CompressionEnabled", new object[1] { CompressionStatus.ourStatus.compressionEnabled }); if (CompressionStatus.ourStatus.compressionEnabled && CompressionStatus.GetCompressionEnabled(peer.m_socket)) { SendCompressionStarted(peer, started: true); } else { SendCompressionStarted(peer, started: false); } } } private static void RPC_CompressionEnabled(ZRpc rpc, bool peerCompressionEnabled) { ZNetPeer peer = BN_Utils.GetPeer(rpc); CompressionStatus.SetCompressionEnabled(peer.m_socket, peerCompressionEnabled); if (CompressionStatus.ourStatus.compressionEnabled && peerCompressionEnabled) { SendCompressionStarted(peer, started: true); } else { SendCompressionStarted(peer, started: false); } } private static void SendCompressionStarted(ZNetPeer peer, bool started) { if (!((Object)(object)ZNet.instance == (Object)null) && CompressionStatus.GetSendCompressionStarted(peer.m_socket) != started) { peer.m_rpc.Invoke("CW_Jesse.BetterNetworking.CompressedStarted", new object[1] { started }); Flush(peer); CompressionStatus.SetSendCompressionStarted(peer.m_socket, started); BN_Logger.LogMessage($"Compression: Compression to {BN_Utils.GetPeerName(peer)}: {started}"); } } private static void Flush(ZNetPeer peer) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_000b: Invalid comparison between Unknown and I4 OnlineBackendType onlineBackend = ZNet.m_onlineBackend; if ((int)onlineBackend != 0) { if ((int)onlineBackend == 1) { BN_Patch_Compression_PlayFab.FlushQueue(peer.m_socket); } } else { peer.m_socket.Flush(); } } private static void RPC_CompressionStarted(ZRpc rpc, bool peerCompressionStarted) { ZNetPeer peer = BN_Utils.GetPeer(rpc); CompressionStatus.SetReceiveCompressionStarted(peer.m_socket, peerCompressionStarted); BN_Logger.LogMessage($"Compression: Compression from {BN_Utils.GetPeerName(peer)}: {peerCompressionStarted}"); } } [HarmonyPatch] public static class BN_Patch_Compression_PlayFab { private static Dictionary<PlayFabZLibWorkQueue, ZPlayFabSocket> workQueueSockets = new Dictionary<PlayFabZLibWorkQueue, ZPlayFabSocket>(); [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void SocketOpen0(ref ZPlayFabSocket __instance, ref PlayFabZLibWorkQueue ___m_zlibWorkQueue) { SocketOpen(ref __instance, ref ___m_zlibWorkQueue); } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void SocketOpen1(ref ZPlayFabSocket __instance, ref PlayFabZLibWorkQueue ___m_zlibWorkQueue) { SocketOpen(ref __instance, ref ___m_zlibWorkQueue); } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void SocketOpen2(ref ZPlayFabSocket __instance, ref PlayFabZLibWorkQueue ___m_zlibWorkQueue) { SocketOpen(ref __instance, ref ___m_zlibWorkQueue); } private static void SocketOpen(ref ZPlayFabSocket __instance, ref PlayFabZLibWorkQueue ___m_zlibWorkQueue) { workQueueSockets.Add(___m_zlibWorkQueue, __instance); BN_Logger.LogMessage("PlayFab: Added socket " + BN_Utils.GetPeerName((ISocket)(object)__instance)); } [HarmonyPatch(typeof(ZPlayFabSocket), "Dispose")] [HarmonyPostfix] private static void SocketClose(ref PlayFabZLibWorkQueue ___m_zlibWorkQueue) { workQueueSockets.Remove(___m_zlibWorkQueue); BN_Logger.LogMessage("PlayFab: Removed socket"); } [HarmonyPatch(typeof(PlayFabZLibWorkQueue), "DoCompress")] [HarmonyPrefix] private static bool PlayFab_Compress(ref PlayFabZLibWorkQueue __instance, ref Queue<byte[]> ___m_inCompress, ref Queue<byte[]> ___m_outCompress) { if (!workQueueSockets.TryGetValue(__instance, out var value)) { return true; } if (!CompressionStatus.GetSendCompressionStarted((ISocket)(object)value)) { return true; } while (___m_inCompress.Count > 0) { try { ___m_outCompress.Enqueue(BN_Patch_Compression.Compress(___m_inCompress.Dequeue())); } catch { BN_Logger.LogError("PlayFab: Failed BN compress"); } } return false; } [HarmonyPatch(typeof(PlayFabZLibWorkQueue), "DoUncompress")] [HarmonyPrefix] private static bool PlayFab_Decompress(ref PlayFabZLibWorkQueue __instance, ref Queue<byte[]> ___m_inDecompress, ref Queue<byte[]> ___m_outDecompress) { bool flag = false; if (workQueueSockets.TryGetValue(__instance, out var value)) { flag = CompressionStatus.GetReceiveCompressionStarted((ISocket)(object)value); } while (___m_inDecompress.Count > 0) { byte[] array = ___m_inDecompress.Dequeue(); try { ___m_outDecompress.Enqueue(BN_Patch_Compression.Decompress(array)); if (!CompressionStatus.GetReceiveCompressionStarted((ISocket)(object)value)) { BN_Logger.LogMessage("PlayFab: Received unexpected compressed message from " + BN_Utils.GetPeerName((ISocket)(object)value)); CompressionStatus.SetReceiveCompressionStarted((ISocket)(object)value, started: true); } } catch { if (flag) { BN_Logger.LogInfo("PlayFab: Failed BN decompress"); } try { ___m_outDecompress.Enqueue((byte[])AccessTools.Method(typeof(PlayFabZLibWorkQueue), "UncompressOnThisThread", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { array })); if (CompressionStatus.GetReceiveCompressionStarted((ISocket)(object)value)) { BN_Logger.LogMessage("PlayFab: Received unexpected vanilla message from " + BN_Utils.GetPeerName((ISocket)(object)value)); CompressionStatus.SetReceiveCompressionStarted((ISocket)(object)value, started: false); } } catch { BN_Logger.LogMessage("PlayFab: Failed vanilla decompress; keeping data (this data would have been lost without Better Networking)"); ___m_outDecompress.Enqueue(array); } } } return false; } public static void FlushQueue(ISocket socket) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown PlayFabZLibWorkQueue obj = (PlayFabZLibWorkQueue)AccessTools.Field(typeof(ZPlayFabSocket), "m_zlibWorkQueue").GetValue(socket); Mutex mutex = (Mutex)AccessTools.Field(typeof(PlayFabZLibWorkQueue), "s_workersMutex").GetValue(obj); List<PlayFabZLibWorkQueue> obj2 = (List<PlayFabZLibWorkQueue>)AccessTools.Field(typeof(PlayFabZLibWorkQueue), "s_workers").GetValue(obj); MethodInfo methodInfo = AccessTools.Method(typeof(PlayFabZLibWorkQueue), "Execute", (Type[])null, (Type[])null); mutex.WaitOne(); foreach (PlayFabZLibWorkQueue item in obj2) { methodInfo.Invoke(item, new object[0]); } mutex.ReleaseMutex(); AccessTools.Method(typeof(ZPlayFabSocket), "LateUpdate", (Type[])null, (Type[])null).Invoke(socket, null); } } [HarmonyPatch] public static class BN_Patch_Compression_Steamworks { private const int k_nSteamNetworkingSend_Reliable = 8; private const int k_cbMaxSteamNetworkingSocketsMessageSizeSend = 524288; [HarmonyPatch(typeof(ZSteamSocket), "SendQueuedPackages")] [HarmonyPrefix] private static bool Steamworks_SendCompressedPackages(ref ZSteamSocket __instance, ref Queue<byte[]> ___m_sendQueue) { if (!__instance.IsConnected()) { return false; } if (!CompressionStatus.GetSendCompressionStarted((ISocket)(object)__instance)) { return true; } ___m_sendQueue = new Queue<byte[]>(___m_sendQueue.Select((byte[] p) => BN_Patch_Compression.Compress(p))); return true; } [HarmonyPatch(typeof(ZSteamSocket), "Recv")] [HarmonyPostfix] private static void Steamworks_ReceiveCompressedPackages(ref ZPackage __result, ref ZSteamSocket __instance) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (!__instance.IsConnected() || __result == null) { return; } try { byte[] array = BN_Patch_Compression.Decompress(__result.GetArray()); __result = new ZPackage(array); if (!CompressionStatus.GetReceiveCompressionStarted((ISocket)(object)__instance)) { BN_Logger.LogMessage("Compression (Steamworks): Received unexpected compressed message from " + BN_Utils.GetPeerName((ISocket)(object)__instance)); CompressionStatus.SetReceiveCompressionStarted((ISocket)(object)__instance, started: true); } } catch { if (CompressionStatus.GetReceiveCompressionStarted((ISocket)(object)__instance)) { BN_Logger.LogMessage("Compression (Steamworks): Received unexpected uncompressed message from " + BN_Utils.GetPeerName((ISocket)(object)__instance)); CompressionStatus.SetReceiveCompressionStarted((ISocket)(object)__instance, started: false); } } } } internal static class CompressionStatus { public class SocketCompressionStatus { public int version; public bool compressionEnabled; public bool receivingCompressed; public bool sendingCompressed; } private const int COMPRESSION_VERSION = 6; private const int COMPRESSION_VERSION_UNKNOWN = 0; public static SocketCompressionStatus ourStatus = new SocketCompressionStatus { version = 6, compressionEnabled = (BetterNetworking.configCompressionEnabled.Value == BN_Patch_Compression.Options_NetworkCompression.@true) }; private static readonly Dictionary<ISocket, SocketCompressionStatus> socketStatuses = new Dictionary<ISocket, SocketCompressionStatus>(); public static bool AddSocket(ISocket socket) { if (socket == null) { BN_Logger.LogWarning("Compression: Tried to add null peer"); return false; } if (IsSocketExist(socket)) { BN_Logger.LogWarning("Compression: Removing existing peer (" + BN_Utils.GetPeerName(socket) + "); did they lose internet or Alt+F4?"); RemoveSocket(socket); } BN_Logger.LogMessage("Compression: " + BN_Utils.GetPeerName(socket) + " connected"); socketStatuses.Add(socket, new SocketCompressionStatus()); return true; } public static void RemoveSocket(ISocket socket) { if (!IsSocketExist(socket)) { BN_Logger.LogWarning("Compression: Tried to remove non-existent peer: " + BN_Utils.GetPeerName(socket)); } else { socketStatuses.Remove(socket); } } public static bool IsSocketExist(ISocket socket) { if (socket != null && socketStatuses.ContainsKey(socket)) { return true; } return false; } public static int GetVersion(ISocket socket) { if (!IsSocketExist(socket)) { return 0; } return socketStatuses[socket].version; } public static void SetVersion(ISocket socket, int theirVersion) { if (IsSocketExist(socket)) { socketStatuses[socket].version = theirVersion; } } public static bool GetIsCompatibleWith(ISocket socket) { if (!IsSocketExist(socket)) { return false; } return ourStatus.version == GetVersion(socket); } public static bool GetCompressionEnabled(ISocket socket) { if (!IsSocketExist(socket)) { return false; } return socketStatuses[socket].compressionEnabled; } public static void SetCompressionEnabled(ISocket socket, bool enabled) { if (IsSocketExist(socket)) { socketStatuses[socket].compressionEnabled = enabled; } } public static bool GetSendCompressionStarted(ISocket socket) { if (!IsSocketExist(socket)) { return false; } return socketStatuses[socket].sendingCompressed; } public static void SetSendCompressionStarted(ISocket socket, bool started) { if (IsSocketExist(socket)) { socketStatuses[socket].sendingCompressed = started; } } public static bool GetReceiveCompressionStarted(ISocket socket) { if (!IsSocketExist(socket)) { return false; } return socketStatuses[socket].receivingCompressed; } public static void SetReceiveCompressionStarted(ISocket socket, bool started) { if (IsSocketExist(socket)) { socketStatuses[socket].receivingCompressed = started; } } } } namespace Costura { [CompilerGenerated] internal static class AssemblyLoader { private static object nullCacheLock = new object(); private static Dictionary<string, bool> nullCache = new Dictionary<string, bool>(); private static Dictionary<string, string> assemblyNames = new Dictionary<string, string>(); private static Dictionary<string, string> symbolNames = new Dictionary<string, string>(); private static int isAttached; private static string CultureToString(CultureInfo culture) { if (culture == null) { return ""; } return culture.Name; } private static Assembly ReadExistingAssembly(AssemblyName name) { AppDomain currentDomain = AppDomain.CurrentDomain; Assembly[] assemblies = currentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { AssemblyName name2 = assembly.GetName(); if (string.Equals(name2.Name, name.Name, StringComparison.InvariantCultureIgnoreCase) && string.Equals(CultureToString(name2.CultureInfo), CultureToString(name.CultureInfo), StringComparison.InvariantCultureIgnoreCase)) { return assembly; } } return null; } private static void CopyTo(Stream source, Stream destination) { byte[] array = new byte[81920]; int count; while ((count = source.Read(array, 0, array.Length)) != 0) { destination.Write(array, 0, count); } } private static Stream LoadStream(string fullName) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); if (fullName.EndsWith(".compressed")) { using (Stream stream = executingAssembly.GetManifestResourceStream(fullName)) { using DeflateStream source = new DeflateStream(stream, CompressionMode.Decompress); MemoryStream memoryStream = new MemoryStream(); CopyTo(source, memoryStream); memoryStream.Position = 0L; return memoryStream; } } return executingAssembly.GetManifestResourceStream(fullName); } private static Stream LoadStream(Dictionary<string, string> resourceNames, string name) { if (resourceNames.TryGetValue(name, out var value)) { return LoadStream(value); } return null; } private static byte[] ReadStream(Stream stream) { byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); return array; } private static Assembly ReadFromEmbeddedResources(Dictionary<string, string> assemblyNames, Dictionary<string, string> symbolNames, AssemblyName requestedAssemblyName) { string text = requestedAssemblyName.Name.ToLowerInvariant(); if (requestedAssemblyName.CultureInfo != null && !string.IsNullOrEmpty(requestedAssemblyName.CultureInfo.Name)) { text = requestedAssemblyName.CultureInfo.Name + "." + text; } byte[] rawAssembly; using (Stream stream = LoadStream(assemblyNames, text)) { if (stream == null) { return null; } rawAssembly = ReadStream(stream); } using (Stream stream2 = LoadStream(symbolNames, text)) { if (stream2 != null) { byte[] rawSymbolStore = ReadStream(stream2); return Assembly.Load(rawAssembly, rawSymbolStore); } } return Assembly.Load(rawAssembly); } public static Assembly ResolveAssembly(object sender, ResolveEventArgs e) { lock (nullCacheLock) { if (nullCache.ContainsKey(e.Name)) { return null; } } AssemblyName assemblyName = new AssemblyName(e.Name); Assembly assembly = ReadExistingAssembly(assemblyName); if ((object)assembly != null) { return assembly; } assembly = ReadFromEmbeddedResources(assemblyNames, symbolNames, assemblyName); if ((object)assembly == null) { lock (nullCacheLock) { nullCache[e.Name] = true; } if ((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0) { assembly = Assembly.Load(assemblyName); } } return assembly; } static AssemblyLoader() { assemblyNames.Add("costura", "costura.costura.dll.compressed"); symbolNames.Add("costura", "costura.costura.pdb.compressed"); assemblyNames.Add("microsoft.bcl.asyncinterfaces", "costura.microsoft.bcl.asyncinterfaces.dll.compressed"); assemblyNames.Add("system.buffers", "costura.system.buffers.dll.compressed"); assemblyNames.Add("system.diagnostics.diagnosticsource", "costura.system.diagnostics.diagnosticsource.dll.compressed"); assemblyNames.Add("system.memory", "costura.system.memory.dll.compressed"); assemblyNames.Add("system.numerics.vectors", "costura.system.numerics.vectors.dll.compressed"); assemblyNames.Add("system.runtime.compilerservices.unsafe", "costura.system.runtime.compilerservices.unsafe.dll.compressed"); assemblyNames.Add("system.threading.tasks.extensions", "costura.system.threading.tasks.extensions.dll.compressed"); assemblyNames.Add("zstdsharp", "costura.zstdsharp.dll.compressed"); } public static void Attach() { if (Interlocked.Exchange(ref isAttached, 1) == 1) { return; } AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e) { lock (nullCacheLock) { if (nullCache.ContainsKey(e.Name)) { return null; } } AssemblyName assemblyName = new AssemblyName(e.Name); Assembly assembly = ReadExistingAssembly(assemblyName); if ((object)assembly != null) { return assembly; } assembly = ReadFromEmbeddedResources(assemblyNames, symbolNames, assemblyName); if ((object)assembly == null) { lock (nullCacheLock) { nullCache[e.Name] = true; } if ((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0) { assembly = Assembly.Load(assemblyName); } } return assembly; }; } } } internal class CW_JesseBetterNetworking_ProcessedByFody { internal const string FodyVersion = "6.6.4.0"; internal const string Costura = "5.7.0"; }