Decompiled source of Autolocalization v1.0.1

Autolocalization.dll

Decompiled 2 months ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("Autolocalization")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+f037d14c974c584a2dd277c4edd844e8c24a70a2")]
[assembly: AssemblyProduct("Autolocalization")]
[assembly: AssemblyTitle("Autolocalization")]
[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 Autolocalization
{
	public static class Preloader
	{
		public static class ConfigDescriptionPatch
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			public static void Prefix(ref string description)
			{
				if (string.IsNullOrEmpty(description))
				{
					return;
				}
				try
				{
					if (GlobalTranslations.TryGetValue(description, out string value))
					{
						description = value;
					}
					else if (!ProcessedTexts.Contains(description))
					{
						UntranslatedQueue.Enqueue(description);
						lastProcessTime = DateTime.UtcNow.Ticks;
					}
				}
				catch (Exception arg)
				{
					PreloaderLog.LogError((object)$"配置描述处理异常: {arg}");
				}
			}
		}

		internal static ManualLogSource PreloaderLog;

		private static readonly Harmony Harmony = new Harmony(".com.HsgtLgt.autolocalization.preloader");

		public static readonly string PluginConfigDir = Path.Combine(Paths.ConfigPath, "智能本地化引擎");

		public static readonly string GlobalTranslationsPath = Path.Combine(PluginConfigDir, "AutolocalizationGlobalTranslations.yaml");

		public static readonly string UntranslatedTextsPath = Path.Combine(PluginConfigDir, "AutolocalizationUntranslatedTexts.yaml");

		public static readonly string TranslationStatePath = Path.Combine(PluginConfigDir, "AutolocalizationState.bin");

		public static readonly string ConfigPath = Path.Combine(PluginConfigDir, "Config.yaml");

		private static ConfigFile configFile;

		private static readonly ConcurrentDictionary<string, string> GlobalTranslations = new ConcurrentDictionary<string, string>(StringComparer.Ordinal);

		private static readonly HashSet<string> ProcessedTexts = new HashSet<string>(StringComparer.Ordinal);

		private static readonly ConcurrentQueue<string> UntranslatedQueue = new ConcurrentQueue<string>();

		private static readonly object StateLock = new object();

		private static FileSystemWatcher fileWatcher;

		private static bool reloadRequested = false;

		private static DateTime lastReloadTime = DateTime.MinValue;

		private static Thread processingThread;

		private static volatile bool isRunning = true;

		private static long lastProcessTime;

		public static readonly ISerializer YamlSerializer = ((BuilderSkeleton<SerializerBuilder>)new SerializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).Build();

		public static readonly IDeserializer YamlDeserializer = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).Build();

		public static bool Initialized { get; private set; }

		public static bool DebugMode { get; set; } = false;


		public static void Initialize()
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			if (!Initialized)
			{
				PreloaderLog = Logger.CreateLogSource("智能本地化引擎(预加载)");
				Directory.CreateDirectory(PluginConfigDir);
				LoadConfig();
				if (DebugMode)
				{
					PreloaderLog.LogInfo((object)"预加载器初始化开始");
				}
				EnsureBasicFilesExist();
				LoadTranslationState();
				StartProcessingThread();
				SetupFileWatcher();
				Harmony.Patch((MethodBase)typeof(ConfigDescription).GetConstructor(new Type[3]
				{
					typeof(string),
					typeof(AcceptableValueBase),
					typeof(object[])
				}), new HarmonyMethod(typeof(ConfigDescriptionPatch).GetMethod("Prefix")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Initialized = true;
				PreloaderLog.LogInfo((object)"预加载器初始化完成 - 已应用核心补丁");
			}
		}

		private static void LoadConfig()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			try
			{
				configFile = new ConfigFile(ConfigPath, true);
				DebugMode = configFile.Bind<bool>("General", "DebugMode", false, "启用调试日志输出(可能影响性能)").Value;
				if (DebugMode)
				{
					PreloaderLog.LogInfo((object)("配置文件路径: " + ConfigPath));
					PreloaderLog.LogInfo((object)$"调试模式: {DebugMode}");
				}
			}
			catch (Exception arg)
			{
				PreloaderLog.LogError((object)$"加载配置失败: {arg}");
			}
		}

		private static void EnsureBasicFilesExist()
		{
			try
			{
				if (!File.Exists(GlobalTranslationsPath))
				{
					File.WriteAllText(GlobalTranslationsPath, "{}");
					if (DebugMode)
					{
						PreloaderLog.LogInfo((object)("已创建全局翻译文件: " + GlobalTranslationsPath));
					}
				}
				if (!File.Exists(UntranslatedTextsPath))
				{
					File.WriteAllText(UntranslatedTextsPath, "{}");
					if (DebugMode)
					{
						PreloaderLog.LogInfo((object)("已创建未翻译文本文件: " + UntranslatedTextsPath));
					}
				}
			}
			catch (Exception arg)
			{
				PreloaderLog.LogError((object)$"创建基本文件失败: {arg}");
			}
		}

		private static void LoadTranslationState()
		{
			if (File.Exists(GlobalTranslationsPath))
			{
				try
				{
					string text = File.ReadAllText(GlobalTranslationsPath);
					Dictionary<string, string> dictionary = YamlDeserializer.Deserialize<Dictionary<string, string>>(text) ?? new Dictionary<string, string>();
					foreach (KeyValuePair<string, string> item2 in dictionary)
					{
						GlobalTranslations[item2.Key] = item2.Value;
						ProcessedTexts.Add(item2.Key);
					}
					PreloaderLog.LogInfo((object)$"已加载全局翻译: {dictionary.Count} 条记录");
				}
				catch (Exception arg)
				{
					PreloaderLog.LogError((object)$"加载全局翻译失败: {arg}");
				}
			}
			if (File.Exists(UntranslatedTextsPath))
			{
				try
				{
					string text2 = File.ReadAllText(UntranslatedTextsPath);
					Dictionary<string, string> dictionary2 = YamlDeserializer.Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>();
					foreach (string key in dictionary2.Keys)
					{
						ProcessedTexts.Add(key);
					}
					if (DebugMode)
					{
						PreloaderLog.LogInfo((object)$"已加载已处理文本记录: {dictionary2.Count} 条");
					}
				}
				catch (Exception arg2)
				{
					PreloaderLog.LogError((object)$"加载未翻译文本记录失败: {arg2}");
				}
			}
			if (!File.Exists(TranslationStatePath))
			{
				return;
			}
			try
			{
				using MemoryStream input = new MemoryStream(File.ReadAllBytes(TranslationStatePath));
				using BinaryReader binaryReader = new BinaryReader(input);
				int num = binaryReader.ReadInt32();
				for (int i = 0; i < num; i++)
				{
					string item = binaryReader.ReadString();
					ProcessedTexts.Add(item);
				}
				if (DebugMode)
				{
					PreloaderLog.LogInfo((object)$"已加载持久化状态: {num} 条记录");
				}
			}
			catch (Exception arg3)
			{
				PreloaderLog.LogError((object)$"加载持久化状态失败: {arg3}");
			}
		}

		private static void StartProcessingThread()
		{
			processingThread = new Thread(ProcessBackgroundTasks)
			{
				IsBackground = true,
				Priority = ThreadPriority.BelowNormal,
				Name = "Autolocalization Processing"
			};
			processingThread.Start();
			if (DebugMode)
			{
				PreloaderLog.LogInfo((object)"后台处理线程已启动");
			}
		}

		private static void ProcessBackgroundTasks()
		{
			if (DebugMode)
			{
				PreloaderLog.LogInfo((object)"后台处理线程开始运行");
			}
			List<string> list = new List<string>(100);
			DateTime utcNow = DateTime.UtcNow;
			while (isRunning)
			{
				try
				{
					if (reloadRequested && (DateTime.UtcNow - lastReloadTime).TotalSeconds > 5.0)
					{
						ReloadTranslations();
						reloadRequested = false;
					}
					string result;
					while (UntranslatedQueue.TryDequeue(out result))
					{
						if (!string.IsNullOrEmpty(result))
						{
							list.Add(result);
							ProcessedTexts.Add(result);
							if (list.Count >= 100 || (DateTime.UtcNow - utcNow).TotalSeconds > 10.0)
							{
								SaveBatch(list);
								list.Clear();
								utcNow = DateTime.UtcNow;
							}
						}
					}
					if ((DateTime.UtcNow - utcNow).TotalSeconds > 30.0 && list.Count > 0)
					{
						SaveBatch(list);
						list.Clear();
						utcNow = DateTime.UtcNow;
					}
					if (DebugMode && (DateTime.UtcNow - utcNow).TotalSeconds > 60.0)
					{
						LogSystemStatus();
						utcNow = DateTime.UtcNow;
					}
					Thread.Sleep(100);
				}
				catch (Exception arg)
				{
					PreloaderLog.LogError((object)$"后台处理线程异常: {arg}");
					Thread.Sleep(1000);
				}
			}
			if (list.Count > 0)
			{
				SaveBatch(list);
			}
			SavePersistentState();
			if (DebugMode)
			{
				PreloaderLog.LogInfo((object)"后台处理线程已停止");
			}
		}

		private static void SaveBatch(List<string> batch)
		{
			if (batch.Count == 0)
			{
				return;
			}
			try
			{
				Dictionary<string, string> dictionary = new Dictionary<string, string>();
				if (File.Exists(UntranslatedTextsPath))
				{
					string text = File.ReadAllText(UntranslatedTextsPath);
					dictionary = YamlDeserializer.Deserialize<Dictionary<string, string>>(text) ?? new Dictionary<string, string>();
				}
				int num = 0;
				foreach (string item in batch)
				{
					if (!dictionary.ContainsKey(item))
					{
						dictionary[item] = item;
						num++;
					}
				}
				if (num > 0)
				{
					string contents = YamlSerializer.Serialize((object)dictionary);
					File.WriteAllText(UntranslatedTextsPath, contents);
					if (DebugMode)
					{
						PreloaderLog.LogInfo((object)$"已添加 {num} 条新未翻译文本到文件");
					}
				}
				SavePersistentState();
			}
			catch (Exception arg)
			{
				PreloaderLog.LogError((object)$"保存批次失败: {arg}");
			}
		}

		private static void SavePersistentState()
		{
			lock (StateLock)
			{
				try
				{
					using MemoryStream memoryStream = new MemoryStream();
					using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
					binaryWriter.Write(ProcessedTexts.Count);
					foreach (string processedText in ProcessedTexts)
					{
						binaryWriter.Write(processedText);
					}
					File.WriteAllBytes(TranslationStatePath, memoryStream.ToArray());
					if (DebugMode)
					{
						PreloaderLog.LogDebug((object)$"已保存持久化状态: {ProcessedTexts.Count} 条记录");
					}
				}
				catch (Exception arg)
				{
					PreloaderLog.LogError((object)$"保存持久化状态失败: {arg}");
				}
			}
		}

		private static void SetupFileWatcher()
		{
			try
			{
				fileWatcher = new FileSystemWatcher(PluginConfigDir)
				{
					NotifyFilter = NotifyFilters.LastWrite,
					Filter = "*.yaml",
					EnableRaisingEvents = true,
					IncludeSubdirectories = false
				};
				fileWatcher.Changed += delegate(object sender, FileSystemEventArgs e)
				{
					if ((!(e.FullPath != GlobalTranslationsPath) || !(e.FullPath != UntranslatedTextsPath)) && !((DateTime.UtcNow - lastReloadTime).TotalSeconds < 5.0))
					{
						if (DebugMode)
						{
							PreloaderLog.LogInfo((object)("检测到文件变更: " + Path.GetFileName(e.FullPath)));
						}
						reloadRequested = true;
						lastReloadTime = DateTime.UtcNow;
					}
				};
				if (DebugMode)
				{
					PreloaderLog.LogInfo((object)("文件监视器已启用,监控目录: " + PluginConfigDir));
				}
			}
			catch (Exception arg)
			{
				PreloaderLog.LogError((object)$"创建文件监视器失败: {arg}");
			}
		}

		private static void ReloadTranslations()
		{
			try
			{
				PreloaderLog.LogInfo((object)"开始重新加载翻译...");
				if (File.Exists(GlobalTranslationsPath))
				{
					string text = File.ReadAllText(GlobalTranslationsPath);
					Dictionary<string, string> dictionary = YamlDeserializer.Deserialize<Dictionary<string, string>>(text) ?? new Dictionary<string, string>();
					foreach (KeyValuePair<string, string> item in dictionary)
					{
						GlobalTranslations[item.Key] = item.Value;
					}
					PreloaderLog.LogInfo((object)$"已重新加载全局翻译: {dictionary.Count} 条记录");
				}
				if (File.Exists(UntranslatedTextsPath))
				{
					string text2 = File.ReadAllText(UntranslatedTextsPath);
					Dictionary<string, string> dictionary2 = YamlDeserializer.Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>();
					foreach (string key in dictionary2.Keys)
					{
						if (!ProcessedTexts.Contains(key))
						{
							ProcessedTexts.Add(key);
						}
					}
					if (DebugMode)
					{
						PreloaderLog.LogInfo((object)$"已重新加载未翻译文本: {dictionary2.Count} 条记录");
					}
				}
				PreloaderLog.LogInfo((object)"翻译重新加载完成");
			}
			catch (Exception arg)
			{
				PreloaderLog.LogError((object)$"重新加载翻译失败: {arg}");
			}
		}

		private static void LogSystemStatus()
		{
			PreloaderLog.LogInfo((object)("本地化引擎状态:\n" + $"翻译缓存: {GlobalTranslations.Count}条\n" + $"已处理文本: {ProcessedTexts.Count}条\n" + $"待处理队列: {UntranslatedQueue.Count}条\n" + $"最后处理时间: {DateTime.UtcNow.AddSeconds(-lastProcessTime):HH:mm:ss}"));
		}

		public static void Shutdown()
		{
			isRunning = false;
			processingThread?.Join(3000);
			SavePersistentState();
			fileWatcher?.Dispose();
			if (DebugMode)
			{
				PreloaderLog.LogInfo((object)"预加载器已关闭");
			}
		}
	}
	[BepInPlugin(".com.HsgtLgt.autolocalization", "智能本地化引擎", "1.0.0")]
	public class Autolocalization : BaseUnityPlugin
	{
		public const string PluginGuid = ".com.HsgtLgt.autolocalization";

		public const string PluginName = "智能本地化引擎";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource MainLog;

		public static ConfigEntry<bool> DebugModeConfig { get; private set; }

		public void Awake()
		{
			MainLog = ((BaseUnityPlugin)this).Logger;
			DebugModeConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugMode", false, "启用调试日志输出(可能影响性能)");
			Preloader.DebugMode = DebugModeConfig.Value;
			Preloader.Initialize();
			CheckLoadOrder();
		}

		private void CheckLoadOrder()
		{
			try
			{
				Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
				if (pluginInfos == null || pluginInfos.Count == 0)
				{
					return;
				}
				int num = 1;
				foreach (PluginInfo value in pluginInfos.Values)
				{
					if (value.Metadata.GUID == ".com.HsgtLgt.autolocalization")
					{
						if (num == 1)
						{
							((BaseUnityPlugin)this).Logger.LogInfo((object)"√ 智能本地化引擎是第一个加载的插件");
						}
						else
						{
							((BaseUnityPlugin)this).Logger.LogWarning((object)$"⚠ 加载顺序警告!当前位置: {num}/{pluginInfos.Count}\n  --在之前的插件无法本地化描述");
						}
						break;
					}
					num++;
				}
			}
			catch
			{
			}
		}

		public void OnDestroy()
		{
			Preloader.Shutdown();
		}
	}
	public static class StringExtensions
	{
		public static string Truncate(this string value, int maxLength)
		{
			if (string.IsNullOrEmpty(value))
			{
				return value;
			}
			if (value.Length > maxLength)
			{
				return value.Substring(0, maxLength) + "...";
			}
			return value;
		}
	}
}