using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PingDisplayMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Показывает пинг игроков над головами и ваш собственный пинг")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PingDisplayMod")]
[assembly: AssemblyTitle("PingDisplay")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 PingDisplayMod
{
[BepInPlugin("Freddy.PingDisplay", "PingDisplay", "1.0.0")]
public class PingDisplayMod : BaseUnityPlugin
{
public static ManualLogSource Logger;
private readonly Harmony harmony = new Harmony("Freddy.PingDisplay");
private object pingUI;
private object pingText;
private Dictionary<ulong, object> playerPingLabels = new Dictionary<ulong, object>();
private float updateTimer;
private const float UPDATE_INTERVAL = 1f;
private void Awake()
{
Logger = Logger.CreateLogSource("Freddy.PingDisplay");
Logger.LogInfo((object)"Plugin Freddy.PingDisplay is loaded!");
harmony.PatchAll();
}
private void Start()
{
try
{
CreatePingUI();
}
catch (Exception ex)
{
Logger.LogError((object)("Error in Start: " + ex.Message));
}
}
private void Update()
{
try
{
object gameNetworkManager = GetGameNetworkManager();
object startOfRound = GetStartOfRound();
if (gameNetworkManager != null && startOfRound != null)
{
updateTimer += GetDeltaTime();
if (updateTimer >= 1f)
{
updateTimer = 0f;
UpdatePingDisplay();
UpdatePlayerPingLabels();
}
}
}
catch (Exception ex)
{
Logger.LogError((object)("Error in Update: " + ex.Message));
}
}
private void CreatePingUI()
{
try
{
Type unityType = GetUnityType("UnityEngine.Canvas");
object obj = FindObjectOfType(unityType);
if (obj == null)
{
Logger.LogWarning((object)"Canvas not found, UI will not be created");
return;
}
Type unityType2 = GetUnityType("UnityEngine.GameObject");
Type unityType3 = GetUnityType("UnityEngine.RectTransform");
Type unityType4 = GetUnityType("UnityEngine.UI.Image");
Type unityType5 = GetUnityType("UnityEngine.UI.Text");
pingUI = Activator.CreateInstance(unityType2);
SetProperty(pingUI, "name", "PingDisplayUI");
object property = GetProperty(pingUI, "transform");
SetProperty(property, "parent", GetProperty(obj, "transform"));
SetProperty(property, "localScale", new object[3] { 1f, 1f, 1f });
object obj2 = InvokeMethod(pingUI, "AddComponent", unityType3);
SetProperty(obj2, "anchorMin", new object[2] { 0f, 1f });
SetProperty(obj2, "anchorMax", new object[2] { 0f, 1f });
SetProperty(obj2, "anchoredPosition", new object[2] { 10f, -10f });
SetProperty(obj2, "sizeDelta", new object[2] { 200f, 50f });
object obj3 = InvokeMethod(pingUI, "AddComponent", unityType4);
Type unityType6 = GetUnityType("UnityEngine.Color");
object value = Activator.CreateInstance(unityType6, 0f, 0f, 0f, 0.7f);
SetProperty(obj3, "color", value);
object obj4 = Activator.CreateInstance(unityType2);
SetProperty(obj4, "name", "PingText");
object property2 = GetProperty(obj4, "transform");
SetProperty(property2, "parent", property);
SetProperty(property2, "localScale", new object[3] { 1f, 1f, 1f });
object obj5 = InvokeMethod(obj4, "AddComponent", unityType3);
SetProperty(obj5, "anchorMin", new object[2] { 0f, 0f });
SetProperty(obj5, "anchorMax", new object[2] { 1f, 1f });
SetProperty(obj5, "offsetMin", new object[2] { 0f, 0f });
SetProperty(obj5, "offsetMax", new object[2] { 0f, 0f });
pingText = InvokeMethod(obj4, "AddComponent", unityType5);
SetProperty(pingText, "text", "Ping: --");
Type unityType7 = GetUnityType("UnityEngine.Font");
object value2 = InvokeStaticMethod(unityType7, "CreateDynamicFontFromOSFont", "Arial", 16);
SetProperty(pingText, "font", value2);
SetProperty(pingText, "fontSize", 16);
SetProperty(pingText, "color", Activator.CreateInstance(unityType6, 1f, 1f, 1f, 1f));
object value3 = Enum.Parse(GetUnityType("UnityEngine.TextAnchor"), "MiddleLeft");
SetProperty(pingText, "alignment", value3);
Logger.LogInfo((object)"Ping UI created successfully");
}
catch (Exception ex)
{
Logger.LogError((object)("Error creating ping UI: " + ex.Message));
}
}
private void UpdatePingDisplay()
{
if (pingText == null)
{
return;
}
try
{
object gameNetworkManager = GetGameNetworkManager();
if (gameNetworkManager == null)
{
return;
}
int num = 0;
object property = GetProperty(gameNetworkManager, "NetworkManager");
if (property != null)
{
object property2 = GetProperty(property, "NetworkConfig");
if (property2 != null)
{
object property3 = GetProperty(property2, "NetworkTransport");
if (property3 != null)
{
num = (int)InvokeMethod(property3, "GetCurrentRtt", 0);
}
}
}
if (num <= 0)
{
SetProperty(pingText, "text", "Ping: ---");
return;
}
SetProperty(pingText, "text", $"Ping: {num}ms");
Type unityType = GetUnityType("UnityEngine.Color");
SetProperty(value: (num < 50) ? Activator.CreateInstance(unityType, 0f, 1f, 0f, 1f) : ((num >= 100) ? Activator.CreateInstance(unityType, 1f, 0f, 0f, 1f) : Activator.CreateInstance(unityType, 1f, 1f, 0f, 1f)), obj: pingText, propertyName: "color");
}
catch (Exception ex)
{
Logger.LogError((object)("Error updating ping display: " + ex.Message));
SetProperty(pingText, "text", "Ping: Error");
}
}
private void UpdatePlayerPingLabels()
{
try
{
object startOfRound = GetStartOfRound();
if (startOfRound == null || !(GetProperty(startOfRound, "allPlayerScripts") is Array array))
{
return;
}
foreach (object value in playerPingLabels.Values)
{
if (value != null)
{
Destroy(value);
}
}
playerPingLabels.Clear();
foreach (object item in array)
{
if (item != null)
{
object property = GetProperty(startOfRound, "localPlayerController");
if (item != property)
{
CreatePlayerPingLabel(item);
}
}
}
}
catch (Exception ex)
{
Logger.LogError((object)("Error updating player ping labels: " + ex.Message));
}
}
private void CreatePlayerPingLabel(object player)
{
if (player == null)
{
return;
}
try
{
object property = GetProperty(player, "playerClientId");
string text = GetProperty(player, "playerUsername") as string;
object obj = Activator.CreateInstance(GetUnityType("UnityEngine.GameObject"));
SetProperty(obj, "name", $"PingLabel_{property}");
object property2 = GetProperty(obj, "transform");
object property3 = GetProperty(player, "transform");
SetProperty(property2, "parent", property3);
SetProperty(property2, "localPosition", new object[3] { 0f, 2.5f, 0f });
Type unityType = GetUnityType("UnityEngine.Canvas");
object obj2 = InvokeMethod(obj, "AddComponent", unityType);
SetProperty(obj2, "renderMode", 1);
Type unityType2 = GetUnityType("UnityEngine.Camera");
object value = InvokeStaticMethod(unityType2, "main");
SetProperty(obj2, "worldCamera", value);
Type unityType3 = GetUnityType("UnityEngine.UI.Text");
object obj3 = InvokeMethod(obj, "AddComponent", unityType3);
SetProperty(obj3, "text", text + "\nPing: ---");
Type unityType4 = GetUnityType("UnityEngine.Font");
object value2 = InvokeStaticMethod(unityType4, "CreateDynamicFontFromOSFont", "Arial", 12);
SetProperty(obj3, "font", value2);
SetProperty(obj3, "fontSize", 12);
Type unityType5 = GetUnityType("UnityEngine.Color");
SetProperty(obj3, "color", Activator.CreateInstance(unityType5, 1f, 1f, 1f, 1f));
object value3 = Enum.Parse(GetUnityType("UnityEngine.TextAnchor"), "MiddleCenter");
SetProperty(obj3, "alignment", value3);
playerPingLabels[(ulong)property] = obj;
Logger.LogInfo((object)("Created ping label for player " + text));
}
catch (Exception ex)
{
Logger.LogError((object)("Error creating player ping label: " + ex.Message));
}
}
private Type GetUnityType(string typeName)
{
return Type.GetType(typeName) ?? Type.GetType(typeName + ", UnityEngine") ?? Type.GetType(typeName + ", UnityEngine.CoreModule") ?? Type.GetType(typeName + ", UnityEngine.UI");
}
private object GetGameNetworkManager()
{
Type unityType = GetUnityType("GameNetcodeStuff.GameNetworkManager");
if (unityType == null)
{
return null;
}
return InvokeStaticMethod(unityType, "get_Instance");
}
private object GetStartOfRound()
{
Type unityType = GetUnityType("GameNetcodeStuff.StartOfRound");
if (unityType == null)
{
return null;
}
return InvokeStaticMethod(unityType, "get_Instance");
}
private float GetDeltaTime()
{
Type unityType = GetUnityType("UnityEngine.Time");
if (unityType == null)
{
return 0f;
}
return (float)InvokeStaticMethod(unityType, "get_deltaTime");
}
private object FindObjectOfType(Type type)
{
Type unityType = GetUnityType("UnityEngine.Object");
if (unityType == null)
{
return null;
}
return InvokeStaticMethod(unityType, "FindObjectOfType", type);
}
private object InvokeMethod(object obj, string methodName, params object[] parameters)
{
if (obj == null)
{
return null;
}
MethodInfo method = obj.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
return null;
}
return method.Invoke(obj, parameters);
}
private object InvokeStaticMethod(Type type, string methodName, params object[] parameters)
{
if (type == null)
{
return null;
}
MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
return null;
}
return method.Invoke(null, parameters);
}
private object GetProperty(object obj, string propertyName)
{
if (obj == null)
{
return null;
}
PropertyInfo property = obj.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property == null)
{
return null;
}
return property.GetValue(obj);
}
private void SetProperty(object obj, string propertyName, object value)
{
if (obj != null)
{
PropertyInfo property = obj.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (!(property == null))
{
property.SetValue(obj, value);
}
}
}
private void Destroy(object obj)
{
if (obj != null)
{
Type unityType = GetUnityType("UnityEngine.Object");
if (!(unityType == null))
{
InvokeStaticMethod(unityType, "Destroy", obj);
}
}
}
private void OnDestroy()
{
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
if (pingUI != null)
{
Destroy(pingUI);
}
foreach (object value in playerPingLabels.Values)
{
if (value != null)
{
Destroy(value);
}
}
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "Freddy.PingDisplay";
public const string PLUGIN_NAME = "PingDisplay";
public const string PLUGIN_VERSION = "1.0.0";
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "PingDisplayMod";
public const string PLUGIN_NAME = "PingDisplayMod";
public const string PLUGIN_VERSION = "1.0.0";
}
}