Decompiled source of GWYF Russian Translation v1.1.0

BepInEx/plugins/RTLC.GWYF/RTLC.GWYF.Text.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RTLC.GWYF.TextRuntime;

[BepInPlugin("rtlc.gwyf.text", "RTLC.GWYF Text Runtime", "0.3.0")]
public sealed class Plugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		LogRtlcBanner(((BaseUnityPlugin)this).Logger);
		RuntimeTranslator.Load(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), ((BaseUnityPlugin)this).Logger, force: true);
		_harmony = new Harmony("dimalooper.gwyf.russianruntime");
		_harmony.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Runtime text hooks installed.");
	}

	private static void LogRtlcBanner(ManualLogSource logger)
	{
		logger.LogInfo((object)"");
		logger.LogInfo((object)"RRRRR  TTTTT  L      CCCCC");
		logger.LogInfo((object)"R   R    T    L     C     ");
		logger.LogInfo((object)"RRRRR    T    L     C     ");
		logger.LogInfo((object)"R  R     T    L     C     ");
		logger.LogInfo((object)"R   R    T    LLLLL  CCCCC");
		logger.LogInfo((object)"RTLC.GWYF runtime localization pack");
		logger.LogInfo((object)"© Плагин является интеллектуальной собственностью RTLC Team. Любое копирование, изменение и распространение материалов без письменного разрешения запрещено. Все права защищены.");
		logger.LogInfo((object)"");
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal static class RuntimeTranslator
{
	private sealed class RegexEntry
	{
		public Regex Regex;

		public string Replacement;
	}

	private static readonly Dictionary<string, string> Exact = new Dictionary<string, string>(StringComparer.Ordinal);

	private static readonly Dictionary<string, string> LoadingQuoteTranslations = new Dictionary<string, string>(StringComparer.Ordinal);

	private static readonly List<RegexEntry> Regexes = new List<RegexEntry>();

	private static string _loadedPath;

	private static DateTime _loadedWriteTimeUtc;

	public static bool Load(string pluginDirectory, ManualLogSource log, bool force)
	{
		string text = ResolveTranslationPath(pluginDirectory);
		if (text == null)
		{
			if (force)
			{
				log.LogWarning((object)"Translate.txt was not found in BepInEx/config/Translation/ru/Text or fallback paths.");
			}
			return false;
		}
		DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(text);
		if (!force && string.Equals(_loadedPath, text, StringComparison.OrdinalIgnoreCase) && lastWriteTimeUtc == _loadedWriteTimeUtc)
		{
			return false;
		}
		Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
		Dictionary<string, string> dictionary2 = new Dictionary<string, string>(StringComparer.Ordinal);
		List<RegexEntry> list = new List<RegexEntry>();
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		string[] array = File.ReadAllLines(text, Encoding.UTF8);
		for (int i = 0; i < array.Length; i++)
		{
			string text2 = array[i];
			if (string.IsNullOrWhiteSpace(text2))
			{
				continue;
			}
			string text3 = text2.TrimStart(new char[0]);
			if (text3.StartsWith("#", StringComparison.Ordinal) || text3.StartsWith("//", StringComparison.Ordinal))
			{
				continue;
			}
			int num4 = FindDelimiter(text2);
			if (num4 <= 0)
			{
				continue;
			}
			string text4 = text2.Substring(0, num4);
			string text5 = text2.Substring(num4 + 1);
			if (text4.StartsWith("r:\"", StringComparison.Ordinal) && text4.EndsWith("\"", StringComparison.Ordinal) && text4.Length >= 4)
			{
				string pattern = text4.Substring(3, text4.Length - 4).Replace("\\=", "=");
				try
				{
					list.Add(new RegexEntry
					{
						Regex = new Regex(pattern, RegexOptions.CultureInvariant),
						Replacement = UnescapeText(text5)
					});
					num2++;
				}
				catch (Exception ex)
				{
					log.LogWarning((object)("Bad regex translation at line " + (i + 1) + ": " + ex.Message));
				}
			}
			else
			{
				string key = UnescapeDelimiterEscapes(text4);
				string text6 = UnescapeText(text4);
				string translation = UnescapeDelimiterEscapes(text5);
				string translation2 = UnescapeText(text5);
				AddExactTranslation(dictionary, dictionary2, key, translation);
				AddExactTranslation(dictionary, dictionary2, text6, translation2);
				if (IsLoadingQuoteKey(text6))
				{
					num3++;
				}
				num++;
			}
		}
		Exact.Clear();
		LoadingQuoteTranslations.Clear();
		foreach (KeyValuePair<string, string> item in dictionary)
		{
			Exact[item.Key] = item.Value;
		}
		foreach (KeyValuePair<string, string> item2 in dictionary2)
		{
			LoadingQuoteTranslations[item2.Key] = item2.Value;
		}
		Regexes.Clear();
		Regexes.AddRange(list);
		_loadedPath = text;
		_loadedWriteTimeUtc = lastWriteTimeUtc;
		log.LogInfo((object)("Loaded runtime translations: exact=" + num + ", regex=" + num2 + ", loadingQuotes=" + num3 + " from " + text));
		return true;
	}

	private static string ResolveTranslationPath(string pluginDirectory)
	{
		string gameRootPath = Paths.GameRootPath;
		string[] array = new string[4]
		{
			Path.Combine(Paths.ConfigPath, "Translation", "ru", "Text", "Translate.txt"),
			Path.Combine(gameRootPath, "BepInEx", "config", "Translation", "ru", "Text", "Translate.txt"),
			Path.Combine(gameRootPath, "BepInEx", "Translation", "ru", "Text", "Translate.txt"),
			Path.Combine(pluginDirectory ?? string.Empty, "Translate.txt")
		};
		for (int i = 0; i < array.Length; i++)
		{
			if (File.Exists(array[i]))
			{
				return array[i];
			}
		}
		return null;
	}

	public static string Translate(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return text;
		}
		if (TryLookupExact(text, out var value))
		{
			return value;
		}
		for (int i = 0; i < Regexes.Count; i++)
		{
			RegexEntry regexEntry = Regexes[i];
			if (regexEntry.Regex.IsMatch(text))
			{
				return regexEntry.Regex.Replace(text, regexEntry.Replacement);
			}
		}
		return text;
	}

	public static string TranslateLoadingQuote(string text)
	{
		string text2 = Translate(text);
		if (!string.Equals(text2, text, StringComparison.Ordinal))
		{
			return text2;
		}
		if (TryLookupRawTranslation(text, out var value, out var lineNumber))
		{
			Exact[text] = value;
			if (IsLoadingQuoteKey(text))
			{
				LoadingQuoteTranslations[text] = value;
			}
			Plugin.Log.LogInfo((object)("Recovered loading quote translation from Translate.txt line " + lineNumber + "."));
			return value;
		}
		return text;
	}

	public static string TranslatePreserveOuterWhitespace(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return text;
		}
		int i;
		for (i = 0; i < text.Length && char.IsWhiteSpace(text[i]); i++)
		{
		}
		int num = text.Length - 1;
		while (num >= i && char.IsWhiteSpace(text[num]))
		{
			num--;
		}
		if (i == 0 && num == text.Length - 1)
		{
			return Translate(text);
		}
		if (num < i)
		{
			return text;
		}
		string text2 = text.Substring(i, num - i + 1);
		if (TryLookupExact(text2, out var value))
		{
			return text.Substring(0, i) + value + text.Substring(num + 1);
		}
		for (int j = 0; j < Regexes.Count; j++)
		{
			RegexEntry regexEntry = Regexes[j];
			if (regexEntry.Regex.IsMatch(text2))
			{
				return text.Substring(0, i) + regexEntry.Regex.Replace(text2, regexEntry.Replacement) + text.Substring(num + 1);
			}
		}
		return text;
	}

	private static bool TryLookupExact(string text, out string value)
	{
		if (Exact.TryGetValue(text, out value))
		{
			return true;
		}
		if (LoadingQuoteTranslations.TryGetValue(text, out value))
		{
			return true;
		}
		if (text.IndexOf('\r') >= 0)
		{
			string text2 = text.Replace("\r\n", "\n").Replace("\r", "\n");
			if (!string.Equals(text2, text, StringComparison.Ordinal) && Exact.TryGetValue(text2, out value))
			{
				return true;
			}
			if (!string.Equals(text2, text, StringComparison.Ordinal) && LoadingQuoteTranslations.TryGetValue(text2, out value))
			{
				return true;
			}
		}
		value = null;
		return false;
	}

	private static bool TryLookupRawTranslation(string text, out string value, out int lineNumber)
	{
		value = null;
		lineNumber = 0;
		if (string.IsNullOrEmpty(_loadedPath) || !File.Exists(_loadedPath))
		{
			return false;
		}
		string[] array = File.ReadAllLines(_loadedPath, Encoding.UTF8);
		for (int i = 0; i < array.Length; i++)
		{
			string text2 = array[i];
			if (string.IsNullOrWhiteSpace(text2))
			{
				continue;
			}
			string text3 = text2.TrimStart(new char[0]);
			if (text3.StartsWith("#", StringComparison.Ordinal) || text3.StartsWith("//", StringComparison.Ordinal))
			{
				continue;
			}
			int num = FindDelimiter(text2);
			if (num <= 0)
			{
				continue;
			}
			string text4 = text2.Substring(0, num);
			if (!text4.StartsWith("r:\"", StringComparison.Ordinal) || !text4.EndsWith("\"", StringComparison.Ordinal) || text4.Length < 4)
			{
				string a = UnescapeDelimiterEscapes(text4);
				string a2 = UnescapeText(text4);
				if (string.Equals(a, text, StringComparison.Ordinal))
				{
					value = UnescapeDelimiterEscapes(text2.Substring(num + 1));
					lineNumber = i + 1;
					return true;
				}
				if (string.Equals(a2, text, StringComparison.Ordinal))
				{
					value = UnescapeText(text2.Substring(num + 1));
					lineNumber = i + 1;
					return true;
				}
			}
		}
		return false;
	}

	private static bool IsLoadingQuoteKey(string text)
	{
		if (text.IndexOf("\n\n-", StringComparison.Ordinal) < 0)
		{
			return text.IndexOf("\\n\\n-", StringComparison.Ordinal) >= 0;
		}
		return true;
	}

	private static void AddExactTranslation(Dictionary<string, string> exact, Dictionary<string, string> loadingQuoteTranslations, string key, string translation)
	{
		exact[key] = translation;
		if (IsLoadingQuoteKey(key))
		{
			loadingQuoteTranslations[key] = translation;
		}
	}

	private static int FindDelimiter(string line)
	{
		for (int i = 0; i < line.Length; i++)
		{
			if (line[i] == '=' && (i == 0 || line[i - 1] != '\\'))
			{
				return i;
			}
		}
		return -1;
	}

	private static string UnescapeText(string text)
	{
		if (text.IndexOf('\\') < 0)
		{
			return text;
		}
		return text.Replace("\\r", "\r").Replace("\\n", "\n").Replace("\\t", "\t")
			.Replace("\\=", "=");
	}

	private static string UnescapeDelimiterEscapes(string text)
	{
		return text.Replace("\\=", "=");
	}
}
internal static class RuntimeTextTracker
{
	private sealed class TrackedText
	{
		public WeakReference Target;

