Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PrefabLocalizer v1.6.2
PrefabLocalizer.dll
Decompiled 4 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using UnityEngine.SceneManagement; using ValMod.Localization.DeepSeekApi; using ValModLocalization.Data; using local; using 全局本地化.Data; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("全局本地化")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a1bcb304f805c35486011f12a5e86c4ac7217d27")] [assembly: AssemblyProduct("全局本地化")] [assembly: AssemblyTitle("全局本地化")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] 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; } } } public class MonsterPrefabFinder { public static GameObject FindMonsterPrefabByName(string monsterName) { if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } int stableHashCode = StringExtensionMethods.GetStableHashCode(monsterName); return ZNetScene.instance.GetPrefab(stableHashCode); } public static GameObject FindMonsterPrefabByHash(int monsterHash) { if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } return ZNetScene.instance.GetPrefab(monsterHash); } public static List<GameObject> GetAllMonsterPrefabs() { List<GameObject> list = new List<GameObject>(); if ((Object)(object)ZNetScene.instance == (Object)null) { return list; } List<string> prefabNames = ZNetScene.instance.GetPrefabNames(); foreach (string item in prefabNames) { GameObject prefab = ZNetScene.instance.GetPrefab(item); if ((Object)(object)prefab != (Object)null) { Humanoid component = prefab.GetComponent<Humanoid>(); MonsterAI component2 = prefab.GetComponent<MonsterAI>(); Character component3 = prefab.GetComponent<Character>(); if (((Object)(object)component != (Object)null && !Object.op_Implicit((Object)(object)prefab.GetComponent<Player>())) || (Object)(object)component2 != (Object)null || ((Object)(object)component3 != (Object)null && !component3.IsPlayer())) { list.Add(prefab); } } } return list; } } namespace ValMod.Localization.DeepSeekApi { internal class DeepSeekTranslator { private static DeepSeekTranslator _instance; private static readonly object _lock = new object(); private const string ApiEndpoint = "https://api.deepseek.com/chat/completions"; private const int TimeoutSeconds = 30; private string _apiKey; private readonly HttpClient _httpClient; private readonly CancellationTokenSource _globalCts; public static DeepSeekTranslator Instance { get { if (_instance == null) { lock (_lock) { if (_instance == null) { _instance = new DeepSeekTranslator(); } } } return _instance; } } private DeepSeekTranslator() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown _httpClient = new HttpClient(); _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); _httpClient.Timeout = TimeSpan.FromSeconds(30.0); _globalCts = new CancellationTokenSource(); } public void SetApiKey(string apiKey) { _apiKey = apiKey; } public async Task<string> TranslateAsync(string text, string targetLanguage, string context = null) { if (string.IsNullOrEmpty(_apiKey)) { throw new InvalidOperationException("API密钥未设置"); } if (string.IsNullOrEmpty(text)) { return string.Empty; } using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(new CancellationToken[1] { _globalCts.Token }); cts.CancelAfter(TimeSpan.FromSeconds(30.0)); try { string prompt = BuildPrompt(text, targetLanguage, context); string systemMessage = BuildSystemMessage(context); var requestBody = new { model = "deepseek-chat", messages = new[] { new { role = "system", content = systemMessage }, new { role = "user", content = prompt } }, stream = false, temperature = 0.7 }; string jsonContent = JsonConvert.SerializeObject((object)requestBody); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://api.deepseek.com/chat/completions") { Content = (HttpContent)new StringContent(jsonContent, Encoding.UTF8, "application/json") }; request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _apiKey); HttpResponseMessage response = await ((HttpMessageInvoker)_httpClient).SendAsync(request, cts.Token); response.EnsureSuccessStatusCode(); return CleanTranslationResult(JsonConvert.DeserializeObject<DeepSeekResponse>(await response.Content.ReadAsStringAsync())?.choices?[0]?.message?.content) ?? text; } catch (TaskCanceledException) { throw new Exception("翻译请求超时"); } catch (HttpRequestException val) { HttpRequestException val2 = val; HttpRequestException ex2 = val2; throw new Exception("HTTP请求失败: " + ((Exception)(object)ex2).Message, (Exception?)(object)ex2); } catch (Exception ex4) { Exception ex = ex4; throw new Exception("翻译服务出错: " + ex.Message, ex); } } private string BuildPrompt(string text, string targetLanguage, string context) { if (context != null && context.StartsWith("$")) { string text2 = text ?? "该物品"; return "为" + text2 + "设计一个简单的" + targetLanguage + "描述,要求简洁明了,符合维京游戏风格,直接返回描述内容不要其他文字"; } return "请将以下游戏文本翻译成" + targetLanguage + ",保持专业准确,直接返回翻译结果:\n" + text; } private string BuildSystemMessage(string context) { return (context != null && context.StartsWith("$")) ? "你是一个游戏物品描述设计师,创作符合维京风格的描述。" : "你是一个专业的翻译助手,请准确翻译用户提供的文本。"; } private string CleanTranslationResult(string result) { return result?.Trim('"', '\'', '“', '”', '。', ' ') ?? string.Empty; } public void CancelAllOperations() { _globalCts.Cancel(); } public void Dispose() { _globalCts?.Cancel(); HttpClient httpClient = _httpClient; if (httpClient != null) { ((HttpMessageInvoker)httpClient).Dispose(); } _globalCts?.Dispose(); } } internal class DeepSeekResponse { public List<DeepSeekChoice> choices { get; set; } } internal class DeepSeekChoice { public int index { get; set; } public DeepSeekMessage message { get; set; } public object logprobs { get; set; } public string finish_reason { get; set; } } internal class DeepSeekMessage { public string role { get; set; } public string content { get; set; } } } namespace local { public class 翻译工具 { public static Dictionary<string, EffectInfoData> 效果字典 = new Dictionary<string, EffectInfoData>(); public static Dictionary<string, iteminfodata> 物品字典 = new Dictionary<string, iteminfodata>(); public static Dictionary<string, monsterinfodata> 怪物字典 = new Dictionary<string, monsterinfodata>(); public static Dictionary<string, pieceInfoData> 工具字典 = new Dictionary<string, pieceInfoData>(); } public class 缓存 { public static Dictionary<string, GameObject> m_PrefabCache = new Dictionary<string, GameObject>(); public static Dictionary<int, GameObject> m_PrefabHashCache = new Dictionary<int, GameObject>(); public static Dictionary<string, string> monsterNameCache = new Dictionary<string, string>(); public static Dictionary<string, (string name, string desc)> pieceCache = new Dictionary<string, (string, string)>(); public static Dictionary<string, (string name, string desc)> statusEffectCache = new Dictionary<string, (string, string)>(); public static Dictionary<string, (string name, string desc, int hash)> itemTranslationCache = new Dictionary<string, (string, string, int)>(); } } namespace ValModLocalization.Data { public class 存放 { public string 预制名 { get; set; } = string.Empty; public string 名 { get; set; } = string.Empty; public string 描述 { get; set; } = string.Empty; public string 哈希 { get; set; } = string.Empty; } } namespace 全局本地化 { public static class TranslationProcessor { [Serializable] private class SerializableDictionary { public List<string> keys = new List<string>(); public List<int> values = new List<int>(); public SerializableDictionary() { } public SerializableDictionary(Dictionary<string, int> dict) { foreach (KeyValuePair<string, int> item in dict) { keys.Add(item.Key); values.Add(item.Value); } } public Dictionary<string, int> ToDictionary() { Dictionary<string, int> dictionary = new Dictionary<string, int>(); for (int i = 0; i < keys.Count && i < values.Count; i++) { dictionary[keys[i]] = values[i]; } return dictionary; } } public class TranslationTimer : IDisposable { private string _operationName; private Stopwatch _stopwatch; public TranslationTimer(string operationName) { _operationName = operationName; _stopwatch = Stopwatch.StartNew(); } public void Dispose() { _stopwatch.Stop(); Debug.Log((object)$"[TIMER] {_operationName} - 耗时: {_stopwatch.Elapsed.TotalSeconds:F2}秒"); } } private static Dictionary<string, int> translationStats = new Dictionary<string, int>(); private static Dictionary<string, int> progressTracker = new Dictionary<string, int>(); private static 存放 存 => 全局本地化.存; public static string AiLocalizationFolder { get; set; } public static int TranslationDelay { get; set; } = 50; public static string ProgressFile => Path.Combine(AiLocalizationFolder, "translation_progress.txt"); public static async void ProcessAllTranslations() { try { if (string.IsNullOrEmpty(AiLocalizationFolder)) { Debug.LogError((object)"翻译文件夹路径未设置!"); return; } if (!Directory.Exists(AiLocalizationFolder)) { Debug.LogError((object)("翻译文件夹不存在: " + AiLocalizationFolder)); return; } Debug.Log((object)"开始批量翻译处理..."); LoadProgress(); translationStats.Clear(); string[] allFiles = (from f in Directory.GetFiles(AiLocalizationFolder, "*", SearchOption.AllDirectories) where Path.GetExtension(f) == ".txt" && !Path.GetFileName(f).Contains("_translated") select f).ToArray(); Debug.Log((object)$"找到 {allFiles.Length} 个待翻译文件"); string[] array = allFiles; foreach (string filePath in array) { await ProcessSingleFile(filePath); } ClearProgress(); LogTranslationStats(); Debug.Log((object)"批量翻译处理完成!"); } catch (Exception ex2) { Exception ex = ex2; Debug.LogError((object)("批量翻译处理失败: " + ex.Message)); SaveProgress(); } } private static async Task ProcessSingleFile(string filePath) { try { string fileName = Path.GetFileNameWithoutExtension(filePath); string translatedFilePath = GetTranslatedFilePath(filePath); if (File.Exists(translatedFilePath)) { string fileKey = Path.GetFileName(filePath); if (!progressTracker.ContainsKey(fileKey) || progressTracker[fileKey] <= 0) { Debug.Log((object)("已翻译文件存在,跳过: " + fileName)); return; } Debug.Log((object)$"继续翻译文件: {fileName} (进度: {progressTracker[fileKey]})"); } Debug.Log((object)("处理文件: " + fileName)); if (fileName.StartsWith("汉化信息_怪物")) { await ProcessMonsterTranslations(filePath); } else if (fileName.StartsWith("汉化信息_工具")) { await ProcessPieceTranslations(filePath); } else if (fileName.StartsWith("汉化信息_效果")) { await ProcessStatusEffectsTranslations(filePath); } else if (fileName.StartsWith("汉化信息_物品")) { await ProcessItemTranslations(filePath); } else { Debug.LogWarning((object)("未知文件类型,跳过: " + fileName)); } } catch (Exception ex2) { Exception ex = ex2; Debug.LogError((object)("处理文件失败 " + filePath + ": " + ex.Message)); SaveProgress(); } } private static async Task ProcessItemTranslations(string filePath) { if (!File.Exists(filePath)) { Debug.LogError((object)("文件不存在: " + filePath)); return; } string[] lines = File.ReadAllLines(filePath, Encoding.UTF8); List<string> translatedLines = LoadPartialTranslation(filePath); int translatedCount = 0; string fileKey = Path.GetFileName(filePath); int startIndex = (progressTracker.ContainsKey(fileKey) ? progressTracker[fileKey] : 0); if (translatedLines.Count > 0) { Debug.Log((object)$"从临时文件继续翻译 {fileKey},已有 {translatedLines.Count} 行"); startIndex = Math.Max(startIndex, translatedLines.Count); } else { translatedLines = new List<string>(); for (int j = 0; j < Math.Min(startIndex, lines.Length); j++) { translatedLines.Add(lines[j]); } } Debug.Log((object)$"开始处理文件 {fileKey},从第 {startIndex} 行开始,总行数: {lines.Length}"); for (int i = startIndex; i < lines.Length; i++) { try { string line = lines[i]; if (i < translatedLines.Count) { continue; } translatedLines.Add(line); if (line.StartsWith(存.预制名) && i + 2 < lines.Length) { string prefabNameLine = line; string nameLine = lines[i + 1]; string descLine = lines[i + 2]; string originalName = nameLine.Substring(存.名.Length).Trim(); string originalDesc = descLine.Substring(存.描述.Length).Trim(); if (!ContainsChinese(originalName) || !ContainsChinese(originalDesc)) { using (new TranslationTimer("翻译物品 " + originalName)) { var (translatedName, translatedDesc) = await TranslateWithRetry(originalName, originalDesc, "物品"); translatedLines[translatedLines.Count - 1] = prefabNameLine; translatedLines.Add(存.名 + translatedName); translatedLines.Add(存.描述 + translatedDesc); translatedCount += 2; i += 2; } } else { translatedLines.Add(nameLine); translatedLines.Add(descLine); i += 2; } if (i + 1 < lines.Length && lines[i + 1].StartsWith(存.哈希)) { translatedLines.Add(lines[i + 1]); i++; } } progressTracker[fileKey] = i + 1; if (translatedCount > 0 && translatedCount % 10 == 0) { SaveProgress(); SavePartialTranslation(filePath, translatedLines); Debug.Log((object)$"已保存进度: {fileKey} - 第 {i + 1}/{lines.Length} 行"); } } catch (Exception ex) { Debug.LogError((object)$"处理第 {i} 行时出错: {ex.Message}"); SaveProgress(); SavePartialTranslation(filePath, translatedLines); throw; } } string outputPath = GetTranslatedFilePath(filePath); File.WriteAllLines(outputPath, translatedLines, Encoding.UTF8); CleanTempFile(filePath); translationStats["物品"] = translatedCount / 2; Debug.Log((object)$"物品翻译完成: {translatedCount / 2} 个物品已翻译"); } private static async Task ProcessMonsterTranslations(string filePath) { if (!File.Exists(filePath)) { Debug.LogError((object)("文件不存在: " + filePath)); return; } string[] lines = File.ReadAllLines(filePath, Encoding.UTF8); List<string> translatedLines = LoadPartialTranslation(filePath); int translatedCount = 0; string fileKey = Path.GetFileName(filePath); int startIndex = (progressTracker.ContainsKey(fileKey) ? progressTracker[fileKey] : 0); if (translatedLines.Count > 0) { startIndex = Math.Max(startIndex, translatedLines.Count); } else { translatedLines = new List<string>(); for (int j = 0; j < Math.Min(startIndex, lines.Length); j++) { translatedLines.Add(lines[j]); } } Debug.Log((object)$"开始处理怪物文件 {fileKey},从第 {startIndex} 行开始"); for (int i = startIndex; i < lines.Length; i++) { try { string line = lines[i]; if (i < translatedLines.Count) { continue; } translatedLines.Add(line); if (line.StartsWith(存.预制名) && i + 1 < lines.Length) { string prefabNameLine = line; string nameLine = lines[i + 1]; string originalName = nameLine.Substring(存.名.Length).Trim(); if (!ContainsChinese(originalName)) { using (new TranslationTimer("翻译怪物 " + originalName)) { string translatedName = await TranslateWithRetry(originalName, "怪物"); translatedLines[translatedLines.Count - 1] = prefabNameLine; translatedLines.Add(存.名 + translatedName); translatedCount++; i++; } } else { translatedLines.Add(nameLine); i++; } } progressTracker[fileKey] = i + 1; if (translatedCount > 0 && translatedCount % 10 == 0) { SaveProgress(); SavePartialTranslation(filePath, translatedLines); } } catch (Exception ex) { Debug.LogError((object)$"处理第 {i} 行时出错: {ex.Message}"); SaveProgress(); SavePartialTranslation(filePath, translatedLines); throw; } } string outputPath = GetTranslatedFilePath(filePath); File.WriteAllLines(outputPath, translatedLines, Encoding.UTF8); CleanTempFile(filePath); translationStats["怪物"] = translatedCount; Debug.Log((object)$"怪物翻译完成: {translatedCount} 个怪物已翻译"); } private static async Task ProcessPieceTranslations(string filePath) { if (!File.Exists(filePath)) { Debug.LogError((object)("文件不存在: " + filePath)); return; } string[] lines = File.ReadAllLines(filePath, Encoding.UTF8); List<string> translatedLines = LoadPartialTranslation(filePath); int translatedCount = 0; string fileKey = Path.GetFileName(filePath); int startIndex = (progressTracker.ContainsKey(fileKey) ? progressTracker[fileKey] : 0); if (translatedLines.Count > 0) { startIndex = Math.Max(startIndex, translatedLines.Count); } else { translatedLines = new List<string>(); for (int j = 0; j < Math.Min(startIndex, lines.Length); j++) { translatedLines.Add(lines[j]); } } Debug.Log((object)$"开始处理工具文件 {fileKey},从第 {startIndex} 行开始"); for (int i = startIndex; i < lines.Length; i++) { try { string line = lines[i]; if (i < translatedLines.Count) { continue; } translatedLines.Add(line); if (line.StartsWith(存.预制名) && i + 2 < lines.Length) { string prefabNameLine = line; string nameLine = lines[i + 1]; string descLine = lines[i + 2]; string originalName = nameLine.Substring(存.名.Length).Trim(); string originalDesc = descLine.Substring(存.描述.Length).Trim(); if (!ContainsChinese(originalName) || !ContainsChinese(originalDesc)) { using (new TranslationTimer("翻译工具 " + originalName)) { var (translatedName, translatedDesc) = await TranslateWithRetry(originalName, originalDesc, "建造项目"); translatedLines[translatedLines.Count - 1] = prefabNameLine; translatedLines.Add(存.名 + translatedName); translatedLines.Add(存.描述 + translatedDesc); translatedCount += 2; i += 2; } } else { translatedLines.Add(nameLine); translatedLines.Add(descLine); i += 2; } } progressTracker[fileKey] = i + 1; if (translatedCount > 0 && translatedCount % 10 == 0) { SaveProgress(); SavePartialTranslation(filePath, translatedLines); } } catch (Exception ex) { Debug.LogError((object)$"处理第 {i} 行时出错: {ex.Message}"); SaveProgress(); SavePartialTranslation(filePath, translatedLines); throw; } } string outputPath = GetTranslatedFilePath(filePath); File.WriteAllLines(outputPath, translatedLines, Encoding.UTF8); CleanTempFile(filePath); translationStats["工具"] = translatedCount / 2; Debug.Log((object)$"工具翻译完成: {translatedCount / 2} 个工具已翻译"); } private static async Task ProcessStatusEffectsTranslations(string filePath) { if (!File.Exists(filePath)) { Debug.LogError((object)("文件不存在: " + filePath)); return; } string[] lines = File.ReadAllLines(filePath, Encoding.UTF8); List<string> translatedLines = LoadPartialTranslation(filePath); int translatedCount = 0; string fileKey = Path.GetFileName(filePath); int startIndex = (progressTracker.ContainsKey(fileKey) ? progressTracker[fileKey] : 0); if (translatedLines.Count > 0) { startIndex = Math.Max(startIndex, translatedLines.Count); } else { translatedLines = new List<string>(); for (int j = 0; j < Math.Min(startIndex, lines.Length); j++) { translatedLines.Add(lines[j]); } } Debug.Log((object)$"开始处理状态效果文件 {fileKey},从第 {startIndex} 行开始"); for (int i = startIndex; i < lines.Length; i++) { try { string line = lines[i]; if (i < translatedLines.Count) { continue; } translatedLines.Add(line); if (line.StartsWith(存.预制名) && i + 2 < lines.Length) { string prefabNameLine = line; string nameLine = lines[i + 1]; string descLine = lines[i + 2]; string originalName = nameLine.Substring(存.名.Length).Trim(); string originalDesc = descLine.Substring(存.描述.Length).Trim(); if (!ContainsChinese(originalName) || !ContainsChinese(originalDesc)) { using (new TranslationTimer("翻译状态效果 " + originalName)) { var (translatedName, translatedDesc) = await TranslateWithRetry(originalName, originalDesc, "角色状态效果"); translatedLines[translatedLines.Count - 1] = prefabNameLine; translatedLines.Add(存.名 + translatedName); translatedLines.Add(存.描述 + translatedDesc); translatedCount += 2; i += 2; } } else { translatedLines.Add(nameLine); translatedLines.Add(descLine); i += 2; } } progressTracker[fileKey] = i + 1; if (translatedCount > 0 && translatedCount % 10 == 0) { SaveProgress(); SavePartialTranslation(filePath, translatedLines); } } catch (Exception ex) { Debug.LogError((object)$"处理第 {i} 行时出错: {ex.Message}"); SaveProgress(); SavePartialTranslation(filePath, translatedLines); throw; } } string outputPath = GetTranslatedFilePath(filePath); File.WriteAllLines(outputPath, translatedLines, Encoding.UTF8); CleanTempFile(filePath); translationStats["状态效果"] = translatedCount / 2; Debug.Log((object)$"状态效果翻译完成: {translatedCount / 2} 个效果已翻译"); } private static async Task<string> TranslateWithRetry(string text, string fileType, int maxRetries = 3) { for (int retry = 0; retry < maxRetries; retry++) { try { return await TranslateText(text); } catch (Exception ex) when (retry < maxRetries - 1) { Debug.LogWarning((object)$"翻译重试 {retry + 1}/{maxRetries}: {ex.Message}"); await Task.Delay(1000 * (retry + 1)); } } Debug.LogError((object)("翻译失败,返回原始文本: " + text)); return text; } private static async Task<(string name, string desc)> TranslateWithRetry(string originalName, string originalDesc, string fileType, int maxRetries = 3) { for (int retry = 0; retry < maxRetries; retry++) { try { return await TranslateWithIntelligence(originalName, originalDesc, fileType); } catch (Exception ex) when (retry < maxRetries - 1) { Debug.LogWarning((object)$"翻译重试 {retry + 1}/{maxRetries}: {ex.Message}"); await Task.Delay(1000 * (retry + 1)); } } Debug.LogError((object)("翻译失败,返回原始文本: " + originalName)); return (originalName, originalDesc); } private static async Task<(string name, string desc)> TranslateWithIntelligence(string originalName, string originalDesc, string fileType) { try { string translatedName = await DeepSeekTranslator.Instance.TranslateAsync(originalName, 全局本地化.TARGET_LANGUAGE.Value); string translatedDesc = (string.IsNullOrEmpty(originalDesc) ? (await DeepSeekTranslator.Instance.TranslateAsync(translatedName, 全局本地化.TARGET_LANGUAGE.Value, "$design_description")) : ((!originalDesc.StartsWith("$")) ? (await DeepSeekTranslator.Instance.TranslateAsync(originalDesc, 全局本地化.TARGET_LANGUAGE.Value)) : (await DeepSeekTranslator.Instance.TranslateAsync(translatedName, 全局本地化.TARGET_LANGUAGE.Value, originalDesc)))); if (string.IsNullOrEmpty(translatedDesc)) { translatedDesc = translatedName + "的装备"; } await Task.Delay(TranslationDelay); return (translatedName, translatedDesc); } catch (Exception ex2) { Exception ex = ex2; Debug.LogError((object)("智能翻译失败: " + ex.Message)); return (originalName, originalDesc); } } private static void SavePartialTranslation(string originalPath, List<string> translatedLines) { try { string path = GetTranslatedFilePath(originalPath) + ".temp"; File.WriteAllLines(path, translatedLines, Encoding.UTF8); } catch (Exception ex) { Debug.LogWarning((object)("保存临时文件失败: " + ex.Message)); } } private static List<string> LoadPartialTranslation(string originalPath) { try { string path = GetTranslatedFilePath(originalPath) + ".temp"; if (File.Exists(path)) { List<string> list = File.ReadAllLines(path, Encoding.UTF8).ToList(); Debug.Log((object)$"加载临时翻译文件: {Path.GetFileName(originalPath)},共 {list.Count} 行"); return list; } } catch (Exception ex) { Debug.LogWarning((object)("加载临时文件失败: " + ex.Message)); } return new List<string>(); } private static void CleanTempFile(string originalPath) { try { string path = GetTranslatedFilePath(originalPath) + ".temp"; if (File.Exists(path)) { File.Delete(path); Debug.Log((object)("清理临时文件: " + Path.GetFileName(path))); } } catch (Exception ex) { Debug.LogWarning((object)("清理临时文件失败: " + ex.Message)); } } private static void LoadProgress() { try { if (File.Exists(ProgressFile)) { string text = File.ReadAllText(ProgressFile); progressTracker = JsonUtility.FromJson<SerializableDictionary>(text)?.ToDictionary() ?? new Dictionary<string, int>(); Debug.Log((object)$"加载翻译进度,共 {progressTracker.Count} 个文件的进度"); } } catch (Exception ex) { Debug.LogWarning((object)("加载进度文件失败: " + ex.Message)); progressTracker = new Dictionary<string, int>(); } } private static void SaveProgress() { try { SerializableDictionary serializableDictionary = new SerializableDictionary(progressTracker); string contents = JsonUtility.ToJson((object)serializableDictionary); File.WriteAllText(ProgressFile, contents); } catch (Exception ex) { Debug.LogWarning((object)("保存进度文件失败: " + ex.Message)); } } private static void ClearProgress() { try { if (File.Exists(ProgressFile)) { File.Delete(ProgressFile); Debug.Log((object)"清理进度文件"); } string[] files = Directory.GetFiles(AiLocalizationFolder, "*.temp", SearchOption.AllDirectories); foreach (string text in files) { try { File.Delete(text); } catch (Exception ex) { Debug.LogWarning((object)("清理临时文件失败 " + text + ": " + ex.Message)); } } progressTracker.Clear(); } catch (Exception ex2) { Debug.LogWarning((object)("清理进度文件失败: " + ex2.Message)); } } private static async Task<string> TranslateText(string text) { if (string.IsNullOrEmpty(text)) { return text; } try { string translatedText = await DeepSeekTranslator.Instance.TranslateAsync(text, 全局本地化.TARGET_LANGUAGE.Value); await Task.Delay(TranslationDelay); return translatedText ?? text; } catch (Exception ex) { Debug.LogError((object)("翻译文本失败 '" + text + "': " + ex.Message)); return text; } } private static string GetTranslatedFilePath(string originalPath) { string directoryName = Path.GetDirectoryName(originalPath); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(originalPath); string extension = Path.GetExtension(originalPath); return Path.Combine(directoryName, fileNameWithoutExtension + "_translated" + extension); } private static bool ContainsChinese(string text) { return !string.IsNullOrEmpty(text) && text.Any((char c) => c >= '一' && c <= '\u9fff'); } private static void LogTranslationStats() { Debug.Log((object)"=== 翻译统计 ==="); foreach (KeyValuePair<string, int> translationStat in translationStats) { Debug.Log((object)$"{translationStat.Key}: {translationStat.Value} 个条目已翻译"); } Debug.Log((object)"================="); } public static async void TestSingleFileTranslation(string fileName = "汉化信息_物品.txt") { try { string testFile = Path.Combine(AiLocalizationFolder, fileName); if (File.Exists(testFile)) { Debug.Log((object)("开始测试翻译文件: " + fileName)); await ProcessSingleFile(testFile); } else { Debug.LogError((object)("测试文件不存在: " + testFile)); } } catch (Exception ex2) { Exception ex = ex2; Debug.LogError((object)("测试翻译失败: " + ex.Message)); } } public static async void ResumeTranslation() { Debug.Log((object)"恢复上次的翻译进度..."); LoadProgress(); ProcessAllTranslations(); } public static void ResetProgress() { ClearProgress(); Debug.Log((object)"翻译进度已重置"); } public static string GetProgressInfo() { if (progressTracker.Count == 0) { return "暂无翻译进度"; } string text = "当前翻译进度:\n"; foreach (KeyValuePair<string, int> item in progressTracker) { text += $"{item.Key}: 第 {item.Value} 行\n"; } return text; } public static bool HasProgress() { return progressTracker.Count > 0; } public static void ShowProgress() { string progressInfo = GetProgressInfo(); Debug.Log((object)progressInfo); } } [BepInPlugin("lanlng_locailization", "懒濑的本地化", "1.6")] public class 全局本地化 : BaseUnityPlugin { [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPriority(800)] private class ObjectDBInitializationPatch { private static void Postfix(ObjectDB __instance) { InitializeAllData(__instance); Debug.Log((object)"懒濑:初始化成功!"); if (finish2.Value) { ApplyAllTranslations(__instance); } } } internal const string mod_GUID = "lanlng_locailization"; internal const string mod_NAME = "懒濑的本地化"; internal const string mod_VERSION = "1.6"; internal readonly Harmony harmony = new Harmony("lanlng_locailization"); public static 存放 存 = new 存放(); internal static string[] searchFields = Array.Empty<string>(); internal static List<iteminfodata> 物品汉化结果 = new List<iteminfodata>(); internal static List<EffectInfoData> 效果汉化结果 = new List<EffectInfoData>(); internal static List<monsterinfodata> 怪物汉化结果 = new List<monsterinfodata>(); internal static int num1 = 0; internal static int num2 = 0; internal static int num3 = 0; internal static int num4 = 0; internal static string configFolder = "BepInEx/config"; internal static string modLocalizationFolder = Path.Combine(configFolder, "mod汉化"); internal static string savePath = Path.Combine(Application.dataPath, "../" + modLocalizationFolder + "/汉化信息_物品.txt"); internal static string monstersavePath = Path.Combine(Application.dataPath, "../" + modLocalizationFolder + "/汉化信息_怪物.txt"); internal static string effectsavePath = Path.Combine(Application.dataPath, "../" + modLocalizationFolder + "/汉化信息_效果.txt"); internal static string piecesavePath = Path.Combine(Application.dataPath, "../" + modLocalizationFolder + "/汉化信息_工具.txt"); internal static string modSearchSavePath = Path.Combine(Application.dataPath, "../" + modLocalizationFolder + "/汉化信息_Mod名称.txt"); private static ConfigEntry<string> apiKey; private static ConfigEntry<bool> finish; private static ConfigEntry<bool> finish2; private static ConfigEntry<KeyboardShortcut> Shortcut; private static ConfigEntry<KeyboardShortcut> modShortcut; private static ConfigEntry<KeyboardShortcut> TranslateShortcut; private static ConfigEntry<KeyboardShortcut> textup; public static ConfigEntry<string> TARGET_LANGUAGE; public static string[] ItemSearchFields; public static string[] EffectSearchFields; public static string[] MonsterSearchFields; public static string[] PieceSearchFields; private static bool isInitialized = false; private const string FilterConfigFileName = "筛选条件.txt"; internal static string modNameConfigPath => Path.Combine(Application.dataPath, "../" + modLocalizationFolder + "/筛选条件_Mod名称.txt"); public void Awake() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) apiKey = ((BaseUnityPlugin)this).Config.Bind<string>("General通用", "APIKey", "sk-eb0f2f33abc548219d36d05b39e23177", "你的API密钥"); TARGET_LANGUAGE = ((BaseUnityPlugin)this).Config.Bind<string>("General通用", "ai翻译的目标语言如Japanese,Korean,Spanish,French,German,Russian,Italian,Portuguese,Dutch等", "中文", "你想要翻译成什么语言"); finish = ((BaseUnityPlugin)this).Config.Bind<bool>("General通用", "是否开启文本收集", true, "是否开启文本收集"); finish2 = ((BaseUnityPlugin)this).Config.Bind<bool>("General通用", "是否应用文本翻译", true, "是否应用文本翻译"); TranslateShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys快捷键", "api翻译导出快捷键", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "api翻译快捷键"); Shortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys快捷键", "筛选条件导出快捷键", new KeyboardShortcut((KeyCode)293, Array.Empty<KeyCode>()), "筛选条件导出快捷键"); modShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys快捷键", "mod筛选导出快捷键", new KeyboardShortcut((KeyCode)292, Array.Empty<KeyCode>()), "mod筛选导出快捷键"); textup = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys快捷键", "更新翻译", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "mod筛选导出快捷键"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"初始化 插件 lanlng_locailization "); Directory.CreateDirectory(Path.Combine(Application.dataPath, "../" + modLocalizationFolder)); TranslationProcessor.AiLocalizationFolder = Path.Combine(modLocalizationFolder, "ai翻译"); Directory.CreateDirectory(Path.Combine(Application.dataPath, "../" + TranslationProcessor.AiLocalizationFolder)); DeepSeekTranslator instance = DeepSeekTranslator.Instance; instance.SetApiKey(apiKey.Value); 存.预制名 = "预制名:"; 存.名 = "名字:"; 存.描述 = "描述:"; 存.哈希 = "哈希:"; harmony.PatchAll(); EnsureFilterFile("筛选条件.txt", new Dictionary<string, string[]> { { "物品", new string[2] { "_Ygg", "_Custom" } }, { "效果", new string[1] { "SE_" } }, { "怪物", new string[2] { "RRR", "Custom" } }, { "工具", new string[2] { "_piece", "_Piece" } } }); EnsureFilterFile("筛选条件_Mod名称.txt", new Dictionary<string, string[]> { { "Mod名称", new string[3] { "CustomMod", "Extended", "Additional" } } }); } private void EnsureFilterFile(string fileName, Dictionary<string, string[]> defaultSections) { try { string text = Path.Combine(Application.dataPath, "../" + modLocalizationFolder + "/" + fileName); if (File.Exists(text)) { return; } Directory.CreateDirectory(Path.GetDirectoryName(text)); List<string> list = new List<string>(); foreach (KeyValuePair<string, string[]> defaultSection in defaultSections) { list.Add("[" + defaultSection.Key + "]//filter condition for “" + defaultSection.Key + "”"); list.AddRange(defaultSection.Value); list.Add(""); } File.WriteAllLines(text, list, Encoding.UTF8); ((BaseUnityPlugin)this).Logger.LogInfo((object)("懒濑:已创建默认筛选文件 " + text)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("懒濑:创建筛选文件 " + fileName + " 失败: " + ex.Message)); } } public static void InitializeAllData(ObjectDB instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (isInitialized || (Object)(object)instance == (Object)null) { return; } Scene activeScene = SceneManager.GetActiveScene(); if (!(((Scene)(ref activeScene)).name != "main")) { LoadAllSearchFields(); if (finish.Value) { CollectAllItems(instance); CollectAllEffects(instance); CollectAllMonsters(); CollectAllPieces(); Debug.Log((object)"懒濑:完整数据收集完成"); } ModPrefabManager.InitializeModInfo(); isInitialized = true; } } public static void ExportFilteredData() { try { LoadAllSearchFields(); ExportFilteredItems(); ExportFilteredEffects(); ExportFilteredMonsters(); ExportFilteredPieces(); Debug.Log((object)"懒濑:筛选数据导出完成"); } catch (Exception ex) { Debug.LogError((object)("懒濑:导出数据时出错: " + ex.Message)); } } private static void CollectAllItems(ObjectDB instance) { foreach (KeyValuePair<int, GameObject> item in instance.m_itemByHash) { if ((Object)(object)item.Value == (Object)null) { continue; } ItemDrop component = item.Value.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null)) { iteminfodata value = new iteminfodata { itemname = GetLocalizedText(component.m_itemData.m_shared.m_name), itemdesc = GetLocalizedText(component.m_itemData.m_shared.m_description), itemHash = item.Key }; if (!翻译工具.物品字典.ContainsKey(((Object)item.Value).name)) { 翻译工具.物品字典.Add(((Object)item.Value).name, value); } } } Debug.Log((object)$"懒濑:收集到 {翻译工具.物品字典.Count} 个物品"); } private static void CollectAllEffects(ObjectDB instance) { foreach (StatusEffect statusEffect in instance.m_StatusEffects) { if (!((Object)(object)statusEffect == (Object)null) && !翻译工具.效果字典.ContainsKey(((Object)statusEffect).name)) { EffectInfoData value = new EffectInfoData { effectprename = ((Object)statusEffect).name, effectname = GetLocalizedText(statusEffect.m_name), effectdesc = GetLocalizedText(statusEffect.m_tooltip), effecthash = statusEffect.m_nameHash }; if (!翻译工具.效果字典.ContainsKey(((Object)statusEffect).name)) { 翻译工具.效果字典.Add(((Object)statusEffect).name, value); } } } Debug.Log((object)$"懒濑:收集到 {翻译工具.效果字典.Count} 个效果"); } private static void CollectAllMonsters() { Humanoid[] array = Resources.FindObjectsOfTypeAll<Humanoid>(); Humanoid[] array2 = array; foreach (Humanoid val in array2) { monsterinfodata value = new monsterinfodata { monsterprename = ((Object)val).name, monstername = GetLocalizedText(((Character)((Component)val).GetComponent<Humanoid>()).m_name), monsterhash = ((object)val).GetHashCode() }; if (!翻译工具.怪物字典.ContainsKey(((Object)val).name)) { 翻译工具.怪物字典.Add(((Object)val).name, value); } } Debug.Log((object)$"懒濑:收集到 {翻译工具.怪物字典.Count} 个怪物"); } private static void CollectAllPieces() { Piece[] array = Resources.FindObjectsOfTypeAll<Piece>(); Piece[] array2 = array; foreach (Piece val in array2) { if (!((Object)(object)val == (Object)null) && !翻译工具.工具字典.ContainsKey(((Object)val).name)) { pieceInfoData value = new pieceInfoData { pieceprename = ((Object)val).name, piecename = GetLocalizedText(val.m_name), piecedesc = GetLocalizedText(val.m_description), piecehash = ((object)val).GetHashCode() }; if (!翻译工具.工具字典.ContainsKey(((Object)val).name)) { 翻译工具.工具字典.Add(((Object)val).name, value); } } } Debug.Log((object)$"懒濑:收集到 {翻译工具.工具字典.Count} 个工具"); } private static string GetLocalizedText(string text) { if (string.IsNullOrEmpty(text)) { return string.Empty; } try { if (Localization.instance == null) { return text; } string text2 = Localization.instance.Localize(text); if (!string.IsNullOrEmpty(text2)) { return text2; } return text; } catch (Exception ex) { Debug.LogWarning((object)("本地化文本失败: " + text + ", 错误: " + ex.Message)); return text; } } private static void ExportFilteredItems() { Dictionary<string, iteminfodata> dictionary = FilterDictionary(翻译工具.物品字典, ItemSearchFields); string filePath = Path.Combine(modLocalizationFolder, $"汉化信息_物品_{DateTime.Now:yyyyMMdd_HHmm}.txt"); SaveDictionaryToTxt(filePath, "物品", dictionary); } private static void ExportFilteredEffects() { Dictionary<string, EffectInfoData> dictionary = FilterDictionary(翻译工具.效果字典, EffectSearchFields); string filePath = Path.Combine(modLocalizationFolder, $"汉化信息_效果_{DateTime.Now:yyyyMMdd_HHmm}.txt"); SaveDictionaryToTxt(filePath, "效果", dictionary); } private static void ExportFilteredMonsters() { Dictionary<string, monsterinfodata> dictionary = FilterDictionary(翻译工具.怪物字典, MonsterSearchFields); string filePath = Path.Combine(modLocalizationFolder, $"汉化信息_怪物_{DateTime.Now:yyyyMMdd_HHmm}.txt"); SaveDictionaryToTxt(filePath, "怪物", dictionary); } private static void ExportFilteredPieces() { Dictionary<string, pieceInfoData> dictionary = FilterDictionary(翻译工具.工具字典, PieceSearchFields); string filePath = Path.Combine(modLocalizationFolder, $"汉化信息_工具_{DateTime.Now:yyyyMMdd_HHmm}.txt"); SaveDictionaryToTxt(filePath, "工具", dictionary); } private static Dictionary<string, T> FilterDictionary<T>(Dictionary<string, T> source, string[] searchFields) { Dictionary<string, T> dictionary = new Dictionary<string, T>(); bool flag = searchFields == null || searchFields.Length == 0; foreach (KeyValuePair<string, T> item in source) { if (flag) { dictionary.Add(item.Key, item.Value); continue; } foreach (string value in searchFields) { if (item.Key.Contains(value)) { dictionary.Add(item.Key, item.Value); break; } } } return dictionary; } private static void LoadAllSearchFields() { Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>(); dictionary.Add("物品", new string[3] { "_Ygg", "_Custom", "//Filtering conditions for items(This bank's note can be deleted.)" }); dictionary.Add("效果", new string[2] { "SE_", "//Filtering conditions for effects(This bank's note can be deleted.)" }); dictionary.Add("怪物", new string[2] { "RRR", "//Filtering conditions for creature(This bank's note can be deleted.)" }); dictionary.Add("工具", new string[3] { "_piece", "_Piece", "//Filtering conditions for pieces(This bank's note can be deleted.)" }); Dictionary<string, string[]> defaultFilters = dictionary; (string[], string[], string[], string[]) tuple = LoadAllFiltersFromFile(defaultFilters); string[] item = tuple.Item1; string[] item2 = tuple.Item2; string[] item3 = tuple.Item3; string[] item4 = tuple.Item4; ItemSearchFields = item; EffectSearchFields = item2; MonsterSearchFields = item3; PieceSearchFields = item4; } private static (string[], string[], string[], string[]) LoadAllFiltersFromFile(Dictionary<string, string[]> defaultFilters) { try { string path = Path.Combine(modLocalizationFolder, "筛选条件.txt"); Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>> { { "物品", new List<string>() }, { "效果", new List<string>() }, { "怪物", new List<string>() }, { "工具", new List<string>() } }; string text = null; if (!File.Exists(path)) { string directoryName = Path.GetDirectoryName(path); if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } List<string> list = new List<string>(); string[] array = new string[4] { "物品", "效果", "怪物", "工具" }; foreach (string text2 in array) { list.Add("[" + text2 + "]//filter condition"); if (defaultFilters.ContainsKey(text2) && defaultFilters[text2].Length != 0) { list.AddRange(defaultFilters[text2]); } list.Add(""); } File.WriteAllLines(path, list); Debug.Log((object)"懒濑:配置文件不存在,已创建默认配置文件"); return (defaultFilters["物品"], defaultFilters["效果"], defaultFilters["怪物"], defaultFilters["工具"]); } string[] array2 = File.ReadAllLines(path); foreach (string text3 in array2) { string text4 = text3.Trim(); if (!string.IsNullOrWhiteSpace(text4)) { if (text4.StartsWith("[") && text4.Contains("]")) { text = text4.Trim('[', ']').Trim(); } else if (text != null && dictionary.ContainsKey(text)) { dictionary[text].Add(text4); } } } return (dictionary["物品"].ToArray(), dictionary["效果"].ToArray(), dictionary["怪物"].ToArray(), dictionary["工具"].ToArray()); } catch (Exception ex) { Debug.LogError((object)("懒濑:加载配置文件 筛选条件.txt 失败: " + ex.Message)); return (defaultFilters["物品"], defaultFilters["效果"], defaultFilters["怪物"], defaultFilters["工具"]); } } private static void SaveDictionaryToTxt<T>(string filePath, string dictionaryType, Dictionary<string, T> dictionary) { try { using (StreamWriter streamWriter = new StreamWriter(filePath, append: false, Encoding.UTF8)) { streamWriter.WriteLine(dictionaryType + "信息列表 - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); streamWriter.WriteLine("使用说明Instructions:汉化名字和描述后面的内容,然后重启游戏即可,本mod只读取以“汉化信息_怪物”等形式开头的本地化文件"); streamWriter.WriteLine("Locate the content after \"名字:\" and \"描述:\", then restart the game.This mod only reads the localized files that start with \"汉化信息_物品\"、\"汉化信息_工具\"、\"汉化信息_怪物\"、\"汉化信息_效果\""); streamWriter.WriteLine("=========================================="); foreach (KeyValuePair<string, T> item in dictionary) { if (typeof(T) == typeof(iteminfodata)) { iteminfodata iteminfodata = item.Value as iteminfodata; streamWriter.WriteLine(存.预制名 + item.Key); streamWriter.WriteLine(存.名 + iteminfodata.itemname); streamWriter.WriteLine(存.描述 + iteminfodata.itemdesc); streamWriter.WriteLine($"{存.哈希}{iteminfodata.itemHash}"); } else if (typeof(T) == typeof(EffectInfoData)) { EffectInfoData effectInfoData = item.Value as EffectInfoData; streamWriter.WriteLine(存.预制名 + effectInfoData.effectprename); streamWriter.WriteLine(存.名 + effectInfoData.effectname); streamWriter.WriteLine(存.描述 + effectInfoData.effectdesc); streamWriter.WriteLine($"{存.哈希}{effectInfoData.effecthash}"); } else if (typeof(T) == typeof(monsterinfodata)) { monsterinfodata monsterinfodata = item.Value as monsterinfodata; streamWriter.WriteLine(存.预制名 + monsterinfodata.monsterprename); streamWriter.WriteLine(存.名 + monsterinfodata.monstername); streamWriter.WriteLine($"{存.哈希}{monsterinfodata.monsterhash}"); } else if (typeof(T) == typeof(pieceInfoData)) { pieceInfoData pieceInfoData = item.Value as pieceInfoData; streamWriter.WriteLine(存.预制名 + pieceInfoData.pieceprename); streamWriter.WriteLine(存.名 + pieceInfoData.piecename); streamWriter.WriteLine(存.描述 + pieceInfoData.piecedesc); streamWriter.WriteLine($"{存.哈希}{pieceInfoData.piecehash}"); } streamWriter.WriteLine("------------------------------------------"); } } Debug.Log((object)("懒濑:" + dictionaryType + "字典已成功保存到: " + filePath)); } catch (Exception ex) { Debug.LogError((object)("懒濑:保存" + dictionaryType + "字典时出错: " + ex.Message)); } } public static void ApplyAllTranslations(ObjectDB objectDB) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Stopwatch stopwatch = Stopwatch.StartNew(); num1 = 0; num2 = 0; num3 = 0; num4 = 0; string[] files = Directory.GetFiles(modLocalizationFolder, "*", SearchOption.AllDirectories); Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "main") { return; } string[] array = files; foreach (string text in array) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); string extension = Path.GetExtension(text); if (!(extension != ".txt")) { if (fileNameWithoutExtension.StartsWith("汉化信息_怪物")) { Stopwatch stopwatch2 = Stopwatch.StartNew(); ApplyMonsterTranslations(objectDB, text); stopwatch2.Stop(); Debug.Log((object)$"懒:怪物翻译耗时 {stopwatch2.Elapsed.TotalSeconds:F2}秒,处理文件:{text}"); } else if (fileNameWithoutExtension.StartsWith("汉化信息_效果")) { Stopwatch stopwatch3 = Stopwatch.StartNew(); ApplyStatusEffects1(objectDB, text); stopwatch3.Stop(); Debug.Log((object)$"懒:效果翻译耗时 {stopwatch3.Elapsed.TotalSeconds:F2}秒,处理文件:{text}"); } else if (fileNameWithoutExtension.StartsWith("汉化信息_物品")) { Stopwatch stopwatch4 = Stopwatch.StartNew(); ApplyItemTranslations(objectDB, text); stopwatch4.Stop(); Debug.Log((object)$"懒:物品翻译耗时 {stopwatch4.Elapsed.TotalSeconds:F2}秒,处理文件:{text}"); } else if (fileNameWithoutExtension.StartsWith("汉化信息_工具")) { Stopwatch stopwatch5 = Stopwatch.StartNew(); ApplyPicecTranslations(objectDB, text); stopwatch5.Stop(); Debug.Log((object)$"懒:工具翻译耗时 {stopwatch5.Elapsed.TotalSeconds:F2}秒,处理文件:{text}"); } } } stopwatch.Stop(); Debug.Log((object)$"懒:翻译完成 - 总耗时 {stopwatch.Elapsed.TotalSeconds:F2}秒"); Debug.Log((object)$"懒:翻译统计 - 物品:{num1} 个,怪物:{num2} 个,工具:{num3} 个,效果:{num4} 个"); } public static void ApplyItemTranslations(ObjectDB objectDB, string filePath) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "main" || !File.Exists(filePath)) { return; } string[] array = File.ReadAllLines(filePath, Encoding.UTF8); for (int i = 0; i < array.Length - 3; i++) { if (!array[i].StartsWith(存.预制名)) { continue; } string prefabName = array[i].Substring(存.预制名.Length).Trim(); string text = array[i + 1].Substring(存.名.Length).Trim(); string description = array[i + 2].Substring(存.描述.Length).Trim(); int result = 0; if (i + 3 < array.Length && array[i + 3].StartsWith(存.哈希)) { int.TryParse(array[i + 3].Substring(存.哈希.Length).Trim(), out result); } GameObject itemPrefab = GetItemPrefab(objectDB, result, prefabName, text); if (!((Object)(object)itemPrefab == (Object)null)) { ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if (component?.m_itemData?.m_shared != null) { component.m_itemData.m_shared.m_name = text; component.m_itemData.m_shared.m_description = description; num1++; } } } } public static void ApplyMonsterTranslations(ObjectDB objectDB, string filePath) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "main" || !File.Exists(filePath)) { return; } string[] array = File.ReadAllLines(filePath); for (int i = 0; i < array.Length - 1; i++) { if (!array[i].StartsWith(存.预制名)) { continue; } string text = array[i].Substring(存.预制名.Length); string text2 = array[i + 1].Substring(存.名.Length); int result = 0; if (i + 2 < array.Length && array[i + 2].StartsWith(存.哈希)) { int.TryParse(array[i + 2].Substring(存.哈希.Length).Trim(), out result); } GameObject itemPrefab = GetItemPrefab(objectDB, result, text, text2); Humanoid val = ((itemPrefab != null) ? itemPrefab.GetComponent<Humanoid>() : null); if (val != null) { ((Character)val).m_name = text2; num2++; continue; } Humanoid[] array2 = Resources.FindObjectsOfTypeAll<Humanoid>(); foreach (Humanoid val2 in array2) { if (((Object)val2).name == text) { ((Character)val2).m_name = text2; num2++; } } } } public static void ApplyPicecTranslations(ObjectDB objectDB, string filePath) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "main" || !File.Exists(filePath)) { return; } string[] array = File.ReadAllLines(filePath); for (int i = 0; i < array.Length - 1; i++) { if (!array[i].StartsWith(存.预制名)) { continue; } string text = array[i].Substring(存.预制名.Length); string text2 = array[i + 1].Substring(存.名.Length); string description = array[i + 2].Substring(存.描述.Length); int result = 0; if (i + 3 < array.Length && array[i + 3].StartsWith(存.哈希)) { int.TryParse(array[i + 3].Substring(存.哈希.Length).Trim(), out result); } GameObject itemPrefab = GetItemPrefab(objectDB, result, text, text2); Piece val = ((itemPrefab != null) ? itemPrefab.GetComponent<Piece>() : null); if (val != null) { val.m_name = text2; val.m_description = description; num3++; continue; } Piece[] array2 = Resources.FindObjectsOfTypeAll<Piece>(); foreach (Piece val2 in array2) { if (((Object)val2).name == text) { val2.m_name = text2; val2.m_description = description; num3++; } } } } public static void ApplyStatusEffects1(ObjectDB objectDB, string filePath) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "main" || !File.Exists(filePath)) { return; } string[] array = File.ReadAllLines(filePath); for (int i = 0; i < array.Length - 1; i++) { if (!array[i].StartsWith(存.预制名)) { continue; } string text = array[i].Substring(存.预制名.Length); string text2 = array[i + 1].Substring(存.名.Length); string text3 = array[i + 2].Substring(存.描述.Length); int result = 0; if (i + 3 < array.Length && array[i + 3].StartsWith(存.哈希)) { int.TryParse(array[i + 3].Substring(存.哈希.Length).Trim(), out result); } Dictionary<int, EffectInfoData> dictionary = new Dictionary<int, EffectInfoData>(); Dictionary<string, EffectInfoData> dictionary2 = new Dictionary<string, EffectInfoData>(); dictionary[result] = new EffectInfoData { effectprename = text, effectdesc = text3, effectname = text2, effecthash = result }; dictionary2[text] = new EffectInfoData { effectprename = text, effectdesc = text3, effectname = text2, effecthash = result }; foreach (StatusEffect item in objectDB.m_StatusEffects.Where((StatusEffect se) => (Object)(object)se != (Object)null)) { EffectInfoData value; EffectInfoData effectInfoData = (dictionary.TryGetValue(item.NameHash(), out value) ? value : (dictionary2.TryGetValue(((Object)item).name, out value) ? value : null)); if (effectInfoData != null) { item.m_name = text2; item.m_tooltip = text3; num4++; } } } } private static GameObject GetItemPrefab(ObjectDB objectDB, int hash, string prefabName, string itemName) { string prefabName2 = prefabName; string itemName2 = itemName; if (hash != 0) { GameObject val = GetGameObject(hash) ?? ((objectDB != null) ? objectDB.GetItemPrefab(hash) : null); if ((Object)(object)val != (Object)null) { return val; } } if (!string.IsNullOrEmpty(prefabName2)) { GameObject val2 = GetGameObject(prefabName2) ?? ((IEnumerable<GameObject>)objectDB?.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject item) => ((item != null) ? ((Object)item).name : null) == prefabName2)); if ((Object)(object)val2 != (Object)null) { return val2; } } if (!string.IsNullOrEmpty(itemName2)) { return GetGameObject(itemName2) ?? ((IEnumerable<GameObject>)objectDB?.m_items).FirstOrDefault((Func<GameObject, bool>)((GameObject item) => ((item != null) ? ((Object)item).name : null) == itemName2)); } return null; } public static GameObject GetGameObject(string name) { if (string.IsNullOrEmpty(name)) { Debug.LogError((object)"获取预制件名时,传入了空字符"); return null; } if (缓存.m_PrefabCache.ContainsKey(name)) { return 缓存.m_PrefabCache[name]; } GameObject val = ZNetScene.instance.GetPrefab(name) ?? ObjectDB.instance.GetItemPrefab(name) ?? ResourcesGetGameObject(name); if ((Object)(object)val == (Object)null) { return null; } if (!缓存.m_PrefabCache.ContainsKey(((Object)val).name)) { 缓存.m_PrefabCache.Add(((Object)val).name, val); } return val; } public static GameObject GetGameObject(int hash) { GameObject val = ZNetScene.instance.GetPrefab(hash) ?? ObjectDB.instance.GetItemPrefab(hash); if ((Object)(object)val == (Object)null) { return null; } if (!缓存.m_PrefabCache.ContainsKey(((Object)val).name)) { 缓存.m_PrefabCache.Add(((Object)val).name, val); } return val; } private static GameObject ResourcesGetGameObject(string name) { GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); GameObject[] array2 = array; foreach (GameObject val in array2) { if (((Object)val).name == name) { return val; } } return null; } public void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = Shortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { ExportFilteredData(); } value = modShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { LoadModNamesFromConfig(); string[] array = LoadModNamesFromConfig(); string[] array2 = array; foreach (string modName in array2) { ExportByModSearch(modName); } } value = TranslateShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { if (TranslationProcessor.HasProgress()) { TranslationProcessor.ResumeTranslation(); } else { TranslationProcessor.ProcessAllTranslations(); } } value = TranslateShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown() && Input.GetKey((KeyCode)306)) { TranslationProcessor.ResetProgress(); TranslationProcessor.ProcessAllTranslations(); } value = TranslateShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown() && Input.GetKey((KeyCode)308)) { TranslationProcessor.ShowProgress(); } value = textup.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance != (Object)null) { ApplyAllTranslations(instance); } else { Debug.LogError((object)"懒濑:按键触发时无法获取 ObjectDB 实例"); } } } private async void TestTranslation() { try { ((BaseUnityPlugin)this).Logger.LogInfo((object)"开始测试翻译功能..."); string testText = "Hello world! This is a translation test."; string translatedText = await DeepSeekTranslator.Instance.TranslateAsync(testText, "中文"); if (!string.IsNullOrEmpty(translatedText)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("翻译前: " + testText)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("翻译后: " + translatedText)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"翻译测试成功完成!"); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"翻译测试失败:返回结果为空"); } } catch (Exception ex2) { Exception ex = ex2; ((BaseUnityPlugin)this).Logger.LogError((object)("翻译测试过程中发生异常: " + ex.Message)); } } private string[] LoadModNamesFromConfig() { try { if (File.Exists(modNameConfigPath)) { return (from line in File.ReadAllLines(modNameConfigPath) where !string.IsNullOrWhiteSpace(line) select line.Trim()).ToArray(); } string[] array = new string[2] { "//Please enter the name of the mod to which the text you want to export belongs.for example, SouthsilArmor,Multiple entries, please press enter to continue.", "SouthsilArmor" }; File.WriteAllLines(modNameConfigPath, array); Debug.Log((object)("已创建默认Mod名称筛选文件: " + modNameConfigPath)); return array; } catch (Exception ex) { Debug.LogError((object)("加载Mod名称配置文件失败: " + ex.Message)); return new string[0]; } } private void ExportByModSearch(string modName) { if (string.IsNullOrWhiteSpace(modName)) { Debug.LogWarning((object)"跳过空的Mod名称筛选条件"); return; } int num = 0; bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; bool flag5 = false; try { ModPrefabManager.InitializeModInfo(); List<string> list = ModPrefabManager.SearchPrefabsByModName(modName); if (list.Count == 0) { Debug.LogWarning((object)("未找到Mod '" + modName + "' 相关的预制件")); return; } string path = $"汉化信息__{modName}_{DateTime.Now:yyyyMMdd_HHmm}.txt"; string text = Path.Combine(modLocalizationFolder, path); using (StreamWriter streamWriter = new StreamWriter(text, append: false, Encoding.UTF8)) { streamWriter.WriteLine("Mod名称/modname: " + modName); streamWriter.WriteLine($"导出时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); streamWriter.WriteLine($"找到预制件数量: {list.Count}"); streamWriter.WriteLine("这里是根据mod名导出的文本,例如SouthsilArmor。"); streamWriter.WriteLine("This is the text derived based on the mod name. "); streamWriter.WriteLine("本地化后将其中内容按板块分别复制到以\"汉化信息_物品\\\"、\\\"汉化信息_工具\\\"、\\\"汉化信息_怪物\\\"、\\\"汉化信息_效果\\\"开头的文件。 "); streamWriter.WriteLine("完成后重启生效"); streamWriter.WriteLine("After localization, the contents should be copied to separate files starting with \"汉化信息_物品\"、\"汉化信息_工具\"、\"汉化信息_怪物\"and\"汉化信息_效果\", respectively."); streamWriter.WriteLine("After completion, restart to make the localization take effect."); streamWriter.WriteLine("=========================================="); streamWriter.WriteLine(); foreach (string item in list) { EffectInfoData value2; monsterinfodata value3; pieceInfoData value4; if (翻译工具.物品字典.TryGetValue(item, out iteminfodata value)) { if (!flag) { streamWriter.WriteLine("【物品item】"); streamWriter.WriteLine("------------------------------------------"); flag = true; } streamWriter.WriteLine(存.预制名 + item); streamWriter.WriteLine(存.名 + value.itemname); streamWriter.WriteLine(存.描述 + value.itemdesc); streamWriter.WriteLine($"{存.哈希}{value.itemHash}"); streamWriter.WriteLine("------------------------------------------"); num++; } else if (翻译工具.效果字典.TryGetValue(item, out value2)) { if (!flag2) { streamWriter.WriteLine("【效果effect】"); streamWriter.WriteLine("------------------------------------------"); flag2 = true; } streamWriter.WriteLine(存.预制名 + item); streamWriter.WriteLine(存.名 + value2.effectname); streamWriter.WriteLine(存.描述 + value2.effectdesc); streamWriter.WriteLine($"{存.哈希}{value2.effecthash}"); streamWriter.WriteLine("------------------------------------------"); num++; } else if (翻译工具.怪物字典.TryGetValue(item, out value3)) { if (!flag3) { streamWriter.WriteLine("【怪物creature】"); streamWriter.WriteLine("------------------------------------------"); flag3 = true; } streamWriter.WriteLine(存.预制名 + item); streamWriter.WriteLine(存.名 + value3.monstername); streamWriter.WriteLine($"{存.哈希}{value3.monsterhash}"); streamWriter.WriteLine("------------------------------------------"); num++; } else if (翻译工具.工具字典.TryGetValue(item, out value4)) { if (!flag4) { streamWriter.WriteLine("【工具pieces】"); streamWriter.WriteLine("------------------------------------------"); flag4 = true; } streamWriter.WriteLine(存.预制名 + item); streamWriter.WriteLine(存.名 + value4.piecename); streamWriter.WriteLine(存.描述 + value4.piecedesc); streamWriter.WriteLine($"{存.哈希}{value4.piecehash}"); streamWriter.WriteLine("------------------------------------------"); num++; } else { if (!flag5) { streamWriter.WriteLine("【未知unknown】"); streamWriter.WriteLine("------------------------------------------"); flag5 = true; } streamWriter.WriteLine(存.预制名 + item); streamWriter.WriteLine(存.名 + "未找到本地化信息"); streamWriter.WriteLine(存.描述 + "未找到本地化信息"); streamWriter.WriteLine(存.哈希 + "未找到本地化信息"); streamWriter.WriteLine("------------------------------------------"); num++; } } streamWriter.WriteLine(); streamWriter.WriteLine($"成功导出: {num} 个预制件"); } Debug.Log((object)$"懒濑:已导出Mod '{modName}' 的 {num} 个预制件到: {text}"); } catch (Exception ex) { Debug.LogError((object)("懒濑:导出Mod '" + modName + "' 时出错: " + ex.Message)); } } public void OnDestroy() { } } } namespace 全局本地化.Data { public class EffectInfoData { public string effectprename { get; set; } = string.Empty; public string effectname { get; set; } = string.Empty; public string effectdesc { get; set; } = string.Empty; public int effecthash { get; set; } = 0; } public class EffectInfoData1 { public string effectprename { get; set; } public string effectdesc { get; set; } public string effectname { get; set; } public string effecthash { get; set; } } public class iteminfodata { public string itemname { get; set; } = string.Empty; public string itemdesc { get; set; } = string.Empty; public int itemHash { get; set; } = 0; } public class ModInfoData { public string ModName { get; set; } = ""; public string ModGUID { get; set; } = ""; public List<string> PrefabNames { get; set; } = new List<string>(); } public static class ModPrefabManager { public static readonly Dictionary<string, ModInfoData> ModInfoDict = new Dictionary<string, ModInfoData>(); public static readonly Dictionary<string, string> PrefabToModMap = new Dictionary<string, string>(); public static void InitializeModInfo() { ModInfoDict.Clear(); PrefabToModMap.Clear(); foreach (IModPrefab prefab in ModQuery.GetPrefabs()) { if (prefab != null && Object.op_Implicit((Object)(object)prefab.Prefab) && prefab.SourceMod != null) { string gUID = prefab.SourceMod.GUID; string name = ((Object)prefab.Prefab).name; if (!ModInfoDict.ContainsKey(gUID)) { ModInfoDict[gUID] = new ModInfoData { ModName = prefab.SourceMod.Name, ModGUID = gUID, PrefabNames = new List<string>() }; } if (!ModInfoDict[gUID].PrefabNames.Contains(name)) { ModInfoDict[gUID].PrefabNames.Add(name); } if (!PrefabToModMap.ContainsKey(name)) { PrefabToModMap[name] = gUID; } } } } public static List<string> SearchPrefabsByModName(string modName) { List<string> list = new List<string>(); foreach (ModInfoData value in ModInfoDict.Values) { if (value.ModName.IndexOf(modName, StringComparison.OrdinalIgnoreCase) >= 0 || value.ModGUID.IndexOf(modName, StringComparison.OrdinalIgnoreCase) >= 0) { list.AddRange(value.PrefabNames); } } return list.Distinct().ToList(); } public static List<string> GetAllModNames() { return ModInfoDict.Values.Select((ModInfoData mod) => mod.ModName).Distinct().ToList(); } public static ModInfoData GetModByPrefabName(string prefabName) { if (PrefabToModMap.TryGetValue(prefabName, out string value) && ModInfoDict.TryGetValue(value, out ModInfoData value2)) { return value2; } return null; } } public class monsterinfodata { public string monstername { get; set; } = string.Empty; public string monsterprename { get; set; } = string.Empty; public int monsterhash { get; set; } = 0; } public class pieceInfoData { public string pieceprename { get; set; } = string.Empty; public string piecename { get; set; } = string.Empty; public string piecedesc { get; set; } = string.Empty; public int piecehash { get; set; } = 0; } }