Decompiled source of PeakMapBrowser v0.1.1

PeakMapBrowser.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Steamworks;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PeakMapBrowser
{
	internal sealed class MapsResponse
	{
		public bool success;

		public List<MapEntry> data;

		public PaginationInfo pagination;

		public string error_code;

		public string error;

		public string error_message;
	}
	internal sealed class ModVersionsResponse
	{
		public bool success;

		public List<ModVersionEntry> data;

		public string error_code;

		public string error;

		public string error_message;
	}
	internal sealed class AuthResponse
	{
		public bool success;

		public string access_token;

		public string refresh_token;

		public long expires_at;

		public int expires_in;

		public AccountUser user;

		public string error;

		public string error_message;
	}
	internal sealed class AccountUser
	{
		public string id;

		public string email;

		public string nickname;
	}
	internal sealed class LikeResponse
	{
		public bool success;

		public bool liked;

		public int likes;

		public string error;

		public string error_message;
	}
	internal sealed class BasicResponse
	{
		public bool success;

		public string message;

		public string error;

		public string error_message;
	}
	internal sealed class PeakMapSession
	{
		public string access_token;

		public string refresh_token;

		public long expires_at;

		public string user_id;

		public string email;

		public string nickname;

		public string guest_id;

		public bool HasUser => !string.IsNullOrEmpty(access_token) && !string.IsNullOrEmpty(refresh_token);

		public bool HasRefreshToken => !string.IsNullOrEmpty(refresh_token);

		public string DisplayName
		{
			get
			{
				if (!string.IsNullOrWhiteSpace(nickname))
				{
					return nickname;
				}
				if (!string.IsNullOrWhiteSpace(email))
				{
					return email;
				}
				return string.Empty;
			}
		}
	}
	internal sealed class MapEntry
	{
		public string id;

		public string name;

		public string author;

		public string mod_version;

		public string description;

		public int downloads;

		public int likes;

		public string created_at;

		public string updated_at;

		public int revision;

		public bool liked_by_me;

		public string image_url;

		public string thumbnail_url;

		public string json_file_url;

		public string download_url;
	}
	internal sealed class PaginationInfo
	{
		public int page;

		public int page_size;

		public int total;

		public int total_pages;

		public bool has_next;

		public bool has_prev;
	}
	internal sealed class ModVersionEntry
	{
		public string id;

		public string version_name;

		public string created_at;
	}
	internal static class MapImageCache
	{
		private const long MaxCacheBytes = 268435456L;

		private const int MaxCacheFiles = 300;

		private static readonly object Sync = new object();

		private static string CacheDirectory => Path.Combine(Application.persistentDataPath, "PeakMapBrowser", "ImageCache");

		public static string GetExistingPath(string url)
		{
			if (string.IsNullOrEmpty(url))
			{
				return null;
			}
			lock (Sync)
			{
				try
				{
					string cachePath = GetCachePath(url);
					if (!File.Exists(cachePath) || new FileInfo(cachePath).Length == 0)
					{
						return null;
					}
					Touch(cachePath);
					return cachePath;
				}
				catch
				{
					return null;
				}
			}
		}

		public static void Remove(string url)
		{
			if (string.IsNullOrEmpty(url))
			{
				return;
			}
			lock (Sync)
			{
				try
				{
					string cachePath = GetCachePath(url);
					if (File.Exists(cachePath))
					{
						File.Delete(cachePath);
					}
				}
				catch
				{
				}
			}
		}

		public static void Save(string url, byte[] bytes)
		{
			if (string.IsNullOrEmpty(url) || bytes == null || bytes.Length == 0)
			{
				return;
			}
			lock (Sync)
			{
				try
				{
					Directory.CreateDirectory(CacheDirectory);
					string cachePath = GetCachePath(url);
					if (File.Exists(cachePath))
					{
						Touch(cachePath);
						return;
					}
					string text = cachePath + ".tmp-" + Guid.NewGuid().ToString("N");
					try
					{
						File.WriteAllBytes(text, bytes);
						File.Move(text, cachePath);
					}
					finally
					{
						if (File.Exists(text))
						{
							File.Delete(text);
						}
					}
					PruneCache();
				}
				catch
				{
				}
			}
		}

		private static string GetCachePath(string url)
		{
			Directory.CreateDirectory(CacheDirectory);
			return Path.Combine(CacheDirectory, "image-" + Hash(url) + ".cache");
		}

		private static string Hash(string value)
		{
			using SHA256 sHA = SHA256.Create();
			byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(value));
			StringBuilder stringBuilder = new StringBuilder(array.Length * 2);
			for (int i = 0; i < array.Length; i++)
			{
				stringBuilder.Append(array[i].ToString("x2"));
			}
			return stringBuilder.ToString();
		}

		private static void Touch(string path)
		{
			try
			{
				File.SetLastAccessTimeUtc(path, DateTime.UtcNow);
			}
			catch
			{
			}
		}

		private static void PruneCache()
		{
			string[] files = Directory.GetFiles(CacheDirectory, "*.cache", SearchOption.TopDirectoryOnly);
			Array.Sort(files, (string a, string b) => File.GetLastAccessTimeUtc(a).CompareTo(File.GetLastAccessTimeUtc(b)));
			long num = 0L;
			for (int num2 = 0; num2 < files.Length; num2++)
			{
				num += new FileInfo(files[num2]).Length;
			}
			int num3 = Mathf.Max(0, files.Length - 300);
			for (int num4 = 0; num4 < files.Length && (num > 268435456 || num4 < num3); num4++)
			{
				try
				{
					long length = new FileInfo(files[num4]).Length;
					File.Delete(files[num4]);
					num -= length;
				}
				catch
				{
				}
			}
		}
	}
	internal static class MapSaveService
	{
		public static string SavePath => Path.Combine(Application.persistentDataPath, "TerrainCustomiser", "Map Saves");

		public static string CoverPath => Path.Combine(SavePath, "Covers");

		public static string BackupPath => Path.Combine(SavePath, "Backups");

		private static string IndexPath => Path.Combine(Application.persistentDataPath, "PeakMapBrowser", "map-index.json");

		public static string PicturesPath => Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

		public static string[] GetLocalJsonFiles()
		{
			EnsureSaveDirectory();
			string[] files = Directory.GetFiles(SavePath, "*.json");
			Array.Sort(files, (string a, string b) => File.GetLastWriteTimeUtc(b).CompareTo(File.GetLastWriteTimeUtc(a)));
			return files;
		}

		public static string[] GetLocalImageFiles()
		{
			EnsureSaveDirectory();
			string[] imageRootPaths = GetImageRootPaths();
			List<string> list = new List<string>();
			for (int i = 0; i < imageRootPaths.Length; i++)
			{
				if (!Directory.Exists(imageRootPaths[i]))
				{
					continue;
				}
				string[] files = Directory.GetFiles(imageRootPaths[i], "*.*", SearchOption.TopDirectoryOnly);
				for (int j = 0; j < files.Length; j++)
				{
					if (IsSupportedImage(files[j]))
					{
						list.Add(files[j]);
					}
				}
			}
			list.Sort((string a, string b) => File.GetLastWriteTimeUtc(b).CompareTo(File.GetLastWriteTimeUtc(a)));
			return list.ToArray();
		}

		public static void EnsureSaveDirectory()
		{
			Directory.CreateDirectory(SavePath);
			Directory.CreateDirectory(CoverPath);
			Directory.CreateDirectory(BackupPath);
		}

		public static string[] GetImageRootPaths()
		{
			EnsureSaveDirectory();
			if (string.IsNullOrEmpty(PicturesPath))
			{
				return new string[2] { SavePath, CoverPath };
			}
			return new string[3] { SavePath, CoverPath, PicturesPath };
		}

		public static string GetImageRootLabel(string root)
		{
			string a = NormalizePath(root);
			if (string.Equals(a, NormalizePath(SavePath), StringComparison.OrdinalIgnoreCase))
			{
				return "Map Saves";
			}
			if (string.Equals(a, NormalizePath(CoverPath), StringComparison.OrdinalIgnoreCase))
			{
				return "Covers";
			}
			if (!string.IsNullOrEmpty(PicturesPath) && string.Equals(a, NormalizePath(PicturesPath), StringComparison.OrdinalIgnoreCase))
			{
				return "Pictures";
			}
			return DisplayName(root);
		}

		public static bool TryNormalizeWhitelistedDirectory(string path, out string normalized)
		{
			normalized = null;
			if (string.IsNullOrEmpty(path) || IsNetworkPath(path))
			{
				return false;
			}
			string text;
			try
			{
				text = NormalizePath(path);
			}
			catch
			{
				return false;
			}
			if (!Directory.Exists(text) || IsHiddenOrSystem(text))
			{
				return false;
			}
			string[] imageRootPaths = GetImageRootPaths();
			for (int i = 0; i < imageRootPaths.Length; i++)
			{
				if (IsInsideRoot(text, imageRootPaths[i]))
				{
					normalized = text;
					return true;
				}
			}
			return false;
		}

		public static bool TryNormalizeWhitelistedImage(string path, out string normalized)
		{
			normalized = null;
			if (string.IsNullOrEmpty(path) || IsNetworkPath(path) || !IsSupportedImage(path))
			{
				return false;
			}
			string text;
			try
			{
				text = NormalizePath(path);
			}
			catch
			{
				return false;
			}
			if (!File.Exists(text))
			{
				return false;
			}
			string directoryName = Path.GetDirectoryName(text);
			if (!TryNormalizeWhitelistedDirectory(directoryName, out var _))
			{
				return false;
			}
			normalized = text;
			return true;
		}

		public static string[] GetChildDirectories(string directory)
		{
			if (!TryNormalizeWhitelistedDirectory(directory, out var normalized))
			{
				return new string[0];
			}
			string[] directories = Directory.GetDirectories(normalized, "*", SearchOption.TopDirectoryOnly);
			List<string> list = new List<string>();
			for (int i = 0; i < directories.Length; i++)
			{
				if (TryNormalizeWhitelistedDirectory(directories[i], out var normalized2))
				{
					list.Add(normalized2);
				}
			}
			list.Sort(StringComparer.OrdinalIgnoreCase);
			return list.ToArray();
		}

		public static string[] GetImageFilesInDirectory(string directory)
		{
			if (!TryNormalizeWhitelistedDirectory(directory, out var normalized))
			{
				return new string[0];
			}
			string[] files = Directory.GetFiles(normalized, "*.*", SearchOption.TopDirectoryOnly);
			List<string> list = new List<string>();
			for (int i = 0; i < files.Length; i++)
			{
				if (TryNormalizeWhitelistedImage(files[i], out var normalized2))
				{
					list.Add(normalized2);
				}
			}
			list.Sort((string a, string b) => File.GetLastWriteTimeUtc(b).CompareTo(File.GetLastWriteTimeUtc(a)));
			return list.ToArray();
		}

		public static string SaveDownloadedMap(MapEntry map, byte[] bytes)
		{
			return SaveDownloadedMap(map, bytes, allowOverwriteLocalChanges: false);
		}

		public static string SaveDownloadedMap(MapEntry map, byte[] bytes, bool allowOverwriteLocalChanges)
		{
			if (map == null)
			{
				throw new ArgumentNullException("map");
			}
			if (bytes == null)
			{
				throw new ArgumentNullException("bytes");
			}
			EnsureSaveDirectory();
			MapDownloadInfo downloadInfo = GetDownloadInfo(map);
			if (downloadInfo.Status == MapDownloadStatus.UpToDate)
			{
				return downloadInfo.Path;
			}
			if (downloadInfo.Status == MapDownloadStatus.LocalModified && !allowOverwriteLocalChanges)
			{
				throw new MapSaveException(MapDownloadStatus.LocalModified, "LOCAL_MODIFIED");
			}
			string value = (string.IsNullOrWhiteSpace(map.name) ? "peak-map" : map.name.Trim());
			string text = SanitizeFileName(value);
			if (string.IsNullOrEmpty(text))
			{
				text = "peak-map";
			}
			string text2 = FindRecord(map.id)?.path;
			if (string.IsNullOrEmpty(text2) || !IsInsideRoot(text2, SavePath))
			{
				text2 = Path.Combine(SavePath, text + ".json");
				int num = 2;
				while (File.Exists(text2))
				{
					text2 = Path.Combine(SavePath, text + "-" + num + ".json");
					num++;
				}
			}
			string text3 = text2 + ".tmp-" + Guid.NewGuid().ToString("N");
			try
			{
				File.WriteAllBytes(text3, bytes);
				if (File.Exists(text2))
				{
					string destFileName = Path.Combine(BackupPath, Path.GetFileNameWithoutExtension(text2) + "-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + ".json");
					File.Copy(text2, destFileName, overwrite: false);
					File.Replace(text3, text2, null);
				}
				else
				{
					File.Move(text3, text2);
				}
				SaveRecord(map, text2, ComputeSha256(bytes));
			}
			finally
			{
				if (File.Exists(text3))
				{
					File.Delete(text3);
				}
			}
			return text2;
		}

		public static MapDownloadInfo GetDownloadInfo(MapEntry map)
		{
			MapDownloadInfo mapDownloadInfo = new MapDownloadInfo();
			if (map == null || string.IsNullOrEmpty(map.id))
			{
				mapDownloadInfo.Status = MapDownloadStatus.New;
				return mapDownloadInfo;
			}
			LocalMapRecord localMapRecord = FindRecord(map.id);
			if (localMapRecord == null || string.IsNullOrEmpty(localMapRecord.path) || !File.Exists(localMapRecord.path))
			{
				mapDownloadInfo.Status = MapDownloadStatus.New;
				mapDownloadInfo.CurrentRevision = map.revision;
				return mapDownloadInfo;
			}
			mapDownloadInfo.Path = localMapRecord.path;
			mapDownloadInfo.LocalRevision = localMapRecord.revision;
			mapDownloadInfo.CurrentRevision = map.revision;
			mapDownloadInfo.LocalHash = localMapRecord.sha256;
			string a = ComputeSha256(localMapRecord.path);
			if (!string.Equals(a, localMapRecord.sha256, StringComparison.OrdinalIgnoreCase))
			{
				mapDownloadInfo.Status = MapDownloadStatus.LocalModified;
			}
			else if (map.revision > localMapRecord.revision)
			{
				mapDownloadInfo.Status = MapDownloadStatus.UpdateAvailable;
			}
			else
			{
				mapDownloadInfo.Status = MapDownloadStatus.UpToDate;
			}
			return mapDownloadInfo;
		}

		private static LocalMapRecord FindRecord(string mapId)
		{
			if (string.IsNullOrEmpty(mapId))
			{
				return null;
			}
			LocalMapIndex localMapIndex = LoadIndex();
			for (int i = 0; i < localMapIndex.maps.Count; i++)
			{
				if (string.Equals(localMapIndex.maps[i].map_id, mapId, StringComparison.Ordinal))
				{
					return localMapIndex.maps[i];
				}
			}
			return null;
		}

		private static void SaveRecord(MapEntry map, string path, string sha256)
		{
			LocalMapIndex localMapIndex = LoadIndex();
			LocalMapRecord localMapRecord = null;
			for (int i = 0; i < localMapIndex.maps.Count; i++)
			{
				if (string.Equals(localMapIndex.maps[i].map_id, map.id, StringComparison.Ordinal))
				{
					localMapRecord = localMapIndex.maps[i];
					break;
				}
			}
			if (localMapRecord == null)
			{
				localMapRecord = new LocalMapRecord();
				localMapRecord.map_id = map.id;
				localMapIndex.maps.Add(localMapRecord);
			}
			localMapRecord.path = path;
			localMapRecord.name = map.name ?? string.Empty;
			localMapRecord.revision = map.revision;
			localMapRecord.sha256 = sha256;
			SaveIndex(localMapIndex);
		}

		private static LocalMapIndex LoadIndex()
		{
			try
			{
				if (!File.Exists(IndexPath))
				{
					return new LocalMapIndex();
				}
				LocalMapIndex localMapIndex = JsonConvert.DeserializeObject<LocalMapIndex>(File.ReadAllText(IndexPath));
				return localMapIndex ?? new LocalMapIndex();
			}
			catch
			{
				return new LocalMapIndex();
			}
		}

		private static void SaveIndex(LocalMapIndex index)
		{
			string directoryName = Path.GetDirectoryName(IndexPath);
			Directory.CreateDirectory(directoryName);
			string text = IndexPath + ".tmp-" + Guid.NewGuid().ToString("N");
			try
			{
				File.WriteAllText(text, JsonConvert.SerializeObject((object)index, (Formatting)1), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				if (File.Exists(IndexPath))
				{
					File.Replace(text, IndexPath, null);
				}
				else
				{
					File.Move(text, IndexPath);
				}
			}
			finally
			{
				if (File.Exists(text))
				{
					File.Delete(text);
				}
			}
		}

		private static string ComputeSha256(string path)
		{
			using FileStream inputStream = File.OpenRead(path);
			using SHA256 sHA = SHA256.Create();
			return ToHex(sHA.ComputeHash(inputStream));
		}

		private static string ComputeSha256(byte[] bytes)
		{
			using SHA256 sHA = SHA256.Create();
			return ToHex(sHA.ComputeHash(bytes));
		}

		private static string ToHex(byte[] bytes)
		{
			StringBuilder stringBuilder = new StringBuilder(bytes.Length * 2);
			for (int i = 0; i < bytes.Length; i++)
			{
				stringBuilder.Append(bytes[i].ToString("x2"));
			}
			return stringBuilder.ToString();
		}

		public static string SanitizeFileName(string value)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			StringBuilder stringBuilder = new StringBuilder(value.Length);
			foreach (char c in value)
			{
				bool flag = false;
				for (int j = 0; j < invalidFileNameChars.Length; j++)
				{
					if (c == invalidFileNameChars[j])
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString().Trim();
		}

		public static string DisplayName(string path)
		{
			return string.IsNullOrEmpty(path) ? string.Empty : Path.GetFileName(path);
		}

		public static bool IsSupportedImage(string path)
		{
			string text = Path.GetExtension(path).ToLowerInvariant();
			int result;
			switch (text)
			{
			default:
				result = ((text == ".gif") ? 1 : 0);
				break;
			case ".png":
			case ".jpg":
			case ".jpeg":
			case ".webp":
				result = 1;
				break;
			}
			return (byte)result != 0;
		}

		private static bool IsHiddenOrSystem(string path)
		{
			try
			{
				FileAttributes attributes = File.GetAttributes(path);
				return (attributes & FileAttributes.Hidden) != FileAttributes.None || (attributes & FileAttributes.System) != 0;
			}
			catch
			{
				return true;
			}
		}

		private static bool IsNetworkPath(string path)
		{
			return path.StartsWith("\\\\", StringComparison.Ordinal) || path.StartsWith("//", StringComparison.Ordinal);
		}

		private static bool IsInsideRoot(string candidate, string root)
		{
			string text = NormalizePath(candidate);
			string text2 = NormalizePath(root);
			if (string.Equals(text, text2, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			string text3 = text2.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string value = text3 + directorySeparatorChar;
			return text.StartsWith(value, StringComparison.OrdinalIgnoreCase);
		}

		private static string NormalizePath(string path)
		{
			return Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
		}

		public static string FindMatchingImage(string jsonPath, string[] imageFiles)
		{
			if (string.IsNullOrEmpty(jsonPath) || imageFiles == null || imageFiles.Length == 0)
			{
				return null;
			}
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(jsonPath);
			for (int i = 0; i < imageFiles.Length; i++)
			{
				string fileNameWithoutExtension2 = Path.GetFileNameWithoutExtension(imageFiles[i]);
				if (string.Equals(fileNameWithoutExtension, fileNameWithoutExtension2, StringComparison.OrdinalIgnoreCase))
				{
					return imageFiles[i];
				}
			}
			return null;
		}
	}
	internal enum MapDownloadStatus
	{
		New,
		UpToDate,
		UpdateAvailable,
		LocalModified
	}
	internal sealed class MapDownloadInfo
	{
		public MapDownloadStatus Status;

		public string Path;

		public int LocalRevision;

		public int CurrentRevision;

		public string LocalHash;
	}
	internal sealed class LocalMapIndex
	{
		public List<LocalMapRecord> maps = new List<LocalMapRecord>();
	}
	internal sealed class LocalMapRecord
	{
		public string map_id;

		public string path;

		public string name;

		public int revision;

		public string sha256;
	}
	internal sealed class MapSaveException : Exception
	{
		public readonly MapDownloadStatus Status;

		public MapSaveException(MapDownloadStatus status, string message)
			: base(message)
		{
			Status = status;
		}
	}
	internal sealed class PeakMapApiClient
	{
		private readonly MonoBehaviour _runner;

		private readonly ManualLogSource _log;

		private readonly string _baseUrl;

		private string _language;

		public PeakMapSession Session { get; private set; }

		public bool IsSignedIn => Session != null && Session.HasUser;

		public bool ShouldRefreshSession
		{
			get
			{
				if (Session == null || !Session.HasRefreshToken)
				{
					return false;
				}
				if (string.IsNullOrEmpty(Session.access_token))
				{
					return true;
				}
				if (Session.expires_at <= 0)
				{
					return false;
				}
				long num = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
				return Session.expires_at - num < 300;
			}
		}

		public PeakMapApiClient(MonoBehaviour runner, ManualLogSource log, string baseUrl, string language)
		{
			_runner = runner;
			_log = log;
			_baseUrl = (baseUrl ?? "https://peakmap.top").TrimEnd(new char[1] { '/' });
			_language = (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase) ? "en" : "zh");
			Session = PeakMapSessionStore.Load(log);
		}

		public void SetLanguage(string language)
		{
			_language = (string.Equals(language, "en", StringComparison.OrdinalIgnoreCase) ? "en" : "zh");
		}

		public void SignOut()
		{
			PeakMapSessionStore.ClearUser(Session, _log);
		}

		public void SignOut(Action<bool, string> done)
		{
			_runner.StartCoroutine(SignOutRoutine(done));
		}

		public void SignIn(string email, string password, Action<AuthResponse, string> done)
		{
			_runner.StartCoroutine(SignInRoutine(email, password, done));
		}

		public void RefreshSession(Action<bool, string> done)
		{
			_runner.StartCoroutine(RefreshSessionRoutine(done));
		}

		public void FetchMaps(int page, int pageSize, string query, string sort, string modVersion, Action<MapsResponse, string> done)
		{
			_runner.StartCoroutine(FetchMapsRoutine(page, pageSize, query, sort, modVersion, done));
		}

		public void FetchAccountMaps(Action<MapsResponse, string> done)
		{
			_runner.StartCoroutine(FetchAccountMapsRoutine(done));
		}

		public void FetchModVersions(Action<ModVersionsResponse, string> done)
		{
			_runner.StartCoroutine(FetchModVersionsRoutine(done));
		}

		public void ToggleLike(MapEntry map, Action<LikeResponse, string> done)
		{
			_runner.StartCoroutine(ToggleLikeRoutine(map, done));
		}

		public void DownloadMap(MapEntry map, Action<string, string> done)
		{
			DownloadMap(map, allowOverwriteLocalChanges: false, done);
		}

		public void DownloadMap(MapEntry map, bool allowOverwriteLocalChanges, Action<string, string> done)
		{
			_runner.StartCoroutine(DownloadMapRoutine(map, allowOverwriteLocalChanges, done));
		}

		public MapDownloadInfo GetDownloadInfo(MapEntry map)
		{
			return MapSaveService.GetDownloadInfo(map);
		}

		public void UploadMap(string mapName, string author, string version, string description, string jsonPath, string imagePath, Action<string> done)
		{
			_runner.StartCoroutine(UploadMapRoutine(mapName, author, version, description, jsonPath, imagePath, done));
		}

		public void UpdateMap(string mapId, string mapName, string author, string version, string description, string jsonPath, string imagePath, bool removeImage, Action<string> done)
		{
			_runner.StartCoroutine(UpdateMapRoutine(mapId, mapName, author, version, description, jsonPath, imagePath, removeImage, done));
		}

		public void DeleteMap(string mapId, Action<string> done)
		{
			_runner.StartCoroutine(DeleteMapRoutine(mapId, done));
		}

		public void DownloadTexture(string url, Action<Texture2D> done)
		{
			string existingPath = MapImageCache.GetExistingPath(url);
			if (!string.IsNullOrEmpty(existingPath))
			{
				_runner.StartCoroutine(LoadCachedTextureRoutine(url, existingPath, done));
			}
			else
			{
				_runner.StartCoroutine(DownloadTextureRoutine(url, done));
			}
		}

		private IEnumerator SignInRoutine(string email, string password, Action<AuthResponse, string> done)
		{
			UnityWebRequest request = JsonRequest(json: JsonConvert.SerializeObject((object)new
			{
				email = ((email == null) ? string.Empty : email.Trim()),
				password = (password ?? string.Empty)
			}), url: _baseUrl + "/api/auth/sign-in", method: "POST");
			try
			{
				yield return request.SendWebRequest();
				AuthResponse response = Parse<AuthResponse>(Body(request));
				if (HasError(request) || response == null || !response.success)
				{
					done(response, ResponseError(response, Text("登录失败", "Sign in failed")));
					yield break;
				}
				ApplyAuthResponse(response);
				done(response, null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator RefreshSessionRoutine(Action<bool, string> done)
		{
			if (Session == null || string.IsNullOrEmpty(Session.refresh_token))
			{
				done(arg1: false, Text("没有可刷新的登录状态", "No refreshable session"));
				yield break;
			}
			UnityWebRequest request = JsonRequest(json: JsonConvert.SerializeObject((object)new { Session.refresh_token }), url: _baseUrl + "/api/auth/refresh", method: "POST");
			try
			{
				yield return request.SendWebRequest();
				AuthResponse response = Parse<AuthResponse>(Body(request));
				if (HasError(request) || response == null || !response.success)
				{
					PeakMapSessionStore.ClearUser(Session, _log);
					done(arg1: false, ResponseError(response, Text("登录状态已过期", "Session expired")));
					yield break;
				}
				ApplyAuthResponse(response);
				done(arg1: true, null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator SignOutRoutine(Action<bool, string> done)
		{
			bool serverRevoked = false;
			string error = null;
			if (Session != null && !string.IsNullOrEmpty(Session.access_token))
			{
				UnityWebRequest request = JsonRequest(_baseUrl + "/api/auth/sign-out", "POST", "{}");
				try
				{
					ApplySessionHeaders(request);
					yield return request.SendWebRequest();
					BasicResponse response = Parse<BasicResponse>(Body(request));
					serverRevoked = !HasError(request) && response != null && response.success;
					if (!serverRevoked)
					{
						error = ResponseError(response, Text("服务端退出登录失败", "Server sign-out failed"));
					}
				}
				finally
				{
					((IDisposable)request)?.Dispose();
				}
			}
			else
			{
				serverRevoked = true;
			}
			PeakMapSessionStore.ClearUser(Session, _log);
			done(serverRevoked, error);
		}

		private IEnumerator FetchMapsRoutine(int page, int pageSize, string query, string sort, string modVersion, Action<MapsResponse, string> done)
		{
			string url = _baseUrl + "/api/maps?page=" + page + "&page_size=" + pageSize + "&sort=" + Escape(sort) + "&lang=" + _language;
			if (!string.IsNullOrWhiteSpace(query))
			{
				url = url + "&q=" + Escape(query.Trim());
			}
			if (!string.IsNullOrWhiteSpace(modVersion))
			{
				url = url + "&mod_version=" + Escape(modVersion.Trim());
			}
			UnityWebRequest request = UnityWebRequest.Get(url);
			try
			{
				ApplySessionHeaders(request);
				yield return request.SendWebRequest();
				CaptureGuestCookie(request);
				if (HasError(request))
				{
					done(null, Text("获取地图列表失败: ", "Failed to fetch maps: ") + ErrorText(request));
					yield break;
				}
				MapsResponse response = Parse<MapsResponse>(Body(request));
				if (response == null || !response.success)
				{
					done(response, ResponseError(response, Text("获取地图列表失败", "Failed to fetch maps")));
					yield break;
				}
				done(response, null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator FetchAccountMapsRoutine(Action<MapsResponse, string> done)
		{
			if (!IsSignedIn)
			{
				done(null, Text("请先登录", "Please sign in first"));
				yield break;
			}
			UnityWebRequest request = UnityWebRequest.Get(_baseUrl + "/api/account/maps");
			try
			{
				ApplySessionHeaders(request);
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					MapsResponse failed = Parse<MapsResponse>(Body(request));
					done(failed, ResponseError(failed, Text("获取我的地图失败", "Failed to fetch my maps")));
					yield break;
				}
				MapsResponse response = Parse<MapsResponse>(Body(request));
				if (response == null || !response.success)
				{
					done(response, ResponseError(response, Text("获取我的地图失败", "Failed to fetch my maps")));
					yield break;
				}
				done(response, null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator FetchModVersionsRoutine(Action<ModVersionsResponse, string> done)
		{
			UnityWebRequest request = UnityWebRequest.Get(_baseUrl + "/api/mod-versions?lang=" + _language);
			try
			{
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					done(null, Text("获取 MOD 版本失败: ", "Failed to fetch MOD versions: ") + ErrorText(request));
					yield break;
				}
				ModVersionsResponse response = Parse<ModVersionsResponse>(Body(request));
				if (response == null || !response.success)
				{
					done(response, ResponseError(response, Text("获取 MOD 版本失败", "Failed to fetch MOD versions")));
					yield break;
				}
				done(response, null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator ToggleLikeRoutine(MapEntry map, Action<LikeResponse, string> done)
		{
			if (map == null || string.IsNullOrEmpty(map.id))
			{
				done(null, Text("地图缺少 ID", "Map is missing an ID"));
				yield break;
			}
			UnityWebRequest request = JsonRequest(_baseUrl + "/api/maps/" + Escape(map.id) + "/like", "POST", "{}");
			try
			{
				ApplySessionHeaders(request);
				yield return request.SendWebRequest();
				CaptureGuestCookie(request);
				LikeResponse response = Parse<LikeResponse>(Body(request));
				if (HasError(request) || response == null || !response.success)
				{
					done(response, ResponseError(response, Text("点赞失败", "Like failed")));
					yield break;
				}
				map.liked_by_me = response.liked;
				map.likes = response.likes;
				done(response, null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator DownloadMapRoutine(MapEntry map, bool allowOverwriteLocalChanges, Action<string, string> done)
		{
			if (map == null || string.IsNullOrEmpty(map.download_url))
			{
				done(null, Text("地图缺少下载地址", "Map is missing a download URL"));
				yield break;
			}
			MapDownloadInfo localInfo = MapSaveService.GetDownloadInfo(map);
			if (localInfo.Status == MapDownloadStatus.UpToDate)
			{
				done(null, Text("地图已经是最新版本", "This map is already up to date"));
				yield break;
			}
			if ((localInfo.Status == MapDownloadStatus.LocalModified || localInfo.Status == MapDownloadStatus.UpdateAvailable) && !allowOverwriteLocalChanges)
			{
				done(null, (localInfo.Status == MapDownloadStatus.LocalModified) ? Text("本地 JSON 已被修改,请确认覆盖", "The local JSON was modified; confirm overwrite") : Text("发现地图新版本,请确认更新", "A newer map version is available; confirm update"));
				yield break;
			}
			UnityWebRequest request = UnityWebRequest.Get(map.download_url);
			try
			{
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					done(null, Text("下载失败: ", "Download failed: ") + ErrorText(request));
					yield break;
				}
				try
				{
					string saved = MapSaveService.SaveDownloadedMap(map, request.downloadHandler.data, allowOverwriteLocalChanges);
					done(saved, null);
				}
				catch (MapSaveException ex)
				{
					done(null, (ex.Status == MapDownloadStatus.LocalModified) ? Text("本地 JSON 已被修改,请确认覆盖", "The local JSON was modified; confirm overwrite") : (Text("保存失败: ", "Save failed: ") + ex.Message));
				}
				catch (Exception ex2)
				{
					done(null, Text("保存失败: ", "Save failed: ") + ex2.Message);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator UploadMapRoutine(string mapName, string author, string version, string description, string jsonPath, string imagePath, Action<string> done)
		{
			List<IMultipartFormSection> form;
			string error = BuildMapForm(mapName, author, version, description, jsonPath, imagePath, jsonOptional: false, out form);
			if (!string.IsNullOrEmpty(error))
			{
				done(error);
				yield break;
			}
			UnityWebRequest request = UnityWebRequest.Post(_baseUrl + "/api/upload", form);
			try
			{
				ApplySessionHeaders(request);
				_log.LogInfo((object)("Sending upload request to " + _baseUrl + "/api/upload"));
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					string body = Body(request);
					_log.LogWarning((object)("Upload request failed. Code=" + request.responseCode + ", error=" + request.error + ", body=" + body));
					done(Text("上传失败: ", "Upload failed: ") + ((!string.IsNullOrEmpty(body)) ? ExtractError(body) : ErrorText(request)));
					yield break;
				}
				_log.LogInfo((object)("Upload request succeeded. Code=" + request.responseCode));
				done(null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator UpdateMapRoutine(string mapId, string mapName, string author, string version, string description, string jsonPath, string imagePath, bool removeImage, Action<string> done)
		{
			if (!IsSignedIn)
			{
				done(Text("请先登录", "Please sign in first"));
				yield break;
			}
			if (string.IsNullOrEmpty(mapId))
			{
				done(Text("地图缺少 ID", "Map is missing an ID"));
				yield break;
			}
			List<IMultipartFormSection> form;
			string error = BuildMapForm(mapName, author, version, description, jsonPath, imagePath, jsonOptional: true, out form);
			if (!string.IsNullOrEmpty(error))
			{
				done(error);
				yield break;
			}
			form.Add((IMultipartFormSection)new MultipartFormDataSection("remove_image", removeImage ? "true" : "false"));
			UnityWebRequest request = UnityWebRequest.Post(_baseUrl + "/api/maps/" + Escape(mapId), form);
			try
			{
				request.method = "PUT";
				ApplySessionHeaders(request);
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					done(Text("保存失败: ", "Save failed: ") + ExtractError(Body(request), ErrorText(request)));
					yield break;
				}
				done(null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator DeleteMapRoutine(string mapId, Action<string> done)
		{
			if (!IsSignedIn)
			{
				done(Text("请先登录", "Please sign in first"));
				yield break;
			}
			if (string.IsNullOrEmpty(mapId))
			{
				done(Text("地图缺少 ID", "Map is missing an ID"));
				yield break;
			}
			UnityWebRequest request = UnityWebRequest.Delete(_baseUrl + "/api/maps/" + Escape(mapId));
			try
			{
				ApplySessionHeaders(request);
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					done(Text("删除失败: ", "Delete failed: ") + ExtractError(Body(request), ErrorText(request)));
					yield break;
				}
				done(null);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator DownloadTextureRoutine(string url, Action<Texture2D> done)
		{
			if (string.IsNullOrEmpty(url))
			{
				done(null);
				yield break;
			}
			UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
			try
			{
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					_log.LogWarning((object)("Thumbnail failed: " + request.error));
					done(null);
					yield break;
				}
				MapImageCache.Save(url, request.downloadHandler.data);
				done(DownloadHandlerTexture.GetContent(request));
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private IEnumerator LoadCachedTextureRoutine(string url, string path, Action<Texture2D> done)
		{
			string fileUrl;
			try
			{
				fileUrl = new Uri(path).AbsoluteUri;
			}
			catch
			{
				MapImageCache.Remove(url);
				fileUrl = null;
			}
			if (string.IsNullOrEmpty(fileUrl))
			{
				yield return _runner.StartCoroutine(DownloadTextureRoutine(url, done));
				yield break;
			}
			UnityWebRequest request = UnityWebRequestTexture.GetTexture(fileUrl);
			try
			{
				yield return request.SendWebRequest();
				if (HasError(request))
				{
					_log.LogWarning((object)("Cached thumbnail failed, downloading again: " + request.error));
					MapImageCache.Remove(url);
					yield return _runner.StartCoroutine(DownloadTextureRoutine(url, done));
					yield break;
				}
				done(DownloadHandlerTexture.GetContent(request));
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		private string BuildMapForm(string mapName, string author, string version, string description, string jsonPath, string imagePath, bool jsonOptional, out List<IMultipartFormSection> form)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Expected O, but got Unknown
			form = new List<IMultipartFormSection>();
			if (string.IsNullOrWhiteSpace(mapName) || string.IsNullOrWhiteSpace(author) || string.IsNullOrWhiteSpace(version))
			{
				return Text("地图名称、作者和版本不能为空", "Map name, author, and version are required");
			}
			if (!jsonOptional && (string.IsNullOrEmpty(jsonPath) || !File.Exists(jsonPath)))
			{
				return Text("请选择本地 JSON 地图文件", "Please select a local JSON map file");
			}
			form.Add((IMultipartFormSection)new MultipartFormDataSection("name", mapName.Trim()));
			form.Add((IMultipartFormSection)new MultipartFormDataSection("author", author.Trim()));
			form.Add((IMultipartFormSection)new MultipartFormDataSection("mod_version", version.Trim()));
			form.Add((IMultipartFormSection)new MultipartFormDataSection("description", (description == null) ? string.Empty : description.Trim()));
			if (!string.IsNullOrEmpty(jsonPath) && File.Exists(jsonPath))
			{
				form.Add((IMultipartFormSection)new MultipartFormFileSection("json_file", File.ReadAllBytes(jsonPath), Path.GetFileName(jsonPath), "application/json"));
			}
			if (!string.IsNullOrEmpty(imagePath) && File.Exists(imagePath))
			{
				object obj;
				switch (Path.GetExtension(imagePath).ToLowerInvariant())
				{
				default:
					obj = "image/png";
					break;
				case ".gif":
					obj = "image/gif";
					break;
				case ".webp":
					obj = "image/webp";
					break;
				case ".jpg":
				case ".jpeg":
					obj = "image/jpeg";
					break;
				}
				string text = (string)obj;
				form.Add((IMultipartFormSection)new MultipartFormFileSection("image_file", File.ReadAllBytes(imagePath), Path.GetFileName(imagePath), text));
			}
			return null;
		}

		private UnityWebRequest JsonRequest(string url, string method, string json)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			byte[] bytes = Encoding.UTF8.GetBytes(json ?? "{}");
			UnityWebRequest val = new UnityWebRequest(url, method);
			val.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes);
			val.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
			val.SetRequestHeader("Content-Type", "application/json; charset=utf-8");
			val.SetRequestHeader("Accept", "application/json");
			return val;
		}

		private void ApplySessionHeaders(UnityWebRequest request)
		{
			if (request != null && Session != null)
			{
				if (!string.IsNullOrEmpty(Session.access_token))
				{
					request.SetRequestHeader("Authorization", "Bearer " + Session.access_token);
				}
				if (!string.IsNullOrEmpty(Session.guest_id))
				{
					request.SetRequestHeader("Cookie", "peak_guest_id=" + Session.guest_id);
				}
			}
		}

		private void CaptureGuestCookie(UnityWebRequest request)
		{
			if (request == null || Session == null)
			{
				return;
			}
			string responseHeader = request.GetResponseHeader("Set-Cookie");
			if (string.IsNullOrEmpty(responseHeader))
			{
				return;
			}
			int num = responseHeader.IndexOf("peak_guest_id=", StringComparison.OrdinalIgnoreCase);
			if (num >= 0)
			{
				num += "peak_guest_id=".Length;
				int num2 = responseHeader.IndexOf(';', num);
				string text = ((num2 >= 0) ? responseHeader.Substring(num, num2 - num) : responseHeader.Substring(num));
				if (!string.IsNullOrEmpty(text) && !string.Equals(Session.guest_id, text, StringComparison.Ordinal))
				{
					Session.guest_id = text;
					PeakMapSessionStore.Save(Session, _log);
				}
			}
		}

		private void ApplyAuthResponse(AuthResponse response)
		{
			if (Session == null)
			{
				Session = new PeakMapSession();
			}
			Session.access_token = response.access_token;
			Session.refresh_token = response.refresh_token;
			Session.expires_at = response.expires_at;
			if (response.user != null)
			{
				Session.user_id = response.user.id;
				Session.email = response.user.email;
				Session.nickname = response.user.nickname;
			}
			PeakMapSessionStore.Save(Session, _log);
		}

		private T Parse<T>(string json) where T : class
		{
			try
			{
				return JsonConvert.DeserializeObject<T>(json);
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("API JSON parse failed: " + ex.Message));
				return null;
			}
		}

		private static bool HasError(UnityWebRequest request)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			return (int)request.result != 1;
		}

		private static string Body(UnityWebRequest request)
		{
			return (request != null && request.downloadHandler != null) ? request.downloadHandler.text : string.Empty;
		}

		private static string ErrorText(UnityWebRequest request)
		{
			return (request != null && !string.IsNullOrEmpty(request.error)) ? request.error : ("HTTP " + ((request != null) ? request.responseCode.ToString() : "0"));
		}

		private static string ResponseError(MapsResponse response, string fallback)
		{
			return (response != null && !string.IsNullOrEmpty(response.error_message)) ? response.error_message : ((response != null && !string.IsNullOrEmpty(response.error)) ? response.error : fallback);
		}

		private static string ResponseError(ModVersionsResponse response, string fallback)
		{
			return (response != null && !string.IsNullOrEmpty(response.error_message)) ? response.error_message : ((response != null && !string.IsNullOrEmpty(response.error)) ? response.error : fallback);
		}

		private static string ResponseError(AuthResponse response, string fallback)
		{
			return (response != null && !string.IsNullOrEmpty(response.error_message)) ? response.error_message : ((response != null && !string.IsNullOrEmpty(response.error)) ? response.error : fallback);
		}

		private static string ResponseError(BasicResponse response, string fallback)
		{
			return (response != null && !string.IsNullOrEmpty(response.error_message)) ? response.error_message : ((response != null && !string.IsNullOrEmpty(response.error)) ? response.error : fallback);
		}

		private static string ResponseError(LikeResponse response, string fallback)
		{
			return (response != null && !string.IsNullOrEmpty(response.error_message)) ? response.error_message : ((response != null && !string.IsNullOrEmpty(response.error)) ? response.error : fallback);
		}

		private string ExtractError(string json)
		{
			return ExtractError(json, Text("服务器错误", "Server error"));
		}

		private string ExtractError(string json, string fallback)
		{
			BasicResponse basicResponse = Parse<BasicResponse>(json);
			if (basicResponse != null)
			{
				if (!string.IsNullOrEmpty(basicResponse.error_message))
				{
					return basicResponse.error_message;
				}
				if (!string.IsNullOrEmpty(basicResponse.error))
				{
					return basicResponse.error;
				}
			}
			return string.IsNullOrEmpty(json) ? fallback : json;
		}

		private static string Escape(string value)
		{
			return UnityWebRequest.EscapeURL(value ?? string.Empty);
		}

		private string Text(string zh, string en)
		{
			return string.Equals(_language, "en", StringComparison.OrdinalIgnoreCase) ? en : zh;
		}
	}
	internal static class PeakMapLanguage
	{
		public static string Resolve(string mode, ManualLogSource log)
		{
			return ResolveDetailed(mode, log).Language;
		}

		public static PeakMapLanguageResult ResolveDetailed(string mode, ManualLogSource log)
		{
			//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_00b6: Unknown result type (might be due to invalid IL or missing references)
			string text = NormalizeMode(mode);
			if (text == "zh" || text == "en")
			{
				return new PeakMapLanguageResult(text, "Config", text, text);
			}
			if (TryGetGameLocalizedTextLanguage(out var language))
			{
				return new PeakMapLanguageResult(IsChineseGameLanguage(language) ? "zh" : "en", "Game.LocalizedText.CURRENT_LANGUAGE", language, text);
			}
			if (TryGetUnityLocalizationCode(out var code, out var source))
			{
				return new PeakMapLanguageResult(IsChineseCode(code) ? "zh" : "en", source, code, text);
			}
			string rawValue = ((object)Application.systemLanguage/*cast due to .constrained prefix*/).ToString();
			return new PeakMapLanguageResult(IsChineseSystemLanguage(Application.systemLanguage) ? "zh" : "en", "SystemLanguageFallback", rawValue, text);
		}

		public static string NormalizeMode(string mode)
		{
			if (string.IsNullOrWhiteSpace(mode))
			{
				return "auto";
			}
			string text = mode.Trim().ToLowerInvariant();
			switch (text)
			{
			default:
				if (!(text == "chinese"))
				{
					if (text == "en" || text == "en-us" || text == "english")
					{
						return "en";
					}
					return "auto";
				}
				goto case "zh";
			case "zh":
			case "cn":
			case "zh-cn":
				return "zh";
			}
		}

		private static bool TryGetUnityLocalizationCode(out string code, out string source)
		{
			code = null;
			source = null;
			try
			{
				Type type = Type.GetType("UnityEngine.Localization.Settings.LocalizationSettings, Unity.Localization");
				if (type == null)
				{
					return false;
				}
				PropertyInfo property = type.GetProperty("SelectedLocale", BindingFlags.Static | BindingFlags.Public);
				object locale = ((property != null) ? property.GetValue(null, null) : null);
				if (TryExtractLocaleCode(locale, out code))
				{
					source = "UnityLocalization.SelectedLocale";
					return true;
				}
				PropertyInfo property2 = type.GetProperty("SelectedLocaleAsync", BindingFlags.Static | BindingFlags.Public);
				object selectedLocaleAsync = ((property2 != null) ? property2.GetValue(null, null) : null);
				if (TryExtractAsyncLocaleCode(selectedLocaleAsync, out code))
				{
					source = "UnityLocalization.SelectedLocaleAsync";
					return true;
				}
				MethodInfo method = type.GetMethod("GetSelectedLocale", BindingFlags.Static | BindingFlags.Public);
				object locale2 = ((method != null) ? method.Invoke(null, null) : null);
				if (TryExtractLocaleCode(locale2, out code))
				{
					source = "UnityLocalization.GetSelectedLocale";
					return true;
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		private static bool TryGetGameLocalizedTextLanguage(out string language)
		{
			language = null;
			try
			{
				Type type = FindType("LocalizedText", "Assembly-CSharp");
				if (type == null)
				{
					return false;
				}
				FieldInfo field = type.GetField("CURRENT_LANGUAGE", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				object obj = ((field != null) ? field.GetValue(null) : null);
				if (obj == null)
				{
					return false;
				}
				language = obj.ToString();
				if (string.IsNullOrWhiteSpace(language))
				{
					language = Convert.ToInt32(obj).ToString();
				}
				return !string.IsNullOrWhiteSpace(language);
			}
			catch
			{
				return false;
			}
		}

		private static bool TryExtractAsyncLocaleCode(object selectedLocaleAsync, out string code)
		{
			code = null;
			if (selectedLocaleAsync == null)
			{
				return false;
			}
			try
			{
				PropertyInfo property = selectedLocaleAsync.GetType().GetProperty("IsDone", BindingFlags.Instance | BindingFlags.Public);
				object obj = ((property != null) ? property.GetValue(selectedLocaleAsync, null) : null);
				if (obj is bool && !(bool)obj)
				{
					return false;
				}
				PropertyInfo property2 = selectedLocaleAsync.GetType().GetProperty("Result", BindingFlags.Instance | BindingFlags.Public);
				object locale = ((property2 != null) ? property2.GetValue(selectedLocaleAsync, null) : null);
				return TryExtractLocaleCode(locale, out code);
			}
			catch
			{
				return false;
			}
		}

		private static bool TryExtractLocaleCode(object locale, out string code)
		{
			code = null;
			if (locale == null)
			{
				return false;
			}
			try
			{
				PropertyInfo property = locale.GetType().GetProperty("Identifier", BindingFlags.Instance | BindingFlags.Public);
				object obj = ((property != null) ? property.GetValue(locale, null) : null);
				if (obj != null)
				{
					PropertyInfo property2 = obj.GetType().GetProperty("Code", BindingFlags.Instance | BindingFlags.Public);
					object obj2 = ((property2 != null) ? property2.GetValue(obj, null) : null);
					if (obj2 != null && !string.IsNullOrWhiteSpace(obj2.ToString()))
					{
						code = obj2.ToString();
						return true;
					}
				}
				PropertyInfo property3 = locale.GetType().GetProperty("LocaleName", BindingFlags.Instance | BindingFlags.Public);
				object obj3 = ((property3 != null) ? property3.GetValue(locale, null) : null);
				if (obj3 != null && !string.IsNullOrWhiteSpace(obj3.ToString()))
				{
					code = obj3.ToString();
					return true;
				}
				string text = locale.ToString();
				if (!string.IsNullOrWhiteSpace(text))
				{
					code = text;
					return true;
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		private static Type FindType(string typeName, string assemblyName)
		{
			Type type = Type.GetType(typeName + ", " + assemblyName);
			if (type != null)
			{
				return type;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				AssemblyName name = assemblies[i].GetName();
				if (string.Equals(name.Name, assemblyName, StringComparison.OrdinalIgnoreCase))
				{
					Type type2 = assemblies[i].GetType(typeName, throwOnError: false);
					if (type2 != null)
					{
						return type2;
					}
				}
			}
			return null;
		}

		private static bool IsChineseCode(string code)
		{
			return !string.IsNullOrWhiteSpace(code) && code.Trim().StartsWith("zh", StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsChineseGameLanguage(string language)
		{
			if (string.IsNullOrWhiteSpace(language))
			{
				return false;
			}
			string a = language.Trim();
			return string.Equals(a, "SimplifiedChinese", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "Chinese", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "ChineseSimplified", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "9", StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsChineseSystemLanguage(SystemLanguage language)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			return (int)language == 6 || (int)language == 40 || (int)language == 41;
		}
	}
	internal sealed class PeakMapLanguageResult
	{
		public readonly string Language;

		public readonly string Source;

		public readonly string RawValue;

		public readonly string Mode;

		public PeakMapLanguageResult(string language, string source, string rawValue, string mode)
		{
			Language = language;
			Source = source;
			RawValue = rawValue;
			Mode = mode;
		}
	}
	internal static class PeakMapSessionStore
	{
		private sealed class PersistedSession
		{
			public int version;

			public string protected_refresh_token;

			public string user_id;

			public string email;

			public string nickname;

			public string guest_id;
		}

		private static readonly byte[] Entropy = Encoding.UTF8.GetBytes("com.wuyachiyu.peakmapbrowser.session.v2");

		private static string DirectoryPath => Path.Combine(Application.persistentDataPath, "PeakMapBrowser");

		private static string FilePath => Path.Combine(DirectoryPath, "session.json");

		public static PeakMapSession Load(ManualLogSource log)
		{
			try
			{
				if (!File.Exists(FilePath))
				{
					return new PeakMapSession();
				}
				string text = File.ReadAllText(FilePath);
				PersistedSession persistedSession = JsonConvert.DeserializeObject<PersistedSession>(text);
				if (persistedSession != null && persistedSession.version >= 2)
				{
					PeakMapSession peakMapSession = new PeakMapSession
					{
						user_id = persistedSession.user_id,
						email = persistedSession.email,
						nickname = persistedSession.nickname,
						guest_id = persistedSession.guest_id
					};
					if (!string.IsNullOrEmpty(persistedSession.protected_refresh_token))
					{
						peakMapSession.refresh_token = Unprotect(persistedSession.protected_refresh_token);
					}
					return peakMapSession;
				}
				PeakMapSession peakMapSession2 = JsonConvert.DeserializeObject<PeakMapSession>(text);
				if (peakMapSession2 != null)
				{
					Save(peakMapSession2, log);
					return peakMapSession2;
				}
				return new PeakMapSession();
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Failed to load PeakMapBrowser session: " + ex.Message));
				return new PeakMapSession();
			}
		}

		public static void Save(PeakMapSession session, ManualLogSource log)
		{
			try
			{
				Directory.CreateDirectory(DirectoryPath);
				PeakMapSession peakMapSession = session ?? new PeakMapSession();
				PersistedSession persistedSession = new PersistedSession
				{
					version = 2,
					protected_refresh_token = (string.IsNullOrEmpty(peakMapSession.refresh_token) ? string.Empty : Protect(peakMapSession.refresh_token)),
					user_id = (peakMapSession.user_id ?? string.Empty),
					email = (peakMapSession.email ?? string.Empty),
					nickname = (peakMapSession.nickname ?? string.Empty),
					guest_id = (peakMapSession.guest_id ?? string.Empty)
				};
				string text = FilePath + ".tmp-" + Guid.NewGuid().ToString("N");
				try
				{
					File.WriteAllText(text, JsonConvert.SerializeObject((object)persistedSession, (Formatting)1), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
					if (File.Exists(FilePath))
					{
						File.Replace(text, FilePath, null);
					}
					else
					{
						File.Move(text, FilePath);
					}
				}
				finally
				{
					if (File.Exists(text))
					{
						File.Delete(text);
					}
				}
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("Failed to save PeakMapBrowser session: " + ex.Message));
			}
		}

		public static void ClearUser(PeakMapSession session, ManualLogSource log)
		{
			if (session == null)
			{
				session = new PeakMapSession();
			}
			session.access_token = string.Empty;
			session.refresh_token = string.Empty;
			session.expires_at = 0L;
			session.user_id = string.Empty;
			session.email = string.Empty;
			session.nickname = string.Empty;
			Save(session, log);
		}

		private static string Protect(string value)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(value ?? string.Empty);
			byte[] inArray = ProtectedData.Protect(bytes, Entropy, (DataProtectionScope)0);
			return Convert.ToBase64String(inArray);
		}

		private static string Unprotect(string value)
		{
			byte[] array = Convert.FromBase64String(value);
			byte[] bytes = ProtectedData.Unprotect(array, Entropy, (DataProtectionScope)0);
			return Encoding.UTF8.GetString(bytes);
		}
	}
	internal sealed class PeakMapWindow
	{
		private readonly MonoBehaviour _runner;

		private readonly ManualLogSource _log;

		private readonly PeakMapApiClient _api;

		private readonly int _pageSize;

		private readonly Dictionary<string, Texture2D> _thumbnails = new Dictionary<string, Texture2D>();

		private readonly Dictionary<string, MapDownloadInfo> _downloadInfoCache = new Dictionary<string, MapDownloadInfo>();

		private bool _visible;

		private bool _cursorCaptured;

		private bool _previousCursorVisible;

		private CursorLockMode _previousCursorLockMode;

		private GameObject _inputBlocker;

		private bool _stylesReady;

		private bool _loadingMaps;

		private bool _loadingVersions;

		private bool _downloading;

		private bool _uploading;

		private bool _liking;

		private bool _uploadOpen;

		private bool _loginOpen;

		private bool _accountOpen;

		private bool _communityDetailOpen;

		private bool _downloadConfirmOpen;

		private bool _loadingAccountMaps;

		private bool _savingAccountMap;

		private bool _deletingAccountMap;

		private bool _refreshingSession;

		private bool _loadedOnce;

		private int _topLayerOpenedFrame = -1;

		private float _nextSessionRefreshCheckTime;

		private Rect _windowRect;

		private Vector2 _mapScroll;

		private Vector2 _uploadSaveScroll;

		private Vector2 _detailScroll;

		private Vector2 _accountScroll;

		private Vector2 _accountDescriptionScroll;

		private List<MapEntry> _maps = new List<MapEntry>();

		private List<MapEntry> _accountMaps = new List<MapEntry>();

		private List<ModVersionEntry> _versions = new List<ModVersionEntry>();

		private PaginationInfo _pagination;

		private int _selectedMapIndex;

		private int _selectedAccountMapIndex = -1;

		private int _page = 1;

		private string _query = string.Empty;

		private string _sort = "newest";

		private string _versionFilter = string.Empty;

		private string _languageMode;

		private string _language;

		private string _languageSource;

		private string _languageRawValue;

		private string _toggleKeyLabel;

		private float _nextLanguageCheckTime;

		private string _status = string.Empty;

		private string _toast = string.Empty;

		private float _toastUntil;

		private float _downloadInfoCacheUntil;

		private string[] _localSaves = new string[0];

		private readonly List<int> _filteredLocalSaveIndexes = new List<int>();

		private int _selectedLocalSave;

		private string _localSaveFilter = string.Empty;

		private string _localSaveError = string.Empty;

		private float _nextLocalSaveScanTime;

		private int _selectedUploadVersion;

		private bool _uploadVersionDropdownOpen;

		private Vector2 _uploadVersionScroll;

		private bool _uploadSaveDropdownOpen;

		private string[] _localImages = new string[0];

		private readonly List<int> _filteredLocalImageIndexes = new List<int>();

		private int _selectedLocalImage = -1;

		private string _localImageFilter = string.Empty;

		private string _localImageError = string.Empty;

		private bool _uploadImageDropdownOpen;

		private Vector2 _uploadImageScroll;

		private bool _imagePickerOpen;

		private string[] _imageRootPaths = new string[0];

		private int _imagePickerRootIndex;

		private string _imagePickerDirectory = string.Empty;

		private string[] _imagePickerDirs = new string[0];

		private string[] _imagePickerFiles = new string[0];

		private string _imagePickerSelected = string.Empty;

		private string _imagePickerError = string.Empty;

		private Vector2 _imagePickerScroll;

		private string _uploadName = string.Empty;

		private string _uploadAuthor = string.Empty;

		private string _uploadDescription = string.Empty;

		private string _loginEmail = string.Empty;

		private string _loginPassword = string.Empty;

		private string _editName = string.Empty;

		private string _editAuthor = string.Empty;

		private string _editVersion = string.Empty;

		private string _editDescription = string.Empty;

		private bool _editReplaceJson;

		private bool _accountJsonDropdownOpen;

		private bool _accountVersionDropdownOpen;

		private Vector2 _accountVersionScroll;

		private bool _editReplaceImage;

		private bool _editRemoveImage;

		private string _deleteConfirmMapId = string.Empty;

		private string _downloadConfirmMapId = string.Empty;

		private GUIStyle _rootStyle;

		private GUIStyle _panelStyle;

		private GUIStyle _panelStrongStyle;

		private GUIStyle _detailMetaStyle;

		private GUIStyle _detailDescriptionStyle;

		private GUIStyle _cardStyle;

		private GUIStyle _buttonStyle;

		private GUIStyle _primaryButtonStyle;

		private GUIStyle _iconButtonStyle;

		private GUIStyle _inputStyle;

		private GUIStyle _textAreaStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _h2Style;

		private GUIStyle _labelStyle;

		private GUIStyle _statLabelStyle;

		private GUIStyle _statValueStyle;

		private GUIStyle _cardStatsStyle;

		private GUIStyle _mutedStyle;

		private GUIStyle _cardDescStyle;

		private GUIStyle _detailTextStyle;

		private GUIStyle _detailTitleStyle;

		private GUIStyle _tinyStyle;

		private GUIStyle _badgeStyle;

		private GUIStyle _apiBadgeStyle;

		private GUIStyle _pagePillStyle;

		private GUIStyle _toastStyle;

		private GUIStyle _thumbStyle;

		private GUIStyle _sidebarButtonStyle;

		private GUIStyle _sidebarSelectedStyle;

		private GUIStyle _statBoxStyle;

		private GUIStyle _modalBackdropStyle;

		private GUIStyle _dangerStyle;

		private Texture2D _placeholderThumb;

		private Font _uiFont;

		private string SelectedLocalSavePath => (_selectedLocalSave >= 0 && _selectedLocalSave < _localSaves.Length) ? _localSaves[_selectedLocalSave] : null;

		private string SelectedLocalImagePath => (_selectedLocalImage >= 0 && _selectedLocalImage < _localImages.Length) ? _localImages[_selectedLocalImage] : null;

		private MapEntry SelectedMap => (_maps != null && _maps.Count > 0 && _selectedMapIndex >= 0 && _selectedMapIndex < _maps.Count) ? _maps[_selectedMapIndex] : null;

		private MapEntry SelectedAccountMap => (_accountMaps != null && _accountMaps.Count > 0 && _selectedAccountMapIndex >= 0 && _selectedAccountMapIndex < _accountMaps.Count) ? _accountMaps[_selectedAccountMapIndex] : null;

		public PeakMapWindow(MonoBehaviour runner, ManualLogSource log, string apiBaseUrl, string language, int pageSize, string toggleKeyLabel)
		{
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			_runner = runner;
			_log = log;
			_toggleKeyLabel = (string.IsNullOrWhiteSpace(toggleKeyLabel) ? "/" : toggleKeyLabel);
			_languageMode = language;
			PeakMapLanguageResult peakMapLanguageResult = PeakMapLanguage.ResolveDetailed(language, log);
			_language = peakMapLanguageResult.Language;
			_languageSource = peakMapLanguageResult.Source;
			_languageRawValue = peakMapLanguageResult.RawValue;
			_api = new PeakMapApiClient(runner, log, apiBaseUrl, _language);
			_pageSize = pageSize;
			_windowRect = new Rect(0f, 0f, 960f, 640f);
			_status = T("按 " + _toggleKeyLabel + " 打开或关闭地图库", "Press " + _toggleKeyLabel + " to open or close the map browser");
			_log.LogInfo((object)("PEAK Map Browser language resolved: lang=" + _language + ", mode=" + peakMapLanguageResult.Mode + ", source=" + _languageSource + ", raw=" + _languageRawValue));
		}

		public void Toggle()
		{
			SetVisible(!_visible);
			if (_visible && !_loadedOnce)
			{
				RefreshAll();
			}
		}

		private void SetVisible(bool visible)
		{
			if (_visible != visible)
			{
				_visible = visible;
				if (visible)
				{
					_log.LogInfo((object)"Map browser opened.");
					CaptureCursor();
					EnsureInputBlocker();
					return;
				}
				_log.LogInfo((object)"Map browser closed.");
				RestoreCursor();
				SetInputBlockerActive(active: false);
				_uploadOpen = false;
				_imagePickerOpen = false;
				_loginOpen = false;
				_accountOpen = false;
				_communityDetailOpen = false;
				_uploadVersionDropdownOpen = false;
				_uploadImageDropdownOpen = false;
				_uploadSaveDropdownOpen = false;
			}
		}

		private void CaptureCursor()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!_cursorCaptured)
			{
				_previousCursorVisible = Cursor.visible;
				_previousCursorLockMode = Cursor.lockState;
				_cursorCaptured = true;
			}
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)0;
		}

		private void RestoreCursor()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (_cursorCaptured)
			{
				Cursor.visible = _previousCursorVisible;
				Cursor.lockState = _previousCursorLockMode;
				_cursorCaptured = false;
			}
		}

		private void EnsureInputBlocker()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_inputBlocker == (Object)null)
			{
				_inputBlocker = new GameObject("PeakMapBrowser_InputBlocker");
				Object.DontDestroyOnLoad((Object)(object)_inputBlocker);
				Canvas val = _inputBlocker.AddComponent<Canvas>();
				val.renderMode = (RenderMode)0;
				val.sortingOrder = 32767;
				_inputBlocker.AddComponent<GraphicRaycaster>();
				GameObject val2 = new GameObject("Blocker");
				val2.transform.SetParent(_inputBlocker.transform, false);
				Image val3 = val2.AddComponent<Image>();
				((Graphic)val3).color = new Color(0f, 0f, 0f, 0f);
				((Graphic)val3).raycastTarget = true;
				RectTransform rectTransform = ((Graphic)val3).rectTransform;
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.offsetMin = Vector2.zero;
				rectTransform.offsetMax = Vector2.zero;
			}
			SetInputBlockerActive(active: true);
		}

		private void SetInputBlockerActive(bool active)
		{
			if ((Object)(object)_inputBlocker != (Object)null && _inputBlocker.activeSelf != active)
			{
				_inputBlocker.SetActive(active);
			}
		}

		public void Update()
		{
			RefreshLanguageIfNeeded();
			RefreshSessionIfNeeded();
			if (_visible)
			{
				CaptureCursor();
				EnsureInputBlocker();
				Input.ResetInputAxes();
			}
		}

		private void RefreshLanguageIfNeeded()
		{
			if (Time.unscaledTime < _nextLanguageCheckTime)
			{
				return;
			}
			_nextLanguageCheckTime = Time.unscaledTime + 2f;
			PeakMapLanguageResult peakMapLanguageResult = PeakMapLanguage.ResolveDetailed(_languageMode, _log);
			bool flag = !string.Equals(peakMapLanguageResult.Language, _language, StringComparison.OrdinalIgnoreCase);
			bool flag2 = !string.Equals(peakMapLanguageResult.Source, _languageSource, StringComparison.Ordinal) || !string.Equals(peakMapLanguageResult.RawValue, _languageRawValue, StringComparison.Ordinal);
			if (flag || flag2)
			{
				string language = _language;
				string languageSource = _languageSource;
				string languageRawValue = _languageRawValue;
				_language = peakMapLanguageResult.Language;
				_languageSource = peakMapLanguageResult.Source;
				_languageRawValue = peakMapLanguageResult.RawValue;
				if (flag)
				{
					_api.SetLanguage(_language);
					_status = T("语言已切换为中文", "Language switched to English");
					ShowToast(_status);
				}
				_log.LogInfo((object)("PEAK Map Browser language resolved: lang=" + _language + ", mode=" + peakMapLanguageResult.Mode + ", source=" + _languageSource + ", raw=" + _languageRawValue + " (previous lang=" + language + ", source=" + languageSource + ", raw=" + languageRawValue + ")"));
			}
		}

		public void Dispose()
		{
			SetVisible(visible: false);
			if ((Object)(object)_inputBlocker != (Object)null)
			{
				Object.Destroy((Object)(object)_inputBlocker);
				_inputBlocker = null;
			}
		}

		public void Draw()
		{
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			if (!_visible)
			{
				return;
			}
			Color color = GUI.color;
			Color contentColor = GUI.contentColor;
			Color backgroundColor = GUI.backgroundColor;
			bool enabled = GUI.enabled;
			int depth = GUI.depth;
			GUI.color = Color.white;
			GUI.contentColor = Color.white;
			GUI.backgroundColor = Color.white;
			GUI.enabled = true;
			try
			{
				EnsureStyles();
				CenterWindow();
				GUI.depth = -100;
				DrawDimBackground();
				DrawSolidBackground(_windowRect, new Color(0.01f, 0.016f, 0.012f, 1f));
				GUI.Box(_windowRect, GUIContent.none, _rootStyle);
				bool flag = _communityDetailOpen || _downloadConfirmOpen;
				bool enabled2 = GUI.enabled;
				if (flag)
				{
					GUI.enabled = false;
				}
				if (!_uploadOpen && !_imagePickerOpen && !_loginOpen)
				{
					DrawHeader();
					DrawSidebar();
					if (_accountOpen)
					{
						DrawAccountPage();
					}
					else
					{
						DrawContent();
					}
					DrawFooter();
				}
				GUI.enabled = enabled2;
				if (_communityDetailOpen && !_downloadConfirmOpen && !_imagePickerOpen && !_loginOpen && !_uploadOpen)
				{
					DrawCommunityDetailModal();
				}
				if (_downloadConfirmOpen && !_imagePickerOpen && !_loginOpen && !_uploadOpen)
				{
					DrawDownloadConfirmModal();
				}
				if (_uploadOpen && !_imagePickerOpen)
				{
					DrawUploadModal();
				}
				if (_loginOpen && !_imagePickerOpen)
				{
					DrawLoginModal();
				}
				if (_imagePickerOpen)
				{
					DrawImagePickerModal();
				}
				DrawToast();
				ConsumeOverlayEvents();
			}
			finally
			{
				GUI.color = color;
				GUI.contentColor = contentColor;
				GUI.backgroundColor = backgroundColor;
				GUI.enabled = enabled;
				GUI.depth = depth;
			}
		}

		private void ConsumeOverlayEvents()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			Event current = Event.current;
			if (current != null && ((int)current.type == 0 || (int)current.type == 1 || (int)current.type == 3 || (int)current.type == 6))
			{
				current.Use();
			}
		}

		private void BlockTopLayerInputThisFrame()
		{
			_topLayerOpenedFrame = Time.frameCount;
		}

		private bool IsTopLayerInputBlocked()
		{
			return _topLayerOpenedFrame == Time.frameCount;
		}

		private void CenterWindow()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Round(Mathf.Min(1160f, (float)Screen.width - 24f));
			float num2 = Mathf.Round(Mathf.Min(720f, (float)Screen.height - 24f));
			_windowRect = new Rect(Mathf.Round(((float)Screen.width - num) * 0.5f), Mathf.Round(((float)Screen.height - num2) * 0.5f), num, num2);
		}

		private void DrawDimBackground()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			Color color = GUI.color;
			GUI.color = new Color(0f, 0f, 0f, 0.42f);
			GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color;
		}

		private void DrawSolidBackground(Rect rect, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Color color2 = GUI.color;
			GUI.color = color;
			GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture, (ScaleMode)0);
			GUI.color = color2;
		}

		private void DrawHeader()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Invalid comparison between Unknown and I4
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Invalid comparison between Unknown and I4
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref _windowRect)).x, ((Rect)(ref _windowRect)).y, ((Rect)(ref _windowRect)).width, 64f);
			GUI.Box(val, GUIContent.none, _panelStrongStyle);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(((Rect)(ref val)).x + 22f, ((Rect)(ref val)).y + 17f, 30f, 30f);
			GUI.Box(val2, GUIContent.none, _badgeStyle);
			GUI.Label(new Rect(((Rect)(ref val2)).x + 8f, ((Rect)(ref val2)).y - 2f, 22f, 28f), "/", _titleStyle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 62f, ((Rect)(ref val)).y + 11f, 190f, 16f), T("远征数据库", "EXPEDITION DATABASE"), _tinyStyle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 62f, ((Rect)(ref val)).y + 27f, 210f, 30f), T("PEAK 地图库", "PEAK Maps"), _titleStyle);
			float num = ((Rect)(ref val)).y + 17f;
			float num2 = 38f;
			float num3 = 118f;
			float num4 = 112f;
			float num5 = 38f;
			float num6 = 8f;
			float num7 = ((Rect)(ref val)).xMax - num2 - num4 - num3 - num5 - num6 * 4f - 22f;
			if (GUI.Button(new Rect(num7, num, num3, 34f), T("上传地图", "Upload"), _primaryButtonStyle))
			{
				OpenUpload();
			}
			num7 += num3 + num6;
			if (GUI.Button(new Rect(num7, num, num5, 34f), "↻", _iconButtonStyle))
			{
				RefreshAll();
			}
			num7 += num5 + num6;
			string text = (_api.IsSignedIn ? ShortAccountName(_api.Session.DisplayName) : T("登录", "Sign in"));
			if (GUI.Button(new Rect(num7, num, num4, 34f), text, _buttonStyle))
			{
				if (_api.IsSignedIn)
				{
					OpenAccount();
				}
				else
				{
					OpenLogin();
				}
			}
			num7 += num4 + num6;
			if (GUI.Button(new Rect(num7, num, num2, 34f), "×", _iconButtonStyle))
			{
				SetVisible(visible: false);
			}
			Event current = Event.current;
			if ((int)current.type == 4 && (int)current.keyCode == 13 && GUI.GetNameOfFocusedControl() == "PeakMapSearch")
			{
				_page = 1;
				FetchMaps();
				current.Use();
			}
		}

		private void DrawSidebar()
		{
			//IL_003a: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref _windowRect)).x, ((Rect)(ref _windowRect)).y + 64f, 230f, ((Rect)(ref _windowRect)).height - 92f);
			GUI.Box(val, GUIContent.none, _panelStyle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 24f, ((Rect)(ref val)).y + 22f, 160f, 16f), T("导航", "NAVIGATION"), _tinyStyle);
			float num = ((Rect)(ref val)).y + 58f;
			DrawNavButton(new Rect(((Rect)(ref val)).x + 22f, num, ((Rect)(ref val)).width - 44f, 42f), T("⌂  主页", "⌂  Home"), !_accountOpen, delegate
			{
				_accountOpen = false;
			});
			num += 50f;
			DrawNavButton(new Rect(((Rect)(ref val)).x + 22f, num, ((Rect)(ref val)).width - 44f, 42f), T("▣  我的地图", "▣  My Maps"), _accountOpen, delegate
			{
				if (_api.IsSignedIn)
				{
					OpenAccount();
				}
				else
				{
					OpenLogin();
				}
			});
			num += 50f;
			DrawNavButton(new Rect(((Rect)(ref val)).x + 22f, num, ((Rect)(ref val)).width - 44f, 42f), T("◎  社区地图", "◎  Database"), !_accountOpen, delegate
			{
				_accountOpen = false;
			});
			num += 50f;
			DrawNavButton(new Rect(((Rect)(ref val)).x + 22f, num, ((Rect)(ref val)).width - 44f, 42f), T("⚙  设置", "⚙  Settings"), selected: false, OpenAccountWebsite);
			if (GUI.Button(new Rect(((Rect)(ref val)).x + 22f, ((Rect)(ref val)).yMax - 84f, ((Rect)(ref val)).width - 44f, 40f), T("上传地图", "Upload Map"), _primaryButtonStyle))
			{
				OpenUpload();
			}
			if (_api.IsSignedIn && GUI.Button(new Rect(((Rect)(ref val)).x + 22f, ((Rect)(ref val)).yMax - 38f, ((Rect)(ref val)).width - 44f, 30f), T("退出登录", "Logout"), _buttonStyle))
			{
				_accountOpen = false;
				_api.SignOut(delegate(bool serverRevoked, string error)
				{
					_status = (string.IsNullOrEmpty(error) ? T("已退出登录", "Signed out") : T("已退出本地登录,但服务端撤销失败", "Signed out locally, but server revocation failed"));
					ShowToast(_status);
					FetchMaps();
				});
			}
		}

		private void DrawNavButton(Rect rect, string label, bool selected, Action clicked)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (GUI.Button(rect, label, selected ? _sidebarSelectedStyle : _sidebarButtonStyle))
			{
				clicked();
			}
		}

		private void DrawFooter()
		{
			//IL_0034: 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)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref _windowRect)).x, ((Rect)(ref _windowRect)).yMax - 28f, ((Rect)(ref _windowRect)).width, 28f);
			GUI.Box(val, GUIContent.none, _panelStrongStyle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 16f, ((Rect)(ref val)).y + 7f, 360f, 16f), T("● 在线   © 2024 PEAK 地图库", "● ONLINE   © 2024 PEAK MAP DATABASE"), _tinyStyle);
			GUI.Label(new Rect(((Rect)(ref val)).xMax - 360f, ((Rect)(ref val)).y + 7f, 340f, 16f), "API: peakmap.top", _mutedStyle);
		}

		private void DrawContent()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = default(Rect);
			((Rect)(ref rect))..ctor(((Rect)(ref _windowRect)).x + 248f, ((Rect)(ref _windowRect)).y + 84f, ((Rect)(ref _windowRect)).width - 270f, ((Rect)(ref _windowRect)).height - 128f);
			DrawMapList(rect);
		}

		private void DrawMapList(Rect rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			GUI.Box(rect, GUIContent.none, _panelStyle);
			string text = ((_pagination != null) ? _pagination.total.ToString() : ((_maps != null) ? _maps.Count.ToString() : "0"));
			GUI.Label(new Rect(((Rect)(ref rect)).x + 18f, ((Rect)(ref rect)).y + 16f, 260f, 16f), T("共 " + text + " 张地图", "TOTAL " + text + " MAPS FOUND"), _tinyStyle);
			GUI.Label(new Rect(((Rect)(ref rect)).x + 18f, ((Rect)(ref rect)).y + 32f, 260f, 34f), T("社区地图", "Community Maps"), _titleStyle);
			GUI.Label(new Rect(((Rect)(ref rect)).xMax - 142f, ((Rect)(ref rect)).y + 18f, 124f, 26f), "API: peakmap.top", _apiBadgeStyle);
			float num = ((Rect)(ref rect)).y + 72f;
			float num2 = 8f;
			float num3 = Mathf.Max(180f, ((Rect)(ref rect)).width - 36f - 96f - 92f - 104f - num2 * 3f);
			GUI.SetNextControlName("PeakMapSearch");
			string text2 = GUI.TextField(new Rect(((Rect)(ref rect)).x + 18f, num, num3, 34f), _query, _inputStyle);
			if (text2 != _query)
			{
				_query = text2;
			}
			float num4 = ((Rect)(ref rect)).x + 18f + num3 + num2;
			if (GUI.Button(new Rect(num4, num, 96f, 34f), ShortVersion(_versionFilter), _buttonStyle))
			{
				CycleVersionFilter();
			}
			num4 += 96f + num2;
			if (GUI.Button(new Rect(num4, num, 92f, 34f), (_sort == "downloads") ? T("下载量", "Popular") : T("最新", "Newest"), _buttonStyle))
			{
				_sort = ((_sort == "downloads") ? "newest" : "downloads");
				_page = 1;
				FetchMaps();
			}
			num4 += 92f + num2;
			if (GUI.Button(new Rect(num4, num, 104f, 34f), T("搜索", "Search"), _primaryButtonStyle))
			{
				_page = 1;
				FetchMaps();
			}
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref rect)).x + 18f, ((Rect)(ref rect)).y + 118f, ((Rect)(ref rect)).width - 36f, ((Rect)(ref rect)).height - 174f);
			if (_loadingMaps)
			{
				GUI.Label(val, T("正在从 peakmap.top 获取地图列表...", "Fetching maps from peakmap.top..."), _labelStyle);
			}
			else if (_maps == null || _maps.Count == 0)
			{
				GUI.Label(val, string.IsNullOrEmpty(_query) ? T("暂无地图。", "No maps yet.") : T("没有找到匹配的地图。", "No matching maps found."), _labelStyle);
			}
			else
			{
				DrawCards(val);
			}
			DrawPagination(new Rect(((Rect)(ref rect)).x + 18f, ((Rect)(ref rect)).yMax - 46f, ((Rect)(ref rect)).width - 36f, 34f));
		}

		private void DrawCards(Rect rect)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			int num = ((!(((Rect)(ref rect)).width > 560f)) ? 1 : 2);
			float num2 = 14f;
			float num3 = (((Rect)(ref rect)).width - (float)(num - 1) * num2 - 10f) / (float)num;
			float num4 = 290f;
			int num5 = Mathf.CeilToInt((float)_maps.Count / (float)num);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref rect)).width - 18f, (float)num5 * (num4 + num2));
			_mapScroll = GUI.BeginScrollView(rect, _mapScroll, val, false, true);
			Rect rect2 = default(Rect);
			for (int i = 0; i < _maps.Count; i++)
			{
				int num6 = i % num;
				int num7 = i / num;
				((Rect)(ref rect2))..ctor((float)num6 * (num3 + num2), (float)num7 * (num4 + num2), num3, num4);
				DrawCard(rect2, i, _maps[i]);
			}
			GUI.EndScrollView();
		}

		private void DrawCard(Rect rect, int index, MapEntry map)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: 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_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			bool flag = index == _selectedMapIndex;
			GUI.Box(rect, GUIContent.none, _cardStyle);
			if (flag)
			{
				DrawCardSelectionOutline(rect);
			}
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).y + 1f, ((Rect)(ref rect)).width - 2f, ((Rect)(ref rect)).height - 2f);
			Rect rect2 = default(Rect);
			((Rect)(ref rect2))..ctor(((Rect)(ref val)).x, ((Rect)(ref val)).y, ((Rect)(ref val)).width, 130f);
			DrawThumbnail(rect2, map);
			GUI.Label(new Rect(((Rect)(ref rect2)).x + 10f, ((Rect)(ref rect2)).y + 10f, 86f, 22f), ShortVersion(map.mod_version), _badgeStyle);
			if (map.revision > 1)
			{
				GUI.Label(new Rect(((Rect)(ref rect2)).xMax - 78f, ((Rect)(ref rect2)).y + 10f, 66f, 22f), "v" + map.revision, _badgeStyle);
			}
			float num = ((Rect)(ref val)).y + 146f;
			GUI.Label(new Rect(((Rect)(ref val)).x + 14f, num, ((Rect)(ref val)).width - 28f, 30f), CleanUiText(Safe(map.name, T("未命名地图", "Untitled map"))), _h2Style);
			GUI.Label(new Rect(((Rect)(ref val)).x + 14f, num + 34f, ((Rect)(ref val)).width - 28f, 18f), "♙ " + CleanUiText(Safe(map.author, T("未知", "Unknown"))), _mutedStyle);
			float num2 = ((Rect)(ref val)).yMax - 42f;
			float num3 = Mathf.Max(28f, num2 - (num + 58f) - 6f);
			string text = CompactCardDescription(CleanUiText(Safe(map.description, T("没有描述", "No description"))), ((Rect)(ref val)).width - 28f);
			GUI.Label(new Rect(((Rect)(ref val)).x + 14f, num + 58f, ((Rect)(ref val)).width - 28f, num3), text, _cardDescStyle);
			string text2 = T("下载 " + map.downloads + "    点赞 " + map.likes, "Downloads " + map.downloads + "    Likes " + map.likes);
			GUI.Label(new Rect(((Rect)(ref val)).x + 14f, num2, ((Rect)(ref val)).width - 104f, 26f), text2, _cardStatsStyle);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(((Rect)(ref val)).xMax - 82f, ((Rect)(ref val)).yMax - 46f, 68f, 34f);
			if (GUI.Button(val2, DownloadButtonLabel(map), _primaryButtonStyle))
			{
				SelectMap(index);
				DownloadSelected();
			}
			if (GUI.enabled && (int)Event.current.type == 0 && ((Rect)(ref rect)).Contains(Event.current.mousePosition) && !((Rect)(ref val2)).Contains(Event.current.mousePosition))
			{
				SelectMap(index);
				_communityDetailOpen = true;
				BlockTopLayerInputThisFrame();
				Event.current.Use();
			}
		}

		private void DrawCardSelectionOutline(Rect rect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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)
			Color color = GUI.color;
			GUI.color = new Color(0.2f, 0.86f, 0.46f, 1f);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width, 2f), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).yMax - 2f, ((Rect)(ref rect)).width, 2f), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, 2f, ((Rect)(ref rect)).height), (Texture)(object)Texture2D.whiteTexture);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).xMax - 2f, ((Rect)(ref rect)).y, 2f, ((Rect)(ref rect)).height), (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color;
		}

		private void DrawThumbnail(Rect rect, MapEntry map)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			DrawThumbnail(rect, map, (ScaleMode)1);
		}

		private void DrawThumbnail(Rect rect, MapEntry map, ScaleMode scaleMode)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			Texture2D thumbnail = GetThumbnail(map);
			GUI.DrawTexture(rect, (Texture)(object)(((Object)(object)thumbnail != (Object)null) ? thumbnail : _placeholderThumb), scaleMode);
			Color color = GUI.color;
			GUI.color = new Color(0f, 0f, 0f, 0.2f);
			GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
			GUI.color = new Color(0f, 0f, 0f, 0.5f);
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).yMax - 34f, ((Rect)(ref rect)).width, 34f), (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color;
		}

		private Texture2D GetThumbnail(MapEntry map)
		{
			string url = ((!string.IsNullOrEmpty(map.thumbnail_url)) ? map.thumbnail_url : map.image_url);
			if (string.IsNullOrEmpty(url))
			{
				return _placeholderThumb;
			}
			if (_thumbnails.TryGetValue(url, out var value))
			{
				return ((Object)(object)value != (Object)null) ? value : _placeholderThumb;
			}
			_thumbnails[url] = null;
			_api.DownloadTexture(url, delegate(Texture2D loaded)
			{
				if ((Object)(object)loaded != (Object)null)
				{
					_thumbnails[url] = loaded;
				}
			});
			return _placeholderThumb;
		}

		private void DrawDetail(Rect rect)
		{
			//IL_0001: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: 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_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			GUI.Box(rect, GUIContent.none, _panelStyle);
			MapEntry selectedMap = SelectedMap;
			if (selectedMap == null)
			{
				GUI.Label(new Rect(((Rect)(ref rect)).x + 16f, ((Rect)(ref rect)).y + 16f, ((Rect)(ref rect)).width - 32f, 40f), T("选择一张地图查看详情", "Select a map to view details"), _labelStyle);
				return;
			}
			Rect rect2 = default(Rect);
			((Rect)(ref rect2))..ctor(((Rect)(ref rect)).x + 14f, ((Rect)(ref rect)).y + 14f, ((Rect)(ref rect)).width - 28f, 150f);
			DrawThumbnail(rect2, selectedMap);
			GUI.Label(new Rect(((Rect)(ref rect2)).x + 12f, ((Rect)(ref rect2)).yMax - 58f, ((Rect)(ref rect2)).width - 24f, 16f), T("当前地图", "SELECTED MAP"), _tinyStyle);
			GUI.Label(new Rect(((Rect)(ref rect2)).x + 12f, ((Rect)(ref rect2)).yMax - 40f, ((Rect)(ref rect2)).width - 24f, 34f), CleanUiText(Safe(selectedMap.name, T("未命名地图", "Untitled map"))), _detailTitleStyle);
			float num = ((Rect)(ref rect2)).yMax + 16f;
			DrawDetailMeta(new Rect(((Rect)(ref rect)).x + 14f, num, ((Rect)(ref rect)).width - 28f, 88f), selectedMap);
			num += 102f;
			GUI.Label(new Rect(((Rect)(ref rect)).x + 16f, num, ((Rect)(ref rect)).width - 32f, 18f), T("描述", "DESCRIPTION"), _tinyStyle);
			num += 24f;
			float num2 = ((Rect)(ref rect)).yMax - 48f;
			Rect rect3 = default(Rect);
			((Rect)(ref rect3))..ctor(((Rect)(ref rect)).x + 14f, num, ((Rect)(ref rect)).width - 28f, Mathf.Max(110f, num2 - num - 12f));
			DrawScrollableDescription(rect3, FormatDetailDescription(CleanUiText(Safe(selectedMap.description, T("没有描述", "No description")))));
			float num3 = 8f;
			float num4 = (((Rect)(ref rect)).width - 32f - num3 * 2f) / 3f;
			GUI.enabled = !_downloading;
			if (GUI.Button(new Rect(((Rect)(ref rect)).x + 16f, num2, num4, 36f), _downloading ? T("下载中", "Loading") : DownloadButtonLabel(selectedMap), _primaryButtonStyle))
			{
				DownloadSelected();
			}
			GUI.enabled = true;
			GUI.enabled = !_liking;
			if (GUI.Button(new Rect(((Rect)(ref rect)).x + 16f + num4 + num3, num2, num4, 36f), selectedMap.liked_by_me ? T("已赞", "Liked") : T("点赞", "Like"), _buttonStyle))
			{
				ToggleLikeSelected();
			}
			GUI.enabled = true;
			if (GUI.Button(new Rect(((Rect)(ref rect)).x + 16f + (num4 + num3) * 2f, num2, num4, 36f), T("刷新", "Refresh"), _buttonStyle))
			{
				RefreshAll();
			}
		}

		private void DrawCommunityDetailModal()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0521: Unknown result type (might be due to invalid IL or missing references)
			//IL_058b: Unknown result type (might be due to invalid IL or missing references)
			MapEntry selectedMap = SelectedMap;
			if (selectedMap == null)
			{
				_communityDetailOpen = false;
				return;
			}
			GUI.depth = -101;
			GUI.Box(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), GUIContent.none, _modalBackdropStyle);
			float num = Mathf.Min(820f, (float)Screen.width - 32f);
			float num2 = Mathf.Min(680f, (float)Screen.height - 26f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(Mathf.Round(((float)Screen.width - num) * 0.5f), Mathf.Round(((float)Screen.height - num2) * 0.5f), num, num2);
			GUI.Box(val, GUIContent.none, _rootStyle);
			Rect rect = default(Rect);
			((Rect)(ref rect))..ctor(((Rect)(ref val)).x + 14f, ((Rect)(ref val)).y + 14f, ((Rect)(ref val)).width - 28f, 238f);
			DrawThumbnail(rect, selectedMap, (ScaleMode)2);
			GUI.Label(new Rect(((Rect)(ref rect)).x + 14f, ((Rect)(ref rect)).y + 12f, 118f, 24f), ShortVersion(selectedMap.mod_version), _badgeStyle);
			if (GUI.Button(new Rect(((Rect)(ref val)).xMax - 52f, ((Rect)(ref val)).y + 18f, 34f, 34f), "×", _iconButtonStyle))
			{
				_communityDetailOpen = false;
			}
			float num3 = ((Rect)(ref rect)).yMax + 16f;
			GUI.Label(new Rect(((Rect)(ref val)).x + 24f, num3, ((Rect)(ref val)).width - 48f, 38f), CleanUiText(Safe(selectedMap.name, T("未命名地图", "Untitled map"))), _titleStyle);
			num3 += 48f;
			float num4 = 10f;
			float num5 = (((Rect)(ref val)).width - 48f - num4 * 3f) / 4f;
			DrawStatBox(new Rect(((Rect)(ref val)).x + 24f, num3, num5, 64f), T("作者", "AUTHOR"), CleanUiText(Safe(selectedMap.author, T("未知", "Unknown"))));
			DrawStatBox(new Rect(((Rect)(ref val)).x + 24f + num5 + num4, num3, num5, 64f), T("MOD 版本", "MOD VERSION"), CleanUiText(Safe(selectedMap.mod_version, "-")));
			DrawStatBox(new Rect(((Rect)(ref val)).x + 24f + (num5 + num4) * 2f, num3, num5, 64f), T("下载次数", "DOWNLOADS"), selectedMap.downloads.ToString());
			DrawStatBox(new Rect(((Rect)(ref val)).x + 24f + (num5 + num4) * 3f, num3, num5, 64f), T("点赞", "LIKES"), selectedMap.likes.ToString());
			num3 += 78f;
			GUI.Label(new Rect(((Rect)(ref val)