		public string Original;
	}

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

	public static void Apply(TMP_Text target, string original)
	{
		if (!((Object)(object)target == (Object)null) && !string.IsNullOrEmpty(original))
		{
			string text = RuntimeTranslator.Translate(original);
			if (!string.Equals(text, original, StringComparison.Ordinal))
			{
				target.text = text;
				Track(target, original);
			}
		}
	}

	public static void ApplyAlways(TMP_Text target, string original)
	{
		if (!((Object)(object)target == (Object)null) && !string.IsNullOrEmpty(original))
		{
			target.text = RuntimeTranslator.Translate(original);
			Track(target, original);
		}
	}

	public static void TrackOriginal(TMP_Text target, string original)
	{
		if (!((Object)(object)target == (Object)null) && !string.IsNullOrEmpty(original))
		{
			Track(target, original);
		}
	}

	public static void RefreshTrackedTexts()
	{
		List<int> list = null;
		foreach (KeyValuePair<int, TrackedText> item in Tracked)
		{
			object? target = item.Value.Target.Target;
			TMP_Text val = (TMP_Text)((target is TMP_Text) ? target : null);
			if ((Object)(object)val == (Object)null)
			{
				if (list == null)
				{
					list = new List<int>();
				}
				list.Add(item.Key);
			}
			else
			{
				string text = RuntimeTranslator.Translate(item.Value.Original);
				if (!string.Equals(val.text, text, StringComparison.Ordinal))
				{
					val.text = text;
				}
			}
		}
		if (list != null)
		{
			for (int i = 0; i < list.Count; i++)
			{
				Tracked.Remove(list[i]);
			}
		}
	}

	public static void ScanVisibleTexts()
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		TMP_Text[] array = Resources.FindObjectsOfTypeAll<TMP_Text>();
		foreach (TMP_Text val in array)
		{
			if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled || (Object)(object)((Component)val).gameObject == (Object)null)
			{
				continue;
			}
			Scene scene = ((Component)val).gameObject.scene;
			if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
			{
				int instanceID = ((Object)val).GetInstanceID();
				if (!Tracked.ContainsKey(instanceID))
				{
					Apply(val, val.text);
				}
			}
		}
	}

	private static void Track(TMP_Text target, string original)
	{
		int instanceID = ((Object)target).GetInstanceID();
		Tracked[instanceID] = new TrackedText
		{
			Target = new WeakReference(target),
			Original = original
		};
	}
}
internal static class ReflectionCache
{
	public static readonly FieldInfo InteractionItemNameText = AccessTools.Field(typeof(InteractionUIPanel), "itemNameText");

	public static readonly FieldInfo LoadingQuoteTargetText = AccessTools.Field(typeof(LoadingQuotes), "targetText");

	public static readonly FieldInfo LoadingQuoteQuotes = AccessTools.Field(typeof(LoadingQuotes), "quotes");

	public static readonly FieldInfo ChallengeNameText = AccessTools.Field(typeof(ChallengeEntryUI), "challengeNameText");

