Decompiled source of LC Chinese Project v3.3.2

BepInEx/plugins/V81TestChn/V81TestChn.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dissonance;
using Dissonance.Audio.Capture;
using Dissonance.Networking;
using Dissonance.VAD;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NAudio.Wave;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Steamworks;
using Steamworks.Data;
using TMPro;
using Unity.Netcode;
using Unity.Profiling;
using Unity.Profiling.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.UI;
using UnityEngine.Video;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("V81TestChn")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("3.3.2.0")]
[assembly: AssemblyInformationalVersion("3.3.2+fa69832bb5c280f46ca9ea20e4b92c3f12f7c3be")]
[assembly: AssemblyProduct("V81TestChn")]
[assembly: AssemblyTitle("V81TestChn")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.3.2.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;
		}
	}
}
namespace V81TestChn
{
	internal static class AlertTextureReplacementService
	{
		private enum NativeTextRole
		{
			None,
			SystemOnline,
			EnteringAtmosphere
		}

		private readonly struct CachedNativeTextRole
		{
			public int ParentId { get; }

			public NativeTextRole Role { get; }

			public CachedNativeTextRole(int parentId, NativeTextRole role)
			{
				ParentId = parentId;
				Role = role;
			}
		}

		private const int NativeTextRoleCacheLimit = 16384;

		private const string SystemOnlineTitleObjectName = "TipLeft1";

		private const string SystemOnlineTitleFullPath = "Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/SystemsOnline/TipLeft1";

		private const string SystemOnlineTitlePathSuffix = "IngamePlayerHUD/BottomMiddle/SystemsOnline/TipLeft1";

		private const string SystemOnlineRelativePath = "BottomMiddle/SystemsOnline/TipLeft1";

		private const string EnteringAtmosphereTitleObjectName = "LoadText";

		private const string RelaySceneName = "SampleSceneRelay";

		private const string SystemOnlineLocalizedText = "系统在线";

		private const string EnteringAtmosphereLocalizedText = "正在进入大气层...";

		private const string HazardLevelLocalizedText = "风险级别:";

		private const string LifeSupportOfflineLocalizedText = "[生命维持:离线]";

		private static Coroutine? _systemOnlineWatcher;

		private static Coroutine? _fixedSceneLabelWatcher;

		private static HUDManager? _systemOnlineWatcherOwner;

		private static HUDManager? _fixedSceneLabelWatcherOwner;

		private static bool _fixedSceneLabelSceneLoadedSubscribed;

		private static string _fixedSceneLabelSceneLoadedStage = "SceneLoaded";

		private static readonly BoundedCache<int, CachedNativeTextRole> NativeTextRoleCache = new BoundedCache<int, CachedNativeTextRole>(16384);

		private static readonly Dictionary<string, string> FixedSceneLabels = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["TO MEET PROFIT QUOTA"] = "以达到利润配额",
			["PERFORMANCE REPORT"] = "绩效报告",
			["EMPLOYEE RANK"] = "员工等级",
			["Fines"] = "罚款",
			["(Dead)"] = "(死亡)",
			["Deceased"] = "死亡",
			["[LIFE SUPPORT: OFFLINE]"] = "[生命维持:离线]",
			["You will keep your employee rank. Your ship and credits will be reset."] = "你的员工等级将被保留,但飞船和点数将被重置。"
		};

		public static void Initialize(string pluginDir)
		{
			if (Plugin.RuntimeLocalizationLogsEnabled)
			{
				Plugin.LogRuntimeLocalizationEvent("Native relay title translation enabled; SYSTEMS ONLINE uses original TMP object only.");
			}
		}

		public static void ForceApplySystemOnlineOverlay(HUDManager? hudManager, string stage)
		{
			TMP_Text val = FindSystemOnlineTitle(hudManager, allowGlobalFallback: false);
			if ((Object)(object)val != (Object)null)
			{
				ApplySystemOnlineNativeTranslation(val, stage);
			}
			else if (Plugin.RuntimeLocalizationLogsEnabled)
			{
				Plugin.Log.LogWarning((object)("NativeRelay[" + stage + "] target=SystemOnline action=not-found"));
				AuditSystemOnlineBranch(stage, hudManager);
			}
		}

		public static void BeginSystemOnlineExactPathWatcher(HUDManager? hudManager, string stage)
		{
			if (!((Object)(object)hudManager == (Object)null))
			{
				ResetSystemOnlineWatcherIfStale(hudManager);
				if (_systemOnlineWatcher == null)
				{
					_systemOnlineWatcherOwner = hudManager;
					_systemOnlineWatcher = ((MonoBehaviour)hudManager).StartCoroutine(WaitForSystemOnlineTitle(hudManager, stage));
				}
			}
		}

		public static void TryApplySystemOnlineDirect(HUDManager? hudManager, string stage)
		{
			TMP_Text val = FindSystemOnlineTitle(hudManager, allowGlobalFallback: true);
			if ((Object)(object)val == (Object)null)
			{
				if (Plugin.RuntimeLocalizationLogsEnabled)
				{
					Plugin.Log.LogWarning((object)("NativeRelay[" + stage + "] target=SystemOnline action=not-found"));
				}
			}
			else
			{
				ApplySystemOnlineNativeTranslation(val, stage);
			}
		}

		public static void QueueSystemOnlineSync(HUDManager? hudManager, string stage)
		{
		}

		public static void TryApplyEnteringAtmosphereOverlayFromLoadingScreen(HUDManager? hudManager, string stage)
		{
			TMP_Text val = FindEnteringAtmosphereTitle(hudManager);
			if ((Object)(object)val == (Object)null)
			{
				if (Plugin.RuntimeLocalizationLogsEnabled)
				{
					Plugin.Log.LogWarning((object)("NativeRelay[" + stage + "] target=EnteringAtmosphere action=not-found"));
				}
			}
			else
			{
				ApplyEnteringAtmosphereNativeTranslation(val, stage);
			}
		}

		public static void HideEnteringAtmosphereOverlayForHud(HUDManager? hudManager, string stage)
		{
			TMP_Text val = FindEnteringAtmosphereTitle(hudManager);
			if ((Object)(object)val != (Object)null)
			{
				ApplyEnteringAtmosphereNativeTranslation(val, stage);
			}
		}

		public static void SyncEnteringAtmosphereOverlayState(TMP_Text? text, string stage)
		{
			if (!((Object)(object)text == (Object)null) && GetNativeTextRole(text) == NativeTextRole.EnteringAtmosphere)
			{
				ApplyEnteringAtmosphereNativeTranslation(text, stage);
			}
		}

		public static void SyncHazardLevelRelay(HUDManager? hudManager, string stage)
		{
			TMP_Text val = FindHazardLevelTitle(hudManager);
			if ((Object)(object)val != (Object)null)
			{
				ApplyHazardLevelNativeTranslation(val, stage);
			}
		}

		public static void SyncLandingInfo(HUDManager? hudManager, string stage)
		{
			if (!((Object)(object)hudManager == (Object)null))
			{
				ApplyDynamicFieldTranslation((TMP_Text?)(object)hudManager.planetInfoHeaderText, stage, "PlanetInfoHeader");
				ApplyDynamicFieldTranslation((TMP_Text?)(object)hudManager.planetInfoSummaryText, stage, "PlanetInfoSummary");
				ApplyDynamicFieldTranslation((TMP_Text?)(object)hudManager.planetRiskLevelText, stage, "PlanetRiskLevel");
				SyncHazardLevelRelay(hudManager, stage);
			}
		}

