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