	public static readonly FieldInfo ChallengeProgressText = AccessTools.Field(typeof(ChallengeEntryUI), "progressText");

	public static readonly FieldInfo RerollCostText = AccessTools.Field(typeof(RerollButton), "rerollCostText");

	public static readonly FieldInfo PhoneBoothScreenText = AccessTools.Field(typeof(PhoneBooth), "screenText");
}
[HarmonyPatch(typeof(LoadingQuotes), "ShowRandomQuote")]
internal static class LoadingQuotes_ShowRandomQuote_Patch
{
	private static readonly HashSet<string> MissingQuotesLogged = new HashSet<string>(StringComparer.Ordinal);

	private static bool Prefix(LoadingQuotes __instance)
	{
		object? value = ReflectionCache.LoadingQuoteTargetText.GetValue(__instance);
		TMP_Text val = (TMP_Text)((value is TMP_Text) ? value : null);
		string[] array = ReflectionCache.LoadingQuoteQuotes.GetValue(__instance) as string[];
		if ((Object)(object)val == (Object)null || array == null || array.Length == 0)
		{
			return true;
		}
		string text = array[Random.Range(0, array.Length)];
		string text2 = RuntimeTranslator.TranslateLoadingQuote(text);
		if (string.Equals(text2, text, StringComparison.Ordinal) && MissingQuotesLogged.Add(text))
		{
			Plugin.Log.LogWarning((object)("Untranslated loading quote key: len=" + text.Length + ", text=" + EscapeForLog(text) + ", chars=" + GetCharCodes(text)));
		}
		val.text = text2;
		RuntimeTextTracker.TrackOriginal(val, text);
		return false;
	}

	private static string EscapeForLog(string text)
	{
		return text.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t");
	}

