Decompiled source of LC Chinese Project v3.1.3

BepInEx/plugins/V81TestChn/V81TestChn.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.UI;
using UnityEngine.Video;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("V81TestChn")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+1facf15d35766b81c56e6948d20291ab6fc9c82c")]
[assembly: AssemblyProduct("V81TestChn")]
[assembly: AssemblyTitle("V81TestChn")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
			}
		}

		[CompilerGenerated]
		private sealed class <WaitForFixedSceneLabels>d__49 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string stage;

			private float <elapsed>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitForFixedSceneLabels>d__49(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<elapsed>5__2 = 0f;
					break;
				case 1:
					<>1__state = -1;
					<elapsed>5__2 += 0.5f;
					break;
				}
				if (<elapsed>5__2 < 8f)
				{
					if (SyncFixedSceneLabelsInRelayScene(stage + ".relay-scene") > 0)
					{
						_fixedSceneLabelWatcher = null;
						_fixedSceneLabelWatcherOwner = null;
						return false;
					}
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 1;
					return true;
				}
				if (Plugin.RuntimeLocalizationLogsEnabled)
				{
					Plugin.Log.LogWarning((object)("NativeRelay[" + stage + ".relay-scene] target=FixedSceneLabel action=timeout"));
				}
				_fixedSceneLabelWatcher = null;
				_fixedSceneLabelWatcherOwner = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <WaitForSystemOnlineTitle>d__48 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public HUDManager hudManager;

			public string stage;

			private float <elapsed>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitForSystemOnlineTitle>d__48(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<elapsed>5__2 = 0f;
					break;
				case 1:
					<>1__state = -1;
					<elapsed>5__2 += 0.25f;
					break;
				}
				if ((Object)(object)hudManager != (Object)null && <elapsed>5__2 < 12f)
				{
					TMP_Text text = FindSystemOnlineTitleByHudPath(hudManager);
					if (IsExactSystemOnlineTitle(text))
					{
						ApplySystemOnlineNativeTranslation(text, stage + ".watcher");
						_systemOnlineWatcher = null;
						_systemOnlineWatcherOwner = null;
						return false;
					}
					<>2__current = (object)new WaitForSeconds(0.25f);
					<>1__state = 1;
					return true;
				}
				if (Plugin.RuntimeLocalizationLogsEnabled)
				{
					Plugin.Log.LogWarning((object)("NativeRelay[" + stage + ".watcher] target=SystemOnline action=timeout"));
				}
				_systemOnlineWatcher = null;
				_systemOnlineWatcherOwner = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		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 Dictionary<int, CachedNativeTextRole> NativeTextRoleCache = new Dictionary<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.Log.LogInfo((object)"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.Log.LogInfo((object)("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.Log.LogInfo((object)("NativeRelay[" + stage + "] target=SystemOnline action=applied name=" + ((Object)text).name + " path=" + BuildPath(text.transform) + " text=" + text.text));
			}
		}

		[IteratorStateMachine(typeof(<WaitForSystemOnlineTitle>d__48))]
		private static IEnumerator WaitForSystemOnlineTitle(HUDManager hudManager, string stage)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitForSystemOnlineTitle>d__48(0)
			{
				hudManager = hudManager,
				stage = stage
			};
		}

		[IteratorStateMachine(typeof(<WaitForFixedSceneLabels>d__49))]
		private static IEnumerator WaitForFixedSceneLabels(string stage)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitForFixedSceneLabels>d__49(0)
			{
				stage = stage
			};
		}

		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.Log.LogInfo((object)$"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.Log.LogInfo((object)("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();
			if (NativeTextRoleCache.Count < RuntimePerformanceSettings.ComponentTextCacheLimit || NativeTextRoleCache.ContainsKey(instanceID))
			{
				NativeTextRoleCache[instanceID] = new CachedNativeTextRole(GetParentInstanceId(text.transform), role);
			}
		}

		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 RadiationWarningAuditService
	{
		[CompilerGenerated]
		private sealed class <SampleWarningSubtree>d__9 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public int sampleCount;

			public float sampleIntervalSeconds;

			public HUDManager hudManager;

			public string stage;

			private int <boundedSampleCount>5__2;

			private float <boundedIntervalSeconds>5__3;

			private int <sampleIndex>5__4;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SampleWarningSubtree>d__9(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0124: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_013e;
				}
				<>1__state = -1;
				<boundedSampleCount>5__2 = Mathf.Max(1, sampleCount);
				<boundedIntervalSeconds>5__3 = Mathf.Max(0f, sampleIntervalSeconds);
				<sampleIndex>5__4 = 0;
				goto IL_014e;
				IL_013e:
				<sampleIndex>5__4++;
				goto IL_014e;
				IL_014e:
				if (<sampleIndex>5__4 < <boundedSampleCount>5__2 && !((Object)(object)hudManager == (Object)null))
				{
					Transform val = FindWarningRoot(hudManager);
					if (!((Object)(object)val == (Object)null))
					{
						AuditImages(val, stage, <sampleIndex>5__4);
						AuditRawImages(val, stage, <sampleIndex>5__4);
						AuditSpriteRenderers(val, stage, <sampleIndex>5__4);
						AuditGraphicMaterials(val, stage, <sampleIndex>5__4);
						AuditRendererMaterials(val, stage, <sampleIndex>5__4);
						if (<sampleIndex>5__4 + 1 < <boundedSampleCount>5__2)
						{
							object obj = this;
							obj = (object)((!(<boundedIntervalSeconds>5__3 > 0f)) ? ((WaitForSeconds)null) : new WaitForSeconds(<boundedIntervalSeconds>5__3));
							((<SampleWarningSubtree>d__9)obj).<>2__current = obj;
							<>1__state = 1;
							return true;
						}
						goto IL_013e;
					}
					Plugin.Log.LogInfo((object)string.Format("RadiationAudit[{0}] sample={1} action=sampling-stopped-root-lost suffix={2}", stage, <sampleIndex>5__4, "IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease"));
				}
				_activeAuditCoroutine = null;
				_activeHudManager = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

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

		[IteratorStateMachine(typeof(<SampleWarningSubtree>d__9))]
		private static IEnumerator SampleWarningSubtree(HUDManager hudManager, string stage, int sampleCount, float sampleIntervalSeconds)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SampleWarningSubtree>d__9(0)
			{
				hudManager = hudManager,
				stage = stage,
				sampleCount = sampleCount,
				sampleIntervalSeconds = sampleIntervalSeconds
			};
		}

		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 sealed class PlaybackState
		{
			public Transform Root { get; }

			public Image PanelImage { get; }

			public Sprite? OriginalRawOverrideSprite { get; }

			public Sprite? LastAppliedLocalizedSprite { get; set; }

			public string? LastAppliedOriginalSpriteName { get; set; }

			public bool CleanupCompleted { get; set; }

			public PlaybackState(Transform root, Image panelImage, Sprite? originalRawOverrideSprite)
			{
				Root = root;
				PanelImage = panelImage;
				OriginalRawOverrideSprite = originalRawOverrideSprite;
			}
		}

		[CompilerGenerated]
		private sealed class <FollowAnimatorSpriteCurve>d__24 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string stage;

			public PlaybackState playbackState;

			private float <endTime>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FollowAnimatorSpriteCurve>d__24(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
					{
						<>1__state = -1;
						float followDurationSeconds = GetFollowDurationSeconds();
						<endTime>5__2 = Time.realtimeSinceStartup + followDurationSeconds;
						Plugin.Log.LogInfo((object)$"RadiationPlayback[{stage}] FollowAnimatorSpriteCurve started path={BuildPath(playbackState.Root)} panel={BuildPath(((Component)playbackState.PanelImage).transform)} duration={followDurationSeconds:0.###}");
						<>1__state = -3;
						break;
					}
					case 1:
						<>1__state = -3;
						break;
					}
					if ((Object)(object)playbackState.PanelImage != (Object)null && Time.realtimeSinceStartup <= <endTime>5__2)
					{
						ApplyCurrentAnimatorSpriteSubstitution(playbackState, stage);
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					if ((Object)(object)playbackState.PanelImage != (Object)null)
					{
						ApplyCurrentAnimatorSpriteSubstitution(playbackState, stage);
					}
					Plugin.Log.LogInfo((object)("RadiationPlayback[" + stage + "] FollowAnimatorSpriteCurve finished path=" + BuildPath(playbackState.Root)));
					<>m__Finally1();
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				CleanupPlaybackState(playbackState, stage, "finally");
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const string TextureSubfolder = "textures";

		private const string WarningRootPathSuffix = "IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease";

		private const string PanelObjectName = "Panel";

		private const float OriginalClipDurationSeconds = 1.7166667f;

		private const float DefaultFollowDurationSeconds = 1.85f;

		private const float MaxFollowDurationSeconds = 5f;

		private const long MaxTextureBytes = 8388608L;

		private const long MaxTexturePixels = 16777216L;

		private static readonly Dictionary<string, string[]> OriginalSpriteFrameFiles = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
		{
			["RedUIPanelGlitchB"] = FrameFileNameCandidates("RedUIPanelGlitchB", "C864CEDFD2-470F6C25C6"),
			["RedUIPanelGlitchBWarning"] = FrameFileNameCandidates("RedUIPanelGlitchBWarning", "E5C5C6E52B-F9F9EA9261"),
			["RedUIPanelGlitchBWarningRadiation"] = FrameFileNameCandidates("RedUIPanelGlitchBWarningRadiation", "FFCC97E055-2C688E6DC8"),
			["RedUIPanelGlitchBWarningRadiationB"] = FrameFileNameCandidates("RedUIPanelGlitchBWarningRadiationB", "7D4ED37952-95F686DE01"),
			["RedUIPanelGlitchBWarningRadiationC"] = FrameFileNameCandidates("RedUIPanelGlitchBWarningRadiationC", "7FBAA1AA30-9E2C036778"),
			["RedUIPanelGlitchBWarningRadiationD"] = FrameFileNameCandidates("RedUIPanelGlitchBWarningRadiationD", "4877939F7B-47E20481B0")
		};

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

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

		private static readonly Dictionary<string, Sprite?> SpriteCache = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

		private static readonly FieldInfo? RawOverrideSpriteField = typeof(Image).GetField("m_OverrideSprite", BindingFlags.Instance | BindingFlags.NonPublic);

		private static string? _textureDirectory;

		private static ConfigEntry<bool>? _enabled;

		private static ConfigEntry<float>? _followDurationSeconds;

		private static HUDManager? _activeHudManager;

		private static Coroutine? _activePlaybackCoroutine;

		private static PlaybackState? _activePlaybackState;

		public static void Initialize(string pluginDir, ConfigFile config)
		{
			_textureDirectory = Path.Combine(pluginDir, "textures");
			_enabled = config.Bind<bool>("04 资源 - 辐射警告", "Enabled", true, "启用跟随原版动画的辐射警告贴图替换。");
			_followDurationSeconds = config.Bind<float>("04 资源 - 辐射警告", "FollowDurationSeconds", 1.85f, "跟随原版 RadiationIncreaseWarning 动画并替换本地化贴图的持续时间,单位为秒。");
			foreach (string key in OriginalSpriteFrameFiles.Keys)
			{
				ResolveFrameTexture(key, "Initialize");
			}
			Plugin.Log.LogInfo((object)$"RadiationPlayback initialized mode=animator-follow clipSeconds={1.7166667f:0.###}");
		}

		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 (_activePlaybackCoroutine != null)
			{
				Plugin.Log.LogInfo((object)("RadiationPlayback[" + stage + "] action=duplicate-trigger-restart mode=animator-follow"));
				CleanupActivePlayback(stage, "duplicate-restart");
			}
			Transform val = FindWarningRoot(hudManager);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("RadiationPlayback[" + stage + "] action=root-not-found suffix=IngamePlayerHUD/SpecialHUDGraphics/RadiationIncrease"));
				return;
			}
			Image val2 = FindWarningPanel(val);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)("RadiationPlayback[" + stage + "] action=panel-not-found path=" + BuildPath(val) + " child=Panel"));
			}
			else if (HasAllLocalizedTextures(stage))
			{
				PlaybackState playbackState = new PlaybackState(val, val2, ReadRawOverrideSprite(val2));
				_activeHudManager = hudManager;
				_activePlaybackState = playbackState;
				_activePlaybackCoroutine = ((MonoBehaviour)hudManager).StartCoroutine(FollowAnimatorSpriteCurve(playbackState, stage));
			}
		}

		public static void Shutdown()
		{
			CleanupActivePlayback("Shutdown", "shutdown");
			ClearCachedAssets();
		}

		public static void ResetForHudLifecycle(HUDManager hudManager, string stage)
		{
			if (!((Object)(object)hudManager == (Object)null) && (_activePlaybackCoroutine != null || _activePlaybackState != null))
			{
				CleanupActivePlayback(stage, "hud-reset");
			}
		}

		[IteratorStateMachine(typeof(<FollowAnimatorSpriteCurve>d__24))]
		private static IEnumerator FollowAnimatorSpriteCurve(PlaybackState playbackState, string stage)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FollowAnimatorSpriteCurve>d__24(0)
			{
				playbackState = playbackState,
				stage = stage
			};
		}

		private static float GetFollowDurationSeconds()
		{
			float num = _followDurationSeconds?.Value ?? 1.85f;
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				num = 1.85f;
			}
			return Mathf.Clamp(num, 1.7166667f, 5f);
		}

		private static void ApplyCurrentAnimatorSpriteSubstitution(PlaybackState playbackState, string stage)
		{
			Image panelImage = playbackState.PanelImage;
			Sprite sprite = panelImage.sprite;
			string text = NormalizeSpriteName((sprite != null) ? ((Object)sprite).name : null);
			if (string.IsNullOrWhiteSpace(text))
			{
				return;
			}
			if (!OriginalSpriteFrameFiles.ContainsKey(text))
			{
				ClearLocalizedOverrideIfOwned(playbackState, "unmapped-original");
				return;
			}
			Texture2D val = ResolveFrameTexture(text, stage);
			if (!((Object)(object)val == (Object)null))
			{
				Sprite val2 = ResolveLocalizedSprite(text, sprite, val);
				if (!((Object)(object)val2 == (Object)null) && ReadRawOverrideSprite(panelImage) != val2)
				{
					panelImage.overrideSprite = val2;
					((Graphic)panelImage).SetVerticesDirty();
					((Graphic)panelImage).SetMaterialDirty();
					string.Equals(playbackState.LastAppliedOriginalSpriteName, text, StringComparison.OrdinalIgnoreCase);
					playbackState.LastAppliedOriginalSpriteName = text;
					playbackState.LastAppliedLocalizedSprite = val2;
				}
			}
		}

		private static void CleanupActivePlayback(string stage, string reason)
		{
			Coroutine activePlaybackCoroutine = _activePlaybackCoroutine;
			HUDManager activeHudManager = _activeHudManager;
			PlaybackState activePlaybackState = _activePlaybackState;
			_activePlaybackCoroutine = null;
			_activeHudManager = null;
			_activePlaybackState = null;
			if (activePlaybackCoroutine != null && (Object)(object)activeHudManager != (Object)null)
			{
				((MonoBehaviour)activeHudManager).StopCoroutine(activePlaybackCoroutine);
			}
			if (activePlaybackState != null)
			{
				CleanupPlaybackState(activePlaybackState, stage, reason);
			}
		}

		private static void CleanupPlaybackState(PlaybackState playbackState, string stage, string reason)
		{
			if (!playbackState.CleanupCompleted)
			{
				playbackState.CleanupCompleted = true;
				ClearLocalizedOverrideIfOwned(playbackState, reason);
				if (_activePlaybackState == playbackState)
				{
					_activePlaybackState = null;
					_activePlaybackCoroutine = null;
					_activeHudManager = null;
				}
				string text = (((Object)(object)playbackState.PanelImage != (Object)null) ? BuildPath(((Component)playbackState.PanelImage).transform) : "<null>");
				Plugin.Log.LogInfo((object)("RadiationPlayback[" + stage + "] action=restore reason=" + reason + " path=" + BuildPath(playbackState.Root) + " panel=" + text));
			}
		}

		private static void ClearLocalizedOverrideIfOwned(PlaybackState playbackState, string reason)
		{
			Image panelImage = playbackState.PanelImage;
			if (!((Object)(object)panelImage == (Object)null))
			{
				Sprite val = ReadRawOverrideSprite(panelImage);
				if ((Object)(object)val != (Object)null && val != playbackState.LastAppliedLocalizedSprite && !IsCachedLocalizedSprite(val))
				{
					Plugin.Log.LogInfo((object)("RadiationPlayback action=skip-restore reason=" + reason + " currentOverride=" + ((Object)val).name));
					return;
				}
				panelImage.overrideSprite = playbackState.OriginalRawOverrideSprite;
				((Graphic)panelImage).SetVerticesDirty();
				((Graphic)panelImage).SetMaterialDirty();
			}
		}

		private static bool HasAllLocalizedTextures(string stage)
		{
			foreach (string key in OriginalSpriteFrameFiles.Keys)
			{
				if ((Object)(object)ResolveFrameTexture(key, stage) == (Object)null)
				{
					return false;
				}
			}
			return true;
		}

		private static string[] FrameFileNameCandidates(string baseName, string contentHash)
		{
			return new string[2]
			{
				baseName + " [" + contentHash + "].png",
				baseName + "[" + contentHash + "].png"
			};
		}

		private static string? ResolveFrameFileName(string originalSpriteName, string stage)
		{
			if (!OriginalSpriteFrameFiles.TryGetValue(originalSpriteName, out string[] value))
			{
				return null;
			}
			string[] array = value;
			foreach (string text in array)
			{
				if ((Object)(object)LoadTexture(text) != (Object)null)
				{
					return text;
				}
			}
			Plugin.Log.LogWarning((object)("RadiationPlayback[" + stage + "] action=incomplete-frame-set original=" + originalSpriteName + " candidates=" + string.Join("|", value) + " nativeFallback=true"));
			return null;
		}

		private static Texture2D? ResolveFrameTexture(string originalSpriteName, string stage)
		{
			if (ResolvedFrameTextureCache.TryGetValue(originalSpriteName, out Texture2D value))
			{
				return value;
			}
			string text = ResolveFrameFileName(originalSpriteName, stage);
			if (text == null)
			{
				ResolvedFrameTextureCache[originalSpriteName] = null;
				return null;
			}
			Texture2D val = LoadTexture(text);
			ResolvedFrameTextureCache[originalSpriteName] = val;
			return val;
		}

		private static Image? FindWarningPanel(Transform root)
		{
			Transform obj = root.Find("Panel");
			Image val = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Image[] componentsInChildren = ((Component)root).GetComponentsInChildren<Image>(true);
			foreach (Image val2 in componentsInChildren)
			{
				if (string.Equals(((Object)val2).name, "Panel", StringComparison.OrdinalIgnoreCase))
				{
					return val2;
				}
			}
			return null;
		}

		private static Sprite? ResolveLocalizedSprite(string originalSpriteName, Sprite? originalSprite, Texture2D texture)
		{
			string key = BuildSpriteCacheKey(originalSpriteName, originalSprite, texture);
			if (SpriteCache.TryGetValue(key, out Sprite value))
			{
				return value;
			}
			Sprite val = CreateLocalizedSprite(texture, originalSprite);
			SpriteCache[key] = val;
			return val;
		}

		private static string BuildSpriteCacheKey(string originalSpriteName, Sprite? originalSprite, Texture2D texture)
		{
			//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)
			//IL_007f: 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)
			if ((Object)(object)originalSprite == (Object)null)
			{
				return originalSpriteName + ":" + ((Object)texture).name + ":fallback";
			}
			Rect rect = originalSprite.rect;
			return $"{originalSpriteName}:{((Object)texture).name}:{((Rect)(ref rect)).x}:{((Rect)(ref rect)).y}:{((Rect)(ref rect)).width}:{((Rect)(ref rect)).height}:{originalSprite.pivot.x}:{originalSprite.pivot.y}:{originalSprite.pixelsPerUnit}";
		}

		private static Sprite? CreateLocalizedSprite(Texture2D texture, Sprite? template)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)template != (Object)null)
				{
					Rect rect = template.rect;
					if (((Rect)(ref rect)).width > 0f && ((Rect)(ref rect)).height > 0f && ((Rect)(ref rect)).xMax <= (float)((Texture)texture).width && ((Rect)(ref rect)).yMax <= (float)((Texture)texture).height)
					{
						Vector2 val = default(Vector2);
						((Vector2)(ref val))..ctor(template.pivot.x / ((Rect)(ref rect)).width, template.pivot.y / ((Rect)(ref rect)).height);
						Sprite obj = Sprite.Create(texture, rect, val, template.pixelsPerUnit, 0u, (SpriteMeshType)0, template.border);
						((Object)obj).name = ((Object)texture).name;
						return obj;
					}
				}
				Sprite obj2 = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)obj2).name = ((Object)texture).name;
				return obj2;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("RadiationPlayback[Sprite] action=create-failed texture=" + ((Object)texture).name + " error=" + ex.GetType().Name + ": " + ex.Message));
				return null;
			}
		}

		private static bool IsCachedLocalizedSprite(Sprite sprite)
		{
			foreach (Sprite value in SpriteCache.Values)
			{
				if (value == sprite)
				{
					return true;
				}
			}
			return false;
		}

		private static Sprite? ReadRawOverrideSprite(Image image)
		{
			if (RawOverrideSpriteField == null)
			{
				return null;
			}
			try
			{
				object? value = RawOverrideSpriteField.GetValue(image);
				return (Sprite?)((value is Sprite) ? value : null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("RadiationPlayback[Image] action=read-raw-override-failed error=" + ex.GetType().Name + ": " + ex.Message));
				return null;
			}
		}

		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 Texture2D? LoadTexture(string fileName)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			if (TextureCache.TryGetValue(fileName, out Texture2D value))
			{
				return value;
			}
			if (string.IsNullOrWhiteSpace(_textureDirectory))
			{
				return null;
			}
			string text = Path.Combine(_textureDirectory, fileName);
			if (!File.Exists(text))
			{
				TextureCache[fileName] = null;
				return null;
			}
			Texture2D val = null;
			try
			{
				FileInfo fileInfo = new FileInfo(text);
				if (fileInfo.Length > 8388608)
				{
					Plugin.Log.LogWarning((object)$"RadiationPlayback[Texture] action=file-too-large file={fileName} bytes={fileInfo.Length} max={8388608L}");
					TextureCache[fileName] = null;
					return null;
				}
				byte[] array = File.ReadAllBytes(text);
				val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!ImageConversion.LoadImage(val, array, false))
				{
					Object.Destroy((Object)(object)val);
					val = null;
					TextureCache[fileName] = null;
					return null;
				}
				if (IsDecodedTextureTooLarge(val))
				{
					Plugin.Log.LogWarning((object)("RadiationPlayback[Texture] action=decoded-texture-too-large file=" + fileName + " " + $"width={((Texture)val).width} height={((Texture)val).height} pixels={(long)((Texture)val).width * (long)((Texture)val).height} maxPixels={16777216L}"));
					Object.Destroy((Object)(object)val);
					val = null;
					TextureCache[fileName] = null;
					return null;
				}
				((Object)val).name = Path.GetFileNameWithoutExtension(fileName);
				((Texture)val).wrapMode = (TextureWrapMode)1;
				TextureCache[fileName] = val;
				Texture2D result = val;
				val = null;
				return result;
			}
			catch (Exception ex)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				Plugin.Log.LogWarning((object)("RadiationPlayback[Texture] action=load-failed file=" + fileName + " error=" + ex.GetType().Name + ": " + ex.Message));
				TextureCache[fileName] = null;
				return null;
			}
		}

		private static void ClearCachedAssets()
		{
			HashSet<int> hashSet = new HashSet<int>();
			foreach (Sprite value in SpriteCache.Values)
			{
				if (!((Object)(object)value == (Object)null) && hashSet.Add(((Object)value).GetInstanceID()))
				{
					Object.Destroy((Object)(object)value);
				}
			}
			HashSet<int> destroyedTextureIds = new HashSet<int>();
			foreach (Texture2D value2 in TextureCache.Values)
			{
				DestroyTextureOnce(value2, destroyedTextureIds);
			}
			foreach (Texture2D value3 in ResolvedFrameTextureCache.Values)
			{
				DestroyTextureOnce(value3, destroyedTextureIds);
			}
			SpriteCache.Clear();
			TextureCache.Clear();
			ResolvedFrameTextureCache.Clear();
		}

		private static bool IsDecodedTextureTooLarge(Texture2D texture)
		{
			if (((Texture)texture).width <= 0 || ((Texture)texture).height <= 0)
			{
				return true;
			}
			return (long)((Texture)texture).width * (long)((Texture)texture).height > 16777216;
		}

		private static void DestroyTextureOnce(Texture2D? texture, HashSet<int> destroyedTextureIds)
		{
			if (!((Object)(object)texture == (Object)null) && destroyedTextureIds.Add(((Object)texture).GetInstanceID()))
			{
				Object.Destroy((Object)(object)texture);
			}
		}

		private static string NormalizeSpriteName(string? spriteName)
		{
			if (string.IsNullOrWhiteSpace(spriteName))
			{
				return string.Empty;
			}
			string text = spriteName.Trim();
			if (text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd();
			}
			return 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;
		}
	}
	internal static class ExternalEnglishCompatibilityService
	{
		private const int MaxSourceLength = 512;

		private const int RuntimeCacheLimit = 4096;

		private const string DiscountAlertNoDiscountLocalizedText = "暂无折扣\n明天再来查看";

		private static readonly Dictionary<string, string> ExactEntries = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			["Emote Menu"] = "动作菜单",
			["Random Emote"] = "随机动作",
			["Zoom"] = "缩放",
			["Freeze"] = "冻结",
			["Swap Page"] = "切换页面",
			["Favorite Emote"] = "收藏动作",
			["Set Quick Emote"] = "设置快捷动作",
			["Tell autopilot ship to leave early"] = "命令自动驾驶飞船提前离开",
			["Spectate Previous Player"] = "切换上一名玩家",
			["Open Admin UI"] = "打开管理界面",
			["Copy Lobby ID"] = "复制房间 ID",
			["Enter tag or id..."] = "输入标签或 ID...",
			["Enter tag or ip..."] = "输入标签或 IP...",
			["Search Mods"] = "搜索模组",
			["Search Configs"] = "搜索配置",
			["Close"] = "关闭",
			["Apply"] = "应用",
			["Delete"] = "删除",
			["Go back"] = "返回",
			["OK"] = "确认",
			["Server Password"] = "房间密码",
			["Validate Steam Sessions"] = "验证 Steam 会话",
			["Max Players"] = "最大人数",
			["Server Access"] = "房间权限",
			["Invite-only"] = "仅限邀请",
			["Friends-only"] = "仅限好友",
			["Server Tag"] = "房间标签",
			["New File"] = "新存档",
			["Players"] = "玩家",
			["Today's discounts"] = "今日折扣",
			["Target on ship"] = "飞船上的目标",
			["Signal lost"] = "信号丢失",
			["Antenna stored"] = "天线已存放",
			["PERFORMANCE REPORT"] = "绩效报告",
			["NO SURVIVORS"] = "无人生还",
			["NOTES"] = "备注",
			["DECEASED"] = "死亡",
			["Collected"] = "已收集",
			["Grade"] = "评级",
			["Rating"] = "评级",
			["Lost 100% scrap"] = "损失 100% 废料",
			["No items were found"] = "未找到可售物品",
			["Error selling items"] = "售卖物品时出错",
			["You can't afford to sell that amount"] = "可售物品不足,无法卖出该金额",
			["Successfully emptied temporary blacklist"] = "已清空临时黑名单",
			["Successfully emptied temporary priority set"] = "已清空临时优先列表",
			["Item Blacklist"] = "物品黑名单",
			["Priority Items"] = "优先售卖物品",
			["Flag Prefix"] = "标志前缀",
			["Items to never sell by internal name (comma-separated)"] = "永不出售的物品内部名称(逗号分隔)",
			["Items which are prioritized when selling"] = "出售时优先选择的物品",
			["QUICKSELL"] = "快速出售",
			["SELL RESULTS"] = "出售结果",
			["Command"] = "命令",
			["Invalid command"] = "命令无效",
			["HELP PAGE"] = "帮助页面",
			["ALL HELP PAGE"] = "全部出售帮助页面",
			["AMOUNT HELP PAGE"] = "金额帮助页面",
			["BLACKLIST HELP PAGE"] = "黑名单帮助页面",
			["ITEM HELP PAGE"] = "物品帮助页面",
			["PRIORITY HELP PAGE"] = "优先列表帮助页面",
			["QUOTA HELP PAGE"] = "配额帮助页面",
			["FLAG HELP PAGE"] = "标志帮助页面",
			["OVERTIME HELP PAGE"] = "加班奖励帮助页面",
			["PAGES HELP PAGE"] = "页面帮助",
			["-A HELP PAGE"] = "-A 标志帮助",
			["-E HELP PAGE"] = "-E 标志帮助",
			["-N HELP PAGE"] = "-N 标志帮助",
			["-O HELP PAGE"] = "-O 标志帮助",
			["-P HELP PAGE"] = "-P 标志帮助",
			["Combining flags"] = "组合标志",
			["\"help\" to open this page or a specific help page"] = "\"help\":打开此页或指定帮助页",
			["\"quota\" to sell exactly for quota"] = "\"quota\":按配额精确出售",
			["\"all\" to sell all unfiltered scrap available"] = "\"all\":出售所有未过滤的可用废料",
			["\"item\" to sell all items like the one you are holding or the one you specified"] = "\"item\":出售所持有或指定的同类物品",
			["\"-a\" to ignore blacklist (used with quota, all, <amount>)"] = "\"-a\":忽略黑名单(用于 quota、all、<amount>)",
			["\"-o\" to sell accounting for overtime (used with <amount>)"] = "\"-o\":计入加班奖励后出售(用于 <amount>)",
			["The symbol which is used as prefix in flags (aka \"-\" in \"-e\")"] = "命令标志使用的前缀符号(例如 -e 中的 -)",
			["Command variations"] = "命令用法",
			["The sell command was initiated"] = "售卖命令已开始",
			["The sell command completed it's job, terminating"] = "售卖命令已完成,正在结束",
			["The overtime command was initiated"] = "加班奖励命令已开始",
			["Use \"/sell help flags\" to see info on important flags"] = "输入 \"/sell help flags\" 查看重要标志说明",
			["Use \"/sell help <flag>\" to see info on specific flag"] = "输入 \"/sell help <flag>\" 查看指定标志说明",
			["Use \"/sell help <variation>\" to see info on specific command"] = "输入 \"/sell help <variation>\" 查看指定命令说明",
			["Use \"/sell help pages\" to see info on all pages"] = "输入 \"/sell help pages\" 查看所有帮助页面",
			["Use \"/sell help overtime\" to see info on the \"/ot\" (overtime command)"] = "输入 \"/sell help overtime\" 查看 \"/ot\"(加班奖励命令)说明",
			["The value must be positive"] = "数值必须为正",
			["Cannot find terminal!"] = "未找到终端!",
			["Cannot find terminal?!"] = "未找到终端!",
			["Quota is already fulfilled"] = "利润指标已完成",
			["No item is held and no item was specified"] = "未持有物品,也未指定物品",
			["No items on the desk"] = "柜台上没有物品",
			["Door already open"] = "门已经打开",
			["Wrong item name"] = "物品名称错误",
			["No page with this name exists"] = "不存在这个帮助页面",
			["Failed to evalute expression"] = "表达式计算失败",
			["No items to sort"] = "没有可整理的物品",
			["No items on the ship"] = "飞船上没有物品",
			["Sorting all items..."] = "正在整理所有物品...",
			["Finished sorting items"] = "物品整理完成",
			["Invalid arguments"] = "参数无效",
			["Invalid item name"] = "物品名称无效",
			["Error running command"] = "运行命令时出错",
			["Error getting position"] = "获取位置时出错",
			["Automatic sorting failed"] = "自动整理失败",
			["Error while autosorting items"] = "自动整理物品时出错",
			["Automatic sorting failed due to an internal error, check the log for details"] = "自动整理因内部错误失败,请查看日志",
			["Couldn't find ship"] = "未找到飞船",
			["Raycast unsuccessful"] = "射线检测未成功",
			["The ship must be in orbit"] = "飞船必须处于轨道中",
			["You can't pick anything up while sorting items."] = "整理物品时无法拾取任何物品。",
			["Toggles automatic item sorting when leaving a planet"] = "切换离开星球时是否自动整理物品",
			["* The most paranoid employee."] = "* 最多疑的员工",
			["The most paranoid employee."] = "最多疑的员工",
			["* Sustained the most injuries."] = "* 受伤最多",
			["Sustained the most injuries."] = "受伤最多",
			["* Dislikes smoke."] = "* 讨厌烟雾",
			["Dislikes smoke."] = "讨厌烟雾",
			["* The least likely to die next time."] = "* 下次最不可能死亡",
			["The least likely to die next time."] = "下次最不可能死亡",
			["* I think this one's a serial killer."] = "* 我觉得这人像个连环杀手",
			["I think this one's a serial killer."] = "我觉得这人像个连环杀手",
			["* Go! Freaky on a Friday night."] = "* 周五夜晚尽情疯狂",
			["Go! Freaky on a Friday night."] = "周五夜晚尽情疯狂"
		};

		private static readonly Dictionary<string, string> KeyTokenEntries = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			["Scroll Mouse"] = "滚动鼠标",
			["keybind #"] = "按键绑定 #"
		};

		private static readonly string[] SellingNamedMarkers = new string[3] { " item(s) named \"", " items named \"", " item named \"" };

		private static readonly string[] SellingCountMarkers = new string[3] { " item(s) with a total value of ", " items with a total value of ", " item with a total value of " };

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

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

		public static void ClearRuntimeCaches()
		{
			CanHandleCache.Clear();
			TranslationCache.Clear();
		}

		public static bool CanHandleCheap(string? source)
		{
			if (string.IsNullOrWhiteSpace(source) || source.Length > 512)
			{
				return false;
			}
			if (CanHandleCache.TryGetValue(source, out var value))
			{
				return value;
			}
			bool result = CanHandleCheapCore(source);
			CacheCanHandleResult(source, result);
			return result;
		}

		public static bool MightTranslateStatusLikeTextCheap(string? source)
		{
			if (string.IsNullOrWhiteSpace(source) || source.Length > 512)
			{
				return false;
			}
			if (ContainsLineBreak(source))
			{
				int num = 0;
				while (num <= source.Length)
				{
					int num2 = source.IndexOf('\n', num);
					int num3 = ((num2 < 0) ? source.Length : num2);
					ReadOnlySpan<char> line = source.AsSpan(num, num3 - num);
					if (line.Length > 0)
					{
						if (line[line.Length - 1] == '\r')
						{
							line = line.Slice(0, line.Length - 1);
						}
					}
					if (LineMightNeedExternalCompatibilityCheck(line) && MightTranslateStatusLikeSingleLineCheap(line.ToString()))
					{
						return true;
					}
					if (num2 < 0)
					{
						break;
					}
					num = num2 + 1;
				}
				return false;
			}
			return MightTranslateStatusLikeSingleLineCheap(source);
		}

		public static bool MightTranslateStatusLikeLabelCheap(string? label)
		{
			if (string.IsNullOrWhiteSpace(label) || label.Length > 64)
			{
				return false;
			}
			string text = StripMenuSelectionPrefix(StripLeadingSimpleRichTextTags(StripOuterSimpleRichTextEnvelope(label)).Trim());
			if (text.EndsWith(":", StringComparison.Ordinal))
			{
				string text2 = text;
				text = text2.Substring(0, text2.Length - 1).TrimEnd();
			}
			return ExactEntries.ContainsKey(text);
		}

		private static bool CanHandleCheapCore(string source)
		{
			if (MightContainDeleteFilePrompt(source) && LooksLikeDeleteFilePrompt(source))
			{
				return true;
			}
			if (MightContainDiscountAlertNoDiscountText(source) && LooksLikeDiscountAlertNoDiscountText(source))
			{
				return true;
			}
			if (ContainsLineBreak(source))
			{
				return CanHandleAnyLineCheap(source);
			}
			if (ContainsCjk(source))
			{
				return false;
			}
			return CanHandleSingleLineCheap(source);
		}

		private static bool CanHandleAnyLineCheap(string source)
		{
			int num = 0;
			while (num <= source.Length)
			{
				int num2 = source.IndexOf('\n', num);
				int num3 = ((num2 < 0) ? source.Length : num2);
				ReadOnlySpan<char> line = source.AsSpan(num, num3 - num);
				if (line.Length > 0)
				{
					if (line[line.Length - 1] == '\r')
					{
						line = line.Slice(0, line.Length - 1);
					}
				}
				if (LineMightNeedExternalCompatibilityCheck(line) && CanHandleSingleLineCheap(line.ToString()))
				{
					return true;
				}
				if (num2 < 0)
				{
					break;
				}
				num = num2 + 1;
			}
			return false;
		}

		private static bool LineMightNeedExternalCompatibilityCheck(ReadOnlySpan<char> line)
		{
			line = line.Trim();
			if (line.Length == 0 || line.Length > 512)
			{
				return false;
			}
			bool result = false;
			ReadOnlySpan<char> readOnlySpan = line;
			for (int i = 0; i < readOnlySpan.Length; i++)
			{
				char ch = readOnlySpan[i];
				if (IsCjk(ch))
				{
					return false;
				}
				if (IsAsciiLetter(ch))
				{
					result = true;
				}
			}
			return result;
		}

		private static bool MightContainDeleteFilePrompt(string source)
		{
			if (source.IndexOf("delete", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return source.IndexOf("file", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static bool MightContainDiscountAlertNoDiscountText(string source)
		{
			if (source.IndexOf("None", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return source.IndexOf("tomorrow", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static bool MightContainDiscountLine(string source)
		{
			if (source.IndexOf('$') >= 0)
			{
				if (source.IndexOf(" off!", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return source.IndexOf(" up!", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return true;
			}
			return false;
		}

		private static bool MightContainCompositeExternalUiShape(string text)
		{
			foreach (char c in text)
			{
				bool flag = char.IsWhiteSpace(c);
				if (!flag)
				{
					bool flag2;
					switch (c)
					{
					case '!':
					case '#':
					case '$':
					case '%':
					case '(':
					case ')':
					case '*':
					case '-':
					case ':':
					case '[':
					case ']':
						flag2 = true;
						break;
					default:
						flag2 = false;
						break;
					}
					flag = flag2;
				}
				if (flag)
				{
					return true;
				}
			}
			return false;
		}

		private static bool CanHandleSingleLineCheap(string source)
		{
			string text = StripLeadingSimpleRichTextTags(StripOuterSimpleRichTextEnvelope(source)).Trim();
			if (text.Length == 0)
			{
				return false;
			}
			string text2 = StripMenuSelectionPrefix(text);
			if (ExactEntries.ContainsKey(text2) || LooksLikeBracketedKnownExternalUiToken(text2) || LooksLikeDecoratedKnownExternalUiToken(text2))
			{
				return true;
			}
			if (!MightContainCompositeExternalUiShape(text2))
			{
				return false;
			}
			if (!LooksLikeKnownExternalUiLabel(text2) && !LooksLikeSaveFileLabel(text2) && !LooksLikeAdvancedFeaturesPlayerLabel(text2) && !LooksLikeDeleteFilePrompt(text2) && text.IndexOf("Emote", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Admin UI", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Lobby ID", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Server Access", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Steam Sessions", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("FRIENDS ONLY", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("INVITE ONLY", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("discount", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf(" off!", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf(" up!", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return LooksLikeChatCommandCompatibilityText(text2);
			}
			return true;
		}

		private static bool MightTranslateStatusLikeSingleLineCheap(string source)
		{
			string text = StripLeadingSimpleRichTextTags(StripOuterSimpleRichTextEnvelope(source)).Trim();
			if (text.Length == 0 || ContainsCjk(text))
			{
				return false;
			}
			string text2 = StripMenuSelectionPrefix(text).Trim();
			if (!LooksLikeKnownExternalUiLabel(text2) && !LooksLikeBracketedKnownExternalUiToken(text2) && !LooksLikeDecoratedKnownExternalUiToken(text2))
			{
				return LooksLikeChatCommandCompatibilityText(text2);
			}
			return true;
		}

		public static bool TryTranslateFast(string? source, out string translated)
		{
			translated = source ?? string.Empty;
			if (string.IsNullOrWhiteSpace(source) || source.Length > 512)
			{
				return false;
			}
			if (TryGetCachedTranslation(source, out translated, out var hasTranslation))
			{
				return hasTranslation;
			}
			if (!CanHandleCheap(source))
			{
				CacheTranslationResult(source, null);
				return false;
			}
			if (TryTranslateDiscountAlertNoDiscountText(source, out translated) || TryTranslateDeleteFilePrompt(source, out translated))
			{
				CacheTranslationResult(source, translated);
				return true;
			}
			if (ContainsLineBreak(source))
			{
				bool flag = TryTranslateLines(source, out translated);
				CacheTranslationResult(source, flag ? translated : null);
				return flag;
			}
			bool flag2 = TryTranslateSingleLinePreservingWhitespace(source, out translated);
			CacheTranslationResult(source, flag2 ? translated : null);
			return flag2;
		}

		public static bool TryTranslateDisplayTipText(string? source, out string translated)
		{
			translated = source ?? string.Empty;
			if (string.IsNullOrWhiteSpace(source))
			{
				return false;
			}
			if (source.Length <= 512)
			{
				return TryTranslateFast(source, out translated);
			}
			if (ContainsLineBreak(source))
			{
				return TryTranslateDisplayTipLines(source, out translated);
			}
			return false;
		}

		public static bool MightContainDisplayTipCompatibilityText(string? source)
		{
			if (string.IsNullOrWhiteSpace(source))
			{
				return false;
			}
			if (source.Length <= 512)
			{
				if (!CanHandleCheap(source))
				{
					return MightContainDiscountLine(source);
				}
				return true;
			}
			return MightContainDiscountLine(source);
		}

		private static void CacheCanHandleResult(string source, bool result)
		{
			if ((result || !LooksLikeVolatileNegativeCacheSource(source)) && CanHandleCache.Count < RuntimePerformanceSettings.ExternalCompatibilityCacheLimit)
			{
				CanHandleCache[source] = result;
			}
		}

		private static bool TryGetCachedTranslation(string source, out string translated, out bool hasTranslation)
		{
			if (!TranslationCache.TryGetValue(source, out string value))
			{
				translated = source;
				hasTranslation = false;
				return false;
			}
			hasTranslation = value != null;
			translated = value ?? source;
			return true;
		}

		private static void CacheTranslationResult(string source, string? translated)
		{
			if ((translated != null || !LooksLikeVolatileNegativeCacheSource(source)) && TranslationCache.Count < RuntimePerformanceSettings.ExternalCompatibilityCacheLimit)
			{
				TranslationCache[source] = translated;
			}
		}

		private static bool LooksLikeVolatileNegativeCacheSource(string source)
		{
			if (source.Length > 128)
			{
				return true;
			}
			foreach (char c in source)
			{
				bool flag = char.IsDigit(c);
				if (!flag)
				{
					bool flag2;
					switch (c)
					{
					case '\n':
					case '\r':
					case '#':
					case '$':
					case '%':
					case '(':
					case ')':
					case '/':
					case ':':
					case '<':
					case '>':
					case '[':
					case '\\':
					case ']':
						flag2 = true;
						break;
					default:
						flag2 = false;
						break;
					}
					flag = flag2;
				}
				if (flag)
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryTranslateLines(string source, out string translated)
		{
			bool flag = false;
			StringBuilder stringBuilder = new StringBuilder(source.Length + 16);
			int num = 0;
			while (num <= source.Length)
			{
				int num2 = source.IndexOf('\n', num);
				int num3 = ((num2 < 0) ? source.Length : num2);
				string text = source.Substring(num, num3 - num);
				bool flag2 = text.EndsWith("\r", StringComparison.Ordinal);
				string source2;
				if (!flag2)
				{
					source2 = text;
				}
				else
				{
					string text2 = text;
					source2 = text2.Substring(0, text2.Length - 1);
				}
				if (TryTranslateSingleLinePreservingWhitespace(source2, out string translated2))
				{
					stringBuilder.Append(translated2);
					if (flag2)
					{
						stringBuilder.Append('\r');
					}
					flag = true;
				}
				else
				{
					stringBuilder.Append(text);
				}
				if (num2 < 0)
				{
					break;
				}
				stringBuilder.Append('\n');
				num = num2 + 1;
			}
			translated = (flag ? stringBuilder.ToString() : source);
			return flag;
		}

		private static bool TryTranslateDisplayTipLines(string source, out string translated)
		{
			bool flag = false;
			StringBuilder stringBuilder = new StringBuilder(source.Length + 16);
			int num = 0;
			while (num <= source.Length)
			{
				int num2 = source.IndexOf('\n', num);
				int num3 = ((num2 < 0) ? source.Length : num2);
				string text = source.Substring(num, num3 - num);
				bool flag2 = text.EndsWith("\r", StringComparison.Ordinal);
				string text2;
				if (!flag2)
				{
					text2 = text;
				}
				else
				{
					string text3 = text;
					text2 = text3.Substring(0, text3.Length - 1);
				}
				string text4 = text2;
				if (text4.Length <= 512 && LineMightNeedExternalCompatibilityCheck(text4.AsSpan()) && TryTranslateSingleLinePreservingWhitespace(text4, out string translated2))
				{
					stringBuilder.Append(translated2);
					if (flag2)
					{
						stringBuilder.Append('\r');
					}
					flag = true;
				}
				else
				{
					stringBuilder.Append(text);
				}
				if (num2 < 0)
				{
					break;
				}
				stringBuilder.Append('\n');
				num = num2 + 1;
			}
			translated = (flag ? stringBuilder.ToString() : source);
			return flag;
		}

		private static bool TryTranslateSingleLinePreservingWhitespace(string source, out string translated)
		{
			translated = source;
			int num = source.Length - source.TrimStart().Length;
			int num2 = source.Length - source.TrimEnd().Length;
			int num3 = source.Length - num - num2;
			if (num3 <= 0)
			{
				return false;
			}
			string text = ((num > 0) ? source.Substring(0, num) : string.Empty);
			string text2;
			if (num2 <= 0)
			{
				text2 = string.Empty;
			}
			else
			{
				int num4 = num2;
				int length = source.Length;
				int num5 = length - num4;
				text2 = source.Substring(num5, length - num5);
			}
			string text3 = text2;
			if (!TryTranslateSingleLineCore(source.Substring(num, num3), out string translated2))
			{
				return false;
			}
			translated = text + translated2 + text3;
			return true;
		}

		private static bool TryTranslateSingleLineCore(string source, out string translated)
		{
			translated = source;
			string value = source.Trim();
			string text = string.Empty;
			string text2 = string.Empty;
			string prefix;
			string inner;
			string suffix;
			while (TryExtractOuterSimpleRichTextEnvelope(value, out prefix, out inner, out suffix))
			{
				text += prefix;
				text2 = suffix + text2;
				value = inner.Trim();
			}
			text += ExtractLeadingSimpleRichTextPrefix(ref value);
			string text3 = string.Empty;
			if (value.StartsWith(">", StringComparison.Ordinal))
			{
				text3 = "> ";
				value = StripMenuSelectionPrefix(value);
			}
			if (LooksLikeNonUiName(value))
			{
				return false;
			}
			if (TryTranslateBracketedCommand(value, out translated) || TryTranslateDecoratedExactUiText(value, out translated) || TryTranslateControlTip(value, out translated) || TryTranslateLabelValue(value, out translated) || TryTranslateDiscountLine(value, out translated) || TryTranslateSaveFileLabel(value, out translated) || TryTranslateAdvancedFeaturesPlayerLabel(value, out translated) || TryTranslateDeleteFilePrompt(value, out translated) || TryTranslateChatCommandCompatibilityText(value, out translated) || TryTranslateExactUiText(value, out translated))
			{
				translated = text3 + text + translated + text2;
				return true;
			}
			return false;
		}

		private static bool TryTranslateSaveFileLabel(string text, out string translated)
		{
			translated = text;
			string text2 = StripMenuSelectionPrefix(text).Trim();
			if (!LooksLikeSaveFileLabel(text2))
			{
				return false;
			}
			string text3 = text2;
			int length = "File ".Length;
			translated = text3.Substring(length, text3.Length - length).TrimStart() + " 号存档";
			return true;
		}

		private static bool TryTranslateDeleteFilePrompt(string text, out string translated)
		{
			translated = text;
			if (TryExtractDeleteFileAlias(text, out string alias))
			{
				translated = "要删除 " + alias + " 吗";
				return true;
			}
			if (!TryExtractDeleteFileNumber(text, out string fileNumber))
			{
				return false;
			}
			translated = "要删除 " + fileNumber + " 号存档吗";
			return true;
		}

		private static bool TryTranslateChatCommandCompatibilityText(string text, out string translated)
		{
			translated = text;
			string text2 = text.Trim();
			if (!TryTranslateCommandItemLabel(text2, "Item to sell:", "要售卖的物品", out translated) && !TryTranslateCommandItemLabel(text2, "Items with priority:", "优先售卖物品", out translated) && !TryTranslateNoItemsCalled(text2, out translated) && !TryTranslateThereIsScrapOnShip(text2, out translated) && !TryTranslateItemsCouldNotBeSorted(text2, out translated) && !TryTranslateItemsOfTypePosition(text2, out translated) && !TryTranslateMovingAllItemsOfType(text2, out translated) && !TryTranslateSellingItemsSummary(text2, out translated) && !TryTranslateSoldRequestedSummary(text2, out translated) && !TryTranslateCommandValueLabel(text2, "Overtime:", "加班奖励", out translated) && !TryTranslateCommandValueLabel(text2, "Money after takeoff:", "起飞后资金", out translated))
			{
				return TryTranslateMoneyInTerminal(text2, out translated);
			}
			return true;
		}

		private static bool LooksLikeChatCommandCompatibilityText(string text)
		{
			string text2 = text.Trim();
			if (!text2.StartsWith("Item to sell:", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("Items with priority:", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("No items called \"", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("There is ", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("Items of type ", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("Moving all items of type ", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("Selling ", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("Overtime:", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("Money after takeoff:", StringComparison.OrdinalIgnoreCase) && !text2.StartsWith("Money in terminal", StringComparison.OrdinalIgnoreCase) && text2.IndexOf(" sold / ", StringComparison.OrdinalIgnoreCase) <= 0)
			{
				return text2.EndsWith(" items couldn't be sorted", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static bool TryTranslateCommandItemLabel(string text, string prefix, string localizedLabel, out string translated)
		{
			translated = text;
			if (!text.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			int length = prefix.Length;
			string text2 = text.Substring(length, text.Length - length).Trim();
			if (text2.Length == 0)
			{
				return false;
			}
			translated = localizedLabel + ":" + LocalizeCommandItemName(text2);
			return true;
		}

		private static bool TryTranslateNoItemsCalled(string text, out string translated)
		{
			translated = text;
			if (!text.StartsWith("No items called \"", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			int num = text.IndexOf('"', "No items called \"".Length);
			if (num <= "No items called \"".Length)
			{
				return false;
			}
			string text2 = text.Substring("No items called \"".Length, num - "No items called \"".Length).Trim();
			int num2 = num + 1;
			string text3 = text.Substring(num2, text.Length - num2).Trim();
			if (text2.Length == 0 || (text3.Length > 0 && !string.Equals(text3, "were detected", StringComparison.OrdinalIgnoreCase)))
			{
				return false;
			}
			translated = "未找到名为 \"" + LocalizeCommandItemName(text2) + "\" 的物品";
			return true;
		}

		private static bool TryTranslateThereIsScrapOnShip(string text, out string translated)
		{
			translated = text;
			if (!text.StartsWith("There is ", StringComparison.OrdinalIgnoreCase) || !text.EndsWith(" scrap on ship", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string text2 = text.Substring("There is ".Length, text.Length - "There is ".Length - " scrap on ship".Length).Trim();
			if (!LooksLikeSimpleNumber(text2))
			{
				return false;
			}
			translated = "飞船上有 " + text2 + " 件废料";
			return true;
		}

		private static bool TryTranslateItemsCouldNotBeSorted(string text, out string translated)
		{
			translated = text;
			if (!text.EndsWith(" items couldn't be sorted", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			int length = " items couldn't be sorted".Length;
			string text2 = text.Substring(0, text.Length - length).Trim();
			if (!LooksLikeSimpleNumber(text2))
			{
				return false;
			}
			translated = text2 + " 件物品无法整理";
			return true;
		}

		private static bool TryTranslateItemsOfTypePosition(string text, out string translated)
		{
			translated = text;
			if (!text.StartsWith("Items of type ", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			int num = text.IndexOf(" will be put on position ", StringComparison.OrdinalIgnoreCase);
			if (num <= "Items of type ".Length)
			{
				return false;
			}
			string text2 = text.Substring("Items of type ".Length, num - "Items of type ".Length).Trim();
			string text3 = text;
			int num2 = num + " will be put on position ".Length;
			string text4 = text3.Substring(num2, text3.Length - num2).Trim();
			bool flag = false;
			if (text4.EndsWith(" for this game", StringComparison.OrdinalIgnoreCase))
			{
				flag = true;
				text3 = text4;
				num2 = " for this game".Length;
				text4 = text3.Substring(0, text3.Length - num2).TrimEnd();
			}
			if (text2.Length == 0 || text4.Length == 0)
			{
				return false;
			}
			string text5 = LocalizeCommandItemName(text2);
			translated = (flag ? ("本局内,类型为 " + text5 + " 的物品将放到 " + text4 + " 位置") : ("类型为 " + text5 + " 的物品将放到 " + text4 + " 位置"));
			return true;
		}

		private static bool TryTranslateMovingAllItemsOfType(string text, out string translated)
		{
			translated = text;
			if (!text.StartsWith("Moving all items of type ", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			int num = text.IndexOf(" to position ", StringComparison.OrdinalIgnoreCase);
			if (num <= "Moving all items of type ".Length)
			{
				return false;
			}
			string text2 = text.Substring("Moving all items of type ".Length, num - "Moving all items of type ".Length).Trim();
			int num2 = num + " to position ".Length;
			string text3 = text.Substring(num2, text.Length - num2).Trim();
			if (text2.Length == 0 || text3.Length == 0)
			{
				return false;
			}
			translated = "正在将所有 " + LocalizeCommandItemName(text2) + " 类物品移动到 " + text3 + " 位置";
			return true;
		}

		private static bool TryTranslateSellingItemsSummary(string text, out string translated)
		{
			translated = text;
			if (!text.StartsWith("Selling ", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string markerText;
			int num = FindFirstMarker(text, "Selling ".Length, SellingNamedMarkers, out markerText);
			string text4;
			int num4;
			if (num > "Selling ".Length)
			{
				string text2 = text.Substring("Selling ".Length, num - "Selling ".Length).Trim();
				int num2 = num + markerText.Length;
				int num3 = text.IndexOf("\" with a total value of ", num2, StringComparison.OrdinalIgnoreCase);
				if (!LooksLikeSimpleNumber(text2) || num3 <= num2)
				{
					return false;
				}
				string text3 = text.Substring(num2, num3 - num2).Trim();
				text4 = text;
				num4 = num3 + "\" with a total value of ".Length;
				string text5 = text4.Substring(num4, text4.Length - num4).Trim();
				if (text3.Length == 0 || text5.Length == 0)
				{
					return false;
				}
				translated = "正在出售 " + text2 + " 件名为 \"" + LocalizeCommandItemName(text3) + "\" 的物品,总价值 " + LocalizeCommandResultValueTail(text5);
				return true;
			}
			string markerText2;
			int num5 = FindFirstMarker(text, "Selling ".Length, SellingCountMarkers, out markerText2);
			if (num5 <= "Selling ".Length)
			{
				return false;
			}
			string text6 = text.Substring("Selling ".Length, num5 - "Selling ".Length).Trim();
			text4 = text;
			num4 = num5 + markerText2.Length;
			string text7 = text4.Substring(num4, text4.Length - num4).Trim();
			if (!LooksLikeSimpleNumber(text6) || text7.Length == 0)
			{
				return false;
			}
			translated = "正在出售 " + text6 + " 件物品,总价值 " + LocalizeCommandResultValueTail(text7);
			return true;
		}

		private static int FindFirstMarker(string text, int startIndex, string[] markers, out string markerText)
		{
			int num = -1;
			markerText = string.Empty;
			foreach (string text2 in markers)
			{
				int num2 = text.IndexOf(text2, startIndex, StringComparison.OrdinalIgnoreCase);
				if (num2 >= 0 && (num < 0 || num2 < num))
				{
					num = num2;
					markerText = text2;
				}
			}
			return num;
		}

		private static string LocalizeCommandResultValueTail(string value)
		{
			string text = value.Replace(" overtime", " 加班奖励", StringComparison.OrdinalIgnoreCase).Replace(", sold every unblacklisted item", ",已出售所有未列入黑名单的物品", StringComparison.OrdinalIgnoreCase);
			if (!TryTranslateSoldRequestedResultTail(text, out string translated))
			{
				return text;
			}
			return translated;
		}

		private static bool TryTranslateSoldRequestedSummary(string text, out string translated)
		{
			return TryTranslateSoldRequestedSummaryCore(text, out translated);
		}

		private static bool TryTranslateSoldRequestedResultTail(string text, out string translated)
		{
			translated = text;
			if (TryTranslateSoldRequestedSummaryCore(text, out translated))
			{
				return true;
			}
			int num = text.LastIndexOf(':');
			if (num <= 0 || num >= text.Length - 1)
			{
				return false;
			}
			string text2 = text.Substring(0, num).TrimEnd();
			int num2 = num + 1;
			string text3 = text.Substring(num2, text.Length - num2).TrimStart();
			if (text2.Length == 0 || !TryTranslateSoldRequestedSummaryCore(text3, out string translated2))
			{
				return false;
			}
			translated = text2 + ":" + translated2;
			return true;
		}

		private static bool TryTranslateSoldRequestedSummaryCore(string text, out string translated)
		{
			translated = text;
			text = text.Trim();
			int num = text.IndexOf(" sold / ", StringComparison.OrdinalIgnoreCase);
			if (num <= 0 || !text.EndsWith(" requested", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string text2 = text.Substring(0, num).Trim();
			string text3 = text.Substring(num + " sold / ".Length, text.Length - num - " sold / ".Length - " requested".Length).Trim();
			if (!LooksLikeSimpleNumber(text2) || !LooksLikeSimpleNumber(text3))
			{
				return false;
			}
			translated = "已出售 " + text2 + " / 目标 " + text3;
			return true;
		}

		private static bool TryTranslateCommandValueLabel(string text, string prefix, string localizedLabel, out string translated)
		{
			translated = text;
			if (!text.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			int length = prefix.Length;
			string text2 = text.Substring(length, text.Length - length).Trim();
			if (text2.Length == 0)
			{
				return false;
			}
			translated = localizedLabel + ":" + text2;
			return true;
		}

		private static bool TryTranslateMoneyInTerminal(string text, out string translated)
		{
			translated = text;
			if (!text.StartsWith("Money in terminal", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			int num = FindTopLevelColon(text);
			if (num <= 0 || num >= text.Length - 1)
			{
				return false;
			}
			string text2 = text.Substring(0, num);
			int num2 = num + 1;
			string text3 = text.Substring(num2, text.Length - num2).Trim();
			if (text3.Length == 0)
			{
				return false;
			}
			translated = ((text2.IndexOf("desk", StringComparison.OrdinalIgnoreCase) >= 0) ? ("终端资金(含柜台):" + text3) : ("终端资金:" + text3));
			return true;
		}

		private static string LocalizeCommandItemName(string item)
		{
			string text = item.Trim();
			if (text.Length == 0)
			{
				return text;
			}
			string text2 = TranslationService.BuildTerminalLocalizedItemName(text);
			if (!string.IsNullOrWhiteSpace(text2))
			{
				return text2;
			}
			return text;
		}

		private static bool LooksLikeSimpleNumber(string value)
		{
			if (value.Length == 0)
			{
				return false;
			}
			for (int i = 0; i < value.Length; i++)
			{
				if (!char.IsDigit(value[i]))
				{
					return false;
				}
			}
			return true;
		}

		private static bool TryTranslateDiscountAlertNoDiscountText(string text, out string translated)
		{
			translated = text;
			int num = text.Length - text.TrimStart().Length;
			int num2 = text.Length - text.TrimEnd().Length;
			int num3 = text.Length - num - num2;
			if (num3 <= 0)
			{
				return false;
			}
			string text2 = ((num > 0) ? text.Substring(0, num) : string.Empty);
			string text3;
			if (num2 <= 0)
			{
				text3 = string.Empty;
			}
			else
			{
				int num4 = num2;
				int length = text.Length;
				int num5 = length - num4;
				text3 = text.Substring(num5, length - num5);
			}
			string text4 = text3;
			string text5 = text.Substring(num, num3);
			string text6 = string.Empty;
			string text7 = string.Empty;
			string prefix;
			string inner;
			string suffix;
			while (TryExtractOuterSimpleRichTextEnvelope(text5.Trim(), out prefix, out inner, out suffix))
			{
				text6 += prefix;
				text7 = suffix + text7;
				text5 = inner;
			}
			if (!LooksLikeDiscountAlertNoDiscountCore(text5))
			{
				return false;
			}
			translated = text2 + text6 + "暂无折扣\n明天再来查看" + text7 + text4;
			return true;
		}

		private static bool LooksLikeDiscountAlertNoDiscountText(string text)
		{
			return LooksLikeDiscountAlertNoDiscountCore(StripLeadingSimpleRichTextTags(StripOuterSimpleRichTextEnvelope(text)));
		}

		private static bool LooksLikeDiscountAlertNoDiscountCore(string text)
		{
			return NormalizeAsciiWhitespace(text.Replace("\\n", "\n", StringComparison.Ordinal).Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n')).Equals("None :( Check back tomorrow!", StringComparison.OrdinalIgnoreCase);
		}

		internal static bool TryTranslateBetterSavesDeleteFilePrompt(string? source, int fileToDelete, out string translated)
		{
			translated = source ?? string.Empty;
			if (fileToDelete <= 0 || string.IsNullOrWhiteSpace(source))
			{
				return false;
			}
			if (TryExtractDeleteFileAlias(source, out string alias))
			{
				translated = "要删除 " + alias + " 吗";
				return true;
			}
			if (!TryExtractDeleteFileNumber(source, out string _) && !LooksLikeLocalizedDeleteFileNumberPrompt(source))
			{
				return false;
			}
			translated = "要删除 " + fileToDelete.ToString(CultureInfo.InvariantCulture) + " 号存档吗";
			return true;
		}

		private static bool TryTranslateExactUiText(string text, out string translated)
		{
			translated = text;
			if (ExactEntries.TryGetValue(text, out translated))
			{
				return true;
			}
			if (text.EndsWith(":", StringComparison.Ordinal))
			{
				string