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 kou fixdesync v1.0.1
kou_fixdesync.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using KouFixDesync.Patches; using Microsoft.CodeAnalysis; using Steamworks; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("TestHarness")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("kou_fixdesync")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("kou_fixdesync")] [assembly: AssemblyTitle("kou_fixdesync")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 KouFixDesync { [BepInPlugin("kou.fixdesync", "kou_fixdesync", "1.0.1")] public class Plugin : BaseUnityPlugin { public const string GUID = "kou.fixdesync"; public const string NAME = "kou_fixdesync"; public const string VERSION = "1.0.1"; internal static Plugin Instance; internal static ManualLogSource Log; internal ConfigEntry<bool> CfgWindowEnabled; internal ConfigEntry<int> CfgWindowBytes; internal ConfigEntry<int> CfgMinWindowBytes; internal ConfigEntry<bool> CfgAdaptiveWindow; internal ConfigEntry<int> CfgTargetRateKBps; internal ConfigEntry<bool> CfgCadenceEnabled; internal ConfigEntry<int> CfgSendIntervalMs; internal ConfigEntry<bool> CfgSteamRatesEnabled; internal ConfigEntry<int> CfgRateMinKBps; internal ConfigEntry<int> CfgRateMaxKBps; internal ConfigEntry<bool> CfgDistantSyncEnabled; internal ConfigEntry<int> CfgDistantThreshold; internal ConfigEntry<bool> CfgOwnershipEnabled; internal ConfigEntry<int> CfgOwnershipPingCeiling; internal ConfigEntry<int> CfgOwnershipPingFloor; internal ConfigEntry<int> CfgOwnershipCooldownSec; private FileSystemWatcher _cfgWatcher; private volatile bool _cfgDirty; private bool _reloadScheduled; private float _reloadDueTime; private void Awake() { //IL_0247: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; CfgWindowEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1.SendWindow", "Enabled", true, "Enlarge the per-peer ZDO send window (vanilla: 10240 bytes incl. unacked data - the main desync cause)."); CfgWindowBytes = ((BaseUnityPlugin)this).Config.Bind<int>("1.SendWindow", "WindowBytes", 61440, "Send window size in bytes. Hard-clamped to 10240-262144 (Steamworks drops single messages >512KB)."); CfgMinWindowBytes = ((BaseUnityPlugin)this).Config.Bind<int>("1.SendWindow", "MinWindowBytes", 2048, "Minimum free window required before sending a batch (vanilla: 2048). Clamped 1024-8192."); CfgAdaptiveWindow = ((BaseUnityPlugin)this).Config.Bind<bool>("1.SendWindow", "PingAdaptive", true, "Scale each peer's window with its measured round-trip time (window = TargetRate x RTT). High-ping players get bigger windows automatically."); CfgTargetRateKBps = ((BaseUnityPlugin)this).Config.Bind<int>("1.SendWindow", "TargetRateKBps", 300, "Target per-peer send rate in KB/s used for the ping-adaptive window. Clamped 60-2048."); CfgCadenceEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2.SendCadence", "Enabled", true, "Service ALL peers every send tick instead of vanilla's one-peer-per-frame round robin."); CfgSendIntervalMs = ((BaseUnityPlugin)this).Config.Bind<int>("2.SendCadence", "SendIntervalMs", 50, "Send tick interval in milliseconds (vanilla: 50). Clamped 20-200."); CfgSteamRatesEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3.SteamRates", "Enabled", true, "Raise Steam networking send rate limits (vanilla pins min=max=150 KB/s)."); CfgRateMinKBps = ((BaseUnityPlugin)this).Config.Bind<int>("3.SteamRates", "SendRateMinKBps", 256, "Steam SendRateMin in KB/s. Clamped 150-4096."); CfgRateMaxKBps = ((BaseUnityPlugin)this).Config.Bind<int>("3.SteamRates", "SendRateMaxKBps", 1024, "Steam SendRateMax in KB/s. Keeping max > min lets Steam's congestion control work. Clamped to >= min, <= 8192."); CfgDistantSyncEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4.DistantSync", "Enabled", true, "Sync distant-zone objects when fewer than DistantThreshold near objects are queued (vanilla threshold: 10)."); CfgDistantThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("4.DistantSync", "DistantThreshold", 30, "Queue-size threshold below which distant objects are added to the sync list. Clamped 10-200."); CfgOwnershipEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("5.SmartOwnership", "Enabled", true, "SERVER ONLY: assign mob/object simulation ownership to the lowest-ping player covering the area, and migrate it off high-ping players."); CfgOwnershipPingCeiling = ((BaseUnityPlugin)this).Config.Bind<int>("5.SmartOwnership", "PingCeilingMs", 150, "Migrate objects away from an owner whose ping exceeds this (ms)."); CfgOwnershipPingFloor = ((BaseUnityPlugin)this).Config.Bind<int>("5.SmartOwnership", "PingFloorMs", 80, "Only migrate when a candidate with ping below this (ms) also covers the area."); CfgOwnershipCooldownSec = ((BaseUnityPlugin)this).Config.Bind<int>("5.SmartOwnership", "CooldownSec", 10, "Per-object cooldown between ownership migrations, to prevent flapping."); Settings.ApplyLocal(); new Harmony("kou.fixdesync").PatchAll(); Log.LogInfo((object)"kou_fixdesync 1.0.1 loaded, patches applied"); StartConfigWatcher(); } private void StartConfigWatcher() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; _cfgWatcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)) { NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime) }; FileSystemEventHandler value = delegate { _cfgDirty = true; }; _cfgWatcher.Changed += value; _cfgWatcher.Created += value; _cfgWatcher.Renamed += delegate { _cfgDirty = true; }; _cfgWatcher.EnableRaisingEvents = true; Log.LogInfo((object)"kou_fixdesync: watching config file for live reload (no restart needed)"); } catch (Exception ex) { Log.LogWarning((object)("kou_fixdesync: could not start config watcher, live reload disabled: " + ex.Message)); } } private void Update() { if (_cfgDirty) { _cfgDirty = false; _reloadScheduled = true; _reloadDueTime = Time.time + 0.5f; } if (_reloadScheduled && Time.time >= _reloadDueTime) { _reloadScheduled = false; ReloadFromDisk(); } } private void ReloadFromDisk() { try { ((BaseUnityPlugin)this).Config.Reload(); bool flag = (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer(); if ((Object)(object)ZNet.instance != (Object)null && !flag) { Log.LogInfo((object)"kou_fixdesync: config file reloaded, but the server dictates config while connected - local edits apply when you host or play solo."); return; } Settings.ApplyLocal(); SteamRatePatch.Apply(); if (flag) { ConfigSyncPatch.BroadcastToPeers(); } Log.LogInfo((object)"kou_fixdesync: config reloaded live (no restart needed)."); } catch (Exception ex) { Log.LogWarning((object)("kou_fixdesync: live config reload failed: " + ex.Message)); } } private void OnDestroy() { if (_cfgWatcher != null) { _cfgWatcher.EnableRaisingEvents = false; _cfgWatcher.Dispose(); _cfgWatcher = null; } } } internal static class Settings { public const int PkgVersion = 1; public const int AbsoluteMaxWindow = 262144; public static bool WindowEnabled = true; public static int WindowBytes = 61440; public static int MinWindowBytes = 2048; public static bool AdaptiveWindow = true; public static int TargetRateKBps = 300; public static bool CadenceEnabled = true; public static int SendIntervalMs = 50; public static bool SteamRatesEnabled = true; public static int RateMinKBps = 256; public static int RateMaxKBps = 1024; public static bool DistantSyncEnabled = true; public static int DistantThreshold = 30; public static bool OwnershipEnabled = true; public static int OwnershipPingCeiling = 150; public static int OwnershipPingFloor = 80; public static int OwnershipCooldownSec = 10; public static void ApplyLocal() { Plugin instance = Plugin.Instance; WindowEnabled = instance.CfgWindowEnabled.Value; WindowBytes = Clamp(instance.CfgWindowBytes.Value, 10240, 262144); MinWindowBytes = Clamp(instance.CfgMinWindowBytes.Value, 1024, 8192); AdaptiveWindow = instance.CfgAdaptiveWindow.Value; TargetRateKBps = Clamp(instance.CfgTargetRateKBps.Value, 60, 2048); CadenceEnabled = instance.CfgCadenceEnabled.Value; SendIntervalMs = Clamp(instance.CfgSendIntervalMs.Value, 20, 200); SteamRatesEnabled = instance.CfgSteamRatesEnabled.Value; RateMinKBps = Clamp(instance.CfgRateMinKBps.Value, 150, 4096); RateMaxKBps = Clamp(instance.CfgRateMaxKBps.Value, RateMinKBps, 8192); DistantSyncEnabled = instance.CfgDistantSyncEnabled.Value; DistantThreshold = Clamp(instance.CfgDistantThreshold.Value, 10, 200); OwnershipEnabled = instance.CfgOwnershipEnabled.Value; OwnershipPingCeiling = Clamp(instance.CfgOwnershipPingCeiling.Value, 50, 1000); OwnershipPingFloor = Clamp(instance.CfgOwnershipPingFloor.Value, 10, OwnershipPingCeiling); OwnershipCooldownSec = Clamp(instance.CfgOwnershipCooldownSec.Value, 1, 300); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"kou_fixdesync: local config applied"); } } public static void WritePackage(ZPackage pkg) { pkg.Write(1); pkg.Write(WindowEnabled); pkg.Write(WindowBytes); pkg.Write(MinWindowBytes); pkg.Write(AdaptiveWindow); pkg.Write(TargetRateKBps); pkg.Write(CadenceEnabled); pkg.Write(SendIntervalMs); pkg.Write(SteamRatesEnabled); pkg.Write(RateMinKBps); pkg.Write(RateMaxKBps); pkg.Write(DistantSyncEnabled); pkg.Write(DistantThreshold); } public static void ReadPackage(ZPackage pkg) { int num = pkg.ReadInt(); if (num != 1) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"kou_fixdesync: server config version {num} != {1}, keeping local values"); } return; } WindowEnabled = pkg.ReadBool(); WindowBytes = Clamp(pkg.ReadInt(), 10240, 262144); MinWindowBytes = Clamp(pkg.ReadInt(), 1024, 8192); AdaptiveWindow = pkg.ReadBool(); TargetRateKBps = Clamp(pkg.ReadInt(), 60, 2048); CadenceEnabled = pkg.ReadBool(); SendIntervalMs = Clamp(pkg.ReadInt(), 20, 200); SteamRatesEnabled = pkg.ReadBool(); RateMinKBps = Clamp(pkg.ReadInt(), 150, 4096); RateMaxKBps = Clamp(pkg.ReadInt(), RateMinKBps, 8192); DistantSyncEnabled = pkg.ReadBool(); DistantThreshold = Clamp(pkg.ReadInt(), 10, 200); ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogInfo((object)($"kou_fixdesync: server-dictated config applied (window={WindowBytes} adaptive={AdaptiveWindow} " + $"cadence={CadenceEnabled}/{SendIntervalMs}ms rates={RateMinKBps}-{RateMaxKBps}KB/s distant={DistantThreshold})")); } } private static int Clamp(int v, int min, int max) { return Mathf.Clamp(v, min, max); } } } namespace KouFixDesync.Patches { internal static class ConfigSyncPatch { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class OnNewConnectionPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown peer.m_rpc.Register<ZPackage>("KouFixDesync_Cfg", (Action<ZRpc, ZPackage>)OnConfigReceived); if (__instance.IsServer()) { ZPackage val = new ZPackage(); Settings.WritePackage(val); peer.m_rpc.Invoke("KouFixDesync_Cfg", new object[1] { val }); } } } [HarmonyPatch(typeof(ZNet), "Awake")] private static class AwakePatch { [HarmonyPostfix] private static void Postfix() { Settings.ApplyLocal(); } } private const string RpcName = "KouFixDesync_Cfg"; private static void OnConfigReceived(ZRpc rpc, ZPackage pkg) { if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()) { Settings.ReadPackage(pkg); SteamRatePatch.Apply(); } } internal static void BroadcastToPeers() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } int num = 0; foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer?.m_rpc != null) { ZPackage val = new ZPackage(); Settings.WritePackage(val); peer.m_rpc.Invoke("KouFixDesync_Cfg", new object[1] { val }); num++; } } if (num > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)$"kou_fixdesync: pushed updated config to {num} connected peer(s)."); } } } } [HarmonyPatch(typeof(ZDOMan), "CreateSyncList")] internal static class DistantSyncPatch { [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { int replaced = 0; foreach (CodeInstruction instruction in instructions) { if (replaced == 0 && instruction.opcode == OpCodes.Ldc_I4_S && Convert.ToInt32(instruction.operand) == 10) { replaced++; yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DistantSyncPatch), "GetThreshold", (Type[])null, (Type[])null)) { labels = instruction.labels, blocks = instruction.blocks }; } else { yield return instruction; } } if (replaced != 1) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"kou_fixdesync: CreateSyncList transpiler matched {replaced} (expected 1) - game update may have changed the method"); } } } public static int GetThreshold() { if (!Settings.DistantSyncEnabled) { return 10; } return Settings.DistantThreshold; } } [HarmonyPatch(typeof(ZDOMan), "ReleaseNearbyZDOS")] internal static class OwnershipPatch { private static readonly List<ZDO> _tempObjects = new List<ZDO>(); private static readonly Dictionary<ZDOID, float> _lastMigration = new Dictionary<ZDOID, float>(); private static float _lastCacheClean; [HarmonyPrefix] private static bool Prefix(ZDOMan __instance, Vector3 refPosition, long uid) { //IL_0022: 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_0028: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if (!Settings.OwnershipEnabled || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return true; } Vector2s zone = ZoneSystem.GetZone(refPosition); SimulationDistance syncedSimulationDistance = ZNet.instance.GetSyncedSimulationDistance(); SimulationDistance val = default(SimulationDistance); ((SimulationDistance)(ref val))..ctor(((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance, 0, ((SimulationDistance)(ref syncedSimulationDistance)).IsClassic); _tempObjects.Clear(); __instance.FindSectorObjects(zone, val, _tempObjects, (List<ZDO>)null); List<ZNetPeer> peers = ZNet.instance.GetPeers(); long sessionID = ZDOMan.GetSessionID(); float time = Time.time; CleanMigrationCache(time); foreach (ZDO tempObject in _tempObjects) { if (!tempObject.Persistent) { continue; } Vector3 position = tempObject.GetPosition(); long owner = tempObject.GetOwner(); if (owner == uid) { if (!ZNetScene.InActiveArea(position, zone)) { tempObject.SetOwner(0L); } else if (uid != sessionID) { TryMigrate(tempObject, position, owner, peers, time); } } else if ((!tempObject.HasOwner() || !IsInPeerActiveArea(position, owner)) && ZNetScene.InActiveArea(position, zone)) { tempObject.SetOwner(BestOwnerFor(position, uid, peers)); } } return false; } private static long BestOwnerFor(Vector3 position, long fallbackUid, List<ZNetPeer> peers) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) long result = fallbackUid; int num = int.MaxValue; foreach (ZNetPeer peer in peers) { if (ZNetScene.InActiveArea(position, peer.GetRefPos())) { int pingMs = GetPingMs(peer); if (pingMs < num) { num = pingMs; result = peer.m_uid; } } } return result; } private static void TryMigrate(ZDO zdo, Vector3 position, long owner, List<ZNetPeer> peers, float now) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_00bc: Unknown result type (might be due to invalid IL or missing references) ZNetPeer peer = ZNet.instance.GetPeer(owner); if (peer == null || GetPingMs(peer) <= Settings.OwnershipPingCeiling || (_lastMigration.TryGetValue(zdo.m_uid, out var value) && now - value < (float)Settings.OwnershipCooldownSec)) { return; } ZNetPeer val = null; int num = int.MaxValue; foreach (ZNetPeer peer2 in peers) { if (peer2.m_uid != owner && ZNetScene.InActiveArea(position, peer2.GetRefPos())) { int pingMs = GetPingMs(peer2); if (pingMs < num) { num = pingMs; val = peer2; } } } if (val != null && num < Settings.OwnershipPingFloor) { zdo.SetOwner(val.m_uid); _lastMigration[zdo.m_uid] = now; } } private static bool IsInPeerActiveArea(Vector3 position, long uid) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) if (uid == ZDOMan.GetSessionID()) { return ZNetScene.InActiveArea(position, ZNet.instance.GetReferencePosition()); } ZNetPeer peer = ZNet.instance.GetPeer(uid); if (peer == null) { return false; } return ZNetScene.InActiveArea(position, peer.GetRefPos()); } private static int GetPingMs(ZNetPeer peer) { if (peer.m_socket == null || !PingUtil.TryGetPing(peer.m_socket, out var pingMs)) { return int.MaxValue; } return pingMs; } private static void CleanMigrationCache(float now) { if (!(now - _lastCacheClean < 60f) && _lastMigration.Count >= 512) { _lastCacheClean = now; _lastMigration.Clear(); } } } internal static class PingUtil { private static bool _clientDead; private static bool _gameServerDead; private static bool _announced; private static FieldInfo _conField; public static bool TryGetPing(ISocket socket, out int pingMs) { pingMs = 0; if (socket == null) { return false; } if (!_clientDead) { try { float num = default(float); float num2 = default(float); float num3 = default(float); float num4 = default(float); socket.GetConnectionQuality(ref num, ref num2, ref pingMs, ref num3, ref num4); return true; } catch { _clientDead = true; } } if (!_gameServerDead) { if (TryGameServerPing(socket, out pingMs, out var apiThrew)) { if (!_announced) { _announced = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"kou_fixdesync: reading per-peer ping via the Steam game-server interface (dedicated server)."); } } return true; } if (apiThrew) { _gameServerDead = true; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)"kou_fixdesync: per-peer ping unavailable via client and game-server interfaces; ping-adaptive window and ping-based ownership disabled for this session. Fixed send-window, cadence and distant-sync fixes stay active."); } } } pingMs = 0; return false; } private static bool TryGameServerPing(ISocket socket, out int pingMs, out bool apiThrew) { //IL_0053: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_006b: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Invalid comparison between Unknown and I4 //IL_0093: Unknown result type (might be due to invalid IL or missing references) pingMs = 0; apiThrew = false; if (!(socket is ZSteamSocket)) { return false; } HSteamNetConnection val2; try { if (_conField == null) { _conField = AccessTools.Field(typeof(ZSteamSocket), "m_con"); } if (!(_conField?.GetValue(socket) is HSteamNetConnection val) || val == HSteamNetConnection.Invalid) { return false; } val2 = val; } catch { return false; } try { SteamNetConnectionRealTimeStatus_t val3 = default(SteamNetConnectionRealTimeStatus_t); SteamNetConnectionRealTimeLaneStatus_t val4 = default(SteamNetConnectionRealTimeLaneStatus_t); if ((int)SteamGameServerNetworkingSockets.GetConnectionRealTimeStatus(val2, ref val3, 0, ref val4) == 1) { pingMs = val3.m_nPing; return true; } return false; } catch { apiThrew = true; return false; } } } [HarmonyPatch(typeof(ZDOMan), "SendZDOToPeers2")] internal static class SendCadencePatch { private static readonly FieldInfo PeersField = AccessTools.Field(typeof(ZDOMan), "m_peers"); private static readonly FieldInfo NextSendPeerField = AccessTools.Field(typeof(ZDOMan), "m_nextSendPeer"); private static readonly MethodInfo SendZDOsMethod = AccessTools.Method(typeof(ZDOMan), "SendZDOs", (Type[])null, (Type[])null); private static float _timer; private static readonly object[] _args = new object[2]; [HarmonyPrefix] private static bool Prefix(ZDOMan __instance, float dt) { if (!Settings.CadenceEnabled) { return true; } IList list = (IList)PeersField.GetValue(__instance); if (list == null || list.Count == 0) { return false; } _timer += dt; if (_timer < (float)Settings.SendIntervalMs / 1000f) { return false; } _timer = 0f; _args[1] = false; for (int i = 0; i < list.Count; i++) { _args[0] = list[i]; SendZDOsMethod.Invoke(__instance, _args); } NextSendPeerField.SetValue(__instance, -1); return false; } } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] internal static class SendWindowPatch { private struct PingCache { public float Time; public int Ping; } private static FieldInfo _zdoPeerPeerField; private static readonly Dictionary<object, PingCache> _pingCache = new Dictionary<object, PingCache>(); [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { int windows = 0; int mins = 0; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num && num == 10240) { windows++; yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null) { labels = instruction.labels, blocks = instruction.blocks }; yield return CodeInstruction.Call(typeof(SendWindowPatch), "GetWindow", (Type[])null, (Type[])null); } else if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num2 && num2 == 2048) { mins++; yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(SendWindowPatch), "GetMinWindow", (Type[])null, (Type[])null)) { labels = instruction.labels, blocks = instruction.blocks }; } else { yield return instruction; } } if (windows != 2 || mins != 1) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"kou_fixdesync: SendZDOs transpiler matched {windows}x10240 (expected 2), {mins}x2048 (expected 1) - game update may have changed the method"); } } } public static int GetWindow(object zdoPeer) { if (!Settings.WindowEnabled) { return 10240; } int num = Settings.WindowBytes; if (Settings.AdaptiveWindow) { int peerPingMs = GetPeerPingMs(zdoPeer); if (peerPingMs > 0) { int num2 = (int)((long)Settings.TargetRateKBps * 1024L * peerPingMs / 1000); if (num2 > num) { num = num2; } } } return Mathf.Min(num, 262144); } public static int GetMinWindow() { if (!Settings.WindowEnabled) { return 2048; } return Settings.MinWindowBytes; } private static int GetPeerPingMs(object zdoPeer) { if (zdoPeer == null) { return 0; } float time = Time.time; if (_pingCache.TryGetValue(zdoPeer, out var value) && time - value.Time < 1f) { return value.Ping; } int pingMs = 0; if (_zdoPeerPeerField == null) { _zdoPeerPeerField = AccessTools.Field(zdoPeer.GetType(), "m_peer"); } object? obj = _zdoPeerPeerField?.GetValue(zdoPeer); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && val.m_socket != null) { PingUtil.TryGetPing(val.m_socket, out pingMs); } if (_pingCache.Count > 64) { _pingCache.Clear(); } _pingCache[zdoPeer] = new PingCache { Time = time, Ping = pingMs }; return pingMs; } } [HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")] internal static class SteamRatePatch { private static bool _useGameServer; [HarmonyPostfix] private static void Postfix() { Apply(); } public static void Apply() { if (!Settings.SteamRatesEnabled) { return; } try { SetGlobalInt((ESteamNetworkingConfigValue)10, Settings.RateMinKBps * 1024); SetGlobalInt((ESteamNetworkingConfigValue)11, Settings.RateMaxKBps * 1024); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)($"kou_fixdesync: Steam send rate set to {Settings.RateMinKBps}-{Settings.RateMaxKBps} KB/s" + (_useGameServer ? " (game-server interface)" : ""))); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("kou_fixdesync: could not set Steam send rates: " + ex.Message)); } } } private static void SetGlobalInt(ESteamNetworkingConfigValue key, int value) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) GCHandle gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned); try { if (_useGameServer) { SetVia(gameServer: true, key, gCHandle.AddrOfPinnedObject()); return; } try { SetVia(gameServer: false, key, gCHandle.AddrOfPinnedObject()); } catch { _useGameServer = true; SetVia(gameServer: true, key, gCHandle.AddrOfPinnedObject()); } } finally { gCHandle.Free(); } } private static void SetVia(bool gameServer, ESteamNetworkingConfigValue key, IntPtr valuePtr) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) if (gameServer) { SteamGameServerNetworkingUtils.SetConfigValue(key, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, valuePtr); } else { SteamNetworkingUtils.SetConfigValue(key, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, valuePtr); } } } }