Decompiled source of ULTRAESPANOL o UltraEsp v2.1.0

plugins/UltrakULL/UltrakULL.dll

Decompiled 6 days 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 AngryLevelLoader.Containers;
using AngryLevelLoader.Fields;
using AngryLevelLoader.Managers;
using AngryLevelLoader.Notifications;
using AngryLevelLoader.Patches;
using AngryLevelLoader.UserInterface;
using AngryUiComponents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Discord;
using GameConsole;
using GameConsole.CommandTree;
using GreyAnnouncer.AudioClipLoad;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Functionals;
using Sandbox;
using ScriptableObjects;
using SettingsMenu.Components;
using TMPro;
using UltrakULL.Harmony_Patches;
using UltrakULL.audio;
using UltrakULL.json;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using plog;
using plog.Models;

[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("AngryLevelLoader")]
[assembly: IgnoresAccessChecksTo("AngryUiComponents")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("plog")]
[assembly: IgnoresAccessChecksTo("RudeLevelScripts.Essentials")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: AssemblyCompany("UltrakULL")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+741cfab974b6ba7b1dfcc673ec496a58ad58c0ba")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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)
		{
		}
	}
}
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
	{
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class PatchForMod : Attribute
	{
		public string Guid;

		public string ClassName;

		public string MethodName;

		public string[] Args;

		public PatchForMod(string guid, string className = null, string methodName = null, string[] args = null)
		{
			Guid = guid;
			ClassName = className;
			MethodName = methodName;
			Args = args;
		}
	}
	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)
					{
						SubtitleData val2 = item.ToSubtitleData();
						if (val2.lines.Any((SubtitleDataLine line) => !StringHelper.IsEmpty(line.subtitle)))
						{
							ReflectionUtils.SetPrivate<SubtitledAudioSource, SubtitleData>(component, typeof(SubtitledAudioSource), "subtitles", val2);
						}
					}
				}
			}
			AudioSwapper.WhenReady(delegate
			{
				foreach (var item2 in audioReplacements)
				{
					item2.source.clip = AudioSwapper.SwapClipWithFile(item2.source.clip, item2.path);
				}
			});
		}

		private static bool ActiveDubbingEnabled()
		{
			return Settings.activeDubbing.Value;
		}

		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 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 || StringHelper.IsEmpty(line))
			{
				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 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);
		}
	}
	public sealed class CommandToRegister : CommandRoot, IConsoleLogger
	{
		public override string Name => "ultrakull";

		public override string Description => "tons of setting";

		public Logger Log { get; } = new Logger("ultrakull");

		public CommandToRegister(Console con)
			: base(con)
		{
		}//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown


		public override Branch BuildTree(Console con)
		{
			return CommandRoot.Branch(((CommandRoot)this).Name, (Node[])(object)new Node[4]
			{
				(Node)CommandRoot.Leaf("migrate", (Action)delegate
				{
					LegacyLanguageMigrator.LegacyMigrationResult legacyMigrationResult = LegacyLanguageMigrator.Migrate();
					Log.Info($"Migrated {legacyMigrationResult.MigratedLanguages} legacy language package(s).", (IEnumerable<Tag>)null, (string)null, (object)null);
					foreach (string warning in legacyMigrationResult.Warnings)
					{
						Log.Warning(warning, (IEnumerable<Tag>)null, (string)null, (object)null);
					}
					if (legacyMigrationResult.SkippedLanguages > 0)
					{
						Log.Warning($"Skipped {legacyMigrationResult.SkippedLanguages} language package(s). See messages above.", (IEnumerable<Tag>)null, (string)null, (object)null);
					}
					if (legacyMigrationResult.MigratedLanguages > 0)
					{
						Log.Info("A copy of every migrated file was kept in \"" + legacyMigrationResult.BackupDirectory + "\".", (IEnumerable<Tag>)null, (string)null, (object)null);
					}
					Log.Info("Restart the game before editing or removing the backup.", (IEnumerable<Tag>)null, (string)null, (object)null);
				}, false),
				(Node)CommandRoot.Leaf("dhm", (Action)delegate
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					Logging.Info("=========================", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Commands\\CommandsToRegister.cs");
					Scene activeScene = SceneManager.GetActiveScene();
					GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
					foreach (GameObject val in rootGameObjects)
					{
						HudMessage[] componentsInChildren = val.GetComponentsInChildren<HudMessage>(true);
						foreach (HudMessage val2 in componentsInChildren)
						{
							string arg = (((Object)(object)val2.actionReference == (Object)null) ? "-" : val2.actionReference.action.id.ToString());
							Logging.Info($"\n[HudMsgScan] obj='{((Object)((Component)val2).gameObject).name}' (active={((Component)val2).gameObject.activeInHierarchy})" + "\n  msg ='" + val2.message + "'\n  m2  ='" + val2.message2 + "'\n  fm = '" + GetFullMessage(val2) + "'" + $"\n  advanced={val2.advancedMessage} action={arg}" + "\n  ------------------------------", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Commands\\CommandsToRegister.cs");
						}
					}
				}, false),
				(Node)CommandRoot.Branch("gene", (Node[])(object)new Node[1] { (Node)CommandRoot.Leaf("angry", (Action)delegate
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: Expected O, but got Unknown
					try
					{
						string path;
						JObject val = LoadAngryFile(out path);
						if (val["angryUi"] == null)
						{
							JObject val2 = new JObject();
							string[] array = (from property in val.Properties()
								select property.Name).ToArray();
							foreach (string text in array)
							{
								if (!(text == "angryBundles"))
								{
									val2[text] = val[text];
									val.Remove(text);
								}
							}
							if (((JToken)val2).HasValues)
							{
								val["angryUi"] = (JToken)(object)val2;
								Log.Info("Moved the flat UI sections under \"angryUi\".", (IEnumerable<Tag>)null, (string)null, (object)null);
							}
						}
						JToken obj = val["angryUi"];
						JObject val3 = (JObject)(object)((obj is JObject) ? obj : null);
						if (val3 != null)
						{
							FillGaps(val3, BlankOf(new AngryUi()));
						}
						else
						{
							val["angryUi"] = (JToken)(object)BlankOf(new AngryUi());
						}
						File.WriteAllText(path, ((JToken)val).ToString((Formatting)1, Array.Empty<JsonConverter>()));
						Log.Info("Written " + path + " (angry ui).", (IEnumerable<Tag>)null, (string)null, (object)null);
					}
					catch (Exception arg)
					{
						Log.Error($"Failed to write the angry ui: {arg}", (IEnumerable<Tag>)null, (string)null, (object)null);
					}
				}, false) }),
				(Node)CommandRoot.Branch("scan", (Node[])(object)new Node[1] { (Node)CommandRoot.Leaf("angrylevel", (Action)delegate
				{
					//IL_0064: Unknown result type (might be due to invalid IL or missing references)
					//IL_0069: Unknown result type (might be due to invalid IL or missing references)
					//IL_006f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0074: Unknown result type (might be due to invalid IL or missing references)
					//IL_0076: Expected O, but got Unknown
					//IL_007b: Expected O, but got Unknown
					//IL_0081: Expected O, but got Unknown
					//IL_0103: Unknown result type (might be due to invalid IL or missing references)
					//IL_0108: Unknown result type (might be due to invalid IL or missing references)
					//IL_010b: Expected O, but got Unknown
					//IL_0110: Expected O, but got Unknown
					//IL_0167: Unknown result type (might be due to invalid IL or missing references)
					//IL_016c: Unknown result type (might be due to invalid IL or missing references)
					//IL_016f: Expected O, but got Unknown
					//IL_0174: Expected O, but got Unknown
					//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
					//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
					//IL_0194: Unknown result type (might be due to invalid IL or missing references)
					//IL_0199: Unknown result type (might be due to invalid IL or missing references)
					//IL_019c: Expected O, but got Unknown
					//IL_01a1: Expected O, but got Unknown
					try
					{
						if (!AngrySceneTracker.InAngryLevel)
						{
							Log.Warning("Not in an Angry level. Load a custom level first, then scan it.", (IEnumerable<Tag>)null, (string)null, (object)null);
						}
						else
						{
							string path;
							JObject val = LoadAngryFile(out path);
							JToken obj = val["angryBundles"];
							JToken obj2 = ((obj != null) ? obj[(object)"bundles"] : null);
							JObject val2 = (JObject)(object)((obj2 is JObject) ? obj2 : null);
							if (val2 == null)
							{
								JObject val3 = new JObject();
								JObject val4 = new JObject();
								val2 = val4;
								val3["bundles"] = (JToken)val4;
								val["angryBundles"] = (JToken)val3;
							}
							string bundleGuid = AngryLevelText.BundleGuid;
							string levelId = AngryLevelText.LevelId;
							if (string.IsNullOrEmpty(bundleGuid) || string.IsNullOrEmpty(levelId))
							{
								Log.Error("In an Angry level but its ids are empty... (bundle='" + bundleGuid + "', level='" + levelId + "').", (IEnumerable<Tag>)null, (string)null, (object)null);
							}
							else
							{
								JToken obj3 = val2[bundleGuid];
								JObject val5 = (JObject)(object)((obj3 is JObject) ? obj3 : null);
								if (val5 == null)
								{
									JObject obj4 = val2;
									JObject val6 = new JObject();
									val5 = val6;
									obj4[bundleGuid] = (JToken)val6;
								}
								JObject val7 = val5;
								if (val7["bundleName"] == null)
								{
									JToken val8 = (val7["bundleName"] = JToken.op_Implicit(AngrySceneManager.currentBundleContainer.BundleName));
								}
								JToken obj5 = val5["levels"];
								JObject val10 = (JObject)(object)((obj5 is JObject) ? obj5 : null);
								if (val10 == null)
								{
									JObject obj6 = val5;
									JObject val11 = new JObject();
									val10 = val11;
									obj6["levels"] = (JToken)val11;
								}
								JToken obj7 = val10[levelId];
								JObject val12 = (JObject)(object)((obj7 is JObject) ? obj7 : null);
								if (val12 == null)
								{
									JObject obj8 = val10;
									JObject val13 = new JObject();
									val12 = val13;
									obj8[levelId] = (JToken)val13;
								}
								FillGaps(val12, BlankOf(new AngryLevel()));
								JArray array = ArrayIn(val12, "books");
								JArray array2 = ArrayIn(val12, "hudMessages");
								Scene activeScene = SceneManager.GetActiveScene();
								GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
								foreach (GameObject val14 in rootGameObjects)
								{
									HudMessage[] componentsInChildren = val14.GetComponentsInChildren<HudMessage>(true);
									foreach (HudMessage hm in componentsInChildren)
									{
										AddMatch(array2, GetFullMessage(hm), "");
									}
									Readable[] componentsInChildren2 = val14.GetComponentsInChildren<Readable>(true);
									foreach (Readable val15 in componentsInChildren2)
									{
										AddMatch(array, val15.content, "");
									}
								}
								File.WriteAllText(path, ((JToken)val).ToString((Formatting)1, Array.Empty<JsonConverter>()));
								Log.Info("Written " + path + ": " + AngrySceneManager.currentBundleContainer.BundleName + " / " + levelId + ".", (IEnumerable<Tag>)null, (string)null, (object)null);
							}
						}
					}
					catch (Exception arg)
					{
						Log.Error($"Failed to scan the angry level: {arg}", (IEnumerable<Tag>)null, (string)null, (object)null);
					}
				}, false) })
			});
		}

		private static string GetFullMessage(HudMessage hm)
		{
			if (hm.advancedMessage)
			{
				return hm.message;
			}
			if ((Object)(object)hm.actionReference == (Object)null)
			{
				return hm.message;
			}
			return hm.message + "{0}" + hm.message2;
		}

		private static JObject LoadAngryFile(out string path)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			string angryLevelFolder = LanguageManager.Current.AngryLevelFolder;
			path = Path.Combine(angryLevelFolder, "angry.json");
			Directory.CreateDirectory(angryLevelFolder);
			return (JObject)(File.Exists(path) ? (((object)JObject.Parse(File.ReadAllText(path))) ?? ((object)new JObject())) : ((object)new JObject()));
		}

		private static JObject BlankOf(object target)
		{
			JObject val = JObject.FromObject(target);
			foreach (JToken item in (from t in ((JContainer)val).Descendants()
				where (int)t.Type == 10
				select t).ToList())
			{
				item.Replace(JToken.op_Implicit(""));
			}
			return val;
		}

		private static void FillGaps(JObject node, JObject template)
		{
			foreach (JProperty item in template.Properties())
			{
				JToken value = item.Value;
				JObject val = (JObject)(object)((value is JObject) ? value : null);
				if (val != null)
				{
					JToken obj = node[item.Name];
					JObject val2 = (JObject)(object)((obj is JObject) ? obj : null);
					if (val2 != null)
					{
						FillGaps(val2, val);
					}
					else
					{
						node[item.Name] = ((JToken)val).DeepClone();
					}
				}
				else if (node[item.Name] == null)
				{
					node[item.Name] = item.Value.DeepClone();
				}
			}
		}

		private static JArray ArrayIn(JObject parent, string name)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			JToken obj = parent[name];
			JArray val = (JArray)(object)((obj is JArray) ? obj : null);
			if (val != null)
			{
				return val;
			}
			return (JArray)(object)(parent[name] = (JToken)new JArray());
		}

		private static void AddMatch(JArray array, string match, string text)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			if (string.IsNullOrEmpty(match))
			{
				return;
			}
			foreach (JToken item in array)
			{
				JObject val = (JObject)(object)((item is JObject) ? item : null);
				if (val != null && (string)val["match"] == match)
				{
					return;
				}
			}
			array.Add((JToken)new JObject
			{
				["match"] = JToken.op_Implicit(match),
				["text"] = JToken.op_Implicit(text)
			});
		}
	}
	[HarmonyPatch(typeof(Console))]
	public class ConsolePatcher
	{
		[HarmonyPatch("Awake")]
		[HarmonyPrefix]
		public static void AddConsoleCommands(Console __instance)
		{
			CommandToRegister commandToRegister = new CommandToRegister(__instance);
			__instance.RegisterCommand((ICommand)(object)commandToRegister);
		}
	}
	public static class ConfigPaths
	{
		public static string RootDirectory => Path.Combine(Paths.ConfigPath, "ultrakull");

		public static string LanguagesDirectory => Path.Combine(RootDirectory, "languages");

		public static string TemplatesDirectory => Path.Combine(RootDirectory, "templates");

		public static string LegacyBackupDirectory => Path.Combine(RootDirectory, "legacy-backup");

		public static string SettingsFile => Path.Combine(RootDirectory, "lastLang.cfg");

		public static string GetLegacyAudioDirectory(string languageId)
		{
			return Path.Combine(RootDirectory, "audio", languageId);
		}

		public static string GetLegacyTextureDirectory(string languageId)
		{
			return Path.Combine(RootDirectory, "textures", languageId);
		}

		public static string GetLegacyAngryDirectory(string languageId)
		{
			return Path.Combine(RootDirectory, "angry", languageId);
		}

		public static string GetFontBundlePath(string languageId)
		{
			return Path.Combine(MainPatch.ModFolder, "fonts", languageId);
		}

		public static string GetUIOverridePath(string languageId)
		{
			return Path.Combine(MainPatch.ModFolder, "fonts", languageId, "layout.json");
		}
	}
	public static class Core
	{
		public static bool wasLanguageReset;

		public static void LocalizeScene(GameObject canvasObj, bool sceneEntry)
		{
			string currentSceneName = SceneObjects.GetCurrentSceneName();
			if (currentSceneName == "Intro" || currentSceneName == "Bootstrap")
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)canvasObj))
			{
				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(canvasObj);
				Options.Patch(canvasObj);
			}
			else
			{
				if (sceneEntry)
				{
					UILayoutOverride.AdjustOptionTextPosition();
				}
				if (LanguageManager.IsEnglish)
				{
					Logging.Warn("Current language is English, not patching.", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
					return;
				}
				Logging.Message("Regular scene", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
				PatchingBaseElements(canvasObj);
				LevelPatcher.Patch(currentSceneName, canvasObj);
			}
		}

		private static void PatchingBaseElements(GameObject canvasObj)
		{
			Logging.Message("Attempting to patch base elements", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			try
			{
				_PauseMenu.PatchPauseMenu(canvasObj);
			}
			catch (Exception ex)
			{
				Logging.Error(ex.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			try
			{
				Cheats.PatchCheatConsentPanel(canvasObj);
			}
			catch (Exception ex2)
			{
				Logging.Error(ex2.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			try
			{
				Sandbox.PatchAlterMenu();
			}
			catch (Exception ex3)
			{
				Logging.Error(ex3.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			try
			{
				HUDMessages.PatchDeathScreen(canvasObj);
			}
			catch (Exception ex4)
			{
				Logging.Error(ex4.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			try
			{
				LevelStatWindow.PatchStats(canvasObj);
			}
			catch (Exception ex5)
			{
				Logging.Error(ex5.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			try
			{
				HUDMessages.PatchMisc(canvasObj);
			}
			catch (Exception ex6)
			{
				Logging.Error(ex6.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			try
			{
				Options.Patch(canvasObj);
			}
			catch (Exception ex7)
			{
				Logging.Error(ex7.ToString(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
			}
			Logging.Message("Base elements patched", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Core.cs");
		}
	}
	internal static class DependencyGuid
	{
		public const string ANGRY_LEVEL_LOADER = "com.eternalUnion.angryLevelLoader";
	}
	public static class LocalizationExtensions
	{
		internal static bool DebugMode;

		public static T Localize<T>(this T target, string translation, bool uppercase = false) where T : Component
		{
			if ((Object)(object)target == (Object)null)
			{
				return target;
			}
			object obj = target;
			TMP_Text val = (TMP_Text)((obj is TMP_Text) ? obj : null);
			if (val == null)
			{
				object obj2 = target;
				Text val2 = (Text)((obj2 is Text) ? obj2 : null);
				if (val2 != null)
				{
					val2.text = translation.Or(val2.text).ToUpperIf(uppercase);
				}
			}
			else
			{
				val.text = translation.Or(val.text).ToUpperIf(uppercase);
			}
			return target;
		}

		public static OptionData Localize(this OptionData option, string translation, bool uppercase = false)
		{
			if (option == null)
			{
				return option;
			}
			option.text = translation.Or(option.text).ToUpperIf(uppercase);
			return option;
		}

		public static T Localize<T>(this GameObject parent, string translation, string[] path, bool uppercase = false, bool saveToCache = true) where T : Component
		{
			return SceneObjects.FindComponent<T>(parent, path).Localize(translation, uppercase);
		}

		public static string Or(this string translation, string original)
		{
			return StringHelper.IsEmpty(translation) ? original : Penis(original, translation);
		}

		public static string ToUpperIf(this string text, bool uppercase)
		{
			return uppercase ? text.ToUpper() : text;
		}

		private static string Penis(string original, string replacement)
		{
			original = ((!DebugMode) ? replacement : (original + "/" + replacement));
			return original;
		}

		public static string Format(string format, params object[] parts)
		{
			if (string.IsNullOrEmpty(format) || parts == null || parts.Length == 0)
			{
				return null;
			}
			foreach (object obj in parts)
			{
				if (obj == null || (obj is string text && StringHelper.IsEmpty(text)))
				{
					return null;
				}
			}
			try
			{
				return string.Format(format, parts);
			}
			catch (FormatException)
			{
				Logging.Warn("Format failed for template: '" + format + "'", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Extensions\\LocalizationExtensions.cs");
				return null;
			}
		}

		public static string FormatWith(this string format, params object[] parts)
		{
			return Format(format, parts);
		}
	}
	public class FontConfig
	{
		public string FontPackName;

		public string MainFont;

		public string TerminalFont;

		public string MuseumFont;

		public string SecretFont;
	}
	public static class FontManager
	{
		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");
			TwinFont = val.LoadAsset<TMP_FontAsset>("VCR_OSD_MONO_TWINFONT");
			TMPFontReady = true;
		}

		public static void LoadLangFonts(Lang lang)
		{
			if ((Object)(object)lang.FontBundle != (Object)null)
			{
				return;
			}
			string fontBundlePath = ConfigPaths.GetFontBundlePath(lang.Name);
			FontConfig fontConfig = JsonConvert.DeserializeObject<FontConfig>(File.ReadAllText(Path.Combine(fontBundlePath, "fontconfig.json")));
			AssetBundle val = AssetBundle.LoadFromFile(Path.Combine(fontBundlePath, fontConfig.FontPackName));
			if ((Object)(object)val == (Object)null)
			{
				Logging.Warn("Failed to load language font bundle: " + 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;
			lang.MainFontAsset = val.LoadAsset<TMP_FontAsset>(fontConfig.MainFont);
			lang.TerminalAsset = val.LoadAsset<TMP_FontAsset>(fontConfig.TerminalFont);
			lang.MuseumAsset = val.LoadAsset<TMP_FontAsset>(fontConfig.MuseumFont);
			lang.SecretTerminalAsset = val.LoadAsset<TMP_FontAsset>(fontConfig.SecretFont);
		}

		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;
					}
					else if ((Object)(object)val == (Object)(object)TwinFont)
					{
						fallback = lang.MainFontAsset;
					}
					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 LegacyLanguageMigrator
	{
		public struct LegacyMigrationResult
		{
			public int MigratedLanguages;

			public int SkippedLanguages;

			public IReadOnlyList<string> Warnings;

			public string BackupDirectory;

			public LegacyMigrationResult(int migrated, int skipped, IReadOnlyList<string> warnings, string backupDirectory)
			{
				MigratedLanguages = migrated;
				SkippedLanguages = skipped;
				Warnings = warnings;
				BackupDirectory = backupDirectory;
			}
		}

		public static LegacyMigrationResult Migrate()
		{
			int num = 0;
			int num2 = 0;
			List<string> list = new List<string>();
			if (!Directory.Exists(ConfigPaths.RootDirectory))
			{
				return new LegacyMigrationResult(0, 0, Array.Empty<string>(), null);
			}
			string legacyBackupDirectory = ConfigPaths.LegacyBackupDirectory;
			MirrorLegacyLayout(legacyBackupDirectory);
			foreach (string item in Directory.EnumerateFiles(ConfigPaths.RootDirectory, "*.json", SearchOption.TopDirectoryOnly))
			{
				try
				{
					if (MoveToPackage(item))
					{
						num++;
					}
				}
				catch (Exception ex)
				{
					num2++;
					list.Add("Skipped '" + item + "': " + ex.Message);
				}
			}
			return new LegacyMigrationResult(num, num2, list, legacyBackupDirectory);
		}

		private static void MirrorLegacyLayout(string backupRoot)
		{
			Directory.CreateDirectory(backupRoot);
			foreach (string item in Directory.EnumerateFiles(ConfigPaths.RootDirectory, "*.json", SearchOption.TopDirectoryOnly))
			{
				File.Copy(item, Path.Combine(backupRoot, Path.GetFileName(item)), overwrite: true);
			}
			CopyDirectoryIfExists(Path.Combine(ConfigPaths.RootDirectory, "audio"), Path.Combine(backupRoot, "audio"));
			CopyDirectoryIfExists(Path.Combine(ConfigPaths.RootDirectory, "textures"), Path.Combine(backupRoot, "textures"));
		}

		private static bool MoveToPackage(string sourceFile)
		{
			string text = JsonConvert.DeserializeObject<JsonFormat>(File.ReadAllText(sourceFile))?.metadata?.langName;
			if (text == "te-mp")
			{
				MoveTemplate(sourceFile);
				return false;
			}
			if (!IsSafeLanguageId(text))
			{
				throw new InvalidDataException("Invalid or missing language id");
			}
			string text2 = Path.Combine(ConfigPaths.LanguagesDirectory, text);
			string text3 = Path.Combine(text2, "language.json");
			string legacyAudioDirectory = ConfigPaths.GetLegacyAudioDirectory(text);
			string legacyTextureDirectory = ConfigPaths.GetLegacyTextureDirectory(text);
			string text4 = Path.Combine(text2, "audio");
			string text5 = Path.Combine(text2, "textures");
			if (File.Exists(text3) || (Directory.Exists(legacyAudioDirectory) && Directory.Exists(text4)) || (Directory.Exists(legacyTextureDirectory) && Directory.Exists(text5)))
			{
				throw new IOException("The destination package already contains data");
			}
			Directory.CreateDirectory(text2);
			MoveDirectoryIfExists(legacyAudioDirectory, text4);
			MoveDirectoryIfExists(legacyTextureDirectory, text5);
			File.Move(sourceFile, text3);
			return true;
		}

		private static void MoveTemplate(string sourceFile)
		{
			string text = Path.Combine(ConfigPaths.TemplatesDirectory, "language.json");
			if (!File.Exists(text))
			{
				Directory.CreateDirectory(ConfigPaths.TemplatesDirectory);
				File.Move(sourceFile, text);
			}
		}

		private static void CopyDirectoryIfExists(string source, string destination)
		{
			if (Directory.Exists(source))
			{
				CopyDirectory(source, destination);
			}
		}

		private static void MoveDirectoryIfExists(string source, string destination)
		{
			if (Directory.Exists(source))
			{
				Directory.Move(source, destination);
			}
		}

		private static void CopyDirectory(string source, string destination)
		{
			Directory.CreateDirectory(destination);
			foreach (string item in Directory.EnumerateFiles(source))
			{
				File.Copy(item, Path.Combine(destination, Path.GetFileName(item)), overwrite: true);
			}
			foreach (string item2 in Directory.EnumerateDirectories(source))
			{
				CopyDirectory(item2, Path.Combine(destination, Path.GetFileName(item2)));
			}
		}

		private static bool IsSafeLanguageId(string languageId)
		{
			return !string.IsNullOrWhiteSpace(languageId) && languageId != "." && languageId != ".." && languageId.IndexOfAny(Path.GetInvalidFileNameChars()) < 0 && languageId.IndexOf(Path.DirectorySeparatorChar) < 0 && languageId.IndexOf(Path.AltDirectorySeparatorChar) < 0;
		}
	}
	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")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class MainPatch : BaseUnityPlugin
	{
		private const string Guid = "clearwater.ultrakill.ultrakull";

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

		internal 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 DisableMod()
		{
			ready = false;
		}

		private void Awake()
		{
			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
			{
				InitializeLocalization();
				Logging.Warn(" --- All done. Enjoy! ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				ready = true;
				SceneManager.sceneLoaded += OnSceneLoaded;
			}
			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");
				Logging.Fatal("Scene name: " + SceneObjects.GetCurrentSceneName(), addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				ready = false;
			}
		}

		private static void InitializeLocalization()
		{
			Logging.Warn("--- Initializing config ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
			Settings.InitializeConfig();
			Logging.Warn("--- Loading shared font assets ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
			FontManager.LoadFonts();
			Logging.Warn("--- Registering language-change handlers ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
			FontManager.Initialize();
			TextMeshProFontSwap.Initialize();
			SubtitleLocalizer.Initialize();
			TextureSwapper.Initialize();
			UILayoutOverride.Initialize();
			Logging.Warn("--- Loading languages and selecting the active language ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
			LanguageManager.InitializeManager("1.3.0");
			Logging.Warn("--- Installing game hooks ---", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
			LoadPatches();
		}

		private static void LoadPatches()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			Harmony val = new Harmony("clearwater.ultrakill.ultrakull");
			TriggerEngine.Init(val);
			AngrySceneTracker.Init();
			Type[] types = typeof(MainPatch).Assembly.GetTypes();
			foreach (Type type in types)
			{
				try
				{
					PatchForMod customAttribute = type.GetCustomAttribute<PatchForMod>();
					if (customAttribute != null)
					{
						if (Chainloader.PluginInfos.ContainsKey(customAttribute.Guid))
						{
							if (string.IsNullOrEmpty(customAttribute.ClassName))
							{
								val.PatchAll(type);
								continue;
							}
							TriggerEngine.Bind(type, new MethodTrigger
							{
								className = customAttribute.ClassName,
								methodName = customAttribute.MethodName,
								argTypes = customAttribute.Args
							});
						}
					}
					else if (((MemberInfo)type).GetCustomAttribute<HarmonyPatch>() != null)
					{
						val.PatchAll(type);
					}
				}
				catch (TypeLoadException)
				{
				}
				catch (Exception arg)
				{
					Logging.Error($"Failed to inspect {type}: {arg}", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Main.cs");
				}
			}
		}

		private void ApplySceneLocalization(Scene scene, LoadSceneMode mode, bool clearObjectCaches, bool sceneEntry)
		{
			//IL_0031: 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)
			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;
			}
			if (clearObjectCaches)
			{
				SceneObjects.ClearObjectCaches(scene, mode);
			}
			FontManager.RefreshFallback();
			GameObject inactiveRootObject = SceneObjects.GetInactiveRootObject("Canvas");
			AngrySceneTracker.ReadCurrentScene();
			Core.LocalizeScene(inactiveRootObject, sceneEntry);
			AudioSwapper.OnSceneLoaded(SceneObjects.GetCurrentSceneName());
			RunDeferred(((Scene)(ref scene)).handle);
		}

		private async void RunDeferred(int sceneHandle)
		{
			await Task.Delay(250);
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).handle == sceneHandle)
			{
				SubtitledAudioSourcesReplacer.ReplaceSubsAndAudio();
				TextureSwapper.Apply();
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			ApplySceneLocalization(scene, mode, clearObjectCaches: true, sceneEntry: true);
		}

		public void RefreshCurrentScene()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			ApplySceneLocalization(SceneManager.GetActiveScene(), (LoadSceneMode)0, clearObjectCaches: false, sceneEntry: false);
		}
	}
	public static class LanguageOptions
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__6_0;

			internal void <BuildLanguagePage>b__6_0()
			{
				Application.OpenURL(ConfigPaths.LanguagesDirectory);
			}
		}

		private const string PageName = "Language Page";

		private static TextMeshProUGUI navigationLabel;

		private static TextMeshProUGUI pageTitle;

		private static TextMeshProUGUI openFolderLabel;

		public static void Initialize(SettingsMenu settingsMenu)
		{
			Transform pageContainer = settingsMenu.pageContainer;
			if (!((Object)(object)pageContainer.Find("Language Page") != (Object)null))
			{
				Logging.Message("Adding language option to options menu...", addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Menus\\LanguageOptions.cs");
				Transform navigationRail = settingsMenu.navigationRail;
				GameObject gameObject = ((Component)navigationRail.Find("General")).gameObject;
				GameObject languagePage = BuildLanguagePage(((Component)settingsMenu).transform, pageContainer, gameObject);
				GameObject val = BuildButton(gameObject, navigationRail, "Language", LanguageManager.CurrentLanguage.options.language_title, null, resizeText: false);
				val.transform.SetSiblingIndex(7);
				navigationLabel = val.GetComponentInChildren<TextMeshProUGUI>();
				ConfigureNavigationButton(settingsMenu, languagePage, val);
				RefreshText();
			}
		}

		public static void RefreshText()
		{
			Option options = LanguageManager.CurrentLanguage.options;
			if ((Object)(object)navigationLabel != (Object)null)
			{
				((TMP_Text)navigationLabel).text = options.language_title;
			}
			if ((Object)(object)pageTitle != (Object)null)
			{
				((TMP_Text)pageTitle).text = "--" + options.language_languages + "--";
			}
			if ((Object)(object)openFolderLabel != (Object)null)
			{
				((TMP_Text)openFolderLabel).text = "<color=#03fc07>" + options.language_openLanguageFolder + "</color>";
			}
		}

		private static GameObject BuildLanguagePage(Transform optionsMenu, Transform pages, GameObject buttonTemplate)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_006e: 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_00c7: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Expected O, but got Unknown
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Expected O, but got Unknown
			Transform val = pages.Find("General");
			Transform val2 = val.Find("Scroll Rect");
			Transform val3 = val2.Find("Contents");
			GameObject val4 = new GameObject("Language Page", new Type[2]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer)
			});
			val4.transform.SetParent(pages, false);
			val4.GetComponent<RectTransform>().sizeDelta = new Vector2(600f, 800f);
			val4.SetActive(false);
			GameObject val5 = new GameObject("Scroll Rect", new Type[4]
			{
				typeof(RectTransform),
				typeof(ScrollRect),
				typeof(Image),
				typeof(Mask)
			});
			val5.transform.SetParent(val4.transform, false);
			CopyRect(((Component)val2).GetComponent<RectTransform>(), val5.GetComponent<RectTransform>());
			((Graphic)val5.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.5f);
			val5.GetComponent<Mask>().showMaskGraphic = false;
			ScrollRect component = val5.GetComponent<ScrollRect>();
			component.horizontal = false;
			component.vertical = true;
			component.verticalScrollbarVisibility = (ScrollbarVisibility)2;
			component.scrollSensitivity = 20f;
			GameObject val6 = new GameObject("Contents", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			val6.transform.SetParent(val5.transform, false);
			RectTransform component2 = val6.GetComponent<RectTransform>();
			CopyRect(((Component)val3).GetComponent<RectTransform>(), component2);
			VerticalLayoutGroup component3 = val6.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component3).spacing = 10f;
			((LayoutGroup)component3).childAlignment = (TextAnchor)1;
			((HorizontalOrVerticalLayoutGroup)component3).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)component3).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component3).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component3).childControlHeight = true;
			val6.GetComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			component.content = component2;
			Transform transform = val6.transform;
			Scrollbar val7 = Object.Instantiate<Scrollbar>(((Component)val).GetComponentsInChildren<Scrollbar>().First(), val4.transform);
			val7.direction = (Direction)2;
			component.verticalScrollbar = val7;
			GameObject val8 = Object.Instantiate<GameObject>(((Component)optionsMenu.Find("Text")).gameObject, transform);
			((Object)val8).name = "Title";
			pageTitle = val8.GetComponent<TextMeshProUGUI>();
			((TMP_Text)pageTitle).alignment = (TextAlignmentOptions)514;
			((TMP_Text)pageTitle).fontSize = 24f;
			((TMP_Text)pageTitle).rectTransform.sizeDelta = new Vector2(400f, 50f);
			foreach (KeyValuePair<string, Lang> allLanguage in LanguageManager.allLanguages)
			{
				string languageId = allLanguage.Key;
				BuildButton(buttonTemplate, transform, languageId, allLanguage.Value.DisplayName, (UnityAction)delegate
				{
					SelectLanguage(languageId);
				}, resizeText: true, (Vector2?)new Vector2(160f, 40f));
			}
			string empty = string.Empty;
			object obj = <>c.<>9__6_0;
			if (obj == null)
			{
				UnityAction val9 = delegate
				{
					Application.OpenURL(ConfigPaths.LanguagesDirectory);
				};
				<>c.<>9__6_0 = val9;
				obj = (object)val9;
			}
			openFolderLabel = BuildButton(buttonTemplate, transform, "openLangFolder", empty, (UnityAction)obj).GetComponentInChildren<TextMeshProUGUI>();
			return val4;
		}

		private static GameObject BuildButton(GameObject template, Transform parent, string name, string label, UnityAction onClick = null, bool resizeText = true, Vector2? size = null)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(template, parent);
			((Object)val).name = name;
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).localPosition = Vector3.zero;
			((Transform)component).localRotation = Quaternion.identity;
			((Transform)component).localScale = Vector3.one;
			if (size.HasValue)
			{
				component.sizeDelta = size.Value;
			}
			Button component2 = val.GetComponent<Button>();
			component2.onClick = new ButtonClickedEvent();
			if (onClick != null)
			{
				((UnityEvent)component2.onClick).AddListener(onClick);
			}
			((Selectable)component2).interactable = true;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)component2).navigation = navigation;
			TextMeshProUGUI componentInChildren = val.GetComponentInChildren<TextMeshProUGUI>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((TMP_Text)componentInChildren).text = label;
				((TMP_Text)componentInChildren).richText = true;
				((TMP_Text)componentInChildren).alignment = (TextAlignmentOptions)514;
				((TMP_Text)componentInChildren).enableAutoSizing = resizeText;
				if (resizeText)
				{
					((TMP_Text)componentInChildren).fontSizeMin = 10f;
					((TMP_Text)componentInChildren).fontSizeMax = 36f;
				}
			}
			val.SetActive(true);
			return val;
		}

		private static void SelectLanguage(string languageId)
		{
			Logging.Message("Selected language: " + languageId, addCallerFilePath: false, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Menus\\LanguageOptions.cs");
			LanguageManager.TrySwitchLanguage(languageId);
		}

		private static void ConfigureNavigationButton(SettingsMenu settingsMenu, GameObject languagePage, GameObject navigationButton)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			ButtonHighlightParent highlight = ((Component)settingsMenu.navigationRail).GetComponent<ButtonHighlightParent>();
			Button component = navigationButton.GetComponent<Button>();
			Image image = navigationButton.GetComponent<Image>();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				ButtonHighlightParent obj = highlight;
				if (obj != null)
				{
					obj.ChangeButton(image);
				}
				settingsMenu.SetActivePage(languagePage);
			});
			RegisterNavigationButton(highlight, image);
		}

		private static void RegisterNavigationButton(ButtonHighlightParent highlight, Image image)
		{
			if (highlight?.buttons != null && !highlight.buttons.Contains(image))
			{
				TMP_Text componentInChildren = ((Component)image).GetComponentInChildren<TMP_Text>();
				int num = highlight.buttons.Length;
				Array.Resize(ref highlight.buttons, num + 1);
				Array.Resize(ref highlight.buttonTexts, num + 1);
				Array.Resize(ref highlight.buttonSprites, num + 1);
				highlight.buttons[num] = image;
				highlight.buttonTexts[num] = componentInChildren;
				highlight.buttonSprites[num] = image.sprite;
			}
		}

		private static void CopyRect(RectTransform source, RectTransform target)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			target.anchorMin = source.anchorMin;
			target.anchorMax = source.anchorMax;
			target.pivot = source.pivot;
			target.anchoredPosition = source.anchoredPosition;
			target.sizeDelta = source.sizeDelta;
		}
	}
	public static class Settings
	{
		public static ConfigEntry<string> lastLanguage;

		public static ConfigEntry<bool> activeDubbing;

		public static ConfigFile configFile;

		public static void InitializeConfig()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			configFile = new ConfigFile(ConfigPaths.SettingsFile, true);
			lastLanguage = configFile.Bind<string>("General", "LastLanguage", "en-GB", (ConfigDescription)null);
			activeDubbing = configFile.Bind<bool>("General", "activeDubbing", false, (ConfigDescription)null);
		}
	}
	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 Dictionary<Texture2D, AtlasState> atlases = new Dictionary<Texture2D, AtlasState>();

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

		private static int optimizerId;

		private static bool resolving;

		internal static void Capture(StaticSceneOptimizer optimizer)
		{
			ReleaseAtlases();
			pendingTemplates.Clear();
			TextureSwapper.RestoreMutatedTextures();
			optimizerId = (((Object)(object)optimizer != (Object)null) ? ((Object)optimizer).GetInstanceID() : 0);
			if ((Object)(object)optimizer == (Object)null || LanguageManager.IsEnglish)
			{
				return;
			}
			HashSet<Texture2D> seenBefore = 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\\Core\\Textures\\AtlasBatchSwapper.cs");
			void CaptureMaterial(Material material)
			{
				foreach (var mainTexture in GetMainTextures(material))
				{
					Texture2D item = mainTexture.Texture;
					Texture2D originalTexture = TextureSwapper.GetOriginalTexture(item);
					Texture2D val = (((Object)(object)originalTexture != (Object)null) ? originalTexture : item);
					string text = (((Object)(object)originalTexture != (Object)null) ? ((Object)originalTexture).name : ((Object)item).name);
					if (seenBefore.Add(item) && TextureSwapper.TryGetFile(text, out var _))
					{
						Color32[] array = ReadPixels((Texture)(object)val);
						if (array == null)
						{
							WarnOnce($"template-read:{((Object)item).GetInstanceID()}", "Cannot read source template " + $"'{text}' ({((Texture)val).width}x{((Texture)val).height}).");
						}
						else
						{
							pendingTemplates.Add(new Template(text, ((Texture)val).width, ((Texture)val).height, array));
						}
					}
				}
			}
			void CaptureRenderer(MeshRenderer renderer)
			{
				if (!((Object)(object)renderer == (Object)null))
				{
					Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials;
					foreach (Material material in sharedMaterials)
					{
						CaptureMaterial(material);
					}
				}
			}
		}

		private static void ReleaseAtlases()
		{
			foreach (AtlasState value in atlases.Values)
			{
				if ((Object)(object)value.texture != (Object)null && value.originalPixels.Length == ((Texture)value.texture).width * ((Texture)value.texture).height)
				{
					value.texture.SetPixels32(value.originalPixels);
					value.texture.Apply(false, false);
				}
			}
			atlases.Clear();
		}

		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> sceneAtlases = GetOrCreateAtlases(optimizer);
			if (sceneAtlases.Count == 0)
			{
				WarnOnce($"missing-atlas:{optimizerId}", "Optimizer finished, but no runtime Texture2D was found on its batch materials.");
				resolving = false;
				yield break;
			}
			Template[] pending = pendingTemplates.ToArray();
			HashSet<string> found = new HashSet<string>();
			foreach (AtlasState sceneAtlas in sceneAtlases)
			{
				Color32[] source = sceneAtlas.originalPixels;
				int sourceWidth = ((Texture)sceneAtlas.texture).width;
				int sourceHeight = ((Texture)sceneAtlas.texture).height;
				Task<List<(Template Template, RectInt Rect)>> task = Task.Run(() => FindRegions(source, sourceWidth, sourceHeight, pending));
				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\\Core\\Textures\\AtlasBatchSwapper.cs");
					continue;
				}
				foreach (var result in task.Result)
				{
					RectInt item = result.Rect;
					if (((RectInt)(ref item)).width > 0)
					{
						sceneAtlas.Regions.Add((result.Template.Name, result.Rect));
						found.Add(result.Template.Name);
						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\\Core\\Textures\\AtlasBatchSwapper.cs");
					}
				}
			}
			Template[] array = pending;
			for (int num = 0; num < array.Length; num++)
			{
				Template template = array[num];
				if (!found.Contains(template.Name))
				{
					WarnOnce($"not-found:{optimizerId}:{template.Name}", "'" + template.Name + "' was not found in " + $"{sceneAtlases.Count} runtime atlas(es).");
				}
			}
			pendingTemplates.Clear();
			resolving = false;
			Apply();
		}

		internal static void Apply()
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00f1: 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_0183: 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_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (AtlasState value in atlases.Values)
			{
				if ((Object)(object)value.texture == (Object)null || value.originalPixels.Length != ((Texture)value.texture).width * ((Texture)value.texture).height)
				{
					continue;
				}
				value.texture.SetPixels32(value.originalPixels);
				if (LanguageManager.IsEnglish)
				{
					value.texture.Apply(false, false);
					continue;
				}
				foreach (var region in value.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)
						{
							try
							{
								Color32[] array = DecodePixels(file.Bytes);
								if (array != null)
								{
									Texture2D texture = value.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, array);
									num++;
								}
							}
							catch (Exception ex)
							{
								WarnOnce("apply:" + region.Name + ":" + file.Path, "Failed to apply '" + file.Path + "': " + ex.Message);
							}
							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));
				}
				value.texture.Apply(false, false);
			}
			if (num > 0)
			{
				Logging.Message($"Applied {num} cached region(s) to " + $"{atlases.Count} atlas(es) without rescanning.", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Core\\Textures\\AtlasBatchSwapper.cs");
			}
		}

		private static List<AtlasState> GetOrCreateAtlases(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))
					{
						continue;
					}
					if (atlases.TryGetValue(mainTexture.Texture, out var value))
					{
						list.Add(value);
						continue;
					}
					Color32[] array3 = ReadPixels((Texture)(object)mainTexture.Texture);
					if (array3 != null)
					{
						AtlasState atlasState = new AtlasState(mainTexture.Texture, array3);
						atlases[mainTexture.Texture] = atlasState;
						list.Add(atlasState);
						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\\Core\\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[] DecodePixels(byte[] png)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			try
			{
				return ImageConversion.LoadImage(val, png, false) ? val.GetPixels32() : null;
			}
			catch (Exception)
			{
				return null;
			}
			finally
			{
				Object.Destroy((Object)(object)val);
			}
		}

		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\\Core\\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);
		}

		internal static Texture2D GetOriginalTexture(Texture2D current)
		{
			Texture original = textureReplacementCache.GetOriginal((Texture)(object)current);
			Texture2D val = (Texture2D)(object)((original is Texture2D) ? original : null);
			return ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)current) ? val : null;
		}

		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\\Core\\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\\Core\\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\\Core\\Textures\\Swapper\\TextureSwapper.cs");
				}
			}
			catch (Exception arg)
			{
				Logging.Error($"Scan failed: {arg}", addCallerFilePath: true, "H:\\C#Project\\UltrakULL-1\\src\\Core\\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\\Core\\Textures\\Swapper\\TextureSwapper.cs");
			}
		}

		private static void LoadFiles(Lang language)
		{
			RestoreMutatedTextures();
			QueueGeneratedAssetsForCleanup();
			files.Clear();
			diagnostics.Clear();
			if (language == null || languag