using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;
using Zorro.Settings;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Peak4KScreenshot")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Peak4KScreenshot")]
[assembly: AssemblyTitle("Peak4KScreenshot")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
internal sealed class IsUnmanagedAttribute : Attribute
{
}
[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 Peak4KScreenshot
{
public enum CaptureResolution
{
UHD_4K,
QHD_2K,
DCI_4K,
UHD_8K,
Native
}
public enum OrientationFix
{
None,
FlipVertical,
FlipHorizontal,
Rotate180
}
public enum UiScaleMode
{
Auto,
MatchScreen
}
public readonly struct CaptureRequest
{
public readonly int Width;
public readonly int Height;
public readonly int SuperSample;
public readonly bool HideHud;
public readonly string OutputPath;
public readonly OrientationFix Orientation;
public readonly UiScaleMode UiScale;
public readonly bool BoostQuality;
public CaptureRequest(int width, int height, int superSample, bool hideHud, string outputPath, OrientationFix orientation = OrientationFix.None, UiScaleMode uiScale = UiScaleMode.Auto, bool boostQuality = false)
{
Width = width;
Height = height;
SuperSample = superSample;
HideHud = hideHud;
OutputPath = outputPath;
Orientation = orientation;
UiScale = uiScale;
BoostQuality = boostQuality;
}
}
public readonly struct CaptureResult
{
public readonly bool Success;
public readonly string FilePath;
public readonly int Width;
public readonly int Height;
public readonly string Error;
public CaptureResult(bool success, string filePath, int width, int height, string error)
{
Success = success;
FilePath = filePath;
Width = width;
Height = height;
Error = error;
}
}
public static class HighResCapture
{
private const int MaxWaitFrames = 600;
private const int MinWaitFrames = 2;
private const int CanvasWarmupFrames = 3;
private const int QualityWarmupFrames = 5;
public static IEnumerator CaptureRoutine(CaptureRequest request, Action<CaptureResult> onDone)
{
Camera cam = ResolveMainCamera();
if ((Object)(object)cam == (Object)null)
{
CaptureResult obj = new CaptureResult(success: false, null, request.Width, request.Height, Lang.Get("Main camera not found", "找不到主相机"));
onDone?.Invoke(obj);
yield break;
}
int renderWidth = request.Width * request.SuperSample;
int renderHeight = request.Height * request.SuperSample;
RenderTextureDescriptor val = default(RenderTextureDescriptor);
((RenderTextureDescriptor)(ref val))..ctor(renderWidth, renderHeight);
((RenderTextureDescriptor)(ref val)).graphicsFormat = SystemInfo.GetGraphicsFormat((DefaultFormat)0);
((RenderTextureDescriptor)(ref val)).depthBufferBits = 24;
((RenderTextureDescriptor)(ref val)).msaaSamples = 1;
((RenderTextureDescriptor)(ref val)).sRGB = true;
((RenderTextureDescriptor)(ref val)).useMipMap = false;
((RenderTextureDescriptor)(ref val)).autoGenerateMips = false;
RenderTextureDescriptor val2 = val;
RenderTexture rt = null;
Texture2D readback = null;
List<HudController.CanvasState> hudStates = null;
QualityBoost.Restore qualityRestore = null;
string failure = null;
SingleCameraRequest renderRequest = new SingleCameraRequest
{
destination = null,
mipLevel = 0,
face = (CubemapFace)(-1),
slice = 0
};
try
{
rt = new RenderTexture(val2)
{
name = "Peak4KScreenshot_RT",
filterMode = (FilterMode)1,
wrapMode = (TextureWrapMode)1
};
if (!rt.Create())
{
throw new InvalidOperationException(Lang.Get("Failed to create the RenderTexture", "RenderTexture 创建失败"));
}
hudStates = (request.HideHud ? HudController.HideAll() : HudController.PrepareForCapture(cam, renderWidth, request.UiScale));
if (request.BoostQuality)
{
qualityRestore = QualityBoost.Apply();
}
renderRequest.destination = rt;
}
catch (Exception ex)
{
failure = ex.Message;
}
if (failure == null)
{
if (!request.HideHud)
{
Canvas.ForceUpdateCanvases();
for (int i = 0; i < 3; i++)
{
yield return null;
}
Canvas.ForceUpdateCanvases();
}
if (request.BoostQuality)
{
for (int i = 0; i < 5; i++)
{
yield return null;
}
}
RenderPipeline.SubmitRenderRequest<SingleCameraRequest>(cam, renderRequest);
for (int i = 0; i < 2; i++)
{
yield return null;
}
int waited = 0;
while (cam.isProcessingRenderRequest && waited < 600)
{
waited++;
yield return null;
}
if (waited >= 600)
{
failure = Lang.Get("Timed out waiting for the offscreen render", "等待离屏渲染超时");
}
else
{
yield return (object)new WaitForEndOfFrame();
}
}
byte[] png = null;
string finalPath = request.OutputPath + ".png";
int outW = renderWidth;
int outH = renderHeight;
if (failure == null)
{
try
{
readback = new Texture2D(renderWidth, renderHeight, (TextureFormat)3, false);
RenderTexture active = RenderTexture.active;
RenderTexture.active = rt;
readback.ReadPixels(new Rect(0f, 0f, (float)renderWidth, (float)renderHeight), 0, 0);
readback.Apply(false);
RenderTexture.active = active;
ApplyOrientation(readback, request.Orientation);
if (request.SuperSample > 1)
{
Texture2D val3 = ScaleDown(readback, request.Width, request.Height, request.SuperSample);
Object.Destroy((Object)(object)readback);
readback = val3;
outW = request.Width;
outH = request.Height;
}
png = ImageConversion.EncodeToPNG(readback);
Object.Destroy((Object)(object)readback);
readback = null;
if (png == null || png.Length == 0)
{
failure = Lang.Get("PNG encoding failed", "PNG 编码失败");
}
}
catch (Exception ex2)
{
failure = ex2.Message;
}
}
HudController.Restore(hudStates);
qualityRestore?.Dispose();
if (failure != null)
{
Log.Error(Lang.Get("Capture failed: " + failure, "截图失败:" + failure));
Cleanup(rt, readback);
onDone?.Invoke(new CaptureResult(success: false, null, outW, outH, failure));
yield break;
}
Cleanup(rt, readback);
Task.Run(delegate
{
string text = null;
try
{
string directoryName = Path.GetDirectoryName(finalPath);
if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
File.WriteAllBytes(finalPath, png);
}
catch (Exception ex3)
{
text = ex3.Message;
}
CaptureResult result = ((text == null) ? new CaptureResult(success: true, finalPath, outW, outH, null) : new CaptureResult(success: false, null, outW, outH, Lang.Get("Failed to write the file: " + text, "写盘失败:" + text)));
UnityMainThreadDispatcher.Enqueue(delegate
{
Log.Info(result.Success ? Lang.Get($"Screenshot saved: {result.FilePath} ({result.Width}x{result.Height})", $"截图已保存:{result.FilePath} ({result.Width}x{result.Height})") : Lang.Get("Capture failed: " + result.Error, "截图失败:" + result.Error));
onDone?.Invoke(result);
});
});
}
private static void Cleanup(RenderTexture rt, Texture2D readback)
{
if ((Object)(object)readback != (Object)null)
{
Object.Destroy((Object)(object)readback);
}
if ((Object)(object)rt != (Object)null)
{
rt.Release();
Object.Destroy((Object)(object)rt);
}
}
private static Camera ResolveMainCamera()
{
try
{
Type type = Type.GetType("MainCamera, Assembly-CSharp");
if (type != null)
{
object obj = type.GetField("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
if (obj != null)
{
object? obj2 = type.GetField("cam", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
Camera val = (Camera)((obj2 is Camera) ? obj2 : null);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
}
}
catch (Exception ex)
{
Log.Warning(Lang.Get("Failed to resolve MainCamera via reflection: " + ex.Message, "反射获取 MainCamera 失败:" + ex.Message));
}
return Camera.main;
}
private static void ApplyOrientation(Texture2D tex, OrientationFix fix)
{
switch (fix)
{
case OrientationFix.FlipVertical:
FlipRows(tex);
break;
case OrientationFix.FlipHorizontal:
FlipColumns(tex);
break;
case OrientationFix.Rotate180:
FlipRows(tex);
FlipColumns(tex);
break;
}
}
private static void FlipRows(Texture2D tex)
{
int width = ((Texture)tex).width;
int height = ((Texture)tex).height;
Color[] pixels = tex.GetPixels();
Color[] array = (Color[])(object)new Color[pixels.Length];
for (int i = 0; i < height; i++)
{
Array.Copy(pixels, (height - 1 - i) * width, array, i * width, width);
}
tex.SetPixels(array);
tex.Apply(false);
}
private static void FlipColumns(Texture2D tex)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
int width = ((Texture)tex).width;
int height = ((Texture)tex).height;
Color[] pixels = tex.GetPixels();
Color[] array = (Color[])(object)new Color[pixels.Length];
for (int i = 0; i < height; i++)
{
int num = i * width;
for (int j = 0; j < width; j++)
{
array[num + j] = pixels[num + (width - 1 - j)];
}
}
tex.SetPixels(array);
tex.Apply(false);
}
private static Texture2D ScaleDown(Texture2D source, int targetWidth, int targetHeight, int factor)
{
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: 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_0112: Expected O, but got Unknown
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
Color[] pixels = source.GetPixels();
int width = ((Texture)source).width;
Color[] array = (Color[])(object)new Color[targetWidth * targetHeight];
for (int i = 0; i < targetHeight; i++)
{
for (int j = 0; j < targetWidth; j++)
{
float num = 0f;
float num2 = 0f;
float num3 = 0f;
int num4 = 0;
for (int k = 0; k < factor; k++)
{
int num5 = i * factor + k;
if (num5 >= ((Texture)source).height)
{
continue;
}
for (int l = 0; l < factor; l++)
{
int num6 = j * factor + l;
if (num6 < width)
{
Color val = pixels[num5 * width + num6];
num += val.r;
num2 += val.g;
num3 += val.b;
num4++;
}
}
}
if (num4 == 0)
{
num4 = 1;
}
array[i * targetWidth + j] = new Color(num / (float)num4, num2 / (float)num4, num3 / (float)num4);
}
}
Texture2D val2 = new Texture2D(targetWidth, targetHeight, (TextureFormat)3, false);
val2.SetPixels(array);
val2.Apply(false);
return val2;
}
}
public static class HudController
{
public readonly struct CanvasState
{
public readonly Canvas Canvas;
public readonly RenderMode Mode;
public readonly Camera WorldCamera;
public readonly float PlaneDistance;
public readonly bool Enabled;
public readonly bool OverrideSorting;
public readonly int SortingOrder;
public readonly CanvasScaler AddedScaler;
public readonly CanvasScaler ExistingScaler;
public readonly ScaleMode ExistingScaleMode;
public readonly float ExistingScaleFactor;
public readonly Vector2 ExistingReferenceResolution;
public readonly ScreenMatchMode ExistingMatchMode;
public readonly float ExistingMatchWidthOrHeight;
public readonly float ExistingReferencePixelsPerUnit;
public CanvasState(Canvas canvas, CanvasScaler addedScaler, CanvasScaler existingScaler)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: 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_0068: 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_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: 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_0091: Unknown result type (might be due to invalid IL or missing references)
Canvas = canvas;
Mode = canvas.renderMode;
WorldCamera = canvas.worldCamera;
PlaneDistance = canvas.planeDistance;
Enabled = ((Behaviour)canvas).enabled;
OverrideSorting = canvas.overrideSorting;
SortingOrder = canvas.sortingOrder;
AddedScaler = addedScaler;
ExistingScaler = existingScaler;
if ((Object)(object)existingScaler != (Object)null)
{
ExistingScaleMode = existingScaler.uiScaleMode;
ExistingScaleFactor = existingScaler.scaleFactor;
ExistingReferenceResolution = existingScaler.referenceResolution;
ExistingMatchMode = existingScaler.screenMatchMode;
ExistingMatchWidthOrHeight = existingScaler.matchWidthOrHeight;
ExistingReferencePixelsPerUnit = existingScaler.referencePixelsPerUnit;
}
else
{
ExistingScaleMode = (ScaleMode)0;
ExistingScaleFactor = 1f;
ExistingReferenceResolution = Vector2.zero;
ExistingMatchMode = (ScreenMatchMode)0;
ExistingMatchWidthOrHeight = 0.5f;
ExistingReferencePixelsPerUnit = 100f;
}
}
}
private const string OwnCanvasPrefix = "Peak4KScreenshot_";
public static List<CanvasState> HideAll()
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Invalid comparison between Unknown and I4
List<CanvasState> list = new List<CanvasState>();
foreach (Canvas item in FindUiCanvases())
{
if (((Behaviour)item).enabled && (int)item.renderMode != 2)
{
list.Add(new CanvasState(item, null, ((Component)item).GetComponent<CanvasScaler>()));
((Behaviour)item).enabled = false;
}
}
Log.Info(Lang.Get($"Disabled {list.Count} UI canvases", $"已关闭 {list.Count} 个 UI Canvas"));
return list;
}
public static List<CanvasState> PrepareForCapture(Camera camera, int renderWidth, UiScaleMode uiScale)
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Invalid comparison between Unknown and I4
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
List<CanvasState> list = new List<CanvasState>();
if ((Object)(object)camera == (Object)null)
{
return list;
}
float planeDistance = Mathf.Max(camera.nearClipPlane * 2f, 0.5f);
float scaleFactor = (float)renderWidth / (float)Mathf.Max(1, Screen.width);
foreach (Canvas item in FindUiCanvases())
{
if (!((Behaviour)item).enabled || (int)item.renderMode == 2 || (int)item.renderMode != 0)
{
continue;
}
CanvasScaler val = null;
CanvasScaler component = ((Component)item).GetComponent<CanvasScaler>();
try
{
if (uiScale == UiScaleMode.MatchScreen)
{
if ((Object)(object)component != (Object)null)
{
component.uiScaleMode = (ScaleMode)0;
component.scaleFactor = scaleFactor;
}
else
{
val = ((Component)item).gameObject.AddComponent<CanvasScaler>();
val.uiScaleMode = (ScaleMode)0;
val.scaleFactor = scaleFactor;
val.referencePixelsPerUnit = 100f;
}
}
list.Add(new CanvasState(item, val, component));
item.renderMode = (RenderMode)1;
item.worldCamera = camera;
item.planeDistance = planeDistance;
item.overrideSorting = true;
item.sortingOrder = 32767;
}
catch (Exception ex)
{
Log.Warning(Lang.Get("Failed to process canvas '" + ((Object)item).name + "': " + ex.Message, "处理 Canvas '" + ((Object)item).name + "' 失败: " + ex.Message));
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)val);
}
}
}
Log.Info(Lang.Get($"Converted {list.Count} canvases to Camera mode (UI scale mode: {uiScale})", $"已转换 {list.Count} 个 Canvas 为 Camera 模式,UI缩放模式={uiScale}"));
return list;
}
public static void Restore(List<CanvasState> states)
{
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
if (states == null)
{
return;
}
foreach (CanvasState state in states)
{
if ((Object)(object)state.Canvas == (Object)null)
{
continue;
}
try
{
if ((Object)(object)state.ExistingScaler != (Object)null)
{
state.ExistingScaler.uiScaleMode = state.ExistingScaleMode;
state.ExistingScaler.scaleFactor = state.ExistingScaleFactor;
state.ExistingScaler.referenceResolution = state.ExistingReferenceResolution;
state.ExistingScaler.screenMatchMode = state.ExistingMatchMode;
state.ExistingScaler.matchWidthOrHeight = state.ExistingMatchWidthOrHeight;
state.ExistingScaler.referencePixelsPerUnit = state.ExistingReferencePixelsPerUnit;
}
state.Canvas.overrideSorting = state.OverrideSorting;
state.Canvas.sortingOrder = state.SortingOrder;
state.Canvas.renderMode = state.Mode;
state.Canvas.worldCamera = state.WorldCamera;
state.Canvas.planeDistance = state.PlaneDistance;
((Behaviour)state.Canvas).enabled = state.Enabled;
}
catch (Exception)
{
}
if ((Object)(object)state.AddedScaler != (Object)null)
{
Object.Destroy((Object)(object)state.AddedScaler);
}
}
states.Clear();
}
private static IEnumerable<Canvas> FindUiCanvases()
{
Canvas[] array = Object.FindObjectsByType<Canvas>((FindObjectsSortMode)0);
Canvas[] array2 = array;
foreach (Canvas val in array2)
{
if (!((Object)(object)val == (Object)null) && val.isRootCanvas && !((Object)val).name.StartsWith("Peak4KScreenshot_", StringComparison.Ordinal))
{
yield return val;
}
}
}
public static void DumpDiagnostics()
{
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
Canvas[] array = Object.FindObjectsByType<Canvas>((FindObjectsSortMode)0);
Log.Info(Lang.Get($"Scene canvas count: {array.Length}", $"场景 Canvas 总数: {array.Length}"));
Canvas[] array2 = array;
foreach (Canvas val in array2)
{
if (!((Object)(object)val == (Object)null))
{
string arg = (((Object)(object)((Component)val).GetComponent<CanvasScaler>() != (Object)null) ? Lang.Get("hasScaler", "有Scaler") : Lang.Get("noScaler", "无Scaler"));
string arg2 = (((Object)(object)val.worldCamera != (Object)null) ? ((Object)val.worldCamera).name : "null");
string text = $" '{((Object)val).name}' mode={val.renderMode} root={val.isRootCanvas} ";
string text2 = $"enabled={((Behaviour)val).enabled} active={((Component)val).gameObject.activeInHierarchy} ";
string text3 = $"layer={((Component)val).gameObject.layer} camera={arg2} {arg} ";
Rect pixelRect = val.pixelRect;
object arg3 = ((Rect)(ref pixelRect)).width;
pixelRect = val.pixelRect;
Log.Info(text + text2 + text3 + $"size={arg3}x{((Rect)(ref pixelRect)).height}");
}
}
}
}
public enum UiLanguage
{
Chinese,
English
}
public static class Lang
{
public static UiLanguage Current { get; private set; } = UiLanguage.English;
public static void Init()
{
Current = Detect();
}
private static UiLanguage Detect()
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Invalid comparison between Unknown and I4
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Invalid comparison between Unknown and I4
try
{
Type type = Type.GetType("LocalizedText, Assembly-CSharp");
if (type != null)
{
FieldInfo field = type.GetField("CURRENT_LANGUAGE", BindingFlags.Static | BindingFlags.Public);
if (field != null)
{
object value = field.GetValue(null);
if (value != null)
{
string text = value.ToString();
if (text == "SimplifiedChinese" || text == "TraditionalChinese")
{
return UiLanguage.Chinese;
}
return UiLanguage.English;
}
}
}
}
catch (Exception)
{
}
SystemLanguage systemLanguage = Application.systemLanguage;
if ((int)systemLanguage != 40 && (int)systemLanguage != 41)
{
return UiLanguage.English;
}
return UiLanguage.Chinese;
}
public static string Get(string en, string zh)
{
if (Current != UiLanguage.Chinese)
{
return en;
}
return zh;
}
}
public static class Log
{
public const string Prefix = "[Peak4KScreenshot] ";
private static ManualLogSource _source;
public static void Init(ManualLogSource source)
{
_source = source;
}
public static void Info(string message)
{
if (_source != null)
{
_source.LogInfo((object)("[Peak4KScreenshot] " + message));
}
else
{
Debug.Log((object)("[Peak4KScreenshot] " + message));
}
}
public static void Error(string message)
{
if (_source != null)
{
_source.LogError((object)("[Peak4KScreenshot] " + message));
}
else
{
Debug.LogError((object)("[Peak4KScreenshot] " + message));
}
}
public static void Warning(string message)
{
if (_source != null)
{
_source.LogWarning((object)("[Peak4KScreenshot] " + message));
}
else
{
Debug.LogWarning((object)("[Peak4KScreenshot] " + message));
}
}
}
public static class NotificationFont
{
private static TMP_FontAsset _font;
private static bool _searched;
private static Font _osFont;
private static bool _osFontSearched;
public static TMP_FontAsset Get()
{
if ((Object)(object)_font != (Object)null)
{
return _font;
}
if (_searched)
{
return null;
}
_searched = true;
try
{
Type type = Type.GetType("FontFallbackSwapper, Assembly-CSharp");
if (type != null)
{
object obj = type.GetField("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
if (obj != null)
{
object? obj2 = type.GetField("mainBaseFont", BindingFlags.Instance | BindingFlags.Public)?.GetValue(obj);
_font = (TMP_FontAsset)((obj2 is TMP_FontAsset) ? obj2 : null);
}
}
}
catch (Exception)
{
}
if ((Object)(object)_font == (Object)null)
{
try
{
TextMeshProUGUI[] array = Object.FindObjectsByType<TextMeshProUGUI>((FindObjectsSortMode)0);
foreach (TextMeshProUGUI val in array)
{
if ((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)null)
{
_font = ((TMP_Text)val).font;
break;
}
}
}
catch (Exception)
{
}
}
return _font;
}
public static Font GetSystemFont()
{
if ((Object)(object)_osFont != (Object)null)
{
return _osFont;
}
if (_osFontSearched)
{
return null;
}
_osFontSearched = true;
string[] array = new string[11]
{
"Microsoft YaHei UI", "Microsoft YaHei", "SimHei", "SimSun", "DengXian", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "WenQuanYi Micro Hei", "Source Han Sans SC",
"Arial Unicode MS"
};
string[] array2 = array;
foreach (string text in array2)
{
try
{
Font val = Font.CreateDynamicFontFromOSFont(text, 24);
if ((Object)(object)val != (Object)null)
{
_osFont = val;
break;
}
}
catch (Exception)
{
}
}
if ((Object)(object)_osFont == (Object)null)
{
try
{
_osFont = Font.CreateDynamicFontFromOSFont(array, 24);
}
catch (Exception)
{
}
}
return _osFont;
}
}
[BepInPlugin("peak4k.screenshot", "Peak4K Screenshot", "1.6.1")]
public class Peak4KScreenshotPlugin : BaseUnityPlugin
{
public const string Guid = "peak4k.screenshot";
private ConfigEntry<CaptureResolution> _resolution;
private ConfigEntry<KeyCode> _hotkey;
private ConfigEntry<bool> _hideHud;
private ConfigEntry<int> _superSample;
private ConfigEntry<string> _outputFolder;
private ConfigEntry<bool> _showNotification;
private ConfigEntry<bool> _openFolderAfterSave;
private ConfigEntry<OrientationFix> _orientation;
private ConfigEntry<UiScaleMode> _uiScale;
private ConfigEntry<bool> _boostQuality;
private ConfigEntry<KeyCode> _openFolderKey;
private bool _capturing;
private float _notificationTimer;
private string _notificationText;
private bool _notificationIsError;
private int _lastHotkeyFrame = -1;
private TextMeshProUGUI _tmpText;
private Canvas _notificationCanvas;
private void Awake()
{
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_0240: Unknown result type (might be due to invalid IL or missing references)
//IL_030c: Unknown result type (might be due to invalid IL or missing references)
//IL_0311: Unknown result type (might be due to invalid IL or missing references)
Log.Init(((BaseUnityPlugin)this).Logger);
Lang.Init();
UnityMainThreadDispatcher.Initialize();
_resolution = ((BaseUnityPlugin)this).Config.Bind<CaptureResolution>("Capture", "Resolution", CaptureResolution.UHD_4K, Lang.Get("Screenshot resolution. UHD_4K=3840x2160, QHD_2K=2560x1440, DCI_4K=4096x2160, UHD_8K=7680x4320, Native=current game resolution", "截图分辨率。UHD_4K=3840x2160,QHD_2K=2560x1440,DCI_4K=4096x2160,UHD_8K=7680x4320,Native=跟随游戏当前分辨率"));
_hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Capture", "Hotkey", (KeyCode)285, Lang.Get("Screenshot hotkey. Default: F4", "截图热键。默认 F4"));
_hideHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Capture", "HideHud", true, Lang.Get("Hide the HUD while capturing (health bar, crosshair, name tags, etc.)", "截图时隐藏 HUD(血条、准星、名字等)"));
_superSample = ((BaseUnityPlugin)this).Config.Bind<int>("Capture", "SuperSample", 1, Lang.Get("Supersampling factor. 1=render at target resolution (recommended); 2=render at 2x then downscale (sharper edges, slower)", "超采样倍数。1=按目标分辨率直接渲染(推荐);2=2 倍分辨率渲染后缩放,边缘更干净但更耗时"));
_outputFolder = ((BaseUnityPlugin)this).Config.Bind<string>("Capture", "OutputFolder", "Screenshots", Lang.Get("Output folder name, relative to the game root. An absolute path is also accepted", "截图输出文件夹名(相对于游戏根目录)。填绝对路径则使用绝对路径"));
_showNotification = ((BaseUnityPlugin)this).Config.Bind<bool>("Capture", "ShowNotification", true, Lang.Get("Show an on-screen notification after a capture", "截图完成后在屏幕左下角显示提示"));
_openFolderAfterSave = ((BaseUnityPlugin)this).Config.Bind<bool>("Capture", "OpenFolderAfterSave", false, Lang.Get("Open the output folder after saving", "截图完成后打开输出文件夹"));
_uiScale = ((BaseUnityPlugin)this).Config.Bind<UiScaleMode>("Capture", "UiScaleMode", UiScaleMode.Auto, Lang.Get("UI scaling used when keeping the HUD in the capture. Auto=leave scaling untouched (PEAK's HUD uses a relative layout, so this is correct); MatchScreen=scale the UI by render width / screen width (for fixed-pixel layouts)", "截图保留 UI 时的缩放处理。Auto=不动缩放(PEAK 的 HUD 是相对布局,默认用这个);MatchScreen=按 渲染宽/屏幕宽 放大 UI(UI 是固定像素布局时用)"));
_boostQuality = ((BaseUnityPlugin)this).Config.Bind<bool>("Capture", "BoostQuality", false, Lang.Get("Temporarily raise every graphics setting (shadow distance, texture quality, world quality, render scale, ambient occlusion) to its highest level for the moment the capture is taken, then restore the original values. Note: this makes the capture noticeably slower and more GPU intensive.", "截图的那一瞬间,自动把所有图像相关选项(阴影距离、纹理质量、世界质量、渲染比例、环境光遮蔽)临时提升到最高档,截图结束后自动恢复原值。注意:开启后截图会明显变慢、GPU 占用变高。"));
_openFolderKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Capture", "OpenFolderKey", (KeyCode)293, Lang.Get("Hotkey that opens the folder where the screenshots are saved. Default: F12", "打开截图保存文件夹的快捷键。默认 F12"));
_orientation = ((BaseUnityPlugin)this).Config.Bind<OrientationFix>("Capture", "OrientationFix", OrientationFix.None, Lang.Get("Orientation correction. None=no correction (correct by default); FlipVertical=flip top/bottom; FlipHorizontal=mirror left/right; Rotate180=rotate 180 degrees. Try another value if the capture looks upside down.", "方向修正。None=不修正(默认正确);FlipVertical=上下翻转;FlipHorizontal=左右镜像;Rotate180=旋转180度。如果截图方向看着不对,换一个试试即可"));
((BaseUnityPlugin)this).Logger.LogInfo((object)Lang.Get("Loaded. Resolution preset: " + _resolution.Value.ToString() + ", hotkey: " + ((object)_hotkey.Value/*cast due to .constrained prefix*/).ToString() + ", orientation fix: " + _orientation.Value.ToString() + ", UI scale mode: " + _uiScale.Value.ToString() + ", screen resolution: " + Screen.width + "x" + Screen.height, "已加载。当前分辨率预设:" + _resolution.Value.ToString() + ",热键:" + ((object)_hotkey.Value/*cast due to .constrained prefix*/).ToString() + ",方向修正:" + _orientation.Value.ToString() + ",UI缩放模式:" + _uiScale.Value.ToString() + ",屏幕分辨率:" + Screen.width + "x" + Screen.height));
((MonoBehaviour)this).StartCoroutine(DelayedDiagnostics());
}
private IEnumerator DelayedDiagnostics()
{
for (int i = 0; i < 60; i++)
{
yield return null;
}
HudController.DumpDiagnostics();
}
private void Update()
{
UnityMainThreadDispatcher.Pump();
HandleUtilityKeys();
if (IsHotkeyPressed())
{
TryCapture();
}
if (_notificationTimer > 0f)
{
_notificationTimer -= Time.unscaledDeltaTime;
}
}
private void HandleUtilityKeys()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (!_capturing && IsKeyDown(_openFolderKey.Value))
{
OpenOutputFolder();
}
}
private static bool IsKeyDown(KeyCode key)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
bool flag = false;
try
{
Keyboard current = Keyboard.current;
if (current != null)
{
KeyControl keyControl = GetKeyControl(current, key);
if (keyControl != null && ((ButtonControl)keyControl).wasPressedThisFrame)
{
flag = true;
}
}
}
catch (Exception)
{
}
if (!flag)
{
try
{
flag = Input.GetKeyDown(key);
}
catch (Exception)
{
}
}
return flag;
}
private bool IsHotkeyPressed()
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
if (Time.frameCount == _lastHotkeyFrame)
{
return false;
}
bool flag = false;
try
{
Keyboard current = Keyboard.current;
if (current != null)
{
KeyControl keyControl = GetKeyControl(current, _hotkey.Value);
if (keyControl != null && ((ButtonControl)keyControl).wasPressedThisFrame)
{
flag = true;
}
}
}
catch (Exception)
{
}
if (!flag)
{
try
{
flag = Input.GetKeyDown(_hotkey.Value);
}
catch (Exception)
{
}
}
if (flag)
{
_lastHotkeyFrame = Time.frameCount;
}
return flag;
}
private static KeyControl GetKeyControl(Keyboard keyboard, KeyCode key)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Invalid comparison between Unknown and I4
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Invalid comparison between Unknown and I4
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Expected I4, but got Unknown
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected I4, but got Unknown
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Invalid comparison between Unknown and I4
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Expected I4, but got Unknown
if ((int)key <= 101)
{
switch (key - 48)
{
case 0:
return keyboard.digit0Key;
case 1:
return keyboard.digit1Key;
case 2:
return keyboard.digit2Key;
case 3:
return keyboard.digit3Key;
case 4:
return keyboard.digit4Key;
case 5:
return keyboard.digit5Key;
case 6:
return keyboard.digit6Key;
case 7:
return keyboard.digit7Key;
case 8:
return keyboard.digit8Key;
case 9:
return keyboard.digit9Key;
}
if ((int)key == 101)
{
return keyboard.eKey;
}
}
else
{
if ((int)key == 105)
{
return keyboard.iKey;
}
switch (key - 111)
{
default:
switch (key - 282)
{
case 0:
return keyboard.f1Key;
case 1:
return keyboard.f2Key;
case 2:
return keyboard.f3Key;
case 3:
return keyboard.f4Key;
case 4:
return keyboard.f5Key;
case 5:
return keyboard.f6Key;
case 6:
return keyboard.f7Key;
case 7:
return keyboard.f8Key;
case 8:
return keyboard.f9Key;
case 9:
return keyboard.f10Key;
case 10:
return keyboard.f11Key;
case 11:
return keyboard.f12Key;
}
break;
case 1:
return keyboard.pKey;
case 0:
return keyboard.oKey;
case 6:
return keyboard.uKey;
case 10:
return keyboard.yKey;
case 5:
return keyboard.tKey;
case 3:
return keyboard.rKey;
case 2:
case 4:
case 7:
case 8:
case 9:
break;
}
}
return null;
}
private void TryCapture()
{
if (_capturing)
{
ShowNotification(Lang.Get("The previous capture is still in progress, please wait…", "上一次截图还没完成,请稍候…"), isError: true);
return;
}
if (!ResolveTargetResolution(out var width, out var height))
{
ShowNotification(Lang.Get("Could not determine the target resolution", "无法确定目标分辨率"), isError: true);
return;
}
int superSample = Mathf.Clamp(_superSample.Value, 1, 3);
string outputPath = BuildOutputPath();
_capturing = true;
string arg = (_boostQuality.Value ? Lang.Get(" · max quality", " · 最高画质") : "");
ShowNotification(Lang.Get($"Rendering {width}x{height} capture{arg}…", $"正在渲染 {width}x{height} 4K 截图{arg}…"), isError: false);
CaptureRequest request = new CaptureRequest(width, height, superSample, _hideHud.Value, outputPath, _orientation.Value, _uiScale.Value, _boostQuality.Value);
((MonoBehaviour)this).StartCoroutine(HighResCapture.CaptureRoutine(request, delegate(CaptureResult result)
{
_capturing = false;
if (!result.Success)
{
ShowNotification(Lang.Get("Capture failed: " + result.Error, "截图失败:" + result.Error), isError: true);
}
else
{
string text = (_boostQuality.Value ? Lang.Get(" · max quality", " · 最高画质") : "");
ShowNotification(Lang.Get($"Saved {result.Width}x{result.Height}{text}: {Path.GetFileName(result.FilePath)}", $"已保存 {result.Width}x{result.Height}{text}:{Path.GetFileName(result.FilePath)}"), isError: false);
if (_openFolderAfterSave.Value)
{
TryOpenFolder(Path.GetDirectoryName(result.FilePath));
}
}
}));
}
private bool ResolveTargetResolution(out int width, out int height)
{
switch (_resolution.Value)
{
case CaptureResolution.UHD_4K:
width = 3840;
height = 2160;
return true;
case CaptureResolution.QHD_2K:
width = 2560;
height = 1440;
return true;
case CaptureResolution.DCI_4K:
width = 4096;
height = 2160;
return true;
case CaptureResolution.UHD_8K:
width = 7680;
height = 4320;
return true;
case CaptureResolution.Native:
width = Screen.width;
height = Screen.height;
if (width > 0)
{
return height > 0;
}
return false;
default:
width = 3840;
height = 2160;
return true;
}
}
private string BuildOutputPath()
{
string outputDirectory = GetOutputDirectory();
string text = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
return Path.Combine(outputDirectory, "PEAK-4K-" + text);
}
private void ShowNotification(string text, bool isError)
{
_notificationText = text;
_notificationIsError = isError;
_notificationTimer = (isError ? 5f : 3.5f);
if ((Object)(object)_tmpText != (Object)null)
{
((TMP_Text)_tmpText).text = string.Empty;
((Component)_tmpText).gameObject.SetActive(false);
}
}
private void OpenOutputFolder()
{
try
{
string outputDirectory = GetOutputDirectory();
if (!Directory.Exists(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
Process.Start("explorer.exe", "\"" + outputDirectory + "\"");
ShowNotification(Lang.Get("Opened the screenshots folder", "已打开截图文件夹"), isError: false);
}
catch (Exception ex)
{
ShowNotification(Lang.Get("Could not open the folder: " + ex.Message, "无法打开文件夹:" + ex.Message), isError: true);
}
}
private string GetOutputDirectory()
{
string text = _outputFolder.Value;
if (string.IsNullOrWhiteSpace(text))
{
text = "Screenshots";
}
if (Path.IsPathRooted(text))
{
return text;
}
return Path.Combine(Path.GetDirectoryName(Application.dataPath) ?? ".", text);
}
private static void TryOpenFolder(string path)
{
if (string.IsNullOrEmpty(path) || !Directory.Exists(path))
{
return;
}
try
{
Process.Start("explorer.exe", "\"" + path + "\"");
}
catch (Exception)
{
}
}
private void OnGUI()
{
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Expected O, but got Unknown
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Expected O, but got Unknown
//IL_0110: 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_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01b9: Expected O, but got Unknown
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: 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_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Expected O, but got Unknown
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
//IL_0207: Expected O, but got Unknown
//IL_0207: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Unknown result type (might be due to invalid IL or missing references)
//IL_0226: Unknown result type (might be due to invalid IL or missing references)
if (_notificationTimer <= 0f || string.IsNullOrEmpty(_notificationText))
{
HideTmpText();
return;
}
float num = Mathf.Clamp01((_notificationTimer < 0.5f) ? (_notificationTimer / 0.5f) : 1f);
Rect val = default(Rect);
((Rect)(ref val))..ctor(28f, (float)Screen.height - 92f, 900f, 46f);
GUIStyle val2 = new GUIStyle(GUI.skin.box);
Color color = GUI.color;
GUI.color = new Color(0f, 0f, 0f, 0.55f * num);
GUI.Box(new Rect(((Rect)(ref val)).x - 14f, ((Rect)(ref val)).y - 8f, ((Rect)(ref val)).width + 28f, ((Rect)(ref val)).height + 16f), GUIContent.none, val2);
GUI.color = color;
Font systemFont = NotificationFont.GetSystemFont();
if ((Object)(object)systemFont != (Object)null)
{
GUIContent val3 = new GUIContent(_notificationText);
GUIStyle val4 = new GUIStyle(GUI.skin.label)
{
font = systemFont,
fontSize = 22,
alignment = (TextAnchor)3
};
val4.normal.textColor = (Color)(_notificationIsError ? new Color(1f, 0.55f, 0.55f) : Color.white);
GUIStyle val5 = val4;
Color color2 = GUI.color;
GUI.color = new Color(1f, 1f, 1f, num);
GUI.Label(val, val3, val5);
GUI.color = color2;
HideTmpText();
return;
}
TMP_FontAsset val6 = NotificationFont.Get();
if ((Object)(object)val6 != (Object)null)
{
DrawTmpText(val, val6, num);
return;
}
GUIContent val7 = new GUIContent(_notificationText);
GUIStyle val8 = new GUIStyle(GUI.skin.label)
{
fontSize = 22,
alignment = (TextAnchor)3
};
val8.normal.textColor = (Color)(_notificationIsError ? new Color(1f, 0.55f, 0.55f) : Color.white);
GUIStyle val9 = val8;
Color color3 = GUI.color;
GUI.color = new Color(1f, 1f, 1f, num);
GUI.Label(val, val7, val9);
GUI.color = color3;
HideTmpText();
}
private void HideTmpText()
{
if ((Object)(object)_tmpText != (Object)null && ((Component)_tmpText).gameObject.activeSelf)
{
((Component)_tmpText).gameObject.SetActive(false);
}
}
private void DrawTmpText(Rect area, TMP_FontAsset font, float alpha)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Expected O, but got Unknown
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: 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_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
//IL_01de: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_tmpText == (Object)null)
{
GameObject val = new GameObject("Peak4KScreenshot_NotificationCanvas");
Object.DontDestroyOnLoad((Object)(object)val);
_notificationCanvas = val.AddComponent<Canvas>();
_notificationCanvas.renderMode = (RenderMode)0;
_notificationCanvas.sortingOrder = 32000;
GameObject val2 = new GameObject("Peak4KScreenshot_NotificationText");
val2.transform.SetParent(val.transform, false);
_tmpText = val2.AddComponent<TextMeshProUGUI>();
((Graphic)_tmpText).raycastTarget = false;
((TMP_Text)_tmpText).textWrappingMode = (TextWrappingModes)0;
((TMP_Text)_tmpText).overflowMode = (TextOverflowModes)0;
((TMP_Text)_tmpText).alignment = (TextAlignmentOptions)513;
}
if (!((Component)_tmpText).gameObject.activeSelf)
{
((Component)_tmpText).gameObject.SetActive(true);
}
string notificationText = _notificationText;
if (((TMP_Text)_tmpText).text != notificationText)
{
((TMP_Text)_tmpText).text = notificationText;
}
if ((Object)(object)((TMP_Text)_tmpText).font != (Object)(object)font)
{
((TMP_Text)_tmpText).font = font;
}
((TMP_Text)_tmpText).fontSize = 22f;
((Graphic)_tmpText).color = (_notificationIsError ? new Color(1f, 0.55f, 0.55f, alpha) : new Color(1f, 1f, 1f, alpha));
RectTransform rectTransform = ((TMP_Text)_tmpText).rectTransform;
rectTransform.anchorMin = new Vector2(0f, 0f);
rectTransform.anchorMax = new Vector2(0f, 0f);
rectTransform.pivot = new Vector2(0f, 0f);
rectTransform.anchoredPosition = new Vector2(((Rect)(ref area)).x, (float)Screen.height - ((Rect)(ref area)).y - ((Rect)(ref area)).height);
rectTransform.sizeDelta = new Vector2(((Rect)(ref area)).width, ((Rect)(ref area)).height);
}
}
public static class QualityBoost
{
public sealed class Restore : IDisposable
{
private readonly List<Action> _revertActions = new List<Action>();
private bool _disposed;
internal Restore(List<Action> revertActions)
{
_revertActions = revertActions;
}
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
for (int num = _revertActions.Count - 1; num >= 0; num--)
{
try
{
_revertActions[num]();
}
catch (Exception ex)
{
Log.Warning(Lang.Get("Failed to restore a quality setting: " + ex.Message, "恢复画质设置失败:" + ex.Message));
}
}
_revertActions.Clear();
}
}
public static Restore Apply()
{
List<Action> list = new List<Action>();
try
{
SettingsHandler instance = SettingsHandler.Instance;
if (instance == null)
{
Log.Warning(Lang.Get("SettingsHandler not found — cannot boost quality", "找不到 SettingsHandler,无法提升画质"));
return new Restore(list);
}
ShadowDistanceSettings setting = instance.GetSetting<ShadowDistanceSettings>();
if (setting != null)
{
BoostEnum<ShadowDistanceQuality>((EnumSetting<ShadowDistanceQuality>)(object)setting, (ShadowDistanceQuality)0, list);
}
TextureQualitySetting setting2 = instance.GetSetting<TextureQualitySetting>();
if (setting2 != null)
{
BoostEnum<TextureQuality>((EnumSetting<TextureQuality>)(object)setting2, (TextureQuality)0, list);
}
LodQuality setting3 = instance.GetSetting<LodQuality>();
if (setting3 != null)
{
BoostEnum<Quality>((EnumSetting<Quality>)(object)setting3, (Quality)2, list);
}
RenderScaleSetting setting4 = instance.GetSetting<RenderScaleSetting>();
if (setting4 != null)
{
BoostEnum<RenderScaleQuality>((EnumSetting<RenderScaleQuality>)(object)setting4, (RenderScaleQuality)0, list);
}
AOSetting setting5 = instance.GetSetting<AOSetting>();
if (setting5 != null)
{
BoostOffOn((OffOnSetting)(object)setting5, (OffOnMode)1, list);
}
Log.Info(Lang.Get($"Quality boosted for the capture ({list.Count} settings)", $"已为截图提升画质({list.Count} 项设置)"));
}
catch (Exception ex)
{
Log.Warning(Lang.Get("Failed to boost quality: " + ex.Message, "提升画质失败:" + ex.Message));
}
return new Restore(list);
}
private static void BoostEnum<T>(EnumSetting<T> setting, T best, List<Action> revertActions) where T : unmanaged, Enum
{
object value = GetValue((Setting)(object)setting);
if (value != null)
{
if (!object.Equals(value, best))
{
SetValue((Setting)(object)setting, best);
}
ApplyValueSafe((Setting)(object)setting);
object captured = value;
revertActions.Add(delegate
{
SetValue((Setting)(object)setting, captured);
ApplyValueSafe((Setting)(object)setting);
});
Log.Info(Lang.Get($" {((object)setting).GetType().Name}: {captured} → {best}", $" {((object)setting).GetType().Name}:{captured} → {best}"));
}
}
private static void BoostOffOn(OffOnSetting setting, OffOnMode best, List<Action> revertActions)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
object value = GetValue((Setting)(object)setting);
if (value != null)
{
if (!object.Equals(value, best))
{
SetValue((Setting)(object)setting, best);
}
ApplyValueSafe((Setting)(object)setting);
object captured = value;
revertActions.Add(delegate
{
SetValue((Setting)(object)setting, captured);
ApplyValueSafe((Setting)(object)setting);
});
Log.Info(Lang.Get($" {((object)setting).GetType().Name}: {captured} → {best}", $" {((object)setting).GetType().Name}:{captured} → {best}"));
}
}
private static object GetValue(Setting setting)
{
try
{
return ((object)setting).GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(setting);
}
catch (Exception)
{
return null;
}
}
private static void SetValue(Setting setting, object value)
{
(((object)setting).GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetSetMethod(nonPublic: true))?.Invoke(setting, new object[1] { value });
}
private static void ApplyValueSafe(Setting setting)
{
try
{
setting.ApplyValue();
}
catch (Exception ex)
{
Log.Warning(Lang.Get("ApplyValue failed for " + ((object)setting).GetType().Name + ": " + ex.Message, ((object)setting).GetType().Name + " 的 ApplyValue 失败:" + ex.Message));
}
}
}
public static class UnityMainThreadDispatcher
{
private static readonly ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>();
private static int _mainThreadId;
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
public static void Initialize()
{
_mainThreadId = GetCurrentThreadId();
}
public static void Enqueue(Action action)
{
if (action != null)
{
_queue.Enqueue(action);
}
}
public static void Pump()
{
if (GetCurrentThreadId() != _mainThreadId)
{
return;
}
Action result;
while (_queue.TryDequeue(out result))
{
try
{
result();
}
catch (Exception ex)
{
Debug.LogError((object)("[Peak4KScreenshot] " + Lang.Get("Main-thread callback threw an exception: " + ex, "主线程回调执行异常:" + ex)));
}
}
}
}
}