Decompiled source of MapPreviewGenerator v1.0.1

plugins/PMod.MapPreviewGenerator.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using BoplFixedMath;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[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: AssemblyVersion("0.0.0.0")]
[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 PMod.MapPreviewGenerator
{
	internal static class MapLayoutPreview
	{
		private struct PlatformData
		{
			public double X;

			public double Y;

			public double Rotation;

			public string Preset;

			public double ScaleFactor;
		}

		private abstract class JNode
		{
		}

		private sealed class JObj : JNode
		{
			public Dictionary<string, JNode> Fields = new Dictionary<string, JNode>();

			public JNode Get(string key)
			{
				JNode value;
				return Fields.TryGetValue(key, out value) ? value : null;
			}
		}

		private sealed class JArr : JNode
		{
			public List<JNode> Items = new List<JNode>();
		}

		private sealed class JStr : JNode
		{
			public string Value;
		}

		private sealed class JNum : JNode
		{
			public double Value;
		}

		private const int W = 640;

		private const int H = 360;

		private const double MinScale = 1.5;

		public static Texture2D TryBuild(string mapJson, string mapType, out int platformCount)
		{
			//IL_07b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ba: Expected O, but got Unknown
			//IL_07da: Unknown result type (might be due to invalid IL or missing references)
			//IL_07dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0811: Unknown result type (might be due to invalid IL or missing references)
			//IL_0824: Unknown result type (might be due to invalid IL or missing references)
			//IL_083c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0841: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_09aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_09d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_09d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_09da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0afa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0afc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b01: Unknown result type (might be due to invalid IL or missing references)
			platformCount = 0;
			if (string.IsNullOrEmpty(mapJson))
			{
				return null;
			}
			try
			{
				if (mapJson.Length > 0 && mapJson[0] == '\ufeff')
				{
					mapJson = mapJson.Substring(1);
				}
				if (!(ParseJson(mapJson) is JObj jObj))
				{
					return null;
				}
				List<PlatformData> list = new List<PlatformData>();
				if (jObj.Get("platforms") is JArr jArr)
				{
					foreach (JNode item in jArr.Items)
					{
						if (!(item is JObj jObj2))
						{
							continue;
						}
						JObj jObj3 = jObj2.Get("transform") as JObj;
						JNum jNum = ((jObj3 != null) ? (jObj3.Get("x") as JNum) : null);
						JNum jNum2 = ((jObj3 != null) ? (jObj3.Get("y") as JNum) : null);
						if (jNum == null || jNum2 == null)
						{
							continue;
						}
						JNum jNum3 = jObj2.Get("rotation") as JNum;
						JObj jObj4 = jObj2.Get("PresetPlatform") as JObj;
						string preset = null;
						double scaleFactor = 1.0;
						if (jObj4 != null)
						{
							if (jObj4.Get("PresetPlatformName") is JStr jStr)
							{
								preset = jStr.Value;
							}
							if (jObj4.Get("ScaleFactor") is JNum { Value: >0.0 } jNum4)
							{
								scaleFactor = jNum4.Value;
							}
						}
						list.Add(new PlatformData
						{
							X = jNum.Value,
							Y = jNum2.Value,
							Rotation = (jNum3?.Value ?? 0.0),
							Preset = preset,
							ScaleFactor = scaleFactor
						});
					}
				}
				platformCount = list.Count;
				if (list.Count == 0)
				{
					return null;
				}
				List<double[]> list2 = new List<double[]>();
				if (jObj.Get("teamSpawns") is JArr jArr2)
				{
					foreach (JNode item2 in jArr2.Items)
					{
						if (item2 is JArr jArr3 && jArr3.Items.Count >= 2)
						{
							JNum jNum5 = jArr3.Items[0] as JNum;
							JNum jNum6 = jArr3.Items[1] as JNum;
							if (jNum5 != null && jNum6 != null)
							{
								list2.Add(new double[2] { jNum5.Value, jNum6.Value });
							}
						}
					}
				}
				if (list2.Count == 0)
				{
					list2.Add(new double[2]);
				}
				int count = list.Count;
				int num = count / 10;
				double[] array = new double[count];
				double[] array2 = new double[count];
				for (int i = 0; i < count; i++)
				{
					array[i] = list[i].X;
					array2[i] = list[i].Y;
				}
				Array.Sort(array);
				Array.Sort(array2);
				double val = array[num];
				double val2 = array[count - 1 - num];
				double val3 = array2[num];
				double val4 = array2[count - 1 - num];
				double num2 = double.MaxValue;
				double num3 = double.MinValue;
				double num4 = double.MaxValue;
				double num5 = double.MinValue;
				double num6 = 0.0;
				double num7 = 0.0;
				foreach (double[] item3 in list2)
				{
					num6 += item3[0];
					num7 += item3[1];
					num2 = Math.Min(num2, item3[0]);
					num3 = Math.Max(num3, item3[0]);
					num4 = Math.Min(num4, item3[1]);
					num5 = Math.Max(num5, item3[1]);
				}
				num6 /= (double)list2.Count;
				num7 /= (double)list2.Count;
				val = Math.Min(val, num2 - 6.0);
				val2 = Math.Max(val2, num3 + 6.0);
				val3 = Math.Min(val3, num4 - 6.0);
				val4 = Math.Max(val4, num5 + 6.0);
				double num8 = Math.Min(640.0 / (val2 - val), 360.0 / (val4 - val3)) * 0.92;
				double num9;
				double num10;
				double num11;
				if (num8 >= 1.5)
				{
					num9 = num8;
					num10 = (val + val2) * 0.5;
					num11 = (val3 + val4) * 0.5;
				}
				else
				{
					num9 = 1.5;
					double num12 = 640.0 / num9;
					double num13 = 360.0 / num9;
					double num14 = val + num12 * 0.5;
					double num15 = val2 - num12 * 0.5;
					num10 = ((num14 < num15) ? Math.Min(Math.Max(num6, num14), num15) : ((val + val2) * 0.5));
					num14 = val3 + num13 * 0.5;
					num15 = val4 - num13 * 0.5;
					num11 = ((num14 < num15) ? Math.Min(Math.Max(num7, num14), num15) : ((val3 + val4) * 0.5));
				}
				Color val5 = default(Color);
				Color val6 = default(Color);
				Color c = default(Color);
				Color c2 = default(Color);
				if (!(mapType == "space"))
				{
					if (mapType == "snow")
					{
						((Color)(ref val5))..ctor(0.96f, 0.98f, 1f);
						((Color)(ref val6))..ctor(0.62f, 0.76f, 0.92f);
						((Color)(ref c))..ctor(0.9f, 0.95f, 1f);
						((Color)(ref c2))..ctor(0.3f, 0.42f, 0.55f);
					}
					else
					{
						((Color)(ref val5))..ctor(0.55f, 0.76f, 0.5f);
						((Color)(ref val6))..ctor(0.13f, 0.34f, 0.14f);
						((Color)(ref c))..ctor(0.42f, 0.6f, 0.4f);
						((Color)(ref c2))..ctor(0.06f, 0.16f, 0.06f);
					}
				}
				else
				{
					((Color)(ref val5))..ctor(0.3f, 0.26f, 0.52f);
					((Color)(ref val6))..ctor(0.07f, 0.05f, 0.14f);
					((Color)(ref c))..ctor(0.42f, 0.45f, 0.58f);
					((Color)(ref c2))..ctor(0.1f, 0.11f, 0.16f);
				}
				Color c3 = default(Color);
				((Color)(ref c3))..ctor(0.98f, 0.85f, 0.3f);
				Texture2D val7 = new Texture2D(640, 360, (TextureFormat)3, false);
				Color32[] array3 = (Color32[])(object)new Color32[230400];
				for (int j = 0; j < 360; j++)
				{
					float num16 = (float)j / 359f;
					Color val8 = Color.Lerp(val6, val5, num16);
					int num17 = j * 640;
					for (int k = 0; k < 640; k++)
					{
						array3[num17 + k] = new Color32((byte)Mathf.RoundToInt(val8.r * 255f), (byte)Mathf.RoundToInt(val8.g * 255f), (byte)Mathf.RoundToInt(val8.b * 255f), byte.MaxValue);
					}
				}
				for (int l = 0; l < count; l++)
				{
					PlatformData p = list[l];
					GetShape(p, out var halfW, out var halfH, out var circle);
					double num18 = (p.X - num10) * num9 + 320.0;
					double num19 = 180.0 - (p.Y - num11) * num9;
					double theta = p.Rotation * Math.PI / 180.0;
					int num20 = (int)(halfW * num9) + 3;
					int num21 = (int)(halfH * num9) + 3;
					int num22 = Math.Max(0, (int)Math.Floor(num18) - num20);
					int num23 = Math.Min(639, (int)Math.Ceiling(num18) + num20);
					int num24 = Math.Max(0, (int)Math.Floor(num19) - num21);
					int num25 = Math.Min(359, (int)Math.Ceiling(num19) + num21);
					for (int m = num24; m <= num25; m++)
					{
						for (int n = num22; n <= num23; n++)
						{
							double num26 = Sdf(n, m, num18, num19, theta, halfW, halfH, circle, num9) * num9;
							if (num26 <= 0.0)
							{
								array3[m * 640 + n] = To32(c);
							}
							else if (num26 < 1.2)
							{
								array3[m * 640 + n] = To32(c2);
							}
						}
					}
				}
				foreach (double[] item4 in list2)
				{
					double num27 = (item4[0] - num10) * num9 + 320.0;
					double num28 = 180.0 - (item4[1] - num11) * num9;
					int num29 = (int)Math.Round(num27);
					int num30 = (int)Math.Round(num28);
					for (int num31 = num30 - 4; num31 <= num30 + 4; num31++)
					{
						for (int num32 = num29 - 4; num32 <= num29 + 4; num32++)
						{
							if (num32 >= 0 && num32 < 640 && num31 >= 0 && num31 < 360 && Math.Abs((double)num32 - num27) + Math.Abs((double)num31 - num28) <= 3.5)
							{
								array3[num31 * 640 + num32] = To32(c3);
							}
						}
					}
				}
				val7.SetPixels32(array3);
				val7.Apply();
				((Object)val7).name = "NextMapVote_CustomLayout";
				return val7;
			}
			catch
			{
				return null;
			}
		}

		private static void GetShape(PlatformData p, out double halfW, out double halfH, out bool circle)
		{
			string preset = p.Preset;
			double scaleFactor = p.ScaleFactor;
			circle = false;
			switch (preset)
			{
			case "circle":
				halfW = 1.0;
				halfH = 1.0;
				circle = true;
				break;
			case "smallcapsule":
				halfW = 2.0;
				halfH = 0.55;
				break;
			case "longroundedrectangle":
				halfW = 6.0;
				halfH = 0.9;
				break;
			case "bigroundedrectangle":
				halfW = 3.5;
				halfH = 1.1;
				break;
			case "detailedrectangle":
				halfW = 2.6;
				halfH = 0.8;
				break;
			case "snowcircle":
				halfW = 1.2;
				halfH = 1.2;
				circle = true;
				break;
			case "longsnowcapsule":
				halfW = 6.0;
				halfH = 0.8;
				break;
			case "ice":
				halfW = 4.0;
				halfH = 0.8;
				break;
			case "icesmall":
				halfW = 2.6;
				halfH = 0.7;
				break;
			case "big_ice":
				halfW = 6.0;
				halfH = 1.4;
				break;
			case "asteroid s":
				halfW = 1.1;
				halfH = 1.1;
				circle = true;
				break;
			case "asteroid m":
				halfW = 1.6;
				halfH = 1.6;
				circle = true;
				break;
			case "asteroid l":
				halfW = 2.2;
				halfH = 2.2;
				circle = true;
				break;
			case "asteroid xl":
				halfW = 3.0;
				halfH = 3.0;
				circle = true;
				break;
			default:
				halfW = 2.0;
				halfH = 0.6;
				break;
			}
			halfW *= scaleFactor;
			halfH *= scaleFactor;
		}

		private static double Sdf(double x, double y, double sx, double sy, double theta, double halfW, double halfH, bool circle, double scale)
		{
			double num = (x - sx) / scale;
			double num2 = (sy - y) / scale;
			double num3 = num * Math.Cos(theta) + num2 * Math.Sin(theta);
			double num4 = (0.0 - num) * Math.Sin(theta) + num2 * Math.Cos(theta);
			if (circle)
			{
				return Math.Sqrt(num3 * num3 + num4 * num4) - halfW;
			}
			double num5 = Math.Min(halfW, halfH);
			double num6 = Math.Max(Math.Abs(num3) - (halfW - num5), 0.0);
			double num7 = Math.Max(Math.Abs(num4) - (halfH - num5), 0.0);
			return Math.Sqrt(num6 * num6 + num7 * num7) - num5;
		}

		private static Color32 To32(Color c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			return new Color32((byte)Mathf.RoundToInt(c.r * 255f), (byte)Mathf.RoundToInt(c.g * 255f), (byte)Mathf.RoundToInt(c.b * 255f), byte.MaxValue);
		}

		private static JNode ParseJson(string json)
		{
			int i = 0;
			JNode jNode = ParseValue(json, ref i);
			if (jNode == null)
			{
				throw new FormatException("empty json");
			}
			return jNode;
		}

		private static JNode ParseValue(string s, ref int i)
		{
			SkipWs(s, ref i);
			if (i >= s.Length)
			{
				throw new FormatException("unexpected end of json");
			}
			char c = s[i];
			switch (c)
			{
			case '{':
				return ParseObject(s, ref i);
			case '[':
				return ParseArray(s, ref i);
			case '"':
				return new JStr
				{
					Value = ParseString(s, ref i)
				};
			case 't':
				Expect(s, ref i, "true");
				return new JNum
				{
					Value = 1.0
				};
			case 'f':
				Expect(s, ref i, "false");
				return new JNum
				{
					Value = 0.0
				};
			case 'n':
				Expect(s, ref i, "null");
				return null;
			default:
				if (c == '-' || (c >= '0' && c <= '9'))
				{
					int num = i;
					while (i < s.Length && (s[i] == '-' || s[i] == '+' || s[i] == '.' || s[i] == 'e' || s[i] == 'E' || (s[i] >= '0' && s[i] <= '9')))
					{
						i++;
					}
					if (!double.TryParse(s.Substring(num, i - num), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						throw new FormatException("bad number");
					}
					return new JNum
					{
						Value = result
					};
				}
				throw new FormatException("unexpected character");
			}
		}

		private static JObj ParseObject(string s, ref int i)
		{
			i++;
			JObj jObj = new JObj();
			SkipWs(s, ref i);
			if (i < s.Length && s[i] == '}')
			{
				i++;
				return jObj;
			}
			while (true)
			{
				SkipWs(s, ref i);
				string key = ParseString(s, ref i);
				SkipWs(s, ref i);
				if (i >= s.Length || s[i] != ':')
				{
					throw new FormatException("expected ':'");
				}
				i++;
				JNode jNode = ParseValue(s, ref i);
				if (jNode != null)
				{
					jObj.Fields[key] = jNode;
				}
				SkipWs(s, ref i);
				if (i >= s.Length)
				{
					break;
				}
				switch (s[i])
				{
				case '}':
					i++;
					return jObj;
				case ',':
					break;
				default:
					throw new FormatException("expected ',' or '}'");
				}
				i++;
			}
			throw new FormatException("unterminated object");
		}

		private static JArr ParseArray(string s, ref int i)
		{
			i++;
			JArr jArr = new JArr();
			SkipWs(s, ref i);
			if (i < s.Length && s[i] == ']')
			{
				i++;
				return jArr;
			}
			while (true)
			{
				SkipWs(s, ref i);
				JNode jNode = ParseValue(s, ref i);
				if (jNode != null)
				{
					jArr.Items.Add(jNode);
				}
				SkipWs(s, ref i);
				if (i >= s.Length)
				{
					break;
				}
				switch (s[i])
				{
				case ']':
					i++;
					return jArr;
				case ',':
					break;
				default:
					throw new FormatException("expected ',' or ']'");
				}
				i++;
			}
			throw new FormatException("unterminated array");
		}

		private static string ParseString(string s, ref int i)
		{
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					return stringBuilder.ToString();
				case '\\':
					break;
				default:
					stringBuilder.Append(c);
					continue;
				}
				if (i >= s.Length)
				{
					break;
				}
				char c2 = s[i++];
				switch (c2)
				{
				case '"':
					stringBuilder.Append('"');
					break;
				case '\\':
					stringBuilder.Append('\\');
					break;
				case '/':
					stringBuilder.Append('/');
					break;
				case 'b':
					stringBuilder.Append('\b');
					break;
				case 'f':
					stringBuilder.Append('\f');
					break;
				case 'n':
					stringBuilder.Append('\n');
					break;
				case 'r':
					stringBuilder.Append('\r');
					break;
				case 't':
					stringBuilder.Append('\t');
					break;
				case 'u':
				{
					if (i + 4 <= s.Length && int.TryParse(s.Substring(i, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
					{
						stringBuilder.Append((char)result);
						i += 4;
					}
					break;
				}
				default:
					stringBuilder.Append(c2);
					break;
				}
			}
			throw new FormatException("unterminated string");
		}

		private static void SkipWs(string s, ref int i)
		{
			while (i < s.Length && (s[i] == ' ' || s[i] == '\t' || s[i] == '\n' || s[i] == '\r'))
			{
				i++;
			}
		}

		private static void Expect(string s, ref int i, string word)
		{
			if (i + word.Length > s.Length || string.CompareOrdinal(s, i, word, 0, word.Length) != 0)
			{
				throw new FormatException("expected " + word);
			}
			i += word.Length;
		}
	}
	internal static class MapMakerBridge
	{
		private static Type _pluginType;

		private static bool _resolved;

		private static FieldInfo _mapJsonsField;

		private static FieldInfo _metaDataJsonsField;

		private static FieldInfo _currentMapIndexField;

		private static FieldInfo _nextMapIndexField;

		private static FieldInfo _currentMapUuidField;

		private static FieldInfo _grassMapIdField;

		private static FieldInfo _snowMapIdField;

		private static FieldInfo _spaceMapIdField;

		private static readonly Dictionary<int, string> _nameCache = new Dictionary<int, string>();

		private static readonly Dictionary<int, string> _typeCache = new Dictionary<int, string>();

		private static readonly Dictionary<int, int> _uuidCache = new Dictionary<int, int>();

		public static bool Active
		{
			get
			{
				string[] array = CustomMaps();
				return array != null && array.Length != 0;
			}
		}

		public static int MapCount
		{
			get
			{
				string[] array = CustomMaps();
				return (array != null) ? array.Length : 0;
			}
		}

		public static int CurrentCustomMapIndex()
		{
			return ReadInt(_currentMapIndexField, -1);
		}

		public static int CurrentMapUuid()
		{
			return ReadInt(_currentMapUuidField, -1);
		}

		public static int NextMapIndex()
		{
			return ReadInt(_nextMapIndexField, -1);
		}

		public static void RestoreState(int mapIndex, int mapUuid, int nextMapIndex)
		{
			WriteInt(_currentMapIndexField, mapIndex);
			WriteInt(_currentMapUuidField, mapUuid);
			WriteInt(_nextMapIndexField, nextMapIndex);
		}

		public static string MapNameOf(int customIndex)
		{
			if (_nameCache.TryGetValue(customIndex, out var value))
			{
				return value;
			}
			string text = RegexValue(MetaOf(customIndex), "\"MapName\"\\s*:\\s*\"([^\"]+)\"");
			if (string.IsNullOrEmpty(text))
			{
				text = "Custom map " + (customIndex + 1);
			}
			_nameCache[customIndex] = text;
			return text;
		}

		public static string MapTypeOf(int customIndex)
		{
			if (_typeCache.TryGetValue(customIndex, out var value) && value != null)
			{
				return value;
			}
			string text = RegexValue(MetaOf(customIndex), "\"MapType\"\\s*:\\s*\"([^\"]+)\"");
			if (string.IsNullOrEmpty(text))
			{
				text = "grass";
			}
			_typeCache[customIndex] = text;
			return text;
		}

		public static int MapUuidOf(int customIndex)
		{
			if (_uuidCache.TryGetValue(customIndex, out var value))
			{
				return value;
			}
			int result = -1;
			string s = RegexValue(MetaOf(customIndex), "\"MapUUID\"\\s*:\\s*(-?[0-9]+)");
			int.TryParse(s, out result);
			_uuidCache[customIndex] = result;
			return result;
		}

		public static int BaseLevelIdOf(int customIndex)
		{
			string text = MapTypeOf(customIndex);
			string text2 = text;
			if (!(text2 == "space"))
			{
				if (text2 == "snow")
				{
					return ReadInt(_snowMapIdField, 21);
				}
				return ReadInt(_grassMapIdField, 0);
			}
			return ReadInt(_spaceMapIdField, 33);
		}

		public static string MapJsonOf(int customIndex)
		{
			string[] array = CustomMaps();
			if (array == null || customIndex < 0 || customIndex >= array.Length)
			{
				return null;
			}
			return array[customIndex];
		}

		public static void CommitWinner(int customIndex)
		{
			WriteInt(_currentMapIndexField, customIndex);
			WriteInt(_nextMapIndexField, customIndex);
			WriteInt(_currentMapUuidField, MapUuidOf(customIndex));
		}

		public static void EnsureCommitted(int customIndex)
		{
			if (!Active)
			{
				return;
			}
			int num = ReadInt(_currentMapIndexField, -2);
			if (num == customIndex)
			{
				return;
			}
			CommitWinner(customIndex);
			int num2 = BaseLevelIdOf(customIndex);
			try
			{
				GameSession.SetCurrentLevel((byte)num2);
			}
			catch
			{
			}
			if (GameLobby.isOnlineGame)
			{
				try
				{
					SteamManager.startParameters.currentLevel = (byte)num2;
				}
				catch
				{
				}
			}
			Log($"MapMaker guard: CurrentMapIndex drifted to {num}, re-committed voted map {customIndex}");
		}

		private static string[] CustomMaps()
		{
			EnsureResolved();
			if (_mapJsonsField == null)
			{
				return null;
			}
			try
			{
				return _mapJsonsField.GetValue(null) as string[];
			}
			catch
			{
				return null;
			}
		}

		private static string MetaOf(int customIndex)
		{
			EnsureResolved();
			if (_metaDataJsonsField == null || customIndex < 0)
			{
				return null;
			}
			try
			{
				if (!(_metaDataJsonsField.GetValue(null) is string[] array) || customIndex >= array.Length)
				{
					return null;
				}
				return array[customIndex];
			}
			catch
			{
				return null;
			}
		}

		private static string RegexValue(string json, string pattern)
		{
			if (string.IsNullOrEmpty(json))
			{
				return null;
			}
			try
			{
				Match match = Regex.Match(json, pattern);
				return match.Success ? match.Groups[1].Value : null;
			}
			catch
			{
				return null;
			}
		}

		private static int ReadInt(FieldInfo f, int fallback)
		{
			if (f == null)
			{
				return fallback;
			}
			try
			{
				return (int)f.GetValue(null);
			}
			catch
			{
				return fallback;
			}
		}

		private static void WriteInt(FieldInfo f, int value)
		{
			if (f == null)
			{
				return;
			}
			try
			{
				f.SetValue(null, value);
			}
			catch
			{
			}
		}

		private static void EnsureResolved()
		{
			if (_resolved)
			{
				return;
			}
			_resolved = true;
			_pluginType = MapPreviewGeneratorPlugin.ResolveTypeNoWarn("MapMaker.Plugin");
			if (!(_pluginType == null))
			{
				_mapJsonsField = _pluginType.GetField("MapJsons", BindingFlags.Static | BindingFlags.Public);
				_metaDataJsonsField = _pluginType.GetField("MetaDataJsons", BindingFlags.Static | BindingFlags.Public);
				_currentMapIndexField = _pluginType.GetField("CurrentMapIndex", BindingFlags.Static | BindingFlags.Public);
				_nextMapIndexField = _pluginType.GetField("NextMapIndex", BindingFlags.Static | BindingFlags.Public);
				_currentMapUuidField = _pluginType.GetField("CurrentMapUUID", BindingFlags.Static | BindingFlags.Public);
				_grassMapIdField = _pluginType.GetField("GrassMapId", BindingFlags.Static | BindingFlags.Public);
				_snowMapIdField = _pluginType.GetField("SnowMapId", BindingFlags.Static | BindingFlags.Public);
				_spaceMapIdField = _pluginType.GetField("SpaceMapId", BindingFlags.Static | BindingFlags.Public);
				if (_mapJsonsField != null)
				{
					Log($"MapMaker integration: detected, {MapCount} custom map(s)");
				}
			}
		}

		private static void Log(string msg)
		{
			ManualLogSource log = MapPreviewGeneratorPlugin.Log;
			if (log != null)
			{
				log.LogMessage((object)msg);
			}
		}
	}
	[BepInPlugin("com.pmod.mappreviewgenerator", "PMod Map Preview Generator", "1.0.0")]
	[BepInProcess("BoplBattle.exe")]
	public sealed class MapPreviewGeneratorPlugin : BaseUnityPlugin
	{
		internal sealed class Driver : MonoBehaviour
		{
			internal static Driver Host;

			private static float _progressFade;

			private static Texture2D _whiteTex;

			private static Texture2D WhiteTex
			{
				get
				{
					//IL_0015: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Expected O, but got Unknown
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					if ((Object)(object)_whiteTex == (Object)null)
					{
						_whiteTex = new Texture2D(1, 1, (TextureFormat)4, false);
						_whiteTex.SetPixel(0, 0, Color.white);
						_whiteTex.Apply();
					}
					return _whiteTex;
				}
			}

			internal static void StartRoutine(IEnumerator routine)
			{
				if ((Object)(object)Host != (Object)null)
				{
					((MonoBehaviour)Host).StartCoroutine(routine);
				}
			}

			private void Update()
			{
				PollSceneChange();
				PreviewGenerator.PumpMainThreadJobs();
				PreviewGenerator.Tick();
			}

			private void OnGUI()
			{
				DrawProgressBar();
			}

			private static void DrawProgressBar()
			{
				//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0105: Unknown result type (might be due to invalid IL or missing references)
				//IL_010f: Expected O, but got Unknown
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_016a: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_025d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0222: Unknown result type (might be due to invalid IL or missing references)
				//IL_024c: Unknown result type (might be due to invalid IL or missing references)
				int preloadTotal = PreviewGenerator.PreloadTotal;
				int preloadDone = PreviewGenerator.PreloadDone;
				float num = ((PreviewGenerator.InMenu() && preloadTotal > 0 && preloadDone < preloadTotal) ? 1f : 0f);
				_progressFade = Mathf.MoveTowards(_progressFade, num, Time.unscaledDeltaTime * 2f);
				if (!(_progressFade <= 0.01f))
				{
					float num2 = Mathf.Min(560f, (float)Screen.width * 0.55f);
					Rect val = default(Rect);
					((Rect)(ref val))..ctor(((float)Screen.width - num2) / 2f, 16f, num2, 58f);
					float progressFade = _progressFade;
					GUI.color = new Color(0f, 0f, 0f, progressFade * 0.72f);
					GUI.DrawTexture(val, (Texture)(object)WhiteTex);
					GUI.color = new Color(1f, 1f, 1f, progressFade);
					GUIStyle val2 = new GUIStyle(GUI.skin.label)
					{
						fontSize = 13,
						fontStyle = (FontStyle)1
					};
					val2.normal.textColor = new Color(1f, 1f, 1f, progressFade);
					float num3 = Mathf.Clamp01((float)preloadDone / (float)preloadTotal);
					GUI.Label(new Rect(((Rect)(ref val)).x + 16f, ((Rect)(ref val)).y + 8f, ((Rect)(ref val)).width - 32f, 24f), $"Map previews: loading... {preloadDone}/{preloadTotal} ({Mathf.RoundToInt(num3 * 100f)}%)", val2);
					Rect val3 = default(Rect);
					((Rect)(ref val3))..ctor(((Rect)(ref val)).x + 16f, ((Rect)(ref val)).y + 36f, ((Rect)(ref val)).width - 32f, 12f);
					GUI.color = new Color(0f, 0f, 0f, progressFade * 0.85f);
					GUI.DrawTexture(val3, (Texture)(object)WhiteTex);
					if (num3 > 0.01f)
					{
						GUI.color = new Color(0.3f, 1f, 0.35f, progressFade);
						GUI.DrawTexture(new Rect(((Rect)(ref val3)).x, ((Rect)(ref val3)).y, ((Rect)(ref val3)).width * num3, ((Rect)(ref val3)).height), (Texture)(object)WhiteTex);
					}
					GUI.color = Color.white;
				}
			}
		}

		internal static ManualLogSource Log;

		internal static MapPreviewGeneratorPlugin Instance;

		private static int _lastSceneIndex = int.MinValue;

		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"MapPreviewGenerator plugin loaded");
			GameObject val = new GameObject("MapPreviewGenDriver");
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)52;
			Driver.Host = val.AddComponent<Driver>();
			if ((Object)(object)val.GetComponent<MapPreviewManager>() == (Object)null)
			{
				val.AddComponent<MapPreviewManager>();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Map preview generator ready (previews cache: BepInEx/plugins/PmodMapPreview)");
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				MapPreviewManager.DestroyAll();
				Instance = null;
			}
		}

		internal static Type ResolveTypeNoWarn(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(typeName, throwOnError: false);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static void PollSceneChange()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).buildIndex == _lastSceneIndex)
			{
				return;
			}
			_lastSceneIndex = ((Scene)(ref activeScene)).buildIndex;
			if (((Scene)(ref activeScene)).buildIndex < 6)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogMessage((object)$"[SceneLoaded] menu index={((Scene)(ref activeScene)).buildIndex} name={((Scene)(ref activeScene)).name} - arming preview preload");
				}
				PreviewGenerator.StartPreloadAll();
				PreviewGenerator.QueueAllMissing();
			}
		}
	}
	internal sealed class MapPreviewManager : MonoBehaviour
	{
		private static readonly Dictionary<int, Sprite> _sprites = new Dictionary<int, Sprite>(16);

		private static readonly Dictionary<int, Sprite> _pmodSprites = new Dictionary<int, Sprite>(16);

		private static readonly HashSet<int> _realSprites = new HashSet<int>(16);

		private static readonly Dictionary<int, Texture2D> _ownedTextures = new Dictionary<int, Texture2D>(16);

		private static FieldInfo _pmodInstanceField;

		private static FieldInfo _pmodSpritesField;

		private static FieldInfo _pmodAutoGeneratedField;

		private static Type _pmodType;

		private static bool _pmodResolved;

		public static MapPreviewManager Instance { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
			}
			else
			{
				Instance = this;
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		public static int MapCount()
		{
			return Mathf.Max(0, SceneManager.sceneCountInBuildSettings - 6);
		}

		public static bool HasRealPreview(int mapId)
		{
			if (_realSprites.Contains(mapId))
			{
				return true;
			}
			Dictionary<int, Sprite> dictionary = PmodSprites();
			if (dictionary == null)
			{
				return false;
			}
			Sprite value;
			return dictionary.TryGetValue(mapId, out value) && (Object)(object)value != (Object)null && !PmodSpriteIsPlaceholder(mapId);
		}

		public void EnsurePrepared(int mapId)
		{
			EnsurePreparedImpl(mapId);
		}

		public static void EnsurePreparedImpl(int mapId)
		{
			if (mapId < 0 || _sprites.ContainsKey(mapId))
			{
				return;
			}
			if (MapMakerBridge.Active)
			{
				try
				{
					Texture2D val = BuildCustomTexture(mapId, MapMakerBridge.MapTypeOf(mapId), MapMakerBridge.MapJsonOf(mapId));
					_ownedTextures[mapId] = val;
					_sprites[mapId] = MakeSprite(val, mapId);
					return;
				}
				catch (Exception ex)
				{
					Log($"custom preview {mapId} build FAILED: {ex.GetType().Name}: {ex.Message}");
					Texture2D val2 = BuildCustomGradient(mapId, MapMakerBridge.MapTypeOf(mapId));
					_ownedTextures[mapId] = val2;
					_sprites[mapId] = MakeSprite(val2, mapId);
					return;
				}
			}
			if (!PreviewGenerator.EnsureSharedCacheAsync(mapId))
			{
				Dictionary<int, Sprite> dictionary = PmodSprites();
				if (dictionary != null && dictionary.TryGetValue(mapId, out var value) && (Object)(object)value != (Object)null && !PmodSpriteIsPlaceholder(mapId))
				{
					_pmodSprites[mapId] = value;
					return;
				}
				Texture2D val3 = BuildTexture(mapId);
				_ownedTextures[mapId] = val3;
				_sprites[mapId] = MakeSprite(val3, mapId);
				PreviewGenerator.EnsureQueued(mapId);
			}
		}

		public bool TryGetSprite(int mapId, out Sprite sprite)
		{
			return TryGetSpriteImpl(mapId, out sprite);
		}

		public static bool TryGetSpriteImpl(int mapId, out Sprite sprite)
		{
			if (_sprites.TryGetValue(mapId, out sprite))
			{
				return true;
			}
			return _pmodSprites.TryGetValue(mapId, out sprite);
		}

		public static void InstallRealPreview(int mapId, Sprite sprite)
		{
			if ((Object)(object)sprite == (Object)null)
			{
				return;
			}
			if (_sprites.TryGetValue(mapId, out var value) && (Object)(object)value != (Object)null && (Object)(object)value != (Object)(object)sprite)
			{
				if (_ownedTextures.TryGetValue(mapId, out var value2) && (Object)(object)value2 != (Object)null)
				{
					Object.Destroy((Object)(object)value2);
					_ownedTextures.Remove(mapId);
				}
				Object.Destroy((Object)(object)value);
			}
			_sprites[mapId] = sprite;
			_realSprites.Add(mapId);
			PreviewLibrary.RaisePreviewReady(mapId);
		}

		public static void InstallTexturePreview(int mapId, Texture2D tex)
		{
			if (!((Object)(object)tex == (Object)null))
			{
				InstallRealPreview(mapId, MakeSprite(tex, mapId));
				_ownedTextures[mapId] = tex;
			}
		}

		public static void DestroyAll()
		{
			foreach (Texture2D value in _ownedTextures.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			foreach (Sprite value2 in _sprites.Values)
			{
				if ((Object)(object)value2 != (Object)null)
				{
					Object.Destroy((Object)(object)value2);
				}
			}
			_ownedTextures.Clear();
			_sprites.Clear();
			_pmodSprites.Clear();
			_realSprites.Clear();
		}

		private static Sprite MakeSprite(Texture2D tex, int mapId)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Sprite val = Sprite.Create(tex, new Rect(0f, 0f, (float)((Texture)tex).width, (float)((Texture)tex).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)val).name = "NextMapVote_Preview_" + mapId;
			return val;
		}

		private static void Log(string msg)
		{
			ManualLogSource log = MapPreviewGeneratorPlugin.Log;
			if (log != null)
			{
				log.LogMessage((object)msg);
			}
		}

		private static Dictionary<int, Sprite> PmodSprites()
		{
			ResolvePmodTypeOnce();
			if (_pmodType == null || _pmodInstanceField == null || _pmodSpritesField == null)
			{
				return null;
			}
			object value = _pmodInstanceField.GetValue(null);
			if (value == null)
			{
				return null;
			}
			return _pmodSpritesField.GetValue(value) as Dictionary<int, Sprite>;
		}

		private static void ResolvePmodTypeOnce()
		{
			if (!_pmodResolved)
			{
				_pmodResolved = true;
				_pmodType = MapPreviewGeneratorPlugin.ResolveTypeNoWarn("PMod");
				if (_pmodType != null)
				{
					_pmodInstanceField = AccessTools.Field(_pmodType, "Instance");
					_pmodSpritesField = AccessTools.Field(_pmodType, "roundMapPreviewSprites");
					_pmodAutoGeneratedField = AccessTools.Field(_pmodType, "roundMapAutoGeneratedPreviewIds");
				}
			}
		}

		private static bool PmodSpriteIsPlaceholder(int mapId)
		{
			if (_pmodAutoGeneratedField == null || _pmodInstanceField == null)
			{
				return false;
			}
			object value = _pmodInstanceField.GetValue(null);
			if (value == null)
			{
				return false;
			}
			return _pmodAutoGeneratedField.GetValue(value) is HashSet<int> hashSet && hashSet.Contains(mapId);
		}

		private static Texture2D BuildTexture(int mapId)
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: 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_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: 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_0235: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			Color val2 = default(Color);
			switch (mapId % 3)
			{
			case 0:
				((Color)(ref val))..ctor(0.55f, 0.62f, 0.5f, 1f);
				((Color)(ref val2))..ctor(0.16f, 0.2f, 0.27f, 1f);
				break;
			case 1:
				((Color)(ref val))..ctor(0.85f, 0.88f, 0.95f, 1f);
				((Color)(ref val2))..ctor(0.4f, 0.48f, 0.6f, 1f);
				break;
			default:
				((Color)(ref val))..ctor(0.2f, 0.18f, 0.32f, 1f);
				((Color)(ref val2))..ctor(0.05f, 0.05f, 0.09f, 1f);
				break;
			}
			Texture2D val3 = new Texture2D(256, 144, (TextureFormat)3, false);
			Color32[] array = (Color32[])(object)new Color32[36864];
			for (int i = 0; i < 144; i++)
			{
				float num = (float)i / 143f;
				Color val4 = Color.Lerp(val2, val, num);
				float num2 = Mathf.Sin(((float)i + (float)mapId * 17f) * 0.06f) * 0.5f + 0.5f;
				val4 = Color.Lerp(val4, Color.Lerp(val, val2, 0.5f), num2 * 0.08f);
				float num3 = (float)i / 143f - 0.5f;
				int num4 = i * 256;
				for (int j = 0; j < 256; j++)
				{
					float num5 = (float)j / 255f - 0.5f;
					float num6 = Mathf.Sqrt(num5 * num5 + num3 * num3) * 2f;
					float num7 = Mathf.Clamp01(1f - Mathf.Max(0f, num6 - 0.55f) * 2.2f);
					Color val5 = Color.Lerp(Color.black, val4, 0.75f + 0.25f * num7);
					array[num4 + j] = new Color32((byte)Mathf.Clamp(Mathf.RoundToInt(val5.r * 255f), 0, 255), (byte)Mathf.Clamp(Mathf.RoundToInt(val5.g * 255f), 0, 255), (byte)Mathf.Clamp(Mathf.RoundToInt(val5.b * 255f), 0, 255), byte.MaxValue);
				}
			}
			val3.SetPixels32(array);
			val3.Apply();
			((Object)val3).name = "NextMapVote_Fallback_" + mapId;
			return val3;
		}

		private static Texture2D BuildCustomTexture(int mapId, string mapType, string mapJson)
		{
			if (PreviewGenerator.TryLoadCustomCache(mapId, out var tex))
			{
				Log($"custom preview {mapId}: loaded from cache ({((Texture)tex).width}x{((Texture)tex).height})");
				((Object)tex).name = "NextMapVote_Custom_" + mapId;
				return tex;
			}
			int platformCount;
			Texture2D val = MapLayoutPreview.TryBuild(mapJson, mapType, out platformCount);
			if ((Object)(object)val != (Object)null)
			{
				PreviewGenerator.SaveCustomCache(mapId, val);
				((Object)val).name = "NextMapVote_Custom_" + mapId;
				Log($"custom preview {mapId}: layout rendered from {platformCount} platforms");
				return val;
			}
			Log($"custom preview {mapId}: layout unavailable (jsonLen={mapJson?.Length ?? (-1)}, platforms={platformCount}), using biome fallback");
			return BuildCustomGradient(mapId, mapType);
		}

		private static Texture2D BuildCustomGradient(int mapId, string mapType)
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: 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)
			Color val = default(Color);
			Color val2 = default(Color);
			if (!(mapType == "space"))
			{
				if (mapType == "snow")
				{
					((Color)(ref val))..ctor(0.96f, 0.98f, 1f, 1f);
					((Color)(ref val2))..ctor(0.62f, 0.76f, 0.92f, 1f);
				}
				else
				{
					((Color)(ref val))..ctor(0.55f, 0.76f, 0.5f, 1f);
					((Color)(ref val2))..ctor(0.13f, 0.34f, 0.14f, 1f);
				}
			}
			else
			{
				((Color)(ref val))..ctor(0.3f, 0.26f, 0.52f, 1f);
				((Color)(ref val2))..ctor(0.07f, 0.05f, 0.14f, 1f);
			}
			Texture2D val3 = new Texture2D(640, 360, (TextureFormat)3, false);
			Color32[] array = (Color32[])(object)new Color32[230400];
			for (int i = 0; i < 360; i++)
			{
				float num = (float)i / 359f - 0.5f;
				float num2 = (float)i / 359f;
				Color val4 = Color.Lerp(val2, val, num2);
				int num3 = i * 640;
				for (int j = 0; j < 640; j++)
				{
					float num4 = ((((j / 40 + i / 40) & 1) == 0) ? 1.06f : 1f);
					float num5 = (float)j / 639f - 0.5f;
					float num6 = Mathf.Sqrt(num5 * num5 + num * num) * 2f;
					float num7 = Mathf.Clamp01(1f - Mathf.Max(0f, num6 - 0.55f) * 2.2f);
					Color val5 = Color.Lerp(Color.black, val4, 0.72f + 0.28f * num7) * num4;
					array[num3 + j] = new Color32((byte)Mathf.Clamp(Mathf.RoundToInt(val5.r * 255f), 0, 255), (byte)Mathf.Clamp(Mathf.RoundToInt(val5.g * 255f), 0, 255), (byte)Mathf.Clamp(Mathf.RoundToInt(val5.b * 255f), 0, 255), byte.MaxValue);
				}
			}
			val3.SetPixels32(array);
			val3.Apply();
			((Object)val3).name = "NextMapVote_Custom_" + mapId;
			return val3;
		}
	}
	internal static class PreviewGenerator
	{
		private struct CacheLoadJob
		{
			public int MapId;

			public byte[] PngBytes;
		}

		private const int LayerHidden = 31;

		private const int PreviewWidth = 640;

		private const int PreviewHeight = 360;

		private static readonly List<int> _queue = new List<int>(16);

		private static bool _running;

		private static float _lastDeferLog;

		private static int _preloadTotal;

		private static int _preloadDone;

		private static int _installsSinceLog;

		private static int _customCaptureFailures;

		private static readonly HashSet<string> _mapMakerTemplateNames = new HashSet<string>
		{
			"TriggerObject", "SpawnerObject", "DisappearPlatformsObject", "AndGateObject", "SignalDelayObject", "OrGateObject", "NotGateObject", "ShootRayObject", "DropPlayersObject", "ShakePlatformObject",
			"LuaTestObject", "SignalSystemObject"
		};

		private static readonly HashSet<int> _pendingCacheLoads = new HashSet<int>();

		private static readonly Queue<CacheLoadJob> _finishedCacheLoads = new Queue<CacheLoadJob>();

		private static readonly object _cacheLock = new object();

		internal static bool Busy => _running || _queue.Count > 0;

		public static int PreloadTotal => _preloadTotal;

		public static int PreloadDone => Mathf.Min(_preloadDone, _preloadTotal);

		public static bool InMenu()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (GameLobby.isPlayingAReplay)
			{
				return false;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).IsValid() && ((Scene)(ref activeScene)).buildIndex >= 0 && ((Scene)(ref activeScene)).buildIndex < 6;
		}

		public static void QueueAllMissing()
		{
			if (MapMakerBridge.Active)
			{
				int mapCount = MapMakerBridge.MapCount;
				int num = 0;
				for (int i = 0; i < mapCount; i++)
				{
					if (!MapPreviewManager.HasRealPreview(i) && !HasCustomCacheFile(i) && !_queue.Contains(i))
					{
						_queue.Add(i);
						num++;
					}
				}
				if (num > 0)
				{
					Log($"preview-gen: queued {num} custom maps missing screenshots ({_queue.Count} total pending)");
				}
				else if (mapCount > 0 && _queue.Count == 0)
				{
					Log($"preview-gen: all {mapCount} custom maps already have screenshots (appdata cache)");
				}
				return;
			}
			int num2 = MapPreviewManager.MapCount();
			int num3 = 0;
			for (int j = 0; j < num2; j++)
			{
				if (!MapPreviewManager.HasRealPreview(j) && !HasSharedCacheFile(j) && !_queue.Contains(j))
				{
					_queue.Add(j);
					num3++;
				}
			}
			if (num3 > 0)
			{
				Log($"preview-gen: queued {num3} maps missing real previews ({_queue.Count} total pending)");
			}
			else if (num2 > 0 && _queue.Count == 0)
			{
				Log($"preview-gen: all {num2} maps already have real previews (appdata cache / PMod)");
			}
		}

		public static void EnsureQueued(int mapId)
		{
			if (!MapPreviewManager.HasRealPreview(mapId) && !_queue.Contains(mapId))
			{
				_queue.Add(mapId);
			}
		}

		public static void StartPreloadAll()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (MapMakerBridge.Active)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (!((Scene)(ref activeScene)).IsValid() || ((Scene)(ref activeScene)).name != "MainMenu")
				{
					_preloadTotal = 0;
					_preloadDone = 0;
					return;
				}
				int mapCount = MapMakerBridge.MapCount;
				if (mapCount <= 0)
				{
					return;
				}
				if (_preloadTotal != mapCount)
				{
					_preloadTotal = mapCount;
					_preloadDone = 0;
					for (int i = 0; i < mapCount; i++)
					{
						Texture2D tex;
						if (MapPreviewManager.HasRealPreview(i))
						{
							_preloadDone++;
						}
						else if (TryLoadCustomCache(i, out tex))
						{
							MapPreviewManager.InstallTexturePreview(i, tex);
							_preloadDone++;
						}
						else
						{
							EnsureQueued(i);
						}
					}
					Log($"preload: armed (custom maps), {_preloadDone}/{_preloadTotal} previews already ready");
				}
				else
				{
					if (_preloadDone >= _preloadTotal)
					{
						return;
					}
					for (int j = 0; j < mapCount; j++)
					{
						if (!MapPreviewManager.HasRealPreview(j))
						{
							if (TryLoadCustomCache(j, out var tex2))
							{
								MapPreviewManager.InstallTexturePreview(j, tex2);
								_preloadDone++;
							}
							else
							{
								EnsureQueued(j);
							}
						}
					}
				}
				return;
			}
			int num = MapPreviewManager.MapCount();
			if (num <= 0)
			{
				return;
			}
			if (_preloadTotal != num)
			{
				_preloadTotal = num;
				_preloadDone = 0;
				for (int k = 0; k < num; k++)
				{
					if (MapPreviewManager.HasRealPreview(k))
					{
						_preloadDone++;
					}
					else if (HasSharedCacheFile(k))
					{
						EnsureSharedCacheAsync(k);
					}
					else
					{
						EnsureQueued(k);
					}
				}
				Log($"preload: armed, {_preloadDone}/{_preloadTotal} previews already ready");
			}
			else
			{
				if (_preloadDone >= _preloadTotal)
				{
					return;
				}
				for (int l = 0; l < num; l++)
				{
					if (!MapPreviewManager.HasRealPreview(l))
					{
						if (HasSharedCacheFile(l))
						{
							EnsureSharedCacheAsync(l);
						}
						else
						{
							EnsureQueued(l);
						}
					}
				}
			}
		}

		public static void Tick()
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (_running)
			{
				return;
			}
			if (!InMenu() || _queue.Count == 0)
			{
				if (_queue.Count > 0 && Time.unscaledTime - _lastDeferLog > 5f)
				{
					_lastDeferLog = Time.unscaledTime;
					Scene activeScene = SceneManager.GetActiveScene();
					Log($"preview-gen: deferred, queue={_queue.Count}, scene={((Scene)(ref activeScene)).name}({((Scene)(ref activeScene)).buildIndex}), replay={GameLobby.isPlayingAReplay}");
				}
				return;
			}
			if (MapMakerBridge.Active)
			{
				Scene activeScene2 = SceneManager.GetActiveScene();
				if (!((Scene)(ref activeScene2)).IsValid() || ((Scene)(ref activeScene2)).name != "MainMenu")
				{
					return;
				}
			}
			int num = _queue[0];
			_queue.RemoveAt(0);
			_running = true;
			Log($"preview-gen: rendering map {num} ({_queue.Count} left)");
			MapPreviewGeneratorPlugin.Driver.StartRoutine(MapMakerBridge.Active ? CustomCaptureRoutine(num) : CaptureRoutine(num));
		}

		private static IEnumerator CaptureRoutine(int mapId)
		{
			IEnumerator core = CaptureCore(mapId);
			while (true)
			{
				bool moveNext;
				try
				{
					moveNext = core.MoveNext();
				}
				catch (Exception ex)
				{
					Exception ex2 = ex;
					Log($"preview {mapId} FAILED: {ex2}");
					_running = false;
					if (InMenu())
					{
						_queue.Add(mapId);
					}
					yield break;
				}
				if (!moveNext)
				{
					break;
				}
				yield return core.Current;
			}
			_running = false;
		}

		private static IEnumerator CaptureCore(int mapId)
		{
			int buildIndex = 6 + mapId;
			Scene loadedScene = default(Scene);
			int platformBaseLayer = -1;
			bool success = false;
			bool aborted = false;
			Camera mainCam = Camera.main;
			int savedMask = (((Object)(object)mainCam != (Object)null) ? mainCam.cullingMask : (-1));
			if ((Object)(object)mainCam != (Object)null && (mainCam.cullingMask & int.MinValue) != 0)
			{
				mainCam.cullingMask &= 0x7FFFFFFF;
			}
			AsyncOperation loadOp = SceneManager.LoadSceneAsync(buildIndex, (LoadSceneMode)1);
			if (loadOp != null)
			{
				bool sceneReady = false;
				loadOp.completed += delegate
				{
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					//IL_0030: Unknown result type (might be due to invalid IL or missing references)
					//IL_0031: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByBuildIndex = SceneManager.GetSceneByBuildIndex(buildIndex);
					if (((Scene)(ref sceneByBuildIndex)).IsValid() && ((Scene)(ref sceneByBuildIndex)).isLoaded)
					{
						loadedScene = sceneByBuildIndex;
						platformBaseLayer = FindPlatformBaseLayer(sceneByBuildIndex);
						SetLayersAndDisableCameras(sceneByBuildIndex);
					}
					sceneReady = true;
				};
				while (!sceneReady)
				{
					if (!InMenu())
					{
						aborted = true;
					}
					yield return null;
				}
				if (!aborted && ((Scene)(ref loadedScene)).IsValid() && ((Scene)(ref loadedScene)).isLoaded)
				{
					LevelType levelType = GetPreviewLevelType(loadedScene);
					Color bg = (Color)(((int)levelType == 2) ? Color.black : new Color(0.53f, 0.81f, 0.92f, 1f));
					yield return (object)new WaitForEndOfFrame();
					if (!InMenu())
					{
						aborted = true;
					}
					if (!aborted)
					{
						if (RestorePlatformPoses(loadedScene, platformBaseLayer))
						{
							Physics2D.SyncTransforms();
						}
						if (TryCapture(loadedScene, mapId, platformBaseLayer, bg, out var sprite))
						{
							MapPreviewManager.InstallRealPreview(mapId, sprite);
							TrySaveSharedCache(mapId, sprite.texture);
							success = true;
						}
					}
				}
				else if (!aborted)
				{
					Log($"preview {mapId} SKIPPED: scene {buildIndex} failed to load");
				}
			}
			if (((Scene)(ref loadedScene)).IsValid() && ((Scene)(ref loadedScene)).isLoaded)
			{
				SetAllRootsToLayer(loadedScene);
				AsyncOperation unloadOp = SceneManager.UnloadSceneAsync(loadedScene);
				if (unloadOp != null)
				{
					while (!unloadOp.isDone)
					{
						yield return null;
					}
				}
			}
			if ((Object)(object)mainCam != (Object)null)
			{
				mainCam.cullingMask = savedMask;
			}
			if (success)
			{
				_preloadDone++;
				Log($"preview {mapId} ready");
			}
			else if (aborted && InMenu() && !_queue.Contains(mapId))
			{
				_queue.Add(mapId);
			}
			else if (!aborted)
			{
				_preloadDone++;
			}
		}

		private static IEnumerator CustomCaptureRoutine(int customIndex)
		{
			IEnumerator core = CustomCaptureCore(customIndex);
			while (true)
			{
				bool moveNext;
				try
				{
					moveNext = core.MoveNext();
				}
				catch (Exception ex)
				{
					Exception ex2 = ex;
					Log($"custom preview {customIndex} FAILED: {ex2}");
					_running = false;
					_customCaptureFailures++;
					if (InMenu() && _customCaptureFailures < 3)
					{
						_queue.Add(customIndex);
					}
					else
					{
						Log($"custom preview {customIndex}: giving up after {_customCaptureFailures} failures (fallback preview stays)");
					}
					yield break;
				}
				if (!moveNext)
				{
					break;
				}
				yield return core.Current;
			}
			_running = false;
		}

		private static IEnumerator CustomCaptureCore(int customIndex)
		{
			int baseLevel = MapMakerBridge.BaseLevelIdOf(customIndex);
			int buildIndex = 6 + baseLevel;
			Scene loadedScene = default(Scene);
			bool success = false;
			bool aborted = false;
			Scene menuScene = SceneManager.GetActiveScene();
			List<GameObject> menuRootsBefore = new List<GameObject>();
			try
			{
				GameObject[] rootGameObjects = ((Scene)(ref menuScene)).GetRootGameObjects();
				foreach (GameObject go in rootGameObjects)
				{
					if ((Object)(object)go != (Object)null)
					{
						menuRootsBefore.Add(go);
					}
				}
			}
			catch
			{
			}
			int savedIndex = MapMakerBridge.CurrentCustomMapIndex();
			int savedUuid = MapMakerBridge.CurrentMapUuid();
			int savedNext = MapMakerBridge.NextMapIndex();
			Camera mainCam = Camera.main;
			int savedMask = (((Object)(object)mainCam != (Object)null) ? mainCam.cullingMask : (-1));
			if ((Object)(object)mainCam != (Object)null && (mainCam.cullingMask & int.MinValue) != 0)
			{
				mainCam.cullingMask &= 0x7FFFFFFF;
			}
			MapMakerBridge.CommitWinner(customIndex);
			AsyncOperation loadOp = SceneManager.LoadSceneAsync(buildIndex, (LoadSceneMode)1);
			if (loadOp != null)
			{
				bool sceneReady = false;
				loadOp.completed += delegate
				{
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					//IL_0041: Unknown result type (might be due to invalid IL or missing references)
					//IL_0042: Unknown result type (might be due to invalid IL or missing references)
					Scene sceneByBuildIndex = SceneManager.GetSceneByBuildIndex(buildIndex);
					if (((Scene)(ref sceneByBuildIndex)).IsValid() && ((Scene)(ref sceneByBuildIndex)).isLoaded)
					{
						MapMakerBridge.CommitWinner(customIndex);
						loadedScene = sceneByBuildIndex;
					}
					sceneReady = true;
				};
				while (!sceneReady)
				{
					if (!InMenu())
					{
						aborted = true;
					}
					yield return null;
				}
				if (!aborted && ((Scene)(ref loadedScene)).IsValid() && ((Scene)(ref loadedScene)).isLoaded)
				{
					for (int f = 0; f < 3; f++)
					{
						yield return null;
						if (!InMenu())
						{
							aborted = true;
							break;
						}
					}
					MoveNewMenuRootsToScene(menuScene, menuRootsBefore, loadedScene);
					DestroyMapTitleText(loadedScene);
					int platformBaseLayer = FindPlatformBaseLayer(loadedScene);
					SetLayersAndDisableCameras(loadedScene);
					yield return (object)new WaitForEndOfFrame();
					if (!InMenu())
					{
						aborted = true;
					}
					if (!aborted)
					{
						FreezePlatformsInPlace(loadedScene, platformBaseLayer);
						Physics2D.SyncTransforms();
						LevelType levelType = GetPreviewLevelType(loadedScene);
						if (TryCapture(bg: (Color)(((int)levelType == 2) ? Color.black : new Color(0.53f, 0.81f, 0.92f, 1f)), s: loadedScene, mapId: customIndex, platformBaseLayer: platformBaseLayer, sprite: out var sprite))
						{
							MapPreviewManager.InstallRealPreview(customIndex, sprite);
							SaveCustomCache(customIndex, sprite.texture);
							success = true;
						}
					}
				}
				else if (!aborted)
				{
					Log($"custom preview {customIndex} SKIPPED: scene {buildIndex} failed to load");
				}
			}
			MapMakerBridge.RestoreState(savedIndex, savedUuid, savedNext);
			if (((Scene)(ref loadedScene)).IsValid() && ((Scene)(ref loadedScene)).isLoaded)
			{
				SetAllRootsToLayer(loadedScene);
				AsyncOperation unloadOp = SceneManager.UnloadSceneAsync(loadedScene);
				if (unloadOp != null)
				{
					while (!unloadOp.isDone)
					{
						yield return null;
					}
				}
			}
			if ((Object)(object)mainCam != (Object)null)
			{
				mainCam.cullingMask = savedMask;
			}
			if (success)
			{
				_customCaptureFailures = 0;
				_preloadDone++;
				Log($"custom preview {customIndex} ready (screenshot of \"{MapMakerBridge.MapNameOf(customIndex)}\")");
			}
			else if (aborted && InMenu() && !_queue.Contains(customIndex))
			{
				_queue.Add(customIndex);
			}
			else if (!aborted)
			{
				_customCaptureFailures++;
				_preloadDone++;
				Log($"custom preview {customIndex} FAILED, fallback preview stays (baseLevel={baseLevel}, scene={buildIndex})");
			}
		}

		private static void MoveNewMenuRootsToScene(Scene menuScene, List<GameObject> rootsBefore, Scene target)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject[] rootGameObjects = ((Scene)(ref menuScene)).GetRootGameObjects();
				foreach (GameObject val in rootGameObjects)
				{
					if (!((Object)(object)val == (Object)null) && !rootsBefore.Contains(val) && val.activeSelf && !((Object)(object)val.GetComponent("Canvas") != (Object)null) && !_mapMakerTemplateNames.Contains(((Object)val).name))
					{
						SceneManager.MoveGameObjectToScene(val, target);
					}
				}
			}
			catch
			{
			}
		}

		private static void DestroyMapTitleText(Scene s)
		{
			try
			{
				GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
				foreach (GameObject val in rootGameObjects)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Component[] componentsInChildren = val.GetComponentsInChildren<Component>(true);
					Component[] array = componentsInChildren;
					foreach (Component val2 in array)
					{
						if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name == "FadeOutText")
						{
							Object.Destroy((Object)(object)val2.gameObject);
						}
					}
				}
			}
			catch
			{
			}
		}

		private static int FindPlatformBaseLayer(Scene s)
		{
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				StickyRoundedRectangle[] componentsInChildren = val.GetComponentsInChildren<StickyRoundedRectangle>(true);
				foreach (StickyRoundedRectangle val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null && !((MonoUpdatable)val2).IsDestroyed)
					{
						return ((Component)val2).gameObject.layer;
					}
				}
			}
			return -1;
		}

		private static void SetLayersAndDisableCameras(Scene s)
		{
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				SetLayerRecursive(val, 31);
				Camera[] componentsInChildren = val.GetComponentsInChildren<Camera>(true);
				foreach (Camera val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						((Behaviour)val2).enabled = false;
					}
				}
			}
		}

		private static void SetAllRootsToLayer(Scene s)
		{
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if (!((Object)(object)val == (Object)null))
				{
					SetLayerRecursive(val, 31);
				}
			}
		}

		private static void SetLayerRecursive(GameObject obj, int layer)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if ((Object)(object)obj == (Object)null)
			{
				return;
			}
			obj.layer = layer;
			foreach (Transform item in obj.transform)
			{
				Transform val = item;
				SetLayerRecursive(((Component)val).gameObject, layer);
			}
		}

		private static LevelType GetPreviewLevelType(Scene s)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				GameSessionHandler[] componentsInChildren = val.GetComponentsInChildren<GameSessionHandler>(true);
				foreach (GameSessionHandler val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null && (int)val2.levelType == 2)
					{
						return (LevelType)2;
					}
				}
			}
			return (LevelType)0;
		}

		private static bool RestorePlatformPoses(Scene s, int baseLayer)
		{
			bool result = false;
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				StickyRoundedRectangle[] componentsInChildren = val.GetComponentsInChildren<StickyRoundedRectangle>(true);
				foreach (StickyRoundedRectangle val2 in componentsInChildren)
				{
					if (!((Object)(object)val2 == (Object)null) && !((MonoUpdatable)val2).IsDestroyed)
					{
						if (baseLayer >= 0)
						{
							((Component)val2).gameObject.layer = baseLayer;
						}
						if (MoveToSerializedPose(val2))
						{
							result = true;
						}
					}
				}
			}
			return result;
		}

		private static void FreezePlatformsInPlace(Scene s, int baseLayer)
		{
			//IL_0094: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				StickyRoundedRectangle[] componentsInChildren = val.GetComponentsInChildren<StickyRoundedRectangle>(true);
				foreach (StickyRoundedRectangle val2 in componentsInChildren)
				{
					if (!((Object)(object)val2 == (Object)null) && !((MonoUpdatable)val2).IsDestroyed)
					{
						if (baseLayer >= 0)
						{
							((Component)val2).gameObject.layer = baseLayer;
						}
						BoplBody component = ((Component)val2).GetComponent<BoplBody>();
						if ((Object)(object)component != (Object)null)
						{
							component.velocity = Vec2.zero;
							component.angularVelocity = Fix.Zero;
						}
						AnimateVelocity component2 = ((Component)val2).GetComponent<AnimateVelocity>();
						if ((Object)(object)component2 != (Object)null)
						{
							((Behaviour)component2).enabled = false;
						}
						DPhysicsRoundedRect component3 = ((Component)val2).GetComponent<DPhysicsRoundedRect>();
						if ((Object)(object)component3 != (Object)null)
						{
							component3.velocity = Vec2.zero;
							component3.angularVelocity = Fix.Zero;
							((Behaviour)component3).enabled = false;
						}
						val2.UpdateBounds();
					}
				}
			}
		}

		private static bool MoveToSerializedPose(StickyRoundedRectangle block)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			FixTransform component = ((Component)block).GetComponent<FixTransform>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			component.position = component.serializedPosition;
			component.rotation = component.serializedRotation;
			BoplBody component2 = ((Component)block).GetComponent<BoplBody>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.position = component.serializedPosition;
				component2.rotation = component.serializedRotation;
				component2.velocity = Vec2.zero;
				component2.angularVelocity = Fix.Zero;
			}
			AnimateVelocity component3 = ((Component)block).GetComponent<AnimateVelocity>();
			if ((Object)(object)component3 != (Object)null)
			{
				bool homeIsMovable = component3.HomeIsMovable;
				component3.HomeIsMovable = true;
				component3.HomePosition = component.serializedPosition;
				component3.HomeIsMovable = homeIsMovable;
				((Behaviour)component3).enabled = false;
			}
			DPhysicsRoundedRect component4 = ((Component)block).GetComponent<DPhysicsRoundedRect>();
			if ((Object)(object)component4 != (Object)null)
			{
				component4.velocity = Vec2.zero;
				component4.angularVelocity = Fix.Zero;
				((Behaviour)component4).enabled = false;
			}
			block.UpdateBounds();
			component.SyncTransform();
			return true;
		}

		private static bool TryGetRenderBounds(Scene s, out Bounds bounds)
		{
			//IL_0002: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			bool flag = false;
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null && val2.enabled && ((Component)val2).gameObject.activeInHierarchy && IsUsable(val2.bounds))
					{
						if (!flag)
						{
							bounds = val2.bounds;
							flag = true;
						}
						else
						{
							((Bounds)(ref bounds)).Encapsulate(val2.bounds);
						}
					}
				}
				Collider2D[] componentsInChildren2 = val.GetComponentsInChildren<Collider2D>(true);
				foreach (Collider2D val3 in componentsInChildren2)
				{
					if ((Object)(object)val3 != (Object)null && ((Behaviour)val3).enabled && ((Component)val3).gameObject.activeInHierarchy && IsUsable(val3.bounds))
					{
						if (!flag)
						{
							bounds = val3.bounds;
							flag = true;
						}
						else
						{
							((Bounds)(ref bounds)).Encapsulate(val3.bounds);
						}
					}
				}
			}
			return flag;
		}

		private static bool IsUsable(Bounds b)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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)
			return IsFinite(((Bounds)(ref b)).center.x) && IsFinite(((Bounds)(ref b)).center.y) && IsFinite(((Bounds)(ref b)).size.x) && IsFinite(((Bounds)(ref b)).size.y) && ((Bounds)(ref b)).size.x > 0.02f && ((Bounds)(ref b)).size.y > 0.02f && ((Bounds)(ref b)).size.x < 400f && ((Bounds)(ref b)).size.y < 400f;
		}

		private static bool IsFinite(float v)
		{
			return !float.IsNaN(v) && !float.IsInfinity(v);
		}

		private static float GetVanillaZoom(Scene s)
		{
			GameObject[] rootGameObjects = ((Scene)(ref s)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				PlayerAverageCamera[] componentsInChildren = val.GetComponentsInChildren<PlayerAverageCamera>(true);
				foreach (PlayerAverageCamera val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null && IsFinite(val2.MIN_ZOOM) && val2.MIN_ZOOM > 0.05f)
					{
						return val2.MIN_ZOOM;
					}
				}
			}
			return 13f;
		}

		private static bool TryCapture(Scene s, int mapId, int platformBaseLayer, Color bg, out Sprite sprite)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			sprite = null;
			if (!TryGetRenderBounds(s, out var bounds))
			{
				Log($"preview {mapId} SKIPPED: no render bounds");
				return false;
			}
			GameObject val = new GameObject("NextMapVotePreviewCamera");
			SceneManager.MoveGameObjectToScene(val, s);
			Camera val2 = val.AddComponent<Camera>();
			val2.orthographic = true;
			float vanillaZoom = GetVanillaZoom(s);
			float num = Mathf.Max(1f, ((Bounds)(ref bounds)).extents.y + 0.5f);
			float num2 = Mathf.Max(1f, ((Bounds)(ref bounds)).extents.x / 1.7777778f + 0.5f);
			val2.orthographicSize = Mathf.Clamp(Mathf.Max(vanillaZoom, Mathf.Max(num, num2)), 8f, 80f) * 0.5f;
			((Component)val2).transform.position = new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y, -40f);
			((Component)val2).transform.rotation = Quaternion.identity;
			val2.clearFlags = (CameraClearFlags)2;
			val2.backgroundColor = bg;
			val2.cullingMask = ((platformBaseLayer >= 0) ? (1 << platformBaseLayer) : (-1));
			val2.nearClipPlane = 0.01f;
			val2.farClipPlane = 1000f;
			val2.depth = 1000f;
			Texture2D val3 = null;
			bool flag = false;
			RenderTexture val4 = null;
			RenderTexture active = RenderTexture.active;
			RenderTexture targetTexture = val2.targetTexture;
			bool enabled = ((Behaviour)val2).enabled;
			float aspect = val2.aspect;
			try
			{
				val4 = new RenderTexture(640, 360, 24, (RenderTextureFormat)0);
				val4.Create();
				((Behaviour)val2).enabled = true;
				val2.aspect = 1.7777778f;
				val2.targetTexture = val4;
				RenderTexture.active = val4;
				val2.Render();
				val3 = new Texture2D(640, 360, (TextureFormat)4, false);
				val3.ReadPixels(new Rect(0f, 0f, 640f, 360f), 0, 0, false);
				val3.Apply(false, false);
				flag = true;
			}
			catch (Exception ex)
			{
				Log($"preview render FAILED for map {mapId}: {ex.Message}");
				if ((Object)(object)val3 != (Object)null)
				{
					Object.Destroy((Object)(object)val3);
				}
				val3 = null;
				flag = false;
			}
			finally
			{
				val2.targetTexture = targetTexture;
				((Behaviour)val2).enabled = enabled;
				val2.aspect = aspect;
				RenderTexture.active = active;
				if ((Object)(object)val4 != (Object)null)
				{
					val4.Release();
					Object.Destroy((Object)(object)val4);
				}
			}
			Object.Destroy((Object)(object)val);
			if (!flag || (Object)(object)val3 == (Object)null)
			{
				return false;
			}
			sprite = Sprite.Create(val3, new Rect(0f, 0f, (float)((Texture)val3).width, (float)((Texture)val3).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)sprite).name = "nextmapvote_preview_" + mapId;
			return true;
		}

		private static string SharedCacheDir()
		{
			try
			{
				string text = Path.Combine(Paths.PluginPath, "PmodMapPreview");
				MigrateLegacyCacheDir(text);
				return text;
			}
			catch
			{
				return string.Empty;
			}
		}

		private static void MigrateLegacyCacheDir(string newDir)
		{
			string text = Path.Combine(Paths.PluginPath, "PmodRoundMapPreview");
			if (string.IsNullOrEmpty(text) || text == newDir || !Directory.Exists(text))
			{
				return;
			}
			if (!Directory.Exists(newDir))
			{
				Directory.Move(text, newDir);
				return;
			}
			string[] files = Directory.GetFiles(text);
			foreach (string text2 in files)
			{
				string text3 = Path.Combine(newDir, Path.GetFileName(text2));
				if (!File.Exists(text3))
				{
					File.Move(text2, text3);
				}
				else
				{
					File.Delete(text2);
				}
			}
			Directory.Delete(text, recursive: true);
		}

		private static string PngCachePath(int mapId)
		{
			return Path.Combine(SharedCacheDir(), "map_" + mapId + ".png");
		}

		private static string CustomCachePath(int customIndex)
		{
			return Path.Combine(SharedCacheDir(), "custom_" + customIndex + ".png");
		}

		public static bool TryLoadCustomCache(int customIndex, out Texture2D tex)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			tex = null;
			string text = CustomCachePath(customIndex);
			if (string.IsNullOrEmpty(text) || !File.Exists(text))
			{
				return false;
			}
			try
			{
				byte[] array = File.ReadAllBytes(text);
				tex = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(tex, array))
				{
					Object.Destroy((Object)(object)tex);
					tex = null;
					return false;
				}
				return true;
			}
			catch
			{
				if ((Object)(object)tex != (Object)null)
				{
					Object.Destroy((Object)(object)tex);
				}
				tex = null;
				return false;
			}
		}

		public static void SaveCustomCache(int customIndex, Texture2D tex)
		{
			string text = SharedCacheDir();
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			try
			{
				Directory.CreateDirectory(text);
				File.WriteAllBytes(CustomCachePath(customIndex), ImageConversion.EncodeToPNG(tex));
			}
			catch
			{
			}
		}

		public static bool HasSharedCacheFile(int mapId)
		{
			string text = SharedCacheDir();
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			return File.Exists(Path.Combine(text, "map_" + mapId + ".png"));
		}

		public static bool HasCustomCacheFile(int customIndex)
		{
			string text = SharedCacheDir();
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			return File.Exists(Path.Combine(text, "custom_" + customIndex + ".png"));
		}

		public static bool TryLoadSharedCache(int mapId, out Texture2D tex)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			tex = null;
			string text = PngCachePath(mapId);
			if (string.IsNullOrEmpty(text) || !File.Exists(text))
			{
				return false;
			}
			try
			{
				byte[] array = File.ReadAllBytes(text);
				tex = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(tex, array))
				{
					Object.Destroy((Object)(object)tex);
					tex = null;
					return false;
				}
				((Object)tex).name = "nextmapvote_sharedcache_" + mapId;
				return true;
			}
			catch (Exception ex)
			{
				Log($"preview cache load FAILED for map {mapId}: {ex.Message}");
				if ((Object)(object)tex != (Object)null)
				{
					Object.Destroy((Object)(object)tex);
				}
				tex = null;
				return false;
			}
		}

		public static bool EnsureSharedCacheAsync(int mapId)
		{
			if (MapPreviewManager.HasRealPreview(mapId))
			{
				return true;
			}
			lock (_cacheLock)
			{
				if (_pendingCacheLoads.Contains(mapId))
				{
					return true;
				}
				if (!HasSharedCacheFile(mapId))
				{
					return false;
				}
				_pendingCacheLoads.Add(mapId);
			}
			ThreadPool.QueueUserWorkItem(delegate
			{
				bool flag = false;
				try
				{
					byte[] array = File.ReadAllBytes(PngCachePath(mapId));
					if (array != null && array.Length != 0)
					{
						lock (_cacheLock)
						{
							_finishedCacheLoads.Enqueue(new CacheLoadJob
							{
								MapId = mapId,
								PngBytes = array
							});
						}
						flag = true;
					}
				}
				catch
				{
				}
				if (!flag)
				{
					lock (_cacheLock)
					{
						_pendingCacheLoads.Remove(mapId);
						_finishedCacheLoads.Enqueue(new CacheLoadJob
						{
							MapId = mapId,
							PngBytes = null
						});
					}
				}
			});
			return true;
		}

		public static void PumpMainThreadJobs()
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			int num = 0;
			while (true)
			{
				bool flag;
				CacheLoadJob cacheLoadJob;
				lock (_cacheLock)
				{
					flag = _finishedCacheLoads.Count > 0;
					cacheLoadJob = ((!flag) ? default(CacheLoadJob) : _finishedCacheLoads.Peek());
				}
				if (!flag || num >= 3)
				{
					break;
				}
				lock (_cacheLock)
				{
					_finishedCacheLoads.Dequeue();
					_pendingCacheLoads.Remove(cacheLoadJob.MapId);
				}
				if (cacheLoadJob.PngBytes == null)
				{
					_preloadDone++;
					continue;
				}
				if (MapPreviewManager.HasRealPreview(cacheLoadJob.MapId))
				{
					_preloadDone++;
					continue;
				}
				Texture2D val = null;
				try
				{
					val = new Texture2D(2, 2, (TextureFormat)4, false);
					if (!ImageConversion.LoadImage(val, cacheLoadJob.PngBytes))
					{
						Object.Destroy((Object)(object)val);
						_preloadDone++;
						continue;
					}
					((Object)val).name = "nextmapvote_sharedcache_" + cacheLoadJob.MapId;
				}
				catch (Exception ex)
				{
					Log($"preview cache install FAILED for map {cacheLoadJob.MapId}: {ex.Message}");
					if ((Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)val);
					}
					_preloadDone++;
					continue;
				}
				MapPreviewManager.InstallTexturePreview(cacheLoadJob.MapId, val);
				_preloadDone++;
				_installsSinceLog++;
				if (_installsSinceLog >= 10 || (_preloadTotal > 0 && _preloadDone >= _preloadTotal))
				{
					_installsSinceLog = 0;
					Log($"preload: {PreloadDone}/{PreloadTotal} previews ready");
				}
				num++;
			}
		}

		public static void ForceSyncWinnerPreview(int mapId)
		{
			if (MapPreviewManager.HasRealPreview(mapId))
			{
				return;
			}
			Texture2D tex;
			if (MapMakerBridge.Active)
			{
				if (TryLoadCustomCache(mapId, out tex))
				{
					MapPreviewManager.InstallTexturePreview(mapId, tex);
				}
			}
			else if (TryLoadSharedCache(mapId, out tex))
			{
				MapPreviewManager.InstallTexturePreview(mapId, tex);
			}
		}

		private static void TrySaveSharedCache(int mapId, Texture2D tex)
		{
			if ((Object)(object)tex == (Object)null)
			{
				return;
			}
			try
			{
				string text = SharedCacheDir();
				if (string.IsNullOrEmpty(text))
				{
					return;
				}
				Directory.CreateDirectory(text);
				string text2 = PngCachePath(mapId);
				File.WriteAllBytes(text2, ImageConversion.EncodeToPNG(tex));
				string path = Path.Combine(text, "map_" + mapId + ".bin");
				if (File.Exists(path))
				{
					try
					{
						File.Delete(path);
					}
					catch
					{
					}
				}
				Log($"preview {mapId} saved to appdata cache: {text2}");
			}
			catch (Exception ex)
			{
				Log($"preview cache save FAILED for map {mapId}: {ex.Message}");
			}
		}

		private static void Log(string msg)
		{
			ManualLogSource log = MapPreviewGeneratorPlugin.Log;
			if (log != null)
			{
				log.LogMessage((object)msg);
			}
		}
	}
	public static class PreviewLibrary
	{
		public static bool Busy => PreviewGenerator.Busy;

		public static int PreloadTotal => PreviewGenerator.PreloadTotal;

		public static int PreloadDone => PreviewGenerator.PreloadDone;

		public static bool InMenu => PreviewGenerator.InMenu();

		public static int VanillaMapCount => MapPreviewManager.MapCount();

		public static bool CustomMapsAvailable => MapMakerBridge.Active;

		public static int CustomMapCount => MapMakerBridge.MapCount;

		public static int CurrentCustomMapIndex => MapMakerBridge.CurrentCustomMapIndex();

		public static event Action<int> PreviewReady;

		public static bool HasRealPreview(int mapId)
		{
			return MapPreviewManager.HasRealPreview(mapId);
		}

		public static void EnsurePrepared(int mapId)
		{
			MapPreviewManager.EnsurePreparedImpl(mapId);
		}

		public static bool TryGetSprite(int mapId, out Sprite sprite)
		{
			return MapPreviewManager.TryGetSpriteImpl(mapId, out sprite);
		}

		public static void InstallTexturePreview(int mapId, Texture2D tex)
		{
			MapPreviewManager.InstallTexturePreview(mapId, tex);
		}

		public static void EnsureRealPreviewSync(int mapId)
		{
			PreviewGenerator.ForceSyncWinnerPreview(mapId);
		}

		public static void StartPreloadAll()
		{
			PreviewGenerator.StartPreloadAll();
		}

		public static void QueueAllMissing()
		{
			PreviewGenerator.QueueAllMissing();
		}

		public static string CustomMapName(int customIndex)
		{
			return MapMakerBridge.MapNameOf(customIndex);
		}

		public static string CustomMapType(int customIndex)
		{
			return MapMakerBridge.MapTypeOf(customIndex);
		}

		public static int CustomMapBaseLevelId(int customIndex)
		{
			return MapMakerBridge.BaseLevelIdOf(customIndex);
		}

		public static string CustomMapJson(int customIndex)
		{
			return MapMakerBridge.MapJsonOf(customIndex);
		}

		public static void EnsureCustomPrepared(int customIndex)
		{
			MapPreviewManager.EnsurePreparedImpl(customIndex);
		}

		public static bool TryGetCustomSprite(int customIndex, out Sprite sprite)
		{
			return MapPreviewManager.TryGetSpriteImpl(customIndex, out sprite);
		}

		public static void CommitCustomMap(int customIndex)
		{
			MapMakerBridge.CommitWinner(customIndex);
		}

		public static void EnsureCommitted(int customIndex)
		{
			MapMakerBridge.EnsureCommitted(customIndex);
		}

		internal static void RaisePreviewReady(int mapId)
		{
			PreviewLibrary.PreviewReady?.Invoke(mapId);
		}
	}
}