Decompiled source of UltrakULL Apodidae Remix v1.3.1

UltrakULL.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ArabicSupportUnity;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Discord;
using GreyAnnouncer.AudioClipLoad;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Sandbox;
using ScriptableObjects;
using SettingsMenu.Components;
using TMPro;
using UltrakULL.Harmony_Patches;
using UltrakULL.audio;
using UltrakULL.json;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: AssemblyCompany("UltrakULL")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+5d3593b83edaaef43c4ff49e68f996fe97c408cb")]
[assembly: AssemblyProduct("UltrakULL")]
[assembly: AssemblyTitle("UltrakULL")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class ExtensionMarkerAttribute : Attribute
	{
		public ExtensionMarkerAttribute(string name)
		{
		}
	}
}
internal enum IsolatedArabicLetters
{
	Hamza = 65152,
	Alef = 65165,
	AlefHamza = 65155,
	WawHamza = 65157,
	AlefMaksoor = 65159,
	AlefMaksora = 64508,
	HamzaNabera = 65161,
	Ba = 65167,
	Ta = 65173,
	Tha2 = 65177,
	Jeem = 65181,
	H7aa = 65185,
	Khaa2 = 65189,
	Dal = 65193,
	Thal = 65195,
	Ra2 = 65197,
	Zeen = 65199,
	Seen = 65201,
	Sheen = 65205,
	S9a = 65209,
	Dha = 65213,
	T6a = 65217,
	T6ha = 65221,
	Ain = 65225,
	Gain = 65229,
	Fa = 65233,
	Gaf = 65237,
	Kaf = 65241,
	Lam = 65245,
	Meem = 65249,
	Noon = 65253,
	Ha = 65257,
	Waw = 65261,
	Ya = 65265,
	AlefMad = 65153,
	TaMarboota = 65171,
	PersianPe = 64342,
	PersianChe = 64378,
	PersianZe = 64394,
	PersianGaf = 64402,
	PersianGaf2 = 64398,
	PersianYeh = 64508
}
internal enum GeneralArabicLetters
{
	Hamza = 1569,
	Alef = 1575,
	AlefHamza = 1571,
	WawHamza = 1572,
	AlefMaksoor = 1573,
	AlefMagsora = 1609,
	HamzaNabera = 1574,
	Ba = 1576,
	Ta = 1578,
	Tha2 = 1579,
	Jeem = 1580,
	H7aa = 1581,
	Khaa2 = 1582,
	Dal = 1583,
	Thal = 1584,
	Ra2 = 1585,
	Zeen = 1586,
	Seen = 1587,
	Sheen = 1588,
	S9a = 1589,
	Dha = 1590,
	T6a = 1591,
	T6ha = 1592,
	Ain = 1593,
	Gain = 1594,
	Fa = 1601,
	Gaf = 1602,
	Kaf = 1603,
	Lam = 1604,
	Meem = 1605,
	Noon = 1606,
	Ha = 1607,
	Waw = 1608,
	Ya = 1610,
	AlefMad = 1570,
	TaMarboota = 1577,
	PersianPe = 1662,
	PersianChe = 1670,
	PersianZe = 1688,
	PersianGaf = 1711,
	PersianGaf2 = 1705,
	PersianYeh = 1740
}
internal struct ArabicMapping
{
	public int from;

	public int to;

	public ArabicMapping(int from, int to)
	{
		this.from = from;
		this.to = to;
	}
}
internal class ArabicTable
{
	private static ArabicMapping[] mapList;

	private static ArabicTable arabicMapper;

	internal static ArabicTable ArabicMapper
	{
		get
		{
			if (arabicMapper == null)
			{
				arabicMapper = new ArabicTable();
			}
			return arabicMapper;
		}
	}

	private ArabicTable()
	{
		mapList = new ArabicMapping[42]
		{
			new ArabicMapping(1569, 65152),
			new ArabicMapping(1575, 65165),
			new ArabicMapping(1571, 65155),
			new ArabicMapping(1572, 65157),
			new ArabicMapping(1573, 65159),
			new ArabicMapping(1609, 64508),
			new ArabicMapping(1574, 65161),
			new ArabicMapping(1576, 65167),
			new ArabicMapping(1578, 65173),
			new ArabicMapping(1579, 65177),
			new ArabicMapping(1580, 65181),
			new ArabicMapping(1581, 65185),
			new ArabicMapping(1582, 65189),
			new ArabicMapping(1583, 65193),
			new ArabicMapping(1584, 65195),
			new ArabicMapping(1585, 65197),
			new ArabicMapping(1586, 65199),
			new ArabicMapping(1587, 65201),
			new ArabicMapping(1588, 65205),
			new ArabicMapping(1589, 65209),
			new ArabicMapping(1590, 65213),
			new ArabicMapping(1591, 65217),
			new ArabicMapping(1592, 65221),
			new ArabicMapping(1593, 65225),
			new ArabicMapping(1594, 65229),
			new ArabicMapping(1601, 65233),
			new ArabicMapping(1602, 65237),
			new ArabicMapping(1603, 65241),
			new ArabicMapping(1604, 65245),
			new ArabicMapping(1605, 65249),
			new ArabicMapping(1606, 65253),
			new ArabicMapping(1607, 65257),
			new ArabicMapping(1608, 65261),
			new ArabicMapping(1610, 65265),
			new ArabicMapping(1570, 65153),
			new ArabicMapping(1577, 65171),
			new ArabicMapping(1662, 64342),
			new ArabicMapping(1670, 64378),
			new ArabicMapping(1688, 64394),
			new ArabicMapping(1711, 64402),
			new ArabicMapping(1705, 64398),
			new ArabicMapping(1740, 64508)
		};
	}

	internal int Convert(int toBeConverted)
	{
		for (int i = 0; i < mapList.Length; i++)
		{
			ArabicMapping arabicMapping = mapList[i];
			if (arabicMapping.from == toBeConverted)
			{
				return arabicMapping.to;
			}
		}
		return toBeConverted;
	}
}
internal class TashkeelLocation
{
	public char tashkeel;

	public int position;

	public TashkeelLocation(char tashkeel, int position)
	{
		this.tashkeel = tashkeel;
		this.position = position;
	}
}
internal class ArabicFixerTool
{
	internal static bool showTashkeel = true;

	internal static bool combineTashkeel = true;

	internal static bool useHinduNumbers = true;

	internal static StringBuilder internalStringBuilder = new StringBuilder();

	internal static void RemoveTashkeel(ref string str, out List<TashkeelLocation> tashkeelLocation)
	{
		tashkeelLocation = new List<TashkeelLocation>();
		int lastSplitIndex = 0;
		internalStringBuilder.Clear();
		internalStringBuilder.EnsureCapacity(str.Length);
		int num = 0;
		for (int i = 0; i < str.Length; i++)
		{
			if (str[i] == '\u064b')
			{
				tashkeelLocation.Add(new TashkeelLocation('\u064b', i));
				num++;
				IncrementSB(ref str, i);
			}
			else if (str[i] == '\u064c')
			{
				tashkeelLocation.Add(new TashkeelLocation('\u064c', i));
				num++;
				IncrementSB(ref str, i);
			}
			else if (str[i] == '\u064d')
			{
				tashkeelLocation.Add(new TashkeelLocation('\u064d', i));
				num++;
				IncrementSB(ref str, i);
			}
			else if (str[i] == '\u064e')
			{
				if (num > 0 && combineTashkeel && tashkeelLocation[num - 1].tashkeel == '\u0651')
				{
					tashkeelLocation[num - 1].tashkeel = 'ﱠ';
					IncrementSB(ref str, i);
				}
				else
				{
					tashkeelLocation.Add(new TashkeelLocation('\u064e', i));
					num++;
					IncrementSB(ref str, i);
				}
			}
			else if (str[i] == '\u064f')
			{
				if (num > 0 && combineTashkeel && tashkeelLocation[num - 1].tashkeel == '\u0651')
				{
					tashkeelLocation[num - 1].tashkeel = 'ﱡ';
					IncrementSB(ref str, i);
				}
				else
				{
					tashkeelLocation.Add(new TashkeelLocation('\u064f', i));
					num++;
					IncrementSB(ref str, i);
				}
			}
			else if (str[i] == '\u0650')
			{
				if (num > 0 && combineTashkeel && tashkeelLocation[num - 1].tashkeel == '\u0651')
				{
					tashkeelLocation[num - 1].tashkeel = 'ﱢ';
					IncrementSB(ref str, i);
				}
				else
				{
					tashkeelLocation.Add(new TashkeelLocation('\u0650', i));
					num++;
					IncrementSB(ref str, i);
				}
			}
			else if (str[i] == '\u0651')
			{
				if (num > 0 && combineTashkeel)
				{
					if (tashkeelLocation[num - 1].tashkeel == '\u064e')
					{
						tashkeelLocation[num - 1].tashkeel = 'ﱠ';
						IncrementSB(ref str, i);
						continue;
					}
					if (tashkeelLocation[num - 1].tashkeel == '\u064f')
					{
						tashkeelLocation[num - 1].tashkeel = 'ﱡ';
						IncrementSB(ref str, i);
						continue;
					}
					if (tashkeelLocation[num - 1].tashkeel == '\u0650')
					{
						tashkeelLocation[num - 1].tashkeel = 'ﱢ';
						IncrementSB(ref str, i);
						continue;
					}
				}
				tashkeelLocation.Add(new TashkeelLocation('\u0651', i));
				num++;
				IncrementSB(ref str, i);
			}
			else if (str[i] == '\u0652')
			{
				tashkeelLocation.Add(new TashkeelLocation('\u0652', i));
				num++;
				IncrementSB(ref str, i);
			}
			else if (str[i] == '\u0653')
			{
				tashkeelLocation.Add(new TashkeelLocation('\u0653', i));
				num++;
				IncrementSB(ref str, i);
			}
			else if (str[i] == 'ﱠ')
			{
				IncrementSB(ref str, i);
			}
			else if (str[i] == 'ﱡ')
			{
				IncrementSB(ref str, i);
			}
			else if (str[i] == 'ﱢ')
			{
				IncrementSB(ref str, i);
			}
		}
		if (lastSplitIndex != 0)
		{
			IncrementSB(ref str, str.Length);
			str = internalStringBuilder.ToString();
		}
		void IncrementSB(ref string reference, int num2)
		{
			if (num2 - lastSplitIndex > 0)
			{
				internalStringBuilder.Append(reference, lastSplitIndex, num2 - lastSplitIndex);
			}
			lastSplitIndex = num2 + 1;
		}
	}

	internal static void ReturnTashkeel(ref char[] letters, List<TashkeelLocation> tashkeelLocation)
	{
		Array.Resize(ref letters, letters.Length + tashkeelLocation.Count);
		for (int i = 0; i < tashkeelLocation.Count; i++)
		{
			TashkeelLocation tashkeelLocation2 = tashkeelLocation[i];
			for (int num = letters.Length - 1; num > tashkeelLocation2.position; num--)
			{
				letters[num] = letters[num - 1];
			}
			letters[tashkeelLocation2.position] = tashkeelLocation2.tashkeel;
		}
	}

