diff --git a/MelonLoader/AssetStore/AudioStore.cs b/MelonLoader/AssetStore/AudioStore.cs index 746ccac..d37899e 100644 --- a/MelonLoader/AssetStore/AudioStore.cs +++ b/MelonLoader/AssetStore/AudioStore.cs @@ -155,6 +155,9 @@ namespace PvZ_Fusion_Translator.AssetStore if (__instance.clip == null) return; + if (Il2CppRhythmGame.RhythmGameManager.Instance != null && __instance.clip.name == "loon") + return; + if (LogSounds) MelonLogger.Msg($"Playing \"{__instance.clip.name}\" from object \"{__instance.gameObject.name}\""); diff --git a/MelonLoader/AssetStore/DllStore.cs b/MelonLoader/AssetStore/DllStore.cs new file mode 100644 index 0000000..663f7ba --- /dev/null +++ b/MelonLoader/AssetStore/DllStore.cs @@ -0,0 +1,115 @@ +/*using MelonLoader; +using MelonLoader.Utils; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PvZ_Fusion_Translator.AssetStore +{ + public static class DllStore + { + public static Dictionary dllData = new Dictionary() + { + { "Blooms_QOL.dll", null }, + { "PvZ_Fusion_Translator.dll", null } + }; + public static bool updateOnClose = false; + + public static void Init(string gameVersion) => TryGetNewDll(gameVersion); + + public static void TryGetNewDll(string gameVersion) + { + bool ableToUpdate = true; + string unableReason = ""; + string getGameVersionRequest = Utils.GetDataFromWeb("https://raw.githubusercontent.com/SillyStar-Github/PvZF-Translation-DLLs/refs/heads/main/CURRENT_GAME_VER").Result; + if(getGameVersionRequest != null) + { + Log.LogDebug($"Requst game version: {getGameVersionRequest} -> {Utils.CalculateGameVersion(getGameVersionRequest)}"); + Log.LogDebug($"This game version: {gameVersion} -> {Utils.CalculateGameVersion(gameVersion)}"); + if (Utils.CalculateGameVersion(getGameVersionRequest) != Utils.CalculateGameVersion(gameVersion)) + { + ableToUpdate = false; + unableReason = "Incorrect game version..."; + } + } + else + { + ableToUpdate = false; + unableReason = "Couldn't get latest game version info..."; + } + + if (ableToUpdate) + { + foreach(var key in dllData.Keys) + { + byte[] newDllRequest = Utils.GetByteDataFromWeb($"https://raw.githubusercontent.com/SillyStar-Github/PvZF-Translation-DLLs/refs/heads/main/{key}").Result; + if(newDllRequest != null) + { + dllData[key] = newDllRequest; + SaveNewDll(key); + } + else + { + Log.LogError($"Couldn't get latest {key} data!"); + } + } + } + else + { + Log.LogError($"Unable to update! {unableReason}"); + } + } + + public static void SaveNewDll(string name) + { + byte[] newDllData = dllData[name]; + if(newDllData != null) + { + string basePath = MelonEnvironment.ModsDirectory; + string toSavePath = Path.Combine(basePath, name + ".update"); + File.WriteAllBytes(toSavePath, newDllData); + } + } + + public static void UpdateNewDll() + { + foreach(var pair in dllData) + { + if(pair.Value != null) + { + updateOnClose = true; + } + } + + if(updateOnClose) + { + int processId = (Process.GetCurrentProcess().Id); + + var assembly = Core.Instance.MelonAssembly.Assembly; + string programName = "PvZ_Fusion_Translator.Resources.ModUpdateUtil.exe"; + + using var exeResourceStream = assembly.GetManifestResourceStream(programName); + string tempPath = Path.Combine(MelonEnvironment.ModsDirectory, "ModUpdateUtil.exe"); + using (var fileStream = File.Create(tempPath)) + { + exeResourceStream.CopyTo(fileStream); + } + + Process.Start(new ProcessStartInfo + { + FileName = tempPath, + Arguments = $"{processId.ToString()} {string.Join(",", dllData.Keys)} \"{MelonEnvironment.ModsDirectory}\"", + UseShellExecute = true + }); + } + else + { + Log.LogError("Cannot update on close! All .dll data is null!"); + } + } + } +} +*/ \ No newline at end of file diff --git a/MelonLoader/AssetStore/StringStore.cs b/MelonLoader/AssetStore/StringStore.cs index 6c0d1a3..270059e 100644 --- a/MelonLoader/AssetStore/StringStore.cs +++ b/MelonLoader/AssetStore/StringStore.cs @@ -1,4 +1,6 @@ -using Il2CppTMPro; +using Il2CppSystem.Runtime.Remoting.Messaging; +using Il2CppTMPro; +using System.Diagnostics; using System.Text.RegularExpressions; using UnityEngine; @@ -87,6 +89,12 @@ namespace PvZ_Fusion_Translator.AssetStore public static TextMeshPro TranslateText(TextMeshPro originalTMP, bool isLog = false) { + /*var frame = new StackTrace().GetFrame(1); + var method = frame.GetMethod(); + var className = method.DeclaringType.Name; + + Console.WriteLine($"TextMeshPro: {className}.{method.Name}");*/ + #if MULTI_LANGUAGE string currentLanguage = Utils.Language.ToString(); TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); @@ -103,6 +111,12 @@ namespace PvZ_Fusion_Translator.AssetStore public static TextMeshProUGUI TranslateText(TextMeshProUGUI originalTMP, bool isLog = false) { + /*var frame = new StackTrace().GetFrame(1); + var method = frame.GetMethod(); + var className = method.DeclaringType.Name; + + Console.WriteLine($"tmp pro ugui: {className}.{method.Name}");*/ + #if MULTI_LANGUAGE string currentLanguage = Utils.Language.ToString(); TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); @@ -119,6 +133,12 @@ namespace PvZ_Fusion_Translator.AssetStore public static string TranslateText(string originalText, bool isLog = false) { + /*var frame = new StackTrace().GetFrame(1); + var method = frame.GetMethod(); + var className = method.DeclaringType.Name; + + Console.WriteLine($"string: {className}.{method.Name}");*/ + string text = DoTranslateText(originalText, false); string checkText; #if DEBUG diff --git a/MelonLoader/AssetStore/TextureStore.cs b/MelonLoader/AssetStore/TextureStore.cs index 9bf4ca4..f5760d5 100644 --- a/MelonLoader/AssetStore/TextureStore.cs +++ b/MelonLoader/AssetStore/TextureStore.cs @@ -6,8 +6,8 @@ namespace PvZ_Fusion_Translator.AssetStore { public static class TextureStore { - internal static Dictionary textureDict = []; - internal static Dictionary spriteDict = []; + internal static Dictionary textureDict = []; + internal static Dictionary spriteDict = []; internal static void Init() => FileLoader.LoadTextures(); @@ -55,13 +55,13 @@ namespace PvZ_Fusion_Translator.AssetStore } #endif - public static void LogAll() + /*public static void LogAll() { Log.LogInfo("Logging all TextureStore entries."); foreach (KeyValuePair entry in textureDict) { Log.LogInfo("TextureDict Entry: " + entry.Key + " | " + entry.Value); } - } + }*/ } } diff --git a/MelonLoader/Core.cs b/MelonLoader/Core.cs index 91c491d..0cd8137 100644 --- a/MelonLoader/Core.cs +++ b/MelonLoader/Core.cs @@ -31,6 +31,9 @@ namespace PvZ_Fusion_Translator { base.OnInitializeMelon(); Instance = this; + + //DllStore.Init(MelonLoader.InternalUtils.UnityInformationHandler.GameVersion); + Config(); #if MULTI_LANGUAGE FileLoader.LoadLanguage(); @@ -40,6 +43,7 @@ namespace PvZ_Fusion_Translator AudioStore.Init(); FontStore.Init(); Utils.RegisterPlantIndices(); + //Utils.RegisterRecipeLinks(); } @@ -47,7 +51,7 @@ namespace PvZ_Fusion_Translator { dtStart = DateTime.Now; replaceTextureRoutine = MelonCoroutines.Start(TextureStore.ReplaceTexturesCoroutine()); - TravelMgr_Patch.DumpTravelBuffs(); + LoadTravelBuffs(); } public override void OnDeinitializeMelon() @@ -56,6 +60,7 @@ namespace PvZ_Fusion_Translator #if MULTI_LANGUAGE FileLoader.SaveLanguage(); #endif + //DllStore.UpdateNewDll(); #if OBFUSCATE && !RELEASE CheckSumStore.ConvertMD5Json(); #endif @@ -78,9 +83,9 @@ namespace PvZ_Fusion_Translator Utils.OpenSaveDirectory(); } - if (Input.GetKeyDown(KeyCode.Delete)) + if (Input.GetKeyDown(KeyCode.PageUp)) { - Utils.OpenTrello(); + Utils.OpenOnlineAlmanac(); } TowerManager_Patch.UpdateText(); diff --git a/MelonLoader/FileLoader.cs b/MelonLoader/FileLoader.cs index bb70c78..59356de 100644 --- a/MelonLoader/FileLoader.cs +++ b/MelonLoader/FileLoader.cs @@ -1,4 +1,5 @@ using Il2Cpp; +using Il2CppAlmanacData; using Il2CppInterop.Runtime.InteropTypes.Arrays; using JetBrains.Annotations; using MelonLoader; @@ -40,6 +41,10 @@ namespace PvZ_Fusion_Translator internal static void LoadStrings(Utils.LanguageEnum language) { string stringDir = GetAssetDir(AssetType.Strings, Utils.Language); + if (!Directory.Exists(stringDir)) + { + Directory.CreateDirectory(stringDir); + } if(!Utils.useLocal) { @@ -75,22 +80,6 @@ namespace PvZ_Fusion_Translator } } - // load travel_buffs - string travelBuffsContent = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Strings/travel_buffs.json").Result; - - if(travelBuffsContent != null) - { - TravelMgr_Patch.translatedTravelBuffs = System.Text.Json.JsonSerializer.Deserialize>>(travelBuffsContent); - } - else - { - string travelBuffsPath = Path.Combine(GetAssetDir(AssetType.Strings, Utils.Language), "travel_buffs.json"); - if(File.Exists(travelBuffsPath)) - { - TravelMgr_Patch.translatedTravelBuffs = System.Text.Json.JsonSerializer.Deserialize>>(File.ReadAllText(travelBuffsPath)); - } - } - // load changelog LoadChangelogText(); @@ -127,6 +116,14 @@ namespace PvZ_Fusion_Translator } // load almanacs + + string almanacDir = GetAssetDir(AssetType.Almanac, Utils.Language); + + if(!Directory.Exists(almanacDir)) + { + Directory.CreateDirectory(almanacDir); + } + string plantAlmanacContent = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Almanac/LawnStringsTranslate.json").Result; if(plantAlmanacContent != null) @@ -135,7 +132,6 @@ namespace PvZ_Fusion_Translator } else { - string almanacDir = GetAssetDir(AssetType.Almanac, Utils.Language); string path = Path.Combine(almanacDir, "LawnStringsTranslate.json"); if(File.Exists(path)) { @@ -151,7 +147,6 @@ namespace PvZ_Fusion_Translator } else { - string almanacDir = GetAssetDir(AssetType.Almanac, Utils.Language); string path = Path.Combine(almanacDir, "ZombieStringsTranslate.json"); if(File.Exists(path)) { @@ -159,6 +154,20 @@ namespace PvZ_Fusion_Translator } } + string detailStringsContent = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Almanac/DetailStringsTranslate.json").Result; + if(detailStringsContent != null) + { + LoadDetailStrings(detailStringsContent); + } + else + { + string path = Path.Combine(almanacDir, "DetailStringsTranslate.json"); + if(File.Exists(path)) + { + LoadDetailStrings(File.ReadAllText(path)); + } + } + // load abyss buffs Patches.Modes.Abyss.AbyssBuffMenu_Patch.LoadAbyssBuffData(); @@ -199,10 +208,6 @@ namespace PvZ_Fusion_Translator { LoadTranslationRegexs(jsonString); } - else if(fileName.EndsWith("travel_buffs")) - { - TravelMgr_Patch.translatedTravelBuffs = System.Text.Json.JsonSerializer.Deserialize>>(jsonString); - } else if(fileName.EndsWith("tips_iz")) { LoadIZStrings(jsonString); @@ -218,16 +223,29 @@ namespace PvZ_Fusion_Translator } string almanacDir = GetAssetDir(AssetType.Almanac, Utils.Language); + + if(!Directory.Exists(almanacDir)) + { + Directory.CreateDirectory(almanacDir); + } + string plantAlmanacPath = Path.Combine(almanacDir, "LawnStringsTranslate.json"); + if(File.Exists(plantAlmanacPath)) { AlmanacPlantMenu_Patch.almanacJson = File.ReadAllText(plantAlmanacPath); } - string zombieAlmanacPlant = Path.Combine(almanacDir, "ZombieStringsTranslate.json"); - if(File.Exists(zombieAlmanacPlant)) + string zombieAlmanacPath = Path.Combine(almanacDir, "ZombieStringsTranslate.json"); + if(File.Exists(zombieAlmanacPath)) { - AlmanacZombieMenu_Patch.almanacJson = File.ReadAllText(zombieAlmanacPlant); + AlmanacZombieMenu_Patch.almanacJson = File.ReadAllText(zombieAlmanacPath); + } + + string detailStringsPath = Path.Combine(almanacDir, "DetailStringsTranslate.json"); + if(File.Exists(detailStringsPath)) + { + LoadDetailStrings(File.ReadAllText(detailStringsPath)); } SaveStrings(); @@ -308,11 +326,42 @@ namespace PvZ_Fusion_Translator } } + internal static void LoadDetailStrings(string content) + { + var detailStringsDump = DumpDetailStrings(); + var detailStringsData = detailStringsDump.Item1; + var detailStrings = detailStringsDump.Item2; + + var translatedDetailStrings = System.Text.Json.JsonSerializer.Deserialize>(content); + AlmanacSelectMenu_Patch.detailStrings = translatedDetailStrings; + + foreach (var detailString in detailStringsData.details) + { + if (translatedDetailStrings.ContainsKey(detailString.title)) + { + if(!AlmanacSelectMenu_Patch.detailTranslateStrings.ContainsKey(detailString.text)) + { + AlmanacSelectMenu_Patch.detailTranslateStrings.Add(detailString.text, translatedDetailStrings[detailString.title]); + } + else + { + AlmanacSelectMenu_Patch.detailTranslateStrings[detailString.text] = translatedDetailStrings[detailString.title]; + } + } + } + } + internal static void LoadChangelogText() { string stringDir = FileLoader.GetAssetDir(FileLoader.AssetType.Strings, Utils.Language); string changelogDir = Path.Combine(stringDir, "changelog.txt"); - string changelogText = File.ReadAllText(changelogDir); + string changelogText = ""; + if (!File.Exists(changelogDir)) + { + File.WriteAllText(changelogDir, ""); + } + + changelogText = File.ReadAllText(changelogDir); if(!Utils.useLocal) { @@ -327,13 +376,47 @@ namespace PvZ_Fusion_Translator NoticePauseMenu_Patch.changelogText = changelogText; } + internal static void LoadTravelBuffs() + { + if (!Utils.useLocal) + { + string travelBuffsContent = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Strings/travel_buffs.json").Result; + + if (travelBuffsContent != null) + { + TravelMgr_Patch.translatedTravelBuffs = TravelMgr_Patch.GenerateTranslatedTravelBuffs(travelBuffsContent); + } + else + { + string travelBuffsPath = Path.Combine(GetAssetDir(AssetType.Strings, Utils.Language), "travel_buffs.json"); + if (File.Exists(travelBuffsPath)) + { + TravelMgr_Patch.translatedTravelBuffs = TravelMgr_Patch.GenerateTranslatedTravelBuffs(File.ReadAllText(travelBuffsPath)); + } + } + } + else + { + string stringDir = FileLoader.GetAssetDir(FileLoader.AssetType.Strings, Utils.Language); + + foreach (string filepath in Directory.EnumerateFiles(stringDir, "*.json", SearchOption.AllDirectories)) + { + string fileName = Path.GetFileNameWithoutExtension(filepath); + string jsonString = File.ReadAllText(filepath); + if (fileName.EndsWith("travel_buffs")) + { + TravelMgr_Patch.translatedTravelBuffs = TravelMgr_Patch.GenerateTranslatedTravelBuffs(jsonString); + } + } + } + } + public static bool loadDefaultTextures = MelonPreferences.GetEntryValue("PvZ_Fusion_Translator", "DefaultTextures"); internal static void LoadTextures() { // Default or Custom Texturse -> English Textures -> Localized Textures try { - if (Utils.customTextures) { LoadCustomTextures(); @@ -365,6 +448,73 @@ namespace PvZ_Fusion_Translator } try { + Dictionary localTOC = new Dictionary(); + string localTOCDir = Path.Combine(textureDir, "Texture_TOC.json"); + if (!File.Exists(localTOCDir)) + { + File.WriteAllText(localTOCDir, "{}"); + } + + string localTOCContent = File.ReadAllText(localTOCDir); + localTOC = System.Text.Json.JsonSerializer.Deserialize>(localTOCContent); + + string basePath = Core.Instance.modsDirectory; + + if (!Utils.useLocal) + { + string textureTOCRequest = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Textures/Texture_TOC.json").Result; + if (textureTOCRequest != null) + { + Dictionary textureTOC = JsonConvert.DeserializeObject>(textureTOCRequest); + + List toDownload = new(); + + foreach(var pair in textureTOC) + { + if(!localTOC.ContainsKey(pair.Key)) + { + toDownload.Add(pair.Key); + continue; + } + + if(pair.Value != localTOC[pair.Key]) + { + toDownload.Add(pair.Key); + } + + if(!File.Exists(Path.Combine(basePath, pair.Key))) + { + toDownload.Add(pair.Key); + continue; + } + } + + string toWriteText = SerializeWithIndentation(textureTOC); + File.WriteAllText(localTOCDir, toWriteText); + + foreach(string path in toDownload) + { + string downloadPath = Path.Combine(basePath, path); + + string baseUrl = $"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/"; + string url = baseUrl + path; + + byte[] imageData = Utils.GetByteDataFromWeb(url).Result; + if(imageData != null) + { + string fileName = Path.GetFileName(downloadPath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.textureDict[fileName] = imageData; + if(!Directory.Exists(Path.GetDirectoryName(downloadPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(downloadPath)); + } + File.WriteAllBytes(downloadPath, imageData); + } + } + } + } + foreach (string filepath in Directory.EnumerateFiles(textureDir, "*.png", SearchOption.AllDirectories)) { if (filepath.Contains("[Custom Textures]", StringComparison.OrdinalIgnoreCase) && loadDefaultTextures) @@ -372,6 +522,9 @@ namespace PvZ_Fusion_Translator continue; } + if (!localTOC.ContainsKey(filepath.Replace(basePath + "\\", "").Replace("\\", "/")) + && (SerializeWithIndentation(localTOC) != "{}")) continue; + #if OBFUSCATE if (CheckSumStore.IsModified(filepath)) { @@ -384,8 +537,9 @@ namespace PvZ_Fusion_Translator Log.LogDebug("Loading File : " + filepath); #endif - Texture2D texture2D = Utils.LoadImage(filepath); - TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath; + byte[] imageData = File.ReadAllBytes(filepath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = imageData; } } @@ -406,12 +560,83 @@ namespace PvZ_Fusion_Translator } try { - foreach (string filepath in Directory.EnumerateFiles(textureDir, "*.png", SearchOption.AllDirectories)) - { - if (filepath.Contains("[Custom Textures]", StringComparison.OrdinalIgnoreCase) && loadDefaultTextures) - { - continue; - } + string trueTextureDir = GetAssetDir(AssetType.Textures, language); + Dictionary localTOC = new Dictionary(); + string localTOCDir = Path.Combine(trueTextureDir, "Texture_TOC.json"); + if (!File.Exists(localTOCDir)) + { + File.WriteAllText(localTOCDir, "{}"); + } + + string localTOCContent = File.ReadAllText(localTOCDir); + localTOC = System.Text.Json.JsonSerializer.Deserialize>(localTOCContent); + + string basePath = Core.Instance.modsDirectory; + + if(!Utils.useLocal) + { + string textureTOCRequest = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Textures/Texture_TOC.json").Result; + if (textureTOCRequest != null) + { + Dictionary textureTOC = JsonConvert.DeserializeObject>(textureTOCRequest); + + List toDownload = new(); + + foreach(var pair in textureTOC) + { + if(!localTOC.ContainsKey(pair.Key)) + { + toDownload.Add(pair.Key); + continue; + } + + if(pair.Value != localTOC[pair.Key]) + { + toDownload.Add(pair.Key); + } + + if(!File.Exists(Path.Combine(basePath, pair.Key))) + { + toDownload.Add(pair.Key); + continue; + } + } + + string toWriteText = SerializeWithIndentation(textureTOC); + File.WriteAllText(localTOCDir, toWriteText); + + foreach(string path in toDownload) + { + string downloadPath = Path.Combine(basePath, path); + + string baseUrl = $"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/"; + string url = baseUrl + path; + + byte[] imageData = Utils.GetByteDataFromWeb(url).Result; + if(imageData != null) + { + string fileName = Path.GetFileName(downloadPath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.spriteDict[fileName] = imageData; + if(!Directory.Exists(Path.GetDirectoryName(downloadPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(downloadPath)); + } + File.WriteAllBytes(downloadPath, imageData); + } + } + } + } + + foreach (string filepath in Directory.EnumerateFiles(textureDir, "*.png", SearchOption.AllDirectories)) + { + if (filepath.Contains("[Custom Textures]", StringComparison.OrdinalIgnoreCase) && loadDefaultTextures) + { + continue; + } + + if (!localTOC.ContainsKey(filepath.Replace(basePath + "\\", "").Replace("\\", "/")) + && (SerializeWithIndentation(localTOC) != "{}")) continue; #if OBFUSCATE if (CheckSumStore.IsModified(filepath)) @@ -422,12 +647,13 @@ namespace PvZ_Fusion_Translator #endif #if DEBUG - Log.LogDebug("Loading File (Sprite): " + filepath); + Log.LogDebug("Loading File (Sprite): " + filepath); #endif - Texture2D texture2D = Utils.LoadImage(filepath); - TextureStore.spriteDict[Path.GetFileNameWithoutExtension(filepath)] = filepath; - } + byte[] imageData = File.ReadAllBytes(filepath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.spriteDict[Path.GetFileNameWithoutExtension(filepath)] = imageData; + } } catch (Exception e) @@ -448,8 +674,78 @@ namespace PvZ_Fusion_Translator } try { - foreach (string filepath in Directory.EnumerateFiles(textureDefaultDir, "*.png", SearchOption.AllDirectories)) - { + string trueTextureDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Textures]"); + Dictionary localTOC = new Dictionary(); + string localTOCDir = Path.Combine(trueTextureDir, "Default_TOC.json"); + if (!File.Exists(localTOCDir)) + { + File.WriteAllText(localTOCDir, "{}"); + } + + string localTOCContent = File.ReadAllText(localTOCDir); + localTOC = System.Text.Json.JsonSerializer.Deserialize>(localTOCContent); + + string basePath = Core.Instance.modsDirectory; + + if (!Utils.useLocal) + { + string textureTOCRequest = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/{Uri.EscapeDataString("[Custom Textures]")}/Default_TOC.json").Result; + if (textureTOCRequest != null) + { + Dictionary textureTOC = JsonConvert.DeserializeObject>(textureTOCRequest); + + List toDownload = new(); + + foreach (var pair in textureTOC) + { + if (!localTOC.ContainsKey(pair.Key)) + { + toDownload.Add(pair.Key); + continue; + } + + if (pair.Value != localTOC[pair.Key]) + { + toDownload.Add(pair.Key); + } + + if(!File.Exists(Path.Combine(basePath, pair.Key))) + { + toDownload.Add(pair.Key); + continue; + } + } + + string toWriteText = SerializeWithIndentation(textureTOC); + File.WriteAllText(localTOCDir, toWriteText); + + foreach (string path in toDownload) + { + string downloadPath = Path.Combine(basePath, path); + + string baseUrl = $"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/"; + string url = baseUrl + path; + + byte[] imageData = Utils.GetByteDataFromWeb(url).Result; + if (imageData != null) + { + string fileName = Path.GetFileName(downloadPath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.textureDict[fileName] = imageData; + if(!Directory.Exists(Path.GetDirectoryName(downloadPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(downloadPath)); + } + File.WriteAllBytes(downloadPath, imageData); + } + } + } + } + + foreach (string filepath in Directory.EnumerateFiles(textureDefaultDir, "*.png", SearchOption.AllDirectories)) + { + if (!localTOC.ContainsKey(filepath.Replace(basePath + "\\", "").Replace("\\", "/")) + && (SerializeWithIndentation(localTOC) != "{}")) continue; #if OBFUSCATE if (CheckSumStore.IsModified(filepath)) @@ -459,9 +755,10 @@ namespace PvZ_Fusion_Translator } #endif - Texture2D texture2D = Utils.LoadImage(filepath); - TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath; - } + byte[] imageData = File.ReadAllBytes(filepath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = imageData; + } } catch (Exception e) @@ -482,18 +779,91 @@ namespace PvZ_Fusion_Translator } try { + string trueTextureDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Textures]"); + Dictionary localTOC = new Dictionary(); + string localTOCDir = Path.Combine(trueTextureDir, "Custom_TOC.json"); + if (!File.Exists(localTOCDir)) + { + File.WriteAllText(localTOCDir, "{}"); + } + + string localTOCContent = File.ReadAllText(localTOCDir); + localTOC = System.Text.Json.JsonSerializer.Deserialize>(localTOCContent); + + string basePath = Core.Instance.modsDirectory; + + if (!Utils.useLocal) + { + string textureTOCRequest = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/{Uri.EscapeDataString("[Custom Textures]")}/Custom_TOC.json").Result; + if (textureTOCRequest != null) + { + Dictionary textureTOC = JsonConvert.DeserializeObject>(textureTOCRequest); + + List toDownload = new(); + + foreach (var pair in textureTOC) + { + if (!localTOC.ContainsKey(pair.Key)) + { + toDownload.Add(pair.Key); + continue; + } + + if (pair.Value != localTOC[pair.Key]) + { + toDownload.Add(pair.Key); + continue; + } + + if(!File.Exists(Path.Combine(basePath, pair.Key))) + { + toDownload.Add(pair.Key); + continue; + } + } + + string toWriteText = SerializeWithIndentation(textureTOC); + File.WriteAllText(localTOCDir, toWriteText); + + foreach (string path in toDownload) + { + string downloadPath = Path.Combine(basePath, path); + + string baseUrl = $"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/"; + string url = baseUrl + path; + + byte[] imageData = Utils.GetByteDataFromWeb(url).Result; + if (imageData != null) + { + string fileName = Path.GetFileName(downloadPath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.textureDict[fileName] = imageData; + if(!Directory.Exists(Path.GetDirectoryName(downloadPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(downloadPath)); + } + File.WriteAllBytes(downloadPath, imageData); + } + } + } + } + foreach (string filepath in Directory.EnumerateFiles(texturePackDir, "*.png", SearchOption.AllDirectories)) { - #if OBFUSCATE - if (CheckSumStore.IsModified(filepath)) - { - Log.LogError("File {0} was modified!" , filepath); - continue; - } - #endif + #if OBFUSCATE + if (CheckSumStore.IsModified(filepath)) + { + Log.LogError("File {0} was modified!" , filepath); + continue; + } + #endif - Texture2D texture2D = Utils.LoadImage(filepath); - TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath; + if (!localTOC.ContainsKey(filepath.Replace(basePath + "\\", "").Replace("\\", "/")) + && (SerializeWithIndentation(localTOC) != "{}")) continue; + + byte[] imageData = File.ReadAllBytes(filepath); + Texture2D texture2D = Utils.LoadImage(imageData); + TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = imageData; } } @@ -540,12 +910,6 @@ namespace PvZ_Fusion_Translator File.WriteAllText(Path.Combine(stringDir, "tips_fs.json"), fsLevelTipDictionary); - // save travel buffs - - string travelBuffs = SerializeWithIndentation(TravelMgr_Patch.translatedTravelBuffs); - - File.WriteAllText(Path.Combine(stringDir, "travel_buffs.json"), travelBuffs); - // save changelog if(NoticePauseMenu_Patch.changelogText != "") @@ -578,6 +942,13 @@ namespace PvZ_Fusion_Translator File.WriteAllText(Path.Combine(almanacDir, "ZombieStringsTranslate.json"), AlmanacZombieMenu_Patch.almanacJson); } + + if(AlmanacSelectMenu_Patch.detailStrings != new Dictionary()) + { + string detailStrings = SerializeWithIndentation(AlmanacSelectMenu_Patch.detailStrings); + + File.WriteAllText(Path.Combine(almanacDir, "DetailStringsTranslate.json"), detailStrings); + } } public static string SerializeWithIndentation(T value, int size = 4, char indentChar = ' ') @@ -634,7 +1005,18 @@ namespace PvZ_Fusion_Translator Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping })); - Dictionary achievementsList = new Dictionary(); + // dump almanac mechanics + var detailStringsDump = DumpDetailStrings(); + var detailStringsData = detailStringsDump.Item1; + var detailStrings = detailStringsDump.Item2; + + File.WriteAllText(Path.Combine(dumpDir, "DetailStrings.json"), System.Text.Json.JsonSerializer.Serialize(detailStrings, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + + /*Dictionary achievementsList = new Dictionary(); foreach (Il2CppSystem.Collections.Generic.KeyValuePair> entry in AchievementClip.achievementsText) { achievementsList.Add(entry.Key, new AchievementObject(entry.Key, entry.Value.Item1, entry.Value.Item2)); @@ -643,7 +1025,7 @@ namespace PvZ_Fusion_Translator { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - })); + }));*/ } public static ValueTuple, Dictionary> DumpIZStrings() @@ -678,6 +1060,26 @@ namespace PvZ_Fusion_Translator return new ValueTuple, Dictionary>(fusionShowcaseData, fusionShowcaseDataDump); } + public static ValueTuple> DumpDetailStrings() + { + string detailStringsData = Resources.Load("detailstrings").text; + Il2CppAlmanacData.AlmanacData detailStrings = JsonUtility.FromJson(detailStringsData); + + Dictionary detailStringsDump = new Dictionary(); + foreach (var detailString in detailStrings.details) + { + if(detailStringsDump.ContainsKey(detailString.title)) + { + detailStringsDump[detailString.title] = detailString.text; + } + else + { + detailStringsDump.Add(detailString.title, detailString.text); + } + } + return new ValueTuple>(detailStrings, detailStringsDump); + } + #if DEBUG public static void DumpUntranslatedStrings(string text) { diff --git a/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs b/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs index beb96e1..87eb32b 100644 --- a/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs +++ b/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs @@ -1,10 +1,9 @@ using HarmonyLib; using Il2Cpp; +using Il2CppAlmanacData; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; using PvZ_Fusion_Translator.Patches.Modes.Odyssey; - -//using PvZ_Fusion_Translator.Patches.Modes.Odyssey; using System.Text.RegularExpressions; using System.Xml.Linq; using UnityEngine; @@ -20,10 +19,6 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects [HarmonyPostfix] public static void ShowText(InGameText __instance) { - if(__instance.textHead == null) return; - - if(!__instance.textHead.active) return; - TranslateInGameText(__instance); } @@ -31,10 +26,6 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects [HarmonyPostfix] public static void DebugWarning(InGameText __instance) { - if(__instance.textHead == null) return; - - if(!__instance.textHead.active) return; - TranslateInGameText(__instance); } @@ -42,25 +33,42 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects [HarmonyPostfix] public static void Update(InGameText __instance) { - if(__instance.textHead == null) return; - - if(!__instance.textHead.active) return; - TranslateInGameText(__instance); } public static void TranslateInGameText(InGameText __instance) { - if (__instance.textMesh == null) return; + TextMeshProUGUI txt = null; - if(!__instance.textHead.active) return; + if (__instance.textMesh == null || __instance.textHead == null) + { + if (__instance.TryGetComponent(out TextMeshProUGUI selfTxt)) + { + txt = selfTxt; + } + } + else + { + txt = __instance.textMesh; + } + + if(txt != null) + { + if (!txt.gameObject.active) return; + + TranslateInGameTextMesh(txt); + } + } + + public static void TranslateInGameTextMesh(TextMeshProUGUI txt) + { + if (txt == null) return; + if (txt.text == currentText) return; TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); - currentText = __instance.textMesh.text; - - TextMeshProUGUI txt = __instance.textMesh; string originalText = txt.text; + string lockedPlantMatch = CheckLockedMessage(originalText); string travelMatch = TravelMgr_Patch.MatchTravelBuff(originalText); int godsGachaCheck = CheckGodsGachaPopup(originalText); string godsGachaMatch = ""; @@ -107,7 +115,11 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects { txt.text = superEditorPlantMatch; } - else if((Regex.Match(txt.text, @"(]*>.*?)", RegexOptions.Singleline).Success) && !StringStore.translationString.ContainsKey(txt.text)) + else if(lockedPlantMatch != "") + { + txt.text = lockedPlantMatch; + } + else if((Regex.Match(txt.text, @"(]*>.*?)", RegexOptions.Singleline).Success) && (!StringStore.translationString.ContainsKey(txt.text) && !StringStore.fsTipCollectionString.ContainsKey(txt.text) && !StringStore.izTipCollectionString.ContainsKey(txt.text))) { txt.text = StringStore.TranslateColorText(txt.text, true); if (txt.gameObject.name.Contains("main")) @@ -134,19 +146,27 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects } } txt.font = fontAsset; + + currentText = txt.text; } public static string namePlantedPattern = "种植了:([^\\s]+)"; public static string nameUpgradedPattern = "升级成功:([^\\s]+) -> ([^\\s]+)"; public static string nameAlreadyPlantedPattern = "场上已经有一个([^\\s]+)了"; + public static string upgradePathRemovedPattern = "已移除路线:([^\\s]+)"; + + public static string lockedPlantPattern = "^([^\\s:]+)\\+([^\\s:]+)"; + public static string multiLockedPlantPattern = "^或 ([^\\s:]+)\\+([^\\s:]+)"; public static Dictionary fallbackFStrs = new Dictionary() { - {"种植了:([^\\s]+)", "{0} planted!"}, - {"升级成功:([^\\s]+) -> ([^\\s]+)", "{0} successfully upgraded to {1}!"}, - {"场上已经有一个([^\\s]+)了", "{0} already exists on the lawn!"}, - {"已移除路线:([^\\s]+)", "Upgrade Path removed for {0}" }, - { @"([^\s]+)\((\d+)\)", "{0}({1})" } + { namePlantedPattern, "{0} planted!"}, + { nameUpgradedPattern, "{0} successfully upgraded to {1}!"}, + { nameAlreadyPlantedPattern, "{0} already exists on the lawn!"}, + { upgradePathRemovedPattern, "Upgrade Path removed for {0}" }, + { @"([^\s]+)\((\d+)\)", "{0}({1})" }, + { lockedPlantPattern, "{0} + {1}" }, + { multiLockedPlantPattern, "or {0} + {1}" } }; public static int CheckGodsGachaPopup(string originalText) @@ -211,14 +231,36 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects } return res; } + + public static string TranslatePlantNameParts(string originalText, string pattern, string fallback) + { + string res = ""; + string fStr = ""; + Match match = Regex.Match(originalText, pattern); + if(match.Success) + { + GroupCollection groups = match.Groups; + fStr = StringStore.translationStringRegex.ContainsKey(pattern) ? StringStore.translationStringRegex[pattern] : fallback; + List dynamicParts = []; + for(int i = 1; i < groups.Count; i++) + { + string group = groups[i].Value; + string plantName = Utils.GetPlantNameFromAlmanac(group); + if (plantName == "") plantName = StringStore.TranslateText(group); + dynamicParts.Add(plantName); + } + res = string.Format(fStr, [.. dynamicParts]); + } + return res; + } public static string CheckSuperEditorPopup(string originalText) { string res = ""; - if(Regex.IsMatch(originalText, "已移除路线:([^\\s]+)")) + if(Regex.IsMatch(originalText, upgradePathRemovedPattern)) { - res = TranslatePlantNameParts(originalText, "已移除路线:([^\\s]+)"); + res = TranslatePlantNameParts(originalText, upgradePathRemovedPattern); } else if(Regex.IsMatch(originalText, "当前全部基础植物:(.*)")) { @@ -247,5 +289,64 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects return res; } + + public static string CheckLockedMessage(string originalText) + { + string res = ""; + + Regex lockedPlantRegex = new Regex(lockedPlantPattern); + Regex multiLockedPlantRegex = new Regex(multiLockedPlantPattern); + + if(lockedPlantRegex.IsMatch(originalText)) + { + if(originalText.Contains("\n")) + { + string[] lines = originalText.Split("\n"); + if (lockedPlantRegex.IsMatch(lines[0])) + { + string firstLine = lines[0]; + Match match = lockedPlantRegex.Match(firstLine); + GroupCollection groups = match.Groups; + Log.LogDebug(Utils.plantIndiceStrings.ContainsKey(groups[1].Value)); + Log.LogDebug(Utils.plantIndiceStrings.ContainsKey(groups[2].Value)); + if (Utils.plantIndiceStrings.ContainsKey(groups[1].Value) && Utils.plantIndiceStrings.ContainsKey(groups[2].Value)) + { + firstLine = TranslatePlantNameParts(firstLine, lockedPlantPattern); + List translatedLines = new List() { firstLine }; + for(int i = 1; i < lines.Length; i++) + { + string nextLine = lines[i]; + Log.LogDebug(nextLine); + string translatedNextLine = TranslatePlantNameParts(nextLine, multiLockedPlantPattern); + translatedLines.Add(translatedNextLine); + } + res = string.Join("\n", translatedLines); + } + else + { + return ""; + } + } + } + else + { + if (lockedPlantRegex.IsMatch(originalText)) + { + Match match = lockedPlantRegex.Match(originalText); + GroupCollection groups = match.Groups; + if (Utils.plantIndiceStrings.ContainsKey(groups[1].Value) && Utils.plantIndiceStrings.ContainsKey(groups[2].Value)) + { + res = TranslatePlantNameParts(originalText, lockedPlantPattern); + } + else + { + return ""; + } + } + } + } + + return res; + } } } \ No newline at end of file diff --git a/MelonLoader/Patches/BaseTextObjects/TMP_Dropdown_Patch.cs b/MelonLoader/Patches/BaseTextObjects/TMP_Dropdown_Patch.cs new file mode 100644 index 0000000..9b7a3a3 --- /dev/null +++ b/MelonLoader/Patches/BaseTextObjects/TMP_Dropdown_Patch.cs @@ -0,0 +1,49 @@ +using HarmonyLib; +using Il2Cpp; +using Il2CppTMPro; +using PvZ_Fusion_Translator.Patches.Managers; +using PvZ_Fusion_Translator.AssetStore; +using UnityEngine; +using UnityEngine.UI; + +namespace PvZ_Fusion_Translator.Patches.BaseTextObjects +{ + [HarmonyPatch(typeof(TMP_Dropdown))] + public static class TMP_Dropdown_Patch + { + [HarmonyPatch(nameof(TMP_Dropdown.Awake))] + [HarmonyPatch(nameof(TMP_Dropdown.Start))] + [HarmonyPatch(nameof(TMP_Dropdown.Show))] + [HarmonyPatch(nameof(TMP_Dropdown.SetValue))] + [HarmonyPostfix] + public static void Awake(TMP_Dropdown __instance) + { + if(__instance.captionText) + { + TMP_Text txt = __instance.captionText; + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + } + + if(__instance.itemText) + { + TMP_Text txt = __instance.itemText; + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + } + + foreach(TMP_Dropdown.DropdownItem dropdownItem in __instance.m_Items) + { + TMP_Text txt = dropdownItem.text; + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + } + } + + [HarmonyPatch(nameof(TMP_Dropdown.CreateDropdownList))] + public static void CreateDropdownList(TMP_Dropdown __instance) + { + foreach(TMP_Text txt in __instance.GetComponentsInChildren(true)) + { + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + } + } + } +} diff --git a/MelonLoader/Patches/BaseTextObjects/TMP_InputField_Patch.cs b/MelonLoader/Patches/BaseTextObjects/TMP_InputField_Patch.cs index 3d665d3..0465668 100644 --- a/MelonLoader/Patches/BaseTextObjects/TMP_InputField_Patch.cs +++ b/MelonLoader/Patches/BaseTextObjects/TMP_InputField_Patch.cs @@ -10,7 +10,7 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects { [HarmonyPatch(nameof(TMP_InputField.OnEnable))] [HarmonyPostfix] - private static void OnEnable(TMP_InputField __instance) + public static void OnEnable(TMP_InputField __instance) { if (!string.IsNullOrEmpty(__instance.text)) { diff --git a/MelonLoader/Patches/BaseTextObjects/TextMeshProUGUI_Patch.cs b/MelonLoader/Patches/BaseTextObjects/TextMeshProUGUI_Patch.cs index d9e6730..fbfd521 100644 --- a/MelonLoader/Patches/BaseTextObjects/TextMeshProUGUI_Patch.cs +++ b/MelonLoader/Patches/BaseTextObjects/TextMeshProUGUI_Patch.cs @@ -17,12 +17,20 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects { if (!string.IsNullOrEmpty(__instance.text)) { - if(__instance.transform.parent.parent != null) + if(__instance.transform.parent != null) { - if (__instance.transform.parent.parent.name.Contains("AbyssBagMenu")) - { - return; - } + if(__instance.transform.parent.name.Contains("DrawCardsText")) + { + return; + } + + if(__instance.transform.parent.parent != null) + { + if (__instance.transform.parent.parent.name.Contains("AbyssBagMenu")) + { + return; + } + } } __instance = StringStore.TranslateText(__instance); @@ -32,7 +40,7 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects { __instance.text = __instance.text.Replace("\n", " "); - if (__instance.name == "LevelName2" || __instance.name == "LevelName3") + if ((__instance.name == "LevelName2" || __instance.name == "LevelName3") && !(__instance.gameObject.transform.parent.name.Contains("Difficulty") || __instance.gameObject.name.Contains("Difficulty"))) { TowerManager_Patch.updatedText.Add(__instance.transform); } @@ -47,7 +55,7 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects } } - [HarmonyPatch(nameof(TextMeshProUGUI.Awake))] + /*[HarmonyPatch(nameof(TextMeshProUGUI.Awake))] [HarmonyPostfix] private static void Awake(TextMeshProUGUI __instance) { @@ -77,9 +85,10 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects // __instance.ForceMeshUpdate(); } - } + }*/ } - [HarmonyPatch(typeof(TMP_SubMeshUI))] + + /*[HarmonyPatch(typeof(TMP_SubMeshUI))] public static class TMP_SubMeshUI_Patch { [HarmonyPatch(nameof(TMP_SubMeshUI.OnEnable))] @@ -93,5 +102,5 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects __instance.textComponent.text = StringStore.TranslateText(text); } } - } + }*/ } diff --git a/MelonLoader/Patches/BaseTextObjects/TextMeshPro_Patch.cs b/MelonLoader/Patches/BaseTextObjects/TextMeshPro_Patch.cs index 8008f53..2be83f5 100644 --- a/MelonLoader/Patches/BaseTextObjects/TextMeshPro_Patch.cs +++ b/MelonLoader/Patches/BaseTextObjects/TextMeshPro_Patch.cs @@ -13,7 +13,11 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects { if (!string.IsNullOrEmpty(__instance.text)) { - if (__instance.transform.parent.name.StartsWith("AlmanacHelp") || __instance.transform.parent.name.StartsWith("CardBank")) + if(__instance.transform.parent.name.Contains("DrawCardsText")) + { + return; + } + else if (__instance.transform.parent.name.StartsWith("AlmanacHelp") || __instance.transform.parent.name.StartsWith("CardBank")) { __instance = StringStore.TranslateText(__instance); __instance.autoSizeTextContainer = false; diff --git a/MelonLoader/Patches/GameObjects/AlmanacCardUI_Patch.cs b/MelonLoader/Patches/GameObjects/AlmanacCardUI_Patch.cs new file mode 100644 index 0000000..8f6527c --- /dev/null +++ b/MelonLoader/Patches/GameObjects/AlmanacCardUI_Patch.cs @@ -0,0 +1,32 @@ +using HarmonyLib; +using Il2Cpp; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; +using UnityEngine; +using System.Text.RegularExpressions; +using Unity.VisualScripting; + +namespace PvZ_Fusion_Translator.Patches.GameObjects +{ + [HarmonyPatch(typeof(AlmanacCardUI))] + public static class AlmanacCardUI_Patch + { + [HarmonyPatch(nameof(AlmanacCardUI.Awake))] + [HarmonyPostfix] + public static void Awake(AlmanacCardUI __instance) + { + if (!Utils.CheckForUntranslatedText(__instance.cost.text)) return; + __instance.cost.text = StringStore.TranslateText(__instance.cost.text); + } + + [HarmonyPatch(nameof(AlmanacCardUI.OnPointerDown))] + [HarmonyPostfix] + public static void OnPointerDown(AlmanacCardUI __instance) + { + foreach(AlmanacCardUI almanacCardUI in __instance.menu.GetComponentsInChildren()) + { + AlmanacCardUI_Patch.Awake(almanacCardUI); + } + } + } +} diff --git a/MelonLoader/Patches/GameObjects/AlmanacPlantMenu_Patch.cs b/MelonLoader/Patches/GameObjects/AlmanacPlantMenu_Patch.cs index a8e8642..837aa7e 100644 --- a/MelonLoader/Patches/GameObjects/AlmanacPlantMenu_Patch.cs +++ b/MelonLoader/Patches/GameObjects/AlmanacPlantMenu_Patch.cs @@ -1,5 +1,6 @@ using HarmonyLib; using Il2Cpp; +using Il2CppAlmanacData; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; using System.Text.RegularExpressions; @@ -7,7 +8,7 @@ using Unity.Collections; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; -using static Il2Cpp.AlmanacPlantBank; +using UnityEngine.UIElements; using static PvZ_Fusion_Translator.FileLoader; using static PvZ_Fusion_Translator.Utils; @@ -26,7 +27,7 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects foreach (TextMeshProUGUI text in __instance.GetComponentsInChildren(true)) { bool isPlantName = text.gameObject.name.Contains("Name") && text.transform.parent.name != "Background"; - if (text.gameObject.name != "Description" && !isPlantName) + if (text.gameObject.name != "Description" && !isPlantName && !text.gameObject.name.Contains("Cost")) { text.text = StringStore.TranslateText(text.text); text.font = font; @@ -34,6 +35,11 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects } } + foreach(AlmanacCardUI almanacCardUI in __instance.GetComponentsInChildren()) + { + AlmanacCardUI_Patch.Awake(almanacCardUI); + } + // skin button resize AlmanacPlantWindow window = __instance.window; @@ -63,7 +69,7 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); - PlantData plantData = JsonUtility.FromJson(json); + AlmanacData plantData = JsonUtility.FromJson(json); Il2CppSystem.Collections.Generic.List searchedPlants = new(); diff --git a/MelonLoader/Patches/GameObjects/AlmanacPlantWindow_Patch.cs b/MelonLoader/Patches/GameObjects/AlmanacPlantWindow_Patch.cs index 3e95368..c0ae83a 100644 --- a/MelonLoader/Patches/GameObjects/AlmanacPlantWindow_Patch.cs +++ b/MelonLoader/Patches/GameObjects/AlmanacPlantWindow_Patch.cs @@ -34,9 +34,9 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects TMP_FontAsset fontAsset = (hasAlmanacFont) ? FontStore.LoadTMPFontAlmanac(Utils.Language.ToString()) : FontStore.LoadTMPFont(Utils.Language.ToString()); - AlmanacPlantBank.PlantData plantData = JsonUtility.FromJson(json); + Il2CppAlmanacData.AlmanacData plantData = JsonUtility.FromJson(json); - foreach (AlmanacPlantBank.PlantInfo plantInfo in plantData.plants) + foreach (Il2CppAlmanacData.PlantInfo plantInfo in plantData.plants) { if (plantInfo.seedType == (int)__instance.currentPlantType) { diff --git a/MelonLoader/Patches/GameObjects/AlmanacSelectMenu_Patch.cs b/MelonLoader/Patches/GameObjects/AlmanacSelectMenu_Patch.cs new file mode 100644 index 0000000..c335bb3 --- /dev/null +++ b/MelonLoader/Patches/GameObjects/AlmanacSelectMenu_Patch.cs @@ -0,0 +1,56 @@ +using HarmonyLib; +using Il2Cpp; +using Il2CppAlmanacData; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; +using System.Text.RegularExpressions; +using Unity.Collections; +using Unity.VisualScripting; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.UIElements; +using static PvZ_Fusion_Translator.FileLoader; +using static PvZ_Fusion_Translator.Utils; + +namespace PvZ_Fusion_Translator.Patches.GameObjects +{ + [HarmonyPatch(typeof(AlmanacSelectMenu))] + public static class AlmanacSelectMenu_Patch + { + public static Dictionary detailStrings = new Dictionary(); + public static Dictionary detailTranslateStrings = new Dictionary(); + + [HarmonyPatch(nameof(AlmanacSelectMenu.Awake))] + [HarmonyPostfix] + public static void Awake(AlmanacSelectMenu __instance) + { + TranslateAlmanacSelectMenu(__instance); + + foreach(UIButton uiButton in __instance.GetComponentsInChildren()) + { + if(uiButton.gameObject.name.Contains("Selection(Clone)")) + { + uiButton.clickEvent.AddListener(new Action(() => { TranslateAlmanacSelectMenu(__instance); })); + } + } + } + + [HarmonyPatch(nameof(AlmanacSelectMenu.InitMenu))] + [HarmonyPostfix] + public static void InitMenu(AlmanacSelectMenu __instance) + { + TranslateAlmanacSelectMenu(__instance); + } + + public static void TranslateAlmanacSelectMenu(AlmanacSelectMenu __instance) + { + TMP_FontAsset font = FontStore.LoadTMPFont(Utils.Language.ToString()); + + foreach(TextMeshProUGUI txt in __instance.GetComponentsInChildren()) + { + txt.text = detailTranslateStrings.ContainsKey(txt.text) ? detailTranslateStrings[txt.text] : StringStore.TranslateText(txt.text); + txt.font = font; + } + } + } +} diff --git a/MelonLoader/Patches/GameObjects/AlmanacZombieMenu_Patch.cs b/MelonLoader/Patches/GameObjects/AlmanacZombieMenu_Patch.cs index 9692390..17e6a27 100644 --- a/MelonLoader/Patches/GameObjects/AlmanacZombieMenu_Patch.cs +++ b/MelonLoader/Patches/GameObjects/AlmanacZombieMenu_Patch.cs @@ -16,13 +16,15 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects { public static string almanacJson = ""; - [HarmonyPatch(nameof(AlmanacZombieMenu.Awake))] + [HarmonyPatch(nameof(AlmanacZombieMenu.Start))] [HarmonyPostfix] - private static void Awake(AlmanacZombieMenu __instance) + private static void Start(AlmanacZombieMenu __instance) { TMP_FontAsset font = FontStore.LoadTMPFont(Utils.Language.ToString()); foreach (TextMeshProUGUI text in __instance.GetComponentsInChildren(true)) { + if (text.gameObject.name.Contains("Cost")) continue; + bool isZombieName = text.gameObject.name.Contains("Name") && text.transform.parent.name != "Background"; if (text.gameObject.name != "Description" && !isZombieName) { diff --git a/MelonLoader/Patches/GameObjects/AlmanacZombieWindow_Patch.cs b/MelonLoader/Patches/GameObjects/AlmanacZombieWindow_Patch.cs index 400394a..afcb7dc 100644 --- a/MelonLoader/Patches/GameObjects/AlmanacZombieWindow_Patch.cs +++ b/MelonLoader/Patches/GameObjects/AlmanacZombieWindow_Patch.cs @@ -33,10 +33,10 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects TMP_FontAsset fontAsset = (hasAlmanacFont) ? FontStore.LoadTMPFontAlmanac(Utils.Language.ToString()) : FontStore.LoadTMPFont(Utils.Language.ToString()); - ZombieAlmanacData zombieAlmanacData = JsonUtility.FromJson(json); + Il2CppAlmanacData.AlmanacData zombieAlmanacData = JsonUtility.FromJson(json); var zombieDataDic = ZombieDataManager.zombieDataDic; - foreach (ZombieInfo zombieInfo in zombieAlmanacData.zombies) + foreach (Il2CppAlmanacData.ZombieInfo zombieInfo in zombieAlmanacData.zombies) { if (zombieInfo.theZombieType == __instance.currentZombieType) { diff --git a/MelonLoader/Patches/GameObjects/Almanac_Patch.cs b/MelonLoader/Patches/GameObjects/Almanac_Patch.cs index 5d2e2dd..be6b547 100644 --- a/MelonLoader/Patches/GameObjects/Almanac_Patch.cs +++ b/MelonLoader/Patches/GameObjects/Almanac_Patch.cs @@ -37,6 +37,8 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects TMP_FontAsset font = FontStore.LoadTMPFont(Utils.Language.ToString()); foreach (TextMeshProUGUI text in __instance.GetComponentsInChildren()) { + if (text.gameObject.name.Contains("Cost")) continue; + if(text.text == "关闭") { text.text = StringStore.TranslateText("合上"); diff --git a/MelonLoader/Patches/GameObjects/BaseMenu_Patch.cs b/MelonLoader/Patches/GameObjects/BaseMenu_Patch.cs index b38c940..f528ec6 100644 --- a/MelonLoader/Patches/GameObjects/BaseMenu_Patch.cs +++ b/MelonLoader/Patches/GameObjects/BaseMenu_Patch.cs @@ -1,5 +1,6 @@ using HarmonyLib; using Il2Cpp; +using Il2CppAlmanacData; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; using UnityEngine; @@ -34,12 +35,15 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects MainMenu_Patch.AnimOver(__instance); } - TranslateBaseMenu(__instance, "Level"); - TranslateBaseMenu(__instance, "Levels"); - TranslateBaseMenu(__instance, "CustomLevel"); + TranslateBaseMenuTransform(__instance, "Level"); + TranslateBaseMenuTransform(__instance, "Levels"); + TranslateBaseMenuTransform(__instance, "CustomLevel"); + + StringStore.TranslateTextTransform(__instance.transform.Find("Goback")); + StringStore.TranslateTextTransform(__instance.transform.Find("Switich")); } - public static void TranslateBaseMenu(BaseMenu __instance, string levelsName) + public static void TranslateBaseMenuTransform(BaseMenu __instance, string levelsName) { Transform levels = __instance.transform.Find(levelsName); if (levels != null) @@ -52,9 +56,6 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects StringStore.TranslateTextTransform(child); } } - - StringStore.TranslateTextTransform(__instance.transform.Find("Goback")); - StringStore.TranslateTextTransform(__instance.transform.Find("Switich")); } } } diff --git a/MelonLoader/Patches/GameObjects/ButtonObjects/InGameBtn_Patch.cs b/MelonLoader/Patches/GameObjects/ButtonObjects/InGameBtn_Patch.cs index dda9ac9..62b7911 100644 --- a/MelonLoader/Patches/GameObjects/ButtonObjects/InGameBtn_Patch.cs +++ b/MelonLoader/Patches/GameObjects/ButtonObjects/InGameBtn_Patch.cs @@ -9,9 +9,9 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects [HarmonyPatch(typeof(InGameBtn))] public static class InGameBtn_Patch { - [HarmonyPatch(nameof(InGameBtn.Update))] + [HarmonyPatch(nameof(InGameBtn.Start))] [HarmonyPostfix] - private static void Update(InGameBtn __instance) + private static void Start(InGameBtn __instance) { Transform sceneText = __instance.transform.FindChild("SceneText"); if(sceneText != null) diff --git a/MelonLoader/Patches/GameObjects/ButtonObjects/MainMenu_Btn_Patch.cs b/MelonLoader/Patches/GameObjects/ButtonObjects/MainMenu_Btn_Patch.cs index c0da663..097df1f 100644 --- a/MelonLoader/Patches/GameObjects/ButtonObjects/MainMenu_Btn_Patch.cs +++ b/MelonLoader/Patches/GameObjects/ButtonObjects/MainMenu_Btn_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using Il2CppTMPro; using UnityEngine; @@ -34,3 +34,4 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects } } +*/ \ No newline at end of file diff --git a/MelonLoader/Patches/GameObjects/ButtonObjects/OptLanguageBtn_Patch.cs b/MelonLoader/Patches/GameObjects/ButtonObjects/OptLanguageBtn_Patch.cs index 0695f5b..45d94df 100644 --- a/MelonLoader/Patches/GameObjects/ButtonObjects/OptLanguageBtn_Patch.cs +++ b/MelonLoader/Patches/GameObjects/ButtonObjects/OptLanguageBtn_Patch.cs @@ -137,7 +137,8 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects data.IsNextButton = false; btn.gameObject.SetActive(true); - UpdateButtonText(btn, Utils.LanguageNames[lang], FontStore.LoadTMPFont(lang.ToString())); + string languageName = Utils.LanguageNames.ContainsKey(lang) ? Utils.LanguageNames[lang] : lang.ToString(); + UpdateButtonText(btn, languageName, FontStore.LoadTMPFont(lang.ToString())); } else { @@ -160,12 +161,25 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects data.Toggle = toggle; data.IsNextButton = false; btn.gameObject.SetActive(true); - string buttonText = Utils.ToggleNames[toggle]; + string buttonText = Utils.ToggleNames.ContainsKey(toggle) ? Utils.ToggleNames[toggle] : toggle.ToString(); UpdateButtonText(btn, StringStore.TranslateText(buttonText), FontStore.LoadTMPFont(Utils.Language.ToString())); - if(i == 2) + string sourceMsg = ""; + switch(i) { - string sourceMsg = "" + (!(Utils.useLocal) ? "Translation Source:\nOnline" : "Translation Source:\nLocal"); - FlashMessage(btn, sourceMsg, 0.1f, false); + case 0: + sourceMsg = "" + (!(Utils.customTextures) ? "Texture Source:\nDefault" : "Texture Source:\nCustom"); + FlashMessage(btn, sourceMsg, 0.1f, false); + break; + case 1: + sourceMsg = "" + (!(Utils.customAudio) ? "Audio Source:\nDefault" : "Audio Source:\nCustom"); + FlashMessage(btn, sourceMsg, 0.1f, false); + break; + case 2: + sourceMsg = "" + (!(Utils.useLocal) ? "Translation Source:\nOnline" : "Translation Source:\nLocal"); + FlashMessage(btn, sourceMsg, 0.1f, false); + break; + default: + break; } } else @@ -223,8 +237,10 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects if (child != null) { var text = child.GetComponent(); + string originalMsg = ""; if (text != null) { + originalMsg = text.text; text.text = message; OptionButtonData data; bool isToggle = ToggleBtnDict.TryGetValue(button.GetInstanceID(), out data); @@ -248,7 +264,24 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects { if (button != null && child != null && child.gameObject.activeSelf) { - child.gameObject.SetActive(false); + OptionButtonData buttonData = ToggleBtnDict[button.GetInstanceID()]; + if(buttonData.Toggle != null) + { + string sourceMsg = originalMsg; + switch(buttonData.Toggle) + { + case Utils.ToggleEnum.Textures: + sourceMsg = "" + (!(Utils.customTextures) ? "Texture Source:\nDefault" : "Texture Source:\nCustom"); + break; + case Utils.ToggleEnum.Audio: + sourceMsg = "" + (!(Utils.customAudio) ? "Audio Source:\nDefault" : "Audio Source:\nCustom"); + break; + default: + break; + } + text.text = sourceMsg; + } + } }); } @@ -329,14 +362,14 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects { string toggleType = toggleData.Toggle.ToString(); ToggleCustomAssets(toggleType); - if (toggleType == "Textures") - { - FlashMessage(toggleData.Button, "Toggled custom textures!", 0.1f); - } - else if (toggleType == "Audio") - { - FlashMessage(toggleData.Button, "Toggled custom audio!", 0.1f); - } + if (toggleType == "Textures") + { + FlashMessage(toggleData.Button, "Toggled custom textures!\n(Restart Required)", 0.1f); + } + else if (toggleType == "Audio") + { + FlashMessage(toggleData.Button, "Toggled custom audio!", 0.1f); + } } } diff --git a/MelonLoader/Patches/GameObjects/Close_Patch.cs b/MelonLoader/Patches/GameObjects/Close_Patch.cs index 9845019..fb6ff9a 100644 --- a/MelonLoader/Patches/GameObjects/Close_Patch.cs +++ b/MelonLoader/Patches/GameObjects/Close_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; @@ -50,3 +50,4 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects } } } +*/ \ No newline at end of file diff --git a/MelonLoader/Patches/GameObjects/CustomSettings_Patch.cs b/MelonLoader/Patches/GameObjects/CustomSettings_Patch.cs index cee9577..18ee55a 100644 --- a/MelonLoader/Patches/GameObjects/CustomSettings_Patch.cs +++ b/MelonLoader/Patches/GameObjects/CustomSettings_Patch.cs @@ -1,24 +1,24 @@ -using HarmonyLib; -using Il2Cpp; -using PvZ_Fusion_Translator.AssetStore; +//using HarmonyLib; +//using Il2Cpp; +//using PvZ_Fusion_Translator.AssetStore; -namespace PvZ_Fusion_Translator.Patches.GameObjects -{ - [HarmonyPatch(typeof(CustomSettings))] - public static class CustomSettings_Patch - { - [HarmonyPatch(nameof(CustomSettings.Awake))] - [HarmonyPostfix] - private static void Awake(CustomSettings __instance) - { - __instance.textMesh = StringStore.TranslateText(__instance.textMesh); - } +//namespace PvZ_Fusion_Translator.Patches.GameObjects +//{ +// [HarmonyPatch(typeof(CustomSettings))] +// public static class CustomSettings_Patch +// { +// [HarmonyPatch(nameof(CustomSettings.Awake))] +// [HarmonyPostfix] +// private static void Awake(CustomSettings __instance) +// { +// __instance.textMesh = StringStore.TranslateText(__instance.textMesh); +// } - [HarmonyPatch(nameof(CustomSettings.ChangeText))] - [HarmonyPostfix] - private static void ChangeText(CustomSettings __instance) - { - __instance.textMesh = StringStore.TranslateText(__instance.textMesh); - } - } -} +// [HarmonyPatch(nameof(CustomSettings.ChangeText))] +// [HarmonyPostfix] +// private static void ChangeText(CustomSettings __instance) +// { +// __instance.textMesh = StringStore.TranslateText(__instance.textMesh); +// } +// } +//} diff --git a/MelonLoader/Patches/GameObjects/CustomSun_Patch.cs b/MelonLoader/Patches/GameObjects/CustomSun_Patch.cs index ab596b9..5d71423 100644 --- a/MelonLoader/Patches/GameObjects/CustomSun_Patch.cs +++ b/MelonLoader/Patches/GameObjects/CustomSun_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; @@ -43,3 +43,4 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects } } } +*/ \ No newline at end of file diff --git a/MelonLoader/Patches/GameObjects/GardenPlant_Patch.cs b/MelonLoader/Patches/GameObjects/GardenPlant_Patch.cs index ead08fa..92ad5ec 100644 --- a/MelonLoader/Patches/GameObjects/GardenPlant_Patch.cs +++ b/MelonLoader/Patches/GameObjects/GardenPlant_Patch.cs @@ -2,6 +2,7 @@ using Il2Cpp; using PvZ_Fusion_Translator.AssetStore; using System.Text.RegularExpressions; +using Il2CppZenGarden; namespace PvZ_Fusion_Translator.Patches.GameObjects { diff --git a/MelonLoader/Patches/GameObjects/LevelResultMenu_Patch.cs b/MelonLoader/Patches/GameObjects/LevelResultMenu_Patch.cs new file mode 100644 index 0000000..8b2071e --- /dev/null +++ b/MelonLoader/Patches/GameObjects/LevelResultMenu_Patch.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Il2Cpp; +using UnityEngine; +using HarmonyLib; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; + +namespace PvZ_Fusion_Translator.Patches.GameObjects +{ + [HarmonyPatch(typeof(LevelResultMenu))] + public static class LevelResultMenu_Patch + { + [HarmonyPatch(nameof(LevelResultMenu.Awake))] + [HarmonyPatch(nameof(LevelResultMenu.Start))] + [HarmonyPatch(nameof(LevelResultMenu.ShowResult))] + [HarmonyPostfix] + public static void Awake(LevelResultMenu __instance) + { + foreach (TextMeshProUGUI txt in __instance.GetComponentsInChildren()) + { + txt.text = StringStore.TranslateText(txt.text); + } + } + } +} diff --git a/MelonLoader/Patches/GameObjects/MainMenu_Patch.cs b/MelonLoader/Patches/GameObjects/MainMenu_Patch.cs index ee63097..f6c1024 100644 --- a/MelonLoader/Patches/GameObjects/MainMenu_Patch.cs +++ b/MelonLoader/Patches/GameObjects/MainMenu_Patch.cs @@ -15,9 +15,10 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects { public static void AnimOver(BaseMenu __instance) { - Transform changelogObj = __instance.transform.Find("Grave/UpdateInfo"); + Transform changelogObj = __instance.transform.Find("Grave/UpdateInfoButton"); Transform langObj = UnityEngine.Object.Instantiate(changelogObj, changelogObj.position + new Vector3(0.0f, 0.855f), changelogObj.rotation, __instance.transform.Find("Grave")); - langObj.name = "Languages"; + langObj.name = "LanguagesButton"; + __instance.collider2Ds.Add(langObj.GetComponent()); UIButton langBtn = langObj.GetComponent(); foreach(TextMeshProUGUI text in langObj.GetComponentsInChildren()) @@ -27,7 +28,6 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects langBtn.clickEvent = new UnityEvent(); langBtn.clickEvent.AddListener(new Action(() => OpenLanguageMenu(langBtn.gameObject))); - langBtn.clickEvent.AddListener(new Action(() => HideLangButton(langBtn.gameObject))); } public static void OpenLanguageMenu(GameObject langBtn) @@ -49,7 +49,6 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects OptLanguageBtn_Patch.OptLangBtn_Patch.Awake(templateButton); UIButton goBackButton = newOptionsMenu.transform.Find("Goback").GetComponent(); - goBackButton.clickEvent.AddListener(new Action(() => ShowLangButton(langBtn.gameObject))); newOptionsMenu.transform.Find("F").gameObject.SetActive(false); diff --git a/MelonLoader/Patches/GameObjects/MinorObjects/GameLose_Patch.cs b/MelonLoader/Patches/GameObjects/MinorObjects/GameLose_Patch.cs new file mode 100644 index 0000000..340fd95 --- /dev/null +++ b/MelonLoader/Patches/GameObjects/MinorObjects/GameLose_Patch.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using UnityEngine; +using Il2Cpp; +using PvZ_Fusion_Translator.Patches.BaseTextObjects; + +namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(GameLose))] + public static class GameLose_Patch + { + [HarmonyPatch(nameof(GameLose.UpdateSecondChanceTimer))] + public static void UpdateSecondChanceTimer(GameLose __instance) + { + if (InGameText.Instance == null) return; + + if (InGameText.Instance.timer < 0) return; + + InGameText_Patch.TranslateInGameText(InGameText.Instance); + } + } +} diff --git a/MelonLoader/Patches/GameObjects/MinorObjects/Money_Patch.cs b/MelonLoader/Patches/GameObjects/MinorObjects/Money_Patch.cs index 12ede0d..3caa1d1 100644 --- a/MelonLoader/Patches/GameObjects/MinorObjects/Money_Patch.cs +++ b/MelonLoader/Patches/GameObjects/MinorObjects/Money_Patch.cs @@ -11,6 +11,7 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects [HarmonyPatch(nameof(Money.Update))] private static void Update(Money __instance) { + if (!Utils.CheckForUntranslatedText(__instance.beanCount.text)) return; __instance.beanCount.text = StringStore.TranslateText(__instance.beanCount.text); __instance.beanCount2.text = StringStore.TranslateText(__instance.beanCount2.text); } diff --git a/MelonLoader/Patches/GameObjects/MinorObjects/Plant_Patch.cs b/MelonLoader/Patches/GameObjects/MinorObjects/Plant_Patch.cs index 0e0cbb2..b46f0db 100644 --- a/MelonLoader/Patches/GameObjects/MinorObjects/Plant_Patch.cs +++ b/MelonLoader/Patches/GameObjects/MinorObjects/Plant_Patch.cs @@ -4,7 +4,7 @@ using System.Text.RegularExpressions; namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects { - [HarmonyPatch(typeof(Plant))] + /*[HarmonyPatch(typeof(Plant))] public static class Plant_Patch { [HarmonyPostfix] @@ -43,5 +43,5 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects } return originalText; } - } + }*/ } \ No newline at end of file diff --git a/MelonLoader/Patches/GameObjects/MinorObjects/PlayerName_Patch.cs b/MelonLoader/Patches/GameObjects/MinorObjects/PlayerName_Patch.cs index 29efec6..6b55d0a 100644 --- a/MelonLoader/Patches/GameObjects/MinorObjects/PlayerName_Patch.cs +++ b/MelonLoader/Patches/GameObjects/MinorObjects/PlayerName_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using PvZ_Fusion_Translator.AssetStore; @@ -14,4 +14,4 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects __instance.textMesh.text = StringStore.TranslateText(__instance.textMesh.text); } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/MelonLoader/Patches/GameObjects/MinorObjects/SelectYourPlants_Patch.cs b/MelonLoader/Patches/GameObjects/MinorObjects/SelectYourPlants_Patch.cs index 073cc7b..a5c1d73 100644 --- a/MelonLoader/Patches/GameObjects/MinorObjects/SelectYourPlants_Patch.cs +++ b/MelonLoader/Patches/GameObjects/MinorObjects/SelectYourPlants_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using PvZ_Fusion_Translator.AssetStore; @@ -19,3 +19,4 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects } } } +*/ \ No newline at end of file diff --git a/MelonLoader/Patches/GameObjects/MinorObjects/Zombie_Patch.cs b/MelonLoader/Patches/GameObjects/MinorObjects/Zombie_Patch.cs index ea643de..5a67517 100644 --- a/MelonLoader/Patches/GameObjects/MinorObjects/Zombie_Patch.cs +++ b/MelonLoader/Patches/GameObjects/MinorObjects/Zombie_Patch.cs @@ -14,9 +14,9 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects private static Dictionary HPStrings = new Dictionary() { { "最后一击:(\\d+)\nDPS:([^\\s]+)\n总伤害:(\\d+)", "Last Damage: {0}\nDPS: {1}\nTotal: {2}" }, - { "^HP:(\\d+)/(\\d+)\n一类:(\\d+)/(\\d+)\n二类:(\\d+)/(\\d+)$", "HP: {0}/{1}\nType 1 armor: {2}/{3}\nType 2 armor: {4}/{5}" }, - { "^HP:(\\d+)/(\\d+)\n一类:(\\d+)/(\\d+)$", "HP: {0}/{1}\nType 1 armor: {2}/{3}" }, - { "^HP:(\\d+)/(\\d+)\n二类:(\\d+)/(\\d+)$", "HP: {0}/{1}\nType 2 armor: {2}/{3}" }, + { "^HP:(\\d+)/(\\d+)\n一类:(\\d+)/(\\d+)\n二类:(\\d+)/(\\d+)$", "HP: {0}/{1}\nT1 armor: {2}/{3}\nT2 armor: {4}/{5}" }, + { "^HP:(\\d+)/(\\d+)\n一类:(\\d+)/(\\d+)$", "HP: {0}/{1}\nT1 armor: {2}/{3}" }, + { "^HP:(\\d+)/(\\d+)\n二类:(\\d+)/(\\d+)$", "HP: {0}/{1}\nT2 armor: {2}/{3}" }, { "^HP:(\\d+)/(\\d+)$", "HP: {0}/{1}" } }; @@ -38,12 +38,15 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects __instance.healthText.transform.rotation = Quaternion.Euler(0f, 0f, 0f); } - [HarmonyPatch(nameof(Zombie.Update))] - [HarmonyPrefix] + [HarmonyPatch(nameof(Zombie.UpdateHealthText))] + [HarmonyPostfix] public static void Update(Zombie __instance) { if (__instance.theZombieType == ZombieType.TrainingDummy || !Board.Instance.showZombieHealth) return; + + if (__instance.healthText == null || __instance.healthTextShadow == null) return; + TranslateHpUI(__instance.healthText, __instance); TranslateHpUI(__instance.healthTextShadow, __instance); @@ -158,13 +161,11 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects.MinorObjects if (fIndex > -1 && found) { string fStr = HPStrings.ElementAt(fIndex).Value; - string DPS = originalText.Split("\n")[1].Replace("DPS:", ""); - DPS = StringStore.TranslateText(DPS); switch (fIndex) { case 0: - finalText = string.Format(fStr, __instance.lastDamage, DPS, __instance.totalDamage); + finalText = string.Format(fStr, __instance.lastDamage, __instance.CurrentDPS, __instance.totalDamage); break; default: break; diff --git a/MelonLoader/Patches/GameObjects/UIDifficulty_Patch.cs b/MelonLoader/Patches/GameObjects/UIDifficulty_Patch.cs index b914913..c7b6c5b 100644 --- a/MelonLoader/Patches/GameObjects/UIDifficulty_Patch.cs +++ b/MelonLoader/Patches/GameObjects/UIDifficulty_Patch.cs @@ -14,11 +14,8 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects [HarmonyPostfix] private static void Update(UIDifficulty __instance) { + if (!Utils.CheckForUntranslatedText(__instance.t.text)) return; __instance.t.text = StringStore.TranslateText(__instance.t.text); - foreach(TextMeshProUGUI text in __instance.GetComponentsInChildren()) - { - text.text = StringStore.TranslateText(text.text); - } } } } \ No newline at end of file diff --git a/MelonLoader/Patches/Managers/AlmanacMgrZombie_Patch.cs b/MelonLoader/Patches/Managers/AlmanacMgrZombie_Patch.cs index daf88bc..a47e22c 100644 --- a/MelonLoader/Patches/Managers/AlmanacMgrZombie_Patch.cs +++ b/MelonLoader/Patches/Managers/AlmanacMgrZombie_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; @@ -125,4 +125,4 @@ namespace PvZ_Fusion_Translator.Patches.Managers return true; } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/MelonLoader/Patches/Managers/AlmanacPlantBank_Patch.cs b/MelonLoader/Patches/Managers/AlmanacPlantBank_Patch.cs index bf150c8..236fc5c 100644 --- a/MelonLoader/Patches/Managers/AlmanacPlantBank_Patch.cs +++ b/MelonLoader/Patches/Managers/AlmanacPlantBank_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; @@ -197,4 +197,4 @@ namespace PvZ_Fusion_Translator.Patches.Managers __instance.skinButton.transform.GetChild(2).Translate(new Vector3(-0.35f, 0)); } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/MelonLoader/Patches/Managers/DrawCardManager_Patch.cs b/MelonLoader/Patches/Managers/DrawCardManager_Patch.cs index f8ccd3b..0db3ecf 100644 --- a/MelonLoader/Patches/Managers/DrawCardManager_Patch.cs +++ b/MelonLoader/Patches/Managers/DrawCardManager_Patch.cs @@ -1,8 +1,9 @@ using HarmonyLib; using Il2Cpp; using Il2CppTMPro; -using Il2CppSystem.Collections.Generic; using PvZ_Fusion_Translator.AssetStore; +using PvZ_Fusion_Translator.Patches.BaseTextObjects; +using System.Text.RegularExpressions; using UnityEngine; using UnityEngine.TextCore.Text; using static MelonLoader.MelonLogger; @@ -12,48 +13,66 @@ namespace PvZ_Fusion_Translator.Patches.GameObjects [HarmonyPatch(typeof(DrawCardManager))] public static class DrawCardManager_Patch { + public static TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + + [HarmonyPatch(nameof(DrawCardManager.Awake))] + [HarmonyPostfix] + private static void Awake(DrawCardManager __instance) + { + fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + } + [HarmonyPatch(nameof(DrawCardManager.UpdateText))] [HarmonyPostfix] private static void Postfix_UpdateText(DrawCardManager __instance) { - Il2CppSystem.Collections.Generic.List texts = __instance.texts; - __instance.upName = StringStore.TranslateText(__instance.upName); - if (texts != null && texts.Count > 0) + KeyValuePair regexPair = new KeyValuePair("抽取次数:\n(\\d+)/(\\d+)\n当前up植物:\n([^\\s]+)\nup刷新倒计时:\n(\\d+)", "Draw Count:\n{0}/{1}\nCurrent Up:\n{2}\nNext Up in: \n{3}s"); + + foreach(TextMeshProUGUI txt in __instance.texts) { - foreach (TextMeshProUGUI textComponent in texts) + if(Regex.IsMatch(txt.text, regexPair.Key)) { - if (textComponent != null) - { - string translatedText = StringStore.TranslateText(textComponent.text); - TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); - textComponent.text = translatedText; - textComponent.font = fontAsset; - } + txt.text = TranslateGashaponText(txt.text, regexPair.Key, regexPair.Value, __instance.up); + txt.font = fontAsset; } } } - [HarmonyPatch(nameof(DrawCardManager.Update))] + public static string TranslateGashaponText(string originalText, string pattern, string fallback, PlantType up) + { + string res = ""; + string fStr = ""; + Match match = Regex.Match(originalText, pattern); + if(match.Success) + { + GroupCollection groups = match.Groups; + fStr = StringStore.translationStringRegex.ContainsKey(pattern) ? StringStore.translationStringRegex[pattern] : fallback; + List dynamicParts = []; + for(int i = 1; i < groups.Count; i++) + { + string group = groups[i].Value; + string translatedGroup = ""; + if(i == 3 && up != PlantType.Peashooter) + { + translatedGroup = Utils.GetPlantNameFromAlmanac(up); + } + else + { + translatedGroup = StringStore.TranslateText(group); + } + dynamicParts.Add(translatedGroup); + } + res = string.Format(fStr, [.. dynamicParts]); + } + return res; + } + + /*[HarmonyPatch(nameof(DrawCardManager.Update))] [HarmonyPostfix] private static void Postfix_Update(DrawCardManager __instance) { - Il2CppSystem.Collections.Generic.List texts = __instance.texts; - __instance.upName = StringStore.TranslateText(__instance.upName); - - if (texts != null && texts.Count > 0) - { - foreach (TextMeshProUGUI textComponent in texts) - { - if (textComponent != null) - { - string translatedText = StringStore.TranslateText(textComponent.text); - TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); - textComponent.text = translatedText; - textComponent.font = fontAsset; - } - } - } - } + Postfix_UpdateText(__instance); + }*/ } } diff --git a/MelonLoader/Patches/Managers/InGameUI_Patch.cs b/MelonLoader/Patches/Managers/InGameUI_Patch.cs index 670187b..b9878bc 100644 --- a/MelonLoader/Patches/Managers/InGameUI_Patch.cs +++ b/MelonLoader/Patches/Managers/InGameUI_Patch.cs @@ -3,6 +3,7 @@ using Il2Cpp; using Il2CppTMPro; using PvZ_Fusion_Translator; using PvZ_Fusion_Translator.AssetStore; +using PvZ_Fusion_Translator.Patches.BaseTextObjects; using System.Text.RegularExpressions; using Unity.Collections; @@ -11,83 +12,42 @@ namespace PvZ_Fusion_Translator.Patches.Managers [HarmonyPatch(typeof(InGameUI))] public static class InGameUI_Patch { + public static string travelAdventurePattern = "^旅行冒险 ([^\\s:]+)"; + public static string travelAdventureFallback = "Odyssey Adventure: {0}"; + [HarmonyPatch(nameof(InGameUI.Start))] [HarmonyPostfix] private static void Start(InGameUI __instance) { - foreach(TextMeshProUGUI text in __instance.T) - { - if (text.text == null) continue; - - string originalText = text.text; - text.text = text.text.Replace("\n", " "); - Regex checkFusionChallenge = new Regex("^超级([^\\s:]+)(:?挑战1?)"); - - if (text.text.Contains("配方:") && !checkFusionChallenge.IsMatch(text.text)) - { - string[] lines = text.text.Split(":"); - lines[1] = Utils.GetPlantNameFromAlmanac(lines[1]); - if (lines[1] == "") - { - Log.LogError("Couldn't find plant! (Fusion Showcase)"); - lines[1] = StringStore.TranslateText(lines[1]); - } - text.text = StringStore.TranslateText("配方:") + lines[1]; - text.autoSizeTextContainer = true; - } - else - { - text.text = (StringStore.translationString.ContainsKey(text.text + "_MG")) ? StringStore.TranslateText(text.text + "_MG") : StringStore.TranslateText(text.text); - text.text = text.text.Replace("\n", " "); - } - } + SetLevelName(__instance); } [HarmonyPatch(nameof(InGameUI.SetUniqueText))] [HarmonyPostfix] private static void SetUniqueText(InGameUI __instance) { - foreach(TextMeshProUGUI text in __instance.T) - { - if (text.text == null) continue; - - string originalText = text.text; - text.text = text.text.Replace("\n", " "); - Regex checkFusionChallenge = new Regex("^超级([^\\s:]+)(:?挑战1?)"); - - if (text.text.Contains("配方:") && !checkFusionChallenge.IsMatch(text.text)) - { - string[] lines = text.text.Split(":"); - lines[1] = Utils.GetPlantNameFromAlmanac(lines[1]); - if (lines[1] == "") - { - Log.LogError("Couldn't find plant! (Fusion Showcase)"); - lines[1] = StringStore.TranslateText(lines[1]); - } - text.text = StringStore.TranslateText("配方:") + lines[1]; - text.autoSizeTextContainer = true; - } - else - { - text.text = (StringStore.translationString.ContainsKey(text.text + "_MG")) ? StringStore.TranslateText(text.text + "_MG") : StringStore.TranslateText(text.text); - text.text = text.text.Replace("\n", " "); - } - } + SetLevelName(__instance); } [HarmonyPatch(nameof(InGameUI.SetLevelName))] [HarmonyPostfix] private static void SetLevelName(InGameUI __instance) { - foreach(TextMeshProUGUI text in __instance.T) + foreach (TextMeshProUGUI text in __instance.levelNameText) { if (text.text == null) continue; - + string originalText = text.text; text.text = text.text.Replace("\n", " "); + Regex checkFusionChallenge = new Regex("^超级([^\\s:]+)(:?挑战1?)"); + Regex checkTravelAdv = new Regex(travelAdventurePattern); - if (text.text.Contains("配方:") && !checkFusionChallenge.IsMatch(text.text)) + if(checkTravelAdv.IsMatch(originalText)) + { + text.text = InGameText_Patch.TranslatePlantNameParts(originalText, travelAdventurePattern, travelAdventureFallback); + } + else if (text.text.Contains("配方:") && !checkFusionChallenge.IsMatch(text.text)) { string[] lines = text.text.Split(":"); lines[1] = Utils.GetPlantNameFromAlmanac(lines[1]); @@ -106,5 +66,22 @@ namespace PvZ_Fusion_Translator.Patches.Managers } } } + + /*[HarmonyPatch(nameof(InGameUI.Update))] + [HarmonyPostfix] + private static void Update(InGameUI __instance) + { + if (!__instance.board.boardTag.isDrawCards) return; + + KeyValuePair regexPair = new KeyValuePair("抽取次数:\n(\\d+)/(\\d+)\n当前up植物:\n([^\\s]+)\nup刷新倒计时:\n(\\d+)", "Draw Count:\n{0}/{1}\nCurrent Up:\n{2}\nNext Up in: \n{3}s"); + + foreach(TextMeshProUGUI txt in __instance.DrawCardsHead.GetComponentsInChildren()) + { + if(Regex.IsMatch(txt.text, regexPair.Key)) + { + txt.text = InGameText_Patch.TranslatePlantNameParts(txt.text, regexPair.Key, regexPair.Value); + } + } + }*/ } } diff --git a/MelonLoader/Patches/Managers/GameAPP_Patch.cs b/MelonLoader/Patches/Managers/Screen_Patch.cs similarity index 68% rename from MelonLoader/Patches/Managers/GameAPP_Patch.cs rename to MelonLoader/Patches/Managers/Screen_Patch.cs index 73943c3..da7c0ed 100644 --- a/MelonLoader/Patches/Managers/GameAPP_Patch.cs +++ b/MelonLoader/Patches/Managers/Screen_Patch.cs @@ -2,23 +2,23 @@ using Il2Cpp; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; +using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace PvZ_Fusion_Translator.Patches.Managers { - [HarmonyPatch(typeof(GameAPP))] - public static class GameAPP_Patch + [HarmonyPatch(typeof(Screen))] + public static class Screen_Patch { - [HarmonyPatch(nameof(GameAPP.Update))] + [HarmonyPatch(nameof(Screen.SetResolution), argumentTypes: [typeof(int), typeof(int), typeof(bool)])] [HarmonyPrefix] - private static bool Update(GameAPP __instance) + private static bool SetResolution(Screen __instance) { if(EventSystem.current.currentSelectedGameObject != null) { if (EventSystem.current.currentSelectedGameObject.TryGetComponent(out TMP_InputField field)) { - __instance.MusicUpdate(); return false; } } diff --git a/MelonLoader/Patches/Managers/TowerManager_Patch.cs b/MelonLoader/Patches/Managers/TowerManager_Patch.cs index 221b6e5..3088e45 100644 --- a/MelonLoader/Patches/Managers/TowerManager_Patch.cs +++ b/MelonLoader/Patches/Managers/TowerManager_Patch.cs @@ -17,7 +17,10 @@ namespace PvZ_Fusion_Translator.Patches.Managers { if (transform != null) { - transform.GetComponent().text = StringStore.TranslateText(transform.GetComponent().text); + if(transform.gameObject.active) + { + transform.GetComponent().text = StringStore.TranslateText(transform.GetComponent().text); + } } } } diff --git a/MelonLoader/Patches/Modes/Odyssey/MultipleChoiceMenu_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/MultipleChoiceMenu_Patch.cs new file mode 100644 index 0000000..4b4f61c --- /dev/null +++ b/MelonLoader/Patches/Modes/Odyssey/MultipleChoiceMenu_Patch.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Il2Cpp; +using HarmonyLib; +using UnityEngine; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; + +namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey +{ + [HarmonyPatch(typeof(MultipleChoiceMenu))] + public static class MultipleChoiceMenu_Patch + { + [HarmonyPatch(nameof(MultipleChoiceMenu.Awake))] + [HarmonyPatch(nameof(MultipleChoiceMenu.UpdateWindow))] + [HarmonyPatch(nameof(MultipleChoiceMenu.Refresh))] + [HarmonyPatch(nameof(MultipleChoiceMenu.Cancel))] + [HarmonyPostfix] + public static void Awake(MultipleChoiceMenu __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + foreach(BaseWindow window in __instance.windows) + { + foreach(TextMeshProUGUI txt in window.GetComponentsInChildren()) + { + txt.font = fontAsset; + txt.text = StringStore.translationString.ContainsKey(txt.text + "_MC") ? StringStore.TranslateText(txt.text + "_MC") : StringStore.TranslateText(txt.text); + } + } + } + } +} diff --git a/MelonLoader/Patches/Modes/Odyssey/OppositeBuffManager_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/OppositeBuffManager_Patch.cs index 89143ce..ef299fa 100644 --- a/MelonLoader/Patches/Modes/Odyssey/OppositeBuffManager_Patch.cs +++ b/MelonLoader/Patches/Modes/Odyssey/OppositeBuffManager_Patch.cs @@ -16,29 +16,33 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey public static string badFormat = StringStore.translationStringRegex.ContainsKey(badPattern) ? StringStore.translationStringRegex[badPattern] : "But, {0}"; public static TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); - [HarmonyPatch(nameof(OppositeBuffManager.Awake))] + [HarmonyPatch(nameof(OppositeBuffManager.SetText))] [HarmonyPostfix] - private static void Awake(OppositeBuffManager __instance) + private static void SetText(OppositeBuffManager __instance) { - TranslateOppositeText(__instance.textA_bad, BuffType.Debuff, __instance.buffA.theDebuffID, true); - TranslateOppositeText(__instance.textA_good, __instance.buffA.theOptionType, __instance.buffA.theOptionID); - TranslateOppositeText(__instance.textB_bad, BuffType.Debuff, __instance.buffB.theDebuffID, true); - TranslateOppositeText(__instance.textB_good, __instance.buffB.theOptionType, __instance.buffB.theOptionID); + /*if (TravelMgr_Patch.travelBuffString.ContainsKey(__result)) + { + __result = TravelMgr_Patch.travelBuffString[__result]; + } + else if(TravelMgr_Patch.travelBuffString.ContainsKey(TravelMgr_Patch.RemoveBuffName(__result))) + { + __result = TravelMgr_Patch.travelBuffString[TravelMgr_Patch.RemoveBuffName(__result)]; + }*/ } - public static void TranslateOppositeText(Il2CppSystem.Collections.Generic.List textList, BuffType buffType, int buffIndex, bool isBad = false) + public static void TranslateOppositeText(Il2CppSystem.Collections.Generic.List textList, Il2CppSystem.Object buff, bool isBad = false) { - string buff = translatedTravelBuffs[buffLinks[buffType]][buffIndex]; + string buffText = TravelMgr.Instance.GetText(buff); foreach (var text in textList) { if (isBad) { - text.text = string.Format(badFormat, buff); + text.text = string.Format(badFormat, buffText); } else { - text.text = buff; + text.text = buffText; } text.font = fontAsset; diff --git a/MelonLoader/Patches/Modes/Odyssey/TravelAdvantureMenu_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/TravelAdvantureMenu_Patch.cs new file mode 100644 index 0000000..f2a38f4 --- /dev/null +++ b/MelonLoader/Patches/Modes/Odyssey/TravelAdvantureMenu_Patch.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using Il2Cpp; +using PvZ_Fusion_Translator.AssetStore; +using UnityEngine; + +namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey +{ + [HarmonyPatch(typeof(TravelAdvantureMenu))] + public static class TravelAdvantureMenu_Patch + { + [HarmonyPatch(nameof(TravelAdvantureMenu.Awake))] + [HarmonyPostfix] + public static void Awake(TravelAdvantureMenu __instance) + { + foreach(CustomButton_enterGame button in __instance.GetComponentsInChildren()) + { + string plantName = Utils.GetPlantNameFromAlmanac(button.levelName.text); + button.levelName.text = (plantName != "") ? plantName : StringStore.TranslateText(button.levelName.text); + } + } + + [HarmonyPatch(nameof(TravelAdvantureMenu.LookWeak))] + [HarmonyPostfix] + public static void LookWeak(TravelAdvantureMenu __instance) + { + Awake(__instance); + } + + [HarmonyPatch(nameof(TravelAdvantureMenu.LookUlti))] + [HarmonyPostfix] + public static void LookUlti(TravelAdvantureMenu __instance) + { + Awake(__instance); + } + } +} diff --git a/MelonLoader/Patches/Modes/Odyssey/TravelBuffOptionButton_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/TravelBuffOptionButton_Patch.cs index a0ef13c..a8138a0 100644 --- a/MelonLoader/Patches/Modes/Odyssey/TravelBuffOptionButton_Patch.cs +++ b/MelonLoader/Patches/Modes/Odyssey/TravelBuffOptionButton_Patch.cs @@ -27,11 +27,10 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey public static void TranslateOptionButton(TravelBuffOptionButton button) { - SortedDictionary buffSet = translatedTravelBuffs[buffLinks[button.buffType]]; - - string buff = button.show != null && button.introduce.text != "词条已选完" ? buffSet[button.buffIndex] : StringStore.TranslateText("词条已选完"); - - button.introduce.text = buff; + if(!TravelMgr_Patch.travelBuffString.ContainsKey(button.introduce.text) && Utils.CheckForUntranslatedText(button.introduce.text)) + { + button.introduce.text = StringStore.TranslateText(button.introduce.text); + } } } diff --git a/MelonLoader/Patches/Modes/Odyssey/TravelLookBuff_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/TravelLookBuff_Patch.cs index ecf918a..9629857 100644 --- a/MelonLoader/Patches/Modes/Odyssey/TravelLookBuff_Patch.cs +++ b/MelonLoader/Patches/Modes/Odyssey/TravelLookBuff_Patch.cs @@ -38,9 +38,17 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey [HarmonyPostfix] public static void Post_SetBuff(TravelLookBuff __instance) { - SortedDictionary buffSet = translatedTravelBuffs[buffLinks[__instance.buffType]]; + /*SortedDictionary buffSet = translatedTravelBuffs[buffLinks[__instance.buffType]]; string buffText = buffSet.ContainsKey(__instance.buffIndex) ? buffSet[__instance.buffIndex] : StringStore.TranslateText(__instance.introduce.text); - __instance.introduce.text = buffText; + __instance.introduce.text = buffText;*/ + + foreach (TextMeshProUGUI text in __instance.transform.FindChild("Images").FindChild("Introduce").GetComponentsInChildren()) + { + if(!TravelMgr_Patch.travelBuffString.ContainsKey(text.text) && Utils.CheckForUntranslatedText(text.text)) + { + text.text = StringStore.TranslateText(text.text); + } + } foreach (TextMeshProUGUI text in __instance.transform.FindChild("Images").FindChild("Button").GetComponentsInChildren()) { diff --git a/MelonLoader/Patches/Modes/Odyssey/TravelMgr_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/TravelMgr_Patch.cs index af371b0..407880f 100644 --- a/MelonLoader/Patches/Modes/Odyssey/TravelMgr_Patch.cs +++ b/MelonLoader/Patches/Modes/Odyssey/TravelMgr_Patch.cs @@ -1,5 +1,6 @@ using HarmonyLib; using Il2Cpp; +using PvZ_Fusion_Translator.AssetStore; using System; using System.Collections.Generic; using System.Linq; @@ -34,6 +35,11 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey { "investmentBuffs", new SortedDictionary() } }; + public static Dictionary travelBuffString = new() + { + + }; + public static Dictionary buffLinks = new() { { BuffType.AdvancedBuff, "advancedBuffs" }, @@ -43,6 +49,24 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey { BuffType.InvestmentBuff, "investmentBuffs" } }; + [HarmonyPatch(nameof(TravelMgr.GetText))] + [HarmonyPostfix] + public static void GetText(TravelMgr __instance, ref string __result) + { + if (travelBuffString.ContainsKey(__result)) + { + __result = travelBuffString[__result]; + } + else if(travelBuffString.ContainsKey(RemoveBuffName(__result))) + { + __result = travelBuffString[RemoveBuffName(__result)]; + } + else + { + __result = StringStore.TranslateText(__result); + } + } + public static void DumpTravelBuffs() { TravelMgr.Instance.GetPlantBuffUnlockCount(PlantType.DoomGatling); @@ -50,26 +74,31 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey foreach (var pair in TravelDictionary.advancedBuffsText) { dumpedTravelBuffs["advancedBuffs"].Add((int)pair.Key, pair.Value); + travelBuffString.Add(pair.Value, pair.Value); } foreach (var pair in TravelDictionary.ultimateBuffsText) { dumpedTravelBuffs["ultimateBuffs"].Add((int)pair.Key, pair.Value); + travelBuffString.Add(pair.Value, pair.Value); } foreach (var pair in TravelDictionary.debuffData) { dumpedTravelBuffs["debuffs"].Add((int)pair.Key, pair.Value.Item1); + travelBuffString.Add(pair.Value.Item1, pair.Value.Item1); } foreach (var pair in TravelDictionary.unlocksText) { dumpedTravelBuffs["unlocks"].Add((int)pair.Key, pair.Value); + travelBuffString.Add(pair.Value, pair.Value); } foreach (var pair in TravelMgr.InvestBuffsData) { dumpedTravelBuffs["investmentBuffs"].Add((int)pair.Key, pair.Value.GetDescription()); + travelBuffString.Add(pair.Value.GetDescription(), pair.Value.GetDescription()); } File.WriteAllText(Path.Combine(GetAssetDir(AssetType.Dumps), "travel_buffs.json"), JsonSerializer.Serialize(dumpedTravelBuffs, new JsonSerializerOptions @@ -91,6 +120,68 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey } } + //System.Text.Json.JsonSerializer.Deserialize>>(travelBuffsContent); + public static Dictionary> GenerateTranslatedTravelBuffs(string travelBuffsContent) + { + TravelMgr_Patch.DumpTravelBuffs(); + + Dictionary> travelBuffs = System.Text.Json.JsonSerializer.Deserialize>>(travelBuffsContent); + + // save travel buffs + + string travelBuffsToSave = SerializeWithIndentation(travelBuffs); + string stringDir = GetAssetDir(AssetType.Strings, Utils.Language); + File.WriteAllText(Path.Combine(stringDir, "travel_buffs.json"), travelBuffsToSave); + + foreach(var i in travelBuffs) + { + var originalBuffSet = dumpedTravelBuffs[i.Key]; + foreach(var j in originalBuffSet) + { + string originalBuff = j.Value; + var translatedBuffSet = travelBuffs[i.Key]; + + if (j.Value == originalBuff) + { + if (translatedBuffSet.ContainsKey(j.Key)) + { + if(travelBuffString.ContainsKey(originalBuff)) + { + travelBuffString[originalBuff] = translatedBuffSet[j.Key]; + } + else + { + travelBuffString.Add(originalBuff, translatedBuffSet[j.Key]); + } + } + } + else if(j.Value == RemoveBuffName(originalBuff)) + { + if (translatedBuffSet.ContainsKey(j.Key)) + { + if(travelBuffString.ContainsKey(originalBuff)) + { + travelBuffString[RemoveBuffName(originalBuff)] = translatedBuffSet[j.Key]; + } + else + { + travelBuffString.Add(RemoveBuffName(originalBuff), translatedBuffSet[j.Key]); + } + } + } + + /*var translatedBuffSet = travelBuffs[i.Key]; + if(translatedBuffSet.ContainsKey(j.Key)) + { + string translatedBuff = travelBuffs[i.Key][j.Key]; + travelBuffString[originalBuff] = translatedBuff; + }*/ + } + } + + return travelBuffs; + } + public static string MatchTravelBuff(string originalText) { string res = ""; @@ -101,7 +192,11 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey { if (j.Value == originalText || j.Value == RemoveBuffName(originalText)) { - res = translatedTravelBuffs[i.Key][j.Key]; + var translatedBuffSet = translatedTravelBuffs[i.Key]; + if (translatedBuffSet.ContainsKey(j.Key)) + { + res = translatedBuffSet[j.Key]; + } break; } } diff --git a/MelonLoader/Patches/Modes/Odyssey/TravelStoreWindow_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/TravelStoreWindow_Patch.cs index f80e5bd..b0dd5bf 100644 --- a/MelonLoader/Patches/Modes/Odyssey/TravelStoreWindow_Patch.cs +++ b/MelonLoader/Patches/Modes/Odyssey/TravelStoreWindow_Patch.cs @@ -2,9 +2,10 @@ using Il2Cpp; using Il2CppTMPro; using PvZ_Fusion_Translator.AssetStore; -using static PvZ_Fusion_Translator.Patches.Modes.Odyssey.TravelMgr_Patch; -using UnityEngine; using System.Text.RegularExpressions; +using UnityEngine; +using static Il2CppSystem.Globalization.TimeSpanFormat; +using static PvZ_Fusion_Translator.Patches.Modes.Odyssey.TravelMgr_Patch; namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey { @@ -15,14 +16,23 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey [HarmonyPostfix] private static void SetType(TravelStoreWindow __instance) { - var buffSet = translatedTravelBuffs[buffLinks[__instance.buffType]]; + /*var buffSet = translatedTravelBuffs[buffLinks[__instance.buffType]]; - string buff = __instance.show != null && __instance.introduce.text != "词条已选完" ? buffSet[__instance.buffIndex] : StringStore.TranslateText("词条已选完"); + string buff = __instance.show != null && __instance.introduce.text != "词条已选完" ? buffSet[__instance.buffIndex] : StringStore.TranslateText("词条已选完");*/ string originalText = __instance.introduce.text; - - string affinities = TranslateAffinities(originalText); - - __instance.introduce.text = buff + affinities; + string affinityPattern = "([\\s\\S]+)(\\\n)([\\s\\S]+)(<\\/color>)"; + if(Regex.IsMatch(__instance.introduce.text, affinityPattern, options: RegexOptions.Singleline)) + { + Match match = Regex.Match(__instance.introduce.text, affinityPattern, options: RegexOptions.Singleline); + string startText = match.Groups[1].Value; + string affinityText = match.Groups[3].Value; + string affinities = TranslateAffinities(affinityText); + __instance.introduce.text = startText + affinities; + } + else + { + __instance.introduce.text = originalText; + } foreach (var text in __instance.buttonText) { @@ -42,55 +52,41 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey public static string TranslateAffinities(string originalText) { - string discolored = Utils.RemoveColorTags(originalText); - int firstNewlineIndex = discolored.IndexOf('\n'); - string result = ""; List translatedAffinities = []; - if(firstNewlineIndex >= 0) + string[] lines = originalText.Split('\n'); + + foreach(string line in lines) { - string affinityString = discolored.Substring(firstNewlineIndex); - string[] affinities = affinityString.Split('\n'); + if (string.IsNullOrEmpty(line)) continue; string fStr = StringStore.translationStringRegex.ContainsKey("【([^\\s]+)】_IV") ? StringStore.translationStringRegex["【([^\\s]+)】_IV"] : "[{0}]"; - string originalPattern = "【([^\\s]+)】"; + + // Extract dynamic parts from the original text + var regex = new Regex("【([^\\s]+)】"); + var match = regex.Match(line); + int groupCount = match.Groups.Count; - foreach (string affinity in affinities) + // List to hold formatted dynamic parts + List dynamicParts = []; + + // Loop through each group and determine its translation + for (int i = 1; i < groupCount; i++) { - if(affinity != "") - { - string translatedAffinity = affinity; - if (StringStore.TestRegex(affinity, originalPattern)) - { - // Extract dynamic parts from the original text - var regex = new Regex(originalPattern); - var match = regex.Match(affinity); - int groupCount = match.Groups.Count; - - // List to hold formatted dynamic parts - List dynamicParts = []; - - // Loop through each group and determine its translation - for (int i = 1; i < groupCount; i++) - { - string groupValue = match.Groups[i].Value; - string translatedValue = StringStore.translationString.ContainsKey(groupValue) - ? StringStore.translationString[groupValue] - : groupValue; - dynamicParts.Add(translatedValue); - } - - // Format the output string with dynamic parts - translatedAffinity = string.Format(fStr, [.. dynamicParts]); - } - - translatedAffinities.Add(translatedAffinity); - } + string groupValue = match.Groups[i].Value; + string translatedValue = StringStore.translationString.ContainsKey(groupValue) + ? StringStore.translationString[groupValue] + : groupValue; + dynamicParts.Add(translatedValue); } - result = "\n" + "" + String.Join("\n", translatedAffinities) + ""; + + // Format the output string with dynamic parts + string translatedAffinity = string.Format(fStr, [.. dynamicParts]); + translatedAffinities.Add(translatedAffinity); } + result = "\n" + "" + String.Join("\n", translatedAffinities) + ""; return result; } } diff --git a/MelonLoader/Patches/Modes/Super Editor/CustomButton_enterGame_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/CustomButton_enterGame_Patch.cs new file mode 100644 index 0000000..aea1f43 --- /dev/null +++ b/MelonLoader/Patches/Modes/Super Editor/CustomButton_enterGame_Patch.cs @@ -0,0 +1,215 @@ +using HarmonyLib; +using Il2Cpp; +using Il2CppGameLevel; +using Il2CppGameLevel.EventNodes; +using PvZ_Fusion_Translator.AssetStore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Threading.Tasks; +using Unity.VisualScripting.FullSerializer; +using UnityEngine; +using UnityEngine.UIElements; + +namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor +{ + [HarmonyPatch(typeof(CustomButton_enterGame))] + public static class CustomButton_enterGame_Patch + { + [HarmonyPatch(nameof(CustomButton_enterGame.LoadOnlineLevelAsync))] + [HarmonyPostfix] + public static void LoadOnlineLevelAsync(CustomButton_enterGame __instance) + { + string dumpPath = Path.Combine(FileLoader.GetAssetDir(FileLoader.AssetType.Dumps), "custom_level_data.json"); + Dictionary dumpData = new Dictionary(); + + if (!File.Exists(dumpPath)) + { + File.WriteAllText(dumpPath, System.Text.Json.JsonSerializer.Serialize(dumpData, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + } + + dumpData = JsonSerializer.Deserialize>(File.ReadAllText(dumpPath)); + + string dumpStringsPath = Path.Combine(FileLoader.GetAssetDir(FileLoader.AssetType.Dumps), "custom_level_strings.json"); + Dictionary dumpStringsData = new Dictionary(); + + if (!File.Exists(dumpStringsPath)) + { + File.WriteAllText(dumpStringsPath, System.Text.Json.JsonSerializer.Serialize(dumpStringsData, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + } + + dumpStringsData = JsonSerializer.Deserialize>(File.ReadAllText(dumpStringsPath)); + + var level = __instance; + + if(level.onlineLevelInfo != null) + { + string levelId = level.onlineLevelInfo.levelId; + if(levelId != null) + { + SerializedLevelData serializedLevel = level.serializedLevel; + if(CustomLevelMenu_Patch.translatedLevelData.ContainsKey(levelId)) + { + TranslatedLevelData levelData = CustomLevelMenu_Patch.translatedLevelData[levelId]; + level.levelName.text = levelData.name; + serializedLevel.name = levelData.name; + serializedLevel.boardConfig.startTip = levelData.startTip; + } + else + { + TranslatedLevelData dumpedLevelData = new TranslatedLevelData(level.onlineLevelInfo.levelName, serializedLevel.boardConfig.startTip); + dumpData.Add(levelId, dumpedLevelData); + } + + /*level.levelData.SerializedLevelData + foreach()*/ + } + } + else + { + level.levelName.text = StringStore.TranslateText(level.levelName.text); + } + + File.WriteAllText(dumpPath, System.Text.Json.JsonSerializer.Serialize(dumpData, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + File.WriteAllText(dumpStringsPath, System.Text.Json.JsonSerializer.Serialize(dumpStringsData, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + } + } + + /*[HarmonyPatch(typeof(LevelManager))] + public static class Test + { + [HarmonyPatch(nameof(LevelManager.SaveLevelData))] + [HarmonyPostfix] + public static void SaveLevelData(LevelManager __instance, ref SerializedLevelData serializedLevelData) + { + Log.LogDebug("hi 2"); + string json = JsonUtility.ToJson(serializedLevelData); + ReferenceLevelData references = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + foreach(var reference in references.references.RefIds) + { + ReferenceLevelData.Data nodeData = reference.data; + string nodeType = nodeData.nodeType; + + if(nodeType == "StringConcatNode") + { + Log.LogDebug(nodeData.value.ToString()); + } + + if(nodeType == "StringValueNode") + { + Log.LogDebug(nodeData.value.ToString()); + } + } + } + } + + + + public class ReferenceLevelData + { + public class Data + { + public string nodeId { get; set; } + public string nodeType { get; set; } + public Position position { get; set; } + public string nodeName { get; set; } + public string plant_PortName { get; set; } + public string column_PortName { get; set; } + public string row_PortName { get; set; } + public string plantType_PortName { get; set; } + public object value { get; set; } + public string value_PortName { get; set; } + public string plantTypeA_PortName { get; set; } + public string plantTypeB_PortName { get; set; } + public string equal_PortName { get; set; } + public string trigger_PortName { get; set; } + public string count_PortName { get; set; } + public string output_PortName { get; set; } + public string index_PortName { get; set; } + public string plants_PortName { get; set; } + public string plantList_PortName { get; set; } + public string loopBody_PortName { get; set; } + public string currentPlant_PortName { get; set; } + public string currentIndex_PortName { get; set; } + public string onCompleted_PortName { get; set; } + public string condition_PortName { get; set; } + public string then_PortName { get; set; } + public string else_PortName { get; set; } + public string a_PortName { get; set; } + public string b_PortName { get; set; } + public string result_PortName { get; set; } + public string shouldReset_PortName { get; set; } + public string onCount_PortName { get; set; } + public int? startValue { get; set; } + public string valueA_PortName { get; set; } + public string valueB_PortName { get; set; } + public string greater_PortName { get; set; } + public string less_PortName { get; set; } + public string displayText { get; set; } + public double? duration { get; set; } + public string text_PortName { get; set; } + public string duration_PortName { get; set; } + public string int_PortName { get; set; } + public string float_PortName { get; set; } + } + + public class GodShootingConfig + { + public List plants { get; set; } + } + + public class Position + { + public double x { get; set; } + public double y { get; set; } + } + + public class References + { + public int version { get; set; } + public List RefIds { get; set; } + } + + public class RefId + { + public int rid { get; set; } + public Type type { get; set; } + public Data data { get; set; } + } + + public class Type + { + public string @class { get; set; } + public string ns { get; set; } + public string asm { get; set; } + } + + public class ZombiesWithRow + { + public int zombieType { get; set; } + public int row { get; set; } + } + + public EventNodeGraph eventNodeGraph { get; set; } + public References references { get; set; } + }*/ +} \ No newline at end of file diff --git a/MelonLoader/Patches/Modes/Super Editor/CustomLevelMenu_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/CustomLevelMenu_Patch.cs index 5e35493..31eead2 100644 --- a/MelonLoader/Patches/Modes/Super Editor/CustomLevelMenu_Patch.cs +++ b/MelonLoader/Patches/Modes/Super Editor/CustomLevelMenu_Patch.cs @@ -36,13 +36,20 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor } } - [HarmonyPatch(nameof(CustomLevelMenu.InitWindows))] + [HarmonyPatch(nameof(CustomLevelMenu.InitLocalWindows))] [HarmonyPostfix] public static void InitWindows(CustomLevelMenu __instance) { TranslateLevelButtons(__instance); } + [HarmonyPatch(nameof(CustomLevelMenu.InitOnlineWindow))] + [HarmonyPostfix] + public static void InitOnlineWindow(CustomLevelMenu __instance) + { + TranslateLevelButtons(__instance); + } + [HarmonyPatch(nameof(CustomLevelMenu.ReloadFiles))] [HarmonyPostfix] public static void ReloadFiles(CustomLevelMenu __instance) @@ -52,33 +59,45 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor public static void TranslateLevelButtons(CustomLevelMenu __instance) { + string dumpPath = Path.Combine(FileLoader.GetAssetDir(FileLoader.AssetType.Dumps), "custom_level_data.json"); Dictionary dumpData = new Dictionary(); + if (!File.Exists(dumpPath)) + { + File.WriteAllText(dumpPath, System.Text.Json.JsonSerializer.Serialize(dumpData, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + } + foreach(CustomButton_enterGame level in __instance.levels) { - string levelId = level.levelData.levelId; - if(levelId != null) + if(level.onlineLevelInfo != null) { - if(translatedLevelData.ContainsKey(levelId)) + string levelId = level.onlineLevelInfo.levelId; + if(levelId != null) { - TranslatedLevelData levelData = translatedLevelData[levelId]; - level.levelName.text = levelData.name; - level.levelData.Name = levelData.name; - level.serializedLevel.boardConfig.startTip = levelData.startTip; - } - else - { - TranslatedLevelData dumpedLevelData = new TranslatedLevelData(level.levelData.Name, level.serializedLevel.boardConfig.startTip); - dumpData.Add(levelId, dumpedLevelData); + if(translatedLevelData.ContainsKey(levelId)) + { + TranslatedLevelData levelData = translatedLevelData[levelId]; + level.levelName.text = levelData.name; + level.serializedLevel.name = levelData.name; + level.serializedLevel.boardConfig.startTip = levelData.startTip; + } + else + { + TranslatedLevelData dumpedLevelData = new TranslatedLevelData(level.onlineLevelInfo.levelName, level.serializedLevel.boardConfig.startTip); + dumpData.Add(levelId, dumpedLevelData); + } } } else { - level.levelName.text = StringStore.TranslateText(level.levelData.Name); + level.levelName.text = StringStore.TranslateText(level.levelName.text); } } - string dumpPath = Path.Combine(FileLoader.GetAssetDir(FileLoader.AssetType.Dumps), "custom_level_data.json"); File.WriteAllText(dumpPath, System.Text.Json.JsonSerializer.Serialize(dumpData, new JsonSerializerOptions { WriteIndented = true, diff --git a/MelonLoader/Patches/Modes/Super Editor/CustomOnlineMenu_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/CustomOnlineMenu_Patch.cs index c01fd95..103d448 100644 --- a/MelonLoader/Patches/Modes/Super Editor/CustomOnlineMenu_Patch.cs +++ b/MelonLoader/Patches/Modes/Super Editor/CustomOnlineMenu_Patch.cs @@ -1,14 +1,17 @@ -using MelonLoader; -using HarmonyLib; -using UnityEngine; +using HarmonyLib; using Il2Cpp; +using Il2CppGameLevel; +using Il2CppTMPro; +using MelonLoader; +using PvZ_Fusion_Translator.AssetStore; using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; using System.Threading.Tasks; -using Il2CppTMPro; -using PvZ_Fusion_Translator.AssetStore; +using UnityEngine; namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor { @@ -34,6 +37,44 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor string translatedText = StringStore.TranslateText(__instance.title.text); __instance.title.text = translatedText; __instance.title2.text = translatedText; + + TranslateLevelData(__instance.levelData); + } + + public static void TranslateLevelData(CustomLevelData levelData) + { + Dictionary dumpData = new Dictionary(); + + if(levelData != null) + { + string levelId = levelData.levelId; + if(levelId != null) + { + if(CustomLevelMenu_Patch.translatedLevelData.ContainsKey(levelId)) + { + TranslatedLevelData translatedLevelData = CustomLevelMenu_Patch.translatedLevelData[levelId]; + levelData.Name = translatedLevelData.name; + levelData.SerializedLevelData.name = translatedLevelData.name; + levelData.SerializedLevelData.boardConfig.startTip = translatedLevelData.startTip; + } + else + { + TranslatedLevelData dumpedLevelData = new TranslatedLevelData(levelData.Name, levelData.SerializedLevelData.boardConfig.startTip); + dumpData.Add(levelId, dumpedLevelData); + } + } + } + else + { + levelData.Name = StringStore.TranslateText(levelData.Name); + } + + string dumpPath = Path.Combine(FileLoader.GetAssetDir(FileLoader.AssetType.Dumps), "custom_level_data.json"); + File.WriteAllText(dumpPath, System.Text.Json.JsonSerializer.Serialize(dumpData, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); } } } diff --git a/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeEventNodeEditor_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeEventNodeEditor_Patch.cs new file mode 100644 index 0000000..217e2c7 --- /dev/null +++ b/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeEventNodeEditor_Patch.cs @@ -0,0 +1,89 @@ +using Il2Cpp; +using Il2CppGameLevel; +using HarmonyLib; +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Il2CppGameLevel.EventNodes; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; + +namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel.EventNodes +{ + [HarmonyPatch(typeof(RuntimeEventNodeEditor))] + public static class RuntimeEventNodeEditor_Patch + { + [HarmonyPatch(nameof(RuntimeEventNodeEditor.AddNode))] + [HarmonyPostfix] + public static void AddNode(RuntimeEventNodeEditor __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + + foreach(var nodeUI in __instance.nodeUIs) + { + string nodeName = nodeUI.key; + RuntimeNodeUI node = nodeUI.Value; + + foreach(TextMeshProUGUI txt in node.GetComponentsInChildren()) + { + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + txt.font = fontAsset; + } + } + } + + [HarmonyPatch(nameof(RuntimeEventNodeEditor.Update))] + [HarmonyPostfix] + public static void Update(RuntimeEventNodeEditor __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + + foreach(var node in __instance.nodeUIs) + { + RuntimeNodeUI nodeUI = node.value; + + if(nodeUI.Node.nodeType == "PlantTypeValueNode") + { + Transform buttonTransform = nodeUI.transform.Find("Header/ValueEditContainer/Button(Clone)/Label"); + TextMeshProUGUI txt = buttonTransform.GetComponent(); + + if (!txt.gameObject.name.Contains("Label")) continue; + if (!Utils.CheckForUntranslatedText(txt.text)) continue; + + string plantName = Utils.GetPlantNameFromAlmanac(nodeUI.Node.GetPortValue(nodeUI.Node.GetOutputPorts()[0].portName, PlantType.Nothing)); + txt.text = (plantName != "") ? plantName : StringStore.TranslateText(txt.text); + txt.font = fontAsset; + } + else if(nodeUI.Node.nodeType == "ZombieTypeValueNode") + { + Transform buttonTransform = nodeUI.transform.Find("Header/ValueEditContainer/Button(Clone)/Label"); + TextMeshProUGUI txt = buttonTransform.GetComponent(); + + if (!txt.gameObject.name.Contains("Label")) continue; + if (!Utils.CheckForUntranslatedText(txt.text)) continue; + + string zombieName = Utils.GetZombieNameFromAlmanac(nodeUI.Node.GetPortValue(nodeUI.Node.GetOutputPorts()[0].portName, ZombieType.Nothing)); + txt.text = (zombieName != "") ? zombieName : StringStore.TranslateText(txt.text); + txt.font = fontAsset; + } + else if(nodeUI.Node.nodeType == "PlantTypeListStorageNode") + { + Transform dropdownTransform = nodeUI.transform.Find("Header/ValueEditContainer/Dropdown(Clone)"); + + if (!dropdownTransform) continue; + + foreach(TextMeshProUGUI txt in dropdownTransform.GetComponentsInChildren()) + { + if (!Utils.CheckForUntranslatedText(txt.text)) continue; + + txt.text = StringStore.TranslateText(txt.text); + txt.font = fontAsset; + } + } + } + } + } +} diff --git a/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeNodeUI_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeNodeUI_Patch.cs new file mode 100644 index 0000000..f197ac5 --- /dev/null +++ b/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeNodeUI_Patch.cs @@ -0,0 +1,112 @@ +using Il2Cpp; +using Il2CppGameLevel; +using HarmonyLib; +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Il2CppGameLevel.EventNodes; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; +using PvZ_Fusion_Translator.Patches.BaseTextObjects; + +namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel.EventNodes +{ + [HarmonyPatch(typeof(RuntimeNodeUI))] + public static class RuntimeNodeUI_Patch + { + [HarmonyPatch(nameof(RuntimeNodeUI.Awake))] + [HarmonyPatch(nameof(RuntimeNodeUI.Initialize))] + [HarmonyPatch(nameof(RuntimeNodeUI.CreatePorts))] + [HarmonyPatch(nameof(RuntimeNodeUI.CreateTravelEntryEditUI), argumentTypes: [typeof(RectTransform), typeof(GetTravelEntryNode)])] + [HarmonyPatch(nameof(RuntimeNodeUI.CreateStringInputField))] + [HarmonyPatch(nameof(RuntimeNodeUI.CreatePorts))] + [HarmonyPostfix] + public static void Awake(RuntimeNodeUI __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + + if(__instance.dropdownPrefab) + { + if(__instance.dropdownPrefab.TryGetComponent(out TMP_Dropdown dropdown)) + { + TMP_Dropdown_Patch.CreateDropdownList(dropdown); + } + } + + if(__instance.valueInputField) + { + TMP_InputField_Patch.OnEnable(__instance.valueInputField); + foreach(TextMeshProUGUI txt in __instance.valueInputField.GetComponentsInChildren(true)) + { + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + } + } + + foreach(TextMeshProUGUI txt in __instance.GetComponentsInChildren()) + { + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + txt.font = fontAsset; + } + } + + [HarmonyPatch(nameof(RuntimeNodeUI.UpdateDisplay))] + [HarmonyPostfix] + public static void UpdateDisplay(RuntimeNodeUI __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + + if(__instance.Node.nodeType == "PlantTypeValueNode") + { + foreach(TextMeshProUGUI txt in __instance.GetComponentsInChildren()) + { + if(txt.gameObject.name.Contains("Label")) + { + string plantName = Utils.GetPlantNameFromAlmanac(__instance.Node.GetPortValue(__instance.Node.nodeName, PlantType.Nothing)); + txt.text = (plantName != "") ? plantName : StringStore.TranslateText(txt.text); + txt.font = fontAsset; + } + } + } + + if(__instance.Node.nodeType == "ZombieTypeValueNode") + { + foreach(TextMeshProUGUI txt in __instance.GetComponentsInChildren()) + { + if(txt.gameObject.name.Contains("Label")) + { + string zombieName = Utils.GetZombieNameFromAlmanac(__instance.Node.GetPortValue(__instance.Node.nodeName, ZombieType.Nothing)); + txt.text = (zombieName != "") ? zombieName : StringStore.TranslateText(txt.text); + txt.font = fontAsset; + } + } + } + + if(__instance.dropdownPrefab) + { + if(__instance.dropdownPrefab.TryGetComponent(out TMP_Dropdown dropdown)) + { + TMP_Dropdown_Patch.CreateDropdownList(dropdown); + } + } + + if(__instance.valueInputField) + { + TMP_InputField_Patch.OnEnable(__instance.valueInputField); + foreach(TextMeshProUGUI txt in __instance.valueInputField.GetComponentsInChildren(true)) + { + txt.text = StringStore.translationString.ContainsKey(txt.text + "_code") ? StringStore.TranslateText(txt.text + "_code") : StringStore.TranslateText(txt.text); + } + } + } + + [HarmonyPatch(nameof(RuntimeNodeUI.UpdateSelectionVisual))] + [HarmonyPostfix] + public static void UpdateSelectionVisual(RuntimeNodeUI __instance) + { + UpdateDisplay(__instance); + } + } +} diff --git a/MelonLoader/Patches/Modes/Super Editor/GameLevel/LevelManager_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/GameLevel/LevelManager_Patch.cs new file mode 100644 index 0000000..5c620ad --- /dev/null +++ b/MelonLoader/Patches/Modes/Super Editor/GameLevel/LevelManager_Patch.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using Il2Cpp; +using Il2CppGameLevel; +using PvZ_Fusion_Translator.AssetStore; +using UnityEngine; + +namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel +{ + [HarmonyPatch(typeof(LevelManager))] + public static class LevelManager_Patch + { + [HarmonyPatch(nameof(LevelManager.SaveLevelData))] + [HarmonyPrefix] + public static void Pre_SaveLevelData(LevelManager __instance, ref SerializedLevelData serializedLevelData) + { + if(serializedLevelData.name == "未命名关卡") + { + serializedLevelData.name = StringStore.translationString.ContainsKey("LEVEL_UNNAMED") ? StringStore.TranslateText("LEVEL_UNNAMED") : "Unnamed"; + } + } + } +} diff --git a/MelonLoader/Patches/Modes/Super Editor/RhythmGame/RhythmGameChartEditorUI_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/RhythmGame/RhythmGameChartEditorUI_Patch.cs new file mode 100644 index 0000000..1cd3db6 --- /dev/null +++ b/MelonLoader/Patches/Modes/Super Editor/RhythmGame/RhythmGameChartEditorUI_Patch.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Il2Cpp; +using Il2CppRhythmGameEditor; +using Il2CppRhythmGame; +using HarmonyLib; +using UnityEngine; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; + +namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.RhythmGameEditor +{ + [HarmonyPatch(typeof(RhythmGameChartEditorUI))] + public static class RhythmGameChartEditorUI_Patch + { + [HarmonyPatch(nameof(RhythmGameChartEditorUI.Awake))] + [HarmonyPostfix] + public static void Awake(RhythmGameChartEditorUI __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + foreach(TextMeshProUGUI txt in __instance.GetComponentsInChildren()) + { + txt.font = fontAsset; + if (!Utils.CheckForUntranslatedText(txt.text)) continue; + txt.text = StringStore.TranslateText(txt.text); + } + + foreach(TextMeshProUGUI txt in __instance.dropdown.GetComponentsInChildren(true)) + { + txt.text = StringStore.TranslateText(txt.text); + } + } + + [HarmonyPatch(nameof(RhythmGameChartEditorUI.Start))] + [HarmonyPostfix] + public static void Start(RhythmGameChartEditorUI __instance) + { + Awake(__instance); + } + + [HarmonyPatch(nameof(RhythmGameChartEditorUI.InitializeSubSystems))] + [HarmonyPostfix] + public static void InitializeSubSystems(RhythmGameChartEditorUI __instance) + { + Awake(__instance); + } + + [HarmonyPatch(nameof(RhythmGameChartEditorUI.Update))] + [HarmonyPostfix] + public static void Update(RhythmGameChartEditorUI __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + foreach(TextMeshProUGUI txt in __instance.transform.Find("TopPanel").GetComponentsInChildren()) + { + txt.font = fontAsset; + txt.text = StringStore.TranslateText(txt.text); + } + + foreach(TheButton btn in __instance.transform.GetComponentsInChildren()) + { + foreach(TextMeshProUGUI txt in btn.GetComponentsInChildren()) + { + if (!Utils.CheckForUntranslatedText(txt.text)) continue; + txt.text = StringStore.TranslateText(txt.text); + } + } + + foreach(TextMeshProUGUI txt in __instance.dropdown.GetComponentsInChildren(true)) + { + if (!Utils.CheckForUntranslatedText(txt.text)) continue; + txt.text = Utils.RemoveSizeTags(StringStore.TranslateText(txt.text)); + } + } + + [HarmonyPatch(nameof(RhythmGameChartEditorUI.UpdateUI))] + [HarmonyPostfix] + public static void UpdateUI(RhythmGameChartEditorUI __instance) + { + foreach(TextMeshProUGUI txt in __instance.dropdown.GetComponentsInChildren(true)) + { + txt.text = StringStore.TranslateText(txt.text); + } + } + + [HarmonyPatch(nameof(RhythmGameChartEditorUI.UpdateSelectedNoteInfo))] + [HarmonyPostfix] + public static void UpdateSelectedNoteInfo(RhythmGameChartEditorUI __instance) + { + __instance.selectedNoteInfoText.text = StringStore.TranslateText(__instance.selectedNoteInfoText.text); + } + } +} diff --git a/MelonLoader/Patches/Modes/Super Editor/RhythmGame/RhythmGameManager_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/RhythmGame/RhythmGameManager_Patch.cs new file mode 100644 index 0000000..e9e3eff --- /dev/null +++ b/MelonLoader/Patches/Modes/Super Editor/RhythmGame/RhythmGameManager_Patch.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using Il2Cpp; +using Il2CppRhythmGame; +using Il2CppTMPro; +using PvZ_Fusion_Translator.AssetStore; +using UnityEngine; + +namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.RhythmGameEditor +{ + [HarmonyPatch(typeof(RhythmGameManager))] + public static class RhythmGameManager_Patch + { + [HarmonyPatch(nameof(RhythmGameManager.Awake))] + [HarmonyPatch(nameof(RhythmGameManager.ComboUpdate))] + [HarmonyPostfix] + public static void Awake(RhythmGameManager __instance) + { + if(__instance.comboText) + { + __instance.comboText.autoSizeTextContainer = false; + __instance.comboText.ForceMeshUpdate(); + } + } + + [HarmonyPatch(nameof(RhythmGameManager.OnNoteClicked))] + [HarmonyPostfix] + public static void OnNoteClicked(RhythmGameManager __instance) + { + if (!__instance.particle) return; + + TextParticle txtParticle = __instance.particle.GetComponent(); + if(txtParticle) + { + TextMeshPro txt = txtParticle.text.GetComponent(); + + if(txt) + { + string originalKey = StringStore.translationString.FirstOrDefault(x => x.Value == txt.text).Key; + txt.text = StringStore.translationString.ContainsKey(originalKey + "_RG") ? StringStore.TranslateText(originalKey + "_RG") : StringStore.TranslateText(txt.text); + txt.autoSizeTextContainer = false; + txt.ForceMeshUpdate(); + } + } + } + } +} diff --git a/MelonLoader/Patches/OtherManagers/AchievementClip_Patch.cs b/MelonLoader/Patches/OtherManagers/AchievementClip_Patch.cs index 2d2fdfd..3b295f4 100644 --- a/MelonLoader/Patches/OtherManagers/AchievementClip_Patch.cs +++ b/MelonLoader/Patches/OtherManagers/AchievementClip_Patch.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +/*using HarmonyLib; using Il2Cpp; using Il2CppTMPro; using Newtonsoft.Json; @@ -68,3 +68,4 @@ namespace PvZ_Fusion_Translator.Patches.OtherManagers } } } +*/ \ No newline at end of file diff --git a/MelonLoader/Patches/OtherManagers/GardenUI_Patch.cs b/MelonLoader/Patches/OtherManagers/GardenUI_Patch.cs index 1e4f3df..6219f62 100644 --- a/MelonLoader/Patches/OtherManagers/GardenUI_Patch.cs +++ b/MelonLoader/Patches/OtherManagers/GardenUI_Patch.cs @@ -2,6 +2,7 @@ using Il2Cpp; using PvZ_Fusion_Translator.AssetStore; using UnityEngine; +using Il2CppZenGarden; namespace PvZ_Fusion_Translator.Patches.OtherManagers { @@ -13,7 +14,6 @@ namespace PvZ_Fusion_Translator.Patches.OtherManagers public static void Update(GardenUI __instance) { __instance.currentPageText = StringStore.TranslateText(__instance.currentPageText, false); - __instance.currentPageText2 = StringStore.TranslateText(__instance.currentPageText2, false); // Transform PageText = __instance.transform.Find("PageText"); // StringStore.TranslateTextTransform(PageText.transform); diff --git a/MelonLoader/PvZ Fusion Translator [MelonLoader].csproj b/MelonLoader/PvZ Fusion Translator [MelonLoader].csproj index 677f8f2..feb9955 100644 --- a/MelonLoader/PvZ Fusion Translator [MelonLoader].csproj +++ b/MelonLoader/PvZ Fusion Translator [MelonLoader].csproj @@ -1,4 +1,4 @@ - + net6.0 enable @@ -33,6 +33,7 @@ + @@ -392,6 +393,7 @@ + @@ -402,8 +404,13 @@ + + + + + @@ -411,6 +418,8 @@ + + @@ -430,7 +439,7 @@ - + @@ -507,11 +516,17 @@ + + + + + + @@ -551,6 +566,10 @@ + + + + @@ -559,5 +578,6 @@ + \ No newline at end of file diff --git a/MelonLoader/Resources/ModUpdateUtil.exe b/MelonLoader/Resources/ModUpdateUtil.exe new file mode 100644 index 0000000..fa4a746 Binary files /dev/null and b/MelonLoader/Resources/ModUpdateUtil.exe differ diff --git a/MelonLoader/Utils.cs b/MelonLoader/Utils.cs index 648005c..8e61ec0 100644 --- a/MelonLoader/Utils.cs +++ b/MelonLoader/Utils.cs @@ -16,7 +16,6 @@ using UnityEngine; using UnityEngine.Events; using UnityEngine.Experimental.Rendering; using UnityEngine.UI; -using static Il2Cpp.AlmanacPlantBank; using static MelonLoader.MelonLogger; using static PvZ_Fusion_Translator.FileLoader; @@ -28,11 +27,11 @@ namespace PvZ_Fusion_Translator { if (ogTexture != null) { - if (TextureStore.textureDict.TryGetValue(ogTexture.name, out string texturePath)) + if (TextureStore.textureDict.TryGetValue(ogTexture.name, out byte[] textureData)) { try { - ImageConversion.LoadImage(ogTexture, File.ReadAllBytes(texturePath)); + ImageConversion.LoadImage(ogTexture, textureData); Log.LogDebug("OK! Replaced Texture " + ogTexture.name); @@ -41,7 +40,7 @@ namespace PvZ_Fusion_Translator } catch (Exception ex) { - Log.LogError("Failed to replace texture: " + ogTexture.name + " at path: " + texturePath); + Log.LogError("Failed to replace texture: " + ogTexture.name); Log.LogError(ex.ToString()); } } @@ -62,6 +61,19 @@ namespace PvZ_Fusion_Translator return texture2D; } + internal static Texture2D LoadImage(byte[] bytes) + { + if (bytes == null) + { + throw new FileNotFoundException($"Byte array was null."); + } + + byte[] array = bytes; + Texture2D texture2D = new(2, 2, GraphicsFormat.R8G8B8A8_UNorm, TextureCreationFlags.None, 1, IntPtr.Zero, null); + ImageConversion.LoadImage(texture2D, array); + return texture2D; + } + public static Color HexToColor(string hex) { @@ -80,9 +92,9 @@ namespace PvZ_Fusion_Translator Process.Start("explorer.exe", saveDirectory); } - public static void OpenTrello() + public static void OpenOnlineAlmanac() { - string website = "https://trello.com/b/DcdT1kUp"; + string website = "https://carroti4ch.itch.io/almanac"; Process.Start(new ProcessStartInfo(website) { UseShellExecute = true }); } @@ -140,76 +152,48 @@ namespace PvZ_Fusion_Translator newGoBackText.color = color; } - public static string GetPlantNameFromAlmanac(PlantType thePlantType) + public static string GetPlantNameFromAlmanac(PlantType thePlantType, bool log = false) { - string json; - string thePlantName = ""; + bool foundPlantName = false; + string thePlantName = ""; - json = AlmanacPlantMenu_Patch.almanacJson; - AlmanacPlantBank.PlantData plantData = JsonUtility.FromJson(json); + if(plantIndices.ContainsKey((int)thePlantType)) + { + foundPlantName = true; + thePlantName = plantIndices[(int)thePlantType].Value; + } - foreach (AlmanacPlantBank.PlantInfo plantInfo in plantData.plants) + if (!foundPlantName) { - if (plantInfo.seedType == (int)thePlantType) - { - thePlantName = plantInfo.name; - } + if(log) + { + Log.LogInfo("Couldn't find plant name!"); + } + thePlantName = ""; } - return thePlantName; + return thePlantName; } public static string GetPlantNameFromAlmanac(string theOriginalPlantName, bool log = false) { - string originalJson; - string translatedJson; - string thePlantName = ""; + bool foundPlantName = false; + string thePlantName = ""; - string currentLanguage = Utils.Language.ToString(); - string almanacDir = GetAssetDir(AssetType.Almanac, Utils.Language); - string dumpDir = GetAssetDir(AssetType.Dumps); - string originalPath = Path.Combine(dumpDir, "LawnStrings.json"); - string path = Path.Combine(almanacDir, "LawnStringsTranslate.json"); + if(plantIndiceStrings.ContainsKey(theOriginalPlantName)) + { + foundPlantName = true; + thePlantName = plantIndiceStrings[theOriginalPlantName]; + } - if ((!File.Exists(originalPath))) + if (!foundPlantName) { if(log) { - Log.LogError($"LawnStringsTranslate.json file not found at path: {path}"); - Log.LogError("Plant name could not be found!"); + Log.LogInfo("Couldn't find plant name!"); } thePlantName = ""; } - else - { - bool foundPlantName = false; - - originalJson = File.ReadAllText(originalPath); - translatedJson = AlmanacPlantMenu_Patch.almanacJson; - AlmanacPlantBank.PlantData originalPlantData = JsonUtility.FromJson(originalJson); - AlmanacPlantBank.PlantData translatedPlantData = JsonUtility.FromJson(translatedJson); - - for(int i = 0; i < originalPlantData.plants.Count; i++) - { - AlmanacPlantBank.PlantInfo originalPlantInfo = originalPlantData.plants[i]; - KeyValuePair translatedPlantInfo = plantIndices[originalPlantInfo.seedType]; - - if (originalPlantInfo.name == theOriginalPlantName) - { - thePlantName = translatedPlantInfo.Value; - foundPlantName = true; - } - } - - if (!foundPlantName) - { - if(log) - { - Log.LogInfo("Couldn't find plant name!"); - } - thePlantName = ""; - } - } return thePlantName; } @@ -222,9 +206,9 @@ namespace PvZ_Fusion_Translator string currentLanguage = Utils.Language.ToString(); json = AlmanacZombieMenu_Patch.almanacJson; - ZombieAlmanacData zombieData = JsonUtility.FromJson(json); + Il2CppAlmanacData.AlmanacData zombieData = JsonUtility.FromJson(json); - foreach (ZombieInfo zombieInfo in zombieData.zombies) + foreach (Il2CppAlmanacData.ZombieInfo zombieInfo in zombieData.zombies) { if ((int)zombieInfo.theZombieType == (int)theZombieType) { @@ -236,10 +220,12 @@ namespace PvZ_Fusion_Translator } public static Dictionary> plantIndices = new Dictionary>(); + public static Dictionary plantIndiceStrings = new Dictionary(); public static void RegisterPlantIndices() { plantIndices = new Dictionary>(); + plantIndiceStrings = new Dictionary(); string originalJson; string translatedJson; @@ -257,15 +243,19 @@ namespace PvZ_Fusion_Translator { originalJson = File.ReadAllText(originalPath); translatedJson = AlmanacPlantMenu_Patch.almanacJson; - AlmanacPlantBank.PlantData originalPlantData = JsonUtility.FromJson(originalJson); - AlmanacPlantBank.PlantData translatedPlantData = JsonUtility.FromJson(translatedJson); + Il2CppAlmanacData.AlmanacData originalPlantData = JsonUtility.FromJson(originalJson); + Il2CppAlmanacData.AlmanacData translatedPlantData = JsonUtility.FromJson(translatedJson); for (int i = 0; i < originalPlantData.plants.Count; i++) { - PlantInfo originalPlantInfo = originalPlantData.plants[i]; - PlantInfo translatedPlantInfo = null; + Il2CppAlmanacData.PlantInfo originalPlantInfo = originalPlantData.plants[i]; + if(!plantIndiceStrings.ContainsKey(originalPlantInfo.name)) + { + plantIndiceStrings.Add(originalPlantInfo.name, originalPlantInfo.name); + } + Il2CppAlmanacData.PlantInfo translatedPlantInfo = null; - foreach (PlantInfo info in translatedPlantData.plants) + foreach (Il2CppAlmanacData.PlantInfo info in translatedPlantData.plants) { if (info.seedType == originalPlantInfo.seedType) { @@ -277,6 +267,7 @@ namespace PvZ_Fusion_Translator { KeyValuePair temp = new KeyValuePair(translatedPlantInfo.seedType, translatedPlantInfo.name); plantIndices.Add(originalPlantInfo.seedType, temp); + plantIndiceStrings[originalPlantInfo.name] = translatedPlantInfo.name; } } } @@ -362,7 +353,7 @@ namespace PvZ_Fusion_Translator { Utils.useLocal = (Utils.useLocal) ? false : true; MelonPreferences.SetEntryValue("PvZ_Fusion_Translator", "UseLocal", Utils.useLocal); - StringStore.Reload(); + ChangeLanguage(Utils.Language.ToString()); string sourceMsg = "" + (!(Utils.useLocal) ? "Translation Source:\nOnline" : "Translation Source:\nLocal"); OptLanguageBtn_Patch.FlashMessage(OptLanguageBtn_Patch.toggleSlots[2], sourceMsg, 0.1f, false); } @@ -373,7 +364,99 @@ namespace PvZ_Fusion_Translator { Log.LogInfo($"Attempting to read {url}"); } - var dataRequest = await new HttpClient().GetAsync(url); + HttpClient client = new HttpClient(); + try + { + var dataRequest = await client.GetAsync(url); + if(dataRequest.StatusCode == System.Net.HttpStatusCode.OK) + { + if (isLog) + { + Log.LogInfo($"Successfully loaded data from {url}!"); + } + + string content = await dataRequest.Content.ReadAsStringAsync(); + return content; + } + else + { + if (isLog) + { + Log.LogError($"Failed to load data from {url}! Falling back..."); + Log.LogError($"Status code: {dataRequest.StatusCode}"); + } + new CancellationTokenSource().Cancel(); + return null; + } + } + catch(Exception ex) + { + Log.LogError($"Failed to load data from {url}! Falling back..."); + Log.LogError(ex); + new CancellationTokenSource().Cancel(); + return null; + } + } + + public static async Task GetByteDataFromWeb(string url, bool isLog = true) + { + if (isLog) + { + Log.LogInfo($"Attempting to read {url}"); + } + HttpClient client = new HttpClient(); + try + { + var dataRequest = await client.GetAsync(url); + if (dataRequest.StatusCode == System.Net.HttpStatusCode.OK) + { + if (isLog) + { + Log.LogInfo($"Successfully loaded data from {url}!"); + } + + byte[] content = await dataRequest.Content.ReadAsByteArrayAsync(); + return content; + } + else + { + if (isLog) + { + Log.LogError($"Failed to load data from {url}! Falling back..."); + Log.LogError($"Status code: {dataRequest.StatusCode}"); + } + new CancellationTokenSource().Cancel(); + return null; + } + } + catch(Exception ex) + { + Log.LogError($"Failed to load data from {url}! Falling back..."); + Log.LogError(ex); + new CancellationTokenSource().Cancel(); + return null; + } + } + + public static async Task GetDataFromWebWithInput(string url, bool isLog = true) + { + if (isLog) + { + Log.LogInfo($"Attempting to read {url}"); + } + HttpClient client = new HttpClient(); + + using var request = new HttpRequestMessage() + { + Method = HttpMethod.Get, + RequestUri = new Uri(url) + }; + request.Headers.Add("Accept", "*/*"); + request.Headers.Add("Accept-Encoding", "gzip, deflate, br"); + request.Headers.Add("User-Agent", "TranslatorMod"); + + + var dataRequest = await client.SendAsync(request); if(dataRequest.StatusCode == System.Net.HttpStatusCode.OK) { if (isLog) @@ -396,6 +479,26 @@ namespace PvZ_Fusion_Translator } } + public static int CalculateGameVersion(string gameVersion) + { + int res = 0; + string[] gameVersionParts = gameVersion.Split('.'); + + int startingPower = (int)Math.Max(gameVersionParts.Length, 3); + for (int i = 0; i < startingPower; i++) + { + int factor = 0; + if (i < gameVersionParts.Length) + { + factor = int.Parse(gameVersionParts[i]); + } + int power = startingPower - i; + res += factor * (int)Math.Pow(10, power - 1); + } + + return res; + } + #if MULTI_LANGUAGE internal static void ChangeLanguage(string language) { @@ -437,7 +540,7 @@ namespace PvZ_Fusion_Translator Chinese_cn, French, //Italian, - //German, + German, Spanish, @@ -468,6 +571,7 @@ namespace PvZ_Fusion_Translator { LanguageEnum.English, "English"}, { LanguageEnum.Chinese_cn, "简体中文"}, { LanguageEnum.French, "Français"}, + { LanguageEnum.German, "Deutsch"}, { LanguageEnum.Spanish, "Español"}, { LanguageEnum.Vietnamese, "Tiếng Việt"}, { LanguageEnum.Japanese, "日本語"}, @@ -478,8 +582,8 @@ namespace PvZ_Fusion_Translator public static Dictionary ToggleNames = new Dictionary() { - { ToggleEnum.Textures, "Textures"}, - { ToggleEnum.Audio, "Audio"}, + { ToggleEnum.Textures, "Change Texture\nSource"}, + { ToggleEnum.Audio, "Change Audio\nSource"}, { ToggleEnum.SwapLocal, "Change Translation\nSource"} };