Due to update 2.4.3, some mods may no longer function. FixedConfig may be necessary.
Decompiled source of MapPreviewGenerator v1.0.1
plugins/PMod.MapPreviewGenerator.dll
Decompiled 13 hours agousing 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); } } }