	internal static string FixLine(string str)
	{
		RemoveTashkeel(ref str, out var tashkeelLocation);
		char[] array = new char[str.Length];
		char[] letters = str.ToCharArray();
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = (char)ArabicTable.ArabicMapper.Convert(str[i]);
		}
		for (int j = 0; j < array.Length; j++)
		{
			bool flag = false;
			if (array[j] == 'ﻝ' && j < array.Length - 1)
			{
				if (array[j + 1] == 'ﺇ')
				{
					array[j] = 'ﻷ';
					letters[j + 1] = '\uffff';
					flag = true;
				}
				else if (array[j + 1] == 'ﺍ')
				{
					array[j] = 'ﻹ';
					letters[j + 1] = '\uffff';
					flag = true;
				}
				else if (array[j + 1] == 'ﺃ')
				{
					array[j] = 'ﻵ';
					letters[j + 1] = '\uffff';
					flag = true;
				}
				else if (array[j + 1] == 'ﺁ')
				{
					array[j] = 'ﻳ';
					letters[j + 1] = '\uffff';
					flag = true;
				}
			}
			if (!IsIgnoredCharacter(array[j]))
			{
				if (IsMiddleLetter(array, j))
				{
					letters[j] = (char)(array[j] + 3);
				}
				else if (IsFinishingLetter(array, j))
				{
					letters[j] = (char)(array[j] + 1);
				}
				else if (IsLeadingLetter(array, j))
				{
					letters[j] = (char)(array[j] + 2);
				}
			}
			if (flag)
			{
				j++;
			}
			letters[j] = (char)HandleInduNumber(array[j], letters[j]);
		}
		if (showTashkeel && tashkeelLocation.Count > 0)
		{
			ReturnTashkeel(ref letters, tashkeelLocation);
		}
		internalStringBuilder.Clear();
		internalStringBuilder.EnsureCapacity(letters.Length);
		List<char> numberList = null;
		for (int num = letters.Length - 1; num >= 0; num--)
		{
			if (char.IsPunctuation(letters[num]) && num > 0 && num < letters.Length - 1 && (char.IsPunctuation(letters[num - 1]) || char.IsPunctuation(letters[num + 1])))
			{
				if (letters[num] != '\uffff')
				{
					internalStringBuilder.Append(letters[num]);
				}
			}
			else if (letters[num] == ' ' && num > 0 && num < letters.Length - 1 && (char.IsLower(letters[num - 1]) || char.IsUpper(letters[num - 1]) || char.IsNumber(letters[num - 1])) && (char.IsLower(letters[num + 1]) || char.IsUpper(letters[num + 1]) || char.IsNumber(letters[num + 1])))
			{
				AddNumber(letters[num]);
			}
			else if (char.IsNumber(letters[num]) || char.IsLower(letters[num]) || char.IsUpper(letters[num]) || char.IsSymbol(letters[num]) || char.IsPunctuation(letters[num]))
			{
				AddNumber(letters[num]);
			}
			else if ((letters[num] >= '\ud800' && letters[num] <= '\udbff') || (letters[num] >= '\udc00' && letters[num] <= '\udfff'))
			{
				AddNumber(letters[num]);
			}
			else
			{
				AppendNumbers();
				if (letters[num] != '\uffff')
				{
					internalStringBuilder.Append(letters[num]);
				}
			}
		}
		AppendNumbers();
		return internalStringBuilder.ToString();
		void AddNumber(char value)
		{
			if (numberList == null)
			{
				numberList = new List<char>();
			}
			numberList.Add(value);
		}
		void AppendNumbers()
		{
			if (numberList != null && numberList.Count > 0)
			{
				for (int k = 0; k < numberList.Count; k++)
				{
					internalStringBuilder.Append(numberList[numberList.Count - 1 - k]);
				}
				numberList.Clear();
			}
		}
	}

	internal static ushort HandleInduNumber(ushort letterOrigin, ushort letterFinal)
	{
		return letterOrigin switch
		{
			48 => 1632, 
			49 => 1633, 
			50 => 1634, 
			51 => 1635, 
			52 => 1636, 
			53 => 1637, 
			54 => 1638, 
			55 => 1639, 
			56 => 1640, 
			57 => 1641, 
			_ => letterFinal, 
		};
	}

	internal static bool IsIgnoredCharacter(char ch)
	{
		bool flag = char.IsPunctuation(ch);
		bool flag2 = char.IsNumber(ch);
		bool flag3 = char.IsLower(ch);
		bool flag4 = char.IsUpper(ch);
		bool flag5 = char.IsSymbol(ch);
		bool flag6 = ch == 'ﭖ' || ch == 'ﭺ' || ch == 'ﮊ' || ch == 'ﮒ' || ch == 'ﮎ';
		bool flag7 = ch <= '\ufeff' && ch >= 'ﹰ';
		bool flag8 = flag7 || flag6 || ch == 'ﯼ';
		return flag || flag2 || flag3 || flag4 || flag5 || !flag8 || ch == 'a' || ch == '>' || ch == '<' || ch == '؛';
	}

	internal static bool IsLeadingLetter(char[] letters, int index)
	{
		bool flag = index == 0 || letters[index - 1] == ' ' || char.IsPunctuation(letters[index - 1]) || letters[index - 1] == 'ﺍ' || letters[index - 1] == 'ﺩ' || letters[index - 1] == 'ﺫ' || letters[index - 1] == 'ﺭ' || letters[index - 1] == 'ﺯ' || letters[index - 1] == 'ﮊ' || letters[index - 1] == 'ﻭ' || letters[index - 1] == 'ﺁ' || letters[index - 1] == 'ﺃ' || letters[index - 1] == 'ﺀ' || letters[index - 1] == 'ﺇ' || letters[index - 1] == 'ﺅ';
		bool flag2 = letters[index] != ' ' && letters[index] != 'ﺩ' && letters[index] != 'ﺫ' && letters[index] != 'ﺭ' && letters[index] != 'ﺯ' && letters[index] != 'ﮊ' && letters[index] != 'ﺍ' && letters[index] != 'ﺃ' && letters[index] != 'ﺇ' && letters[index] != 'ﺁ' && letters[index] != 'ﺅ' && letters[index] != 'ﻭ' && letters[index] != 'ﺀ';
		bool flag3 = index < letters.Length - 1 && letters[index + 1] != ' ' && letters[index + 1] != '\n' && letters[index + 1] != '\r' && !char.IsPunctuation(letters[index + 1]) && !char.IsNumber(letters[index + 1]) && !char.IsSymbol(letters[index + 1]) && !char.IsLower(letters[index + 1]) && !char.IsUpper(letters[index + 1]) && letters[index + 1] != 'ﺀ';
		if (flag && flag2 && flag3)
		{
			return true;
		}
		return false;
	}

	internal static bool IsFinishingLetter(char[] letters, int index)
	{
		bool flag = index != 0;
		bool flag2 = index != 0 && letters[index - 1] != ' ' && letters[index - 1] != 'ﺩ' && letters[index - 1] != 'ﺫ' && letters[index - 1] != 'ﺭ' && letters[index - 1] != 'ﺯ' && letters[index - 1] != 'ﮊ' && letters[index - 1] != 'ﻭ' && letters[index - 1] != 'ﺍ' && letters[index - 1] != 'ﺁ' && letters[index - 1] != 'ﺃ' && letters[index - 1] != 'ﺇ' && letters[index - 1] != 'ﺅ' && letters[index - 1] != 'ﺀ' && !char.IsPunctuation(letters[index - 1]) && !char.IsSymbol(letters[index - 1]);
		bool flag3 = letters[index] != ' ' && letters[index] != 'ﺀ';
		if (flag2 && flag3)
		{
			return true;
		}
		return false;
	}

	internal static bool IsMiddleLetter(char[] letters, int index)
	{
		bool flag = index != 0 && letters[index] != 'ﺍ' && letters[index] != 'ﺩ' && letters[index] != 'ﺫ' && letters[index] != 'ﺭ' && letters[index] != 'ﺯ' && letters[index] != 'ﮊ' && letters[index] != 'ﻭ' && letters[index] != 'ﺁ' && letters[index] != 'ﺃ' && letters[index] != 'ﺇ' && letters[index] != 'ﺅ' && letters[index] != 'ﺀ';
		bool flag2 = index != 0 && letters[index - 1] != 'ﺍ' && letters[index - 1] != 'ﺩ' && letters[index - 1] != 'ﺫ' && letters[index - 1] != 'ﺭ' && letters[index - 1] != 'ﺯ' && letters[index - 1] != 'ﮊ' && letters[index - 1] != 'ﻭ' && letters[index - 1] != 'ﺁ' && letters[index - 1] != 'ﺃ' && letters[index - 1] != 'ﺇ' && letters[index - 1] != 'ﺅ' && letters[index - 1] != 'ﺀ' && !char.IsPunctuation(letters[index - 1]) && letters[index - 1] != '>' && letters[index - 1] != '<' && letters[index - 1] != ' ' && letters[index - 1] != '*';
		bool flag3 = index < letters.Length - 1 && letters[index + 1] != ' ' && letters[index + 1] != '\r' && letters[index + 1] != 'ﺀ' && !char.IsNumber(letters[index + 1]) && !char.IsSymbol(letters[index + 1]) && !char.IsPunctuation(letters[index + 1]);
		if (flag3 && flag2 && flag)
		{
			try
			{
				if (char.IsPunctuation(letters[index + 1]))
				{
					return false;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}
		return false;
	}
}
namespace GreyAnnouncer.AudioClipLoad
{
	public static class StringExtension
	{
		[SpecialName]
		public sealed class <G>$34505F560D9EACF86A87F3ED1F85E448
		{
			[SpecialName]
			public static class <M>$D2C87DABA57FE47E39897F3C24A0705C
			{
			}

			[ExtensionMarker("<M>$D2C87DABA57FE47E39897F3C24A0705C")]
			public AudioType TryGetAudioType()
			{
				throw null;
			}
		}

		public static AudioType TryGetAudioType(this string value)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			string[] array = value.Split('.');
			for (int i = 1; i <= array.Length; i++)
			{
				AudioType unityAudioType = GetUnityAudioType(array[^i]);
				if ((int)unityAudioType > 0)
				{
					return unityAudioType;
				}
			}
			return (AudioType)0;
		}

		[Description("https://docs.unity3d.com/2022.3/Documentation//ScriptReference/AudioType.html")]
		private static AudioType GetUnityAudioType(string extension)
		{
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			if (1 == 0)
			{
			}
			AudioType result = (AudioType)(extension switch
			{
				"aac" => 1, 
				"aiff" => 2, 
				"aif" => 2, 
				"aifc" => 2, 
				"it" => 10, 
				"mod" => 12, 
				"mp3" => 13, 
				"mpga" => 13, 
				"mpeg" => 13, 
				"ogg" => 14, 
				"s3m" => 17, 
				"wav" => 20, 
				"xm" => 21, 
				"xma" => 22, 
				"vag" => 23, 
				_ => 0, 
			});
			if (1 == 0)
			{
			}
			return result;
		}
	}
}
namespace UltrakULL
{
	public class NeedDebugMode : Attribute
	{
	}
	public class NeedRework : Attribute
	{
	}
	public class NonSenseNeedChange : Attribute
	{
	}
	public static class Core
	{
		public static bool wasLanguageReset;

