Decompiled source of PerfKit v1.1.2

PerfKit.dll

Decompiled a week ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Unity.Jobs.LowLevel.Unsafe;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("PerfKit")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PerfKit")]
[assembly: AssemblyTitle("PerfKit")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PerfKit;

[BepInPlugin("local.perfkit", "PerfKit", "1.1.0")]
public class Plugin : BasePlugin
{
	public const string GUID = "local.perfkit";

	internal static ManualLogSource L;

	internal static ConfigEntry<bool> StripLogStackTrace;

	internal static ConfigEntry<bool> StripExceptionStackTrace;

	internal static ConfigEntry<bool> ShadowEnabled;

	internal static ConfigEntry<int> ShadowDistancePercent;

	internal static ConfigEntry<bool> TextureEnabled;

	internal static ConfigEntry<int> TextureMipOffset;

	internal static ConfigEntry<int> JobWorkerCount;

	internal static ConfigEntry<int> AsyncUploadBufferMB;

	internal static ConfigEntry<int> AsyncUploadTimeSliceMs;

	internal static ConfigEntry<bool> AsyncUploadPersistent;

	internal static ConfigEntry<int> TargetFrameRate;

	internal static ConfigEntry<int> VSyncCount;

	internal static ConfigEntry<bool> DisableVSyncWhenCapping;

	internal static ConfigEntry<int> ReapplySeconds;

	public override void Load()
	{
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Expected O, but got Unknown
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Expected O, but got Unknown
		//IL_0280: Unknown result type (might be due to invalid IL or missing references)
		//IL_028a: Expected O, but got Unknown
		L = ((BasePlugin)this).Log;
		StripLogStackTrace = ((BasePlugin)this).Config.Bind<bool>("1-Log", "StripLogStackTrace", true, T("把 Log/Warning/Assert 的堆栈追踪关掉,减少日志开销。纯收益,肉眼无变化。", "Disables stack traces for Log/Warning/Assert to cut logging overhead. No visual change."));
		StripExceptionStackTrace = ((BasePlugin)this).Config.Bind<bool>("1-Log", "StripExceptionStackTrace", false, T("连 Exception/Error 的堆栈也关。更省,但出错时排查会变难。", "Also strips stack traces for Exception/Error. Cheaper, but harder to debug."));
		ShadowEnabled = ((BasePlugin)this).Config.Bind<bool>("2-Shadows", "Enabled", true, T("是否调整阴影距离。", "Whether to scale shadow distance."));
		ShadowDistancePercent = ((BasePlugin)this).Config.Bind<int>("2-Shadows", "DistancePercent", 65, new ConfigDescription(T("阴影距离缩放到原来的百分之几(10-100)。65 = 只留近处阴影,远处投影消失。", "Shadow distance as a percentage of the original (10-100). 65 keeps near shadows only."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>()));
		TextureEnabled = ((BasePlugin)this).Config.Bind<bool>("3-Textures", "Enabled", true, T("是否降低纹理 mip 上限。注意:运行时改动会触发纹理重新上传,所以只在启动时应用一次。", "Whether to lower the texture mip limit. Note: changing it re-uploads textures, so it is applied once at startup only."));
		TextureMipOffset = ((BasePlugin)this).Config.Bind<int>("3-Textures", "MipOffset", 1, new ConfigDescription(T("相对于【启动时游戏自己的设定】:+1=再降一档(更糊、更快),0=不动,-1=提一档。\n这类改动对隐形敌人(Shadow)的可辨识度可能有轻微影响。", "Offset relative to the value the game sets at startup: +1 = one step lower (blurrier, faster), 0 = unchanged, -1 = one step higher.\nMay slightly affect how easily Shadow (invisible) enemies can be spotted."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(-4, 4), Array.Empty<object>()));
		JobWorkerCount = ((BasePlugin)this).Config.Bind<int>("4-Threads", "JobWorkerCount", 0, T("Job 工作线程数。0=不修改。Unity 只允许在 1..最大值 之间调整,默认已是最大值,所以通常没有收益。", "Job worker thread count. 0 = untouched. Unity only allows 1..maximum and defaults to the maximum, so this rarely helps."));
		AsyncUploadBufferMB = ((BasePlugin)this).Config.Bind<int>("4-Threads", "AsyncUploadBufferMB", 0, T("异步纹理上传环形缓冲大小(MB)。0=不修改。调大减少上传卡顿,但多占内存。", "Async texture upload ring buffer size in MB. 0 = untouched. Larger reduces upload hitching but uses more memory."));
		AsyncUploadTimeSliceMs = ((BasePlugin)this).Config.Bind<int>("4-Threads", "AsyncUploadTimeSliceMs", 0, T("每帧用于异步上传的时间片(毫秒)。0=不修改。调大上传更积极,但每帧多花时间。", "Per-frame time slice for async upload in milliseconds. 0 = untouched. Larger uploads faster but costs frame time."));
		AsyncUploadPersistent = ((BasePlugin)this).Config.Bind<bool>("4-Threads", "AsyncUploadPersistentBuffer", false, T("启用持久上传缓冲。只有 BufferMB 不为 0 时才有意义。", "Enables the persistent upload buffer. Only meaningful when BufferMB is not 0."));
		TargetFrameRate = ((BasePlugin)this).Config.Bind<int>("5-Misc", "TargetFrameRate", 0, T("帧率上限。0=不修改,60=锁 60 帧。\n★ Unity 规则:垂直同步开启时本项会被忽略,必须同时关掉 VSync 才能生效。", "Frame rate cap. 0 = untouched, 60 = cap at 60.\n★ Unity rule: ignored while VSync is on. VSync must be disabled for this to work."));
		VSyncCount = ((BasePlugin)this).Config.Bind<int>("5-Misc", "VSyncCount", -1, T("垂直同步。-1=不修改(跟随游戏内设置),0=关闭,1=开启。\n不建议强关:部分玩家会出现画面撕裂。", "VSync. -1 = untouched (follow in-game setting), 0 = off, 1 = on.\nNot recommended to force off: some players get screen tearing."));
		DisableVSyncWhenCapping = ((BasePlugin)this).Config.Bind<bool>("5-Misc", "DisableVSyncWhenCapping", false, T("当 TargetFrameRate > 0 时自动关闭垂直同步,否则锁帧不生效。默认关(不动玩家的 VSync)。", "Automatically disables VSync when TargetFrameRate > 0, otherwise the cap does nothing. Default off."));
		ReapplySeconds = ((BasePlugin)this).Config.Bind<int>("5-Misc", "ReapplySeconds", 0, new ConfigDescription(T("每隔几秒复查一次设置有没有被游戏改回去。0=只在启动时应用一次(默认,零额外开销)。\n★ 复查只处理阴影/日志/帧率这些廉价项,绝不会再改纹理(改纹理会触发贴图重传,造成卡顿)。", "How often to re-check settings in seconds. 0 = apply once at startup (default, zero overhead).\n★ The periodic check only touches cheap values (shadows/log/fps); it never re-applies the texture limit, which would re-upload textures and hitch."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 120), Array.Empty<object>()));
		L.LogInfo((object)"[PerfKit] v1.1.0 已载入。");
		((BasePlugin)this).AddComponent<Applier>();
	}

	internal static string T(string zh, string en)
	{
		return zh + "\n" + en;
	}
}
public class Applier : MonoBehaviour
{
	private float _timer;

	private bool _appliedOnce;

	private float _baseShadowDistance = -1f;

	private int _baseTextureLimit = -1;

	private void Update()
	{
		_timer += Time.deltaTime;
		if (!_appliedOnce)
		{
			if (!(_timer < 1f))
			{
				_timer = 0f;
				ApplyAll();
				_appliedOnce = true;
			}
		}
		else
		{
			int value = Plugin.ReapplySeconds.Value;
			if (value > 0 && _timer >= (float)value)
			{
				_timer = 0f;
				KeepAlive();
			}
		}
	}

	private void ApplyAll()
	{
		LogSnapshot("启动时");
		ApplyLogSettings();
		ApplyShadows();
		ApplyTextures();
		ApplyThreads();
		ApplyMisc();
		LogSnapshot("应用后");
		Plugin.L.LogInfo((object)"[PerfKit] 完成。");
	}

	private static void LogSnapshot(string tag)
	{
		Plugin.L.LogInfo((object)$"[PerfKit] {tag}:VSync={QualitySettings.vSyncCount} targetFrameRate={Application.targetFrameRate} shadowDistance={QualitySettings.shadowDistance:0.#} masterTextureLimit={QualitySettings.masterTextureLimit}");
	}

	private static void ApplyLogSettings()
	{
		if (Plugin.StripLogStackTrace.Value)
		{
			Application.SetStackTraceLogType((LogType)3, (StackTraceLogType)0);
			Application.SetStackTraceLogType((LogType)2, (StackTraceLogType)0);
			Application.SetStackTraceLogType((LogType)1, (StackTraceLogType)0);
		}
		if (Plugin.StripExceptionStackTrace.Value)
		{
			Application.SetStackTraceLogType((LogType)0, (StackTraceLogType)0);
			Application.SetStackTraceLogType((LogType)4, (StackTraceLogType)0);
		}
	}

	private void ApplyShadows(bool verbose = true)
	{
		if (!Plugin.ShadowEnabled.Value)
		{
			return;
		}
		if (_baseShadowDistance < 0f)
		{
			_baseShadowDistance = QualitySettings.shadowDistance;
		}
		float num = _baseShadowDistance * ((float)Plugin.ShadowDistancePercent.Value / 100f);
		if (!(Math.Abs(QualitySettings.shadowDistance - num) < 0.05f))
		{
			float shadowDistance = QualitySettings.shadowDistance;
			QualitySettings.shadowDistance = num;
			if (verbose)
			{
				Plugin.L.LogInfo((object)$"[PerfKit] 阴影距离 {shadowDistance:0.#} -> {QualitySettings.shadowDistance:0.#} m");
			}
			else
			{
				Plugin.L.LogDebug((object)$"[PerfKit] 阴影距离被改回,重新应用 {shadowDistance:0.#} -> {num:0.#} m");
			}
		}
	}

	private void ApplyTextures()
	{
		if (Plugin.TextureEnabled.Value)
		{
			if (_baseTextureLimit < 0)
			{
				_baseTextureLimit = QualitySettings.masterTextureLimit;
				Plugin.L.LogInfo((object)("[PerfKit] 纹理基准 = " + _baseTextureLimit));
			}
			int num = _baseTextureLimit + Plugin.TextureMipOffset.Value;
			if (num < 0)
			{
				num = 0;
			}
			if (num > 8)
			{
				num = 8;
			}
			if (QualitySettings.masterTextureLimit != num)
			{
				int masterTextureLimit = QualitySettings.masterTextureLimit;
				QualitySettings.masterTextureLimit = num;
				Plugin.L.LogInfo((object)$"[PerfKit] 纹理 mip 上限 {masterTextureLimit} -> {QualitySettings.masterTextureLimit}");
			}
		}
	}

	private static void ApplyThreads()
	{
		int value = Plugin.JobWorkerCount.Value;
		if (value > 0)
		{
			int jobWorkerMaximumCount = JobsUtility.JobWorkerMaximumCount;
			int num = Math.Min(value, jobWorkerMaximumCount);
			if (num < 1)
			{
				num = 1;
			}
			if (JobsUtility.JobWorkerCount != num)
			{
				Plugin.L.LogInfo((object)$"[PerfKit] JobWorkers {JobsUtility.JobWorkerCount} -> {num}(上限 {jobWorkerMaximumCount})");
				JobsUtility.JobWorkerCount = num;
			}
		}
		if (Plugin.AsyncUploadBufferMB.Value > 0)
		{
			QualitySettings.asyncUploadBufferSize = Plugin.AsyncUploadBufferMB.Value;
		}
		if (Plugin.AsyncUploadTimeSliceMs.Value > 0)
		{
			QualitySettings.asyncUploadTimeSlice = Plugin.AsyncUploadTimeSliceMs.Value;
		}
		if (Plugin.AsyncUploadPersistent.Value && Plugin.AsyncUploadBufferMB.Value > 0)
		{
			QualitySettings.asyncUploadPersistentBuffer = true;
		}
	}

	private static void ApplyMisc()
	{
		if (Plugin.VSyncCount.Value >= 0)
		{
			QualitySettings.vSyncCount = Plugin.VSyncCount.Value;
		}
		if (Plugin.TargetFrameRate.Value <= 0)
		{
			return;
		}
		Application.targetFrameRate = Plugin.TargetFrameRate.Value;
		if (QualitySettings.vSyncCount > 0)
		{
			if (Plugin.DisableVSyncWhenCapping.Value)
			{
				QualitySettings.vSyncCount = 0;
				Plugin.L.LogInfo((object)"[PerfKit] 为了让锁帧生效,已关闭垂直同步。");
			}
			else
			{
				Plugin.L.LogWarning((object)"[PerfKit] 锁帧未生效:当前垂直同步是开的,Unity 会忽略 targetFrameRate。要把 [5-Misc] DisableVSyncWhenCapping 设成 true,或在游戏内关掉垂直同步。");
			}
		}
	}

	private void KeepAlive()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		ApplyShadows(verbose: false);
		if (Plugin.StripLogStackTrace.Value && (int)Application.GetStackTraceLogType((LogType)3) != 0)
		{
			ApplyLogSettings();
		}
		if (Plugin.TargetFrameRate.Value > 0 && Application.targetFrameRate != Plugin.TargetFrameRate.Value)
		{
			Application.targetFrameRate = Plugin.TargetFrameRate.Value;
			Plugin.L.LogDebug((object)"[PerfKit] targetFrameRate 被改回,已重新应用。");
		}
	}
}