using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: Guid("d9c87954-ce20-459d-81ec-96599caed427")] [assembly: ComVisible(false)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyProduct("VBMapPingSmooth")] [assembly: AssemblyCompany("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("")] [assembly: AssemblyTitle("VBMapPingSmooth")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [Embedded] [CompilerGenerated] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] [Embedded] [CompilerGenerated] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace VBMapPingSmooth { [HarmonyPatch(typeof(Minimap), "UpdatePlayerPins")] public static class Minimap_UpdatePlayerPins_Patch { private class PlayerTrackData { public Vector3 lastRealPosition; public Vector3 lastRealVelocity; public Vector3 smoothPosition; public Vector3 smoothVelocity; public float lastUpdateTime; public float predictedTimeout; public bool wasTeleporting; public float teleportEndTime; } public static float InterpolationSpeed; public static float SmoothTime; public static float TeleportThreshold; public static float MaxPredictionTime; private static bool? serverModDetected; private static float serverLastUpdateTime; private static Dictionary playerData; private static FieldInfo m_characterIDField; private static FieldInfo m_userIDField; static Minimap_UpdatePlayerPins_Patch() { InterpolationSpeed = 2000f; SmoothTime = 0.033f; TeleportThreshold = 50f; MaxPredictionTime = 0.3f; serverModDetected = null; serverLastUpdateTime = 0f; playerData = new Dictionary(); Type typeFromHandle = typeof(PlayerInfo); m_characterIDField = typeFromHandle.GetField("m_characterID"); if (m_characterIDField != null) { Type fieldType = m_characterIDField.FieldType; m_userIDField = fieldType.GetField("m_userID"); } } [HarmonyPrefix] private static void Prefix() { if (Time.frameCount % 600 == 0) { CleanupOldData(); } } [HarmonyPostfix] private static void Postfix(Minimap __instance, float dt) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0081: 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) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_017e: 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_0187: 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_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: 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_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: 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_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; DetectServerMod(time); for (int i = 0; i < __instance.m_playerPins.Count && i < __instance.m_tempPlayerInfo.Count; i++) { PinData val = __instance.m_playerPins[i]; PlayerInfo val2 = __instance.m_tempPlayerInfo[i]; long playerId = GetPlayerId(val2); if (playerId == 0) { continue; } Vector3 position = val2.m_position; if (!playerData.TryGetValue(playerId, out var value)) { value = new PlayerTrackData(); playerData[playerId] = value; value.smoothPosition = position; value.lastRealPosition = position; value.lastUpdateTime = time; } float num = time - value.lastUpdateTime; if (num > 0.001f && num < 1f) { Vector3 val3 = position - value.lastRealPosition; float magnitude = ((Vector3)(ref val3)).magnitude; if (magnitude > TeleportThreshold) { value.wasTeleporting = true; value.teleportEndTime = time + 0.2f; value.lastRealVelocity = Vector3.zero; } else { value.lastRealVelocity = val3 / num; if (((Vector3)(ref value.lastRealVelocity)).magnitude > 100f) { value.lastRealVelocity = ((Vector3)(ref value.lastRealVelocity)).normalized * 100f; } } } value.lastRealPosition = position; value.lastUpdateTime = time; if (value.teleportEndTime > time) { val.m_pos = position; value.smoothPosition = position; value.smoothVelocity = Vector3.zero; continue; } if (value.wasTeleporting) { value.wasTeleporting = false; } Vector3 val4 = position; float num2 = time - value.lastUpdateTime; bool flag = serverModDetected == true; if (num2 > 0.033f && ((Vector3)(ref value.lastRealVelocity)).magnitude > 0.1f && !flag) { float num3 = Mathf.Min(num2, MaxPredictionTime); val4 = position + value.lastRealVelocity * num3; } float num4 = SmoothTime; float num5 = InterpolationSpeed; float num6 = Vector3.Distance(value.smoothPosition, val4); if (num6 > 30f) { num4 = 0.01f; } else if (num6 > 10f) { num4 = 0.02f; } if (flag) { num5 = InterpolationSpeed * 1.5f; } value.smoothPosition = Vector3.SmoothDamp(value.smoothPosition, val4, ref value.smoothVelocity, num4, num5, dt); val.m_pos = value.smoothPosition; } } private static void DetectServerMod(float now) { if (!serverModDetected.HasValue && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer() && now - serverLastUpdateTime > 0.5f) { serverLastUpdateTime = now; List peers = ZNet.instance.GetPeers(); if (peers.Count > 0 && peers[0].m_rpc != null) { serverModDetected = false; } } } private static long GetPlayerId(PlayerInfo info) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) try { if (m_characterIDField != null) { object value = m_characterIDField.GetValue(info); if (value != null && m_userIDField != null) { return (long)m_userIDField.GetValue(value); } } } catch { } try { FieldInfo field = typeof(PlayerInfo).GetField("m_name"); if (field != null) { string text = field.GetValue(info) as string; if (!string.IsNullOrEmpty(text)) { return text.GetHashCode(); } } } catch { } return 0L; } private static void CleanupOldData() { float time = Time.time; List list = new List(); foreach (KeyValuePair playerDatum in playerData) { if (time - playerDatum.Value.lastUpdateTime > 10f) { list.Add(playerDatum.Key); } } foreach (long item in list) { playerData.Remove(item); } } } [BepInPlugin("VitByr.VBMapPingSmooth", "VBMapPingSmooth", "0.0.1")] public class VBMapPingSmooth : BaseUnityPlugin { private const string ModName = "VBMapPingSmooth"; private const string ModVersion = "0.0.1"; private const string ModGUID = "VitByr.VBMapPingSmooth"; public static ConfigEntry ConfigLanguage; public static ConfigEntry ConfigInterpolationSpeed; public static ConfigEntry ConfigSmoothTime; public static ConfigEntry ConfigTeleportThreshold; public static ConfigEntry ConfigMaxPredictionTime; public static ConfigEntry ConfigUpdateInterval; public static VBMapPingSmooth Instance { get; private set; } public void Awake() { Instance = this; InitConfig(); Minimap_UpdatePlayerPins_Patch.InterpolationSpeed = ConfigInterpolationSpeed.Value; Minimap_UpdatePlayerPins_Patch.SmoothTime = ConfigSmoothTime.Value; Minimap_UpdatePlayerPins_Patch.TeleportThreshold = ConfigTeleportThreshold.Value; Minimap_UpdatePlayerPins_Patch.MaxPredictionTime = ConfigMaxPredictionTime.Value; ZNet_SendPeriodicData_Patch.UpdateInterval = ConfigUpdateInterval.Value; Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "VitByr.VBMapPingSmooth"); } private void InitConfig() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown ConfigLanguage = ((BaseUnityPlugin)this).Config.Bind("0 - General", "Language", Language.Russian, new ConfigDescription("Select interface language / Выберите язык интерфейса \nRequired Restart / Требуется рестарт", (AcceptableValueBase)null, Array.Empty())); ConfigInterpolationSpeed = ((BaseUnityPlugin)this).Config.Bind("Client", "InterpolationSpeed", 1000f, GetConfigDescription("Скорость интерполяции маркера (единиц/сек)\nЧем выше, тем быстрее маркер догоняет реальную позицию", "Marker interpolation speed (units/sec)\nHigher = faster marker catches up to real position", (AcceptableValueBase)(object)new AcceptableValueRange(100f, 10000f))); ConfigSmoothTime = ((BaseUnityPlugin)this).Config.Bind("1 - Client", "SmoothTime", 0.033f, GetConfigDescription("Время сглаживания движения (сек)\nМеньше значение = быстрее реакция, но может быть дёргано\nРекомендуется: 0.016-0.066", "Smooth time (sec)\nLower = faster response, but may be jittery\nRecommended: 0.016-0.066", (AcceptableValueBase)(object)new AcceptableValueRange(0.005f, 0.2f))); ConfigTeleportThreshold = ((BaseUnityPlugin)this).Config.Bind("1 - Client", "TeleportThreshold", 50f, GetConfigDescription("Дистанция для определения телепорта (метров)\nЕсли игрок переместился дальше этого значения за один кадр — считаем телепортом", "Distance for teleport detection (meters)\nIf player moves beyond this value in one frame - consider it a teleport", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 200f))); ConfigMaxPredictionTime = ((BaseUnityPlugin)this).Config.Bind("1 - Client", "MaxPredictionTime", 0.3f, GetConfigDescription("Максимальное время предсказания движения (сек)\nПри задержках маркер будет двигаться по инерции", "Maximum movement prediction time (sec)\nDuring lag, marker will move by inertia", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 1f))); ConfigUpdateInterval = ((BaseUnityPlugin)this).Config.Bind("2 - Server", "UpdateInterval", 0.5f, GetConfigDescription("Интервал отправки позиций игроков (сек)\nМеньше = плавнее, но больше нагрузка на сеть\nВаниль: 2.0, Рекомендуется: 0.1-0.5", "Player position update interval (sec)\nLower = smoother, but more network load\nVanilla: 2.0, Recommended: 0.1-0.5", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f))); } private ConfigDescription GetConfigDescription(string russianDesc, string englishDesc, AcceptableValueBase acceptableValues = null) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown ConfigEntry configLanguage = ConfigLanguage; string text = ((configLanguage != null && configLanguage.Value == Language.English) ? englishDesc : russianDesc); return (acceptableValues != null) ? new ConfigDescription(text, acceptableValues, Array.Empty()) : new ConfigDescription(text, (AcceptableValueBase)null, Array.Empty()); } } public enum Language { Russian, English } [HarmonyPatch(typeof(ZNet), "SendPeriodicData")] public static class ZNet_SendPeriodicData_Patch { private const float ORIGINAL_INTERVAL = 2f; public static float UpdateInterval = 0.1f; [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)2f, (string)null) }); if (val.IsValid) { val.SetInstruction(new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(ZNet_SendPeriodicData_Patch), "UpdateInterval"))); } return val.InstructionEnumeration(); } } }