Decompiled source of FrozenRA v1.0.3

plugins/FrozenRA.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using FrozenRA.Core;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
using _K;
using ifapp.Game.Common;
using ifapp.Game.Data;
using ifapp.Game.Scenes;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyTitle("FrozenRA")]
[assembly: AssemblyCompany("SkyFrozen")]
[assembly: AssemblyCopyright("Copyright 2026 SkyFrozen and FrozenRA contributors")]
[assembly: SecurityPermission((SecurityAction)8, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : System.Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(/*Could not decode attribute arguments.*/)]
	internal sealed class RefSafetyRulesAttribute : System.Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[AttributeUsage(/*Could not decode attribute arguments.*/)]
	internal sealed class NullableAttribute : System.Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte value)
		{
			NullableFlags = new byte[1] { value };
		}

		public NullableAttribute(byte[] values)
		{
			NullableFlags = values;
		}
	}
	[AttributeUsage(/*Could not decode attribute arguments.*/)]
	internal sealed class NullableContextAttribute : System.Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte value)
		{
			Flag = value;
		}
	}
}
namespace FrozenRA
{
	public static class AppearanceConfigMigration
	{
		private sealed class PendingMigration
		{
			[field: CompilerGenerated]
			public int Version
			{
				[CompilerGenerated]
				get;
				[CompilerGenerated]
				set;
			} = 1;

			[field: CompilerGenerated]
			public string LegacyDirectory
			{
				[CompilerGenerated]
				get;
				[CompilerGenerated]
				set;
			}

			[field: CompilerGenerated]
			public string CanonicalThemeHash
			{
				[CompilerGenerated]
				get;
				[CompilerGenerated]
				set;
			}

			[field: CompilerGenerated]
			public bool Completed
			{
				[CompilerGenerated]
				get;
				[CompilerGenerated]
				set;
			}
		}

		private static string Hash(string file)
		{
			return Convert.ToHexString(SHA256.HashData(File.ReadAllBytes(file)));
		}