	private static string GetCharCodes(string text)
	{
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < text.Length; i++)
		{
			if (i > 0)
			{
				stringBuilder.Append(',');
			}
			stringBuilder.Append((int)text[i]);
		}
		return stringBuilder.ToString();
	}
}
[HarmonyPatch(typeof(InteractionUIPanel), "SetItemNameText")]
internal static class InteractionUIPanel_SetItemNameText_Patch
{
	private static void Postfix(InteractionUIPanel __instance, string itemName)
	{
		object? value = ReflectionCache.InteractionItemNameText.GetValue(__instance);
		TMP_Text val = (TMP_Text)((value is TMP_Text) ? value : null);
		if ((Object)(object)val != (Object)null)
		{
			RuntimeTextTracker.Apply(val, itemName);
		}
	}
}
[HarmonyPatch(typeof(InteractableBase), "get_InteractableName")]
internal static class InteractableBase_GetInteractableName_Patch
{
	private static void Postfix(ref string __result)
	{
		__result = RuntimeTranslator.Translate(__result);
	}
}
[HarmonyPatch(typeof(InteractableBase), "get_TooltipMessage")]
internal static class InteractableBase_GetTooltipMessage_Patch
{
	private static void Postfix(ref string __result)
	{
		__result = RuntimeTranslator.Translate(__result);
	}
}
[HarmonyPatch(typeof(KeyButtonManager), "CreateTextElement")]
internal static class KeyButtonManager_CreateTextElement_Patch
{
	private static void Prefix(ref string text)
	{
		text = RuntimeTranslator.TranslatePreserveOuterWhitespace(text);
	}
}
[HarmonyPatch(typeof(ItemDescriptionSettings), "GetDescription")]
internal static class ItemDescriptionSettings_GetDescription_Patch
{
	private static void Postfix(ref string __result)
	{
		__result = RuntimeTranslator.Translate(__result);
	}
}
[HarmonyPatch(typeof(ItemDescriptionDisplayManager), "UpdateDescriptionText")]
internal static class ItemDescriptionDisplayManager_UpdateDescriptionText_Patch
{
	private static void Postfix(GameObject canvas)
	{
		if (!((Object)(object)canvas == (Object)null))
		{
			TMP_Text componentInChildren = canvas.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				RuntimeTextTracker.Apply(componentInChildren, componentInChildren.text);
			}
		}
	}
}
[HarmonyPatch(typeof(Challenge), "GetProcessedDescription")]
internal static class Challenge_GetProcessedDescription_Patch
{
	private static void Postfix(ref string __result)
	{
		__result = RuntimeTranslator.Translate(__result);
	}
}
[HarmonyPatch(typeof(Challenge), "GetProgressText")]
internal static class Challenge_GetProgressText_Patch
{
	private static void Postfix(ref string __result)
	{
		__result = RuntimeTranslator.Translate(__result);
	}
}
[HarmonyPatch(typeof(ChallengeEntryUI), "SetData")]
internal static class ChallengeEntryUI_SetData_Patch
{
	private static void Postfix(ChallengeEntryUI __instance)
	{
		object? value = ReflectionCache.ChallengeNameText.GetValue(__instance);
		TMP_Text val = (TMP_Text)((value is TMP_Text) ? value : null);
		if ((Object)(object)val != (Object)null)
		{
			RuntimeTextTracker.Apply(val, val.text);
		}
		object? value2 = ReflectionCache.ChallengeProgressText.GetValue(__instance);
		TMP_Text val2 = (TMP_Text)((value2 is TMP_Text) ? value2 : null);
		if ((Object)(object)val2 != (Object)null)
		{
			RuntimeTextTracker.Apply(val2, val2.text);
		}
	}
}
[HarmonyPatch(typeof(RerollButton), "OnRerollCostChanged")]
internal static class RerollButton_OnRerollCostChanged_Patch
{
	private static void Postfix(RerollButton __instance)
	{
		object? value = ReflectionCache.RerollCostText.GetValue(__instance);
		TMP_Text val = (TMP_Text)((value is TMP_Text) ? value : null);
		if ((Object)(object)val != (Object)null)
		{
			RuntimeTextTracker.Apply(val, val.text);
		}
	}
}
[HarmonyPatch(typeof(PhoneBooth), "UserCode_RpcOnRerollActive")]
internal static class PhoneBooth_UserCode_RpcOnRerollActive_Patch
{
	private static void Postfix(PhoneBooth __instance)
	{
		object? value = ReflectionCache.PhoneBoothScreenText.GetValue(__instance);
		TMP_Text val = (TMP_Text)((value is TMP_Text) ? value : null);
		if ((Object)(object)val != (Object)null)
		{
			RuntimeTextTracker.Apply(val, val.text);
		}
	}
}

BepInEx/plugins/RTLC.GWYF/RTLC.GWYF.Texture.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RTLC.GWYF.TextureRuntime;

[BepInPlugin("rtlc.gwyf.texture", "RTLC.GWYF Texture Runtime", "0.3.0")]
public sealed class Plugin : BaseUnityPlugin
{
	private sealed class Replacement
	{
		public string Name;

		public string Path;

		public Texture2D Texture;

		public readonly HashSet<int> PatchedTextures = new HashSet<int>();

		public readonly Dictionary<int, Sprite> SpriteCache = new Dictionary<int, Sprite>();
	}