		public static void HandleSceneSwitch(Scene scene, ref GameObject canvas)
		{
			string currentSceneName = SceneObjects.GetCurrentSceneName();
			if (currentSceneName == "Intro" || currentSceneName == "Bootstrap")
			{
				return;
			}
			GameObject game = SceneObjects.GetInactiveRootObject("Canvas");
			if (!Object.op_Implicit((Object)(object)game))
			{
				Logging.Fatal("UNABLE TO FIND CANVAS IN CURRENT SCENE", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				return;
			}
			string text = currentSceneName;
			string text2 = text;
			if (text2 == "Main Menu")
			{
				if (wasLanguageReset)
				{
					wasLanguageReset = false;
					HudMessageReceiver instance = MonoSingleton<HudMessageReceiver>.Instance;
					if (instance != null)
					{
						instance.SendHudMessage("<color=orange>The currently set language file could not be loaded.\nLanguage has been reset to English to avoid problems.</color>", "", "", 0, false, false, true);
					}
				}
				MainMenu.Patch(game);
				Options.Patch(ref game);
			}
			else if (LanguageManager.IsEnglish)
			{
				Logging.Warn("Current language is English, not patching.", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			else
			{
				Logging.Message("Regular scene", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				PatchingBaseElements(ref game);
				HandleLevelPatching(currentSceneName, ref game);
			}
		}

		private static void PatchingBaseElements(ref GameObject canvasObj)
		{
			Logging.Message("Attempting to patch base elements", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			try
			{
				_PauseMenu.PatchPauseMenu(ref canvasObj);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.ToString());
			}
			try
			{
				Cheats.PatchCheatConsentPanel(ref canvasObj);
			}
			catch (Exception ex2)
			{
				Console.WriteLine(ex2.ToString());
			}
			try
			{
				Sandbox.PatchAlterMenu();
			}
			catch (Exception ex3)
			{
				Console.WriteLine(ex3.ToString());
			}
			try
			{
				HUDMessages.PatchDeathScreen(ref canvasObj);
			}
			catch (Exception ex4)
			{
				Console.WriteLine(ex4.ToString());
			}
			try
			{
				LevelStatWindow.PatchStats(ref canvasObj);
			}
			catch (Exception ex5)
			{
				Console.WriteLine(ex5.ToString());
			}
			try
			{
				HUDMessages.PatchMisc(ref canvasObj);
			}
			catch (Exception ex6)
			{
				Console.WriteLine(ex6.ToString());
			}
			try
			{
				Options.Patch(ref canvasObj);
			}
			catch (Exception ex7)
			{
				Console.WriteLine(ex7.ToString());
			}
			Logging.Message("Base elements patched", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
		}

		private static void HandleLevelPatching(string levelName, ref GameObject canvasObj)
		{
			if (levelName.Contains("Tutorial"))
			{
				Logging.Message("Tutorial", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			else if (levelName.Contains("-S"))
			{
				Logging.Message("Secret", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				SecretLevels.Patch(ref canvasObj);
			}
			if (levelName.Contains("0-"))
			{
				Logging.Message("Prelude", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				Prelude.Patch(ref canvasObj);
			}
			else if (levelName.Contains("1-") || levelName.Contains("2-") || levelName.Contains("3-"))
			{
				Logging.Message("Act 1", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				Act1.PatchAct1(ref canvasObj);
			}
			else if (levelName.Contains("4-") || levelName.Contains("5-") || levelName.Contains("6-"))
			{
				Logging.Message("Act 2", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				Act2.PatchAct2(ref canvasObj);
			}
			else if (levelName.Contains("7-") || levelName.Contains("8-") || levelName.Contains("9-"))
			{
				Logging.Message("Act 3", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				Act3.PatchAct3(ref canvasObj);
			}
			else if (levelName.Contains("P-"))
			{
				Logging.Message("Prime", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				PrimeSanctum.Patch();
			}
			else if (levelName == "uk_construct")
			{
				Logging.Message("Sandbox", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				Sandbox.Patch(ref canvasObj);
			}
			else if (levelName == "Endless")
			{
				Logging.Message("CyberGrind", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				CyberGrind.PatchCg();
			}
			else if (levelName.Contains("Intermission") || levelName.Contains("EarlyAccessEnd"))
			{
				Logging.Message("Intermission", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				Intermission.Patch(ref canvasObj);
			}
			else if (levelName == "CreditsMuseum2")
			{
				Logging.Message("DevMuseum", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				DevMuseum.Patch();
			}
		}

		public static async void ApplyPostInitFixes(GameObject canvasObj)
		{
			await Task.Delay(250);
			if (SceneObjects.GetCurrentSceneName() == "Main Menu")
			{
				TextMeshProUGUI openLangFolderText = SceneObjects.GetTextMeshProUGUI(SceneObjects.FindDescendant(canvasObj, "OptionsMenu", "Language Page", "Scroll Rect (1)", "Contents", "OpenLangFolder", "Slot Text"));
				if ((Object)(object)openLangFolderText != (Object)null)
				{
					((TMP_Text)openLangFolderText).text = "<color=#03fc07>Open language folder</color>";
				}
			}
		}
	}
	public static class FontManager
	{
		public static Sprite[] CustomRankImages;

		public static Sprite ArabicUltrakillLogo;

		public static bool TMPFontReady;

		public static TMP_FontAsset MeseumFontAsset;

		public static TMP_FontAsset TwinFont;

		private static TMP_FontAsset defaultMainFont;

		private static TMP_FontAsset defaultMuseumFont;

		private static TMP_FontAsset defaultTerminalFont;

		private static TMP_FontAsset defaultSecretFont;

		public static void Initialize()
		{
			LanguageManager.OnLanguageChanged += ApplyLanguageFonts;
		}

		public static void LoadFonts()
		{
			Logging.Message("Loading font resource bundle...", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\FontManager.cs");
			AssetBundle val = AssetBundle.LoadFromFile(Path.Combine(MainPatch.ModFolder, "basegameasset.bundle"));
			MeseumFontAsset = val.LoadAsset<TMP_FontAsset>("GFSGaraldus SDF");
			TMPFontReady = true;
		}

		public static void LoadLangFonts(Lang lang)
		{
			if ((Object)(object)lang.FontBundle != (Object)null)
			{
				return;
			}
			AssetBundle val = AssetBundle.LoadFromFile(lang.FontBundlePath);
			if ((Object)(object)val == (Object)null)
			{
				Logging.Warn("Failed to load language font bundle: " + lang.FontBundlePath, addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\FontManager.cs");
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			TMP_FontAsset[] array = val.LoadAllAssets<TMP_FontAsset>();
			foreach (TMP_FontAsset val2 in array)
			{
				stringBuilder.AppendLine(((Object)val2).name);
			}
			Logging.Info(stringBuilder.ToString() ?? "", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\FontManager.cs");
			lang.FontBundle = val;
			FontsMetadata fonts = lang.Json.metadata.fonts;
			lang.MainFontAsset = val.LoadAsset<TMP_FontAsset>("WenQuanYi.Bitmap.Song.12px");
			lang.MuseumAsset = val.LoadAsset<TMP_FontAsset>("WenYuanSerifSC-Regular");
			lang.TerminalAsset = val.LoadAsset<TMP_FontAsset>("fusion-pixel-10px-monospaced-zh_hans");
			lang.SecretTerminalAsset = val.LoadAsset<TMP_FontAsset>("WenQuanYi.Bitmap.Song.16px");
		}

		private static void ResolveFonts(Lang lang)
		{
			Lang lang2 = lang;
			if (lang2.MainFontAsset == null)
			{
				TMP_FontAsset val = (lang2.MainFontAsset = defaultMainFont);
			}
			lang2 = lang;
			if (lang2.MuseumAsset == null)
			{
				TMP_FontAsset val = (lang2.MuseumAsset = defaultMuseumFont);
			}
			lang2 = lang;
			if (lang2.TerminalAsset == null)
			{
				TMP_FontAsset val = (lang2.TerminalAsset = defaultTerminalFont);
			}
			lang2 = lang;
			if (lang2.SecretTerminalAsset == null)
			{
				TMP_FontAsset val = (lang2.SecretTerminalAsset = defaultSecretFont);
			}
		}

		private static void ApplyLanguageFonts(ValueChangedEvent<Lang> change)
		{
			if (!TMPFontReady)
			{
				return;
			}
			RemoveFallbacksOf(change.OldValue);
			Lang newValue = change.NewValue;
			if (newValue != null && !newValue.IsEnglish)
			{
				LoadLangFonts(newValue);
				ResolveFonts(newValue);
				if (newValue.UseFontFallback)
				{
					RegisterFallbacksForLoadedFonts(newValue);
				}
			}
		}

		public static void RefreshFallback()
		{
			Lang current = LanguageManager.Current;
			if (TMPFontReady && current != null && !current.IsEnglish && current.UseFontFallback)
			{
				RegisterFallbacksForLoadedFonts(current);
			}
		}

		private static void RegisterFallbacksForLoadedFonts(Lang lang)
		{
			TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string text = ((Object)val).name?.ToLowerInvariant();
				if (!string.IsNullOrEmpty(text) && !text.Contains("_alignedto_") && !((Object)(object)val == (Object)(object)lang.MainFontAsset) && !((Object)(object)val == (Object)(object)lang.MuseumAsset) && !((Object)(object)val == (Object)(object)lang.TerminalAsset) && !((Object)(object)val == (Object)(object)lang.SecretTerminalAsset))
				{
					TMP_FontAsset fallback = null;
					if (text.Contains("tahoma"))
					{
						fallback = lang.TerminalAsset;
					}
					else if (text.Contains("bittypix"))
					{
						fallback = lang.SecretTerminalAsset;
					}
					else if (text.Contains("garaldus") || text.Contains("garamond") || text.Contains("museum"))
					{
						fallback = lang.MuseumAsset;
					}
					else if (text.Contains("vcr-osd-replayed"))
					{
						fallback = lang.MainFontAsset;
					}
					if (text.Contains("vcr_osd_mono_ui"))
					{
						TwinFont = val;
					}
					AddFallback(lang, val, fallback);
				}
			}
		}

		public static TMP_FontAsset GetTwinFont(string sourceFontName)
		{
			string text = sourceFontName?.ToLowerInvariant();
			bool flag = !string.IsNullOrEmpty(text) && (text.Contains("garaldus") || text.Contains("garamond") || text.Contains("museum"));
			TMP_FontAsset val = (flag ? (MeseumFontAsset ?? TwinFont) : TwinFont);
			Lang current = LanguageManager.Current;
			if (current == null || current.IsEnglish || current.UseFontFallback)
			{
				return val;
			}
			return flag ? (current.MuseumAsset ?? current.MainFontAsset ?? val) : (current.MainFontAsset ?? val);
		}

		private static void AddFallback(Lang lang, TMP_FontAsset primary, TMP_FontAsset fallback)
		{
			if (!((Object)(object)primary == (Object)null) && !((Object)(object)fallback == (Object)null) && !((Object)(object)primary == (Object)(object)fallback))
			{
				if (primary.fallbackFontAssetTable == null)
				{
					List<TMP_FontAsset> list = (primary.fallbackFontAssetTable = new List<TMP_FontAsset>());
				}
				if (!primary.fallbackFontAssetTable.Contains(fallback))
				{
					primary.fallbackFontAssetTable.Add(fallback);
					lang.AppliedFallbacks.Add((primary, fallback));
				}
			}
		}

		private static void RemoveFallbacksOf(Lang lang)
		{
			if (lang == null)
			{
				return;
			}
			foreach (var (val, item) in lang.AppliedFallbacks)
			{
				if (val != null)
				{
					val.fallbackFontAssetTable?.Remove(item);
				}
			}
			lang.AppliedFallbacks.Clear();
		}
	}
	public static class Logging
	{
		public static ManualLogSource UllLogger = Logger.CreateLogSource("ULL LOGGING");

		public static void Debug(string text, bool addCallerFilePath = false, [CallerFilePath] string callerFilePath = "")
		{
			UllLogger.LogDebug((object)TryAddCallerName(text, addCallerFilePath, callerFilePath));
		}

		public static void Message(string text, bool addCallerFilePath = false, [CallerFilePath] string callerFilePath = "")
		{
			UllLogger.LogMessage((object)TryAddCallerName(text, addCallerFilePath, callerFilePath));
		}

		public static void Warn(string text, bool addCallerFilePath = false, [CallerFilePath] string callerFilePath = "")
		{
			UllLogger.LogWarning((object)TryAddCallerName(text, addCallerFilePath, callerFilePath));
		}

		public static void Error(string text, bool addCallerFilePath = false, [CallerFilePath] string callerFilePath = "")
		{
			UllLogger.LogError((object)TryAddCallerName(text, addCallerFilePath, callerFilePath));
		}

		public static void Fatal(string text, bool addCallerFilePath = false, [CallerFilePath] string callerFilePath = "")
		{
			UllLogger.LogFatal((object)TryAddCallerName(text, addCallerFilePath, callerFilePath));
		}

		public static void Info(string text, bool addCallerFilePath = false, [CallerFilePath] string callerFilePath = "")
		{
			UllLogger.LogInfo((object)TryAddCallerName(text, addCallerFilePath, callerFilePath));
		}

		private static string TryAddCallerName(string text, bool addCallerFilePath, string callerFilePath)
		{
			return addCallerFilePath ? ("[" + GetFileName(callerFilePath) + "] " + text) : text;
		}

		private static string GetFileName(string callerFilePath)
		{
			return Path.GetFileNameWithoutExtension(callerFilePath);
		}
	}
	[BepInPlugin("clearwater.ultrakill.ultrakull", "clearwater.ultrakull.ultrakULL", "1.3.0")]
	public class MainPatch : BaseUnityPlugin
	{
		private const string Guid = "clearwater.ultrakill.ultrakull";

		private const string InternalName = "clearwater.ultrakull.ultrakULL";

		private const string InternalVersion = "1.3.0";

		public static MainPatch Instance;

		public bool ready;

		public static string ModFolder => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		public static string GetVersion()
		{
			return "1.3.0";
		}

		public void OnApplicationQuit()
		{
			LanguageManager.DumpLastLanguage();
		}

		public void DisableMod()
		{
			ready = false;
		}

		private void Awake()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Debug.unityLogger.filterLogType = (LogType)4;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)4;
			Logging.Warn("UltrakULL Loading... | Version v.1.3.0", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
			try
			{
				Logging.Warn("--- Loading default fonts ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				FontManager.LoadFonts();
				Logging.Warn("--- Register events ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				FontManager.Initialize();
				TextMeshProFontSwap.Initialize();
				SubtitleLocalizer.Initialize();
				TextureSwapper.Initialize();
				Logging.Warn("--- Initializing language manager ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				LanguageManager.InitializeManager("1.3.0");
				Logging.Warn("--- Patching vanilla game functions ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				new Harmony("clearwater.ultrakull.ultrakULL").PatchAll();
				Logging.Warn(" --- All done. Enjoy! ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				SceneManager.sceneLoaded += onSceneLoaded;
				ready = true;
			}
			catch (Exception ex)
			{
				Logging.Fatal("An error occured while initialising!", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				Logging.Fatal(ex.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				ready = false;
			}
		}

		public void onSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!ready || LanguageManager.CurrentLanguage == null)
			{
				Logging.Error("UltrakULL has been deactivated to prevent crashing. Check the console for any errors!", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				return;
			}
			SceneObjects.ClearObjectCaches(scene, mode);
			FontManager.RefreshFallback();
			GameObject canvas = SceneObjects.GetInactiveRootObject("Canvas");
			Core.HandleSceneSwitch(scene, ref canvas);
			AudioSwapper.OnSceneLoaded(SceneObjects.GetCurrentSceneName());
			RunDeferred(canvas);
		}

		private async void RunDeferred(GameObject canvasObj)
		{
			await Task.Delay(250);
			Core.ApplyPostInitFixes(canvasObj);
			SubtitledAudioSourcesReplacer.ReplaceSubsAndAudio();
			TextureSwapper.Apply();
		}
	}
	public class SubtitledSourcesConfig
	{
		[JsonProperty("scenes")]
		public Dictionary<string, List<SubtitledObjectReference>> Scenes;
	}
	public class SubtitledObjectReference
	{
		[JsonProperty("objects")]
		public List<string> Objects;

		[JsonProperty("audio")]
		public string AudioPath;

		[JsonProperty("lines")]
		public List<Line> Lines;

		public SubtitleData ToSubtitleData()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			return new SubtitleData
			{
				lines = ((IEnumerable<Line>)Lines).Select((Func<Line, SubtitleDataLine>)((Line line) => new SubtitleDataLine
				{
					subtitle = ColorIfNecessary(LanguageManager.CurrentLanguage.subtitles.GetField(line.Reference), line.Color),
					time = line.Delay
				})).ToArray()
			};
		}

		private static string ColorIfNecessary(string line, string color)
		{
			if (color == null)
			{
				return line;
			}
			return "<color=#" + color + ">" + line + "</color>";
		}
	}
	public class Line
	{
		[JsonProperty("line")]
		public string Reference;

		[JsonProperty("delay")]
		public float Delay;

		[JsonProperty("color")]
		public string Color;
	}
	public static class SubtitledAudioSourcesReplacer
	{
		public static SubtitledSourcesConfig Config;

		public static void ReplaceSubsAndAudio()
		{
			if (!TryLoadMetadata(out var references))
			{
				return;
			}
			List<(AudioSource source, string path)> audioReplacements = new List<(AudioSource, string)>();
			foreach (SubtitledObjectReference item in references)
			{
				foreach (string @object in item.Objects)
				{
					GameObject val = SceneObjects.GetObject(@object);
					SubtitledAudioSource component = val.GetComponent<SubtitledAudioSource>();
					if (ActiveDubbingEnabled())
					{
						audioReplacements.Add((val.GetComponentInChildren<AudioSource>(), Path.Combine(AudioSwapper.SpeechFolder, item.AudioPath)));
					}
					if ((Object)(object)component != (Object)null)
					{
						ReflectionUtils.SetPrivate<SubtitledAudioSource, SubtitleData>(component, typeof(SubtitledAudioSource), "subtitles", item.ToSubtitleData());
					}
				}
			}
			AudioSwapper.WhenReady(delegate
			{
				foreach (var item2 in audioReplacements)
				{
					item2.source.clip = AudioSwapper.SwapClipWithFile(item2.source.clip, item2.path);
				}
			});
		}

		private static bool ActiveDubbingEnabled()
		{
			return LanguageManager.configFile.Bind<string>("General", "activeDubbing", "False", (ConfigDescription)null).Value != "False";
		}

		private static bool TryLoadMetadata(out List<SubtitledObjectReference> references)
		{
			if (Config != null && Config.Scenes.TryGetValue(SceneObjects.GetCurrentSceneName(), out references))
			{
				return true;
			}
			references = null;
			return false;
		}
	}
	public static class SubtitleLocalizer
	{
		private static readonly Dictionary<string, string> map = new Dictionary<string, string>(StringComparer.Ordinal);

		private static readonly MethodInfo DisplaySubtitle = AccessTools.Method(typeof(SubtitleController), "DisplaySubtitle", new Type[3]
		{
			typeof(string),
			typeof(AudioSource),
			typeof(bool)
		}, (Type[])null);

		private static readonly MethodInfo LocalizeMethod = AccessTools.Method(typeof(SubtitleLocalizer), "Localize", (Type[])null, (Type[])null);

		public static void Initialize()
		{
			LanguageManager.OnLanguageChanged += delegate
			{
				Rebuild();
			};
		}

		private static void Rebuild()
		{
			map.Clear();
			Subtitles subtitles = LanguageManager.allLanguages.Values.FirstOrDefault((Lang l) => l.IsEnglish)?.Json?.subtitles;
			Subtitles subtitles2 = LanguageManager.Current?.Json?.subtitles;
			if (subtitles == null || subtitles2 == null)
			{
				return;
			}
			FieldInfo[] fields = typeof(Subtitles).GetFields();
			foreach (FieldInfo fieldInfo in fields)
			{
				string text = fieldInfo.GetValue(subtitles) as string;
				string text2 = fieldInfo.GetValue(subtitles2) as string;
				if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2) && text != text2)
				{
					map[text] = text2;
				}
			}
		}

		public static string Localize(string caption)
		{
			if (string.IsNullOrEmpty(caption) || LanguageManager.IsEnglish)
			{
				return caption;
			}
			string value;
			return map.TryGetValue(caption, out value) ? value : caption;
		}

		public static IEnumerable<CodeInstruction> InjectLocalize(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count + 4);
			for (int i = 0; i < list.Count; i++)
			{
				list2.Add(list[i]);
				if (i + 3 < list.Count && IsDisplaySubtitleCall(list[i + 3]))
				{
					list2.Add(new CodeInstruction(OpCodes.Call, (object)LocalizeMethod));
				}
			}
			return list2;
		}

		private static bool IsDisplaySubtitleCall(CodeInstruction instruction)
		{
			return instruction.opcode == OpCodes.Callvirt && CodeInstructionExtensions.OperandIs(instruction, (MemberInfo)DisplaySubtitle);
		}
	}
	internal static class StaticBatchAtlasSwapper
	{
		private readonly struct Template
		{
			public readonly string Name;

			public readonly int Width;

			public readonly int Height;

			public readonly Color32[] Pixels;

			public Template(string name, int width, int height, Color32[] pixels)
			{
				Name = name;
				Width = width;
				Height = height;
				Pixels = pixels;
			}
		}

		private sealed class AtlasState(Texture2D texture, Color32[] originalPixels)
		{
			public readonly Texture2D Texture = texture;

			public readonly Color32[] OriginalPixels = originalPixels;

			public readonly List<(string Name, RectInt Rect)> Regions = new List<(string, RectInt)>();
		}

		private readonly struct FeaturePoint
		{
			public readonly int X;

			public readonly int Y;

			public readonly Color32 Color;

			public readonly int Contrast;

			public FeaturePoint(int x, int y, Color32 color, int contrast)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				X = x;
				Y = y;
				Color = color;
				Contrast = contrast;
			}
		}

		private static readonly List<Template> pendingTemplates = new List<Template>();

		private static readonly List<AtlasState> atlases = new List<AtlasState>();

		private static readonly HashSet<string> diagnostics = new HashSet<string>();

		private static int optimizerId;

		private static bool resolving;

		internal static void Capture(StaticSceneOptimizer optimizer)
		{
			pendingTemplates.Clear();
			optimizerId = (((Object)(object)optimizer != (Object)null) ? ((Object)optimizer).GetInstanceID() : 0);
			if ((Object)(object)optimizer == (Object)null || LanguageManager.IsEnglish)
			{
				return;
			}
			HashSet<Texture2D> seen = new HashSet<Texture2D>();
			List<MeshRenderer> staticMRends = optimizer.staticMRends;
			if (staticMRends == null)
			{
				WarnOnce("no-renderers", "StaticSceneOptimizer.staticMRends is null; cannot capture pre-batch texture names.");
				return;
			}
			foreach (MeshRenderer item2 in staticMRends)
			{
				CaptureRenderer(item2);
			}
			Logging.Message($"Captured {pendingTemplates.Count} named " + $"pre-batch template(s) from {staticMRends.Count} renderer(s).", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\AtlasBatchSwapper.cs");
			void CaptureMaterial(Material material)
			{
				foreach (var mainTexture in GetMainTextures(material))
				{
					Texture2D item = mainTexture.Texture;
					if (seen.Add(item) && TextureSwapper.TryGetFile(((Object)item).name, out var _))
					{
						Color32[] array = ReadPixels((Texture)(object)item);
						if (array == null)
						{
							WarnOnce($"template-read:{((Object)item).GetInstanceID()}", "Cannot read source template " + $"'{((Object)item).name}' ({((Texture)item).width}x{((Texture)item).height}).");
						}
						else
						{
							pendingTemplates.Add(new Template(((Object)item).name, ((Texture)item).width, ((Texture)item).height, array));
						}
					}
				}
			}
			void CaptureRenderer(MeshRenderer renderer)
			{
				if (!((Object)(object)renderer == (Object)null))
				{
					Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials;
					foreach (Material material in sharedMaterials)
					{
						CaptureMaterial(material);
					}
				}
			}
		}

		internal static IEnumerator Resolve(StaticSceneOptimizer optimizer)
		{
			if (resolving || (Object)(object)optimizer == (Object)null || ((Object)optimizer).GetInstanceID() != optimizerId || pendingTemplates.Count == 0 || LanguageManager.IsEnglish)
			{
				yield break;
			}
			resolving = true;
			List<AtlasState> newAtlases = CollectAtlases(optimizer);
			if (newAtlases.Count == 0)
			{
				WarnOnce($"missing-atlas:{optimizerId}", "Optimizer finished, but no anonymous runtime Texture2D was found on its batch materials.");
				resolving = false;
				yield break;
			}
			foreach (AtlasState atlas in newAtlases)
			{
				Template[] templates = pendingTemplates.ToArray();
				Color32[] source = atlas.originalPixels;
				int sourceWidth = ((Texture)atlas.texture).width;
				int sourceHeight = ((Texture)atlas.texture).height;
				Task<List<(Template Template, RectInt Rect)>> task = Task.Run(() => FindRegions(source, sourceWidth, sourceHeight, templates));
				while (!task.IsCompleted)
				{
					yield return null;
				}
				if (task.IsFaulted)
				{
					Logging.Error("Region search failed for " + $"{sourceWidth}x{sourceHeight} atlas: {task.Exception}", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\AtlasBatchSwapper.cs");
					continue;
				}
				foreach (var result in task.Result)
				{
					RectInt item = result.Rect;
					if (((RectInt)(ref item)).width <= 0)
					{
						WarnOnce($"not-found:{optimizerId}:{result.Template.Name}", "'" + result.Template.Name + "' was not found " + $"in atlas '{((Object)atlas.texture).name}' {sourceWidth}x{sourceHeight}.");
						continue;
					}
					atlas.Regions.Add((result.Template.Name, result.Rect));
					string[] obj = new string[5]
					{
						"Located '",
						result.Template.Name,
						"' at ",
						null,
						null
					};
					item = result.Rect;
					object arg = ((RectInt)(ref item)).x;
					item = result.Rect;
					object arg2 = ((RectInt)(ref item)).y;
					item = result.Rect;
					obj[3] = $"({arg},{arg2}) {((RectInt)(ref item)).width}x";
					item = result.Rect;
					obj[4] = $"{((RectInt)(ref item)).height}.";
					Logging.Message(string.Concat(obj), addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\AtlasBatchSwapper.cs");
				}
				atlases.Add(atlas);
			}
			pendingTemplates.Clear();
			resolving = false;
			Apply();
		}

		internal static void Apply()
		{
			//IL_00ce: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: 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_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			foreach (AtlasState atlase in atlases)
			{
				if ((Object)(object)atlase.texture == (Object)null || atlase.originalPixels.Length != ((Texture)atlase.texture).width * ((Texture)atlase.texture).height)
				{
					continue;
				}
				atlase.texture.SetPixels32(atlase.originalPixels);
				if (LanguageManager.IsEnglish)
				{
					atlase.texture.Apply(false, false);
					continue;
				}
				int num = 0;
				foreach (var region in atlase.Regions)
				{
					if (!TextureSwapper.TryGetFile(region.Name, out var file))
					{
						continue;
					}
					int width = file.Width;
					RectInt item = region.Rect;
					if (width == ((RectInt)(ref item)).width)
					{
						int height = file.Height;
						item = region.Rect;
						if (height == ((RectInt)(ref item)).height)
						{
							Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
							try
							{
								if (ImageConversion.LoadImage(val, file.Bytes, false))
								{
									Texture2D texture = atlase.texture;
									item = region.Rect;
									int x = ((RectInt)(ref item)).x;
									item = region.Rect;
									int y = ((RectInt)(ref item)).y;
									item = region.Rect;
									int width2 = ((RectInt)(ref item)).width;
									item = region.Rect;
									texture.SetPixels32(x, y, width2, ((RectInt)(ref item)).height, val.GetPixels32());
									num++;
								}
							}
							catch (Exception ex)
							{
								WarnOnce("apply:" + region.Name + ":" + file.Path, "Failed to apply '" + file.Path + "': " + ex.Message);
							}
							finally
							{
								Object.Destroy((Object)(object)val);
							}
							continue;
						}
					}
					string key = "size:" + region.Name + ":" + file.Path;
					string[] obj = new string[6]
					{
						"Cannot put '",
						file.Path,
						"' into cached ",
						$"region '{region.Name}': PNG is {file.Width}x{file.Height}, region is ",
						null,
						null
					};
					item = region.Rect;
					object arg = ((RectInt)(ref item)).width;
					item = region.Rect;
					obj[4] = $"{arg}x{((RectInt)(ref item)).height}. Atlas layout ";
					obj[5] = "must not be resized.";
					WarnOnce(key, string.Concat(obj));
				}
				atlase.texture.Apply(false, false);
				if (num > 0)
				{
					Logging.Message($"Applied {num} cached region(s) to " + "'" + ((Object)atlase.texture).name + "' without rescanning.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\AtlasBatchSwapper.cs");
				}
			}
		}

		private static List<AtlasState> CollectAtlases(StaticSceneOptimizer optimizer)
		{
			List<AtlasState> list = new List<AtlasState>();
			HashSet<Texture2D> hashSet = new HashSet<Texture2D>();
			Material[] array = (Material[])(object)new Material[2] { optimizer.batchMaterialOutdoors, optimizer.batchMaterialEnvironment };
			Material[] array2 = array;
			foreach (Material val in array2)
			{
				foreach (var mainTexture in GetMainTextures(val))
				{
					if (hashSet.Add(mainTexture.Texture))
					{
						Color32[] array3 = ReadPixels((Texture)(object)mainTexture.Texture);
						if (array3 != null)
						{
							list.Add(new AtlasState(mainTexture.Texture, array3));
							Logging.Message("Runtime atlas candidate: material '" + ((Object)val).name + "', " + mainTexture.Property + ", texture '" + ((Object)mainTexture.Texture).name + "' " + $"{((Texture)mainTexture.Texture).width}x{((Texture)mainTexture.Texture).height}.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\AtlasBatchSwapper.cs");
						}
					}
				}
			}
			return list;
		}

		private static IEnumerable<(string Property, Texture2D Texture)> GetMainTextures(Material material)
		{
			if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null)
			{
				yield break;
			}
			int count = material.shader.GetPropertyCount();
			for (int i = 0; i < count; i++)
			{
				if ((int)material.shader.GetPropertyType(i) != 4)
				{
					continue;
				}
				string property = material.shader.GetPropertyName(i);
				if (!(property != "_MainTex") || !(property != "_BaseMap") || !(property != "_MainTexture"))
				{
					Texture texture = material.GetTexture(property);
					Texture2D texture2 = (Texture2D)(object)((texture is Texture2D) ? texture : null);
					if (texture2 != null)
					{
						yield return (Property: property, Texture: texture2);
					}
				}
			}
		}

		private static List<(Template Template, RectInt Rect)> FindRegions(Color32[] source, int sourceWidth, int sourceHeight, Template[] templates)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			List<(Template, RectInt)> list = new List<(Template, RectInt)>(templates.Length);
			foreach (Template template in templates)
			{
				list.Add((template, FindRegion(source, sourceWidth, sourceHeight, template)));
			}
			return list;
		}

		private static RectInt FindRegion(Color32[] source, int sourceWidth, int sourceHeight, Template template)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (template.Width > sourceWidth || template.Height > sourceHeight)
			{
				return default(RectInt);
			}
			FeaturePoint[] featurePoints = GetFeaturePoints(template);
			int num = sourceWidth - template.Width;
			int num2 = sourceHeight - template.Height;
			for (int i = 0; i <= num2; i++)
			{
				for (int j = 0; j <= num; j++)
				{
					if (MatchesFeatures(source, sourceWidth, j, i, featurePoints) && MatchesImage(source, sourceWidth, j, i, template))
					{
						return new RectInt(j, i, template.Width, template.Height);
					}
				}
			}
			return default(RectInt);
		}

		private static FeaturePoint[] GetFeaturePoints(Template template)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			long num = 0L;
			long num2 = 0L;
			long num3 = 0L;
			long num4 = 0L;
			Color32[] pixels = template.Pixels;
			foreach (Color32 val in pixels)
			{
				num += val.r;
				num2 += val.g;
				num3 += val.b;
				num4 += val.a;
			}
			int num5 = template.Pixels.Length;
			int num6 = (int)(num / num5);
			int num7 = (int)(num2 / num5);
			int num8 = (int)(num3 / num5);
			int num9 = (int)(num4 / num5);
			List<FeaturePoint> list = new List<FeaturePoint>(25);
			for (int j = 0; j < 5; j++)
			{
				for (int k = 0; k < 5; k++)
				{
					int num10 = k * (template.Width - 1) / 4;
					int num11 = j * (template.Height - 1) / 4;
					Color32 val2 = template.Pixels[num11 * template.Width + num10];
					int contrast = Math.Abs(val2.r - num6) + Math.Abs(val2.g - num7) + Math.Abs(val2.b - num8) + Math.Abs(val2.a - num9);
					list.Add(new FeaturePoint(num10, num11, val2, contrast));
				}
			}
			list.Sort((FeaturePoint a, FeaturePoint b) => b.Contrast.CompareTo(a.Contrast));
			return list.GetRange(0, Math.Min(8, list.Count)).ToArray();
		}

		private static bool MatchesFeatures(Color32[] source, int sourceWidth, int x, int y, FeaturePoint[] features)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < features.Length; i++)
			{
				FeaturePoint featurePoint = features[i];
				Color32 val = source[(y + featurePoint.Y) * sourceWidth + x + featurePoint.X];
				if (!((object)featurePoint.Color/*cast due to .constrained prefix*/).Equals((object?)val))
				{
					return false;
				}
			}
			return true;
		}

		private unsafe static bool MatchesImage(Color32[] source, int sourceWidth, int x, int y, Template template)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < template.Height; i++)
			{
				for (int j = 0; j < template.Width; j++)
				{
					Color32 val = template.Pixels[i * template.Width + j];
					Color32 val2 = source[(y + i) * sourceWidth + x + j];
					if (!((object)(*(Color32*)(&val))/*cast due to .constrained prefix*/).Equals((object?)val2))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static Color32[] ReadPixels(Texture source)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			Texture2D val2 = null;
			try
			{
				val = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0);
				Graphics.Blit(source, val);
				RenderTexture.active = val;
				val2 = new Texture2D(source.width, source.height, (TextureFormat)4, false);
				val2.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0);
				val2.Apply();
				return val2.GetPixels32();
			}
			catch (Exception ex)
			{
				WarnOnce($"read:{((Object)source).GetInstanceID()}", "Failed to read '" + ((Object)source).name + "': " + ex.Message);
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
			}
		}

		private static void WarnOnce(string key, string message)
		{
			if (diagnostics.Add(key))
			{
				Logging.Warn(message, addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\AtlasBatchSwapper.cs");
			}
		}
	}
	[HarmonyPatch(typeof(StaticSceneOptimizer))]
	internal static class StaticSceneOptimizerPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPrefix]
		private static void Prefix(StaticSceneOptimizer __instance)
		{
			StaticBatchAtlasSwapper.Capture(__instance);
		}

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void Postfix(StaticSceneOptimizer __instance)
		{
			if ((Object)(object)MainPatch.Instance != (Object)null)
			{
				((MonoBehaviour)MainPatch.Instance).StartCoroutine(ApplyAfterOptimizer(__instance));
			}
		}

		private static IEnumerator ApplyAfterOptimizer(StaticSceneOptimizer optimizer)
		{
			yield return null;
			yield return null;
			yield return StaticBatchAtlasSwapper.Resolve(optimizer);
		}
	}
	internal sealed class ReplacementCache<T> where T : Object
	{
		private readonly struct Replacement
		{
			public readonly T Original;

			public readonly T Current;

			public Replacement(T original, T current)
			{
				Original = original;
				Current = current;
			}
		}

		private readonly Dictionary<T, Replacement> replacements = new Dictionary<T, Replacement>();

		private readonly HashSet<T> active = new HashSet<T>();

		private readonly List<T> stale = new List<T>();

		public T GetOriginal(T value)
		{
			Replacement value2;
			return ((Object)(object)value != (Object)null && replacements.TryGetValue(value, out value2)) ? value2.Original : value;
		}

		public bool TryGetCurrent(T original, out T current)
		{
			Replacement value;
			bool flag = replacements.TryGetValue(original, out value);
			current = (flag ? value.Current : default(T));
			return (Object)(object)current != (Object)null;
		}

		public bool IsReplacement(T value)
		{
			Replacement value2;
			return (Object)(object)value != (Object)null && replacements.TryGetValue(value, out value2) && (Object)(object)value2.Current == (Object)(object)value;
		}

		public void Add(T original, T replacement, bool cache = true)
		{
			Replacement value = new Replacement(original, replacement);
			if (cache)
			{
				replacements[original] = value;
			}
			replacements[replacement] = value;
			active.Add(replacement);
		}

		public void QueueCleanup()
		{
			foreach (T item in active)
			{
				Replacement replacement = replacements[item];
				if (replacements.TryGetValue(replacement.Original, out var value) && (Object)(object)value.Current == (Object)(object)item)
				{
					replacements.Remove(replacement.Original);
				}
			}
			stale.AddRange(active);
			active.Clear();
		}

		public void Cleanup(Action<T> destroy)
		{
			foreach (T item in stale)
			{
				replacements.Remove(item);
				if (!((Object)(object)item == (Object)null))
				{
					destroy(item);
				}
			}
			stale.Clear();
		}
	}
	public static class TextureSwapper
	{
		internal readonly struct ReplacementFile
		{
			public readonly string Path;

			public readonly byte[] Bytes;

			public readonly int Width;

			public readonly int Height;

			public ReplacementFile(string path, byte[] bytes, int width, int height)
			{
				Path = path;
				Bytes = bytes;
				Width = width;
				Height = height;
			}
		}

		private readonly struct MutatedTexture
		{
			public readonly byte[] OriginalPng;

			public readonly FilterMode FilterMode;

			public readonly TextureWrapMode WrapMode;

			public readonly int AnisoLevel;

			public MutatedTexture(byte[] originalPng, FilterMode filterMode, TextureWrapMode wrapMode, int anisoLevel)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				OriginalPng = originalPng;
				FilterMode = filterMode;
				WrapMode = wrapMode;
				AnisoLevel = anisoLevel;
			}
		}

		private static readonly ReplacementCache<Sprite> spriteReplacementCache = new ReplacementCache<Sprite>();

		private static readonly ReplacementCache<Texture> textureReplacementCache = new ReplacementCache<Texture>();

		private static readonly Dictionary<(Material, string), Texture2D> materialTextureCache = new Dictionary<(Material, string), Texture2D>();

		private static readonly HashSet<string> diagnostics = new HashSet<string>();

		private static readonly Dictionary<string, int> replacementCount = new Dictionary<string, int>
		{
			["Image slot(s)"] = 0,
			["StyleHUD rank sprite(s)"] = 0,
			["RawImage(s)"] = 0,
			["SpriteRenderer(s)"] = 0,
			["SpriteMask(s)"] = 0,
			["Renderer property block slot(s)"] = 0,
			["material property(s)"] = 0,
			["loaded Texture2D object(s)"] = 0
		};

		private static bool scanInProgress;

		private static readonly Dictionary<string, ReplacementFile> files = new Dictionary<string, ReplacementFile>();

		private static readonly Dictionary<Texture2D, MutatedTexture> mutatedTextures = new Dictionary<Texture2D, MutatedTexture>();

		private static Sprite GetDesiredSprite(Sprite value)
		{
			//IL_0066: 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_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)value == (Object)null)
			{
				return null;
			}
			Sprite original = spriteReplacementCache.GetOriginal(value);
			if (LanguageManager.IsEnglish || !TryGetFile(((Object)original).name, out var file))
			{
				return original;
			}
			if (spriteReplacementCache.TryGetCurrent(original, out var current))
			{
				return current;
			}
			Rect rect = original.rect;
			int num = Mathf.RoundToInt(((Rect)(ref rect)).width);
			int num2 = Mathf.RoundToInt(((Rect)(ref rect)).height);
			if (num <= 0 || num2 <= 0)
			{
				WarnOnce($"sprite-empty:{((Object)original).GetInstanceID()}", $"Invalid sprite rect '{((Object)original).name}': {num}x{num2}.");
				return original;
			}
			float num3 = (float)file.Width / ((Rect)(ref rect)).width;
			float num4 = (float)file.Height / ((Rect)(ref rect)).height;
			float num5 = ((Rect)(ref rect)).width / ((Rect)(ref rect)).height;
			float num6 = (float)file.Width / (float)file.Height;
			if (!Mathf.Approximately(num5, num6))
			{
				WarnOnce($"sprite-aspect:{((Object)original).GetInstanceID()}:{file.Path}", $"Aspect change '{((Object)original).name}': {num5:0.###} -> " + $"{num6:0.###} ({num}x{num2} -> {file.Width}x{file.Height}).");
			}
			Texture2D val = CreateTexture(file, (Texture)(object)original.texture);
			if ((Object)(object)val == (Object)null)
			{
				return original;
			}
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(original.pivot.x / ((Rect)(ref rect)).width, original.pivot.y / ((Rect)(ref rect)).height);
			Vector4 border = original.border;
			((Vector4)(ref border))..ctor(border.x * num3, border.y * num4, border.z * num3, border.w * num4);
			Sprite val3;
			try
			{
				val3 = Sprite.Create(val, new Rect(0f, 0f, (float)file.Width, (float)file.Height), val2, original.pixelsPerUnit, 0u, (SpriteMeshType)0, border);
			}
			catch (Exception ex)
			{
				Object.Destroy((Object)(object)val);
				WarnOnce($"sprite-create:{((Object)original).GetInstanceID()}:{file.Path}", "Cannot create sprite '" + ((Object)original).name + "': " + ex.Message);
				return original;
			}
			((Object)val3).name = ((Object)original).name;
			spriteReplacementCache.Add(original, val3);
			return val3;
		}

		private static Texture GetDesiredTexture(Texture value)
		{
			if ((Object)(object)value == (Object)null)
			{
				return null;
			}
			Texture original = textureReplacementCache.GetOriginal(value);
			if (!LanguageManager.IsEnglish)
			{
				Texture2D val = (Texture2D)(object)((original is Texture2D) ? original : null);
				if (val != null && TryGetFile(((Object)original).name, out var file))
				{
					if (textureReplacementCache.TryGetCurrent((Texture)(object)val, out var current))
					{
						return current;
					}
					Texture2D val2 = CreateTexture(file, (Texture)(object)val);
					if ((Object)(object)val2 == (Object)null)
					{
						return original;
					}
					textureReplacementCache.Add(original, (Texture)(object)val2);
					return (Texture)(object)val2;
				}
			}
			return original;
		}

		private static Texture GetCanonicalTexture(Texture value)
		{
			return textureReplacementCache.GetOriginal(value);
		}

		private static Texture GetDesiredMaterialTexture(Material material, string property, Texture original, ReplacementFile file)
		{
			if (LanguageManager.IsEnglish)
			{
				return original;
			}
			(Material, string) key = (material, property);
			if (materialTextureCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				return (Texture)(object)value;
			}
			Texture2D val = CreateTexture(file, original);
			if ((Object)(object)val == (Object)null)
			{
				return original;
			}
			materialTextureCache[key] = val;
			textureReplacementCache.Add(original, (Texture)(object)val, cache: false);
			return (Texture)(object)val;
		}

		private static bool IsUnusableAssetName(string name)
		{
			return string.IsNullOrWhiteSpace(name) || string.Equals(name.Trim(), "untitled");
		}

		private static bool IsMainTextureProperty(string property)
		{
			return string.Equals(property, "_MainTex") || string.Equals(property, "_BaseMap") || string.Equals(property, "_MainTexture");
		}

		private static Texture2D CreateTexture(ReplacementFile file, Texture source)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, file.Bytes, false))
			{
				Object.Destroy((Object)(object)val);
				WarnOnce("decode:" + file.Path, "Cannot decode '" + file.Path + "'.");
				return null;
			}
			((Object)val).name = "UltrakULL:" + LanguageManager.Current.Name + ":" + ((Object)source).name;
			ApplySampling((Texture)(object)val, source.filterMode, source.wrapMode, source.anisoLevel);
			return val;
		}

		private static void ApplySampling(Texture texture, FilterMode filter, TextureWrapMode wrap, int aniso)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			texture.filterMode = filter;
			texture.wrapMode = wrap;
			texture.anisoLevel = aniso;
		}

		private static void QueueGeneratedAssetsForCleanup()
		{
			spriteReplacementCache.QueueCleanup();
			textureReplacementCache.QueueCleanup();
			materialTextureCache.Clear();
		}

		private static void CleanupStaleAssets()
		{
			spriteReplacementCache.Cleanup(delegate(Sprite sprite)
			{
				Texture texture = (Texture)(object)sprite.texture;
				Object.Destroy((Object)(object)sprite);
				if ((Object)(object)texture != (Object)null)
				{
					Object.Destroy((Object)(object)texture);
				}
			});
			textureReplacementCache.Cleanup((Action<Texture>)Object.Destroy);
		}

		private static void LogReplacement(Component component, string slot, Object original, Object replacement)
		{
			Logging.Info(component.transform.GetPath() + " | " + slot + " | '" + (((original != null) ? original.name : null) ?? "<null>") + "' -> '" + (((replacement != null) ? replacement.name : null) ?? "<null>") + "'" + GetSourceSuffix(original), addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Assets.cs");
		}

		private static void LogReplacement(Material material, string property, Texture original, Texture replacement)
		{
			Logging.Info("Material '" + ((Object)material).name + "' (" + ((Object)material.shader).name + ") | " + property + " | '" + (((original != null) ? ((Object)original).name : null) ?? "<null>") + "' -> '" + (((replacement != null) ? ((Object)replacement).name : null) ?? "<null>") + "'" + GetSourceSuffix((Object)(object)original), addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Assets.cs");
		}

		private static string GetSourceSuffix(Object value)
		{
			Object val = value;
			Sprite val2 = (Sprite)(object)((value is Sprite) ? value : null);
			if (val2 != null)
			{
				val = (Object)(object)spriteReplacementCache.GetOriginal(val2);
			}
			else
			{
				Texture val3 = (Texture)(object)((value is Texture) ? value : null);
				if (val3 != null)
				{
					val = (Object)(object)textureReplacementCache.GetOriginal(val3);
				}
			}
			ReplacementFile file;
			return (val != (Object)null && TryGetFile(val.name, out file)) ? (" | PNG: '" + file.Path + "'") : (LanguageManager.IsEnglish ? " | restoring original" : "");
		}

		private static void ReplaceImages()
		{
			Image[] array = Resources.FindObjectsOfTypeAll<Image>();
			foreach (Image image in array)
			{
				ReplaceSpriteSlot((Component)(object)image, "Image.sprite", image.sprite, delegate(Sprite value)
				{
					image.sprite = value;
				}, "Image slot(s)");
				ReplaceSpriteSlot((Component)(object)image, "Image.overrideSprite", image.overrideSprite, delegate(Sprite value)
				{
					image.overrideSprite = value;
				}, "Image slot(s)");
			}
		}

		private static void ReplaceRawImages()
		{
			RawImage[] array = Resources.FindObjectsOfTypeAll<RawImage>();
			foreach (RawImage image in array)
			{
				ReplaceTextureSlot((Component)(object)image, "RawImage.texture", image.texture, delegate(Texture value)
				{
					image.texture = value;
				}, "RawImage(s)");
			}
		}

		private static void ReplaceSpriteRenderers()
		{
			SpriteRenderer[] array = Resources.FindObjectsOfTypeAll<SpriteRenderer>();
			foreach (SpriteRenderer renderer in array)
			{
				ReplaceSpriteSlot((Component)(object)renderer, "SpriteRenderer.sprite", renderer.sprite, delegate(Sprite value)
				{
					renderer.sprite = value;
				}, "SpriteRenderer(s)");
			}
		}

		private static void ReplaceSpriteMasks()
		{
			SpriteMask[] array = Resources.FindObjectsOfTypeAll<SpriteMask>();
			foreach (SpriteMask mask in array)
			{
				ReplaceSpriteSlot((Component)(object)mask, "SpriteMask.sprite", mask.sprite, delegate(Sprite value)
				{
					mask.sprite = value;
				}, "SpriteMask(s)");
			}
		}

		private static void ReplaceSpriteSlot(Component owner, string slot, Sprite current, Action<Sprite> assign, string category)
		{
			Sprite desiredSprite = GetDesiredSprite(current);
			if (!((Object)(object)desiredSprite == (Object)(object)current))
			{
				LogReplacement(owner, slot, (Object)(object)current, (Object)(object)desiredSprite);
				assign(desiredSprite);
				replacementCount[category]++;
			}
		}

		private static void ReplaceTextureSlot(Component owner, string slot, Texture current, Action<Texture> assign, string category)
		{
			Texture desiredTexture = GetDesiredTexture(current);
			if (!((Object)(object)desiredTexture == (Object)(object)current))
			{
				LogReplacement(owner, slot, (Object)(object)current, (Object)(object)desiredTexture);
				assign(desiredTexture);
				replacementCount[category]++;
			}
		}

		internal static void Initialize()
		{
			LanguageManager.OnLanguageChanged += delegate(ValueChangedEvent<Lang> change)
			{
				LoadFiles(change.NewValue);
			};
		}

		public static void Apply()
		{
			Scan();
			StaticBatchAtlasSwapper.Apply();
		}

		private static void Scan()
		{
			if (scanInProgress)
			{
				return;
			}
			scanInProgress = true;
			try
			{
				string[] array = replacementCount.Keys.ToArray();
				foreach (string key in array)
				{
					replacementCount[key] = 0;
				}
				ReplaceImages();
				ReplaceStyleHud();
				ReplaceRawImages();
				ReplaceSpriteRenderers();
				ReplaceSpriteMasks();
				ReplaceRendererPropertyBlocks();
				ReplaceMaterialTextures();
				ReplaceLoadedTextures();
				CleanupStaleAssets();
				if (replacementCount.Values.Sum() > 0)
				{
					Logging.Message("Applied: " + string.Join(", ", replacementCount.Select((KeyValuePair<string, int> item) => $"{item.Value} {item.Key}")) + ".", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.cs");
				}
			}
			catch (Exception arg)
			{
				Logging.Error($"Scan failed: {arg}", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.cs");
			}
			finally
			{
				scanInProgress = false;
			}
		}

		private static void WarnOnce(string key, string message)
		{
			if (diagnostics.Add(key))
			{
				Logging.Warn(message, addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.cs");
			}
		}

		private static void LoadFiles(Lang language)
		{
			RestoreMutatedTextures();
			QueueGeneratedAssetsForCleanup();
			files.Clear();
			diagnostics.Clear();
			if (language == null || language.IsEnglish)
			{
				Logging.Message("Restored original textures for English.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Files.cs");
				return;
			}
			string textureFolder = language.TextureFolder;
			if (!Directory.Exists(textureFolder))
			{
				WarnOnce("folder:" + textureFolder, "Texture folder does not exist: '" + textureFolder + "'.");
				return;
			}
			foreach (string item in Directory.EnumerateFiles(textureFolder, "*.png"))
			{
				if (TryReadPngSize(item, out var png, out var width, out var height))
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item);
					if (files.ContainsKey(fileNameWithoutExtension))
					{
						WarnOnce("duplicate:" + fileNameWithoutExtension, "Multiple PNGs map to '" + fileNameWithoutExtension + "'; using '" + files[fileNameWithoutExtension].Path + "'.");
					}
					else
					{
						files.Add(fileNameWithoutExtension, new ReplacementFile(item, png, width, height));
					}
				}
			}
			Logging.Message($"Loaded {files.Count} replacement PNG(s) for '{language.Name}'.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Files.cs");
		}

		private static bool TryReadPngSize(string path, out byte[] png, out int width, out int height)
		{
			byte[] array = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 };
			byte[] array2 = new byte[8] { 0, 0, 0, 13, 73, 72, 68, 82 };
			try
			{
				png = File.ReadAllBytes(path);
			}
			catch (Exception ex)
			{
				png = null;
				width = (height = 0);
				WarnOnce("read:" + path, "Cannot read '" + path + "': " + ex.Message);
				return false;
			}
			width = (height = 0);
			if (png.Length < 24 || !png.AsSpan(0, 8).SequenceEqual(array) || !png.AsSpan(8, 8).SequenceEqual(array2))
			{
				WarnOnce("png:" + path, "Invalid PNG: '" + path + "'.");
				return false;
			}
			Span<byte> span = png.AsSpan(16, 13);
			width = ReadBigEndianInt(span.Slice(0, 4));
			height = ReadBigEndianInt(span.Slice(4, 4));
			if (width > 0 && height > 0)
			{
				return true;
			}
			WarnOnce("png:" + path, "Invalid PNG: '" + path + "'.");
			return false;
			static int ReadBigEndianInt(ReadOnlySpan<byte> bytes)
			{
				return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
			}
		}

		internal static bool TryGetFile(string assetName, out ReplacementFile file)
		{
			file = default(ReplacementFile);
			if (string.IsNullOrEmpty(assetName))
			{
				return false;
			}
			if (files.TryGetValue(assetName, out file))
			{
				return true;
			}
			string text = assetName;
			while (text.EndsWith(" (Instance)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - " (Instance)".Length);
			}
			if (text == assetName || !files.TryGetValue(text, out file))
			{
				return false;
			}
			if (diagnostics.Add("normalized:" + assetName + ":" + text))
			{
				Logging.Info("Normalized '" + assetName + "' -> '" + text + "'.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Files.cs");
			}
			return true;
		}

		private static void ReplaceRendererPropertyBlocks()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			Renderer[] array = Resources.FindObjectsOfTypeAll<Renderer>();
			foreach (Renderer val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				MaterialPropertyBlock val2 = new MaterialPropertyBlock();
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val3 = sharedMaterials[j];
					if ((Object)(object)val3 == (Object)null || (Object)(object)val3.shader == (Object)null)
					{
						continue;
					}
					val2.Clear();
					val.GetPropertyBlock(val2, j);
					if (val2.isEmpty)
					{
						continue;
					}
					bool flag = false;
					string[] texturePropertyNames = val3.GetTexturePropertyNames();
					foreach (string text in texturePropertyNames)
					{
						int num = Shader.PropertyToID(text);
						Texture texture = val2.GetTexture(num);
						if (!((Object)(object)texture == (Object)null))
						{
							Texture val4 = ResolveMaterialTexture(val3, text, texture);
							if (!((Object)(object)val4 == (Object)(object)texture))
							{
								val2.SetTexture(num, val4);
								flag = true;
								replacementCount["Renderer property block slot(s)"]++;
								Logging.Info("Renderer '" + ((Component)val).transform.GetPath() + "' | " + $"material[{j}] '{((Object)val3).name}'.{text} | " + "'" + ((Object)texture).name + "' -> '" + (((val4 != null) ? ((Object)val4).name : null) ?? "<null>") + "'", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Materials.cs");
							}
						}
					}
					if (flag)
					{
						val.SetPropertyBlock(val2, j);
					}
				}
			}
		}

		private static void ReplaceMaterialTextures()
		{
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			foreach (Material material in array)
			{
				ReplaceMaterialTextureProperties(material);
			}
		}

		private static void ReplaceMaterialTextureProperties(Material material)
		{
			if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null)
			{
				return;
			}
			string[] texturePropertyNames = material.GetTexturePropertyNames();
			foreach (string text in texturePropertyNames)
			{
				Texture texture = material.GetTexture(text);
				Texture val = ResolveMaterialTexture(material, text, texture);
				if (!((Object)(object)val == (Object)(object)texture))
				{
					LogReplacement(material, text, texture, val);
					material.SetTexture(text, val);
					replacementCount["material property(s)"]++;
				}
			}
		}

		private static Texture ResolveMaterialTexture(Material material, string property, Texture current)
		{
			Texture desiredTexture = GetDesiredTexture(current);
			Texture canonicalTexture = GetCanonicalTexture(current);
			if ((Object)(object)desiredTexture != (Object)(object)current || (Object)(object)canonicalTexture == (Object)null || !IsUnusableAssetName(((Object)canonicalTexture).name) || !IsMainTextureProperty(property) || !TryGetFile(((Object)material).name, out var file))
			{
				return desiredTexture;
			}
			desiredTexture = GetDesiredMaterialTexture(material, property, canonicalTexture, file);
			if ((Object)(object)desiredTexture != (Object)(object)current && diagnostics.Add($"material-fallback:{((Object)material).GetInstanceID()}:{property}"))
			{
				Logging.Info("Texture name '" + ((Object)canonicalTexture).name + "' is not usable; matched " + ((Object)material).name + "." + property + " through material name -> '" + file.Path + "'.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Materials.cs");
			}
			return desiredTexture;
		}

		private static void ReplaceLoadedTextures()
		{
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: 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)
			if (LanguageManager.IsEnglish)
			{
				return;
			}
			Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>();
			foreach (Texture2D val in array)
			{
				if ((Object)(object)val == (Object)null || textureReplacementCache.IsReplacement((Texture)(object)val) || mutatedTextures.ContainsKey(val) || !TryGetFile(((Object)val).name, out var file))
				{
					continue;
				}
				if (((Texture)val).width != file.Width || ((Texture)val).height != file.Height)
				{
					WarnOnce($"texture-size:{((Object)val).GetInstanceID()}:{file.Path}", $"Size mismatch '{((Object)val).name}': texture {((Texture)val).width}x{((Texture)val).height}, " + $"PNG {file.Width}x{file.Height}.");
					continue;
				}
				byte[] array2 = CapturePng(val);
				if (array2 != null)
				{
					MutatedTexture value = new MutatedTexture(array2, ((Texture)val).filterMode, ((Texture)val).wrapMode, ((Texture)val).anisoLevel);
					if (!ImageConversion.LoadImage(val, file.Bytes, false))
					{
						WarnOnce($"load:{((Object)val).GetInstanceID()}:{file.Path}", "Unity rejected '" + file.Path + "' for '" + ((Object)val).name + "'.");
					}
					else
					{
						ApplySampling((Texture)(object)val, value.FilterMode, value.WrapMode, value.AnisoLevel);
						mutatedTextures.Add(val, value);
						Logging.Info($"Texture2D '{((Object)val).name}' {((Texture)val).width}x{((Texture)val).height} | " + "PNG: '" + file.Path + "'", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Mutations.cs");
						replacementCount["loaded Texture2D object(s)"]++;
					}
				}
			}
		}

		private static byte[] CapturePng(Texture2D source)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			Texture2D val2 = null;
			try
			{
				val = RenderTexture.GetTemporary(((Texture)source).width, ((Texture)source).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0);
				Graphics.Blit((Texture)(object)source, val);
				RenderTexture.active = val;
				val2 = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false);
				val2.ReadPixels(new Rect(0f, 0f, (float)((Texture)source).width, (float)((Texture)source).height), 0, 0);
				val2.Apply();
				return ImageConversion.EncodeToPNG(val2);
			}
			catch (Exception ex)
			{
				WarnOnce($"capture:{((Object)source).GetInstanceID()}", "Cannot capture '" + ((Object)source).name + "': " + ex.Message);
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					RenderTexture.ReleaseTemporary(val);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
			}
		}

		private static void RestoreMutatedTextures()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<Texture2D, MutatedTexture> mutatedTexture in mutatedTextures)
			{
				Texture2D key = mutatedTexture.Key;
				MutatedTexture value = mutatedTexture.Value;
				if (!((Object)(object)key == (Object)null))
				{
					if (!ImageConversion.LoadImage(key, value.OriginalPng, false))
					{
						Logging.Error("Failed to restore '" + ((Object)key).name + "'.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.Mutations.cs");
					}
					ApplySampling((Texture)(object)key, value.FilterMode, value.WrapMode, value.AnisoLevel);
				}
			}
			mutatedTextures.Clear();
		}

		public static void ReplaceStyleHud()
		{
			StyleHUD instance = MonoSingleton<StyleHUD>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			bool flag = false;
			foreach (StyleRank rank in instance.ranks)
			{
				if (rank != null)
				{
					Sprite desiredSprite = GetDesiredSprite(rank.sprite);
					if (!((Object)(object)desiredSprite == (Object)(object)rank.sprite))
					{
						string[] obj = new string[6] { "StyleHUD.ranks | '", null, null, null, null, null };
						Sprite sprite = rank.sprite;
						obj[1] = ((sprite != null) ? ((Object)sprite).name : null) ?? "<null>";
						obj[2] = "' -> '";
						obj[3] = ((desiredSprite != null) ? ((Object)desiredSprite).name : null) ?? "<null>";
						obj[4] = "'";
						obj[5] = GetSourceSuffix((Object)(object)rank.sprite);
						Logging.Info(string.Concat(obj), addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Localization\\Textures\\Swapper\\TextureSwapper.StyleHud.cs");
						rank.sprite = desiredSprite;
						flag = true;
						replacementCount["StyleHUD rank sprite(s)"]++;
					}
				}
			}
			if (flag)
			{
				instance.rankIndex = instance.rankIndex;
			}
		}
	}
	[HarmonyPatch(typeof(StyleHUD))]
	public static class StyleHudTexturePatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		public static void Postfix()
		{
			TextureSwapper.ReplaceStyleHud();
		}
	}
	public static class TransformExtensions
	{
		[SpecialName]
		public sealed class <G>$1945437846AC44BD79BE419C90BB2AE7
		{
			[SpecialName]
			public static class <M>$18F3075279F8D3FE3282E1665383A7B4
			{
			}

			[ExtensionMarker("<M>$18F3075279F8D3FE3282E1665383A7B4")]
			public string GetPath()
			{
				throw null;
			}
		}

		public static string GetPath(this Transform value)
		{
			List<string> list = new List<string>();
			Transform val = value;
			while ((Object)(object)val != (Object)null)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}
	}
	[HarmonyPatch(typeof(TextMeshProUGUI))]
	public static class TextMeshProFontSwap
	{
		private sealed class OriginalFont
		{
			public TMP_FontAsset Font;

			public Material Material;
		}

		private static readonly Dictionary<TMP_Text, OriginalFont> originalFonts = new Dictionary<TMP_Text, OriginalFont>();

		public static void Initialize()
		{
			LanguageManager.OnLanguageChanged += OnLanguageChanged;
		}

		[HarmonyPatch("OnEnable")]
		[HarmonyPostfix]
		private static void OnEnable_Postfix(TextMeshProUGUI __instance)
		{
			Apply((TMP_Text)(object)__instance);
		}

		public static void Apply(TMP_Text text)
		{
			Lang current = LanguageManager.Current;
			if (!FontManager.TMPFontReady || LanguageManager.IsEnglish || current == null || current.UseFontFallback || (Object)(object)text.font == (Object)(object)current.MainFontAsset || (Object)(object)text.font == (Object)(object)current.TerminalAsset || (Object)(object)text.font == (Object)(object)current.MuseumAsset || (Object)(object)text.font == (Object)(object)current.SecretTerminalAsset)
			{
				return;
			}
			TMP_FontAsset replacementFont = GetReplacementFont(text);
			if (!((Object)(object)replacementFont == (Object)null) && !((Object)(object)replacementFont == (Object)(object)text.font))
			{
				Material val = text.fontSharedMaterial ?? ((TMP_Asset)text.font).material;
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((TMP_Asset)replacementFont).material == (Object)null))
				{
					originalFonts.TryAdd(text, new OriginalFont
					{
						Font = text.font,
						Material = text.fontSharedMaterial
					});
					text.font = replacementFont;
					text.fontSharedMaterial = TMP_MaterialManager.GetFallbackMaterial(val, ((TMP_Asset)replacementFont).material);
				}
			}
		}

		private static void OnLanguageChanged(ValueChangedEvent<Lang> change)
		{
			foreach (KeyValuePair<TMP_Text, OriginalFont> originalFont in originalFonts)
			{
				if (!((Object)(object)originalFont.Key == (Object)null))
				{
					originalFont.Key.font = originalFont.Value.Font;
					originalFont.Key.fontSharedMaterial = originalFont.Value.Material;
				}
			}
			originalFonts.Clear();
			TextMeshProUGUI[] array = Resources.FindObjectsOfTypeAll<TextMeshProUGUI>();
			foreach (TextMeshProUGUI text in array)
			{
				Apply((TMP_Text)(object)text);
			}
		}

		public static TMP_FontAsset GetReplacementFont(TMP_Text text)
		{
			string name = ((Object)text.font).name;
			if (1 == 0)
			{
			}
			TMP_FontAsset result;
			switch (name)
			{
			case "VCR_OSD_MONO_1":
			case "VCR_OSD_MONO_UI":
			case "vcr-osd-replayed":
				result = LanguageManager.Current?.MainFontAsset;
				break;
			case "fs-tahoma-8px SDF":
			case "fs-tahoma-8px SDF v2":
				result = LanguageManager.Current?.TerminalAsset;
				break;
			case "MeseumFont":
				result = LanguageManager.Current?.MuseumAsset;
				break;
			case "Bittypix Monospace SDF":
				result = LanguageManager.Current?.SecretTerminalAsset;
				break;
			default:
				result = LanguageManager.Current.MainFontAsset;
				break;
			}
			if (1 == 0)
			{
			}
			return result;
		}
	}
	public static class TextMirror
	{
		public static TextMeshProUGUI CreateChild(Text source)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject($"TMP_for_{((Object)((Component)source).gameObject).name}_{((Object)source).GetInstanceID()}", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(((Component)source).transform, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			LayoutElement val3 = val.AddComponent<LayoutElement>();
			val3.ignoreLayout = true;
			RectTransform rectTransform = ((TMP_Text)val2).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = Vector2.zero;
			rectTransform.offsetMax = Vector2.zero;
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			((Transform)rectTransform).localScale = Vector3.one;
			((Transform)rectTransform).localRotation = Quaternion.identity;
			return val2;
		}

		public static void SetFont(Text source, TextMeshProUGUI target)
		{
			if (!((Object)(object)source == (Object)null) && !((Object)(object)target == (Object)null))
			{
				TMP_FontAsset twinFont = FontManager.GetTwinFont(((Object)(object)source.font != (Object)null) ? ((Object)source.font).name : null);
				if (!((Object)(object)twinFont == (Object)null))
				{
					((TMP_Text)target).font = twinFont;
					((TMP_Text)target).fontSharedMaterial = ((TMP_Asset)twinFont).material;
				}
			}
		}

		public static void CopyTextProperties(Text source, TextMeshProUGUI target)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_0093: Invalid comparison between Unknown and I4
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)source == (Object)null) && !((Object)(object)target == (Object)null))
			{
				((TMP_Text)target).text = source.text;
				((TMP_Text)target).fontSize = source.fontSize;
				((Graphic)target).color = ((Graphic)source).color;
				((TMP_Text)target).richText = source.supportRichText;
				((Graphic)target).raycastTarget = ((Graphic)source).raycastTarget;
				((MaskableGraphic)target).maskable = ((MaskableGraphic)source).maskable;
				((TMP_Text)target).lineSpacing = source.lineSpacing;
				((TMP_Text)target).alignment = ConvertAlignment(source.alignment);
				((TMP_Text)target).enableWordWrapping = (int)source.horizontalOverflow == 0;
				((TMP_Text)target).overflowMode = (TextOverflowModes)(((int)source.verticalOverflow != 1) ? 3 : 0);
				((TMP_Text)target).enableAutoSizing = source.resizeTextForBestFit;
				if (source.resizeTextForBestFit)
				{
					((TMP_Text)target).fontSizeMin = source.resizeTextMinSize;
					((TMP_Text)target).fontSizeMax = source.resizeTextMaxSize;
				}
				((TMP_Text)target).fontStyle = ConvertFontStyle(source.fontStyle);
			}
		}

		internal static void AddIntermissionShadow(TextMeshProUGUI tmp)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)tmp == (Object)null))
			{
				Material fontMaterial = ((TMP_Text)tmp).fontMaterial;
				fontMaterial.EnableKeyword(ShaderUtilities.Keyword_Underlay);
				fontMaterial.SetColor(ShaderUtilities.ID_UnderlayColor, new Color(0f, 0f, 0f, 0.75f));
				fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetX, 0.5f);
				fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayOffsetY, -0.5f);
				fontMaterial.SetFloat(ShaderUtilities.ID_UnderlayDilate, 0.1f);
				fontMaterial.SetFloat(ShaderUtilities.ID_UnderlaySoftness, 0f);
				((TMP_Text)tmp).UpdateMeshPadding();
				((TMP_Text)tmp).ForceMeshUpdate(false, false);
			}
		}

		internal static void ApplyFishCaughtShadow(TextMeshProUGUI tmp)
		{
			//IL_003b: Unknown result type