		public static void SyncFixedSceneLabels(HUDManager? hudManager, string stage)
		{
			if (!((Object)(object)hudManager == (Object)null))
			{
				TMP_Text[] componentsInChildren = ((Component)hudManager).GetComponentsInChildren<TMP_Text>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					TryReplaceFixedSceneLabel(componentsInChildren[i], stage);
				}
			}
		}

		public static void BeginFixedSceneLabelWatcher(HUDManager? hudManager, string stage)
		{
			if (!((Object)(object)hudManager == (Object)null) && SyncFixedSceneLabelsInRelayScene(stage + ".initial") <= 0)
			{
				_fixedSceneLabelWatcherOwner = hudManager;
				_fixedSceneLabelSceneLoadedStage = stage;
				if (!_fixedSceneLabelSceneLoadedSubscribed)
				{
					SceneManager.sceneLoaded += OnRelaySceneLoadedForFixedLabels;
					_fixedSceneLabelSceneLoadedSubscribed = true;
				}
			}
		}

		public static void Shutdown()
		{
			try
			{
				if (_systemOnlineWatcher != null && (Object)(object)_systemOnlineWatcherOwner != (Object)null)
				{
					((MonoBehaviour)_systemOnlineWatcherOwner).StopCoroutine(_systemOnlineWatcher);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("NativeRelay shutdown failed stopping SystemOnline watcher: " + ex.GetType().Name + ": " + ex.Message));
			}
			try
			{
				if (_fixedSceneLabelWatcher != null && (Object)(object)_fixedSceneLabelWatcherOwner != (Object)null)
				{
					((MonoBehaviour)_fixedSceneLabelWatcherOwner).StopCoroutine(_fixedSceneLabelWatcher);
				}
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("NativeRelay shutdown failed stopping fixed scene label watcher: " + ex2.GetType().Name + ": " + ex2.Message));
			}
			_systemOnlineWatcher = null;
			_fixedSceneLabelWatcher = null;
			_systemOnlineWatcherOwner = null;
			_fixedSceneLabelWatcherOwner = null;
			if (_fixedSceneLabelSceneLoadedSubscribed)
			{
				SceneManager.sceneLoaded -= OnRelaySceneLoadedForFixedLabels;
				_fixedSceneLabelSceneLoadedSubscribed = false;
			}
			_fixedSceneLabelSceneLoadedStage = "SceneLoaded";
			NativeTextRoleCache.Clear();
		}

		private static void OnRelaySceneLoadedForFixedLabels(Scene scene, LoadSceneMode mode)
		{
			if (string.Equals(((Scene)(ref scene)).name, "SampleSceneRelay", StringComparison.Ordinal))
			{
				SyncFixedSceneLabelsInRelayScene(_fixedSceneLabelSceneLoadedStage + ".scene-loaded");
				SceneManager.sceneLoaded -= OnRelaySceneLoadedForFixedLabels;
				_fixedSceneLabelSceneLoadedSubscribed = false;
				_fixedSceneLabelWatcherOwner = null;
				_fixedSceneLabelSceneLoadedStage = "SceneLoaded";
			}
		}

		private static void ResetSystemOnlineWatcherIfStale(HUDManager currentHud)
		{
			if (_systemOnlineWatcher == null)
			{
				_systemOnlineWatcherOwner = null;
			}
			else if (!((Object)(object)_systemOnlineWatcherOwner == (Object)(object)currentHud))
			{
				StopStaleWatcher(_systemOnlineWatcherOwner, _systemOnlineWatcher, "SystemOnline");
				_systemOnlineWatcher = null;
				_systemOnlineWatcherOwner = null;
			}
		}

		private static void ResetFixedSceneLabelWatcherIfStale(HUDManager currentHud)
		{
			if (_fixedSceneLabelWatcher == null)
			{
				_fixedSceneLabelWatcherOwner = null;
			}
			else if (!((Object)(object)_fixedSceneLabelWatcherOwner == (Object)(object)currentHud))
			{
				StopStaleWatcher(_fixedSceneLabelWatcherOwner, _fixedSceneLabelWatcher, "FixedSceneLabel");
				_fixedSceneLabelWatcher = null;
				_fixedSceneLabelWatcherOwner = null;
			}
		}

		private static void StopStaleWatcher(HUDManager? owner, Coroutine watcher, string label)
		{
			if ((Object)(object)owner == (Object)null)
			{
				return;
			}
			try
			{
				((MonoBehaviour)owner).StopCoroutine(watcher);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("NativeRelay stale " + label + " watcher stop failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		public static void TryReplaceSystemOnlineText(TMP_Text? text, string stage)
		{
			if ((Object)(object)text == (Object)null || !MightBeNativeRelayCandidate(text))
			{
				return;
			}
			switch (GetNativeTextRole(text))
			{
			case NativeTextRole.SystemOnline:
				ApplySystemOnlineNativeTranslation(text, stage);
				return;
			case NativeTextRole.EnteringAtmosphere:
				ApplyEnteringAtmosphereNativeTranslation(text, stage);
				return;
			}
			if (IsHazardLevelTitle(text.text))
			{
				ApplyHazardLevelNativeTranslation(text, stage);
			}
			else
			{
				TryReplaceFixedSceneLabel(text, stage);
			}
		}

		public static bool TryReplaceFixedSceneLabel(TMP_Text? text, string stage)
		{
			if ((Object)(object)text == (Object)null || string.IsNullOrWhiteSpace(text.text))
			{
				return false;
			}
			if (!TryResolveFixedSceneLabel(text.text, out string localized))
			{
				return false;
			}
			ApplyLocalizedText(text, localized, stage, "FixedSceneLabel");
			if (Plugin.RuntimeLocalizationLogsEnabled)
			{
				Plugin.LogRuntimeLocalizationEvent("NativeRelay[" + stage + "] target=FixedSceneLabel action=applied name=" + ((Object)text).name + " path=" + BuildPath(text.transform) + " text=" + text.text);
			}
			return true;
		}

		public static void TryReplaceSystemOnlineText(Text? text, string stage)
		{
		}

		private static bool MightBeNativeRelayCandidate(TMP_Text text)
		{
			if (string.Equals(((Object)text).name, "TipLeft1", StringComparison.OrdinalIgnoreCase) || string.Equals(((Object)text).name, "LoadText", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			string text2 = text.text;
			if (string.IsNullOrWhiteSpace(text2) || text2.Length > 160)
			{
				return false;
			}
			int i;
			for (i = 0; i < text2.Length && char.IsWhiteSpace(text2[i]); i++)
			{
			}
			if (i >= text2.Length)
			{
				return false;
			}
			switch (char.ToUpperInvariant(text2[i]))
			{
			case '(':
			case 'D':
			case 'E':
			case 'F':
			case 'H':
			case 'P':
			case 'T':
			case 'Y':
			case '[':
				return true;
			default:
				return false;
			}
		}

		public static void TryReplaceSystemOnlineText(TextMesh? text, string stage)
		{
		}

		public static void TryReplace(Image? image, string stage)
		{
		}

		public static void TryReplace(RawImage? image, string stage)
		{
		}

		public static void TryReplace(SpriteRenderer? renderer, string stage)
		{
		}

		public static void TryReplace(Material? material, string stage)
		{
		}

		private static void ApplySystemOnlineNativeTranslation(TMP_Text text, string stage)
		{
			if (!((Behaviour)text).enabled)
			{
				((Behaviour)text).enabled = true;
			}
			ApplyLocalizedText(text, ResolveLocalizedText(text.text, "系统在线"), stage, "SystemOnline");
			if (Plugin.RuntimeLocalizationLogsEnabled)
			{
				Plugin.LogRuntimeLocalizationEvent("NativeRelay[" + stage + "] target=SystemOnline action=applied name=" + ((Object)text).name + " path=" + BuildPath(text.transform) + " text=" + text.text);
			}
		}

		private static IEnumerator WaitForSystemOnlineTitle(HUDManager hudManager, string stage)
		{
			float elapsed = 0f;
			while ((Object)(object)hudManager != (Object)null && elapsed < 12f)
			{
				TMP_Text text = FindSystemOnlineTitleByHudPath(hudManager);
				if (IsExactSystemOnlineTitle(text))
				{
					ApplySystemOnlineNativeTranslation(text, stage + ".watcher");
					_systemOnlineWatcher = null;
					_systemOnlineWatcherOwner = null;
					yield break;
				}
				yield return (object)new WaitForSeconds(0.25f);
				elapsed += 0.25f;
			}
			if (Plugin.RuntimeLocalizationLogsEnabled)
			{
				Plugin.Log.LogWarning((object)("NativeRelay[" + stage + ".watcher] target=SystemOnline action=timeout"));
			}
			_systemOnlineWatcher = null;
			_systemOnlineWatcherOwner = null;
		}

		private static IEnumerator WaitForFixedSceneLabels(string stage)
		{
			for (float elapsed = 0f; elapsed < 8f; elapsed += 0.5f)
			{
				if (SyncFixedSceneLabelsInRelayScene(stage + ".relay-scene") > 0)
				{
					_fixedSceneLabelWatcher = null;
					_fixedSceneLabelWatcherOwner = null;
					yield break;
				}
				yield return (object)new WaitForSeconds(0.5f);
			}
			if (Plugin.RuntimeLocalizationLogsEnabled)
			{
				Plugin.Log.LogWarning((object)("NativeRelay[" + stage + ".relay-scene] target=FixedSceneLabel action=timeout"));
			}
			_fixedSceneLabelWatcher = null;
			_fixedSceneLabelWatcherOwner = null;
		}

		private static void ApplyEnteringAtmosphereNativeTranslation(TMP_Text text, string stage)
		{
			ApplyLocalizedText(text, ResolveLocalizedText(text.text, "正在进入大气层..."), stage, "EnteringAtmosphere");
		}

		private static void ApplyHazardLevelNativeTranslation(TMP_Text text, string stage)
		{
			ApplyLocalizedText(text, "风险级别:", stage, "HazardLevel");
		}

		private static void ApplyLocalizedText(TMP_Text text, string localized, string stage, string target)
		{
			if (!string.IsNullOrWhiteSpace(localized))
			{
				if (!string.Equals(text.text, localized, StringComparison.Ordinal))
				{
					text.text = localized;
				}
				FontFallbackService.ApplyFallback(text, localized);
				ApplyLifeSupportOfflineTypography(text, localized);
			}
		}

		private static void ApplyLifeSupportOfflineTypography(TMP_Text text, string localized)
		{
			if (string.Equals(localized, "[生命维持:离线]", StringComparison.Ordinal))
			{
				text.richText = true;
				text.enableWordWrapping = false;
				text.overflowMode = (TextOverflowModes)0;
				text.fontStyle = (FontStyles)0;
				text.characterSpacing = Math.Max(text.characterSpacing, 6f);
				text.wordSpacing = Math.Max(text.wordSpacing, 8f);
			}
		}

		private static TMP_Text? FindSystemOnlineTitle(HUDManager? hudManager, bool allowGlobalFallback)
		{
			if ((Object)(object)hudManager != (Object)null)
			{
				if ((Object)(object)((Component)hudManager).transform != (Object)null)
				{
					Transform obj = ((Component)hudManager).transform.Find("BottomMiddle/SystemsOnline/TipLeft1");
					TMP_Text val = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
					if (IsExactSystemOnlineTitle(val))
					{
						return val;
					}
				}
				TMP_Text[] componentsInChildren = ((Component)hudManager).GetComponentsInChildren<TMP_Text>(true);
				foreach (TMP_Text val2 in componentsInChildren)
				{
					if (IsExactSystemOnlineTitle(val2))
					{
						return val2;
					}
				}
			}
			if (allowGlobalFallback)
			{
				TMP_Text val3 = FindSystemOnlineTitleByFullPath();
				if (IsExactSystemOnlineTitle(val3))
				{
					return val3;
				}
				TMP_Text[] componentsInChildren = Resources.FindObjectsOfTypeAll<TMP_Text>();
				foreach (TMP_Text val4 in componentsInChildren)
				{
					if (IsExactSystemOnlineTitle(val4))
					{
						return val4;
					}
				}
			}
			return null;
		}

		private static TMP_Text? FindSystemOnlineTitleByFullPath()
		{
			GameObject val = GameObject.Find("Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/SystemsOnline/TipLeft1");
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<TMP_Text>();
		}

		private static TMP_Text? FindSystemOnlineTitleByHudPath(HUDManager? hudManager)
		{
			if ((Object)(object)((hudManager != null) ? ((Component)hudManager).transform : null) == (Object)null)
			{
				return null;
			}
			Transform val = ((Component)hudManager).transform.Find("BottomMiddle/SystemsOnline/TipLeft1");
			if (!((Object)(object)val == (Object)null))
			{
				return ((Component)val).GetComponent<TMP_Text>();
			}
			return null;
		}

		private static TMP_Text? FindEnteringAtmosphereTitle(HUDManager? hudManager)
		{
			if ((Object)(object)hudManager?.LoadingScreen == (Object)null)
			{
				return null;
			}
			TMP_Text[] componentsInChildren = ((Component)hudManager.LoadingScreen).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				if (IsEnteringAtmosphereTitleObject(val))
				{
					return val;
				}
			}
			return null;
		}

		private static TMP_Text? FindHazardLevelTitle(HUDManager? hudManager)
		{
			if ((Object)(object)hudManager == (Object)null)
			{
				return null;
			}
			TMP_Text[] componentsInChildren = ((Component)hudManager).GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val in componentsInChildren)
			{
				if (IsHazardLevelTitle(val.text))
				{
					return val;
				}
			}
			return null;
		}

		private static bool IsSystemOnlineObject(TMP_Text? text)
		{
			return GetNativeTextRole(text) == NativeTextRole.SystemOnline;
		}

		private static bool IsSystemOnlinePath(Transform? transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return false;
			}
			return BuildPath(transform).EndsWith("IngamePlayerHUD/BottomMiddle/SystemsOnline/TipLeft1", StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsEnteringAtmosphereTitleObject(TMP_Text? text)
		{
			return GetNativeTextRole(text) == NativeTextRole.EnteringAtmosphere;
		}

		private static bool IsHazardLevelTitle(string? text)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			string a = text.Trim();
			if (!string.Equals(a, "HAZARD LEVEL:", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "风险级别:", StringComparison.Ordinal) && !string.Equals(a, "风险级别:", StringComparison.Ordinal) && !string.Equals(a, "危险等级:", StringComparison.Ordinal))
			{
				return string.Equals(a, "危险等级:", StringComparison.Ordinal);
			}
			return true;
		}

		private static string ResolveLocalizedText(string? current, string fallback)
		{
			if (!string.IsNullOrWhiteSpace(current) && TranslationService.TryTranslate(current, out string translated))
			{
				return translated;
			}
			return fallback;
		}

		private static bool TryResolveFixedSceneLabel(string? current, out string localized)
		{
			localized = string.Empty;
			if (string.IsNullOrWhiteSpace(current))
			{
				return false;
			}
			if (FixedSceneLabels.TryGetValue(current.Trim(), out localized) && !string.IsNullOrWhiteSpace(localized))
			{
				return true;
			}
			return false;
		}

		private static int SyncFixedSceneLabelsInRelayScene(string stage)
		{
			//IL_0005: 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)
			Scene sceneByName = SceneManager.GetSceneByName("SampleSceneRelay");
			if (!((Scene)(ref sceneByName)).IsValid() || !((Scene)(ref sceneByName)).isLoaded)
			{
				return 0;
			}
			int num = 0;
			GameObject[] rootGameObjects = ((Scene)(ref sceneByName)).GetRootGameObjects();
			for (int i = 0; i < rootGameObjects.Length; i++)
			{
				TMP_Text[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren<TMP_Text>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					if (TryReplaceFixedSceneLabel(componentsInChildren[j], stage))
					{
						num++;
					}
				}
			}
			return num;
		}

		private static bool HasNamedAncestor(Transform? transform, string expectedName)
		{
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				if (string.Equals(((Object)val).name, expectedName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static void AuditSystemOnlineBranch(string stage, HUDManager? hudManager)
		{
			int num = 0;
			if ((Object)(object)hudManager != (Object)null)
			{
				TMP_Text[] componentsInChildren = ((Component)hudManager).GetComponentsInChildren<TMP_Text>(true);
				foreach (TMP_Text val in componentsInChildren)
				{
					if (HasNamedAncestor(val.transform, "SystemsOnline"))
					{
						num++;
						if (Plugin.RuntimeLocalizationLogsEnabled)
						{
							Plugin.LogRuntimeLocalizationEvent($"NativeRelay[{stage}] target=SystemOnline action=audit exact={IsExactSystemOnlineTitle(val)} name={((Object)val).name} path={BuildPath(val.transform)} text={val.text}");
						}
					}
				}
			}
			_ = 0;
		}

		private static void ApplyDynamicFieldTranslation(TMP_Text? text, string stage, string target)
		{
			if (!((Object)(object)text == (Object)null) && !string.IsNullOrWhiteSpace(text.text) && (TranslationService.TryTranslateKnownDynamicTextTargeted(DynamicTextDomain.PlanetInfo, text.text, out string translated) || TranslationService.TryTranslate(text.text, out translated)) && !string.IsNullOrWhiteSpace(translated))
			{
				if (!string.Equals(text.text, translated, StringComparison.Ordinal))
				{
					text.text = translated;
				}
				FontFallbackService.ApplyFallback(text, translated);
				if (Plugin.RuntimeLocalizationLogsEnabled)
				{
					Plugin.LogRuntimeLocalizationEvent("NativeRelay[" + stage + "] target=" + target + " action=applied name=" + ((Object)text).name + " path=" + BuildPath(text.transform) + " text=" + text.text);
				}
			}
		}

		private static string BuildPath(Transform? transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return "<null>";
			}
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		private static bool IsExactSystemOnlineTitle(TMP_Text? text)
		{
			return GetNativeTextRole(text) == NativeTextRole.SystemOnline;
		}

		private static NativeTextRole GetNativeTextRole(TMP_Text? text)
		{
			if ((Object)(object)text == (Object)null)
			{
				return NativeTextRole.None;
			}
			if (TryGetCachedNativeTextRole(text, out var role))
			{
				return role;
			}
			role = ResolveNativeTextRole(text);
			CacheNativeTextRole(text, role);
			return role;
		}

		private static bool TryGetCachedNativeTextRole(TMP_Text text, out NativeTextRole role)
		{
			int parentInstanceId = GetParentInstanceId(text.transform);
			if (NativeTextRoleCache.TryGetValue(((Object)text).GetInstanceID(), out var value) && value.ParentId == parentInstanceId)
			{
				role = value.Role;
				return true;
			}
			role = NativeTextRole.None;
			return false;
		}

		private static NativeTextRole ResolveNativeTextRole(TMP_Text text)
		{
			if (string.Equals(((Object)text).name, "LoadText", StringComparison.OrdinalIgnoreCase) && HasNamedAncestor(text.transform, "LoadingText"))
			{
				return NativeTextRole.EnteringAtmosphere;
			}
			if (string.Equals(((Object)text).name, "TipLeft1", StringComparison.OrdinalIgnoreCase) && IsSystemOnlinePath(text.transform))
			{
				return NativeTextRole.SystemOnline;
			}
			return NativeTextRole.None;
		}

		private static void CacheNativeTextRole(TMP_Text text, NativeTextRole role)
		{
			int instanceID = ((Object)text).GetInstanceID();
			NativeTextRoleCache.Set(instanceID, new CachedNativeTextRole(GetParentInstanceId(text.transform), role), RuntimePerformanceSettings.ComponentTextCacheLimit);
		}

		private static int GetParentInstanceId(Transform? transform)
		{
			if (!((Object)(object)((transform != null) ? transform.parent : null) == (Object)null))
			{
				return ((Object)transform.parent).GetInstanceID();
			}
			return 0;
		}
	}
	internal static class ClipboardManualLocalizationService
	{
		private sealed class TextureSpec
		{
			public string FileName { get; }

			public int Width { get; }

			public int Height { get; }

			public bool PrecompressedBc3 { get; }

			public TextureSpec(string fileName, int width = 0, int height = 0, bool precompressedBc3 = false)
			{
				FileName = fileName;
				Width = width;
				Height = height;
				PrecompressedBc3 = precompressedBc3;
			}
		}

		private sealed class RendererState
		{
			public Renderer Renderer { get; }

			public Material[] OriginalMaterials { get; }

			public List<Material> LocalizedMaterials { get; }

			public RendererState(Renderer renderer, Material[] originalMaterials, List<Material> localizedMaterials)
			{
				Renderer = renderer;
				OriginalMaterials = originalMaterials;
				LocalizedMaterials = localizedMaterials;
			}
		}

		private const int MaxTextureFileBytes = 8388608;

		private const int MaxTextureDimension = 4096;

		private static readonly Dictionary<string, TextureSpec> TextureFiles = new Dictionary<string, TextureSpec>(StringComparer.OrdinalIgnoreCase)
		{
			["Manual1"] = new TextureSpec("ClipboardManualPage1.png"),
			["Manual2"] = new TextureSpec("ClipboardManualPage2.png"),
			["Manual3"] = new TextureSpec("ClipboardManualPage3.png"),
			["Manual4"] = new TextureSpec("ClipboardManualPage4.png"),
			["CruiserManual1"] = new TextureSpec("CruiserManualPage1.bc3", 900, 1260, precompressedBc3: true),
			["CruiserManual2"] = new TextureSpec("CruiserManualPage2.bc3", 900, 1260, precompressedBc3: true),
			["CruiserManual3"] = new TextureSpec("CruiserManualPage3.bc3", 900, 1260, precompressedBc3: true),
			["CruiserManual4"] = new TextureSpec("CruiserManualPage4.bc3", 900, 1260, precompressedBc3: true)
		};

		private static readonly Dictionary<string, Texture2D> Textures = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> FailedTextures = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

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

		private static string _textureDirectory = string.Empty;

		private static bool _initialized;

		public static void Initialize(string pluginDir)
		{
			_textureDirectory = Path.Combine(pluginDir, "textures");
			_initialized = true;
			FailedTextures.Clear();
		}

		public static void Apply(GrabbableObject? grabbableObject)
		{
			if (!_initialized || Plugin.IsRuntimeShuttingDown)
			{
				return;
			}
			ClipboardItem val = (ClipboardItem)(object)((grabbableObject is ClipboardItem) ? grabbableObject : null);
			if (val == null)
			{
				return;
			}
			Animator clipboardAnimator = val.clipboardAnimator;
			if (!((Object)(object)clipboardAnimator == (Object)null))
			{
				PruneDestroyedRendererStates();
				SkinnedMeshRenderer[] componentsInChildren = ((Component)clipboardAnimator).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					ApplyToRenderer((Renderer?)(object)componentsInChildren[i]);
				}
			}
		}

		public static void ApplyVehicle(VehicleController? vehicle)
		{
			if (_initialized && !Plugin.IsRuntimeShuttingDown && !((Object)(object)vehicle == (Object)null))
			{
				PruneDestroyedRendererStates();
				Renderer[] componentsInChildren = ((Component)vehicle).GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					ApplyToRenderer(componentsInChildren[i]);
				}
			}
		}

		public static void Shutdown()
		{
			foreach (RendererState value in RendererStates.Values)
			{
				try
				{
					if ((Object)(object)value.Renderer != (Object)null)
					{
						value.Renderer.sharedMaterials = value.OriginalMaterials;
					}
				}
				catch
				{
				}
				foreach (Material localizedMaterial in value.LocalizedMaterials)
				{
					DestroyUnityObject((Object?)(object)localizedMaterial);
				}
			}
			RendererStates.Clear();
			foreach (Texture2D value2 in Textures.Values)
			{
				DestroyUnityObject((Object?)(object)value2);
			}
			Textures.Clear();
			FailedTextures.Clear();
			_textureDirectory = string.Empty;
			_initialized = false;
		}

		public static void OnSceneUnloaded()
		{
			PruneDestroyedRendererStates();
		}

		private static void ApplyToRenderer(Renderer? renderer)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			if ((Object)(object)renderer == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)renderer).GetInstanceID();
			if (RendererStates.ContainsKey(instanceID))
			{
				return;
			}
			Material[] sharedMaterials = renderer.sharedMaterials;
			if (sharedMaterials == null || sharedMaterials.Length == 0)
			{
				return;
			}
			Material[] array = (Material[])sharedMaterials.Clone();
			List<Material> list = new List<Material>();
			for (int i = 0; i < sharedMaterials.Length; i++)
			{
				Material val = sharedMaterials[i];
				if (!((Object)(object)val == (Object)null) && TryResolveTexture(((Object)val).name, out Texture2D texture))
				{
					Material val2 = new Material(val)
					{
						name = NormalizeMaterialName(((Object)val).name) + " (zh-CN)"
					};
					SetTexture(val2, texture);
					array[i] = val2;
					list.Add(val2);
				}
			}
			if (list.Count != 0)
			{
				renderer.sharedMaterials = array;
				RendererStates[instanceID] = new RendererState(renderer, sharedMaterials, list);
			}
		}

		private static void PruneDestroyedRendererStates()
		{
			List<int> list = null;
			foreach (KeyValuePair<int, RendererState> rendererState in RendererStates)
			{
				if ((Object)(object)rendererState.Value.Renderer != (Object)null)
				{
					continue;
				}
				if (list == null)
				{
					list = new List<int>();
				}
				list.Add(rendererState.Key);
				foreach (Material localizedMaterial in rendererState.Value.LocalizedMaterials)
				{
					DestroyUnityObject((Object?)(object)localizedMaterial);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item in list)
			{
				RendererStates.Remove(item);
			}
		}

		private static bool TryResolveTexture(string? materialName, out Texture2D texture)
		{
			string text = NormalizeMaterialName(materialName);
			if (Textures.TryGetValue(text, out texture))
			{
				return true;
			}
			if (FailedTextures.Contains(text) || !TextureFiles.TryGetValue(text, out TextureSpec value))
			{
				texture = null;
				return false;
			}
			Texture2D val = LoadTexture(text, value);
			if ((Object)(object)val == (Object)null)
			{
				FailedTextures.Add(text);
				texture = null;
				return false;
			}
			Textures[text] = val;
			texture = val;
			return true;
		}

		private static string NormalizeMaterialName(string? materialName)
		{
			if (string.IsNullOrWhiteSpace(materialName))
			{
				return string.Empty;
			}
			string text = materialName.Trim();
			if (text.EndsWith(" (Instance)", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(0, text.Length - " (Instance)".Length);
			}
			if (text.EndsWith(" (zh-CN)", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(0, text.Length - " (zh-CN)".Length);
			}
			return text;
		}

		private static void SetTexture(Material material, Texture2D texture)
		{
			if (material.HasProperty("_BaseColorMap"))
			{
				material.SetTexture("_BaseColorMap", (Texture)(object)texture);
			}
			if (material.HasProperty("_MainTex"))
			{
				material.SetTexture("_MainTex", (Texture)(object)texture);
			}
			material.mainTexture = (Texture)(object)texture;
		}

		private static Texture2D? LoadTexture(string materialName, TextureSpec spec)
		{
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			string fileName = spec.FileName;
			string text = Path.Combine(_textureDirectory, fileName);
			Texture2D val = null;
			try
			{
				FileInfo fileInfo = new FileInfo(text);
				if (!fileInfo.Exists)
				{
					Plugin.Log.LogWarning((object)("Clipboard manual texture is missing: " + fileName));
					return null;
				}
				if (fileInfo.Length <= 0 || (!spec.PrecompressedBc3 && fileInfo.Length > 8388608))
				{
					Plugin.Log.LogWarning((object)$"Clipboard manual texture has an invalid file size: {fileName} ({fileInfo.Length} bytes)");
					return null;
				}
				if (spec.PrecompressedBc3)
				{
					val = PrecompressedTextureLoader.LoadBc3(text, spec.Width, spec.Height, mipChain: false, out string error);
					if ((Object)(object)val == (Object)null)
					{
						Plugin.Log.LogWarning((object)("Clipboard manual texture could not be loaded: " + fileName + " (" + error + ")"));
						return null;
					}
				}
				else
				{
					byte[] array = File.ReadAllBytes(text);
					val = new Texture2D(2, 2, (TextureFormat)4, false);
					if (!ImageConversion.LoadImage(val, array, true))
					{
						Plugin.Log.LogWarning((object)("Clipboard manual texture could not be decoded: " + fileName));
						DestroyUnityObject((Object?)(object)val);
						return null;
					}
					if (((Texture)val).width <= 0 || ((Texture)val).height <= 0 || ((Texture)val).width > 4096 || ((Texture)val).height > 4096)
					{
						Plugin.Log.LogWarning((object)$"Clipboard manual texture dimensions are invalid: {fileName} ({((Texture)val).width}x{((Texture)val).height})");
						DestroyUnityObject((Object?)(object)val);
						return null;
					}
				}
				((Object)val).name = materialName + " (zh-CN)";
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Texture)val).filterMode = (FilterMode)1;
				return val;
			}
			catch (Exception ex)
			{
				DestroyUnityObject((Object?)(object)val);
				Plugin.Log.LogWarning((object)("Clipboard manual texture load failed for " + fileName + ": " + ex.GetType().Name + ": " + ex.Message));
				return null;
			}
		}

		private static void DestroyUnityObject(Object? value)
		{
			if (!(value == (Object)null))
			{
				if (Application.isPlaying)
				{
					Object.Destroy(value);
				}
				else
				{
					Object.DestroyImmediate(value);
				}
			}
		}
	}
	internal struct EnvironmentCleanupGate
	{
		private bool _hasCompletedFrame;

		private int _completedFrame;

		internal bool NeedsCleanup(int frame)
		{
			if (_hasCompletedFrame)
			{
				return _completedFrame != frame;
			}
			return true;
		}

		internal void Complete(int frame)
		{
			_completedFrame = frame;
			_hasCompletedFrame = true;
		}

		internal void Reset()
		{
			_hasCompletedFrame = false;
			_completedFrame = 0;
		}
	}
	internal sealed class EnvironmentLevelScan : IDisposable
	{
		private struct NodeCursor
		{
			internal Transform Node;

			internal int NextChild;

			internal int ObservedChildCount;

			internal Transform? PreviousChild;

			internal NodeCursor(Transform node)
			{
				Node = node;
				NextChild = 0;
				ObservedChildCount = 0;
				PreviousChild = null;
			}
		}

		private sealed class TransformIdentityComparer : IEqualityComparer<Transform>
		{
			internal static readonly TransformIdentityComparer Instance = new TransformIdentityComparer();

			public bool Equals(Transform? left, Transform? right)
			{
				return left == right;
			}

			public int GetHashCode(Transform value)
			{
				return RuntimeHelpers.GetHashCode(value);
			}
		}

		private static readonly Func<long> Timestamp = Stopwatch.GetTimestamp;

		private readonly Action<Renderer> _apply;

		private IEnumerator<Renderer?>? _work;

		internal EnvironmentLevelScan(Action<Renderer> apply)
		{
			_apply = apply;
			_work = Enumerate().GetEnumerator();
		}

		internal bool Pump()
		{
			return Pump(256, Math.Max(1L, Stopwatch.Frequency / 2000), Timestamp);
		}

		internal bool Pump(int maximumWorkItems, long maximumTicks, Func<long> timestamp)
		{
			if (_work == null)
			{
				return false;
			}
			long num = timestamp();
			for (int i = 0; i < maximumWorkItems; i++)
			{
				if (!_work.MoveNext())
				{
					Dispose();
					return false;
				}
				Renderer current = _work.Current;
				if ((Object)(object)current != (Object)null)
				{
					_apply(current);
				}
				if (_work == null)
				{
					return false;
				}
				if (timestamp() - num >= maximumTicks)
				{
					return true;
				}
			}
			return true;
		}

		public void Dispose()
		{
			IEnumerator<Renderer?>? work = _work;
			_work = null;
			work?.Dispose();
		}

		private static IEnumerable<Renderer?> Enumerate()
		{
			List<GameObject> roots = new List<GameObject>();
			List<Renderer> renderers = new List<Renderer>();
			Stack<NodeCursor> nodes = new Stack<NodeCursor>();
			HashSet<Transform> visited = new HashSet<Transform>(TransformIdentityComparer.Instance);
			try
			{
				for (int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++)
				{
					Scene scene = SceneManager.GetSceneAt(sceneIndex);
					roots.Clear();
					if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
					{
						if (roots.Capacity < ((Scene)(ref scene)).rootCount)
						{
							roots.Capacity = ((Scene)(ref scene)).rootCount;
						}
						((Scene)(ref scene)).GetRootGameObjects(roots);
					}
					yield return null;
					for (int rootIndex = 0; rootIndex < roots.Count; rootIndex++)
					{
						if (!((Scene)(ref scene)).IsValid())
						{
							break;
						}
						if (!((Scene)(ref scene)).isLoaded)
						{
							break;
						}
						GameObject val = roots[rootIndex];
						if ((Object)(object)val == (Object)null)
						{
							yield return null;
							continue;
						}
						Transform next = val.transform;
						while (((Object)(object)next != (Object)null || nodes.Count > 0) && ((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
						{
							if ((Object)(object)next != (Object)null)
							{
								Transform current = next;
								next = null;
								if (!visited.Add(current))
								{
									yield return null;
									continue;
								}
								nodes.Push(new NodeCursor(current));
								renderers.Clear();
								((Component)current).GetComponents<Renderer>(renderers);
								yield return null;
								for (int rendererIndex = 0; rendererIndex < renderers.Count; rendererIndex++)
								{
									if (!((Scene)(ref scene)).IsValid())
									{
										break;
									}
									if (!((Scene)(ref scene)).isLoaded)
									{
										break;
									}
									if ((Object)(object)current == (Object)null)
									{
										break;
									}
									yield return renderers[rendererIndex];
								}
								renderers.Clear();
								continue;
							}
							NodeCursor item = nodes.Pop();
							if ((Object)(object)item.Node != (Object)null)
							{
								int childCount = item.Node.childCount;
								if (item.NextChild > 0 && (childCount != item.ObservedChildCount || item.NextChild > childCount || item.Node.GetChild(item.NextChild - 1) != item.PreviousChild))
								{
									item.NextChild = 0;
								}
								if (item.NextChild < childCount)
								{
									next = (item.PreviousChild = item.Node.GetChild(item.NextChild++));
									item.ObservedChildCount = childCount;
									nodes.Push(item);
								}
							}
							yield return null;
						}
						nodes.Clear();
						yield return null;
					}
				}
			}
			finally
			{
				roots.Clear();
				renderers.Clear();
				nodes.Clear();
				visited.Clear();
			}
		}
	}
	internal static class EnvironmentTextureLocalizationService
	{
		private sealed class TextureSpec
		{
			public string OriginalName { get; }

			public string FileName { get; }

			public int Width { get; }

			public int Height { get; }

			public bool PrecompressedBc1 { get; }

			public bool PrecompressedBc3 { get; }

			public bool PrecompressedBc7 { get; }

			public bool MipChain { get; }

			public TextureSpec(string originalName, string fileName, int width, int height, bool precompressedBc1 = false, bool precompressedBc3 = false, bool precompressedBc7 = false, bool mipChain = true)
			{
				OriginalName = originalName;
				FileName = fileName;
				Width = width;
				Height = height;
				PrecompressedBc1 = precompressedBc1;
				PrecompressedBc3 = precompressedBc3;
				PrecompressedBc7 = precompressedBc7;
				MipChain = mipChain;
			}
		}

		private sealed class RendererState
		{
			public Renderer Renderer { get; }

			public Material[] OriginalMaterials { get; }

			public List<int> LocalizedMaterialIds { get; }

			public RendererState(Renderer renderer, Material[] originalMaterials, List<int> localizedMaterialIds)
			{
				Renderer = renderer;
				OriginalMaterials = originalMaterials;
				LocalizedMaterialIds = localizedMaterialIds;
			}
		}

		private sealed class MaterialState
		{
			public WeakReference<Material> Original { get; }

			public Material Localized { get; }

			public MaterialState(Material original, Material localized)
			{
				Original = new WeakReference<Material>(original);
				Localized = localized;
			}

			public bool HasOriginal(Material material)
			{
				if (Original.TryGetTarget(out Material target) && (Object)(object)target != (Object)null)
				{
					return (Object)(object)target == (Object)(object)material;
				}
				return false;
			}

			public bool HasLiveOriginal()
			{
				if (Original.TryGetTarget(out Material target))
				{
					return (Object)(object)target != (Object)null;
				}
				return false;
			}
		}

		private sealed class FireExitState
		{
			public Renderer Renderer { get; }

			public Material[] OriginalMaterials { get; }

			public GameObject Overlay { get; }

			public FireExitState(Renderer renderer, Material[] originalMaterials, GameObject overlay)
			{
				Renderer = renderer;
				OriginalMaterials = originalMaterials;
				Overlay = overlay;
			}
		}

		private const int MaxTextureFileBytes = 16777216;

		private const string FireExitLabelFileName = "FireExitDoorLabelLocalized.png";

		private static readonly string[] TexturePropertyNames = new string[2] { "_BaseColorMap", "_MainTex" };

		private static readonly List<Renderer> RendererScanBuffer = new List<Renderer>();

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

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

		private static readonly Dictionary<string, TextureSpec> TextureSpecs = new Dictionary<string, TextureSpec>(StringComparer.OrdinalIgnoreCase)
		{
			["posters"] = new TextureSpec("posters", "ShipPostersLocalized.png", 1024, 1024),
			["TipsPoster2"] = new TextureSpec("TipsPoster2", "ShipTipsPosterLocalized.png", 796, 1024),
			["ToiletPaperTex"] = new TextureSpec("ToiletPaperTex", "ToiletPaperTexLocalized.png", 1024, 1024),
			["CashRegisterTex"] = new TextureSpec("CashRegisterTex", "CashRegisterTexLocalized.png", 1024, 1024),
			["FlashbangBottleTexture"] = new TextureSpec("FlashbangBottleTexture", "FlashbangBottleTextureLocalized.png", 1024, 1024),
			["WelcomeMatTex"] = new TextureSpec("WelcomeMatTex", "WelcomeMatTexLocalized.png", 1024, 1024),
			["AirhornTex"] = new TextureSpec("AirhornTex", "AirhornTexLocalized.png", 512, 512),
			["TetraChemicalTex"] = new TextureSpec("TetraChemicalTex", "TetraChemicalTexLocalized.png", 2048, 2048),
			["SprayCanTex"] = new TextureSpec("SprayCanTex", "SprayCanTexLocalized.png", 1024, 1024),
			["StopSignTex"] = new TextureSpec("StopSignTex", "StopSignTexLocalized.png", 1024, 1024),
			["YieldSignTex"] = new TextureSpec("YieldSignTex", "YieldSignTexLocalized.png", 512, 512),
			["SodaCanTex1"] = new TextureSpec("SodaCanTex1", "SodaCanTex1Localized.png", 1024, 1024),
			["ToothpasteTex"] = new TextureSpec("ToothpasteTex", "ToothpasteTexLocalized.png", 1024, 1024),
			["WeedKillerBottleTex"] = new TextureSpec("WeedKillerBottleTex", "WeedKillerBottleTexLocalized.png", 1024, 1024),
			["WhoopieCushionTex"] = new TextureSpec("WhoopieCushionTex", "WhoopieCushionTexLocalized.png", 1024, 1024),
			["YellowMineDoorTex"] = new TextureSpec("YellowMineDoorTex", "YellowMineDoorTexLocalized.png", 1024, 1024),
			["ChemicalBottle1"] = new TextureSpec("ChemicalBottle1", "ChemicalBottle1Localized.png", 1024, 1024),
			["powerBoxTextures"] = new TextureSpec("powerBoxTextures", "powerBoxTexturesLocalized.png", 1024, 820),
			["PlayerLevelStickers"] = new TextureSpec("PlayerLevelStickers", "PlayerLevelStickersLocalized.png", 256, 512),
			["PlayerLevelStickers 1"] = new TextureSpec("PlayerLevelStickers 1", "PlayerVipEmployeeStickerLocalized.png", 512, 128),
			["CompanyCruiserCombined4Diffuse 1"] = new TextureSpec("CompanyCruiserCombined4Diffuse 1", "CompanyCruiserDestroyedDiffuseLocalized.dxt1", 4096, 4096, precompressedBc1: true),
			["CompanyCruiserCombined4DiffuseDirtyV2"] = new TextureSpec("CompanyCruiserCombined4DiffuseDirtyV2", "CompanyCruiserIntactDiffuseLocalized.bc7", 4096, 4096, precompressedBc1: false, precompressedBc3: false, precompressedBc7: true)
		};

		private static readonly Dictionary<string, Texture2D> LocalizedTextures = new Dictionary<string, Texture2D>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> FailedTextures = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

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

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

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

		private static EnvironmentCleanupGate ObjectCleanupGate;

		private static Texture2D? _fireExitLabelTexture;

		private static Material? _fireExitLabelMaterial;

		private static Material? _fireExitHiddenMaterial;

		private static Mesh? _fireExitOverlayMesh;

		private static string _textureDirectory = string.Empty;

		private static bool _initialized;

		private static EnvironmentLevelScan? _levelScan;

		private static RoundManager? _levelScanOwner;

		private static int _levelScanFrame;

		private static bool _levelCleanupPending;

		public static void Initialize(string pluginDir)
		{
			CancelLevelScan();
			_textureDirectory = Path.Combine(pluginDir, "textures");
			ObjectCleanupGate.Reset();
			_initialized = true;
		}

		public static void ApplyShipEnvironment(StartOfRound? startOfRound)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!CanApply() || (Object)(object)startOfRound == (Object)null)
			{
				return;
			}
			PruneDestroyedRendererStates();
			PruneUnusedMaterialStates();
			Scene scene = ((Component)startOfRound).gameObject.scene;
			if (!((Scene)(ref scene)).IsValid() || !((Scene)(ref scene)).isLoaded)
			{
				return;
			}
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			foreach (GameObject val in rootGameObjects)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				RendererScanBuffer.Clear();
				val.GetComponentsInChildren<Renderer>(true, RendererScanBuffer);
				foreach (Renderer item in RendererScanBuffer)
				{
					ApplyToRenderer(item);
				}
			}
			RendererScanBuffer.Clear();
		}

		public static void ApplyVehicle(VehicleController? vehicle)
		{
			if (!CanApply() || (Object)(object)vehicle == (Object)null)
			{
				return;
			}
			PruneDestroyedRendererStates();
			PruneUnusedMaterialStates();
			RendererScanBuffer.Clear();
			((Component)vehicle).GetComponentsInChildren<Renderer>(false, RendererScanBuffer);
			foreach (Renderer item in RendererScanBuffer)
			{
				ApplyToRenderer(item);
			}
			RendererScanBuffer.Clear();
		}

		public static void ApplyLevelEnvironment(RoundManager? roundManager)
		{
			if (CanApply() && !((Object)(object)roundManager == (Object)null))
			{
				CancelLevelScan();
				_levelScanOwner = roundManager;
				_levelScan = new EnvironmentLevelScan(ApplyLevelRenderer);
				_levelCleanupPending = true;
				_levelScanFrame = Time.frameCount;
				MenuRuntimeHost.Ensure();
			}
		}

		internal static void PumpPendingLevelScan()
		{
			if (_levelScan == null)
			{
				return;
			}
			if (!CanApply() || (Object)(object)_levelScanOwner == (Object)null)
			{
				CancelLevelScan();
			}
			else
			{
				if (_levelScanFrame == Time.frameCount)
				{
					return;
				}
				_levelScanFrame = Time.frameCount;
				EnvironmentLevelScan levelScan = _levelScan;
				try
				{
					if (_levelCleanupPending)
					{
						PruneDestroyedRendererStates();
						PruneDestroyedFireExitStates();
						PruneUnusedMaterialStates();
						_levelCleanupPending = false;
					}
					else if (!levelScan.Pump() && levelScan == _levelScan)
					{
						CancelLevelScan();
					}
				}
				catch (Exception ex)
				{
					if (levelScan == _levelScan)
					{
						CancelLevelScan();
					}
					Plugin.Log.LogWarning((object)("Environment scan failed: " + ex.GetType().Name + ": " + ex.Message));
				}
				finally
				{
					UnchangedMaterialIdsThisPass.Clear();
				}
			}
		}

		private static void ApplyLevelRenderer(Renderer renderer)
		{
			try
			{
				ApplyToRenderer(renderer, cacheUnchangedMaterials: true);
				TryApplyFireExitDoor(renderer);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Environment renderer localization failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static void CancelLevelScan()
		{
			EnvironmentLevelScan? levelScan = _levelScan;
			_levelScan = null;
			_levelScanOwner = null;
			_levelCleanupPending = false;
			levelScan?.Dispose();
			UnchangedMaterialIdsThisPass.Clear();
		}

		public static void ApplyGrabbableObject(GrabbableObject? grabbableObject)
		{
			if (!CanApply() || (Object)(object)grabbableObject == (Object)null || !IsLocalizedScrap(((Object)((Component)grabbableObject).gameObject).name))
			{
				return;
			}
			PruneObjectStatesOncePerFrame();
			RendererScanBuffer.Clear();
			((Component)grabbableObject).GetComponentsInChildren<Renderer>(true, RendererScanBuffer);
			foreach (Renderer item in RendererScanBuffer)
			{
				ApplyToRenderer(item);
			}
			RendererScanBuffer.Clear();
		}

		public static void ApplyShipDecoration(AutoParentToShip? shipDecoration)
		{
			if (!CanApply() || (Object)(object)shipDecoration == (Object)null || !IsLocalizedShipDecoration(((Object)((Component)shipDecoration).gameObject).name))
			{
				return;
			}
			PruneObjectStatesOncePerFrame();
			RendererScanBuffer.Clear();
			((Component)shipDecoration).GetComponentsInChildren<Renderer>(true, RendererScanBuffer);
			foreach (Renderer item in RendererScanBuffer)
			{
				ApplyToRenderer(item);
			}
			RendererScanBuffer.Clear();
		}

		public static void ApplyPlayerBadges(PlayerControllerB? playerController)
		{
			if (CanApply() && !((Object)(object)playerController == (Object)null))
			{
				PruneObjectStatesOncePerFrame();
				ApplyToRenderer(((Object)(object)playerController.playerBadgeMesh != (Object)null) ? ((Component)playerController.playerBadgeMesh).GetComponent<Renderer>() : null);
				ApplyToRenderer((Renderer?)(object)playerController.playerBetaBadgeMesh);
			}
		}

		public static void Shutdown()
		{
			CancelLevelScan();
			foreach (RendererState value in RendererStates.Values)
			{
				try
				{
					if ((Object)(object)value.Renderer != (Object)null)
					{
						value.Renderer.sharedMaterials = value.OriginalMaterials;
					}
				}
				catch
				{
				}
			}
			RendererStates.Clear();
			foreach (FireExitState value2 in FireExitStates.Values)
			{
				try
				{
					if ((Object)(object)value2.Renderer != (Object)null)
					{
						value2.Renderer.sharedMaterials = value2.OriginalMaterials;
					}
				}
				catch
				{
				}
				DestroyUnityObject((Object?)(object)value2.Overlay);
			}
			FireExitStates.Clear();
			foreach (MaterialState value3 in MaterialStates.Values)
			{
				DestroyUnityObject((Object?)(object)value3.Localized);
			}
			MaterialStates.Clear();
			RendererScanBuffer.Clear();
			ActiveLocalizedMaterialIds.Clear();
			UnchangedMaterialIdsThisPass.Clear();
			foreach (Texture2D value4 in LocalizedTextures.Values)
			{
				DestroyUnityObject((Object?)(object)value4);
			}
			LocalizedTextures.Clear();
			FailedTextures.Clear();
			DestroyUnityObject((Object?)(object)_fireExitLabelMaterial);
			DestroyUnityObject((Object?)(object)_fireExitHiddenMaterial);
			DestroyUnityObject((Object?)(object)_fireExitOverlayMesh);
			DestroyUnityObject((Object?)(object)_fireExitLabelTexture);
			_fireExitLabelMaterial = null;
			_fireExitHiddenMaterial = null;
			_fireExitOverlayMesh = null;
			_fireExitLabelTexture = null;
			_textureDirectory = string.Empty;
			ObjectCleanupGate.Reset();
			_initialized = false;
		}

		public static void OnSceneUnloaded()
		{
			RoundManager levelScanOwner = _levelScanOwner;
			CancelLevelScan();
			PruneDestroyedRendererStates();
			PruneDestroyedFireExitStates();
			PruneUnusedMaterialStates();
			ObjectCleanupGate.Reset();
			if ((Object)(object)levelScanOwner != (Object)null)
			{
				ApplyLevelEnvironment(levelScanOwner);
			}
		}

		private static bool CanApply()
		{
			if (_initialized)
			{
				return !Plugin.IsRuntimeShuttingDown;
			}
			return false;
		}

		private static bool IsLocalizedScrap(string? objectName)
		{
			if (string.IsNullOrWhiteSpace(objectName))
			{
				return false;
			}
			if (!objectName.StartsWith("ToiletPaperRolls", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("CashRegisterItem", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("DiyFlashbang", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("Airhorn", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("TZPChemical", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("SprayPaint", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("StopSign", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("YieldSign", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("RedSodaCan", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("Toothpaste", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("WeedKillerItem", StringComparison.OrdinalIgnoreCase) && !objectName.StartsWith("WhoopieCushion", StringComparison.OrdinalIgnoreCase))
			{
				return objectName.StartsWith("ChemicalJug", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static bool IsLocalizedShipDecoration(string? objectName)
		{
			if (!string.IsNullOrWhiteSpace(objectName))
			{
				return objectName.StartsWith("WelcomeMatContainer", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		private static void TryApplyFireExitDoor(Renderer? renderer)
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			if ((Object)(object)renderer == (Object)null || FireExitStates.ContainsKey(((Object)renderer).GetInstanceID()) || !string.Equals(((Object)((Component)renderer).gameObject).name, "Cube.001", StringComparison.Ordinal) || (Object)(object)((Component)renderer).transform.parent == (Object)null || !((Object)((Component)((Component)renderer).transform.parent).gameObject).name.StartsWith("FireExitDoor", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>();
			Mesh val = ((component != null) ? component.sharedMesh : null);
			Material[] sharedMaterials = renderer.sharedMaterials;
			if ((Object)(object)val == (Object)null || !string.Equals(((Object)val).name, "Cube.001", StringComparison.Ordinal) || val.subMeshCount != 3 || sharedMaterials == null || sharedMaterials.Length != 3)
			{
				return;
			}
			Material val2 = EnsureFireExitHiddenMaterial();
			Material val3 = EnsureFireExitLabelMaterial();
			Mesh val4 = EnsureFireExitOverlayMesh();
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null)
			{
				return;
			}
			GameObject val5 = null;
			try
			{
				Material[] array = (Material[])sharedMaterials.Clone();
				array[2] = val2;
				renderer.sharedMaterials = array;
				val5 = new GameObject("FireExitDoorLabel (zh-CN)")
				{
					layer = ((Component)renderer).gameObject.layer
				};
				val5.transform.SetParent(((Component)renderer).transform, false);
				val5.AddComponent<MeshFilter>().sharedMesh = val4;
				MeshRenderer obj = val5.AddComponent<MeshRenderer>();
				((Renderer)obj).sharedMaterial = val3;
				((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)obj).receiveShadows = false;
				((Renderer)obj).lightProbeUsage = (LightProbeUsage)0;
				((Renderer)obj).reflectionProbeUsage = (ReflectionProbeUsage)0;
				FireExitStates[((Object)renderer).GetInstanceID()] = new FireExitState(renderer, sharedMaterials, val5);
			}
			catch (Exception ex)
			{
				renderer.sharedMaterials = sharedMaterials;
				DestroyUnityObject((Object?)(object)val5);
				Plugin.Log.LogWarning((object)("Fire-exit localization failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static Texture2D? EnsureFireExitLabelTexture()
		{
			if ((Object)(object)_fireExitLabelTexture != (Object)null)
			{
				return _fireExitLabelTexture;
			}
			string text = Path.Combine(_textureDirectory, "FireExitDoorLabelLocalized.png");
			try
			{
				FileInfo fileInfo = new FileInfo(text);
				if (!fileInfo.Exists || fileInfo.Length <= 0 || fileInfo.Length > 1048576)
				{
					throw new InvalidDataException("missing or invalid fire-exit label texture");
				}
				byte[] data = File.ReadAllBytes(text);
				Texture2D val = LoadTextureData(data, useRuntimeCompression: true) ?? LoadTextureData(data, useRuntimeCompression: false);
				if ((Object)(object)val == (Object)null || ((Texture)val).width != 512 || ((Texture)val).height != 128)
				{
					DestroyUnityObject((Object?)(object)val);
					throw new InvalidDataException("fire-exit label texture must be 512x128");
				}
				((Object)val).name = "FireExitDoorLabel (zh-CN)";
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Texture)val).filterMode = (FilterMode)1;
				_fireExitLabelTexture = val;
				return val;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Fire-exit label load failed: " + ex.GetType().Name + ": " + ex.Message));
				return null;
			}
		}

		private static Shader? FindTransparentShader()
		{
			return Shader.Find("Unlit/Transparent") ?? Shader.Find("Sprites/Default");
		}

		private static Material? EnsureFireExitLabelMaterial()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			if ((Object)(object)_fireExitLabelMaterial != (Object)null)
			{
				return _fireExitLabelMaterial;
			}
			Shader val = FindTransparentShader();
			Texture2D val2 = EnsureFireExitLabelTexture();
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return null;
			}
			_fireExitLabelMaterial = new Material(val)
			{
				name = "FireExitDoorLabelMaterial (zh-CN)",
				mainTexture = (Texture)(object)val2,
				color = Color.white,
				renderQueue = 3000
			};
			return _fireExitLabelMaterial;
		}

		private static Material? EnsureFireExitHiddenMaterial()
		{
			//IL_0025: 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_0035: 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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			if ((Object)(object)_fireExitHiddenMaterial != (Object)null)
			{
				return _fireExitHiddenMaterial;
			}
			Shader val = FindTransparentShader();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			_fireExitHiddenMaterial = new Material(val)
			{
				name = "FireExitDoorOriginalTextHidden (zh-CN)",
				color = Color.clear,
				renderQueue = 3000
			};
			return _fireExitHiddenMaterial;
		}

		private static Mesh EnsureFireExitOverlayMesh()
		{
			//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)
			//IL_0024: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_00f6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_fireExitOverlayMesh != (Object)null)
			{
				return _fireExitOverlayMesh;
			}
			Mesh val = new Mesh
			{
				name = "FireExitDoorLabelQuad (zh-CN)"
			};
			val.vertices = (Vector3[])(object)new Vector3[4]
			{
				new Vector3(1.08f, -34f, -43.6f),
				new Vector3(1.08f, 34f, -43.6f),
				new Vector3(1.08f, 34f, -27.8f),
				new Vector3(1.08f, -34f, -27.8f)
			};
			val.uv = (Vector2[])(object)new Vector2[4]
			{
				new Vector2(1f, 1f),
				new Vector2(0f, 1f),
				new Vector2(0f, 0f),
				new Vector2(1f, 0f)
			};
			val.triangles = new int[6] { 0, 1, 2, 0, 2, 3 };
			val.RecalculateBounds();
			_fireExitOverlayMesh = val;
			return val;
		}

		private static void ApplyToRenderer(Renderer? renderer, bool cacheUnchangedMaterials = false)
		{
			if ((Object)(object)renderer == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)renderer).GetInstanceID();
			if (RendererStates.TryGetValue(instanceID, out RendererState value))
			{
				if ((Object)(object)value.Renderer != (Object)null && (Object)(object)value.Renderer == (Object)(object)renderer)
				{
					return;
				}
				RendererStates.Remove(instanceID);
			}
			Material[] sharedMaterials = renderer.sharedMaterials;
			if (sharedMaterials == null || sharedMaterials.Length == 0)
			{
				return;
			}
			Material[] array = null;
			List<int> list = null;
			bool flag = false;
			for (int i = 0; i < sharedMaterials.Length; i++)
			{
				Material val = sharedMaterials[i];
				Material orCreateLocalizedMaterial = GetOrCreateLocalizedMaterial(val, cacheUnchangedMaterials);
				if (!((Object)(object)orCreateLocalizedMaterial == (Object)null) && orCreateLocalizedMaterial != val)
				{
					if (array == null)
					{
						array = (Material[])sharedMaterials.Clone();
					}
					array[i] = orCreateLocalizedMaterial;
					if (list == null)
					{
						list = new List<int>();
					}
					int instanceID2 = ((Object)val).GetInstanceID();
					if (!list.Contains(instanceID2))
					{
						list.Add(instanceID2);
					}
					flag = true;
				}
			}
			if (flag && array != null)
			{
				renderer.sharedMaterials = array;
				RendererStates[instanceID] = new RendererState(renderer, sharedMaterials, list ?? new List<int>());
			}
		}

		private static Material? GetOrCreateLocalizedMaterial(Material? original, bool cacheUnchangedMaterials)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			if ((Object)(object)original == (Object)null)
			{
				return null;
			}
			int instanceID = ((Object)original).GetInstanceID();
			if (cacheUnchangedMaterials && UnchangedMaterialIdsThisPass.Contains(instanceID))
			{
				return original;
			}
			if (MaterialStates.TryGetValue(instanceID, out MaterialState value))
			{
				if (value.HasOriginal(original) && (Object)(object)value.Localized != (Object)null)
				{
					return value.Localized;
				}
				DestroyUnityObject((Object?)(object)value.Localized);
				MaterialStates.Remove(instanceID);
			}
			Material val = null;
			bool flag = false;
			string[] texturePropertyNames = TexturePropertyNames;
			foreach (string text in texturePropertyNames)
			{
				if (!original.HasProperty(text) || !TryResolveSpec(original.GetTexture(text), out TextureSpec spec))
				{
					continue;
				}
				Texture2D val2 = EnsureTextureLoaded(spec, original.GetTexture(text));
				if (!((Object)(object)val2 == (Object)null))
				{
					if (val == null)
					{
						val = new Material(original);
					}
					val.SetTexture(text, (Texture)(object)val2);
					flag = true;
				}
			}
			if (!flag && original.HasProperty("_MainTex") && TryResolveSpec(original.mainTexture, out TextureSpec spec2))
			{
				Texture2D val3 = EnsureTextureLoaded(spec2, original.mainTexture);
				if ((Object)(object)val3 != (Object)null)
				{
					val = new Material(original)
					{
						mainTexture = (Texture)(object)val3
					};
					flag = true;
				}
			}
			if (!flag || (Object)(object)val == (Object)null)
			{
				DestroyUnityObject((Object?)(object)val);
				if (cacheUnchangedMaterials)
				{
					UnchangedMaterialIdsThisPass.Add(instanceID);
				}
				return original;
			}
			UnchangedMaterialIdsThisPass.Remove(instanceID);
			((Object)val).name = NormalizeName(((Object)original).name) + " (zh-CN)";
			if (MaterialStates.TryGetValue(instanceID, out MaterialState value2))
			{
				DestroyUnityObject((Object?)(object)value2.Localized);
			}
			MaterialStates[instanceID] = new MaterialState(original, val);
			return val;
		}

		private static Texture2D? EnsureTextureLoaded(TextureSpec spec, Texture? originalTexture)
		{
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			if (LocalizedTextures.TryGetValue(spec.OriginalName, out Texture2D value))
			{
				return value;
			}
			if (FailedTextures.Contains(spec.OriginalName))
			{
				return null;
			}
			string text = Path.Combine(_textureDirectory, spec.FileName);
			Texture2D val = null;
			try
			{
				FileInfo fileInfo = new FileInfo(text);
				if (!fileInfo.Exists)
				{
					throw new FileNotFoundException("localized texture file is missing", text);
				}
				if (fileInfo.Length <= 0 || (!spec.PrecompressedBc1 && !spec.PrecompressedBc3 && !spec.PrecompressedBc7 && fileInfo.Length > 16777216))
				{
					throw new InvalidDataException($"invalid file size ({fileInfo.Length} bytes)");
				}
				if (spec.PrecompressedBc1)
				{
					val = PrecompressedTextureLoader.LoadBc1(text, spec.Width, spec.Height, spec.MipChain, out string error);
					if ((Object)(object)val == (Object)null)
					{
						throw new InvalidDataException(error ?? "precompressed BC1 load failed");
					}
				}
				else if (spec.PrecompressedBc3)
				{
					val = PrecompressedTextureLoader.LoadBc3(text, spec.Width, spec.Height, spec.MipChain, out string error2);
					if ((Object)(object)val == (Object)null)
					{
						throw new InvalidDataException(error2 ?? "precompressed BC3 load failed");
					}
				}
				else if (spec.PrecompressedBc7)
				{
					val = PrecompressedTextureLoader.LoadBc7(text, spec.Width, spec.Height, spec.MipChain, out string error3);
					if ((Object)(object)val == (Object)null)
					{
						throw new InvalidDataException(error3 ?? "precompressed BC7 load failed");
					}
				}
				else
				{
					byte[] data = File.ReadAllBytes(text);
					val = LoadTextureData(data, useRuntimeCompression: true) ?? LoadTextureData(data, useRuntimeCompression: false);
				}
				if ((Object)(object)val == (Object)null || ((Texture)val).width != spec.Width || ((Texture)val).height != spec.Height)
				{
					string arg = (((Object)(object)val == (Object)null) ? "decode failed" : $"{((Texture)val).width}x{((Texture)val).height}");
					throw new InvalidDataException($"expected {spec.Width}x{spec.Height}, got {arg}");
				}
				((Object)val).name = spec.OriginalName + " (zh-CN)";
				if ((Object)(object)originalTexture != (Object)null)
				{
					((Texture)val).wrapMode = originalTexture.wrapMode;
					((Texture)val).filterMode = originalTexture.filterMode;
					((Texture)val).anisoLevel = originalTexture.anisoLevel;
					((Texture)val).mipMapBias = originalTexture.mipMapBias;
				}
				LocalizedTextures[spec.OriginalName] = val;
				return val;
			}
			catch (Exception ex)
			{
				DestroyUnityObject((Object?)(object)val);
				FailedTextures.Add(spec.OriginalName);
				Plugin.Log.LogWarning((object)("Environment texture localization failed for " + spec.FileName + ": " + ex.GetType().Name + ": " + ex.Message));
				return null;
			}
		}

		private static Texture2D? LoadTextureData(byte[] data, bool useRuntimeCompression)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Texture2D val = null;
			try
			{
				TextureFormat val2 = (TextureFormat)((useRuntimeCompression && SystemInfo.SupportsTextureFormat((TextureFormat)12)) ? 12 : 4);
				int num = (((int)val2 == 12) ? 4 : 2);
				val = new Texture2D(num, num, val2, true);
				if (ImageConversion.LoadImage(val, data, true))
				{
					return val;
				}
				DestroyUnityObject((Object?)(object)val);
				return null;
			}
			catch
			{
				DestroyUnityObject((Object?)(object)val);
				return null;
			}
		}

		private static bool TryResolveSpec(Texture? texture, out TextureSpec spec)
		{
			return TextureSpecs.TryGetValue(NormalizeName((texture != null) ? ((Object)texture).name : null), out spec);
		}

		private static string NormalizeName(string? name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return string.Empty;
			}
			string text = name.Trim();
			if (text.EndsWith(" (Instance)", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(0, text.Length - " (Instance)".Length);
			}
			if (text.EndsWith(" (zh-CN)", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(0, text.Length - " (zh-CN)".Length);
			}
			return text;
		}

		private static void PruneObjectStatesOncePerFrame()
		{
			int frameCount = Time.frameCount;
			if (ObjectCleanupGate.NeedsCleanup(frameCount))
			{
				PruneDestroyedRendererStates();
				PruneUnusedMaterialStates();
				ObjectCleanupGate.Complete(frameCount);
			}
		}

		private static void PruneDestroyedRendererStates()
		{
			List<int> list = null;
			foreach (KeyValuePair<int, RendererState> rendererState in RendererStates)
			{
				if (!((Object)(object)rendererState.Value.Renderer != (Object)null))
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(rendererState.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item in list)
			{
				RendererStates.Remove(item);
			}
		}

		private static void PruneDestroyedFireExitStates()
		{
			List<int> list = null;
			foreach (KeyValuePair<int, FireExitState> fireExitState in FireExitStates)
			{
				if (!((Object)(object)fireExitState.Value.Renderer != (Object)null) || !((Object)(object)fireExitState.Value.Overlay != (Object)null))
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(fireExitState.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item in list)
			{
				FireExitStates.Remove(item);
			}
		}

		private static void PruneUnusedMaterialStates()
		{
			ActiveLocalizedMaterialIds.Clear();
			foreach (RendererState value in RendererStates.Values)
			{
				if ((Object)(object)value.Renderer == (Object)null)
				{
					continue;
				}
				foreach (int localizedMaterialId in value.LocalizedMaterialIds)
				{
					ActiveLocalizedMaterialIds.Add(localizedMaterialId);
				}
			}
			List<int> list = null;
			foreach (KeyValuePair<int, MaterialState> materialState in MaterialStates)
			{
				if (!((Object)(object)materialState.Value.Localized != (Object)null) || !materialState.Value.HasLiveOriginal() || !ActiveLocalizedMaterialIds.Contains(materialState.Key))
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(materialState.Key);
					DestroyUnityObject((Object?)(object)materialState.Value.Localized);
				}
			}
			if (list != null)
			{
				foreach (int item in list)
				{
					MaterialStates.Remove(item);
				}
			}
			ActiveLocalizedMaterialIds.Clear();
		}

		private static void DestroyUnityObject(Object? value)
		{
			if (!(value == (Object)null))
			{
				if (Application.isPlaying)
				{
					Object.Destroy(value);
				}
				else
				{
					Object.DestroyImmediate(value);
				}
			}
		}
	}
	internal static class PrecompressedTextureLoader
	{
		public static Texture2D? LoadBc1(string path, int width, int height, bool mipChain, out string? error)
		{
			return LoadCompressed(path, width, height, mipChain, (TextureFormat)10, 8, "DXT1/BC1", out error);
		}

		public static Texture2D? LoadBc3(string path, int width, int height, bool mipChain, out string? error)
		{
			return LoadCompressed(path, width, height, mipChain, (TextureFormat)12, 16, "DXT5/BC3", out error);
		}

		public static Texture2D? LoadBc7(string path, int width, int height, bool mipChain, out string? error)
		{
			return LoadCompressed(path, width, height, mipChain, (TextureFormat)25, 16, "BC7", out error);
		}

		private static Texture2D? LoadCompressed(string path, int width, int height, bool mipChain, TextureFormat format, int bytesPerBlock, string formatName, out string? error)
		{
			//IL_0006: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			error = null;
			Texture2D val = null;
			try
			{
				if (!SystemInfo.SupportsTextureFormat(format))
				{
					error = formatName + " is not supported by this graphics device";
					return null;
				}
				FileInfo fileInfo = new FileInfo(path);
				if (!fileInfo.Exists)
				{
					error = "precompressed texture file is missing";
					return null;
				}
				long num = CalculateCompressedByteCount(width, height, mipChain, bytesPerBlock);
				if (fileInfo.Length != num)
				{
					error = $"expected {num} bytes, got {fileInfo.Length}";
					return null;
				}
				byte[] array = File.ReadAllBytes(path);
				val = new Texture2D(width, height, format, mipChain);
				val.LoadRawTextureData(array);
				val.Apply(false, true);
				return val;
			}
			catch (Exception ex)
			{
				DestroyUnityObject((Object?)(object)val);
				error = ex.GetType().Name + ": " + ex.Message;
				return null;
			}
		}

		public static long CalculateBc3ByteCount(int width, int height, bool mipChain)
		{
			return CalculateCompressedByteCount(width, height, mipChain, 16);
		}

		public static long CalculateBc7ByteCount(int width, int height, bool mipChain)
		{
			return CalculateCompressedByteCount(width, height, mipChain, 16);
		}

		public static long CalculateBc1ByteCount(int width, int height, bool mipChain)
		{
			return CalculateCompressedByteCount(width, height, mipChain, 8);
		}

		private static long CalculateCompressedByteCount(int width, int height, bool mipChain, int bytesPerBlock)
		{
			long num = 0L;
			while (true)
			{
				num += (long)Math.Max(1, (width + 3) / 4) * (long)Math.Max(1, (height + 3) / 4) * bytesPerBlock;
				if (!mipChain || (width == 1 && height == 1))
				{
					break;
				}
				width = Math.Max(1, width / 2);
				height = Math.Max(1, height / 2);
			}
			return num;
		}

		private static void DestroyUnityObject(Object? value)
		{
			if (!(value == (Object)null))
			{
				if (Application.isPlaying)
				{
					Object.Destroy(value);
				}
				else
				{
					Object.DestroyImmediate(value);
				}
			}
		}
	}
	internal static class RadiationWarningAuditService
	{
		internal const string WarningRootPathSuffix = "IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease";

		private static ConfigEntry<bool>? _enabled;

		private static ConfigEntry<int>? _sampleCount;

		private static ConfigEntry<float>? _sampleIntervalSeconds;

		private static HUDManager? _activeHudManager;

		private static Coroutine? _activeAuditCoroutine;

		public static void Initialize(ConfigFile config)
		{
			_enabled = config.Bind<bool>("90 诊断 - 辐射警告审计", "Enabled", false, "启用辐射警告原始 UI 子树的限量采样诊断。默认关闭,避免运行时枚举 UI 子树。");
			_sampleCount = config.Bind<int>("90 诊断 - 辐射警告审计", "SampleCount", 5, "辐射警告触发后采样的次数上限。");
			_sampleIntervalSeconds = config.Bind<float>("90 诊断 - 辐射警告审计", "SampleIntervalSeconds", 0.2f, "两次辐射警告诊断采样之间的间隔,单位为秒。");
		}

		public static void Shutdown()
		{
			try
			{
				if (_activeAuditCoroutine != null && (Object)(object)_activeHudManager != (Object)null)
				{
					((MonoBehaviour)_activeHudManager).StopCoroutine(_activeAuditCoroutine);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("RadiationWarningAuditService shutdown failed while stopping coroutine: " + ex.GetType().Name + ": " + ex.Message));
			}
			finally
			{
				_activeAuditCoroutine = null;
				_activeHudManager = null;
				_enabled = null;
				_sampleCount = null;
				_sampleIntervalSeconds = null;
			}
		}

		public static void OnRadiationWarningTriggered(HUDManager hudManager, string stage)
		{
			if ((Object)(object)hudManager == (Object)null)
			{
				return;
			}
			ConfigEntry<bool>? enabled = _enabled;
			if (enabled == null || !enabled.Value)
			{
				return;
			}
			if ((Object)(object)FindWarningRoot(hudManager) == (Object)null)
			{
				Plugin.Log.LogWarning((object)("RadiationAudit[" + stage + "] action=root-not-found suffix=IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease"));
				return;
			}
			if (_activeAuditCoroutine != null && (Object)(object)_activeHudManager != (Object)null)
			{
				((MonoBehaviour)_activeHudManager).StopCoroutine(_activeAuditCoroutine);
				_activeAuditCoroutine = null;
			}
			_activeHudManager = hudManager;
			_activeAuditCoroutine = ((MonoBehaviour)hudManager).StartCoroutine(SampleWarningSubtree(hudManager, stage, _sampleCount?.Value ?? 0, _sampleIntervalSeconds?.Value ?? 0f));
		}

		private static IEnumerator SampleWarningSubtree(HUDManager hudManager, string stage, int sampleCount, float sampleIntervalSeconds)
		{
			int boundedSampleCount = Mathf.Max(1, sampleCount);
			float boundedIntervalSeconds = Mathf.Max(0f, sampleIntervalSeconds);
			for (int sampleIndex = 0; sampleIndex < boundedSampleCount; sampleIndex++)
			{
				if ((Object)(object)hudManager == (Object)null)
				{
					break;
				}
				Transform val = FindWarningRoot(hudManager);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogInfo((object)string.Format("RadiationAudit[{0}] sample={1} action=sampling-stopped-root-lost suffix={2}", stage, sampleIndex, "IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease"));
					break;
				}
				AuditImages(val, stage, sampleIndex);
				AuditRawImages(val, stage, sampleIndex);
				AuditSpriteRenderers(val, stage, sampleIndex);
				AuditGraphicMaterials(val, stage, sampleIndex);
				AuditRendererMaterials(val, stage, sampleIndex);
				if (sampleIndex + 1 < boundedSampleCount)
				{
					yield return (object)((!(boundedIntervalSeconds > 0f)) ? ((WaitForSeconds)null) : new WaitForSeconds(boundedIntervalSeconds));
				}
			}
			_activeAuditCoroutine = null;
			_activeHudManager = null;
		}

		private static void AuditGraphicMaterials(Transform root, string stage, int sampleIndex)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			HashSet<int> hashSet = new HashSet<int>();
			Graphic[] componentsInChildren = ((Component)root).GetComponentsInChildren<Graphic>(true);
			foreach (Graphic val in componentsInChildren)
			{
				Material material;
				try
				{
					material = val.material;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)$"RadiationAudit[{stage}] sample={sampleIndex} component=GraphicMaterial path={BuildPath(((Component)val).transform)} active={((Component)val).gameObject.activeInHierarchy} enabled={((Behaviour)val).enabled} alpha={val.color.a:0.###} material=<error> texture=<error> error={ex.GetType().Name}:{ex.Message}");
					continue;
				}
				if ((Object)(object)material != (Object)null)
				{
					hashSet.Add(((Object)material).GetInstanceID());
				}
			}
		}

		private static void AuditRendererMaterials(Transform root, string stage, int sampleIndex)
		{
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
				if (sharedMaterials != null && sharedMaterials.Length != 0)
				{
					for (int j = 0; j < sharedMaterials.Length; j++)
					{
						_ = sharedMaterials[j];
					}
				}
			}
		}

		private static void AuditImages(Transform root, string stage, int sampleIndex)
		{
			Image[] componentsInChildren = ((Component)root).GetComponentsInChildren<Image>(true);
			foreach (Image val in componentsInChildren)
			{
				Sprite obj = val.overrideSprite ?? val.sprite;
				if (obj != null)
				{
					_ = obj.texture;
				}
			}
		}

		private static void AuditRawImages(Transform root, string stage, int sampleIndex)
		{
			RawImage[] componentsInChildren = ((Component)root).GetComponentsInChildren<RawImage>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				_ = componentsInChildren[i];
			}
		}

		private static void AuditSpriteRenderers(Transform root, string stage, int sampleIndex)
		{
			SpriteRenderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<SpriteRenderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				_ = componentsInChildren[i].sprite;
			}
		}

		private static Transform? FindWarningRoot(HUDManager hudManager)
		{
			Animator radiationGraphicAnimator = hudManager.radiationGraphicAnimator;
			Transform val = ((radiationGraphicAnimator != null) ? ((Component)radiationGraphicAnimator).transform : null);
			if (HasExpectedRootPath(val))
			{
				return val;
			}
			Transform[] componentsInChildren = ((Component)hudManager).GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren)
			{
				if (HasExpectedRootPath(val2))
				{
					return val2;
				}
			}
			return null;
		}

		private static bool HasExpectedRootPath(Transform? transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return false;
			}
			return BuildPath(transform).EndsWith("IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease", StringComparison.OrdinalIgnoreCase);
		}

		private static string DescribeName(Object? obj)
		{
			if (!string.IsNullOrWhiteSpace((obj != null) ? obj.name : null))
			{
				return obj.name;
			}
			return "<null>";
		}

		private static string BuildPath(Transform? transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return "<null>";
			}
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}
	}
	internal static class RadiationWarningPlaybackService
	{
		private const string WarningRootPathSuffix = "IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease";

		private const int NativeWidth = 808;

		private const int NativeHeight = 336;

		private const int NativeTextureCacheLimit = 8;

		private const long MaxTextureBytes = 8388608L;

		private static readonly Dictionary<string, string> FrameFiles = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["RedUIPanelGlitchBWarningRadiation"] = "RedUIPanelGlitchBWarningRadiation [FFCC97E055-2C688E6DC8].png",
			["RedUIPanelGlitchBWarningRadiationB"] = "RedUIPanelGlitchBWarningRadiationB [7D4ED37952-95F686DE01].png",
			["RedUIPanelGlitchBWarningRadiationC"] = "RedUIPanelGlitchBWarningRadiationC [7FBAA1AA30-9E2C036778].png",
			["RedUIPanelGlitchBWarningRadiationD"] = "RedUIPanelGlitchBWarningRadiationD [4877939F7B-47E20481B0].png"
		};

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

		private static readonly Dictionary<Texture, Texture2D?> NativeTextureCache = new Dictionary<Texture, Texture2D>();

		private static ConfigEntry<bool>? _enabled;

		private static Image? _panelImage;

		private static bool _ready;

		public static void Initialize(string pluginDir, ConfigFile config)
		{
			Shutdown();
			_enabled = config.Bind<bool>("04 资源 - 辐射警告", "Enabled", true, "汉化核心装置拔出后的辐射警告贴图,沿用原版动画、闪烁、透明度和位置。");
			foreach (KeyValuePair<string, string> frameFile in FrameFiles)
			{
				Texture2D val = LoadTexture(Path.Combine(pluginDir, "textures", frameFile.Value));
				if ((Object)(object)val != (Object)null)
				{
					LocalizedTextures.Add(frameFile.Key, val);
				}
			}
			_ready = LocalizedTextures.Count == FrameFiles.Count;
			if (!_ready)
			{
				Plugin.Log.LogWarning((object)"Radiation warning textures are incomplete; preserving native rendering.");
			}
		}

		public static void ResetForHudLifecycle(HUDManager hudManager, string stage)
		{
			Image panelImage = _panelImage;
			_panelImage = null;
			NativeTextureCache.Clear();
			if ((Object)(object)panelImage != (Object)null)
			{
				((Graphic)panelImage).SetMaterialDirty();
			}
			AttachPanel(hudManager);
		}

		public static void OnRadiationWarningTriggered(HUDManager hudManager, string stage)
		{
			AttachPanel(hudManager);
		}

		internal static void LocalizeMainTexture(Image image, ref Texture texture)
		{
			if (image != _panelImage || !_ready)
			{
				return;
			}
			ConfigEntry<bool>? enabled = _enabled;
			if (enabled == null || !enabled.Value || (Object)(object)image == (Object)null || (Object)(object)texture == (Object)null || (Object)(object)image.m_OverrideSprite != (Object)null || (Object)(object)image.sprite == (Object)null || (object)image.sprite.texture != texture)
			{
				return;
			}
			if (!NativeTextureCache.TryGetValue(texture, out Texture2D value))
			{
				if (NativeTextureCache.Count >= 8)
				{
					NativeTextureCache.Clear();
				}
				if (texture.width == 808 && texture.height == 336)
				{
					LocalizedTextures.TryGetValue(((Object)texture).name, out value);
				}
				NativeTextureCache.Add(texture, value);
			}
			if ((Object)(object)value != (Object)null)
			{
				texture = (Texture)(object)value;
			}
		}

		public static void Shutdown()
		{
			Image panelImage = _panelImage;
			_panelImage = null;
			_ready = false;
			_enabled = null;
			NativeTextureCache.Clear();
			if ((Object)(object)panelImage != (Object)null)
			{
				((Graphic)panelImage).SetMaterialDirty();
			}
			foreach (Texture2D value in LocalizedTextures.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			LocalizedTextures.Clear();
		}

		private static void AttachPanel(HUDManager hudManager)
		{
			if ((Object)(object)hudManager == (Object)null)
			{
				return;
			}
			Animator radiationGraphicAnimator = hudManager.radiationGraphicAnimator;
			Transform val = ((radiationGraphicAnimator != null) ? ((Component)radiationGraphicAnimator).transform : null);
			if (!HasExpectedRootPath(val))
			{
				return;
			}
			Transform obj = val.Find("Panel");
			Image val2 = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
			if (val2 != _panelImage)
			{
				Image panelImage = _panelImage;
				_panelImage = val2;
				NativeTextureCache.Clear();
				if ((Object)(object)panelImage != (Object)null)
				{
					((Graphic)panelImage).SetMaterialDirty();
				}
				if ((Object)(object)val2 != (Object)null)
				{
					((Graphic)val2).SetMaterialDirty();
				}
			}
		}

		private static bool HasExpectedRootPath(Transform? root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			string text = ((Object)root).name;
			Transform parent = root.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text.EndsWith("IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease", StringComparison.Ordinal);
		}

		private static Texture2D? LoadTexture(string path)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			Texture2D val = null;
			try
			{
				if (!File.Exists(path) || new FileInfo(path).Length > 8388608)
				{
					return null;
				}
				byte[] array = File.ReadAllBytes(path);
				if (!HasExpectedPngDimensions(array))
				{
					return null;
				}
				val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, array, true) || ((Texture)val).width != 808 || ((Texture)val).height != 336)
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				((Object)val).name = Path.GetFileNameWithoutExtension(path);
				((Texture)val).filterMode = (FilterMode)0;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				return val;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				Plugin.Log.LogWarning((object)("Radiation warning texture load failed: " + Path.GetFileName(path) + "; " + ex.GetType().Name + ": " + ex.Message));
				return null;
			}
		}

		private static bool HasExpectedPngDimensions(byte[] data)
		{
			if (data.Length >= 24 && data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 && data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10 && data[12] == 73 && data[13] == 72 && data[14] == 68 && data[15] == 82 && data[16] == 0 && data[17] == 0 && data[18] == 3 && data[19] == 40 && data[20] == 0 && data[21] == 0 && data[22] == 1)
			{
				return data[23] == 80;
			}
			return false;
		}
	}
	internal static class StartupSplashLocalizationService
	{
		private const string TargetTextureName = "flashingLightsWarning";

		private const string LocalizedFileName = "StartupFlashingLightsWarningLocalized.png";

		private const int ExpectedWidth = 800;

		private const int ExpectedHeight = 600;

		private const int MaxStartupAttempts = 24;

		private const int MaxLoggedSprites = 8;

		private static readonly WaitForSecondsRealtime RetryDelay = new WaitForSecondsRealtime(0.05f);

		private static readonly ushort[] FullRectTriangleIndices = new ushort[6] { 0, 1, 2, 2, 3, 0 };

		private static MonoBehaviour? _host;

		private static Coroutine? _retryCoroutine;

		private static ConfigEntry<bool>? _diagnosticsEnabled;

		private static byte[]? _localizedPng;

		private static string _localizedPngSha256 = string.Empty;

		private static bool _diagnosticsEnabledFast;

		private static bool _applied;

		private static int _applyAttempt;

		public static void Initialize(MonoBehaviour host, string pluginDir, ConfigFile config)
		{
			Shutdown();
			_diagnosticsEnabled = config.Bind<bool>("90 诊断 - 通用", "EnableStartupSplashDiagnostics", false, "启用一次性启动警告纹理与 Sprite 几何诊断。仅在启动替换时记录,不增加常驻轮询。");
			_diagnosticsEnabledFast = _diagnosticsEnabled.Value;
			string text = Path.Combine(pluginDir, "textures", "StartupFlashingLightsWarningLocalized.png");
			FileInfo fileInfo = new FileInfo(text);
			if (!fileInfo.Exists || fileInfo.Length <= 0 || fileInfo.Length > 2097152)
			{
				throw new InvalidDataException("Invalid startup splash texture: " + text);
			}
			_host = host;
			_localizedPng = File.ReadAllBytes(text);
			_localizedPngSha256 = ComputeSha256(_localizedPng);
			LogDiagnostic($"stage=initialize pngBytes={_localizedPng.Length} pngSha256={_localizedPngSha256} " + $"splashFinished={SplashScreen.isFinished}");
			if (!TryApply())
			{
				_retryCoroutine = host.StartCoroutine(RetryDuringStartup());
			}
		}

		public static void Shutdown()
		{
			if (_retryCoroutine != null && (Object)(object)_host != (Object)null)
			{
				try
				{
					_host.StopCoroutine(_retryCoroutine);
				}
				catch
				{
				}
			}
			_retryCoroutine = null;
			_host = null;
			_diagnosticsEnabled = null;
			_localizedPng = null;
			_localizedPngSha256 = string.Empty;
			_diagnosticsEnabledFast = false;
			_applied = false;
			_applyAttempt = 0;
		}

		private static IEnumerator RetryDuringStartup()
		{
			for (int attempt = 0; attempt < 24; attempt++)
			{
				yield return RetryDelay;
				if (TryApply())
				{
					_retryCoroutine = null;
					yield break;
				}
				if (attempt >= 2 && SplashScreen.isFinished)
				{
					break;
				}
			}
			_retryCoroutine = null;
			Plugin.Log.LogWarning((object)"Startup splash localization could not find flashingLightsWarning before the native splash finished.");
		}

		private static bool TryApply()
		{
			if (_applied || _localizedPng == null)
			{
				return _applied;
			}
			_applyAttempt++;
			Texture2D[] array = Resources.FindObjectsOfTypeAll<Texture2D>();
			LogDiagnostic($"stage=search attempt={_applyAttempt} loadedTextures={array.Length} " + $"splashFinished={SplashScreen.isFinished}");
			Texture2D[] array2 = array;
			foreach (Texture2D val in array2)
			{
				if ((Object)(object)val == (Object)null || !string.Equals(NormalizeName(((Object)val).name), "flashingLightsWarning", StringComparison.Ordinal))
				{
					continue;
				}
				try
				{
					LogTextureAndReferencingSprites(val, "before-load");
					bool flag = ImageConversion.LoadImage(val, _localizedPng, true);
					LogDiagnostic($"stage=after-load loadSucceeded={flag} pngSha256={_localizedPngSha256} " + DescribeTexture(val));
					if (!flag || ((Texture)val).width != 800 || ((Texture)val).height != 600)
					{
						Plugin.Log.LogWarning((object)$"Startup splash localization produced an invalid texture size: {((Texture)val).width}x{((Texture)val).height}.");
						return false;
					}
					LogTextureAndReferencingSprites(val, "after-load");
					if (!TryOverrideReferencingSpriteGeometry(val))
					{
						Plugin.Log.LogWarning((object)"Startup splash localization could not expand the original Tight Sprite mesh to a full rectangle.");
						return false;
					}
					LogTextureAndReferencingSprites(val, "after-geometry");
					((Object)val).name = "flashingLightsWarning";
					_localizedPng = null;
					_applied = true;
					Plugin.Log.LogInfo((object)"Localized Unity startup flashing-lights warning texture in memory with full-rectangle Sprite geometry.");
					return true;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Startup splash localization failed: " + ex.GetType().Name + ": " + ex.Message));
					return false;
				}
			}
			LogDiagnostic($"stage=search-result attempt={_applyAttempt} matchingTextures=0");
			return false;
		}

		private static bool TryOverrideReferencingSpriteGeometry(Texture2D texture)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown res