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 VBNetTweaks v0.4.3
VBNetTweaks.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net.Http; 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 System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Steamworks; using UnityEngine; using VBNetTweaks.Patches; using VBNetTweaks.Utils; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("VBNetTweaks")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("VitByr")] [assembly: AssemblyProduct("VBNetTweaks")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("d9c87954-ce20-459d-81ec-96599caed427")] [assembly: AssemblyFileVersion("0.4.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.1.0")] [module: UnverifiableCode] [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 VBNetTweaks { [BepInPlugin("VitByr.VBNetTweaks", "VBNetTweaks", "0.4.3.5")] [BepInIncompatibility("CacoFFF.valheim.LeanNet")] [BepInIncompatibility("redseiko.valheim.scenic")] [BepInIncompatibility("Searica.Valheim.NetworkTweaks")] [BepInIncompatibility("Searica.Valheim.OpenSesame")] [BepInIncompatibility("org.bepinex.plugins.network")] [BepInIncompatibility("CW_Jesse.BetterNetworking")] [BepInIncompatibility("com.Fire.FiresGhettoNetworkMod")] [BepInIncompatibility("sighsorry.SkadiNet")] [BepInIncompatibility("redseiko.valheim.returntosender")] [BepInIncompatibility("com.maxsch.valheim.TimeoutLimit")] [BepInIncompatibility("dzk.warheimnetwork")] [BepInIncompatibility("r4v9n1.terramizerserver")] [BepInIncompatibility("com.bfv.CombatPrio")] public class VBNetTweaks : BaseUnityPlugin { private const string ModName = "VBNetTweaks"; private const string ModVersion = "0.4.3.5"; private const string ModGUID = "VitByr.VBNetTweaks"; public CustomRPC _configSyncRPC; private ConfigFile _clientConfig; public static ManualLogSource Logger; public static ConfigEntry<Language> c_ConfigLanguage; public static ConfigEntry<bool> c_ModEnabled; public static ConfigEntry<bool> c_DebugEnabled; public static ConfigEntry<bool> c_VerboseLogging; public static ConfigEntry<bool> c_NetStatsLogging; public static ConfigEntry<int> c_NetStatsInterval; public static ConfigEntry<int> c_TargetFPS; public static ConfigEntry<bool> c_ModuleSteamOptimizations; public static ConfigEntry<bool> c_ModuleZDOOptimization; public static ConfigEntry<bool> c_ModuleMapPositionSync; public static ConfigEntry<bool> c_ModuleStutterGuard; public static ConfigEntry<int> c_SteamSendRateMaxKB; public static ConfigEntry<int> c_SteamSendBufferSizeKB; public static ConfigEntry<float> c_SteamTimeoutConnected; public static ConfigEntry<float> c_MapPositionSendInterval; public static ConfigEntry<float> c_MapMaxPredictionSpeed; public static ConfigEntry<float> c_SendInterval; public static ConfigEntry<int> c_MaxPeersPerFrame; public static ConfigEntry<int> c_ZDOQueueLimit; public static ConfigEntry<float> c_ClientInterpFactor; public static ConfigEntry<float> c_ClientSnapDistance; public static ConfigEntry<float> c_ClientMaxExtrapolation; public static ConfigEntry<bool> c_DiscordInfoEnabled; public static ConfigEntry<string> c_DiscordInfoWebhook; public static ConfigEntry<bool> c_DiscordErrorEnabled; public static ConfigEntry<string> c_DiscordErrorWebhook; private Harmony _harmony; public static VBNetTweaks Instance { get; private set; } private void Awake() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_0105: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; _clientConfig = new ConfigFile(Path.Combine(Paths.ConfigPath, "VitByr/VBNetTweaks/MainConfig.cfg"), true); SynchronizationManager.Instance.RegisterCustomConfig(_clientConfig); InitClientConfigs(); c_ModEnabled = ConfigFileExtensions.BindConfig<bool>(_clientConfig, "00 - Master", "ModEnabled", true, (c_ConfigLanguage.Value == Language.Russian) ? "Полностью включить/выключить мод VBNetTweaks" : "Completely enable/disable VBNetTweaks mod", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_TargetFPS = ConfigFileExtensions.BindConfig<int>(_clientConfig, "00 - Master", "TargetFPS", 120, (c_ConfigLanguage.Value == Language.Russian) ? "Целевой FPS для сервера (только для выделенного сервера)" : "Target FPS for server (dedicated only)", false, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); if (c_ModEnabled.Value) { _configSyncRPC = NetworkManager.Instance.AddRPC("VBNetTweaks_ConfigSync", new CoroutineHandler(OnAdminConfigSync), new CoroutineHandler(OnClientConfigSync)); SynchronizationManager.Instance.AddInitialSynchronization(_configSyncRPC, (Func<ZPackage>)(() => BuildConfigPackage())); CreateConfigWatcher(); if (c_DiscordInfoEnabled.Value || c_DiscordErrorEnabled.Value) { DiscordLogger.Initialize(); } _harmony = new Harmony("VitByr.VBNetTweaks"); _harmony.PatchAll(typeof(MiniMap_Patch)); _harmony.PatchAll(typeof(NetStats_Patch)); _harmony.PatchAll(typeof(ZDOMan_Patch)); _harmony.PatchAll(typeof(ZNet_Patch)); _harmony.PatchAll(typeof(ZSteamSocket_Patch)); _harmony.PatchAll(typeof(ZSyncTransform_Patch)); if (c_ModuleStutterGuard.Value && !Helper.IsDedicated()) { ClientStutterGuard.Initialize((MonoBehaviour)(object)this); _harmony.PatchAll(typeof(StutterGuardTriggers)); } Helper.LogDebug("Режим отладки включен"); } } private void InitClientConfigs() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown string text = "00 - Language"; c_ConfigLanguage = ((BaseUnityPlugin)this).Config.Bind<Language>(text, "Language", Language.Russian, new ConfigDescription("Select interface language / Выберите язык интерфейса\nRequired Restart / Требуется рестарт", (AcceptableValueBase)null, Array.Empty<object>())); string text2 = "01 - Debug"; c_DebugEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "DebugEnabled", false, (c_ConfigLanguage.Value == Language.Russian) ? "Включить отладочный вывод" : "Enable debug output"); c_VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "VerboseLogging", false, (c_ConfigLanguage.Value == Language.Russian) ? "Включить подробное логирование" : "Enable verbose logging"); c_NetStatsLogging = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "NetStatsLogging", false, (c_ConfigLanguage.Value == Language.Russian) ? "Логирование статистики отправки/приёма пакетов (раз в интервал). Пинг становится нестабильным" : "Log send/receive packet statistics (once per interval). The ping is becoming unstable."); c_NetStatsInterval = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "NetStatsIntervalSec", 10, (c_ConfigLanguage.Value == Language.Russian) ? "Интервал дампа статистики, сек." : "Statistics dump interval, sec."); string text3 = "02 - Modules"; c_ModuleSteamOptimizations = ConfigFileExtensions.BindConfig<bool>(_clientConfig, text3, "SteamOptimizations", true, (c_ConfigLanguage.Value == Language.Russian) ? "Оптимизации Steam сокета" : "Steam socket optimizations", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_ModuleZDOOptimization = ConfigFileExtensions.BindConfig<bool>(_clientConfig, text3, "ZDOOptimization", true, (c_ConfigLanguage.Value == Language.Russian) ? "Оптимизация ZDO отправок" : "Optimization ZDO sender", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_ModuleMapPositionSync = ConfigFileExtensions.BindConfig<bool>(_clientConfig, text3, "MapPositionSync", true, (c_ConfigLanguage.Value == Language.Russian) ? "Включить плавные маркеры игроков на карте\nУлучшает отображение позиций игроков" : "Enable smooth player markers on map\nImproves display of player positions", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_ModuleStutterGuard = ConfigFileExtensions.BindConfig<bool>(_clientConfig, text3, "StutterGuard", true, (c_ConfigLanguage.Value == Language.Russian) ? "Защита от микро-фризов (GC) на клиенте" : "Client stutter guard (GC)", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); string text4 = "03 - Steam Settings"; c_SteamSendRateMaxKB = ConfigFileExtensions.BindConfig<int>(_clientConfig, text4, "MaxRateKB", 16384, (c_ConfigLanguage.Value == Language.Russian) ? "Максимальная скорость отправки Steam. Vanilla = ~150KB" : "Maximum Steam send rate. Vanilla = ~150KB", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_SteamSendBufferSizeKB = ConfigFileExtensions.BindConfig<int>(_clientConfig, text4, "SendBufferSizeKB", 8192, (c_ConfigLanguage.Value == Language.Russian) ? "Размер буфера отправки Steam в KB. Vanilla = ~512KB" : "Steam send buffer size in KB. Vanilla = ~512KB", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_SteamTimeoutConnected = ConfigFileExtensions.BindConfig<float>(_clientConfig, text4, "TimeoutConnected", 60000f, (c_ConfigLanguage.Value == Language.Russian) ? "Таймаут соединения Steam (миллисекунды)\nЕсли соединение неактивно дольше этого времени — оно будет разорвано\nVanilla = 30000 (30 секунд)" : "Steam connection timeout (milliseconds)\nIf connection is idle longer than this — it will be closed\nVanilla = 30000 (30 sec)", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); string text5 = "04 - ZDO Settings"; c_SendInterval = ConfigFileExtensions.BindConfig<float>(_clientConfig, text5, "SendInterval", 0.04f, (c_ConfigLanguage.Value == Language.Russian) ? "Интервал отправки данных. Vanilla = 0.05" : "Data send interval. Vanilla = 0.05", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_MaxPeersPerFrame = ConfigFileExtensions.BindConfig<int>(_clientConfig, text5, "MaxPeersPerFrame", 0, (c_ConfigLanguage.Value == Language.Russian) ? "Макс. пиров за один кадр (0 = без лимита, бюджет сам решает)." : "Max peers per frame (0 = unlimited, budget decides).", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_ZDOQueueLimit = ConfigFileExtensions.BindConfig<int>(_clientConfig, text5, "ZDOQueueLimit", 20480, (c_ConfigLanguage.Value == Language.Russian) ? "Размер буфера отправки ZDO пакетов (vanilla = 10240 байт)" : "ZDO packet send buffer size (vanilla = 10240 bytes)", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); string text6 = "05 - Map Positions"; c_MapPositionSendInterval = ConfigFileExtensions.BindConfig<float>(_clientConfig, text6, "SendInterval", 0.75f, (c_ConfigLanguage.Value == Language.Russian) ? "Интервал отправки позиций игроков (сек)\nМеньше = плавнее, но больше трафик. Vanilla: 2.0" : "Player position send interval (sec)\nLower = smoother, but more traffic. Vanilla: 2.0", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_MapMaxPredictionSpeed = ConfigFileExtensions.BindConfig<float>(_clientConfig, text6, "MaxPredictionSpeed", 50f, (c_ConfigLanguage.Value == Language.Russian) ? "Максимальная скорость движения маркера игрока на карте (м/с).\nТелепорты (порталы, спавн) обрабатываются отдельно – маркер перепрыгивает мгновенно." : "Maximum movement speed of player marker on map (m/s).\nTeleports (portals, spawn) are handled separately – the marker jumps instantly.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); string text7 = "06 - Client Smoothing"; c_ClientInterpFactor = ConfigFileExtensions.BindConfig<float>(_clientConfig, text7, "InterpFactor", 0.35f, (c_ConfigLanguage.Value == Language.Russian) ? "Коэффициент интерполяции для чужих объектов (vanilla 0.20).\n0.3 — отзывчивее; 0.20 — ваниль; 1.0 — без сглаживания." : "Interpolation factor for non-owned objects (vanilla 0.20).\n0.3 = snappier; 0.20 = vanilla; 1.0 = no smoothing.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_ClientSnapDistance = ConfigFileExtensions.BindConfig<float>(_clientConfig, text7, "SnapDistance", 3f, (c_ConfigLanguage.Value == Language.Russian) ? "Порог мгновенного снапа вместо интерполяции (vanilla 5.0). Меньше — раньше снап, меньше визуального разъезда." : "Distance threshold for instant snap instead of interpolation (vanilla 5.0). Lower = earlier snap, less visual desync.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_ClientMaxExtrapolation = ConfigFileExtensions.BindConfig<float>(_clientConfig, text7, "MaxExtrapolationSeconds", 0.5f, (c_ConfigLanguage.Value == Language.Russian) ? "Лимит экстраполяции чужих объектов при пропаже апдейтов (vanilla 2.0).\n0.5 — мобы не «бегут в стену» при потере пакетов." : "Cap on extrapolation of non-owned objects when updates are missing (vanilla 2.0).\n0.5 = mobs stop running into walls on packet loss.", true, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); string text8 = "07 - Discord Webhooks"; c_DiscordInfoEnabled = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, text8, "InfoEnabled", false, "Enable info notifications batching / Включить батчинг уведомлений", false, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_DiscordInfoWebhook = ConfigFileExtensions.BindConfig<string>(((BaseUnityPlugin)this).Config, text8, "InfoWebhookUrl", "", "Discord webhook URL for info messages / URL вебхука для уведомлений", false, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_DiscordErrorEnabled = ConfigFileExtensions.BindConfig<bool>(((BaseUnityPlugin)this).Config, text8, "ErrorEnabled", false, "Enable error reporting with network context / Включить отчеты об ошибках", false, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); c_DiscordErrorWebhook = ConfigFileExtensions.BindConfig<string>(((BaseUnityPlugin)this).Config, text8, "ErrorWebhookUrl", "", "Discord webhook URL for errors / URL вебхука для ошибок", false, (int?)null, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null); } public ZPackage BuildConfigPackage() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown ZPackage val = new ZPackage(); try { val.Write(c_ModEnabled.Value); val.Write(c_ModuleSteamOptimizations.Value); val.Write(c_ModuleZDOOptimization.Value); val.Write(c_ModuleMapPositionSync.Value); val.Write(c_SteamSendRateMaxKB.Value); val.Write(c_SteamSendBufferSizeKB.Value); val.Write(c_SteamTimeoutConnected.Value); val.Write(c_MapPositionSendInterval.Value); val.Write(c_MapMaxPredictionSpeed.Value); val.Write(c_SendInterval.Value); val.Write(c_MaxPeersPerFrame.Value); val.Write(c_ZDOQueueLimit.Value); } catch (Exception ex) { Helper.LogDebug("Error building config package: " + ex.Message); return new ZPackage(); } return val; } private void ApplyConfigFromPackage(ZPackage pkg) { if (pkg == null || pkg.GetArray().Length == 0) { Helper.LogDebug("Received empty config package"); return; } try { pkg.SetPos(0); c_ModEnabled.Value = pkg.ReadBool(); c_ModuleSteamOptimizations.Value = pkg.ReadBool(); c_ModuleZDOOptimization.Value = pkg.ReadBool(); c_ModuleMapPositionSync.Value = pkg.ReadBool(); c_SteamSendRateMaxKB.Value = pkg.ReadInt(); c_SteamSendBufferSizeKB.Value = pkg.ReadInt(); c_SteamTimeoutConnected.Value = pkg.ReadSingle(); c_MapPositionSendInterval.Value = pkg.ReadSingle(); c_MapMaxPredictionSpeed.Value = pkg.ReadSingle(); c_SendInterval.Value = pkg.ReadSingle(); c_MaxPeersPerFrame.Value = pkg.ReadInt(); c_ZDOQueueLimit.Value = pkg.ReadInt(); } catch (Exception ex) { Helper.LogDebug("Error applying config package: " + ex.Message); } } private IEnumerator OnAdminConfigSync(long sender, ZPackage pkg) { if (!Helper.IsDedicated()) { yield break; } ZPackage serverConfigPkg = BuildConfigPackage(); byte[] data = serverConfigPkg.GetArray(); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { ZPackage copyPkg = new ZPackage(data); _configSyncRPC.SendPackage(new List<ZNetPeer> { peer }, copyPkg); } Helper.LogDebug("Server config broadcast to all clients"); } public IEnumerator OnClientConfigSync(long sender, ZPackage pkg) { Helper.LogDebug($"Клиент получил конфиг от сервера {sender}"); ApplyConfigFromPackage(pkg); _clientConfig.SaveOnConfigSet = true; _clientConfig.Save(); yield break; } private void CreateConfigWatcher() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown ConfigFileWatcher val = new ConfigFileWatcher(_clientConfig, 1000L); val.OnConfigFileReloaded += delegate { if (Helper.IsDedicated()) { Helper.LogDebug("Server config changed, broadcasting to all clients"); ((MonoBehaviour)this).StartCoroutine(ApplyServerConfigChanges()); } }; } public IEnumerator ApplyServerConfigChanges() { yield return null; ZPackage pkg = BuildConfigPackage(); if (pkg.GetArray().Length == 0) { yield break; } byte[] data = pkg.GetArray(); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { ZPackage copyPkg = new ZPackage(data); _configSyncRPC.SendPackage(new List<ZNetPeer> { peer }, copyPkg); } Helper.LogDebug("Server config broadcast to all clients"); } private void OnDestroy() { ConfigFile clientConfig = _clientConfig; if (clientConfig != null) { clientConfig.Save(); } ClientStutterGuard.Shutdown(); DiscordLogger.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace VBNetTweaks.Utils { internal static class ClientStutterGuard { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct MEMORYSTATUSEX { public uint dwLength; public uint dwMemoryLoad; public ulong ullTotalPhys; public ulong ullAvailPhys; public ulong ullTotalPageFile; public ulong ullAvailPageFile; public ulong ullTotalVirtual; public ulong ullAvailVirtual; public ulong ullAvailExtendedVirtual; } private struct MemoryPressureSnapshot { public bool Known; public ulong TotalMB; public ulong AvailableMB; public int LoadPercent; } private static MonoBehaviour _host; private static Coroutine _cleanupCoroutine; private static volatile int _mainThreadId; private static double _criticalUntil; private static bool _pendingGc; private static double _firstPendingSince; private static bool _runningCleanup; private const float TeleportWindow = 5f; private const float CombatWindow = 2f; private const float FullSnapshotWindow = 1.5f; private const float MaxDelaySeconds = 30f; private const int MinFreeMemoryMB = 2048; private const int MemoryPressureThresholdPercent = 75; private const float IdleCleanupPollSeconds = 1f; internal static bool IsActive => VBNetTweaks.c_ModuleStutterGuard.Value && !Helper.IsDedicated(); internal static void Initialize(MonoBehaviour host) { _host = host; _mainThreadId = Thread.CurrentThread.ManagedThreadId; _criticalUntil = 0.0; _pendingGc = false; _firstPendingSince = 0.0; _runningCleanup = false; EnsureCleanupScheduler(); } internal static void Shutdown() { RunPendingCleanup(); try { if (_cleanupCoroutine != null && Object.op_Implicit((Object)(object)_host)) { _host.StopCoroutine(_cleanupCoroutine); } } catch { } _cleanupCoroutine = null; _host = null; } internal static void MarkTeleportWindow() { ExtendCriticalWindow(5f); } internal static void MarkCombatWindow() { ExtendCriticalWindow(2f); } internal static void MarkFullSnapshotWindow() { ExtendCriticalWindow(1.5f); } private static void ExtendCriticalWindow(float seconds) { if (IsActive && !(seconds <= 0f)) { double num = Time.realtimeSinceStartupAsDouble + (double)seconds; if (num > _criticalUntil) { _criticalUntil = num; } } } internal static bool TryHandleGcCollect() { if (Thread.CurrentThread.ManagedThreadId != _mainThreadId) { return true; } if (_runningCleanup) { return true; } if (!IsActive) { ClearPendingCleanup(); return true; } if (ShouldDelayCleanup()) { RequestPending(); return false; } ClearPendingCleanup(); return true; } private static void RequestPending() { _pendingGc = true; if (_firstPendingSince <= 0.0) { _firstPendingSince = Time.realtimeSinceStartupAsDouble; } EnsureCleanupScheduler(); } private static void EnsureCleanupScheduler() { if (_cleanupCoroutine == null && Object.op_Implicit((Object)(object)_host) && IsActive) { _cleanupCoroutine = _host.StartCoroutine(CleanupScheduler()); } } private static IEnumerator CleanupScheduler() { while (true) { yield return (object)new WaitForSecondsRealtime(Math.Max(0.25f, 1f)); TryRunPendingCleanup(); } } private static bool TryRunPendingCleanup() { if (!_pendingGc || _runningCleanup) { return false; } if (ShouldDelayCleanup()) { return false; } return RunPendingCleanup(); } private static bool RunPendingCleanup() { if (!_pendingGc || _runningCleanup) { return false; } ClearPendingCleanup(); _runningCleanup = true; try { GC.Collect(); } finally { _runningCleanup = false; } return true; } private static void ClearPendingCleanup() { _pendingGc = false; _firstPendingSince = 0.0; } private static bool ShouldDelayCleanup() { if (!IsActive) { return false; } if (_firstPendingSince > 0.0 && Time.realtimeSinceStartupAsDouble - _firstPendingSince >= 30.0) { return false; } if (_criticalUntil > Time.realtimeSinceStartupAsDouble) { return !IsMemoryPressure(); } return IsMemoryPlentiful(); } private static bool IsMemoryPlentiful() { MemoryPressureSnapshot memorySnapshot = GetMemorySnapshot(); if (!memorySnapshot.Known) { return false; } return memorySnapshot.LoadPercent < 75 && memorySnapshot.AvailableMB >= 2048; } private static bool IsMemoryPressure() { MemoryPressureSnapshot memorySnapshot = GetMemorySnapshot(); if (!memorySnapshot.Known) { return false; } if (memorySnapshot.LoadPercent >= 75) { return true; } return memorySnapshot.AvailableMB < 2048; } private static MemoryPressureSnapshot GetMemorySnapshot() { if (TryGetWindowsMemory(out var snapshot)) { return snapshot; } if (TryGetLinuxMemory(out var snapshot2)) { return snapshot2; } return new MemoryPressureSnapshot { Known = false }; } private static bool TryGetLinuxMemory(out MemoryPressureSnapshot snapshot) { snapshot = default(MemoryPressureSnapshot); try { if (!File.Exists("/proc/meminfo")) { return false; } ulong num = 0uL; ulong num2 = 0uL; bool flag = false; bool flag2 = false; string[] array = File.ReadAllLines("/proc/meminfo"); string[] array2 = array; foreach (string text in array2) { if (text.StartsWith("MemTotal:", StringComparison.Ordinal)) { num = ParseMemInfoValue(text); flag = true; } else if (text.StartsWith("MemAvailable:", StringComparison.Ordinal)) { num2 = ParseMemInfoValue(text); flag2 = true; } if (flag && flag2) { break; } } if (!flag || !flag2 || num == 0) { return false; } snapshot.Known = true; snapshot.TotalMB = num / 1024; snapshot.AvailableMB = num2 / 1024; snapshot.LoadPercent = (int)Math.Round(100.0 * (1.0 - (double)num2 / (double)num)); return true; } catch { return false; } } private static ulong ParseMemInfoValue(string line) { string[] array = line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i < array.Length; i++) { if (ulong.TryParse(array[i], out var result)) { return result; } } return 0uL; } private static bool TryGetWindowsMemory(out MemoryPressureSnapshot snapshot) { snapshot = default(MemoryPressureSnapshot); if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return false; } try { MEMORYSTATUSEX lpBuffer = new MEMORYSTATUSEX { dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX)) }; if (!GlobalMemoryStatusEx(ref lpBuffer)) { return false; } snapshot.Known = true; snapshot.TotalMB = lpBuffer.ullTotalPhys / 1024 / 1024; snapshot.AvailableMB = lpBuffer.ullAvailPhys / 1024 / 1024; snapshot.LoadPercent = (int)lpBuffer.dwMemoryLoad; return snapshot.TotalMB != 0; } catch { return false; } } [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer); } internal static class DiscordLogger { private static readonly HttpClient _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(5.0) }; private static readonly ConcurrentQueue<string> _infoQueue = new ConcurrentQueue<string>(); private static readonly ConcurrentQueue<string> _errorQueue = new ConcurrentQueue<string>(); private static CancellationTokenSource _cts; private static Task _workerTask; private const int MaxBatchChars = 1800; private const float InfoFlushInterval = 5f; internal static void Initialize() { if (_workerTask == null || _workerTask.IsCompleted) { _cts = new CancellationTokenSource(); _workerTask = Task.Run((Func<Task?>)WorkerLoop); Helper.LogDebug("[Discord] Logger initialized"); } } internal static void Shutdown() { try { _cts?.Cancel(); _workerTask?.Wait(TimeSpan.FromSeconds(2.0)); } catch { } finally { _cts?.Dispose(); _cts = null; _workerTask = null; } } internal static void SendInfo(string message, string sender = null) { if (VBNetTweaks.c_DiscordInfoEnabled.Value && !string.IsNullOrEmpty(VBNetTweaks.c_DiscordInfoWebhook.Value)) { string item = FormatMessage(message, sender, isError: false); _infoQueue.Enqueue(item); } } internal static void SendError(string message, string sender = null, Exception ex = null) { if (VBNetTweaks.c_DiscordErrorEnabled.Value && !string.IsNullOrEmpty(VBNetTweaks.c_DiscordErrorWebhook.Value)) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("\ud83d\udd34 **ERROR** | " + GetTimestamp()); stringBuilder.AppendLine("**From:** " + (sender ?? GetDefaultSender())); stringBuilder.AppendLine("**Message:** " + message); if (ex != null) { stringBuilder.AppendLine("**Exception:** `" + ex.GetType().Name + "`"); stringBuilder.AppendLine("```" + Truncate(ex.Message, 300) + "```"); } AppendNetworkContext(stringBuilder); string text = stringBuilder.ToString(); if (text.Length > 1900) { text = text.Substring(0, 1900) + "..."; } _errorQueue.Enqueue(text); } } private static async Task WorkerLoop() { StringBuilder infoBatch = new StringBuilder(); float lastInfoFlush = Time.realtimeSinceStartup; while (!_cts.Token.IsCancellationRequested) { try { await Task.Delay(500, _cts.Token); } catch (OperationCanceledException) { break; } string errorMsg; while (_errorQueue.TryDequeue(out errorMsg)) { await PostToWebhook(VBNetTweaks.c_DiscordErrorWebhook.Value, errorMsg); } bool shouldFlush = Time.realtimeSinceStartup - lastInfoFlush >= 5f; string infoMsg; while (_infoQueue.TryDequeue(out infoMsg)) { if (infoBatch.Length + infoMsg.Length + 1 > 1800) { await PostToWebhook(VBNetTweaks.c_DiscordInfoWebhook.Value, infoBatch.ToString()); infoBatch.Clear(); } if (infoBatch.Length > 0) { infoBatch.Append('\n'); } infoBatch.Append(infoMsg); } if (shouldFlush && infoBatch.Length > 0) { await PostToWebhook(VBNetTweaks.c_DiscordInfoWebhook.Value, infoBatch.ToString()); infoBatch.Clear(); lastInfoFlush = Time.realtimeSinceStartup; } } if (infoBatch.Length > 0 && !string.IsNullOrEmpty(VBNetTweaks.c_DiscordInfoWebhook.Value)) { await PostToWebhook(VBNetTweaks.c_DiscordInfoWebhook.Value, infoBatch.ToString()); } } private static async Task PostToWebhook(string url, string content) { if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(content)) { return; } try { string payload = "{\"content\":" + EscapeJson(content) + "}"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url) { Content = (HttpContent)new StringContent(payload, Encoding.UTF8, "application/json") }; try { HttpResponseMessage response = await ((HttpMessageInvoker)_httpClient).SendAsync(request, _cts.Token); try { if (!response.IsSuccessStatusCode && VBNetTweaks.c_DebugEnabled.Value) { Helper.LogDebug($"[Discord] Webhook failed: {(int)response.StatusCode}"); } } finally { ((IDisposable)response)?.Dispose(); } } finally { ((IDisposable)request)?.Dispose(); } } catch (OperationCanceledException) { } catch (Exception ex2) { if (VBNetTweaks.c_DebugEnabled.Value) { Helper.LogDebug("[Discord] Post exception: " + ex2.Message); } } } private static string FormatMessage(string message, string sender, bool isError) { string text = (isError ? "\ud83d\udd34" : "ℹ\ufe0f"); return text + " [" + GetTimestamp() + "] **" + (sender ?? GetDefaultSender()) + "**: " + message; } private static string GetDefaultSender() { if (Helper.IsServer()) { return "Server"; } if ((Object)(object)Player.m_localPlayer != (Object)null) { return Player.m_localPlayer.GetPlayerName(); } return "Client"; } private static string GetTimestamp() { return DateTime.Now.ToString("HH:mm:ss"); } private static void AppendNetworkContext(StringBuilder sb) { try { if (!((Object)(object)ZNet.instance == (Object)null)) { sb.AppendLine("**\ud83d\udcca Network Context:**"); sb.AppendLine($"• Peers: {ZNet.instance.GetPeers().Count}"); ZDOMan instance = ZDOMan.instance; sb.AppendLine($"• ZDO Sent/s: {((instance != null) ? instance.GetSentZDOs() : 0)}"); ZDOMan instance2 = ZDOMan.instance; sb.AppendLine($"• ZDO Recv/s: {((instance2 != null) ? instance2.GetRecvZDOs() : 0)}"); sb.AppendLine($"• Deferred: {NetStats.ZdoDeferred}"); sb.AppendLine($"• SkipQueueFull: {NetStats.SkipQueueFull}"); sb.AppendLine($"• SkipLowSpace: {NetStats.SkipLowSpace}"); sb.AppendLine($"• SteamSendFail: {NetStats.SteamSendFail}"); sb.AppendLine($"• UnknownHost: {NetStats.ZdoUnknownHost}"); } } catch { } } private static string Truncate(string value, int maxLen) { if (string.IsNullOrEmpty(value)) { return ""; } return (value.Length <= maxLen) ? value : (value.Substring(0, maxLen) + "..."); } private static string EscapeJson(string s) { if (s == null) { return "null"; } StringBuilder stringBuilder = new StringBuilder("\""); foreach (char c in s) { switch (c) { case '"': stringBuilder.Append("\\\""); break; case '\\': stringBuilder.Append("\\\\"); break; case '\n': stringBuilder.Append("\\n"); break; case '\r': stringBuilder.Append("\\r"); break; case '\t': stringBuilder.Append("\\t"); break; default: stringBuilder.Append(c); break; } } stringBuilder.Append('"'); return stringBuilder.ToString(); } } public enum Language { Russian, English } public static class Helper { public static readonly Dictionary<ZRpc, List<ZPackage>> _buffers = new Dictionary<ZRpc, List<ZPackage>>(); public static float GetTimeoutConnected() { return Mathf.Clamp(VBNetTweaks.c_SteamTimeoutConnected.Value, 5000f, 600000f); } public static int GetSteamSendBufferSizeKB() { return Math.Max(524288, VBNetTweaks.c_SteamSendBufferSizeKB.Value * 1024); } public static int GetSteamSendRateMaxKB() { return Math.Max(131072, VBNetTweaks.c_SteamSendRateMaxKB.Value * 1024); } public static int GetQueueLimit() { if (!VBNetTweaks.c_ModuleZDOOptimization.Value) { return 10240; } int num = Mathf.Max(10240, VBNetTweaks.c_ZDOQueueLimit.Value); int num2 = (Object.op_Implicit((Object)(object)ZNet.instance) ? ZNet.instance.GetPeers().Count : 0); float num3 = 1f + Mathf.Min(2f, (float)num2 / 10f); int num4 = Mathf.RoundToInt((float)num * num3); return Mathf.Clamp(num4, 10240, 196608); } public static float GetSendInterval() { return Mathf.Clamp(VBNetTweaks.c_SendInterval.Value, 0.01f, 0.2f); } public static float GetMapPositionSendInterval() { return Mathf.Clamp(VBNetTweaks.c_MapPositionSendInterval.Value, 0.1f, 2f); } public static bool IsDedicated() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 return (int)SystemInfo.graphicsDeviceType == 4; } public static bool IsServer() { return Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer(); } public static void LogDebug(string message) { if (VBNetTweaks.c_DebugEnabled.Value) { VBNetTweaks.Logger.LogWarning((object)message); } } public static void LogVerbose(string message) { if (VBNetTweaks.c_VerboseLogging.Value) { VBNetTweaks.Logger.LogInfo((object)message); } } } public static class NetStats { private struct Snapshot { public float Seconds; public long SendOkPackets; public long SendEmpty; public long SkipQueueFull; public long SkipLowSpace; public long ZdoSerialized; public long ZdoDeferred; public long SteamSendFail; public long ZdoDataIn; public long ZdoApplied; public long ZdoUnknownHost; public long PeersServiced; public bool IsServer; public string SenderName; public float ServerFps; public int TotalZdoCount; public int ActiveSectors; public int PeerCount; public float LocalQuality; public float RemoteQuality; public int Ping; public float OutBytesSec; public float InBytesSec; public float JitterMs; } public static long SendOkPackets; public static long SendEmpty; public static long SkipQueueFull; public static long SkipLowSpace; public static long ZdoSerialized; public static long ZdoDeferred; public static long SteamSendFail; public static long ZdoDataIn; public static long ZdoApplied; public static long ZdoUnknownHost; public static long PeersServiced; private static float _timer; private static volatile bool _isPrinting; private static readonly float[] _pingHistory = new float[20]; private static int _pingIdx; public static bool Enabled => VBNetTweaks.c_NetStatsLogging.Value; public static void ResetCounters() { SendOkPackets = (SendEmpty = (SkipQueueFull = (SkipLowSpace = 0L))); ZdoSerialized = (ZdoDeferred = (SteamSendFail = 0L)); ZdoDataIn = (ZdoApplied = (ZdoUnknownHost = 0L)); PeersServiced = 0L; } public static void Tick(float dt) { if (!Enabled || _isPrinting) { return; } _timer += dt; if (_timer < (float)VBNetTweaks.c_NetStatsInterval.Value) { return; } float timer = _timer; _timer = 0f; bool flag = Helper.IsServer(); string senderName = (flag ? "Server" : (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerName() : "Client")); Snapshot snapshot = new Snapshot { Seconds = timer, SendOkPackets = SendOkPackets, SendEmpty = SendEmpty, SkipQueueFull = SkipQueueFull, SkipLowSpace = SkipLowSpace, ZdoSerialized = ZdoSerialized, ZdoDeferred = ZdoDeferred, SteamSendFail = SteamSendFail, ZdoDataIn = ZdoDataIn, ZdoApplied = ZdoApplied, ZdoUnknownHost = ZdoUnknownHost, PeersServiced = PeersServiced, IsServer = flag, SenderName = senderName }; if (flag) { snapshot.ServerFps = 1f / Mathf.Max(Time.unscaledDeltaTime, 0.001f); ref Snapshot reference = ref snapshot; ZDOMan instance = ZDOMan.instance; reference.TotalZdoCount = ((instance != null) ? instance.NrOfObjects() : 0); int num = 0; if (ZDOMan.instance?.m_objectsBySector != null) { List<ZDO>[] objectsBySector = ZDOMan.instance.m_objectsBySector; foreach (List<ZDO> list in objectsBySector) { if (list != null && list.Count > 0) { num++; } } } snapshot.ActiveSectors = num; ref Snapshot reference2 = ref snapshot; ZNet instance2 = ZNet.instance; reference2.PeerCount = ((instance2 == null) ? ((int?)null) : instance2.GetPeers()?.Count).GetValueOrDefault(); } else if ((Object)(object)ZNet.instance != (Object)null) { ZNet.instance.GetNetStats(ref snapshot.LocalQuality, ref snapshot.RemoteQuality, ref snapshot.Ping, ref snapshot.OutBytesSec, ref snapshot.InBytesSec); snapshot.PeerCount = ZNet.instance.GetPeers()?.Count ?? 0; if (snapshot.Ping > 0) { _pingHistory[_pingIdx % _pingHistory.Length] = snapshot.Ping; _pingIdx++; float num2 = float.MaxValue; float num3 = float.MinValue; int num4 = Mathf.Min(_pingIdx, _pingHistory.Length); for (int j = 0; j < num4; j++) { if (_pingHistory[j] < num2) { num2 = _pingHistory[j]; } if (_pingHistory[j] > num3) { num3 = _pingHistory[j]; } } snapshot.JitterMs = num3 - num2; } } ResetCounters(); _isPrinting = true; Task.Run(delegate { try { PrintFromSnapshot(snapshot); } finally { _isPrinting = false; } }); } private static void PrintFromSnapshot(Snapshot snap) { bool flag = snap.ZdoDeferred > 5000; StringBuilder stringBuilder = new StringBuilder(512); string arg = (snap.IsServer ? "[SRV]" : "[CLI]"); float num = (float)snap.ZdoSerialized / snap.Seconds; float num2 = (float)snap.ZdoDeferred / snap.Seconds; string arg2 = "✅"; if (snap.SteamSendFail > 0 || snap.SkipQueueFull > 0) { arg2 = "\ud83d\udd34"; } else if (snap.IsServer && snap.ServerFps < 20f) { arg2 = "\ud83d\udd34"; } else if (snap.ZdoDeferred > 100 || snap.SkipLowSpace > 0) { arg2 = "⚠\ufe0f"; } else if (snap.IsServer && snap.ServerFps < 25f) { arg2 = "⚠\ufe0f"; } stringBuilder.AppendLine($"{arg} {arg2} NetStats ({snap.Seconds:F1}s)"); stringBuilder.AppendLine($" OUT: {num:F0} zdo/s | pk={snap.SendOkPackets} | deferred={snap.ZdoDeferred} ({num2:F0}/s) | skipQ={snap.SkipQueueFull} skipL={snap.SkipLowSpace} | fail={snap.SteamSendFail}"); stringBuilder.AppendLine($" IN: {(float)snap.ZdoApplied / snap.Seconds:F0} zdo/s | pk={snap.ZdoDataIn} | unknown={snap.ZdoUnknownHost} | svc={snap.PeersServiced}"); if (snap.IsServer) { stringBuilder.AppendLine($" SYS: fps={snap.ServerFps:F0} | zdos={snap.TotalZdoCount} | sectors={snap.ActiveSectors} | peers={snap.PeerCount}"); } else { string text = ((snap.JitterMs > 0f) ? $" | jitter={snap.JitterMs:F0}ms" : ""); stringBuilder.AppendLine($" NET: ping={snap.Ping}ms{text} | ↑{snap.OutBytesSec / 1024f:F1} KB/s ↓{snap.InBytesSec / 1024f:F1} KB/s | peers={snap.PeerCount} | quality L:{snap.LocalQuality:P0} R:{snap.RemoteQuality:P0}"); } VBNetTweaks.Logger.LogWarning((object)stringBuilder.ToString()); if (!flag) { DiscordLogger.SendInfo(stringBuilder.ToString(), snap.SenderName); } if (!flag && (snap.SkipQueueFull > 50 || snap.SteamSendFail > 10 || snap.ZdoDeferred > 10000 || (snap.IsServer && snap.ServerFps < 15f))) { string text2 = (snap.IsServer ? $", FPS={snap.ServerFps:F0}" : ""); DiscordLogger.SendError($"Network degradation! QueueFull={snap.SkipQueueFull}, SteamFail={snap.SteamSendFail}, Deferred={snap.ZdoDeferred}{text2}", snap.SenderName); } } } public static class SyncTuning { private static int _frame; private static float _interpFactor; private static float _snapDistance; private static float _maxExtrapolation; private static void Refresh() { int frameCount = Time.frameCount; if (frameCount != _frame) { _frame = frameCount; bool flag = Helper.IsDedicated(); _interpFactor = (flag ? 0.2f : Mathf.Clamp(VBNetTweaks.c_ClientInterpFactor.Value, 0.05f, 1f)); _snapDistance = (flag ? 5f : Mathf.Clamp(VBNetTweaks.c_ClientSnapDistance.Value, 1f, 20f)); _maxExtrapolation = (flag ? 2f : Mathf.Clamp(VBNetTweaks.c_ClientMaxExtrapolation.Value, 0.1f, 2f)); } } public static float GetInterpFactor() { Refresh(); return _interpFactor; } public static float GetSnapDistance() { Refresh(); return _snapDistance; } public static float GetMaxExtrapolationSeconds() { Refresh(); return _maxExtrapolation; } } } namespace VBNetTweaks.Patches { [HarmonyPatch] public static class MiniMap_Patch { public class PlayerTrackData { public Vector3 lastRealPosition; public Vector3 lastRealVelocity; public Vector3 smoothPosition; public Vector3 smoothVelocity; public float lastUpdateTime; public float teleportEndTime; } public static readonly Dictionary<long, PlayerTrackData> _playerTracks = new Dictionary<long, PlayerTrackData>(); private static int _lastCleanupFrame; [HarmonyPatch(typeof(Minimap), "UpdatePlayerPins")] [HarmonyPostfix] private static void UpdatePlayerPins_SmoothPostfix(Minimap __instance, float dt) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) if (!VBNetTweaks.c_ModuleMapPositionSync.Value || Helper.IsDedicated() || __instance.m_playerPins == null || __instance.m_tempPlayerInfo == null) { return; } int num = Mathf.Min(__instance.m_playerPins.Count, __instance.m_tempPlayerInfo.Count); if (num == 0) { return; } float time = Time.time; float value = VBNetTweaks.c_MapMaxPredictionSpeed.Value; if (Time.frameCount - _lastCleanupFrame > 600) { _lastCleanupFrame = Time.frameCount; CleanupStaleTracks(time); } for (int i = 0; i < num; i++) { PinData val = __instance.m_playerPins[i]; PlayerInfo val2 = __instance.m_tempPlayerInfo[i]; if (!val2.m_publicPosition) { continue; } long playerId = GetPlayerId(val2); if (playerId == 0) { continue; } Vector3 position = val2.m_position; if (!_playerTracks.TryGetValue(playerId, out var value2)) { value2 = new PlayerTrackData(); _playerTracks[playerId] = value2; value2.smoothPosition = position; value2.lastRealPosition = position; value2.lastUpdateTime = time; val.m_pos = position; continue; } float num2 = time - value2.lastUpdateTime; if (num2 > 0.001f) { Vector3 val3 = position - value2.lastRealPosition; float magnitude = ((Vector3)(ref val3)).magnitude; if (magnitude > 50f) { value2.teleportEndTime = time + 0.3f; value2.lastRealVelocity = Vector3.zero; } else if (num2 < 2f && magnitude > 0.01f) { value2.lastRealVelocity = val3 / num2; if (((Vector3)(ref value2.lastRealVelocity)).magnitude > 100f) { value2.lastRealVelocity = ((Vector3)(ref value2.lastRealVelocity)).normalized * 100f; } } } if (num2 >= 2f) { float num3 = Vector3.Distance(value2.smoothPosition, position); if (num3 > 50f) { value2.teleportEndTime = time + 0.3f; value2.lastRealVelocity = Vector3.zero; } } value2.lastRealPosition = position; value2.lastUpdateTime = time; if (value2.teleportEndTime > time) { val.m_pos = position; value2.smoothPosition = position; value2.smoothVelocity = Vector3.zero; continue; } Vector3 val4 = position; float num4 = time - value2.lastUpdateTime; if (num4 > 0.05f && ((Vector3)(ref value2.lastRealVelocity)).magnitude > 0.5f) { float num5 = Mathf.Min(num4, 0.5f); val4 = position + value2.lastRealVelocity * num5; } float num6 = Vector3.Distance(value2.smoothPosition, val4); float num7 = ((num6 > 30f) ? 0.01f : ((num6 > 10f) ? 0.03f : 0.05f)); value2.smoothPosition = Vector3.SmoothDamp(value2.smoothPosition, val4, ref value2.smoothVelocity, num7, value, dt); val.m_pos = value2.smoothPosition; } } private static long GetPlayerId(PlayerInfo info) { //IL_0023: 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) if (!((ZDOID)(ref info.m_characterID)).IsNone()) { return ((ZDOID)(ref info.m_characterID)).UserID; } if (!string.IsNullOrEmpty(info.m_name)) { return info.m_name.GetHashCode(); } return 0L; } private static void CleanupStaleTracks(float now) { List<long> list = new List<long>(); foreach (KeyValuePair<long, PlayerTrackData> playerTrack in _playerTracks) { if (now - playerTrack.Value.lastUpdateTime > 10f) { list.Add(playerTrack.Key); } } foreach (long item in list) { _playerTracks.Remove(item); } } } [HarmonyPatch] public static class NetStats_Patch { public struct SendState { public bool active; public int preSent; public int skip; } [HarmonyPatch(typeof(ZNet), "Update")] [HarmonyPostfix] private static void ZNetUpdate_Postfix() { NetStats.Tick(Time.deltaTime); } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] [HarmonyPrefix] private static void SendZDOs_Prefix(ZDOMan __instance, ZDOPeer peer, bool flush, ref SendState __state) { __state = default(SendState); if (NetStats.Enabled && peer?.m_peer?.m_socket != null) { __state.active = true; __state.preSent = __instance.m_zdosSent; int sendQueueSize = peer.m_peer.m_socket.GetSendQueueSize(); int queueLimit = Helper.GetQueueLimit(); if (!flush && sendQueueSize > queueLimit) { __state.skip = 1; NetStats.SkipQueueFull++; } else if (queueLimit - sendQueueSize < 2048) { __state.skip = 2; NetStats.SkipLowSpace++; } } } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] [HarmonyPostfix] private static void SendZDOs_Postfix(ZDOMan __instance, bool __result, SendState __state) { if (!__state.active || __state.skip != 0) { return; } if (__result) { NetStats.SendOkPackets++; int num = __instance.m_zdosSent - __state.preSent; if (num > 0) { NetStats.ZdoSerialized += num; } int num2 = __instance.m_tempToSync.Count - num; if (num2 > 0) { NetStats.ZdoDeferred += num2; } } else { NetStats.SendEmpty++; } } [HarmonyPatch(typeof(ZDOMan), "RPC_ZDOData")] [HarmonyPrefix] private static void RpcZdoData_Prefix(ZDOMan __instance, ZRpc rpc, ref int __state) { __state = -1; if (NetStats.Enabled) { if (__instance.FindPeer(rpc) == null) { NetStats.ZdoUnknownHost++; } else { __state = __instance.m_zdosRecv; } } } [HarmonyPatch(typeof(ZDOMan), "RPC_ZDOData")] [HarmonyPostfix] private static void RpcZdoData_Postfix(ZDOMan __instance, int __state) { if (__state >= 0) { NetStats.ZdoDataIn++; int num = __instance.m_zdosRecv - __state; if (num > 0) { NetStats.ZdoApplied += num; } } } } [HarmonyPatch] internal static class StutterGuardTriggers { [HarmonyPatch(typeof(ZNetScene), "InLoadingScreen")] [HarmonyPostfix] private static void LoadingScreen_Postfix(bool __result) { if (__result) { ClientStutterGuard.MarkTeleportWindow(); } } [HarmonyPatch(typeof(ZDOMan), "RPC_ZDOData")] [HarmonyPrefix] private static void ZdoData_Prefix(object[] __args) { if (Helper.IsServer() || __args == null) { return; } foreach (object obj in __args) { ZPackage val = (ZPackage)((obj is ZPackage) ? obj : null); if (val != null && val.Size() >= 32768) { ClientStutterGuard.MarkFullSnapshotWindow(); break; } } } [HarmonyPatch(typeof(MonsterAI), "SetTarget")] [HarmonyPostfix] private static void SetTarget_Postfix(Character attacker) { if (Object.op_Implicit((Object)(object)attacker) && attacker.IsPlayer()) { ClientStutterGuard.MarkCombatWindow(); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPostfix] private static void NewConnection_Postfix() { ClientStutterGuard.MarkTeleportWindow(); } } [HarmonyPatch] public static class ZDOMan_Patch { private enum SyncPriority : byte { Default, Piece, Creature, Ship, Player } private static int _cursor; private static float _adaptiveBudget; private static readonly Dictionary<int, SyncPriority> _priorityCache = new Dictionary<int, SyncPriority>(); public static void SafeSendZDOToPeers(ZDOMan man, float dt) { try { int count = man.m_peers.Count; if (count == 0) { _cursor = 0; man.m_nextSendPeer = -1; return; } if (_cursor >= count) { _cursor = 0; } float sendInterval = Helper.GetSendInterval(); float num = 1f / sendInterval; _adaptiveBudget += (float)count * dt * num; int num2 = Mathf.FloorToInt(_adaptiveBudget); _adaptiveBudget -= num2; if (num2 > count) { num2 = count; _adaptiveBudget = 0f; } int value = VBNetTweaks.c_MaxPeersPerFrame.Value; if (value > 0 && num2 > value) { num2 = value; } if (num2 <= 0) { man.m_nextSendPeer = -1; return; } int queueLimit = Helper.GetQueueLimit(); int num3 = 0; for (int i = 0; i < num2; i++) { int index = (_cursor + i) % count; ZDOPeer val = man.m_peers[index]; if (val != null && val.m_peer != null && val.m_peer.m_socket != null && val.m_peer.m_socket.IsConnected() && val.m_peer.m_socket.GetSendQueueSize() <= queueLimit) { try { man.SendZDOs(val, false); num3++; } catch (Exception ex) { Helper.LogDebug($"SendZDOs failed for peer {val.m_peer.m_uid}: {ex.Message}"); } } } _cursor = (_cursor + num2) % count; man.m_nextSendPeer = -1; NetStats.PeersServiced += num3; } catch (Exception ex2) { Helper.LogDebug("Error in SafeSendZDOToPeers: " + ex2.Message); } } private static int CustomCompare(ZDO x, ZDO y) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected I4, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected I4, but got Unknown if (x == null || y == null) { return 0; } bool flag = (int)x.Type == 1 && x.HasOwner() && x.GetOwner() != ZDOMan.s_compareReceiver; bool flag2 = (int)y.Type == 1 && y.HasOwner() && y.GetOwner() != ZDOMan.s_compareReceiver; if (flag && flag2) { return CompareFloats(x.m_tempSortValue, y.m_tempSortValue); } if (flag != flag2) { return (!flag) ? 1 : (-1); } if (x.Type != y.Type) { return ((int)y.Type).CompareTo((int)x.Type); } SyncPriority priority = GetPriority(x); SyncPriority priority2 = GetPriority(y); if (priority != priority2) { byte b = (byte)priority2; return b.CompareTo((byte)priority); } return CompareFloats(x.m_tempSortValue, y.m_tempSortValue); } private static int CompareFloats(float a, float b) { if (a < b) { return -1; } if (a > b) { return 1; } return 0; } private static SyncPriority GetPriority(ZDO zdo) { int prefab = zdo.GetPrefab(); if (_priorityCache.TryGetValue(prefab, out var value)) { return value; } SyncPriority syncPriority = SyncPriority.Default; if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); if (Object.op_Implicit((Object)(object)prefab2)) { if (Object.op_Implicit((Object)(object)prefab2.GetComponent<Player>())) { syncPriority = SyncPriority.Player; } else if (Object.op_Implicit((Object)(object)prefab2.GetComponent<Ship>())) { syncPriority = SyncPriority.Ship; } else if (Object.op_Implicit((Object)(object)prefab2.GetComponent<Character>())) { syncPriority = SyncPriority.Creature; } else if (Object.op_Implicit((Object)(object)prefab2.GetComponent<Piece>())) { syncPriority = SyncPriority.Piece; } } _priorityCache[prefab] = syncPriority; } return syncPriority; } [HarmonyPatch(typeof(ZDOMan), "SendZDOToPeers2")] [HarmonyPrefix] private static bool ZDOMan_SendZDOToPeers2_Patch(ZDOMan __instance, float dt) { if (!VBNetTweaks.c_ModuleZDOOptimization.Value) { return true; } SafeSendZDOToPeers(__instance, dt); return false; } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> SendZDOs_QueueLimitFix(IEnumerable<CodeInstruction> instructions) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; MethodInfo methodInfo = AccessTools.Method(typeof(Helper), "GetQueueLimit", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Ldc_I4 && list[i].operand is int num2 && num2 == 10240) { CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)methodInfo); val.labels.AddRange(list[i].labels); val.blocks.AddRange(list[i].blocks); list[i] = val; num++; } } if (num < 2) { Helper.LogDebug($"ZDOQueueLimit patch WARNING: only {num}/2 replacements found!"); } else { Helper.LogDebug($"ZDOQueueLimit patch OK: {num} replacements, limit={VBNetTweaks.c_ZDOQueueLimit.Value}"); } return list; } [HarmonyPatch(typeof(ZDOMan), "ServerSendCompare")] [HarmonyPrefix] private static bool CustomServerSendCompare(ZDO x, ZDO y, ref int __result) { if (!VBNetTweaks.c_ModuleZDOOptimization.Value) { return true; } if (!ZNet.instance.IsServer()) { return true; } __result = CustomCompare(x, y); return false; } [HarmonyPatch(typeof(ZDOMan), "ShutDown")] [HarmonyPostfix] private static void ClearCaches() { _priorityCache.Clear(); _cursor = 0; _adaptiveBudget = 0f; } } [HarmonyPatch] public class ZNet_Patch { [HarmonyPatch(typeof(ZNet), "Start")] [HarmonyPostfix] private static void ZNet_Start_Patch() { if (Helper.IsDedicated()) { Application.targetFrameRate = VBNetTweaks.c_TargetFPS.Value; } } [HarmonyPatch(typeof(ZNet), "SendPeriodicData")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> SendPeriodicData_Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); bool flag = false; for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Ldc_R4 && list[i].operand is float num && Math.Abs(num - 2f) < 0.001f) { list[i].opcode = OpCodes.Call; list[i].operand = AccessTools.Method(typeof(Helper), "GetMapPositionSendInterval", (Type[])null, (Type[])null); flag = true; } } if (!flag) { Helper.LogDebug("[MapPositionSync] SendPeriodicData constant 2f not found!"); } return list; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPostfix] private static void OnNewConnection_Postfix(ZNet __instance, ZNetPeer peer) { if (VBNetTweaks.c_ModEnabled.Value && !__instance.IsServer()) { List<ZPackage> packages = new List<ZPackage>(); Helper._buffers[peer.m_rpc] = packages; peer.m_rpc.Register<ZPackage>("ZDOData", (Action<ZRpc, ZPackage>)delegate(ZRpc _, ZPackage pkg) { packages.Add(pkg); }); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] [HarmonyPostfix] private static void Shutdown_Postfix() { Helper._buffers.Clear(); } [HarmonyPatch(typeof(ZNet), "Disconnect", new Type[] { typeof(ZNetPeer) })] [HarmonyPostfix] private static void Disconnect_Postfix(ZNetPeer peer) { Helper._buffers.Remove(peer.m_rpc); } [HarmonyPatch(typeof(ZNet), "OnDestroy")] [HarmonyPostfix] private static void ClearTracks() { MiniMap_Patch._playerTracks.Clear(); } } [HarmonyPatch] public static class ZSteamSocket_Patch { [HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")] [HarmonyPostfix] private static void ApplySteamSettings() { if (VBNetTweaks.c_ModuleSteamOptimizations.Value) { SetConfigFloat((ESteamNetworkingConfigValue)25, Helper.GetTimeoutConnected()); SetConfigFloat((ESteamNetworkingConfigValue)24, 30000f); SetConfigInt((ESteamNetworkingConfigValue)11, Helper.GetSteamSendRateMaxKB()); SetConfigInt((ESteamNetworkingConfigValue)9, Helper.GetSteamSendBufferSizeKB()); } } [HarmonyPatch(typeof(ZSteamSocket), "Send")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Send_Transpiler(IEnumerable<CodeInstruction> instructions) { return ReplaceSendQueuedPackages(instructions); } [HarmonyPatch(typeof(ZSteamSocket), "Flush")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Flush_Transpiler(IEnumerable<CodeInstruction> instructions) { return ReplaceSendQueuedPackages(instructions); } [HarmonyPatch(typeof(ZSteamSocket), "Update")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Update_Transpiler(IEnumerable<CodeInstruction> instructions) { return ReplaceSendQueuedPackages(instructions); } private static IEnumerable<CodeInstruction> ReplaceSendQueuedPackages(IEnumerable<CodeInstruction> instructions) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(ZSteamSocket_Patch), (Helper.IsDedicated() || Helper.IsServer()) ? "Replacement_Server" : "Replacement_Client", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ZSteamSocket), "SendQueuedPackages", (Type[])null, (Type[])null); CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Call, (object)methodInfo2, (string)null) }); if (!val.IsValid) { val.Start(); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo2, (string)null) }); } if (!val.IsValid) { Debug.LogError((object)"NetworkSpeedup: Failed to find ZSteamSocket.SendQueuedPackages call"); return val.InstructionEnumeration(); } val.SetInstruction(new CodeInstruction(OpCodes.Call, (object)methodInfo)); return val.InstructionEnumeration(); } private unsafe static void Replacement_Client(ZSteamSocket socket) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 if (!socket.IsConnected() || socket.m_con == HSteamNetConnection.Invalid) { return; } long num = default(long); while (socket.m_sendQueue.Count > 0) { byte[] array = socket.m_sendQueue.Peek(); if (array == null || array.Length == 0) { socket.m_sendQueue.Dequeue(); continue; } EResult val; fixed (byte* ptr = array) { val = SteamNetworkingSockets.SendMessageToConnection(socket.m_con, (IntPtr)ptr, (uint)array.Length, 8, ref num); } if ((int)val != 1) { NetStats.SteamSendFail++; ZLog.Log((object)("Failed to send data " + ((object)(*(EResult*)(&val))/*cast due to .constrained prefix*/).ToString())); break; } socket.m_totalSent += array.Length; socket.m_sendQueue.Dequeue(); } } private unsafe static void Replacement_Server(ZSteamSocket socket) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Invalid comparison between Unknown and I4 if (!socket.IsConnected()) { return; } long num = default(long); while (socket.m_sendQueue.Count > 0) { byte[] array = socket.m_sendQueue.Peek(); if (array == null || array.Length == 0) { socket.m_sendQueue.Dequeue(); continue; } EResult val; fixed (byte* ptr = array) { val = SteamGameServerNetworkingSockets.SendMessageToConnection(socket.m_con, (IntPtr)ptr, (uint)array.Length, 8, ref num); } if ((int)val != 1) { NetStats.SteamSendFail++; ZLog.Log((object)("Failed to send data " + ((object)(*(EResult*)(&val))/*cast due to .constrained prefix*/).ToString())); break; } socket.m_totalSent += array.Length; socket.m_sendQueue.Dequeue(); } } private static void SetConfigFloat(ESteamNetworkingConfigValue config, float value) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected I4, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected I4, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected I4, but got Unknown try { IntPtr intPtr = Marshal.AllocHGlobal(4); try { Marshal.StructureToPtr(value, intPtr, fDeleteOld: false); if ((Helper.IsDedicated() || Helper.IsServer()) ? SteamGameServerNetworkingUtils.SetConfigValue(config, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)3, intPtr) : SteamNetworkingUtils.SetConfigValue(config, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)3, intPtr)) { Helper.LogDebug($"Steam cfg {(int)config} = {value:F2} — OK"); } else { Helper.LogDebug($"Steam cfg {(int)config} = {value:F2} — ОТКЛОНЕНО (нативный SDK не знает этот параметр)"); } } finally { Marshal.FreeHGlobal(intPtr); } } catch (Exception ex) { Helper.LogDebug($"Steam cfg {(int)config} — исключение: {ex.Message}"); } } private static void SetConfigInt(ESteamNetworkingConfigValue config, int value) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected I4, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected I4, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected I4, but got Unknown try { IntPtr intPtr = Marshal.AllocHGlobal(4); try { Marshal.WriteInt32(intPtr, value); if ((Helper.IsDedicated() || Helper.IsServer()) ? SteamGameServerNetworkingUtils.SetConfigValue(config, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, intPtr) : SteamNetworkingUtils.SetConfigValue(config, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, intPtr)) { Helper.LogDebug($"Steam cfg {(int)config} = {value} — OK"); } else { Helper.LogDebug($"Steam cfg {(int)config} = {value} — ОТКЛОНЕНО (нативный SDK не знает этот параметр)"); } } finally { Marshal.FreeHGlobal(intPtr); } } catch (Exception ex) { Helper.LogDebug($"Steam cfg {(int)config} — исключение: {ex.Message}"); } } } [HarmonyPatch] public static class ZSyncTransform_Patch { [HarmonyPatch(typeof(ZSyncTransform), "SyncPosition")] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> SyncPosition_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; int num2 = 0; int num3 = 0; MethodInfo methodInfo = AccessTools.Method(typeof(SyncTuning), "GetMaxExtrapolationSeconds", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(SyncTuning), "GetSnapDistance", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(SyncTuning), "GetInterpFactor", (Type[])null, (Type[])null); float num4 = default(float); for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode != OpCodes.Ldc_R4) { continue; } object operand = val.operand; int num5; if (operand is float) { num4 = (float)operand; num5 = 1; } else { num5 = 0; } if (num5 != 0) { if (Mathf.Approximately(num4, 2f)) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo); num++; } else if (Mathf.Approximately(num4, 5f)) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo2); num2++; } else if (Mathf.Approximately(num4, 0.2f)) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo3); num3++; } } } Helper.LogDebug($"[ZSync] SyncPosition transpiler: cap={num} snap={num2} lerp={num3}"); return list; } [HarmonyPatch(typeof(ZSyncTransform), "ClientSync")] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> ClientSync_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; MethodInfo methodInfo = AccessTools.Method(typeof(SyncTuning), "GetInterpFactor", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Ldc_R4 && val.operand is float num2 && Mathf.Approximately(num2, 0.2f)) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo); num++; } } Helper.LogDebug($"[ZSync] ClientSync transpiler: lerp={num}"); return list; } } }