using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Performance")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Performance")]
[assembly: AssemblyTitle("Performance")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("celunar.performance", "Performance", "1.5.0")]
public class Plugin : BaseUnityPlugin
{
private struct Utilization
{
public uint gpu;
public uint memory;
}
private float fps;
private int frames;
private float fpsTimer;
private uint gpuLoad;
private uint gpuTemp;
private float gpuTimer;
private bool nvmlAvailable;
private IntPtr gpuDevice;
private Type tmpType;
private Type fontAssetType;
private Type canvasType;
private Component fpsText;
private Component gpuText;
private Component tempText;
private object peakFont;
private Component peakSample;
private const float TextSize = 13f;
[DllImport("nvml.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int nvmlInit_v2();
[DllImport("nvml.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int nvmlDeviceGetHandleByIndex_v2(uint index, out IntPtr device);
[DllImport("nvml.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int nvmlDeviceGetTemperature(IntPtr device, uint sensorType, out uint temperature);
[DllImport("nvml.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int nvmlDeviceGetUtilizationRates(IntPtr device, out Utilization utilization);
private void Awake()
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"Performance 1.5.0 loaded!");
FindTypes();
FindPeakAssets();
CreateUI();
InitGPU();
}
private void FindTypes()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
if (tmpType == null)
{
tmpType = assembly.GetType("TMPro.TextMeshProUGUI");
}
if (fontAssetType == null)
{
fontAssetType = assembly.GetType("TMPro.TMP_FontAsset");
}
if (canvasType == null)
{
canvasType = assembly.GetType("UnityEngine.Canvas");
}
}
((BaseUnityPlugin)this).Logger.LogInfo((object)("TMP: " + (tmpType != null)));
((BaseUnityPlugin)this).Logger.LogInfo((object)("FontAsset: " + (fontAssetType != null)));
((BaseUnityPlugin)this).Logger.LogInfo((object)("Canvas: " + (canvasType != null)));
}
private void FindPeakAssets()
{
if (fontAssetType != null)
{
Object[] array = Resources.FindObjectsOfTypeAll(fontAssetType);
Object[] array2 = array;
foreach (Object val in array2)
{
if (!(val == (Object)null) && val.name == "DarumaDropOne-Regular SDF")
{
peakFont = val;
((BaseUnityPlugin)this).Logger.LogInfo((object)("PEAK FONT FOUND: " + val.name));
break;
}
}
}
if (tmpType == null)
{
return;
}
Object[] array3 = Resources.FindObjectsOfTypeAll(tmpType);
Object[] array4 = array3;
foreach (Object val2 in array4)
{
Component val3 = (Component)(object)((val2 is Component) ? val2 : null);
if ((Object)(object)val3 == (Object)null)
{
continue;
}
try
{
PropertyInfo property = tmpType.GetProperty("font");
if (property == null)
{
continue;
}
object value = property.GetValue(val3, null);
if (value != null)
{
string text = value.GetType().GetProperty("name")?.GetValue(value, null) as string;
if (!(text != "DarumaDropOne-Regular SDF"))
{
peakSample = val3;
((BaseUnityPlugin)this).Logger.LogInfo((object)("PEAK TEXT SAMPLE FOUND: " + ((Object)val3.gameObject).name));
break;
}
}
}
catch
{
}
}
if ((Object)(object)peakSample == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find PEAK TMP sample.");
}
}
private void CreateUI()
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Expected O, but got Unknown
if (tmpType == null || canvasType == null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"Required Unity/TMP types not found.");
return;
}
GameObject val = new GameObject("PerformanceCanvas");
Object.DontDestroyOnLoad((Object)(object)val);
Component obj = val.AddComponent(canvasType);
Type type = FindType("UnityEngine.RenderMode");
if (type != null)
{
SetProperty(obj, "renderMode", Enum.Parse(type, "ScreenSpaceOverlay"));
}
SetProperty(obj, "sortingOrder", 9999);
fpsText = CreateText(val.transform, "fps");
gpuText = CreateText(val.transform, "gpu");
tempText = CreateText(val.transform, "gpu temp");
SetPosition(fpsText, -12f, -10f);
SetPosition(gpuText, -12f, -27f);
SetPosition(tempText, -12f, -44f);
}
private Component CreateText(Transform parent, string objectName)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
GameObject val = new GameObject("Performance_" + objectName);
val.transform.SetParent(parent, false);
Component val2 = val.AddComponent(tmpType);
ApplyPeakStyle(val2);
SetProperty(val2, "text", objectName);
SetProperty(val2, "raycastTarget", false);
SetupRect(val);
return val2;
}
private void ApplyPeakStyle(Component target)
{
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
if (peakFont != null)
{
SetProperty(target, "font", peakFont);
}
if ((Object)(object)peakSample != (Object)null)
{
CopyProperty(peakSample, target, "fontSharedMaterial");
CopyProperty(peakSample, target, "fontMaterial");
CopyProperty(peakSample, target, "fontStyle");
CopyProperty(peakSample, target, "fontWeight");
CopyProperty(peakSample, target, "characterSpacing");
CopyProperty(peakSample, target, "wordSpacing");
CopyProperty(peakSample, target, "lineSpacing");
CopyProperty(peakSample, target, "paragraphSpacing");
CopyProperty(peakSample, target, "color");
CopyProperty(peakSample, target, "enableVertexGradient");
CopyProperty(peakSample, target, "enableExtraPadding");
}
else
{
SetProperty(target, "color", (object)new Color(0.88f, 0.84f, 0.75f, 1f));
}
SetProperty(target, "fontSize", 13f);
SetProperty(target, "enableAutoSizing", false);
SetProperty(target, "enableWordWrapping", false);
Type type = FindType("TMPro.TextAlignmentOptions");
if (type != null)
{
try
{
object value = Enum.Parse(type, "TopRight");
SetProperty(target, "alignment", value);
}
catch
{
}
}
}
private void CopyProperty(Component source, Component target, string propertyName)
{
try
{
PropertyInfo property = tmpType.GetProperty(propertyName);
if (!(property == null) && property.CanRead && property.CanWrite)
{
object value = property.GetValue(source, null);
property.SetValue(target, value, null);
}
}
catch
{
}
}
private void SetupRect(GameObject obj)
{
//IL_0046: 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_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
Type type = FindType("UnityEngine.RectTransform");
if (!(type == null))
{
Component component = obj.GetComponent(type);
if (!((Object)(object)component == (Object)null))
{
SetProperty(component, "anchorMin", (object)new Vector2(1f, 1f));
SetProperty(component, "anchorMax", (object)new Vector2(1f, 1f));
SetProperty(component, "pivot", (object)new Vector2(1f, 1f));
SetProperty(component, "sizeDelta", (object)new Vector2(190f, 22f));
}
}
}
private void SetPosition(Component text, float x, float y)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)text == (Object)null)
{
return;
}
Type type = FindType("UnityEngine.RectTransform");
if (!(type == null))
{
Component component = text.gameObject.GetComponent(type);
if (!((Object)(object)component == (Object)null))
{
SetProperty(component, "anchoredPosition", (object)new Vector2(x, y));
}
}
}
private void SetText(Component text, string value)
{
if (!((Object)(object)text == (Object)null))
{
SetProperty(text, "text", value);
}
}
private void SetProperty(object obj, string propertyName, object value)
{
if (obj == null)
{
return;
}
try
{
PropertyInfo property = obj.GetType().GetProperty(propertyName);
if (!(property == null) && property.CanWrite)
{
property.SetValue(obj, value, null);
}
}
catch
{
}
}
private Type FindType(string name)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
Type type = assembly.GetType(name);
if (type != null)
{
return type;
}
}
return null;
}
private void InitGPU()
{
try
{
if (nvmlInit_v2() == 0 && nvmlDeviceGetHandleByIndex_v2(0u, out gpuDevice) == 0)
{
nvmlAvailable = true;
((BaseUnityPlugin)this).Logger.LogInfo((object)"NVIDIA GPU detected.");
}
}
catch
{
nvmlAvailable = false;
}
}
private void Update()
{
frames++;
fpsTimer += Time.unscaledDeltaTime;
if (fpsTimer >= 0.5f)
{
fps = (float)frames / fpsTimer;
frames = 0;
fpsTimer = 0f;
}
gpuTimer += Time.unscaledDeltaTime;
if (gpuTimer >= 1f)
{
gpuTimer = 0f;
UpdateGPU();
}
SetText(fpsText, "fps " + fps.ToString("0"));
if (nvmlAvailable)
{
SetText(gpuText, "gpu " + gpuLoad + "%");
SetText(tempText, "gpu temp " + gpuTemp + "°c");
}
else
{
SetText(gpuText, "gpu --");
SetText(tempText, "gpu temp --");
}
}
private void UpdateGPU()
{
if (!nvmlAvailable)
{
return;
}
try
{
if (nvmlDeviceGetTemperature(gpuDevice, 0u, out var temperature) == 0)
{
gpuTemp = temperature;
}
if (nvmlDeviceGetUtilizationRates(gpuDevice, out var utilization) == 0)
{
gpuLoad = utilization.gpu;
}
}
catch
{
nvmlAvailable = false;
}
}
}