		public static void Apply()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: 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_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(AppearanceStore.Root, "appearance", "pending-editor-migration.json");
			if (!File.Exists(text))
			{
				return;
			}
			try
			{
				PendingMigration pendingMigration = JsonSerializer.Deserialize<PendingMigration>(File.ReadAllText(text), AppearanceStore.JsonOptions);
				if (pendingMigration == null || pendingMigration.Version != 1 || pendingMigration.Completed)
				{
					return;
				}
				string fullName = ((FileSystemInfo)Directory.GetParent(AppearanceStore.Root)).FullName;
				if (string.IsNullOrWhiteSpace(pendingMigration.LegacyDirectory) || Path.IsPathRooted(pendingMigration.LegacyDirectory))
				{
					throw new InvalidDataException("旧配置目录格式错误");
				}
				string fullPath = Path.GetFullPath(Path.Combine(fullName, pendingMigration.LegacyDirectory));
				if (!fullPath.StartsWith(fullName.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, (StringComparison)5) || string.Equals(fullPath, AppearanceStore.Root, (StringComparison)5))
				{
					throw new InvalidDataException("旧配置目录超出范围");
				}
				string text2 = Path.Combine(fullPath, "appearance", "theme.json");
				if (File.Exists(AppearanceStore.ThemePath) && File.Exists(text2) && string.Equals(Hash(AppearanceStore.ThemePath), pendingMigration.CanonicalThemeHash, (StringComparison)5) && !string.Equals(Hash(text2), pendingMigration.CanonicalThemeHash, (StringComparison)5))
				{
					AppearanceTheme appearanceTheme = JsonSerializer.Deserialize<AppearanceTheme>(File.ReadAllText(AppearanceStore.ThemePath), AppearanceStore.JsonOptions);
					AppearanceTheme appearanceTheme2 = JsonSerializer.Deserialize<AppearanceTheme>(File.ReadAllText(text2), AppearanceStore.JsonOptions);
					appearanceTheme2.ExportDirectory = appearanceTheme.ExportDirectory;
					AppearanceStore.Validate(appearanceTheme2);
					List<AppearanceResource> obj = new List<AppearanceResource>((System.Collections.Generic.IEnumerable<AppearanceResource>)appearanceTheme2.Images.Values);
					obj.AddRange((System.Collections.Generic.IEnumerable<AppearanceResource>)appearanceTheme2.Fonts.Values);
					HashSet<string> val = new HashSet<string>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase);
					Enumerator<AppearanceResource> enumerator = obj.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							AppearanceResource current = enumerator.Current;
							string[] array = new string[2] { current.File, current.OriginalFile };
							foreach (string text3 in array)
							{
								if (!string.IsNullOrWhiteSpace(text3))
								{
									val.Add(text3);
								}
							}
						}
					}
					finally
					{
						((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
					Enumerator<string> enumerator2 = val.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							string current2 = enumerator2.Current;
							string text4 = AppearanceStore.SafePath(current2);
							string fullPath2 = Path.GetFullPath(Path.Combine(fullPath, current2.Replace('/', Path.DirectorySeparatorChar)));
							if (!fullPath2.StartsWith(fullPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, (StringComparison)5))
							{
								throw new InvalidDataException("旧资源路径超出范围");
							}
							if (!File.Exists(text4))
							{
								if (!File.Exists(fullPath2))
								{
									throw new FileNotFoundException("旧外观资源不存在", fullPath2);
								}
								Directory.CreateDirectory(Path.GetDirectoryName(text4));
								File.Copy(fullPath2, text4);
							}
						}
					}
					finally
					{
						((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
					}
					string root = AppearanceStore.Root;
					DateTimeOffset now = DateTimeOffset.Now;
					string text5 = Path.Combine(root, "backups", ((DateTimeOffset)(ref now)).ToString("yyyyMMdd-HHmmss") + "-editor-migration");
					Directory.CreateDirectory(text5);
					File.Copy(AppearanceStore.ThemePath, Path.Combine(text5, "theme.json"), true);
					AppearanceStore.Save(appearanceTheme2);
					Plugin.Logger.LogInfo((object)"[Appearance] 已迁移兼容面板中保存的外观设置");
				}
				pendingMigration.Completed = true;
				string text6 = text + ".tmp";
				File.WriteAllText(text6, JsonSerializer.Serialize<PendingMigration>(pendingMigration, AppearanceStore.JsonOptions));
				File.Move(text6, text, true);
			}
			catch (System.Exception ex)
			{
				Plugin.Logger.LogWarning((object)("[Appearance] 兼容外观迁移未完成,保留现有设置:" + ex.Message));
			}
		}
	}
	public static class AppearanceHost
	{
		private delegate bool WindowVisitor(System.IntPtr window, System.IntPtr parameter);

		private sealed class RatingSnapshot
		{
			public readonly string Name;

			public readonly string Delta;

			public readonly double Rating;

			public readonly List<ChartRating> Charts;

			public RatingSnapshot()
			{
				lock (Plugin.RatingDataGate)
				{
					Name = Plugin.PlayerName;
					Rating = Plugin.PlayerRating;
					Delta = (Plugin.HasRatingDelta ? Plugin.RatingDeltaText : "");
					Charts = Plugin.ChartRatings ?? new List<ChartRating>();
				}
			}
		}

		private sealed class Request
		{
			public string Method;

			public string Path;

			public Dictionary<string, string> Headers = new Dictionary<string, string>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase);

			public byte[] Body;
		}

		private static readonly object Gate = new object();

		private static readonly object StartGate = new object();

		private static readonly object B30FileGate = new object();

		private static readonly object OverlayFileGate = new object();

		private static readonly object PreviewFileGate = new object();

		private static readonly object RecordsExportGate = new object();

		private static System.IntPtr _editorWindow;

		private static int _editorOpening;

		private static readonly JsonSerializerOptions NetworkJsonOptions = new JsonSerializerOptions(AppearanceStore.JsonOptions)
		{
			WriteIndented = false
		};

		private static TcpListener _listener;

		private static volatile bool _running;

		private static int _port;

		private static readonly string Token = Convert.ToHexString(RandomNumberGenerator.GetBytes(24));

		public static int Port => _port;

		public static string EditorUrl => "http://127.0.0.1:" + _port + "/?key=" + Token;

		[DllImport("user32.dll")]
		private static extern bool IsWindow(System.IntPtr window);

		[DllImport("user32.dll")]
		private static extern bool IsIconic(System.IntPtr window);

		[DllImport("user32.dll")]
		private static extern bool EnumWindows(WindowVisitor visitor, System.IntPtr parameter);

		[DllImport("user32.dll", CharSet = (CharSet)3)]
		private static extern int GetWindowTextW(System.IntPtr window, StringBuilder text, int length);

		[DllImport("user32.dll")]
		private static extern bool ShowWindow(System.IntPtr window, int command);

		[DllImport("user32.dll")]
		private static extern bool SetForegroundWindow(System.IntPtr window);

		public static void OpenEditor()
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			try
			{
				Start();
				if (_editorWindow != System.IntPtr.Zero && IsWindow(_editorWindow))
				{
					ShowWindow(_editorWindow, IsIconic(_editorWindow) ? 9 : 5);
					SetForegroundWindow(_editorWindow);
				}
				else if (Interlocked.CompareExchange(ref _editorOpening, 1, 0) == 0)
				{
					HashSet<System.IntPtr> val = EditorWindows();
					string text = Path.Combine(new string[5]
					{
						Environment.GetFolderPath((SpecialFolder)42),
						"Microsoft",
						"Edge",
						"Application",
						"msedge.exe"
					});
					if (File.Exists(text))
					{
						ProcessStartInfo val2 = new ProcessStartInfo(text)
						{
							UseShellExecute = false
						};
						val2.ArgumentList.Add("--app=" + EditorUrl);
						Process.Start(val2);
					}
					else
					{
						Process.Start(new ProcessStartInfo(EditorUrl)
						{
							UseShellExecute = true
						});
					}
					ThreadPool.QueueUserWorkItem(new WaitCallback(TrackEditorWindow), (object)val);
					Plugin.Logger.LogInfo((object)"[Appearance] 外观编辑器已打开,保存后立即刷新游戏显示");
				}
			}
			catch (System.Exception ex)
			{
				Interlocked.Exchange(ref _editorOpening, 0);
				Plugin.Logger.LogError((object)("[Appearance] 编辑器启动失败: " + ex.Message));
			}
		}

		private static HashSet<System.IntPtr> EditorWindows()
		{
			HashSet<System.IntPtr> windows = new HashSet<System.IntPtr>();
			EnumWindows(delegate(System.IntPtr window, System.IntPtr parameter)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Expected O, but got Unknown
				StringBuilder val = new StringBuilder(160);
				GetWindowTextW(window, val, val.Capacity);
				if (((object)val).ToString().StartsWith("FrozenRA 外观编辑器", (StringComparison)4))
				{
					windows.Add(window);
				}
				return true;
			}, System.IntPtr.Zero);
			return windows;
		}

		private static void TrackEditorWindow(object state)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				HashSet<System.IntPtr> val = (HashSet<System.IntPtr>)state;
				for (int i = 0; i < 100; i++)
				{
					Enumerator<System.IntPtr> enumerator = EditorWindows().GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							System.IntPtr current = enumerator.Current;
							if (!val.Contains(current))
							{
								_editorWindow = current;
								return;
							}
						}
					}
					finally
					{
						((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
					Thread.Sleep(50);
				}
			}
			finally
			{
				Interlocked.Exchange(ref _editorOpening, 0);
			}
		}

		public static void Start()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			lock (StartGate)
			{
				if (_listener != null)
				{
					return;
				}
				for (int i = 53187; i < 53197; i++)
				{
					try
					{
						TcpListener val = new TcpListener(IPAddress.Loopback, i);
						val.Start();
						_listener = val;
						_port = i;
					}
					catch (SocketException)
					{
						continue;
					}
					break;
				}
				if (_listener == null)
				{
					throw new IOException("本地编辑器端口暂时不可用");
				}
				_running = true;
				TcpListener activeListener = _listener;
				new Thread((ThreadStart)delegate
				{
					//IL_0016: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Expected O, but got Unknown
					while (_running && _listener == activeListener)
					{
						try
						{
							TcpClient val2 = activeListener.AcceptTcpClient();
							ThreadPool.QueueUserWorkItem(new WaitCallback(HandleClient), (object)val2);
						}
						catch (System.Exception ex2)
						{
							if (!_running || _listener != activeListener)
							{
								break;
							}
							Plugin.Logger.LogWarning((object)("[Appearance] 编辑器连接: " + ex2.Message));
							Thread.Sleep(500);
						}
					}
				})
				{
					IsBackground = true,
					Name = "FrozenRA Appearance Editor"
				}.Start();
				Plugin.Logger.LogInfo((object)"[Appearance] F5 打开外观编辑器 · F6 显示/隐藏 · F7 导出 B30 到所选文件夹");
			}
		}

		private static void HandleClient(object state)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			Handle((TcpClient)state);
		}

		public static void Stop()
		{
			lock (StartGate)
			{
				_running = false;
				TcpListener listener = _listener;
				if (listener != null)
				{
					listener.Stop();
				}
				_listener = null;
			}
		}

		private static Request ReadRequest(Stream stream)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			List<byte> val = new List<byte>();
			int num;
			while ((num = stream.ReadByte()) >= 0)
			{
				val.Add((byte)num);
				if (val.Count > 16384)
				{
					throw new InvalidDataException("请求头过长");
				}
				int count = val.Count;
				if (count >= 4 && val[count - 4] == 13 && val[count - 3] == 10 && val[count - 2] == 13 && val[count - 1] == 10)
				{
					break;
				}
			}
			string[] array = Encoding.ASCII.GetString(val.ToArray()).Split("\r\n", (StringSplitOptions)0);
			string[] array2 = array[0].Split(' ', (StringSplitOptions)0);
			if (array2.Length < 2)
			{
				throw new InvalidDataException("请求格式错误");
			}
			Request request = new Request
			{
				Method = array2[0],
				Path = array2[1]
			};
			System.Collections.Generic.IEnumerator<string> enumerator = Enumerable.Skip<string>((System.Collections.Generic.IEnumerable<string>)array, 1).GetEnumerator();
			try
			{
				while (((System.Collections.IEnumerator)enumerator).MoveNext())
				{
					string current = enumerator.Current;
					int num2 = current.IndexOf(':');
					if (num2 > 0)
					{
						Dictionary<string, string> headers = request.Headers;
						string text = current.Substring(0, num2).Trim();
						string text2 = current;
						int num3 = num2 + 1;
						headers[text] = text2.Substring(num3, text2.Length - num3).Trim();
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator)?.Dispose();
			}
			string text3 = default(string);
			int num4 = (request.Headers.TryGetValue("Content-Length", ref text3) ? int.Parse(text3) : 0);
			if (num4 < 0 || num4 > 67108864)
			{
				throw new InvalidDataException("图片数据过大");
			}
			request.Body = new byte[num4];
			int num5;
			for (int i = 0; i < num4; i += num5)
			{
				num5 = stream.Read(request.Body, i, num4 - i);
				if (num5 == 0)
				{
					throw new EndOfStreamException();
				}
			}
			return request;
		}

		private static void Respond(NetworkStream stream, int code, string type, byte[] bytes)
		{
			string text = code switch
			{
				404 => "Not Found", 
				403 => "Forbidden", 
				200 => "OK", 
				_ => "Bad Request", 
			};
			byte[] bytes2 = Encoding.ASCII.GetBytes($"HTTP/1.1 {code} {text}\r\nContent-Type: {type}\r\nContent-Length: {bytes.Length}\r\nCache-Control: no-store\r\nX-Content-Type-Options: nosniff\r\nConnection: close\r\n\r\n");
			((Stream)stream).Write(System.ReadOnlySpan<byte>.op_Implicit(bytes2));
			((Stream)stream).Write(System.ReadOnlySpan<byte>.op_Implicit(bytes));
		}

		private static void RespondFile(NetworkStream stream, string type, string file, bool cache = false)
		{
			FileStream val = File.OpenRead(file);
			try
			{
				string text = (cache ? "private, max-age=3600" : "no-store");
				byte[] bytes = Encoding.ASCII.GetBytes($"HTTP/1.1 200 OK\r\nContent-Type: {type}\r\nContent-Length: {((Stream)val).Length}\r\nCache-Control: {text}\r\nX-Content-Type-Options: nosniff\r\nConnection: close\r\n\r\n");
				((Stream)stream).Write(System.ReadOnlySpan<byte>.op_Implicit(bytes));
				((Stream)val).CopyTo((Stream)(object)stream, 65536);
			}
			finally
			{
				((System.IDisposable)val)?.Dispose();
			}
		}

		private static void Json(NetworkStream stream, object value)
		{
			Respond(stream, 200, "application/json; charset=utf-8", JsonSerializer.SerializeToUtf8Bytes<object>(value, NetworkJsonOptions));
		}

		private static string String(JsonElement root, string key, string fallback = null)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			JsonElement val = default(JsonElement);
			if (!((JsonElement)(ref root)).TryGetProperty(key, ref val) || (int)((JsonElement)(ref val)).ValueKind != 3)
			{
				return fallback;
			}
			return ((JsonElement)(ref val)).GetString();
		}

		private static string Query(string query, string key, string fallback)
		{
			string[] array = query.Split('&', (StringSplitOptions)0);
			foreach (string text in array)
			{
				if (text.StartsWith(key + "=", (StringComparison)4))
				{
					string text2 = text;
					int num = key.Length + 1;
					return Uri.UnescapeDataString(text2.Substring(num, text2.Length - num));
				}
			}
			return fallback;
		}

		private static AppearanceTheme ThemeSnapshot()
		{
			lock (Gate)
			{
				return JsonSerializer.Deserialize<AppearanceTheme>(System.ReadOnlySpan<byte>.op_Implicit(JsonSerializer.SerializeToUtf8Bytes<AppearanceTheme>(AppearanceStore.Current, NetworkJsonOptions)), AppearanceStore.JsonOptions);
			}
		}

		public static string EditorDocument()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			Stream manifestResourceStream = typeof(AppearanceHost).Assembly.GetManifestResourceStream("FrozenRA.Editor.html.gz");
			try
			{
				if (manifestResourceStream != null)
				{
					GZipStream val = new GZipStream(manifestResourceStream, (CompressionMode)0);
					try
					{
						StreamReader val2 = new StreamReader((Stream)(object)val, Encoding.UTF8);
						try
						{
							return ((TextReader)val2).ReadToEnd();
						}
						finally
						{
							((System.IDisposable)val2)?.Dispose();
						}
					}
					finally
					{
						((System.IDisposable)val)?.Dispose();
					}
				}
				return File.ReadAllText(Path.Combine(Path.GetDirectoryName(typeof(AppearanceHost).Assembly.Location), "FrozenRAEditor.html"));
			}
			finally
			{
				((System.IDisposable)manifestResourceStream)?.Dispose();
			}
		}

		private unsafe static void Handle(TcpClient client)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0591: Unknown result type (might be due to invalid IL or missing references)
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0627: Unknown result type (might be due to invalid IL or missing references)
			//IL_062e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0634: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0701: Unknown result type (might be due to invalid IL or missing references)
			//IL_0708: Unknown result type (might be due to invalid IL or missing references)
			//IL_070e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0853: Unknown result type (might be due to invalid IL or missing references)
			//IL_085a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0860: Unknown result type (might be due to invalid IL or missing references)
			//IL_0719: Unknown result type (might be due to invalid IL or missing references)
			//IL_071e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0674: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_0490: Unknown result type (might be due to invalid IL or missing references)
			//IL_086b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0870: Unknown result type (might be due to invalid IL or missing references)
			//IL_0753: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cf2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cf9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cff: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_08cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a9a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a9f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aa3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aa8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0795: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d4d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d52: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d5b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d60: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d7c: Unknown result type (might be due to invalid IL or missing references)
			//IL_092f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0935: Invalid comparison between Unknown and I4
			//IL_07d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0dfd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ab1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ab6: Unknown result type (might be due to invalid IL or missing references)
			//IL_093a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0af0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b17: Unknown result type (might be due to invalid IL or missing references)
			//IL_097a: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c09: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a2b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a60: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				client.ReceiveTimeout = 20000;
				client.SendTimeout = 20000;
				NetworkStream stream = client.GetStream();
				BufferedStream val = new BufferedStream((Stream)(object)stream, 8192);
				try
				{
					Request request = ReadRequest((Stream)(object)val);
					Uri val2 = new Uri("http://127.0.0.1:" + _port + request.Path);
					string text = Uri.UnescapeDataString(val2.AbsolutePath);
					string text2 = val2.Query.TrimStart('?');
					string text3 = default(string);
					if ((!request.Headers.TryGetValue("X-InFalsus-Key", ref text3) || !(text3 == Token)) && !Enumerable.Any<string>((System.Collections.Generic.IEnumerable<string>)text2.Split('&', (StringSplitOptions)0), (Func<string, bool>)((string part) => part == "key=" + Token)))
					{
						Respond(stream, 403, "text/plain", Encoding.UTF8.GetBytes("请从游戏内按 " + AppearanceStore.Current.Hotkeys.Editor + " 打开编辑器 / Open the editor from the game"));
						return;
					}
					string text4 = default(string);
					if (request.Headers.TryGetValue("Origin", ref text4) && text4 != "http://127.0.0.1:" + _port)
					{
						throw new InvalidDataException("请求来源不匹配");
					}
					if ((text == "/api/records-preview.png" || text == "/api/records-export" || text == "/api/export" || text == "/api/b30-preview.png" || text == "/api/overlay.png" || text == "/api/b30.png") ? true : false)
					{
						PresentationState.WaitForIdle();
					}
					if (request.Method == "GET" && text == "/")
					{
						string text5 = EditorDocument().Replace("<!--IF_HOST-->", "<script>window.IF_HOST=" + JsonSerializer.Serialize(new
						{
							key = Token,
							port = _port
						}, (JsonSerializerOptions)null) + ";</script>");
						Respond(stream, 200, "text/html; charset=utf-8", Encoding.UTF8.GetBytes(text5));
						return;
					}
					if (request.Method == "GET" && text == "/api/state")
					{
						RatingSnapshot ratingSnapshot = new RatingSnapshot();
						System.Collections.Generic.IEnumerable<ChartRating> enumerable = Enumerable.Take<ChartRating>((System.Collections.Generic.IEnumerable<ChartRating>)ratingSnapshot.Charts, 39);
						Json(stream, new
						{
							gameplay = PresentationState.Gameplay,
							theme = AppearanceStore.Current,
							exportDirectory = B30ExportFiles.ResolveDirectory(AppearanceStore.Current.ExportDirectory),
							defaultExportDirectory = B30ExportFiles.DefaultDirectory,
							rating = ratingSnapshot.Rating,
							ratingDisplay = RatingDeltaEffect.FormatRating(ratingSnapshot.Rating),
							delta = ratingSnapshot.Delta,
							name = ratingSnapshot.Name,
							charts = Enumerable.Select(enumerable, (ChartRating c, int i) => new
							{
								rank = i + 1,
								songId = c.SongId,
								title = SongInfoCache.GetName(c.SongId),
								artist = SongInfoCache.GetArtist(c.SongId),
								baseName = SongInfoCache.GetBaseName(c.SongId),
								rating = c.Rating,
								score = c.Score,
								difficulty = c.Difficulty,
								difficultyColor = ChartBadge.DifficultyColor(c.Difficulty),
								constant = c.Constant,
								dive = c.PaceValue,
								grade = ChartBadge.Grade(c.Score),
								clear = ChartBadge.Clear(c),
								isFC = c.IsFC,
								isPM = c.IsPM
							})
						});
						return;
					}
					if (request.Method == "GET" && text == "/api/records")
					{
						RatingSnapshot ratingSnapshot2 = new RatingSnapshot();
						AppearanceTheme appearanceTheme = ThemeSnapshot();
						CompletionView view = CompletionRecords.Create(Query(text2, "level", "10.8"), ratingSnapshot2.Charts, appearanceTheme, appearanceTheme.State.Name, ratingSnapshot2.Rating, Query(text2, "pack", ""), Query(text2, "difficulty", "all"));
						Json(stream, new
						{
							view = view,
							appearanceGeneration = AppearanceStore.Generation,
							exportDirectory = B30ExportFiles.ResolveDirectory(appearanceTheme.ExportDirectory)
						});
						return;
					}
					if (request.Method == "POST" && (text == "/api/records-preview.png" || text == "/api/records-export"))
					{
						JsonDocument val3 = JsonDocument.Parse(ReadOnlyMemory<byte>.op_Implicit(request.Body), default(JsonDocumentOptions));
						try
						{
							string selected = CompletionRecords.NormalizeLevel(String(val3.RootElement, "level", "10.8"));
							RatingSnapshot ratingSnapshot3 = new RatingSnapshot();
							AppearanceTheme appearanceTheme2 = ThemeSnapshot();
							CompletionView completionView = CompletionRecords.Create(selected, ratingSnapshot3.Charts, appearanceTheme2, appearanceTheme2.State.Name, ratingSnapshot3.Rating, String(val3.RootElement, "pack", ""), String(val3.RootElement, "difficulty", "all"));
							if (text == "/api/records-preview.png")
							{
								string file = Path.Combine(AppearanceStore.Root, "appearance", "preview-records.png");
								lock (PreviewFileGate)
								{
									if (!AppearanceRenderer.CompletionTable(file, completionView, appearanceTheme2, preview: true))
									{
										throw new IOException("完成表预览生成失败");
									}
									RespondFile(stream, "image/png", file);
									return;
								}
							}
							string text6 = B30ExportFiles.ResolveDirectory(appearanceTheme2.ExportDirectory);
							Directory.CreateDirectory(text6);
							string text7;
							lock (RecordsExportGate)
							{
								text7 = CompletionRecords.NewExportPath(completionView, text6);
								if (!AppearanceRenderer.CompletionTable(text7, completionView, appearanceTheme2, preview: false))
								{
									throw new IOException("完成表导出失败");
								}
							}
							Plugin.Logger.LogInfo((object)("[Records] 已导出 " + text7));
							Json(stream, new
							{
								ok = true,
								file = text7,
								level = completionView.Level,
								pack = completionView.PackId,
								difficulty = completionView.Difficulty,
								counts = completionView.Counts
							});
							return;
						}
						finally
						{
							((System.IDisposable)val3)?.Dispose();
						}
					}
					if (request.Method == "POST" && text == "/api/export-directory/browse")
					{
						JsonDocument val4 = JsonDocument.Parse(ReadOnlyMemory<byte>.op_Implicit(request.Body), default(JsonDocumentOptions));
						try
						{
							string text8 = ExportFolderPicker.Browse(B30ExportFiles.ResolveDirectory(String(val4.RootElement, "directory", AppearanceStore.Current.ExportDirectory)));
							Json(stream, new
							{
								cancelled = (text8 == null),
								directory = text8
							});
							return;
						}
						finally
						{
							((System.IDisposable)val4)?.Dispose();
						}
					}
					if (request.Method == "POST" && text == "/api/export-directory")
					{
						JsonDocument val5 = JsonDocument.Parse(ReadOnlyMemory<byte>.op_Implicit(request.Body), default(JsonDocumentOptions));
						try
						{
							lock (Gate)
							{
								AppearanceTheme appearanceTheme3 = JsonSerializer.Deserialize<AppearanceTheme>(System.ReadOnlySpan<byte>.op_Implicit(JsonSerializer.SerializeToUtf8Bytes<AppearanceTheme>(AppearanceStore.Current, NetworkJsonOptions)), AppearanceStore.JsonOptions);
								appearanceTheme3.ExportDirectory = B30ExportFiles.NormalizeDirectory(String(val5.RootElement, "directory", ""));
								AppearanceStore.Save(appearanceTheme3);
								Json(stream, new
								{
									ok = true,
									exportDirectory = B30ExportFiles.ResolveDirectory(appearanceTheme3.ExportDirectory),
									defaultExportDirectory = B30ExportFiles.DefaultDirectory
								});
								return;
							}
						}
						finally
						{
							((System.IDisposable)val5)?.Dispose();
						}
					}
					if (request.Method == "POST" && text == "/api/preferences")
					{
						JsonDocument val6 = JsonDocument.Parse(ReadOnlyMemory<byte>.op_Implicit(request.Body), default(JsonDocumentOptions));
						try
						{
							JsonElement rootElement = val6.RootElement;
							lock (Gate)
							{
								AppearanceTheme appearanceTheme4 = JsonSerializer.Deserialize<AppearanceTheme>(System.ReadOnlySpan<byte>.op_Implicit(JsonSerializer.SerializeToUtf8Bytes<AppearanceTheme>(AppearanceStore.Current, NetworkJsonOptions)), AppearanceStore.JsonOptions);
								string text9 = String(rootElement, "interfaceLanguage", appearanceTheme4.InterfaceLanguage);
								if ((!(text9 == "zh") && !(text9 == "ja")) || 1 == 0)
								{
									throw new InvalidDataException("请选择中文或日本語");
								}
								appearanceTheme4.InterfaceLanguage = text9;
								JsonElement val7 = default(JsonElement);
								if (((JsonElement)(ref rootElement)).TryGetProperty("hotkeys", ref val7))
								{
									appearanceTheme4.Hotkeys = JsonSerializer.Deserialize<HotkeySettings>(((JsonElement)(ref val7)).GetRawText(), AppearanceStore.JsonOptions) ?? throw new InvalidDataException("缺少快捷键设置");
								}
								HotkeyBinding.Validate(appearanceTheme4.Hotkeys);
								AppearanceStore.Save(appearanceTheme4);
								Json(stream, new
								{
									ok = true,
									interfaceLanguage = appearanceTheme4.InterfaceLanguage,
									hotkeys = appearanceTheme4.Hotkeys
								});
								return;
							}
						}
						finally
						{
							((System.IDisposable)val6)?.Dispose();
						}
					}
					JsonElement val9;
					if (request.Method == "POST" && text == "/api/theme")
					{
						JsonDocument val8 = JsonDocument.Parse(ReadOnlyMemory<byte>.op_Implicit(request.Body), default(JsonDocumentOptions));
						try
						{
							JsonElement rootElement2 = val8.RootElement;
							lock (Gate)
							{
								AppearanceTheme appearanceTheme5 = JsonSerializer.Deserialize<AppearanceTheme>(System.ReadOnlySpan<byte>.op_Implicit(JsonSerializer.SerializeToUtf8Bytes<AppearanceTheme>(AppearanceStore.Current, NetworkJsonOptions)), AppearanceStore.JsonOptions);
								val9 = ((JsonElement)(ref rootElement2)).GetProperty("state");
								appearanceTheme5.State = JsonSerializer.Deserialize<AppearanceState>(((JsonElement)(ref val9)).GetRawText(), AppearanceStore.JsonOptions);
								appearanceTheme5.Preset = String(rootElement2, "preset", "poster");
								JsonElement val10 = default(JsonElement);
								string[] array;
								if (((JsonElement)(ref rootElement2)).TryGetProperty("resources", ref val10))
								{
									array = new string[2] { "art", "bg" };
									JsonElement root = default(JsonElement);
									AppearanceResource appearanceResource = default(AppearanceResource);
									JsonElement val11 = default(JsonElement);
									foreach (string text10 in array)
									{
										if (!((JsonElement)(ref val10)).TryGetProperty(text10, ref root) || (int)((JsonElement)(ref root)).ValueKind != 1)
										{
											continue;
										}
										string text11 = String(root, "id");
										if (!string.IsNullOrWhiteSpace(text11) && (!appearanceTheme5.Images.TryGetValue(text10, ref appearanceResource) || !(appearanceResource.Id == text11)))
										{
											string text12 = String(root, "src");
											if (text12 == null || !text12.StartsWith("data:"))
											{
												throw new InvalidDataException("图片尚未导入,请重新选择文件");
											}
											string text13 = SaveData(text12, "image", text10);
											string text14 = String(root, "originalSrc", text12);
											string originalFile = (text14.StartsWith("data:") ? SaveData(text14, "image", text10 + "-original") : (appearanceResource?.OriginalFile ?? text13));
											appearanceTheme5.Images[text10] = new AppearanceResource
											{
												Id = text11,
												File = text13,
												OriginalFile = originalFile,
												Name = String(root, "name", "已导入图片"),
												Crop = (((JsonElement)(ref root)).TryGetProperty("crop", ref val11) ? new JsonElement?(((JsonElement)(ref val11)).Clone()) : ((JsonElement?)null))
											};
										}
									}
								}
								JsonElement val12 = default(JsonElement);
								if (((JsonElement)(ref rootElement2)).TryGetProperty("fonts", ref val12))
								{
									ObjectEnumerator val13 = ((JsonElement)(ref val12)).EnumerateObject();
									ObjectEnumerator enumerator = ((ObjectEnumerator)(ref val13)).GetEnumerator();
									try
									{
										while (((ObjectEnumerator)(ref enumerator)).MoveNext())
										{
											JsonProperty current = ((ObjectEnumerator)(ref enumerator)).Current;
											if (!appearanceTheme5.Fonts.ContainsKey(((JsonProperty)(ref current)).Name))
											{
												appearanceTheme5.Fonts[((JsonProperty)(ref current)).Name] = new AppearanceResource
												{
													Id = ((JsonProperty)(ref current)).Name,
													File = SaveData(String(((JsonProperty)(ref current)).Value, "src"), "font", "font"),
													Name = String(((JsonProperty)(ref current)).Value, "name", "自定义字体")
												};
											}
										}
									}
									finally
									{
										((System.IDisposable)(*(ObjectEnumerator*)(&enumerator))/*cast due to .constrained prefix*/).Dispose();
									}
								}
								array = new string[2] { "art", "bg" };
								AppearanceResource appearanceResource2 = default(AppearanceResource);
								string text16 = default(string);
								foreach (string text15 in array)
								{
									if (((text15 == "art") ? appearanceTheme5.State.Art : appearanceTheme5.State.Bg) == "custom" && (!appearanceTheme5.Images.TryGetValue(text15, ref appearanceResource2) || !appearanceTheme5.State.ImageIds.TryGetValue(text15, ref text16) || appearanceResource2.Id != text16))
									{
										throw new InvalidDataException("请重新导入" + ((text15 == "art") ? "人物图片" : "背景图片"));
									}
								}
								AppearanceStore.Save(appearanceTheme5);
								Plugin.PlayerName = appearanceTheme5.State.Name;
								File.WriteAllText(Path.Combine(AppearanceStore.Root, "name.txt"), Plugin.PlayerName);
							}
							Plugin.Logger.LogInfo((object)"[Appearance] 外观已保存并应用");
							Json(stream, new
							{
								ok = true,
								theme = AppearanceStore.Current
							});
							return;
						}
						finally
						{
							((System.IDisposable)val8)?.Dispose();
						}
					}
					if (request.Method == "POST" && text == "/api/export")
					{
						Plugin.ExportB30Image();
						Json(stream, new
						{
							ok = true
						});
						return;
					}
					if (request.Method == "POST" && text == "/api/b30-preview.png")
					{
						JsonDocument val14 = JsonDocument.Parse(ReadOnlyMemory<byte>.op_Implicit(request.Body), default(JsonDocumentOptions));
						try
						{
							AppearanceTheme appearanceTheme6;
							lock (Gate)
							{
								appearanceTheme6 = JsonSerializer.Deserialize<AppearanceTheme>(System.ReadOnlySpan<byte>.op_Implicit(JsonSerializer.SerializeToUtf8Bytes<AppearanceTheme>(AppearanceStore.Current, NetworkJsonOptions)), AppearanceStore.JsonOptions);
							}
							val9 = val14.RootElement;
							val9 = ((JsonElement)(ref val9)).GetProperty("state");
							appearanceTheme6.State = JsonSerializer.Deserialize<AppearanceState>(((JsonElement)(ref val9)).GetRawText(), AppearanceStore.JsonOptions);
							appearanceTheme6.Preset = String(val14.RootElement, "preset", appearanceTheme6.Preset);
							AppearanceStore.Validate(appearanceTheme6);
							RatingSnapshot ratingSnapshot4 = new RatingSnapshot();
							string file2 = Path.Combine(AppearanceStore.Root, "appearance", "preview-b30-fast.png");
							lock (PreviewFileGate)
							{
								if (!AppearanceRenderer.PreviewB30(file2, appearanceTheme6.State.Name, ratingSnapshot4.Rating, ratingSnapshot4.Charts, appearanceTheme6))
								{
									throw new IOException("B30 预览生成失败");
								}
								RespondFile(stream, "image/png", file2);
								return;
							}
						}
						finally
						{
							((System.IDisposable)val14)?.Dispose();
						}
					}
					if (request.Method == "GET" && (text == "/api/overlay.png" || text == "/api/b30.png"))
					{
						string file3 = Path.Combine(AppearanceStore.Root, "appearance", text.EndsWith("overlay.png") ? "preview-overlay.png" : "preview-b30.png");
						lock (text.EndsWith("overlay.png") ? OverlayFileGate : B30FileGate)
						{
							RatingSnapshot ratingSnapshot5 = new RatingSnapshot();
							if (text.EndsWith("overlay.png"))
							{
								AppearanceRenderer.SaveOverlay(file3, AppearanceStore.Current.State.Name, RatingDeltaEffect.FormatRating(ratingSnapshot5.Rating), Enumerable.Contains<string>((System.Collections.Generic.IEnumerable<string>)text2.Split('&', (StringSplitOptions)0), "deltaPreview=1") ? "+0.020" : ratingSnapshot5.Delta);
							}
							else
							{
								AppearanceRenderer.ExportB30(file3, AppearanceStore.Current.State.Name, ratingSnapshot5.Rating, ratingSnapshot5.Charts, AppearanceStore.Current.State.B30Jackets);
							}
							RespondFile(stream, "image/png", file3);
							return;
						}
					}
					if (request.Method == "GET" && text.StartsWith("/assets/"))
					{
						string text17 = text;
						string text18 = AppearanceStore.SafePath(text17.Substring(8, text17.Length - 8));
						string text19 = Path.GetExtension(text18).ToLowerInvariant();
						if (text19 == ".png")
						{
							text17 = "image/png";
						}
						else
						{
							string text20;
							if ((text19 == ".jpg" || text19 == ".jpeg") ? true : false)
							{
								text20 = "image/jpeg";
							}
							else
							{
								string text21;
								if (text19 == ".webp")
								{
									text21 = "image/webp";
								}
								else
								{
									bool flag = ((text19 == ".ttf" || text19 == ".otf") ? true : false);
									text21 = (flag ? "font/ttf" : null);
								}
								text20 = text21;
							}
							text17 = text20;
						}
						string text22 = text17;
						if (text22 == null || !File.Exists(text18))
						{
							Respond(stream, 404, "text/plain", System.Array.Empty<byte>());
						}
						else
						{
							RespondFile(stream, text22, text18, cache: true);
						}
					}
					else
					{
						Respond(stream, 404, "text/plain", System.Array.Empty<byte>());
					}
				}
				catch (System.Exception ex)
				{
					Plugin.Logger.LogWarning((object)("[Appearance] 编辑器请求失败: " + ex.Message));
					try
					{
						Respond(stream, 400, "application/json; charset=utf-8", Encoding.UTF8.GetBytes(JsonSerializer.Serialize(new
						{
							error = ex.Message
						}, (JsonSerializerOptions)null)));
					}
					catch
					{
					}
				}
				finally
				{
					((System.IDisposable)val)?.Dispose();
				}
			}
			finally
			{
				((System.IDisposable)client)?.Dispose();
			}
		}

		private static string SaveData(string data, string kind, string label)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: 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)
			if (string.IsNullOrEmpty(data) || !data.StartsWith("data:"))
			{
				throw new InvalidDataException("文件数据缺失");
			}
			int num = data.IndexOf(',');
			if (num < 0 || !data.Substring(0, num).Contains(";base64"))
			{
				throw new InvalidDataException("文件编码无效");
			}
			System.ReadOnlySpan<char> readOnlySpan = MemoryExtensions.AsSpan(data, num + 1);
			byte[] array;
			int num2 = default(int);
			string text2;
			bool num3;
			checked
			{
				array = new byte[unchecked(checked(readOnlySpan.Length + 3) / 4) * 3];
				if (!Convert.TryFromBase64Chars(readOnlySpan, System.Span<byte>.op_Implicit(array), ref num2))
				{
					throw new FormatException("Invalid Base64 data");
				}
				if (num2 == 0 || num2 > 41943040)
				{
					throw new InvalidDataException("文件大小无效");
				}
				if (kind == "font")
				{
					bool flag = num2 < 4;
					if (!flag)
					{
						bool flag2 = array[0] == 0 && array[1] == 1 && array[2] == 0 && array[3] == 0;
						if (!flag2)
						{
							string text = Encoding.ASCII.GetString(array, 0, 4);
							bool flag3 = ((text == "OTTO" || text == "ttcf") ? true : false);
							flag2 = flag3;
						}
						flag = !flag2;
					}
					if (flag)
					{
						throw new InvalidDataException("请选择有效的 TTF / OTF 字体");
					}
					text2 = ((Encoding.ASCII.GetString(array, 0, 4) == "OTTO") ? ".otf" : ".ttf");
					goto IL_024d;
				}
				string text3 = data.Substring(0, num);
				text2 = (text3.Contains("image/png") ? ".png" : (text3.Contains("image/jpeg") ? ".jpg" : (text3.Contains("image/webp") ? ".webp" : null)));
				if (text2 == null)
				{
					throw new InvalidDataException("请选择 PNG / JPG / WebP 图片");
				}
				if (!(text2 == ".png"))
				{
					if (!(text2 == ".jpg"))
					{
						if (num2 > 12 && Encoding.ASCII.GetString(array, 0, 4) == "RIFF")
						{
							num3 = Encoding.ASCII.GetString(array, 8, 4) == "WEBP";
							goto IL_0240;
						}
					}
					else if (num2 > 3 && array[0] == 255)
					{
						num3 = array[1] == 216;
						goto IL_0240;
					}
				}
				else if (num2 > 8 && array[0] == 137 && array[1] == 80 && array[2] == 78)
				{
					num3 = array[3] == 71;
					goto IL_0240;
				}
				goto IL_0242;
			}
			IL_0242:
			throw new InvalidDataException("图片内容与格式不匹配");
			IL_0240:
			if (!num3)
			{
				goto IL_0242;
			}
			goto IL_024d;
			IL_024d:
			System.Span<byte> span = MemoryExtensions.AsSpan<byte>(array, 0, num2);
			string text4 = Convert.ToHexString(SHA256.HashData(System.Span<byte>.op_Implicit(span))).Substring(0, 20).ToLowerInvariant();
			string text5 = string.Concat(new string[5] { "appearance/assets/", label, "-", text4, text2 });
			string text6 = AppearanceStore.SafePath(text5);
			if (!File.Exists(text6))
			{
				FileStream val = File.Create(text6);
				try
				{
					((Stream)val).Write(System.Span<byte>.op_Implicit(span));
				}
				finally
				{
					((System.IDisposable)val)?.Dispose();
				}
			}
			return text5;
		}
	}
	public sealed class AppearanceLayer
	{
		[field: CompilerGenerated]
		public double X
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public double Y
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public double Scale
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 100.0;

		[field: CompilerGenerated]
		public double Opacity
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 100.0;

		[field: CompilerGenerated]
		public bool Visible
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		public bool Mirror
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public string Font
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "geometric";

		[field: CompilerGenerated]
		public string Color
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "#F1EDF9";

		[field: CompilerGenerated]
		public double FontSize
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}
	}
	public sealed class AppearanceCanvas
	{
		[field: CompilerGenerated]
		public int Width
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public int Height
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public int Columns
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 5;

		[field: CompilerGenerated]
		public int Gap
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 18;

		[field: CompilerGenerated]
		public string Anchor
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "top-center";

		[field: CompilerGenerated]
		public int ScreenX
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public int ScreenY
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 24;

		[field: CompilerGenerated]
		public double PanelScale
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 100.0;

		[field: CompilerGenerated]
		public bool PreserveFontSize
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		public double TextScale
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 100.0;

		[field: CompilerGenerated]
		public string OverlayStyle
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "infalsus";

		[field: CompilerGenerated]
		public bool IncludeInGameScreenshots
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public string CardFont
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "geometric";

		[field: CompilerGenerated]
		public string CardColor
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "#F1EDF9";

		[field: CompilerGenerated]
		public double CardScale
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 100.0;

		[field: CompilerGenerated]
		public bool JacketGrades
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		public bool JacketClearStates
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		public double JacketGlow
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 70.0;

		[field: CompilerGenerated]
		public double HeaderHeight
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 17.0;

		[field: CompilerGenerated]
		public string BackgroundStyle
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "existing";

		[field: CompilerGenerated]
		public double ArtistScale
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 125.0;

		[field: CompilerGenerated]
		public double DifficultyScale
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 125.0;

		[field: CompilerGenerated]
		public double ScoreScale
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 118.0;

		[field: CompilerGenerated]
		public string B30Style
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "infalsus";

		[field: CompilerGenerated]
		public bool ShowOverflow
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		public bool ExportTimestamp
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;
	}
	public sealed class AppearanceB30Layout
	{
		[field: CompilerGenerated]
		public Dictionary<string, AppearanceLayer> Layers
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, AppearanceLayer>();

		[field: CompilerGenerated]
		public AppearanceCanvas Canvas
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new AppearanceCanvas();
	}
	public sealed class AppearanceState
	{
		[field: CompilerGenerated]
		public bool B30Jackets
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = true;

		[field: CompilerGenerated]
		public int B30LayoutRevision
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public string Mode
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "overlay";

		[field: CompilerGenerated]
		public string Selected
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "art";

		[field: CompilerGenerated]
		public string Accent
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "#8979DC";

		[field: CompilerGenerated]
		public bool Outline
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public string Art
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "mirinae";

		[field: CompilerGenerated]
		public string Bg
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "gradient";

		[field: CompilerGenerated]
		public string Name
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "Player";

		[field: CompilerGenerated]
		public string TitleLanguage
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "ja";

		[field: CompilerGenerated]
		public Dictionary<string, AppearanceB30Layout> B30Layouts
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, AppearanceB30Layout>();

		[field: CompilerGenerated]
		public Dictionary<string, AppearanceLayer> Overlay
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = DefaultLayers(b30: false);

		[field: CompilerGenerated]
		public Dictionary<string, AppearanceLayer> B30
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = DefaultLayers(b30: true);

		[field: CompilerGenerated]
		public Dictionary<string, string> ImageIds
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, string>
		{
			["art"] = null,
			["bg"] = null
		};

		[field: CompilerGenerated]
		public Dictionary<string, AppearanceCanvas> Canvas
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, AppearanceCanvas>
		{
			["overlay"] = new AppearanceCanvas
			{
				Width = 420,
				Height = 88
			},
			["b30"] = DefaultB30Canvas()
		};

		public static AppearanceCanvas DefaultB30Canvas()
		{
			return new AppearanceCanvas
			{
				Width = 1800,
				Height = 3240,
				Columns = 3,
				Gap = 44,
				HeaderHeight = 8.0,
				B30Style = "arc",
				BackgroundStyle = "infalsus",
				CardColor = "#F1F3FF"
			};
		}

		public static Dictionary<string, AppearanceLayer> DefaultLayers(bool b30)
		{
			return new Dictionary<string, AppearanceLayer>
			{
				["bg"] = new AppearanceLayer
				{
					X = 50.0,
					Y = 50.0
				},
				["art"] = new AppearanceLayer
				{
					X = (b30 ? 3 : 81),
					Y = (b30 ? 6 : 0)
				},
				["name"] = new AppearanceLayer
				{
					X = (b30 ? 18 : 4),
					Y = (b30 ? 17 : 9),
					FontSize = (b30 ? 72 : 24)
				},
				["rating"] = new AppearanceLayer
				{
					X = (b30 ? 68 : 44),
					Y = 9.0,
					FontSize = (b30 ? 48 : 38),
					Font = (b30 ? "geometric" : "oxanium")
				},
				["delta"] = new AppearanceLayer
				{
					X = (b30 ? 6 : 44),
					Y = (b30 ? 70 : 69),
					FontSize = ((!b30) ? 16 : 0),
					Color = "#9BFFD1",
					Visible = !b30,
					Font = "oxanium"
				}
			};
		}
	}
	public sealed class AppearanceResource
	{
		[field: CompilerGenerated]
		public string Id
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public string File
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public string OriginalFile
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public string Name
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}

		[field: CompilerGenerated]
		public JsonElement? Crop
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		}
	}
	public sealed class AppearanceTheme
	{
		[field: CompilerGenerated]
		public int Version
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = 1;

		[field: CompilerGenerated]
		public string Preset
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "poster";

		[field: CompilerGenerated]
		public string ExportDirectory
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "";

		[field: CompilerGenerated]
		public string InterfaceLanguage
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = "zh";

		[field: CompilerGenerated]
		public HotkeySettings Hotkeys
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new HotkeySettings();

		[field: CompilerGenerated]
		public AppearanceState State
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new AppearanceState();

		[field: CompilerGenerated]
		public Dictionary<string, AppearanceResource> Images
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, AppearanceResource>();

		[field: CompilerGenerated]
		public Dictionary<string, AppearanceResource> Fonts
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			set;
		} = new Dictionary<string, AppearanceResource>();
	}
	public static class AppearanceStore
	{
		public static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
		{
			PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
			PropertyNameCaseInsensitive = true,
			WriteIndented = true
		};

		private static int _generation;

		private static readonly object Gate = new object();

		private static System.DateTime _lastWrite;

		[field: CompilerGenerated]
		public static string Root
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			private set;
		}

		public static string ThemePath => Path.Combine(Root, "appearance", "theme.json");

		[field: CompilerGenerated]
		public static AppearanceTheme Current
		{
			[CompilerGenerated]
			get;
			[CompilerGenerated]
			private set;
		} = new AppearanceTheme();

		public static int Generation => Volatile.Read(ref _generation);

		public static ValueTuple<AppearanceTheme, int> Snapshot()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			lock (Gate)
			{
				return new ValueTuple<AppearanceTheme, int>(Current, _generation);
			}
		}

		public static void Initialize(string root)
		{
			Root = Path.GetFullPath(root);
			Directory.CreateDirectory(Path.Combine(Root, "appearance", "assets"));
			AppearanceConfigMigration.Apply();
			if (!File.Exists(ThemePath))
			{
				Save(new AppearanceTheme());
			}
			else
			{
				Reload();
			}
		}

		public static string SafePath(string relative)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(relative))
			{
				return null;
			}
			if (Path.IsPathRooted(relative))
			{
				throw new InvalidDataException("资源路径必须位于当前模组配置目录");
			}
			string fullPath = Path.GetFullPath(Path.Combine(Root, relative.Replace('/', Path.DirectorySeparatorChar)));
			if (!fullPath.StartsWith(Root.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, (StringComparison)5))
			{
				throw new InvalidDataException("资源路径超出模组配置目录");
			}
			return fullPath;
		}

		public static void Validate(AppearanceTheme theme)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0760: Unknown result type (might be due to invalid IL or missing references)
			//IL_0765: Unknown result type (might be due to invalid IL or missing references)
			//IL_0776: Unknown result type (might be due to invalid IL or missing references)
			//IL_077b: Unknown result type (might be due to invalid IL or missing references)
			//IL_078c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0791: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0867: Unknown result type (might be due to invalid IL or missing references)
			//IL_086c: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b7: Unknown result type (might be due to invalid IL or missing references)
			if (theme == null || theme.Version != 1 || theme.State == null)
			{
				throw new InvalidDataException("外观配置格式错误");
			}
			theme.ExportDirectory = B30ExportFiles.NormalizeDirectory(theme.ExportDirectory);
			theme.InterfaceLanguage = ((theme.InterfaceLanguage == "ja") ? "ja" : "zh");
			AppearanceTheme appearanceTheme = theme;
			if (appearanceTheme.Hotkeys == null)
			{
				HotkeySettings hotkeySettings = (appearanceTheme.Hotkeys = new HotkeySettings());
			}
			HotkeyBinding.Validate(theme.Hotkeys);
			AppearanceState state = theme.State;
			UpgradeDefaultB30Layout(state);
			state.TitleLanguage = ((state.TitleLanguage == "en") ? "en" : "ja");
			if (!SupportedLayer(state.Selected))
			{
				state.Selected = "rating";
			}
			state.Name = (string.IsNullOrWhiteSpace(state.Name) ? "Player" : state.Name.Substring(0, Math.Min(state.Name.Length, 48)));
			string[] array = new string[2] { "overlay", "b30" };
			AppearanceLayer appearanceLayer = default(AppearanceLayer);
			AppearanceCanvas appearanceCanvas = default(AppearanceCanvas);
			AppearanceState appearanceState;
			foreach (string text in array)
			{
				Dictionary<string, AppearanceLayer> val = AppearanceState.DefaultLayers(text == "b30");
				Dictionary<string, AppearanceLayer> val2 = ((text == "overlay") ? state.Overlay : state.B30);
				if (val2 == null)
				{
					val2 = val;
				}
				RemoveUnsupportedLayers(val2);
				Enumerator<string, AppearanceLayer> enumerator = val.Keys.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						string current = enumerator.Current;
						if (!val2.TryGetValue(current, ref appearanceLayer) || appearanceLayer == null)
						{
							appearanceLayer = (val2[current] = val[current]);
						}
						appearanceLayer.X = Math.Clamp(double.IsFinite(appearanceLayer.X) ? appearanceLayer.X : 0.0, 0.0, 100.0);
						appearanceLayer.Y = Math.Clamp(double.IsFinite(appearanceLayer.Y) ? appearanceLayer.Y : 0.0, 0.0, 100.0);
						appearanceLayer.Scale = Math.Clamp(double.IsFinite(appearanceLayer.Scale) ? appearanceLayer.Scale : 100.0, 10.0, 400.0);
						appearanceLayer.Opacity = Math.Clamp(double.IsFinite(appearanceLayer.Opacity) ? appearanceLayer.Opacity : 100.0, 0.0, 100.0);
						appearanceLayer.FontSize = Math.Clamp(double.IsFinite(appearanceLayer.FontSize) ? appearanceLayer.FontSize : 0.0, 0.0, 400.0);
					}
				}
				finally
				{
					((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
				if (text == "overlay")
				{
					state.Overlay = val2;
				}
				else
				{
					state.B30 = val2;
				}
				appearanceState = state;
				if (appearanceState.Canvas == null)
				{
					Dictionary<string, AppearanceCanvas> val3 = (appearanceState.Canvas = new Dictionary<string, AppearanceCanvas>());
				}
				if (!state.Canvas.TryGetValue(text, ref appearanceCanvas) || appearanceCanvas == null)
				{
					appearanceCanvas = (state.Canvas[text] = ((text == "overlay") ? new AppearanceCanvas
					{
						Width = 420,
						Height = 88
					} : AppearanceState.DefaultB30Canvas()));
				}
				appearanceCanvas.Width = Math.Clamp(appearanceCanvas.Width, (text == "overlay") ? 240 : 800, (text == "overlay") ? 2000 : 4096);
				appearanceCanvas.Height = Math.Clamp(appearanceCanvas.Height, (text == "overlay") ? 80 : 800, (text == "overlay") ? 700 : 4096);
				appearanceCanvas.PanelScale = Math.Clamp(appearanceCanvas.PanelScale, 25.0, 200.0);
				appearanceCanvas.TextScale = Math.Clamp(double.IsFinite(appearanceCanvas.TextScale) ? appearanceCanvas.TextScale : 100.0, 50.0, 200.0);
				appearanceCanvas.Columns = Math.Clamp(appearanceCanvas.Columns, 3, 6);
				appearanceCanvas.Gap = Math.Clamp(appearanceCanvas.Gap, 4, 60);
				appearanceCanvas.CardScale = Math.Clamp(appearanceCanvas.CardScale, 60.0, 140.0);
				appearanceCanvas.JacketGlow = Math.Clamp(double.IsFinite(appearanceCanvas.JacketGlow) ? appearanceCanvas.JacketGlow : 70.0, 0.0, 100.0);
				appearanceCanvas.B30Style = ((appearanceCanvas.B30Style == "arc") ? "arc" : "infalsus");
				appearanceCanvas.HeaderHeight = Math.Clamp(double.IsFinite(appearanceCanvas.HeaderHeight) ? appearanceCanvas.HeaderHeight : 17.0, (double)((appearanceCanvas.B30Style == "arc") ? 6 : 12), 30.0);
				appearanceCanvas.BackgroundStyle = ((appearanceCanvas.BackgroundStyle == "infalsus") ? "infalsus" : "existing");
				appearanceCanvas.OverlayStyle = ((appearanceCanvas.OverlayStyle == "existing") ? "existing" : "infalsus");
				appearanceCanvas.ArtistScale = Math.Clamp(double.IsFinite(appearanceCanvas.ArtistScale) ? appearanceCanvas.ArtistScale : 125.0, 75.0, 175.0);
				appearanceCanvas.DifficultyScale = Math.Clamp(double.IsFinite(appearanceCanvas.DifficultyScale) ? appearanceCanvas.DifficultyScale : 125.0, 75.0, 175.0);
				appearanceCanvas.ScoreScale = Math.Clamp(double.IsFinite(appearanceCanvas.ScoreScale) ? appearanceCanvas.ScoreScale : 118.0, 75.0, 160.0);
				appearanceCanvas.ScreenX = Math.Clamp(appearanceCanvas.ScreenX, -3000, 3000);
				appearanceCanvas.ScreenY = Math.Clamp(appearanceCanvas.ScreenY, -2000, 2000);
			}
			appearanceState = state;
			if (appearanceState.B30Layouts == null)
			{
				Dictionary<string, AppearanceB30Layout> val5 = (appearanceState.B30Layouts = new Dictionary<string, AppearanceB30Layout>());
			}
			Enumerator<string, AppearanceB30Layout> enumerator2 = state.B30Layouts.Values.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					AppearanceB30Layout current2 = enumerator2.Current;
					if (current2 != null)
					{
						RemoveUnsupportedLayers(current2.Layers);
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
			}
			appearanceTheme = theme;
			if (appearanceTheme.Images == null)
			{
				Dictionary<string, AppearanceResource> val7 = (appearanceTheme.Images = new Dictionary<string, AppearanceResource>());
			}
			appearanceTheme = theme;
			if (appearanceTheme.Fonts == null)
			{
				Dictionary<string, AppearanceResource> val7 = (appearanceTheme.Fonts = new Dictionary<string, AppearanceResource>());
			}
			ValueTuple<string, string>[] array2 = new ValueTuple<string, string>[3]
			{
				new ValueTuple<string, string>("oxanium", "Oxanium"),
				new ValueTuple<string, string>("orbitron", "Orbitron"),
				new ValueTuple<string, string>("rajdhani", "Rajdhani")
			};
			for (int i = 0; i < array2.Length; i++)
			{
				ValueTuple<string, string> val10 = array2[i];
				string item = val10.Item1;
				string item2 = val10.Item2;
				string text2 = "appearance/builtin/fonts/" + item2 + "-Bold.ttf";
				if (!theme.Fonts.ContainsKey(item) && File.Exists(SafePath(text2)))
				{
					theme.Fonts[item] = new AppearanceResource
					{
						Id = item,
						File = text2,
						Name = item2 + " · " + ((item == "oxanium") ? "切角数字(推荐)" : ((item == "orbitron") ? "几何数字" : "紧凑数字"))
					};
				}
			}
			Enumerator<string, AppearanceResource> enumerator3 = theme.Images.Values.GetEnumerator();
			try
			{
				while (enumerator3.MoveNext())
				{
					AppearanceResource current3 = enumerator3.Current;
					SafePath(current3.File);
					SafePath(current3.OriginalFile);
				}
			}
			finally
			{
				((System.IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
			}
			enumerator3 = theme.Fonts.Values.GetEnumerator();
			try
			{
				while (enumerator3.MoveNext())
				{
					SafePath(enumerator3.Current.File);
				}
			}
			finally
			{
				((System.IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static bool SupportedLayer(string key)
		{
			if (key == "bg" || key == "art" || key == "name" || key == "rating" || key == "delta")
			{
				return true;
			}
			return false;
		}

		private static void RemoveUnsupportedLayers(Dictionary<string, AppearanceLayer> layers)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (layers == null)
			{
				return;
			}
			Enumerator<string> enumerator = new List<string>((System.Collections.Generic.IEnumerable<string>)layers.Keys).GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					string current = enumerator.Current;
					if (!SupportedLayer(current))
					{
						layers.Remove(current);
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void UpgradeDefaultB30Layout(AppearanceState state)
		{
			if (state.B30LayoutRevision >= 1)
			{
				return;
			}
			AppearanceState appearanceState = state;
			if (appearanceState.B30Layouts == null)
			{
				Dictionary<string, AppearanceB30Layout> val = (appearanceState.B30Layouts = new Dictionary<string, AppearanceB30Layout>());
			}
			AppearanceCanvas appearanceCanvas = default(AppearanceCanvas);
			if (state.Canvas != null && state.Canvas.TryGetValue("b30", ref appearanceCanvas) && appearanceCanvas != null && appearanceCanvas.B30Style == "infalsus" && appearanceCanvas.Width == 2270 && appearanceCanvas.Height == 1830 && appearanceCanvas.Columns == 5 && appearanceCanvas.Gap == 18 && appearanceCanvas.HeaderHeight == 17.0 && state.B30 != null && LegacyLayer("name", 5.0, 17.0, 96.0) && LegacyLayer("rating", 49.0, 17.0, 128.0) && LegacyLayer("art", 82.0, 0.0, 0.0))
			{
				AppearanceB30Layout appearanceB30Layout = Copy(new AppearanceB30Layout
				{
					Layers = state.B30,
					Canvas = state.Canvas["b30"]
				});
				state.B30Layouts["infalsus"] = appearanceB30Layout;
				AppearanceB30Layout appearanceB30Layout2 = default(AppearanceB30Layout);
				if (state.B30Layouts.TryGetValue("arc", ref appearanceB30Layout2) && appearanceB30Layout2?.Canvas != null && appearanceB30Layout2.Layers != null)
				{
					AppearanceB30Layout appearanceB30Layout3 = Copy(appearanceB30Layout2);
					state.B30 = appearanceB30Layout3.Layers;
					state.Canvas["b30"] = appearanceB30Layout3.Canvas;
				}
				else
				{
					AppearanceB30Layout appearanceB30Layout4 = Copy(appearanceB30Layout);
					AppearanceCanvas canvas = appearanceB30Layout4.Canvas;
					canvas.Width = 1800;
					canvas.Height = 3240;
					canvas.Columns = 3;
					canvas.Gap = 44;
					canvas.HeaderHeight = 8.0;
					if (canvas.CardColor == "#F1EDF9")
					{
						canvas.CardColor = "#F1F3FF";
					}
					AppearanceLayer appearanceLayer = appearanceB30Layout4.Layers["art"];
					appearanceLayer.X = 3.0;
					appearanceLayer.Y = 6.0;
					AppearanceLayer appearanceLayer2 = appearanceB30Layout4.Layers["name"];
					appearanceLayer2.X = 18.0;
					appearanceLayer2.Y = 17.0;
					appearanceLayer2.FontSize = 72.0;
					AppearanceLayer appearanceLayer3 = appearanceB30Layout4.Layers["rating"];
					appearanceLayer3.X = 68.0;
					appearanceLayer3.Y = 9.0;
					appearanceLayer3.FontSize = 48.0;
					state.B30 = appearanceB30Layout4.Layers;
					state.Canvas["b30"] = canvas;
				}
				state.Canvas["b30"].B30Style = "arc";
			}
			state.B30LayoutRevision = 1;
			[CompilerGenerated]
			static AppearanceB30Layout Copy(AppearanceB30Layout value)
			{
				return JsonSerializer.Deserialize<AppearanceB30Layout>(JsonSerializer.Serialize<AppearanceB30Layout>(value, JsonOptions), JsonOptions);
			}
			[CompilerGenerated]
			bool LegacyLayer(string key, double x, double y, double size)
			{
				AppearanceLayer appearanceLayer4 = default(AppearanceLayer);
				if (state.B30.TryGetValue(key, ref appearanceLayer4) && appearanceLayer4 != null && appearanceLayer4.X == x && appearanceLayer4.Y == y && appearanceLayer4.FontSize == size)
				{
					return appearanceLayer4.Scale == 100.0;
				}
				return false;
			}
		}

		public static void Save(AppearanceTheme theme)
		{
			lock (Gate)
			{
				Validate(theme);
				string text = JsonSerializer.Serialize<AppearanceTheme>(theme, JsonOptions);
				string text2 = ThemePath + ".tmp";
				File.WriteAllText(text2, text);
				if (File.Exists(ThemePath))
				{
					File.Copy(ThemePath, ThemePath + ".previous", true);
				}
				File.Move(text2, ThemePath, true);
				Current = theme;
				_lastWrite = File.GetLastWriteTimeUtc(ThemePath);
				Interlocked.Increment(ref _generation);
			}
		}

		public static void Reload()
		{
			lock (Gate)
			{
				AppearanceTheme appearanceTheme = JsonSerializer.Deserialize<AppearanceTheme>(File.ReadAllText(ThemePath), JsonOptions);
				Validate(appearanceTheme);
				Current = appearanceTheme;
				_lastWrite = File.GetLastWriteTimeUtc(ThemePath);
				Interlocked.Increment(ref _generation);
			}
		}

		public static void Poll()
		{
			if (File.Exists(ThemePath) && File.GetLastWriteTimeUtc(ThemePath) != _lastWrite)
			{
				try
				{
					Reload();
				}
				catch (System.Exception ex)
				{
					Plugin.Logger.LogWarning((object)("[Appearance] 配置读取失败,沿用上一次有效样式: " + ex.Message));
					_lastWrite = File.GetLastWriteTimeUtc(ThemePath);
				}
			}
		}

		public static string ImageFile(string target, AppearanceTheme theme)
		{
			string text = ((target == "art") ? theme.State.Art : theme.State.Bg);
			if (text == "gradient")
			{
				return null;
			}
			if (text == "custom")
			{
				AppearanceResource appearanceResource = default(AppearanceResource);
				if (!theme.Images.TryGetValue(target, ref appearanceResource))
				{
					return null;
				}
				return SafePath(appearanceResource.File);
			}
			return SafePath("jacket/" + text + ".png");
		}
	}
	public static class AppearanceRenderer
	{
		private sealed class PreviewImageEntry
		{
			public System.IntPtr Image;

			public long Stamp;

			public long Used;

			public int Bytes;

			public int Limit;
		}

		private sealed class RenderContext
		{
			public readonly object Gate;

			public readonly Dictionary<string, System.IntPtr> Images;

			public readonly Dictionary<string, ValueTuple<System.IntPtr, System.IntPtr>> Families;

			public readonly Dictionary<System.IntPtr, Dictionary<char, bool>> Glyphs;

			public readonly HashSet<string> PrivateFonts;

			public readonly Dictionary<string, PreviewImageEntry> Previews = new Dictionary<string, PreviewImageEntry>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase);

			public readonly Dictionary<System.IntPtr, ValueTuple<uint, uint>> OriginalSizes = new Dictionary<System.IntPtr, ValueTuple<uint, uint>>();

			public int Generation = -1;

			public int PreviewBytes;

			public long UseCounter;

			public string Resources;

			public AppearanceTheme Theme;

			public bool Preview;

			public int SourceImageLimit;

			public RenderContext()
				: this(new object(), new Dictionary<string, System.IntPtr>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase), new Dictionary<string, ValueTuple<System.IntPtr, System.IntPtr>>(), new Dictionary<System.IntPtr, Dictionary<char, bool>>(), new HashSet<string>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase))
			{
			}

			public RenderContext(object gate, Dictionary<string, System.IntPtr> images, Dictionary<string, ValueTuple<System.IntPtr, System.IntPtr>> families, Dictionary<System.IntPtr, Dictionary<char, bool>> glyphs, HashSet<string> fonts)
			{
				Gate = gate;
				Images = images;
				Families = families;
				Glyphs = glyphs;
				PrivateFonts = fonts;
			}
		}

		private readonly struct RenderScope : System.IDisposable
		{
			private readonly RenderContext previous;

			public RenderScope(RenderContext value)
			{
				previous = _context;
				_context = value;
			}

			public void Dispose()
			{
				_context = previous;
			}
		}

		private sealed class PreviewFile
		{
			[field: CompilerGenerated]
			public string File
			{
				[CompilerGenerated]
				get;
				[CompilerGenerated]
				set;
			}

			[field: CompilerGenerated]
			public uint Width
			{
				[CompilerGenerated]
				get;
				[CompilerGenerated]
				set;
			}

			[field: CompilerGenerated]
			public uint Height
			{
				[CompilerGenerated]
				get;
				[CompilerGenerated]
				set;
			}
		}

		private sealed class CachedExport
		{
			public string Key;

			public byte[] Png;
		}

		private struct StartupInput
		{
			public uint Version;

			public System.IntPtr Callback;

			public int SuppressThread;

			public int SuppressCodecs;
		}

		private struct Rect
		{
			public float X;

			public float Y;

			public float W;

			public float H;

			public Rect(float x, float y, float w, float h)
			{
				X = x;
				Y = y;
				W = w;
				H = h;
			}
		}

		private struct Point
		{
			public float X;

			public float Y;

			public Point(float x, float y)
			{
				X = x;
				Y = y;
			}
		}

		private struct Matrix
		{
			public float M00;

			public float M01;

			public float M02;

			public float M03;

			public float M04;

			public float M10;

			public float M11;

			public float M12;

			public float M13;

			public float M14;

			public float M20;

			public float M21;

			public float M22;

			public float M23;

			public float M24;

			public float M30;

			public float M31;

			public float M32;

			public float M33;

			public float M34;

			public float M40;

			public float M41;

			public float M42;

			public float M43;

			public float M44;
		}

		private static readonly object StartupGate = new object();

		private static readonly object FontRegistrationGate = new object();

		private static readonly Dictionary<string, int> FontRegistrations = new Dictionary<string, int>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase);

		[ThreadStatic]
		private static RenderContext _context;

		private const int PreviewImageBudget = 8388608;

		private static readonly object PreviewDiskGate = new object();

		private const int PixelArgb = 2498570;

		private static readonly object Gate = new object();

		private static readonly Dictionary<string, System.IntPtr> Images = new Dictionary<string, System.IntPtr>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, ValueTuple<System.IntPtr, System.IntPtr>> Families = new Dictionary<string, ValueTuple<System.IntPtr, System.IntPtr>>();

		private static readonly Dictionary<System.IntPtr, Dictionary<char, bool>> Glyphs = new Dictionary<System.IntPtr, Dictionary<char, bool>>();

		private static readonly HashSet<string> PrivateGdiFonts = new HashSet<string>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase);

		private static readonly RenderContext OverlayContext = new RenderContext(Gate, Images, Families, Glyphs, PrivateGdiFonts);

		private static readonly RenderContext ExportContext = new RenderContext();

		private static readonly RenderContext PreviewContext = new RenderContext
		{
			Preview = true
		};

		private static readonly Dictionary<bool, CachedExport> Exports = new Dictionary<bool, CachedExport>();

		private const int ExportCacheBudget = 8388608;

		private static readonly Guid Png = new Guid("557cf406-1a04-11d3-9a73-0000f81ef32e");

		private static System.IntPtr _token;

		private static RenderContext Context => _context ?? OverlayContext;

		private static string ChartTitle(string id, AppearanceTheme theme)
		{
			return SongLocalization.Title(id, SongInfoCache.GetBaseName(id), SongInfoCache.GetName(id), theme.State.TitleLanguage);
		}

		private static string ChartArtist(string id, AppearanceTheme theme)
		{
			return SongLocalization.Artist(id, SongInfoCache.GetBaseName(id), SongInfoCache.GetArtist(id), theme.State.TitleLanguage);
		}

		[DllImport("gdiplus.dll", ExactSpelling = true)]
		private static extern int GdipScaleWorldTransform(System.IntPtr graphics, float sx, float sy, int order);

		[DllImport("gdiplus.dll", ExactSpelling = true)]
		private static extern int GdipDrawImageRectI(System.IntPtr graphics, System.IntPtr image, int x, int y, int width, int height);

		[DllImport("gdiplus.dll", ExactSpelling = true)]
		private static extern int GdipCloneBitmapAreaI(int x, int y, int width, int height, int format, System.IntPtr source, out System.IntPtr clone);

		private static string ResourceKey(AppearanceTheme theme)
		{
			//IL_0005: 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_0044: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder val = new StringBuilder(AppearanceStore.Root).Append('|').Append(theme.State.Art).Append('|')
				.Append(theme.State.Bg);
			Enumerator<string, AppearanceResource> enumerator = theme.Images.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					KeyValuePair<string, AppearanceResource> current = enumerator.Current;
					val.Append('|').Append(current.Key).Append(':')
						.Append(current.Value.File);
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			enumerator = theme.Fonts.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					KeyValuePair<string, AppearanceResource> current2 = enumerator.Current;
					val.Append('|').Append(current2.Key).Append(':')
						.Append(current2.Value.File);
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			return ((object)val).ToString();
		}

		private static void ClearContext(RenderContext context, bool clearPreviews = true)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_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)
			Enumerator<string, System.IntPtr> enumerator = context.Images.Values.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					DisposeBitmap(enumerator.Current);
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			context.Images.Clear();
			Enumerator<string, ValueTuple<System.IntPtr, System.IntPtr>> enumerator2 = context.Families.Values.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					ValueTuple<System.IntPtr, System.IntPtr> current = enumerator2.Current;
					if (current.Item1 != System.IntPtr.Zero)
					{
						GdipDeleteFontFamily(current.Item1);
					}
					System.IntPtr collection = current.Item2;
					if (collection != System.IntPtr.Zero)
					{
						GdipDeletePrivateFontCollection(ref collection);
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
			}
			context.Families.Clear();
			context.Glyphs.Clear();
			Enumerator<string> enumerator3 = context.PrivateFonts.GetEnumerator();
			try
			{
				while (enumerator3.MoveNext())
				{
					ReleasePrivateFont(enumerator3.Current);
				}
			}
			finally
			{
				((System.IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
			}
			context.PrivateFonts.Clear();
			if (clearPreviews)
			{
				ClearPreviewImages(context);
			}
		}

		private static void ClearPreviewImages(RenderContext context)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Enumerator<string, PreviewImageEntry> enumerator = context.Previews.Values.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					DisposeBitmap(enumerator.Current.Image);
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			context.Previews.Clear();
			context.OriginalSizes.Clear();
			context.PreviewBytes = 0;
		}

		private static void RemovePreview(RenderContext context, string file)
		{
			PreviewImageEntry previewImageEntry = context.Previews[file];
			context.Previews.Remove(file);
			context.OriginalSizes.Remove(previewImageEntry.Image);
			context.PreviewBytes -= previewImageEntry.Bytes;
			DisposeBitmap(previewImageEntry.Image);
		}

		private static void RegisterPrivateFont(string file)
		{
			lock (FontRegistrationGate)
			{
				int num = default(int);
				if (FontRegistrations.TryGetValue(file, ref num))
				{
					FontRegistrations[file] = num + 1;
				}
				else if (AddFontResourceExW(file, 16u, System.IntPtr.Zero) > 0)
				{
					FontRegistrations[file] = 1;
				}
			}
		}

		private static void ReleasePrivateFont(string file)
		{
			lock (FontRegistrationGate)
			{
				int num = default(int);
				if (FontRegistrations.TryGetValue(file, ref num))
				{
					if (num > 1)
					{
						FontRegistrations[file] = num - 1;
						return;
					}
					FontRegistrations.Remove(file);
					RemoveFontResourceExW(file, 16u, System.IntPtr.Zero);
				}
			}
		}

		private static System.IntPtr PreviewImage(string file, int limit = 0)
		{
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			bool flag = limit > 0;
			if (limit == 0)
			{
				limit = PreviewLimit(file);
			}
			RenderContext context = Context;
			long ticks = File.GetLastWriteTimeUtc(file).Ticks;
			PreviewImageEntry previewImageEntry = default(PreviewImageEntry);
			if (context.Previews.TryGetValue(file, ref previewImageEntry))
			{
				if (previewImageEntry.Stamp == ticks && previewImageEntry.Limit == limit)
				{
					previewImageEntry.Used = ++context.UseCounter;
					return previewImageEntry.Image;
				}
				RemovePreview(context, file);
			}
			string directory = Path.Combine(AppearanceStore.Root, "appearance", "cache", flag ? "completion-thumbnails" : "thumbnails");
			PreviewFile previewFile = PreparePreviewImage(file, directory, limit);
			if (previewFile == null)
			{
				return System.IntPtr.Zero;
			}
			System.IntPtr intPtr = LoadPreviewBitmap(previewFile.File);
			if (intPtr == System.IntPtr.Zero)
			{
				return System.IntPtr.Zero;
			}
			try
			{
				GdipGetImageWidth(intPtr, out var w);
				GdipGetImageHeight(intPtr, out var h);
				int num = checked((int)(w * h * 4));
				while (context.PreviewBytes + num > 8388608 && context.Previews.Count > 0)
				{
					string file2 = null;
					long num2 = 9223372036854775807L;
					Enumerator<string, PreviewImageEntry> enumerator = context.Previews.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							KeyValuePair<string, PreviewImageEntry> current = enumerator.Current;
							if (current.Value.Used < num2)
							{
								num2 = current.Value.Used;
								file2 = current.Key;
							}
						}
					}
					finally
					{
						((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
					RemovePreview(context, file2);
				}
				context.Previews[file] = new PreviewImageEntry
				{
					Image = intPtr,
					Stamp = ticks,
					Used = ++context.UseCounter,
					Bytes = num,
					Limit = limit
				};
				context.OriginalSizes[intPtr] = new ValueTuple<uint, uint>(previewFile.Width, previewFile.Height);
				context.PreviewBytes += num;
				System.IntPtr result = intPtr;
				intPtr = System.IntPtr.Zero;
				return result;
			}
			finally
			{
				DisposeBitmap(intPtr);
			}
		}

		private static System.IntPtr LoadPreviewBitmap(string file)
		{
			if (GdipCreateBitmapFromFile(file, out var bitmap) != 0)
			{
				return System.IntPtr.Zero;
			}
			try
			{
				GdipGetImageWidth(bitmap, out var w);
				GdipGetImageHeight(bitmap, out var h);
				Check(GdipCloneBitmapAreaI(0, 0, (int)w, (int)h, 2498570, bitmap, out var clone), "preview detach");
				return clone;
			}
			finally
			{
				DisposeBitmap(bitmap);
			}
		}

		private static int PreviewLimit(string file)
		{
			if (file.IndexOf(Path.DirectorySeparatorChar + "jacket" + Path.DirectorySeparatorChar, (StringComparison)5) < 0)
			{
				return 768;
			}
			return 160;
		}

		private static PreviewFile PreparePreviewImage(string file, string directory, int limit)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//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)
			FileInfo val = new FileInfo(file);
			if (!((FileSystemInfo)val).Exists)
			{
				return null;
			}
			string text = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(string.Concat(new string[8]
			{
				file,
				"|",
				((FileSystemInfo)val).LastWriteTimeUtc.Ticks.ToString(),
				"|",
				val.Length.ToString(),
				"|",
				limit.ToString(),
				"|1"
			})))).ToLowerInvariant();
			string text2 = Path.Combine(directory, "b30-" + text + ".png");
			string text3 = text2 + ".json";
			lock (PreviewDiskGate)
			{
				if (File.Exists(text2) && File.Exists(text3))
				{
					try
					{
						PreviewFile previewFile = JsonSerializer.Deserialize<PreviewFile>(File.ReadAllText(text3), (JsonSerializerOptions)null);
						if (previewFile.Width != 0 && previewFile.Height != 0)
						{
							previewFile.File = text2;
							return previewFile;
						}
					}
					catch (JsonException)
					{
					}
				}
				Directory.CreateDirectory(directory);
				lock (StartupGate)
				{
					if (_token == System.IntPtr.Zero)
					{
						StartupInput input = new StartupInput
						{
							Version = 1u
						};
						Check(GdiplusStartup(out _token, ref input, System.IntPtr.Zero), "GDI+ startup");
					}
				}
				if (GdipCreateBitmapFromFile(file, out var bitmap) != 0)
				{
					return null;
				}
				System.IntPtr image = System.IntPtr.Zero;
				try
				{
					GdipGetImageWidth(bitmap, out var w);
					GdipGetImageHeight(bitmap, out var h);
					double num = Math.Min(1.0, (double)limit / (double)Math.Max(w, h));
					int num2 = Math.Max(1, (int)Math.Round((double)w * num));
					int num3 = Math.Max(1, (int)Math.Round((double)h * num));
					image = Bitmap(num2, num3, out var g);
					try
					{
						Check(GdipDrawImageRectI(g, bitmap, 0, 0, num2, num3), "preview image");
					}
					finally
					{
						GdipDeleteGraphics(g);
					}
					string text4 = text2 + ".tmp";
					Guid encoder = Png;
					Check(GdipSaveImageToFile(image, text4, ref encoder, System.IntPtr.Zero), "preview cache");
					File.Move(text4, text2, true);
					PreviewFile previewFile2 = new PreviewFile
					{
						File = text2,
						Width = w,
						Height = h
					};
					File.WriteAllText(text3, JsonSerializer.Serialize<PreviewFile>(previewFile2, (JsonSerializerOptions)null));
					TrimPreviewFiles(directory);
					return previewFile2;
				}
				finally
				{
					DisposeBitmap(image);
					DisposeBitmap(bitmap);
				}
			}
		}

		private static void TrimPreviewFiles(string directory)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			List<FileInfo> val = new List<FileInfo>();
			long num = 0L;
			string[] files = Directory.GetFiles(directory, "b30-*.png");
			for (int i = 0; i < files.Length; i++)
			{
				FileInfo val2 = new FileInfo(files[i]);
				val.Add(val2);
				num += val2.Length;
			}
			val.Sort((Comparison<FileInfo>)((FileInfo a, FileInfo b) => ((FileSystemInfo)a).LastWriteTimeUtc.CompareTo(((FileSystemInfo)b).LastWriteTimeUtc)));
			Enumerator<FileInfo> enumerator = val.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					FileInfo current = enumerator.Current;
					if (num <= 16777216)
					{
						break;
					}
					if (((FileSystemInfo)current).Name.Length != 72)
					{
						continue;
					}
					try
					{
						long length = current.Length;
						((FileSystemInfo)current).Delete();
						num -= length;
						string text = ((FileSystemInfo)current).FullName + ".json";
						if (File.Exists(text))
						{
							File.Delete(text);
						}
					}
					catch (IOException)
					{
					}
				}
			}
			finally
			{
				((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
		}

		public static int PreparePreviewCache(string root)
		{
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			root = Path.GetFullPath(root);
			string directory = Path.Combine(root, "appearance", "cache", "thumbnails");
			HashSet<string> val = new HashSet<string>((IEqualityComparer<string>)(object)StringComparer.OrdinalIgnoreCase);
			string[] array = new string[2] { "jacket", "appearance/builtin" };
			foreach (string text in array)
			{
				string text2 = Path.Combine(root, text);
				if (Directory.Exists(text2))
				{
					string[] files = Directory.GetFiles(text2, "*.png");
					foreach (string text3 in files)
					{
						val.Add(text3);
					}
				}
			}
			string text4 = Path.Combine(root, "appearance", "theme.json");
			if (File.Exists(text4))
			{
				Enumerator<string, AppearanceResource> enumerator = JsonSerializer.Deserialize<AppearanceTheme>(File.ReadAllText(text4), AppearanceStore.JsonOptions).Images.Values.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						AppearanceResource current = enumerator.Current;
						string fullPath = Path.GetFullPath(Path.Combine(root, current.File));
						if (fullPath.StartsWith(root + Path.DirectorySeparatorChar, (StringComparison)5) && File.Exists(fullPath))
						{
							val.Add(fullPath);
						}
					}
				}
				finally
				{
					((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
			}
			int num = 0;
			Enumerator<string> enumerator2 = val.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					string current2 = enumerator2.Current;
					if (PreparePreviewImage(current2, directory, PreviewLimit(current2)) != null)
					{
						num++;
					}
				}
				return num;
			}
			finally
			{
				((System.IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
			}
		}

		public static bool PreviewB30(string file, string name, double rating, List<ChartRating> charts, AppearanceTheme theme, int maximumWidth = 1000)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return SaveB30(file, name, rating, charts, theme.State.B30Jackets, DateTimeOffset.Now, theme, Math.Clamp(maximumWidth, 400, 1200));
		}

		[DllImport("gdiplus.dll", ExactSpelling = true)]
		private static extern int GdiplusStartup(out System.IntPtr token, ref StartupInput input, System.IntPtr output);

		[DllImport("gdiplus.dll", ExactSpelling = true)]
		private static extern int GdipCreateBitmapFromScan0(int w, int h, int stride, int format, System.IntPtr data, out System.IntPtr bitmap);

		[DllImport("gdiplus.dll", CharSet = (CharSet)3, ExactSpelling = true)]
		private static extern int GdipCreateBitmapFromFile(string file, out System.IntPtr bitmap);

		[DllImport("gdiplus.dll", ExactSpelling = true)]
		private static extern int GdipDisposeImage(System.IntPtr image);

		[DllImport("gdiplus.dll", ExactSpelling = true)]
		private