using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Entities; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using VBNetTweaks.Patches; using VBNetTweaks.RPCUtills; using VBNetTweaks.Utils; using VBNetTweaks.ZDOUtills; [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("")] [assembly: AssemblyProduct("VBNetTweaks")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("d9c87954-ce20-459d-81ec-96599caed427")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.9.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.3.8")] [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")] public class VBNetTweaks : BaseUnityPlugin { private const string ModName = "VBNetTweaks"; private const string ModVersion = "0.3.8"; private const string ModGUID = "VitByr.VBNetTweaks"; public CustomRPC _configSyncRPC; private ConfigFile _serverConfig; public static ConfigEntry ModEnabled; public static ConfigEntry DebugEnabled; public static ConfigEntry VerboseLogging; public static ConfigEntry ModuleSteamOptimizations; public static ConfigEntry ModuleShipSync; public static ConfigEntry ModuleRPCRadiusFiltering; public static ConfigEntry SteamSendRateMaxKB; public static ConfigEntry SteamSendBufferSizeKB; public static ConfigEntry SendInterval; public static ConfigEntry PeersPerUpdate; public static ConfigEntry ZDOQueueLimit; public static ConfigEntry FlushThresholdPercent; private Harmony _harmony; public static VBNetTweaks Instance { get; private set; } private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0097: 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_00ad: Expected O, but got Unknown //IL_00ad: Expected O, but got Unknown //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown _serverConfig = new ConfigFile(Path.Combine(Paths.ConfigPath, "VitByr/VBNetTweaks/ServerConfig.cfg"), true); SynchronizationManager.Instance.RegisterCustomConfig(_serverConfig); Instance = this; ModEnabled = ConfigFileExtensions.BindConfig(_serverConfig, "00 - Master", "ModEnabled", true, "Полностью включить/выключить мод VBNetTweaks", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); if (ModEnabled.Value) { InitClientConfigs(); InitServerConfigs(); _configSyncRPC = NetworkManager.Instance.AddRPC("VBNetTweaks_ConfigSync", new CoroutineHandler(OnAdminConfigSync), new CoroutineHandler(OnClientConfigSync)); SynchronizationManager.Instance.AddInitialSynchronization(_configSyncRPC, (Func)(() => BuildConfigPackage())); CreateConfigWatcher(); _harmony = new Harmony("VitByr.VBNetTweaks"); if (ModuleSteamOptimizations.Value) { _harmony.PatchAll(typeof(ZSteamSocket_Patchs)); } if (ModuleShipSync.Value) { _harmony.PatchAll(typeof(ShipSyncFix)); _harmony.PatchAll(typeof(ShipWaterDamagePatch)); } _harmony.PatchAll(typeof(ZNet_Paths)); _harmony.PatchAll(typeof(NetworkSyncPatches)); _harmony.PatchAll(typeof(ZDONetworkOptimizer)); if (ModuleRPCRadiusFiltering.Value) { _harmony.PatchAll(typeof(RpcFilter)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"VBNetTweaks загружен!"); if (DebugEnabled.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Режим отладки включен"); } } } private void InitClientConfigs() { string text = "01 - Debug"; DebugEnabled = ((BaseUnityPlugin)this).Config.Bind(text, "DebugEnabled", false, "Включить отладочный вывод"); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind(text, "VerboseLogging", false, "Включить подробное логирование"); } private void InitServerConfigs() { string text = "02 - Modules"; ModuleSteamOptimizations = ConfigFileExtensions.BindConfig(_serverConfig, text, "SteamOptimizations", true, "Оптимизации Steam сокета", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ModuleShipSync = ConfigFileExtensions.BindConfig(_serverConfig, text, "ShipSync", true, "Синхронизация кораблей", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ModuleRPCRadiusFiltering = ConfigFileExtensions.BindConfig(_serverConfig, text, "RPCRadiusFiltering", true, "Включить секторную фильтрацию RPC", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); string text2 = "03 - Steam Settings"; ConfigFile serverConfig = _serverConfig; AcceptableValueBase val = (AcceptableValueBase)(object)new AcceptableValueRange(256, 10240); SteamSendRateMaxKB = ConfigFileExtensions.BindConfig(serverConfig, text2, "MaxRateKB", 4096, "Максимальная скорость отправки Steam (vanilla = 150 KB/s)", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile serverConfig2 = _serverConfig; val = (AcceptableValueBase)(object)new AcceptableValueRange(512, 8192); SteamSendBufferSizeKB = ConfigFileExtensions.BindConfig(serverConfig2, text2, "SendBufferSizeKB", 2048, "Размер буфера отправки Steam в KB (vanilla = ~260KB). Рекомендуется 1024-4096", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); string text3 = "04 - Server Settings"; ConfigFile serverConfig3 = _serverConfig; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 0.5f); SendInterval = ConfigFileExtensions.BindConfig(serverConfig3, text3, "SendInterval", 0.03f, "Интервал отправки данных (vanilla = 0.05)", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile serverConfig4 = _serverConfig; val = (AcceptableValueBase)(object)new AcceptableValueRange(1, 200); PeersPerUpdate = ConfigFileExtensions.BindConfig(serverConfig4, text3, "PeersPerUpdate", 50, "Количество пиров за один апдейт (vanilla = 1). Лучше ставить значение равное максимальному количеству слотов сервера.", true, (int?)null, val, (Action)null, (ConfigurationManagerAttributes)null); ZDOQueueLimit = ConfigFileExtensions.BindConfig(_serverConfig, text3, "ZDOQueueLimit", 30720, "Размер буфера отправки ZDO пакетов (vanilla = 10240 Kb)", true, (int?)null, (AcceptableValueBase)null, (Action)null, (ConfigurationManagerAttributes)null); ConfigFile serverConfig5 = _serverConfig; val = (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 0.8f); FlushThresholdPercent = ConfigFileExtensions.BindConfig(serverConfig5, text3, "FlushThresholdPercent", 0.35f, "Процент от ZDOQueueLimit для активации flush (0.0-1.0)\n0.1 = редкий flush (экономия трафика, но задержки)\n0.3 = оптимальный баланс (рекомендуется)\n0.5 = частый flush (меньше задержек, больше трафика)", true, (int?)null, val, (Action)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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown ZPackage val = new ZPackage(); try { val.Write(ModEnabled.Value); val.Write(ModuleSteamOptimizations.Value); val.Write(ModuleShipSync.Value); val.Write(ModuleRPCRadiusFiltering.Value); val.Write(SteamSendRateMaxKB.Value); val.Write(SteamSendBufferSizeKB.Value); val.Write(SendInterval.Value); val.Write(PeersPerUpdate.Value); val.Write(ZDOQueueLimit.Value); val.Write(FlushThresholdPercent.Value); } catch (Exception ex) { Debug.LogError((object)("[VBNetTweaks] Error building config package: " + ex.Message)); return new ZPackage(); } return val; } private void ApplyConfigFromPackage(ZPackage pkg) { if (pkg == null || pkg.GetArray().Length == 0) { Debug.LogWarning((object)"[VBNetTweaks] Received empty config package"); return; } try { pkg.SetPos(0); ModEnabled.Value = pkg.ReadBool(); ModuleSteamOptimizations.Value = pkg.ReadBool(); ModuleShipSync.Value = pkg.ReadBool(); ModuleRPCRadiusFiltering.Value = pkg.ReadBool(); SteamSendRateMaxKB.Value = pkg.ReadInt(); SteamSendBufferSizeKB.Value = pkg.ReadInt(); SendInterval.Value = pkg.ReadSingle(); PeersPerUpdate.Value = pkg.ReadInt(); ZDOQueueLimit.Value = pkg.ReadInt(); FlushThresholdPercent.Value = pkg.ReadInt(); } catch (Exception ex) { Debug.LogError((object)("[VBNetTweaks] Error applying config package: " + ex.Message)); } } private IEnumerator OnAdminConfigSync(long sender, ZPackage pkg) { if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer()) { 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 { peer }, copyPkg); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBNetTweaks] Server config broadcast to all clients"); } public IEnumerator OnClientConfigSync(long sender, ZPackage pkg) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[VBNetTweaks] Клиент получил конфиг от сервера {sender}"); ApplyConfigFromPackage(pkg); ConfigFileExtensions.SetSaveOnConfigSet(_serverConfig, true); _serverConfig.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(_serverConfig, 1000L); val.OnConfigFileReloaded += delegate { if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer()) { Debug.Log((object)"[VBNetTweaks] Server config changed, broadcasting to all clients"); ((MonoBehaviour)this).StartCoroutine(ApplyServerConfigChanges()); } }; } public IEnumerator ApplyServerConfigChanges() { yield return null; if (SendInterval.Value <= 0.001f) { SendInterval.Value = 0.03f; } if (PeersPerUpdate.Value <= 0) { PeersPerUpdate.Value = 30; } 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 { peer }, copyPkg); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[VBNetTweaks] Server config broadcast to all clients"); } private void OnDestroy() { _serverConfig.Save(); _harmony.UnpatchSelf(); } } } namespace VBNetTweaks.ZDOUtills { [HarmonyPatch] public static class ZDONetworkOptimizer { [HarmonyPatch(typeof(ZNetScene), "RemoveObjects")] public static class SafeRemoveObjectsPatch { private static bool Prefix(ZNetScene __instance, List currentNearObjects, List currentDistantObjects) { if (!VBNetTweaks.ModuleSteamOptimizations.Value) { return true; } byte b = (byte)(Time.frameCount & 0xFF); if (currentNearObjects != null) { foreach (ZDO currentNearObject in currentNearObjects) { if (currentNearObject != null) { currentNearObject.TempRemoveEarmark = b; } } } if (currentDistantObjects != null) { foreach (ZDO currentDistantObject in currentDistantObjects) { if (currentDistantObject != null) { currentDistantObject.TempRemoveEarmark = b; } } } __instance.m_tempRemoved.Clear(); foreach (KeyValuePair instance in __instance.m_instances) { if (instance.Key != null && Object.op_Implicit((Object)(object)instance.Value) && instance.Key.TempRemoveEarmark != b) { __instance.m_tempRemoved.Add(instance.Value); } } return true; } } [HarmonyTranspiler] [HarmonyPatch(typeof(ZDOMan), "Update")] private static IEnumerable ZDOManUpdateTranspiler(IEnumerable instructions) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).Start(); val.MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(ZDOMan), "SendZDOToPeers2", (Type[])null, (Type[])null), (string)null) }); val.SetOperandAndAdvance((object)AccessTools.Method(typeof(ZDONetworkOptimizer), "OptimizedSendZDOToPeers", (Type[])null, (Type[])null)); return val.InstructionEnumeration(); } public static void OptimizedSendZDOToPeers(ZDOMan zdoManager, float dt) { try { int count = zdoManager.m_peers.Count; if (count <= 0) { return; } zdoManager.m_sendTimer += dt; float value = VBNetTweaks.SendInterval.Value; if (zdoManager.m_sendTimer < value) { return; } zdoManager.m_sendTimer = 0f; int num = Math.Max(zdoManager.m_nextSendPeer, 0); int value2 = VBNetTweaks.PeersPerUpdate.Value; int value3 = VBNetTweaks.ZDOQueueLimit.Value; float value4 = VBNetTweaks.FlushThresholdPercent.Value; int num2 = Mathf.RoundToInt((float)value3 * value4); int num3 = 0; for (int i = 0; i < Math.Min(value2, count); i++) { int index = (num + i) % count; ZDOPeer val = zdoManager.m_peers[index]; if (val == null) { continue; } ZNetPeer peer = val.m_peer; bool? obj; if (peer == null) { obj = null; } else { ISocket socket = peer.m_socket; obj = ((socket != null) ? new bool?(socket.IsConnected()) : ((bool?)null)); } if (obj == true) { int sendQueueSize = val.m_peer.m_socket.GetSendQueueSize(); if (sendQueueSize > value3) { num3++; continue; } bool flag = sendQueueSize <= num2; zdoManager.SendZDOs(val, flag); num3++; } } zdoManager.m_nextSendPeer = (num + num3) % count; } catch (Exception arg) { Helper.LogDebug($"[VBNetTweaks] Error in OptimizedSendZDOToPeers: {arg}"); } } } } namespace VBNetTweaks.RPCUtills { [HarmonyPatch] public static class RpcFilter { private static int[] _rangeLimitedMethodHashes; private static bool IsFeatureEnabled { get { if (!VBNetTweaks.ModuleRPCRadiusFiltering.Value) { return false; } if (ZNet.IsSinglePlayer) { return false; } return true; } } private static bool IsDebugMode { get { if (!VBNetTweaks.VerboseLogging.Value) { return false; } if (Object.op_Implicit((Object)(object)ZoneSystem.instance)) { return ZoneSystem.instance.GetGlobalKey("VBNET_DEBUG_RPC"); } return false; } } private static bool IsRangeLimitedRpc(RoutedRPCData rpcData) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) return IsRangeLimitedRpc(rpcData.m_methodHash, rpcData.m_targetZDO); } private static bool IsRangeLimitedRpc(int methodHash, ZDOID nviewTargetZDOID) { if (_rangeLimitedMethodHashes == null) { _rangeLimitedMethodHashes = new int[44] { StringExtensionMethods.GetStableHashCode("Step"), StringExtensionMethods.GetStableHashCode("RPC_DamageText"), StringExtensionMethods.GetStableHashCode("RPC_Heal"), StringExtensionMethods.GetStableHashCode("RPC_Stagger"), StringExtensionMethods.GetStableHashCode("RPC_AddNoise"), StringExtensionMethods.GetStableHashCode("RPC_OnTargeted"), StringExtensionMethods.GetStableHashCode("RPC_OnDeath"), StringExtensionMethods.GetStableHashCode("RPC_UseStamina"), StringExtensionMethods.GetStableHashCode("RPC_UseEitr"), StringExtensionMethods.GetStableHashCode("RPC_Emote"), StringExtensionMethods.GetStableHashCode("RPC_Wakeup"), StringExtensionMethods.GetStableHashCode("RPC_Sleep"), StringExtensionMethods.GetStableHashCode("RPC_OnNearProjectileHit"), StringExtensionMethods.GetStableHashCode("Rudder"), StringExtensionMethods.GetStableHashCode("RequestControl"), StringExtensionMethods.GetStableHashCode("ReleaseControl"), StringExtensionMethods.GetStableHashCode("RPC_Damage"), StringExtensionMethods.GetStableHashCode("RPC_CreateFragments"), StringExtensionMethods.GetStableHashCode("RPC_SetAreaHealth"), StringExtensionMethods.GetStableHashCode("Hit"), StringExtensionMethods.GetStableHashCode("Hide"), StringExtensionMethods.GetStableHashCode("RPC_Grow"), StringExtensionMethods.GetStableHashCode("RPC_Shake"), StringExtensionMethods.GetStableHashCode("RPC_Remove"), StringExtensionMethods.GetStableHashCode("RPC_Repair"), StringExtensionMethods.GetStableHashCode("RPC_HealthChanged"), StringExtensionMethods.GetStableHashCode("RPC_ClearCachedSupport"), StringExtensionMethods.GetStableHashCode("RPC_SetPicked"), StringExtensionMethods.GetStableHashCode("RPC_Pick"), StringExtensionMethods.GetStableHashCode("Command"), StringExtensionMethods.GetStableHashCode("SetName"), StringExtensionMethods.GetStableHashCode("RPC_UnSummon"), StringExtensionMethods.GetStableHashCode("AddSaddle"), StringExtensionMethods.GetStableHashCode("SetSaddle"), StringExtensionMethods.GetStableHashCode("RPC_AddFuel"), StringExtensionMethods.GetStableHashCode("RPC_AddFuelAmount"), StringExtensionMethods.GetStableHashCode("RPC_SetFuelAmount"), StringExtensionMethods.GetStableHashCode("RPC_ToggleOn"), StringExtensionMethods.GetStableHashCode("RPC_RemoveDoneItem"), StringExtensionMethods.GetStableHashCode("RPC_AddItem"), StringExtensionMethods.GetStableHashCode("RPC_SetSlotVisual"), StringExtensionMethods.GetStableHashCode("RPC_Shoot"), StringExtensionMethods.GetStableHashCode("RPC_OnLegUse"), StringExtensionMethods.GetStableHashCode("RPC_SetLoadedVisual") }; } if (!((ZDOID)(ref nviewTargetZDOID)).IsNone()) { return true; } return _rangeLimitedMethodHashes.Contains(methodHash); } private static bool IsNearby(Vector3 a, Vector3 b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (Character.InInterior(a) != Character.InInterior(b)) { return false; } int num = ZoneSystem.instance.m_activeArea + ZoneSystem.instance.m_activeDistantArea; float zoneSize = ZoneSystem.instance.m_zoneSize; float num2 = zoneSize / 2f; float num3 = (float)(num + 1) * zoneSize + num2; if (Mathf.Abs(a.x - b.x) <= num3) { return Mathf.Abs(a.z - b.z) <= num3; } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ZRoutedRpc), "InvokeRoutedRPC", new Type[] { typeof(long), typeof(ZDOID), typeof(string), typeof(object[]) })] private static void ZRoutedRpc_InvokeRoutedRpc(ZRoutedRpc __instance, ZDOID targetZDO, ref long targetPeerID, string methodName) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (!IsFeatureEnabled || targetPeerID != ZRoutedRpc.Everybody || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !IsRangeLimitedRpc(StringExtensionMethods.GetStableHashCode(methodName), targetZDO)) { return; } Vector3 a; if (!((ZDOID)(ref targetZDO)).IsNone()) { ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(targetZDO) : null); a = ((val != null) ? val.GetPosition() : ((Component)Player.m_localPlayer).transform.position); } else { a = ((Component)Player.m_localPlayer).transform.position; } bool flag = false; List allPlayers = Player.GetAllPlayers(); foreach (Player item in allPlayers) { if ((Object)(object)item == (Object)(object)Player.m_localPlayer || !IsNearby(a, ((Component)item).transform.position)) { continue; } flag = true; break; } if (!flag) { if (IsDebugMode) { Helper.LogVerbose("[RPCFilter] Client: No nearby players, sending " + methodName + " only to self"); } targetPeerID = __instance.m_id; } else if (IsDebugMode) { Helper.LogVerbose("[RPCFilter] Client: Nearby players found, broadcasting " + methodName); } } [HarmonyPrefix] [HarmonyPatch(typeof(ZRoutedRpc), "RouteRPC")] private static void ZRoutedRpc_RouteRPC(ZRoutedRpc __instance, RoutedRPCData rpcData, ref bool __runOriginal) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) if (!IsFeatureEnabled || !__instance.m_server || rpcData.m_targetPeerID != ZRoutedRpc.Everybody || !IsRangeLimitedRpc(rpcData)) { return; } Vector3? val = null; if (!((ZDOID)(ref rpcData.m_targetZDO)).IsNone()) { ZDOMan instance = ZDOMan.instance; ZDO val2 = ((instance != null) ? instance.GetZDO(rpcData.m_targetZDO) : null); if (val2 != null) { val = val2.GetPosition(); } } if (!val.HasValue) { ZNetPeer peer = __instance.GetPeer(rpcData.m_senderPeerID); if (peer != null) { val = peer.m_refPos; } } if (!val.HasValue) { if (IsDebugMode) { Helper.LogVerbose($"[RPCFilter] Server: No source position for RPC {rpcData.m_methodHash}, skipping filter"); } return; } __runOriginal = false; ZPackage val3 = new ZPackage(); rpcData.Serialize(val3); int num = 0; foreach (ZNetPeer peer2 in __instance.m_peers) { if (peer2 != null && rpcData.m_senderPeerID != peer2.m_uid && peer2.IsReady() && IsNearby(val.Value, peer2.m_refPos)) { peer2.m_rpc.Invoke("RoutedRPC", new object[1] { val3 }); num++; } } if (IsDebugMode && num < __instance.m_peers.Count - 1) { Helper.LogVerbose($"[RPCFilter] Server: {rpcData.m_methodHash} sent to {num}/{__instance.m_peers.Count} peers"); } } [HarmonyPrefix] [HarmonyPatch(typeof(ZRoutedRpc), "RouteRPC")] private static void ZRoutedRpc_RouteRPC_DEBUG(ZRoutedRpc __instance, RoutedRPCData rpcData) { if (!IsDebugMode || !__instance.m_server || !IsRangeLimitedRpc(rpcData)) { return; } Helper.LogVerbose($"[RPCFilter] SERVER ROUTE: ID: {__instance.m_id} MsgID: {rpcData.m_msgID} Peers: {__instance.m_peers.Count}"); Helper.LogVerbose("[RPCFilter] NAME\tID\t\tSendByID\tIsReady"); foreach (ZNetPeer peer in __instance.m_peers) { Helper.LogVerbose($"[RPCFilter] {peer.m_playerName}\t{peer.m_uid}\t{peer.m_uid == rpcData.m_senderPeerID}\t\t{peer.IsReady()}"); } } [HarmonyPrefix] [HarmonyPatch(typeof(ZRoutedRpc), "HandleRoutedRPC")] private static void ZRoutedRpc_HandleRoutedRPC_DEBUG(ZRoutedRpc __instance, RoutedRPCData data) { if (IsDebugMode && !__instance.m_server && IsRangeLimitedRpc(data)) { Helper.LogVerbose("[RPCFilter] CLIENT HANDLING RPC: " + $"localSession={ZDOMan.GetSessionID()}, " + $"msgID={data.m_msgID}, " + $"sender={data.m_senderPeerID}, " + $"targetPeer={data.m_targetPeerID}, " + $"method={data.m_methodHash}"); } } } } namespace VBNetTweaks.Patches { [HarmonyPatch] public static class NetworkSyncPatches { private static float _teleportBoostEnd; public static void TriggerTeleportWindow() { _teleportBoostEnd = Time.time + 5f; } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] [HarmonyTranspiler] public static IEnumerable SendZDOs_QueueLimitFix(IEnumerable instructions) { List list = new List(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Ldc_I4 && (int)list[i].operand == 10240) { list[i].operand = VBNetTweaks.ZDOQueueLimit.Value; num++; } } if (num < 2) { ZLog.LogWarning((object)"[VBNetTweaks] ZDOQueueLimit patch failed: found less than 2 instances of 10240!"); } else if (num == 2) { ZLog.LogWarning((object)$"[VBNetTweaks] ZDOQueueLimit patch to: {VBNetTweaks.ZDOQueueLimit.Value}"); } return list; } [HarmonyPatch(typeof(ZNetScene), "InLoadingScreen")] [HarmonyPrefix] public static bool InLoadingScreen_Extend(ref bool __result) { if (Time.time < _teleportBoostEnd) { __result = true; return false; } return true; } [HarmonyPatch(typeof(ZNetScene), "CreateDestroyObjects")] [HarmonyPostfix] public static void CreateDestroyObjects_TriggerTeleport() { Player localPlayer = Player.m_localPlayer; if (localPlayer != null && ((Character)localPlayer).IsTeleporting()) { TriggerTeleportWindow(); } } } public static class ShipSyncFix { private static readonly Dictionary _playerPosVelocities = new Dictionary(); private static FieldInfo m_sendRudderTimeField = AccessTools.Field(typeof(Ship), "m_sendRudderTime"); [HarmonyPatch(typeof(Ship), "ApplyControlls")] [HarmonyPostfix] private static void FasterRudder(Ship __instance, Vector3 dir) { if (__instance.m_nview.IsOwner()) { float num = (float)m_sendRudderTimeField.GetValue(__instance); if (Time.time - num > 0.05f) { m_sendRudderTimeField.SetValue(__instance, Time.time); __instance.m_nview.InvokeRPC("Rudder", new object[1] { __instance.m_rudderValue }); } } } [HarmonyPatch(typeof(Ship), "Awake")] [HarmonyPostfix] public static void EnableShipInterpolation(Ship __instance) { if (Object.op_Implicit((Object)(object)__instance.m_body)) { __instance.m_body.interpolation = (RigidbodyInterpolation)1; __instance.m_body.collisionDetectionMode = (CollisionDetectionMode)2; } } [HarmonyPatch(typeof(Player), "UpdateAttach")] [HarmonyPostfix] public static void SmoothAttachedPlayer(Player __instance) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0083: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_attached && __instance.m_attachedToShip && Object.op_Implicit((Object)(object)__instance.m_attachPoint)) { long playerID = __instance.GetPlayerID(); Transform attachPoint = __instance.m_attachPoint; Transform transform = ((Component)__instance).transform; if (!_playerPosVelocities.ContainsKey(playerID)) { _playerPosVelocities[playerID] = Vector3.zero; transform.position = attachPoint.position; transform.rotation = attachPoint.rotation; return; } Vector3 position = attachPoint.position; Quaternion rotation = attachPoint.rotation; float num = 0.08f; Vector3 value = _playerPosVelocities[playerID]; transform.position = Vector3.SmoothDamp(transform.position, position, ref value, num); _playerPosVelocities[playerID] = value; transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime / 0.1f); } } [HarmonyPatch(typeof(Player), "AttachStop")] [HarmonyPrefix] public static void ClearCacheOnDetach(Player __instance) { RemoveFromCache(__instance.GetPlayerID()); } [HarmonyPatch(typeof(Player), "OnDestroy")] [HarmonyPrefix] public static void ClearCacheOnDestroy(Player __instance) { RemoveFromCache(__instance.GetPlayerID()); } private static void RemoveFromCache(long id) { if (_playerPosVelocities.ContainsKey(id)) { _playerPosVelocities.Remove(id); } } } [HarmonyPatch(typeof(Ship))] public static class ShipWaterDamagePatch { [HarmonyPrefix] [HarmonyPatch("UpdateWaterForce")] private static bool Prefix(Ship __instance, ref float depth, ref float time) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_0100: Unknown result type (might be due to invalid IL or missing references) float num = depth - __instance.m_lastDepth; float num2 = time - __instance.m_lastUpdateWaterForceTime; __instance.m_lastDepth = depth; __instance.m_lastUpdateWaterForceTime = time; if (num2 <= 0.001f) { return true; } float num3 = num / num2; if (num3 <= 0f && Mathf.Abs(num3) > __instance.m_minWaterImpactForce && time - __instance.m_lastWaterImpactTime > __instance.m_minWaterImpactInterval) { __instance.m_lastWaterImpactTime = time; __instance.m_waterImpactEffect.Create(((Component)__instance).transform.position, ((Component)__instance).transform.rotation, (Transform)null, 1f, -1); if (__instance.m_nview.IsOwner() && __instance.m_players.Count > 0) { HitData val = new HitData(); val.m_damage.m_blunt = __instance.m_waterImpactDamage; val.m_point = ((Component)__instance).transform.position; val.m_dir = Vector3.up; __instance.m_destructible.Damage(val); } } return false; } } [HarmonyPatch] public static class ZSteamSocket_Patchs { private static bool _steamConfigApplied = false; private static bool _steamConfigAttempted = false; private static int _cachedSendBuffer = -1; private static int _cachedMaxRate = -1; private static bool HasSettingsChanged() { if (!_steamConfigAttempted) { return true; } int num = VBNetTweaks.SteamSendBufferSizeKB.Value * 1024; int num2 = VBNetTweaks.SteamSendRateMaxKB.Value * 1024; return num != _cachedSendBuffer || num2 != _cachedMaxRate; } private static void UpdateCachedSettings() { _cachedSendBuffer = VBNetTweaks.SteamSendBufferSizeKB.Value * 1024; _cachedMaxRate = VBNetTweaks.SteamSendRateMaxKB.Value * 1024; _steamConfigAttempted = true; } [HarmonyTranspiler] [HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")] private static IEnumerable RegisterGlobalCallbacks_Transpiler(IEnumerable instructions) { if (!VBNetTweaks.ModuleSteamOptimizations.Value) { return instructions; } List list = new List(instructions); bool flag = false; for (int i = 0; i < list.Count; i++) { if (list[i].opcode == OpCodes.Ldc_I4 && (int)list[i].operand == 153600) { int num = Math.Max(64, VBNetTweaks.SteamSendRateMaxKB.Value) * 1024; list[i].operand = num; flag = true; ZLog.LogWarning((object)$"[VBNetTweaks] Steam rate patched: 153600 -> {num} bytes/s ({VBNetTweaks.SteamSendRateMaxKB.Value}KB/s)"); break; } } if (!flag) { ZLog.LogWarning((object)"[VBNetTweaks] Steam rate constant 153600 not found in IL!"); } return list; } [HarmonyPostfix] [HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")] private static void ApplySteamBuffersOnce() { if (!VBNetTweaks.ModuleSteamOptimizations.Value) { return; } if (_steamConfigApplied && !HasSettingsChanged()) { Helper.LogVerbose("[VBNetTweaks] Steam buffers already applied, settings unchanged - skipping"); return; } ZLog.LogWarning((object)"[VBNetTweaks] Applying Steam buffer settings (first time or config changed)..."); try { Type type = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type type2 = assembly.GetType("Steamworks.SteamNetworkingUtils"); if (type2 != null) { type = type2; break; } type2 = assembly.GetType("Steamworks.SteamGameServerNetworkingUtils"); if (type2 != null) { type = type2; break; } } if (type == null) { ZLog.LogWarning((object)"[VBNetTweaks] SteamNetworkingUtils type not found, buffer settings skipped."); _steamConfigApplied = true; UpdateCachedSettings(); return; } MethodInfo setConfigMethod = type.GetMethod("SetConfigValue", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[5] { typeof(int), typeof(int), typeof(IntPtr), typeof(int), typeof(IntPtr) }, null); if (setConfigMethod == null) { ZLog.LogWarning((object)"[VBNetTweaks] SetConfigValue method not found, buffer settings skipped."); _steamConfigApplied = true; UpdateCachedSettings(); return; } Type configValueType = null; Type type3 = null; Type type4 = null; Assembly[] assemblies2 = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly2 in assemblies2) { if (configValueType == null) { configValueType = assembly2.GetType("Steamworks.ESteamNetworkingConfigValue"); } if (type3 == null) { type3 = assembly2.GetType("Steamworks.ESteamNetworkingConfigScope"); } if (type4 == null) { type4 = assembly2.GetType("Steamworks.ESteamNetworkingConfigDataType"); } if (configValueType != null && type3 != null && type4 != null) { break; } } if (configValueType == null || type3 == null || type4 == null) { ZLog.LogWarning((object)"[VBNetTweaks] Steam enums not found, buffer settings skipped."); _steamConfigApplied = true; UpdateCachedSettings(); return; } object globalScope = Enum.Parse(type3, "k_ESteamNetworkingConfig_Global"); object intDataType = Enum.Parse(type4, "k_ESteamNetworkingConfig_Int32"); int num = Math.Max(524288, VBNetTweaks.SteamSendBufferSizeKB.Value * 1024); SetConfigValue("k_ESteamNetworkingConfig_SendBufferSize", num); SetConfigValue("k_ESteamNetworkingConfig_RecvBufferSize", num); SetConfigValue("k_ESteamNetworkingConfig_RecvMaxMessageSize", 4194304); int num2 = Math.Max(262144, VBNetTweaks.SteamSendRateMaxKB.Value * 1024 / 2); SetConfigValue("k_ESteamNetworkingConfig_SendRateMin", num2); _steamConfigApplied = true; UpdateCachedSettings(); ZLog.LogWarning((object)$"[VBNetTweaks] Steam buffers applied: SendBuffer={num / 1024}KB, MinRate={num2 / 1024}KB/s"); void SetConfigValue(string keyName, int value) { try { object obj = Enum.Parse(configValueType, keyName); GCHandle gCHandle = GCHandle.Alloc(value, GCHandleType.Pinned); try { setConfigMethod.Invoke(null, new object[5] { (int)obj, (int)globalScope, IntPtr.Zero, (int)intDataType, gCHandle.AddrOfPinnedObject() }); } finally { gCHandle.Free(); } } catch (Exception ex2) { ZLog.LogWarning((object)("[VBNetTweaks] Failed to set " + keyName + ": " + ex2.Message)); } } } catch (Exception ex) { ZLog.LogError((object)("[VBNetTweaks] Failed to apply Steam buffer settings: " + ex.Message)); _steamConfigApplied = true; UpdateCachedSettings(); } } } [HarmonyPatch(typeof(ZNet), "Update")] public static class ZNet_Paths { [HarmonyPostfix] public static void Postfix(ZNet __instance) { if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)ZNet.instance)) { PerformanceMonitor.Track("ZNet.Update", delegate { }); } } } } namespace VBNetTweaks.Utils { public static class PerformanceMonitor { private struct Sample { public string Name; public float TotalTime; public int Count; public float LastLogTime; } private static Dictionary _samples = new Dictionary(); private const float LOG_INTERVAL = 5f; public static void Track(string name, Action action) { if (!VBNetTweaks.DebugEnabled.Value) { action(); return; } Stopwatch stopwatch = Stopwatch.StartNew(); action(); stopwatch.Stop(); if (!_samples.TryGetValue(name, out var value)) { value = new Sample { Name = name }; } value.TotalTime += stopwatch.ElapsedMilliseconds; value.Count++; float time = Time.time; if (time - value.LastLogTime > 5f) { float num = value.TotalTime / (float)value.Count; Helper.LogDebug($"{name}: avg={num:F2}ms over {value.Count} samples"); value.TotalTime = 0f; value.Count = 0; value.LastLogTime = time; } _samples[name] = value; } } public static class Helper { public static bool IsServer() { return Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer(); } public static ZNet SafeZNetInstance() { return ZNet.instance; } public static void LogErrorWithContext(string module, string message, Exception ex = null) { string text = ((ex != null) ? (" [" + ex.Message + "]") : ""); Debug.LogError((object)("[VBNetTweaks][" + module + "] " + message + text)); } public static bool IsServerInitialized() { return IsServer() && Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer(); } public static void LogDebug(string message) { if (VBNetTweaks.DebugEnabled.Value) { Debug.LogWarning((object)("[VBNetTweaks] " + message)); } } public static void LogVerbose(string message) { if (VBNetTweaks.VerboseLogging.Value) { Debug.LogWarning((object)("[VBNetTweaks] " + message)); } } } }