Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BTD Networking v1.1.1
Network.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Network.Compatibility; using Network.Sending; using Steamworks; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Network")] [assembly: AssemblyDescription("https://valheim.thunderstore.io/package/Smoothbrain/Network")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Network")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("9BC6D744-34E6-432C-929F-371CF06CEFBD")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Network { [BepInPlugin("org.bepinex.plugins.network", "Network", "1.1.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInIncompatibility("org.bepinex.plugins.valheim_plus")] [BepInIncompatibility("VitByr.VBNetTweaks")] public class Network : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } private enum ConfigScope { Installation, ServerHost, Client } private sealed class ConfigurationManagerAttributes { public int? Order; } private const string ModName = "Network"; private const string ModVersion = "1.1.1"; private const string ModGUID = "org.bepinex.plugins.network"; internal const string ReturnToSenderGUID = "redseiko.valheim.returntosender"; public static readonly ManualLogSource NetworkLogger = Logger.CreateLogSource("Network"); private static ConfigEntry<Toggle> enableNetworkingImprovements = null; private static ConfigEntry<Toggle> reportPatchConflicts = null; public static ConfigEntry<Toggle> adaptiveZdoScheduler = null; public static ConfigEntry<float> sendInterval = null; public static ConfigEntry<int> maxPeersPerFrame = null; public static ConfigEntry<Toggle> increaseZdoBatchSize = null; public static ConfigEntry<int> zdoQueueLimit = null; public static ConfigEntry<Toggle> refreshPeerInterestPosition = null; public static ConfigEntry<Toggle> prioritizeActors = null; public static ConfigEntry<Toggle> useImprovedSteamSettings = null; public static ConfigEntry<float> timeoutConnected = null; public static ConfigEntry<int> sendRateMax = null; public static ConfigEntry<int> sendRateMin = null; public static ConfigEntry<int> sendBufferSize = null; public static ConfigEntry<Toggle> smoothMapMarkers = null; public static ConfigEntry<float> mapSendInterval = null; public static ConfigEntry<float> mapTeleportThreshold = null; public static bool ImprovementEnabled(ConfigEntry<Toggle> feature) { return enableNetworkingImprovements.Value == Toggle.On && feature.Value == Toggle.On; } public void Awake() { //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Expected O, but got Unknown int order = 0; enableNetworkingImprovements = Bind<Toggle>("1 - General", "Enable Networking Improvements", Toggle.On, "Master switch for every added feature. Off leaves only Steam's send-limit removal and the early ZDOData connection guard active. The connection timeout stays vanilla. Config values are never synced; change them separately on each server, host or client.", ConfigScope.Installation); reportPatchConflicts = Bind<Toggle>("1 - General", "Report Patch Conflicts", Toggle.On, "Warn when another mod patches the same networking methods.", ConfigScope.Installation); adaptiveZdoScheduler = Bind<Toggle>("2 - ZDO Sending", "Adaptive ZDO Scheduler", Toggle.On, "Replace vanilla's one-peer-per-frame queue with the adaptive round-robin scheduler.", ConfigScope.Installation); sendInterval = Bind<float>("2 - ZDO Sending", "Send Interval", 0.05f, "Slowest allowed full lap. The default targets 20/s, boosts small servers to 30/s, then tapers between 10 and 15 peers. Actual rate cannot exceed framerate. Lower costs real CPU and upstream.", ConfigScope.Installation, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0.01f, 0.2f)); maxPeersPerFrame = Bind<int>("2 - ZDO Sending", "Max Peers Per Frame", 0, "Emergency brake on how much sending work one frame may do. 0 is no cap and the work is already spread evenly across frames, so leave it there unless you are chasing a stutter.", ConfigScope.Installation, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(0, 128)); increaseZdoBatchSize = Bind<Toggle>("2 - ZDO Sending", "Increase Batch Size", Toggle.On, "Use the configured batch size instead of vanilla's 10240-byte limit.", ConfigScope.Installation); zdoQueueLimit = Bind<int>("2 - ZDO Sending", "Batch Size", 20480, "Bytes per ZDO batch (vanilla 10240). Raising this or lowering the send interval costs upstream bandwidth, so watch your host.", ConfigScope.Installation, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(10240, 262144)); refreshPeerInterestPosition = Bind<Toggle>("2 - ZDO Sending", "Refresh Peer Interest Position", Toggle.On, "Use a peer's live character ZDO position when the server chooses nearby objects to send.", ConfigScope.ServerHost); prioritizeActors = Bind<Toggle>("3 - Send Priority", "Prioritize Players And Creatures", Toggle.On, "Bias players, ships and creatures ahead of scenery within vanilla's existing object and ownership tiers.", ConfigScope.ServerHost); useImprovedSteamSettings = Bind<Toggle>("4 - Steam", "Use Improved Steam Settings", Toggle.On, "Use the timeout, rate and buffer settings below. Off removes Steam's send limit, uses a 100 MB client buffer and leaves the timeout vanilla.", ConfigScope.Installation); timeoutConnected = Bind<float>("4 - Steam", "Connection Timeout", 120000f, "Milliseconds before Steam drops an idle connection (vanilla 30000). Applied before each Steam socket opens.", ConfigScope.Installation, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(30000f, 600000f)); sendRateMax = Bind<int>("4 - Steam", "Send Rate Ceiling", 50000000, "Maximum bytes/sec Steam's bandwidth estimator may use (vanilla 153600). This is permission, not a target. Lower it if you want a hard per-connection ceiling.", ConfigScope.Installation, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(153600, 50000000)); sendRateMin = Bind<int>("4 - Steam", "Send Rate Floor", 153600, "Bytes/sec Steam is allowed to throttle down to. Low is good - it's a floor, not a target. Set it to 50000000 to match the ceiling and get the old pinned behaviour back.", ConfigScope.Installation, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(16384, 50000000)); sendBufferSize = Bind<int>("4 - Steam", "Send Buffer Size", 4194304, "Maximum bytes Steam may hold pending per connection (Steam default 524288). Four MB leaves room for bursts without the 100 MB backlog older Network releases allowed.", ConfigScope.Installation, (AcceptableValueBase?)(object)new AcceptableValueRange<int>(524288, 16777216)); smoothMapMarkers = Bind<Toggle>("5 - Map Markers", "Smooth Player Markers", Toggle.On, "Interpolate other players' map markers instead of letting them sit still for two seconds and jump.", ConfigScope.Installation); mapSendInterval = Bind<float>("5 - Map Markers", "Position Send Interval", 0.5f, "Seconds between marker position broadcasts (vanilla player lists update every 2.0). Clients work out their own interpolation delay from what actually arrives.", ConfigScope.ServerHost, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0.1f, 2f)); mapTeleportThreshold = Bind<float>("5 - Map Markers", "Teleport Threshold", 50f, "Metres of movement between updates that counts as a teleport, where the marker snaps instead of sliding.", ConfigScope.Client, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(10f, 500f)); Assembly executingAssembly = Assembly.GetExecutingAssembly(); Harmony val = new Harmony("org.bepinex.plugins.network"); val.PatchAll(executingAssembly); ReturnToSenderCompatibility.Handle(val); ConfigEntry<T> Bind<T>(string section, string name, T defaultValue, string description, ConfigScope scope, AcceptableValueBase? acceptableValues = null) where T : notnull { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown if (1 == 0) { } string text = scope switch { ConfigScope.ServerHost => "Server/Host", ConfigScope.Client => "Client", _ => "This installation", }; if (1 == 0) { } string text2 = text; return ((BaseUnityPlugin)this).Config.Bind<T>(section, name, defaultValue, new ConfigDescription(description + " [Runs on: " + text2 + "]", acceptableValues, new object[1] { new ConfigurationManagerAttributes { Order = (order -= 1) } })); } } private void Start() { if (ImprovementEnabled(reportPatchConflicts)) { ConflictCheck.Report("org.bepinex.plugins.network"); } } } } namespace Network.Sending { internal static class PeerPosition { public static bool TryGet(ZDOID id, out Vector3 position) { //IL_000d: 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) //IL_001e: 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) ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(id) : null); if (val == null) { position = Vector3.zero; return false; } position = val.GetPosition(); return true; } public static Vector3 GetOr(ZDOID id, Vector3 fallback) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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) Vector3 position; return TryGet(id, out position) ? position : fallback; } } public static class PeerSendRate { [HarmonyPatch(typeof(ZDOMan), "SendZDOToPeers2")] private static class ServeEveryPeerOnAnInterval { private static bool Prefix(ZDOMan __instance, float dt) { if (!Network.ImprovementEnabled(Network.adaptiveZdoScheduler)) { ResetState(); return true; } int count = __instance.m_peers.Count; int num = SendBudget.Take(ref budget, count, dt, Network.sendInterval.Value, Network.maxPeersPerFrame.Value); if (num <= 0) { return false; } for (int i = 0; i < num; i++) { ZDOPeer val = __instance.m_peers[(cursor + i) % count]; if (val != null) { ZNetPeer peer = val.m_peer; bool? obj; if (peer == null) { obj = null; } else { ISocket socket = peer.m_socket; obj = ((socket != null) ? new bool?(socket.IsConnected()) : ((bool?)null)); } bool? flag = obj; if (flag == true) { __instance.SendZDOs(val, false); } } } cursor = (cursor + num) % count; __instance.m_sendTimer = 0f; __instance.m_nextSendPeer = -1; return false; } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class ResetOnShutdown { private static void Postfix() { ResetState(); } } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] private static class ConfigureSendZdos { private static int BatchSize() { return Network.ImprovementEnabled(Network.increaseZdoBatchSize) ? Network.zdoQueueLimit.Value : 10240; } private static void Prefix(ZDOPeer peer) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (Network.ImprovementEnabled(Network.refreshPeerInterestPosition) && ZNet.instance.IsServer() && PeerPosition.TryGet(peer.m_peer.m_characterID, out var position)) { peer.m_peer.m_refPos = position; } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo operand = AccessTools.DeclaredMethod(typeof(ConfigureSendZdos), "BatchSize", (Type[])null, (Type[])null); List<CodeInstruction> list2 = list.FindAll((CodeInstruction i) => i.opcode == OpCodes.Ldc_I4 && CodeInstructionExtensions.OperandIs(i, (object)10240)); if (list2.Count != 2) { Network.NetworkLogger.LogWarning((object)$"ZDO batch size patch expected 2 constants, found {list2.Count}. Leaving vanilla sizes alone."); return list; } foreach (CodeInstruction item in list2) { item.opcode = OpCodes.Call; item.operand = operand; } return list; } } private static int cursor; private static float budget; private static void ResetState() { cursor = 0; budget = 0f; } } internal static class SendBudget { private const float SmallServerRate = 1.5f; private const float BoostWorkPeers = 15f; private static float PerPeerRate(int peerCount, float interval) { float num = 1f / Mathf.Max(interval, 0.01f); return (peerCount > 0) ? (num * Mathf.Max(1f, Mathf.Min(1.5f, 15f / (float)peerCount))) : 0f; } public static int Take(ref float budget, int peerCount, float deltaTime, float interval, int maxPerFrame) { if (peerCount <= 0) { budget = 0f; return 0; } budget += (float)peerCount * deltaTime * PerPeerRate(peerCount, interval); int num = (int)budget; budget -= num; if (num <= peerCount) { return (maxPerFrame > 0) ? Mathf.Min(num, maxPerFrame) : num; } num = peerCount; budget = 0f; return (maxPerFrame > 0) ? Mathf.Min(num, maxPerFrame) : num; } } public static class SendPriority { [HarmonyPatch(typeof(ZDOMan), "ServerSortSendZDOS")] private static class PrioritizeActors { private static void Postfix(List<ZDO> objects) { if (!Network.ImprovementEnabled(Network.prioritizeActors) || objects.Count < 2) { return; } prioritized.Clear(); remaining.Clear(); foreach (ZDO @object in objects) { float bonus = GetBonus(@object); if (bonus > 0f) { @object.m_tempSortValue -= bonus; prioritized.Add(@object); } else { remaining.Add(@object); } } if (prioritized.Count == 0) { remaining.Clear(); return; } prioritized.Sort((Comparison<ZDO>)ZDOMan.ServerSendCompare); SortedMerge.Into(objects, prioritized, remaining, (Comparison<ZDO>)ZDOMan.ServerSendCompare); prioritized.Clear(); remaining.Clear(); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ClearPrefabCacheOnSceneLoad { private static void Postfix() { prefabBonuses.Clear(); } } private static readonly Dictionary<int, float> prefabBonuses = new Dictionary<int, float>(); private static readonly List<ZDO> prioritized = new List<ZDO>(); private static readonly List<ZDO> remaining = new List<ZDO>(); private static float GetBonus(ZDO zdo) { int prefab = zdo.GetPrefab(); if (prefabBonuses.TryGetValue(prefab, out var value)) { return value; } if (!Object.op_Implicit((Object)(object)ZNetScene.instance)) { return 0f; } GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); if (!Object.op_Implicit((Object)(object)prefab2)) { return 0f; } Player val = default(Player); Ship val2 = default(Ship); Character val3 = default(Character); value = (prefab2.TryGetComponent<Player>(ref val) ? 120f : (prefab2.TryGetComponent<Ship>(ref val2) ? 80f : ((!prefab2.TryGetComponent<Character>(ref val3)) ? 0f : 40f))); prefabBonuses[prefab] = value; return value; } } internal static class SortedMerge { public static void Into<T>(List<T> destination, List<T> left, List<T> right, Comparison<T> compare) { int i = 0; int j = 0; int num = 0; while (i < left.Count && j < right.Count) { if (compare(left[i], right[j]) <= 0) { destination[num] = left[i]; i++; } else { destination[num] = right[j]; j++; } num++; } for (; i < left.Count; i++) { destination[num] = left[i]; num++; } for (; j < right.Count; j++) { destination[num] = right[j]; num++; } } } } namespace Network.Map { public static class MapPositions { [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static class RegisterRPC { private static void Postfix(ZRoutedRpc __instance) { __instance.Register<ZPackage>("Network_MapPos", (Action<long, ZPackage>)RPC_ReceiveMapPos); } } [HarmonyPatch(typeof(ZNet), "Update")] private static class BroadcastPositions { private static void Postfix(ZNet __instance) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) if (!Network.ImprovementEnabled(Network.smoothMapMarkers) || !__instance.IsServer()) { return; } sendTimer += Time.deltaTime; if (sendTimer < Network.mapSendInterval.Value) { return; } sendTimer %= Network.mapSendInterval.Value; positions.Clear(); ZDOID localPlayerCharacterID = __instance.LocalPlayerCharacterID; if (__instance.IsReferencePositionPublic() && !((ZDOID)(ref localPlayerCharacterID)).IsNone()) { positions.Add((localPlayerCharacterID, PeerPosition.GetOr(localPlayerCharacterID, __instance.GetReferencePosition()))); } foreach (ZNetPeer peer in __instance.GetPeers()) { if (peer.IsReady() && peer.m_publicRefPos && !((ZDOID)(ref peer.m_characterID)).IsNone()) { positions.Add((peer.m_characterID, PeerPosition.GetOr(peer.m_characterID, peer.m_refPos))); } } if (positions.Count == 0) { return; } ZPackage val = new ZPackage(); val.Write(positions.Count); foreach (var (val2, val3) in positions) { val.Write(val2); val.Write(val3); } ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Network_MapPos", new object[1] { val }); if (!Object.op_Implicit((Object)(object)Minimap.instance)) { return; } float time = Time.time; foreach (var (id, position) in positions) { Record(id, position, time); } Prune(time); } } [HarmonyPatch(typeof(Minimap), "UpdatePlayerPins")] private static class SmoothPlayerPins { private static void Postfix(Minimap __instance) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!Network.ImprovementEnabled(Network.smoothMapMarkers) || tracks.Count == 0) { return; } float time = Time.time; int num = Mathf.Min(__instance.m_playerPins.Count, __instance.m_tempPlayerInfo.Count); for (int i = 0; i < num; i++) { PlayerInfo val = __instance.m_tempPlayerInfo[i]; if (tracks.TryGetValue(val.m_characterID, out MarkerTrack value) && value.TryGet(time - value.Delay, out var result) && !(result == __instance.m_playerPins[i].m_pos)) { __instance.m_playerPins[i].m_pos = result; __instance.m_pinUpdateRequired = true; } } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class ClearTracksOnShutdown { private static void Postfix() { tracks.Clear(); sendTimer = 0f; } } private const string RPCName = "Network_MapPos"; private static float sendTimer; private static readonly List<(ZDOID id, Vector3 position)> positions = new List<(ZDOID, Vector3)>(); private static readonly Dictionary<ZDOID, MarkerTrack> tracks = new Dictionary<ZDOID, MarkerTrack>(); private static readonly List<ZDOID> stale = new List<ZDOID>(); private static void Record(ZDOID id, Vector3 position, float now) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!tracks.TryGetValue(id, out MarkerTrack value)) { value = new MarkerTrack(); tracks[id] = value; } value.Add(now, position, Network.mapTeleportThreshold.Value); } private static void RPC_ReceiveMapPos(long sender, ZPackage package) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!Network.ImprovementEnabled(Network.smoothMapMarkers) || !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsServer()) { return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null && sender == serverPeer.m_uid) { float time = Time.time; int num = package.ReadInt(); for (int i = 0; i < num; i++) { Record(package.ReadZDOID(), package.ReadVector3(), time); } Prune(time); } } private static void Prune(float now) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) stale.Clear(); foreach (KeyValuePair<ZDOID, MarkerTrack> track in tracks) { if (now - track.Value.LastArrival > 30f) { stale.Add(track.Key); } } foreach (ZDOID item in stale) { tracks.Remove(item); } } } internal sealed class MarkerTrack { private const int MaxSnapshots = 20; private readonly List<(float time, Vector3 position)> snapshots = new List<(float, Vector3)>(); private Vector3 velocity; private float arrivalGap = 0.5f; public float LastArrival { get; private set; } = -1f; public float Delay => Mathf.Clamp(arrivalGap * 1.3f, 0.15f, 2f); public void Add(float now, Vector3 position, float teleportThreshold) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) if (snapshots.Count > 0 && now <= snapshots[snapshots.Count - 1].time) { return; } if (LastArrival >= 0f) { arrivalGap = Mathf.Lerp(arrivalGap, Mathf.Clamp(now - LastArrival, 0.05f, 3f), 0.25f); } LastArrival = now; if (snapshots.Count > 0) { (float, Vector3) tuple = snapshots[snapshots.Count - 1]; if (Vector3.Distance(tuple.Item2, position) > teleportThreshold) { snapshots.Clear(); velocity = Vector3.zero; } else { float num = now - tuple.Item1; velocity = ((num > 0.01f) ? Vector3.ClampMagnitude((position - tuple.Item2) / num, 50f) : Vector3.zero); } } snapshots.Add((now, position)); while (snapshots.Count > 20) { snapshots.RemoveAt(0); } } public bool TryGet(float renderTime, out Vector3 result) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0116: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) result = Vector3.zero; if (snapshots.Count == 0) { return false; } if (renderTime <= snapshots[0].time) { result = snapshots[0].position; return true; } for (int i = 1; i < snapshots.Count; i++) { if (renderTime <= snapshots[i].time) { (float, Vector3) tuple = snapshots[i - 1]; (float, Vector3) tuple2 = snapshots[i]; result = Vector3.Lerp(tuple.Item2, tuple2.Item2, Mathf.InverseLerp(tuple.Item1, tuple2.Item1, renderTime)); return true; } } (float, Vector3) tuple3 = snapshots[snapshots.Count - 1]; result = tuple3.Item2 + velocity * Mathf.Min(renderTime - tuple3.Item1, arrivalGap); return true; } } } namespace Network.Connection { public static class SteamSettings { [HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")] private static class IncreaseSendingLimit { private static void Postfix() { bool flag; if (Network.ImprovementEnabled(Network.useImprovedSteamSettings)) { flag = SetFloat((ESteamNetworkingConfigValue)25, Network.timeoutConnected.Value); flag &= SetInt((ESteamNetworkingConfigValue)9, Network.sendBufferSize.Value); flag &= SetInt((ESteamNetworkingConfigValue)10, Network.sendRateMin.Value); flag &= SetInt((ESteamNetworkingConfigValue)11, Math.Max(Network.sendRateMax.Value, Network.sendRateMin.Value)); } else { flag = SetInt((ESteamNetworkingConfigValue)10, 50000000); flag &= SetInt((ESteamNetworkingConfigValue)11, 50000000); if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsDedicated()) { flag &= SetInt((ESteamNetworkingConfigValue)9, 100000000); } } if (!flag) { Network.NetworkLogger.LogWarning((object)"Steam rejected a socket setting. The ZDO changes still work, but check this machine's Steam initialization."); } } } private static bool Set<T>(ESteamNetworkingConfigValue setting, ESteamNetworkingConfigDataType dataType, T value) where T : struct { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) GCHandle gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned); try { IntPtr intPtr = gCHandle.AddrOfPinnedObject(); if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated()) { return SteamGameServerNetworkingUtils.SetConfigValue(setting, (ESteamNetworkingConfigScope)1, IntPtr.Zero, dataType, intPtr); } return SteamNetworkingUtils.SetConfigValue(setting, (ESteamNetworkingConfigScope)1, IntPtr.Zero, dataType, intPtr); } finally { gCHandle.Free(); } } private static bool SetInt(ESteamNetworkingConfigValue setting, int value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Set(setting, (ESteamNetworkingConfigDataType)1, value); } private static bool SetFloat(ESteamNetworkingConfigValue setting, float value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Set(setting, (ESteamNetworkingConfigDataType)3, value); } } public static class ZDODataBuffer { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class StartBufferingOnNewConnection { private static void Postfix(ZNet __instance, ZNetPeer peer) { if (!__instance.IsServer()) { List<ZPackage> packages = new List<ZPackage>(); packageBuffers[peer.m_rpc] = packages; peer.m_rpc.Register<ZPackage>("ZDOData", (Action<ZRpc, ZPackage>)delegate(ZRpc _, ZPackage package) { packages.Add(package); }); } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class ClearPackageBufferOnShutdown { private static void Postfix() { packageBuffers.Clear(); } } [HarmonyPatch(typeof(ZNet), "Disconnect", new Type[] { typeof(ZNetPeer) })] private static class ClearPackageBufferOnDisconnect { private static void Postfix(ZNetPeer peer) { packageBuffers.Remove(peer.m_rpc); } } [HarmonyPatch(typeof(ZDOMan), "AddPeer")] private static class EvaluateBufferedPackages { private static void Postfix(ZDOMan __instance, ZNetPeer netPeer) { if (!packageBuffers.TryGetValue(netPeer.m_rpc, out List<ZPackage> value)) { return; } foreach (ZPackage item in value) { __instance.RPC_ZDOData(netPeer.m_rpc, item); } packageBuffers.Remove(netPeer.m_rpc); } } private static readonly Dictionary<ZRpc, List<ZPackage>> packageBuffers = new Dictionary<ZRpc, List<ZPackage>>(); } } namespace Network.Compatibility { internal static class ConflictCheck { private static bool reported; private static readonly (Type type, string method)[] contestedMethods = new(Type, string)[5] { (typeof(ZDOMan), "Update"), (typeof(ZDOMan), "SendZDOToPeers2"), (typeof(ZDOMan), "SendZDOs"), (typeof(ZDOMan), "ServerSortSendZDOS"), (typeof(ZSteamSocket), "RegisterGlobalCallbacks") }; public static void Report(string ownHarmonyId) { if (reported) { return; } reported = true; (Type, string)[] array = contestedMethods; for (int i = 0; i < array.Length; i++) { (Type, string) tuple = array[i]; Type item = tuple.Item1; string item2 = tuple.Item2; MethodBase methodBase = AccessTools.DeclaredMethod(item, item2, (Type[])null, (Type[])null); if (methodBase == null) { Network.NetworkLogger.LogWarning((object)(item.Name + "." + item2 + " not found.")); continue; } Patches patchInfo = Harmony.GetPatchInfo(methodBase); if (patchInfo == null) { continue; } HashSet<string> hashSet = new HashSet<string>(); foreach (string owner in patchInfo.Owners) { bool flag = item == typeof(ZDOMan) && item2 == "Update" && owner == "redseiko.valheim.returntosender"; if (owner != ownHarmonyId && !flag) { hashSet.Add(owner); } } if (hashSet.Count > 0) { Network.NetworkLogger.LogWarning((object)(item.Name + "." + item2 + " is also patched by: " + string.Join(", ", hashSet) + ". Expect one of us to win. If networking misbehaves, remove the other networking mod before reporting a bug.")); } } } } internal static class ReturnToSenderCompatibility { private static readonly MethodInfo? updateMethod = AccessTools.DeclaredMethod(typeof(ZDOMan), "Update", (Type[])null, (Type[])null); public static void Handle(Harmony harmony) { if (IsActive()) { if (!Network.ImprovementEnabled(Network.adaptiveZdoScheduler)) { Network.NetworkLogger.LogInfo((object)"ReturnToSender will control ZDO scheduling because Network's adaptive scheduler is disabled."); } else if (!Remove(harmony)) { Network.NetworkLogger.LogWarning((object)"Could not remove ReturnToSender's ZDO scheduler. Network's adaptive scheduler will not run."); } else { Network.NetworkLogger.LogInfo((object)"ReturnToSender detected. Its ZDO scheduler was disabled so Network's adaptive scheduler can run."); } } } private static bool IsActive() { if (updateMethod == null) { return false; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)updateMethod); if (patchInfo == null) { return false; } foreach (Patch transpiler in patchInfo.Transpilers) { if (transpiler.owner == "redseiko.valheim.returntosender") { return true; } } return false; } private static bool Remove(Harmony harmony) { if (updateMethod == null) { return false; } harmony.Unpatch((MethodBase)updateMethod, (HarmonyPatchType)3, "redseiko.valheim.returntosender"); return !IsActive(); } } }