	private readonly Dictionary<string, Replacement> _replacements = new Dictionary<string, Replacement>(StringComparer.OrdinalIgnoreCase);

	private ManualLogSource _log;

	private bool _loaded;

	private void Awake()
	{
		_log = ((BaseUnityPlugin)this).Logger;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"RTLC.GWYF texture module loaded. © RTLC Team. Все права защищены.");
		SceneManager.sceneLoaded += OnSceneLoaded;
		((MonoBehaviour)this).StartCoroutine(LoadReplacementsAndApply());
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		if (_loaded)
		{
			((MonoBehaviour)this).StartCoroutine(ApplyDelayed("scene " + ((Scene)(ref scene)).name));
		}
	}

	private IEnumerator LoadReplacementsAndApply()
	{
		string pluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		string textureDirectory = Path.Combine(pluginDirectory ?? string.Empty, "Textures");
		if (!Directory.Exists(textureDirectory))
		{
			_log.LogWarning((object)("Texture directory does not exist: " + textureDirectory));
			yield break;
		}
		string[] files = Directory.GetFiles(textureDirectory, "*.png", SearchOption.TopDirectoryOnly);
		for (int i = 0; i < files.Length; i++)
		{
			yield return LoadReplacement(files[i]);
		}
		_loaded = true;
		if (_replacements.Count == 0)
		{
			_log.LogWarning((object)"No replacement PNG files found.");
			yield break;
		}
		_log.LogInfo((object)("Texture replacement hooks installed. Replacement count: " + _replacements.Count));
		yield return ApplyDelayed("startup");
	}

	private IEnumerator LoadReplacement(string path)
	{
		string uri = new Uri(Path.GetFullPath(path)).AbsoluteUri;
		UnityWebRequest request = UnityWebRequestTexture.GetTexture(uri, false);
		yield return request.SendWebRequest();
		if ((int)request.result != 1)
		{
			_log.LogWarning((object)("Failed to load replacement PNG: " + path + " - " + request.error));
			request.Dispose();
			yield break;
		}
		Texture2D texture = DownloadHandlerTexture.GetContent(request);
		request.Dispose();
		if ((Object)(object)texture == (Object)null)
		{
			_log.LogWarning((object)("Loaded replacement PNG returned null texture: " + path));
			yield break;
		}
		string name = Path.GetFileNameWithoutExtension(path);
		((Object)texture).name = name + "_RU";
		((Texture)texture).wrapMode = (TextureWrapMode)1;
		((Texture)texture).filterMode = (FilterMode)1;
		_replacements[name] = new Replacement
		{
			Name = name,
			Path = path,
			Texture = texture
		};
		_log.LogInfo((object)("Loaded replacement texture: " + name + " (" + ((Texture)texture).width + "x" + ((Texture)texture).height + ") from " + path));
	}

	private IEnumerator ApplyDelayed(string reason)
	{
		ApplyReplacements(reason + " immediate");
		yield return (object)new WaitForSecondsRealtime(0.25f);
		ApplyReplacements(reason + " +0.25s");
		yield return (object)new WaitForSecondsRealtime(1f);
		ApplyReplacements(reason + " +1.25s");
	}

	private void ApplyReplacements(string reason)
	{
		int num = PatchLoadedTextures();
		int num2 = PatchImages();
		int num3 = PatchSpriteRenderers();
		int num4 = PatchMaterials();
		if (num > 0 || num2 > 0 || num3 > 0 || num4 > 0)
		{
			_log.LogInfo((object)("Applied texture replacements (" + reason + "): textures=" + num + ", images=" + num2 + ", spriteRenderers=" + num3 + ", materials=" + num4));
		}
	}

	private int PatchLoadedTextures()
	{
		int num = 0;
		Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>();
		foreach (Texture2D val in array)
		{
			if ((Object)(object)val == (Object)null || !_replacements.TryGetValue(((Object)val).name, out var value))
			{
				continue;
			}
			int instanceID = ((Object)val).GetInstanceID();
			if (!value.PatchedTextures.Contains(instanceID) && !object.ReferenceEquals(val, value.Texture) && ((Texture)val).width == ((Texture)value.Texture).width && ((Texture)val).height == ((Texture)value.Texture).height)
			{
				try
				{
					Graphics.CopyTexture((Texture)(object)value.Texture, (Texture)(object)val);
					value.PatchedTextures.Add(instanceID);
					num++;
				}
				catch (Exception ex)
				{
					value.PatchedTextures.Add(instanceID);
					_log.LogWarning((object)("Could not copy replacement into Texture2D " + ((Object)val).name + "; will rely on sprite/material patching. " + ex.Message));
				}
			}
		}
		return num;
	}

	private int PatchImages()
	{
		int num = 0;
		Image[] array = Resources.FindObjectsOfTypeAll<Image>();
		foreach (Image val in array)
		{
			if ((Object)(object)val == (Object)null || (Object)(object)val.sprite == (Object)null)
			{
				continue;
			}
			Replacement replacement = FindReplacementForSprite(val.sprite);
			if (replacement != null)
			{
				Sprite replacementSprite = GetReplacementSprite(replacement, val.sprite);
				if (!((Object)(object)replacementSprite == (Object)null) && !object.ReferenceEquals(val.sprite, replacementSprite))
				{
					val.sprite = replacementSprite;
					((Graphic)val).SetAllDirty();
					num++;
				}
			}
		}
		return num;
	}

	private int PatchSpriteRenderers()
	{
		int num = 0;
		SpriteRenderer[] array = Resources.FindObjectsOfTypeAll<SpriteRenderer>();
		foreach (SpriteRenderer val in array)
		{
			if ((Object)(object)val == (Object)null || (Object)(object)val.sprite == (Object)null)
			{
				continue;
			}
			Replacement replacement = FindReplacementForSprite(val.sprite);
			if (replacement != null)
			{
				Sprite replacementSprite = GetReplacementSprite(replacement, val.sprite);
				if (!((Object)(object)replacementSprite == (Object)null) && !object.ReferenceEquals(val.sprite, replacementSprite))
				{
					val.sprite = replacementSprite;
					num++;
				}
			}
		}
		return num;
	}

	private int PatchMaterials()
	{
		int num = 0;
		Renderer[] array = Resources.FindObjectsOfTypeAll<Renderer>();
		foreach (Renderer val in array)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			Material[] sharedMaterials = val.sharedMaterials;
			if (sharedMaterials == null)
			{
				continue;
			}
			foreach (Material val2 in sharedMaterials)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.mainTexture == (Object)null) && _replacements.TryGetValue(((Object)val2.mainTexture).name, out var value))
				{
					val2.mainTexture = (Texture)(object)value.Texture;
					num++;
				}
			}
		}
		return num;
	}

	private Replacement FindReplacementForSprite(Sprite sprite)
	{
		if (_replacements.TryGetValue(((Object)sprite).name, out var value))
		{
			return value;
		}
		Texture2D texture = sprite.texture;
		if ((Object)(object)texture != (Object)null && _replacements.TryGetValue(((Object)texture).name, out value))
		{
			return value;
		}
		return null;
	}

	private Sprite GetReplacementSprite(Replacement replacement, Sprite source)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: 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)
		int instanceID = ((Object)source).GetInstanceID();
		if (replacement.SpriteCache.TryGetValue(instanceID, out var value))
		{
			return value;
		}
		Rect rect = source.rect;
		if (((Rect)(ref rect)).xMax > (float)((Texture)replacement.Texture).width || ((Rect)(ref rect)).yMax > (float)((Texture)replacement.Texture).height)
		{
			((Rect)(ref rect))..ctor(0f, 0f, (float)((Texture)replacement.Texture).width, (float)((Texture)replacement.Texture).height);
		}
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(0.5f, 0.5f);
		Rect rect2 = source.rect;
		if (((Rect)(ref rect2)).width > 0f)
		{
			Rect rect3 = source.rect;
			if (((Rect)(ref rect3)).height > 0f)
			{
				float x = source.pivot.x;
				Rect rect4 = source.rect;
				float num = x / ((Rect)(ref rect4)).width;
				float y = source.pivot.y;
				Rect rect5 = source.rect;
				((Vector2)(ref val))..ctor(num, y / ((Rect)(ref rect5)).height);
			}
		}
		Sprite val2 = Sprite.Create(replacement.Texture, rect, val, source.pixelsPerUnit, 0u, (SpriteMeshType)0, source.border);
		((Object)val2).name = replacement.Name;
		replacement.SpriteCache[instanceID] = val2;
		return val2;
	}
}