diff --git a/BepInEx/AssetStore/CheckSumStore.cs b/BepInEx/AssetStore/CheckSumStore.cs new file mode 100644 index 0000000..db01c11 --- /dev/null +++ b/BepInEx/AssetStore/CheckSumStore.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Text.Encodings.Web; +using System.Text.Json; +using static PvZ_Fusion_Translator__BepInEx_.FileLoader; + +namespace PvZ_Fusion_Translator__BepInEx_.AssetStore +{ + public static class CheckSumStore + { + private static Dictionary modifiedCheckSums = new Dictionary(); + + private static Dictionary checkSums = new Dictionary() + { + }; + + static string GetCheckSum(string filename) + { + using (var md5 = SHA256.Create()) + { + byte[] bytes = md5.ComputeHash(File.ReadAllBytes(filename)); + return Convert.ToBase64String(bytes); + } + } + + public static void SaveCheckSum() + { + string stringDir = GetAssetDir(AssetType.Dumps); + if (!Directory.Exists(stringDir)) + { + Directory.CreateDirectory(stringDir); + } + string checkSumString = JsonSerializer.Serialize(checkSums, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + File.WriteAllText(Path.Combine(stringDir, "MD5.json"), checkSumString); + } + + public static void SaveModifiedChecksum() + { + string stringDir = GetAssetDir(AssetType.Dumps); + if (!Directory.Exists(stringDir)) + { + Directory.CreateDirectory(stringDir); + } + string modifiedCheckSumString = JsonSerializer.Serialize(modifiedCheckSums, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + File.WriteAllText(Path.Combine(stringDir, "Modified_MD5.json"), modifiedCheckSumString); + } + + public static bool IsModified(string filepath) + { + string fileName = Path.GetFileNameWithoutExtension(filepath); + string directory = Path.GetDirectoryName(filepath); + string slicedFilePath = directory.Substring(directory.IndexOf("PvZ_Fusion_Translator\\") + "PvZ_Fusion_Translator\\".Length); + string slicedKey = Path.Combine(slicedFilePath, fileName); + + #if DEBUG + if (!checkSums.ContainsKey(slicedKey)) + { + checkSums.Add(slicedKey, GetCheckSum(filepath)); + SaveCheckSum(); + modifiedCheckSums.Add(slicedKey, GetCheckSum(filepath)); + SaveModifiedChecksum(); + } + else + { + if ((checkSums[slicedKey] != GetCheckSum(filepath))) + { + checkSums[slicedKey] = GetCheckSum(filepath); + modifiedCheckSums.Add(slicedKey, GetCheckSum(filepath)); + SaveModifiedChecksum(); + } + } + #elif RELEASE + if (!checkSums.ContainsKey(slicedKey) | (checkSums[slicedKey] != GetCheckSum(filepath))) + { + return true; + } + #endif + return false; + } + + #if MELON + public static void ConvertMD5Json() + { + string stringDir = GetAssetDir(AssetType.Dumps); + if (!Directory.Exists(stringDir)) + { + Directory.CreateDirectory(stringDir); + } + string checksumDumpPath = Path.Combine(stringDir, "MD5.json"); + string checksumConvertPath = Path.Combine(stringDir, "MD5Convert.txt"); + string json = File.ReadAllText(checksumDumpPath); + Dictionary dictionary = DeserializeObject>(json); + + using StreamWriter writer = new StreamWriter(checksumConvertPath); + foreach (var kvp in dictionary) + { + string checksumKey = kvp.Key.Replace("\\", "\\\\"); + writer.WriteLine($"{{ \"{kvp.Key}\" , \"{kvp.Value}\" }},"); + } + + Log.LogDebug($"MD5.json converted to MD5Convert.json at {checksumConvertPath}"); + } + #endif + } +} diff --git a/BepInEx/AssetStore/FontStore.cs b/BepInEx/AssetStore/FontStore.cs new file mode 100644 index 0000000..1788ede --- /dev/null +++ b/BepInEx/AssetStore/FontStore.cs @@ -0,0 +1,143 @@ +using PvZ_Fusion_Translator; +using System.Collections.Generic; +using System.IO; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.AssetStore +{ + public static class FontStore + { + internal static Dictionary fontAssetDict = []; + internal static Dictionary fontAssetDictSecondary = []; + + internal static void Init() + { + string fontsDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Fonts]"); + foreach (string file in Directory.GetFiles(fontsDir)) + { + string fileName = Path.GetFileNameWithoutExtension(file); + string fileExtension = Path.GetExtension(file); + + if (fileExtension == ".ttf" || fileExtension == ".otf") + { + if (!fileName.EndsWith("_Almanac") && !fileName.EndsWith("_Fallback")) + { + string fontPath = Path.Combine("PvZ_Fusion_Translator", "[Custom Fonts]", fileName + fileExtension); + + TMP_FontAsset fontAsset = FontHandler.LoadTMPFont(fontPath, true); + fontAsset.name = fileName; + fontAssetDict.Add(fileName, fontAsset); + + Log.LogInfo($"Font for language '{fileName}' loaded"); + } + } + } + InitFallback(); + } + + internal static void InitFallback() + { + string fontsDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Fonts]"); + foreach (string file in Directory.GetFiles(fontsDir)) + { + string fileName = Path.GetFileNameWithoutExtension(file); + string fileExtension = Path.GetExtension(file); + + if (fileExtension == ".ttf" || fileExtension == ".otf") + { + if (fileName.EndsWith("_Almanac") || fileName.EndsWith("_Fallback")) + { + string fallbackPath = Path.Combine("PvZ_Fusion_Translator", "[Custom Fonts]", fileName + fileExtension); + TMP_FontAsset fallbackFont = FontHandler.LoadTMPFont(fallbackPath, true); + fallbackFont.name = fileName; + + string fileNameLanguage = fileName.Replace("_Fallback", "").Replace("_Almanac", ""); + + if (fontAssetDictSecondary.ContainsKey(fileNameLanguage)) + { + if (fileName.EndsWith("_Fallback")) + { + fontAssetDictSecondary.Add(fileNameLanguage + "_Almanac", fontAssetDictSecondary[fileNameLanguage]); + fontAssetDictSecondary.Remove(fileNameLanguage); + } + else + { + fontAssetDictSecondary.Add(fileNameLanguage + "_Fallback", fontAssetDictSecondary[fileNameLanguage]); + fontAssetDictSecondary.Remove(fileNameLanguage); + } + fontAssetDictSecondary.Add(fileName, fallbackFont); + } + else + fontAssetDictSecondary.Add(fileNameLanguage, fallbackFont); + } + } + } + AddFallback(); + } + + public static void AddFallback() + { + foreach (var lang in fontAssetDict.Keys) + { + if (fontAssetDict[lang].fallbackFontAssetTable == null) + { + fontAssetDict[lang].fallbackFontAssetTable = new Il2CppSystem.Collections.Generic.List(); + } + + if (fontAssetDictSecondary.ContainsKey(lang)) + { + fontAssetDict[lang].fallbackFontAssetTable.Add(fontAssetDictSecondary[lang]); + Log.LogInfo("Fallback font for language '" + lang + "' added"); + continue; + } + if (fontAssetDictSecondary.ContainsKey(lang + "_Almanac")) + { + fontAssetDict[lang].fallbackFontAssetTable.Add(fontAssetDictSecondary[lang + "_Almanac"]); + Log.LogInfo("Fallback font for language '" + lang + "' added"); + continue; + } + if (fontAssetDictSecondary.ContainsKey(lang + "_Fallback")) + { + fontAssetDict[lang].fallbackFontAssetTable.Add(fontAssetDictSecondary[lang + "_Fallback"]); + Log.LogInfo("Fallback font for language '" + lang + "' added"); + continue; + } + } + } + public static TMP_FontAsset LoadTMPFont(string language) + { + if (fontAssetDict.TryGetValue(language, out TMP_FontAsset font)) + { + return font; + } + return fontAssetDict.GetValueOrDefault("English"); + } + public static TMP_FontAsset LoadTMPFontAlmanac(string language) + { + if (fontAssetDictSecondary.ContainsKey(language)) + { + if (fontAssetDictSecondary.TryGetValue(language, out TMP_FontAsset almanacAsset)) + { + return almanacAsset; + } + } + if (fontAssetDictSecondary.ContainsKey(language + "_Almanac")) + { + if (fontAssetDictSecondary.TryGetValue(language + "_Almanac", out TMP_FontAsset almanacAsset)) + { + return almanacAsset; + } + } + return fontAssetDict.GetValueOrDefault("English"); + } + + public static void Reload() + { + // Get the current language + string currentLanguage = Utils.Language.ToString(); + + // Load the font for the current language + _ = LoadTMPFont(currentLanguage); + } + } +} diff --git a/BepInEx/AssetStore/StringStore.cs b/BepInEx/AssetStore/StringStore.cs new file mode 100644 index 0000000..33726a5 --- /dev/null +++ b/BepInEx/AssetStore/StringStore.cs @@ -0,0 +1,327 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.AssetStore +{ + public static class StringStore + { + internal static Dictionary stringsDict = []; + public static Dictionary translationStringRegex = new() + { + {"Test", "Test" } + }; + + public static Dictionary translationString = new() + { + {"Test", "Test" } + }; + + public static Dictionary> patchesStore = new() + { + { "Difficulty", new Dictionary + { + { "English" , "Difficulty:" }, + { "French" , "Difficulté:" }, + { "Italian" , "Difficoltà:" }, + { "German" , "Schwierigkeit:" }, + { "Spanish" , "Dificultad:" }, + { "Portuguese" , "Dificuldade:" }, + { "Filipino" , "Ang Hirap:" }, + { "Vietnamese" , "Độ Khó:" }, + { "Indonesian" , "Kesulitan:" }, + { "Russian" , "Сложность:" }, + { "Japanese" , "困難:" }, + { "Korean", "난이도:" }, + { "Javanese" , "Kesulitan:" }, + // { "Ukrainian" , "Складність:" }, + // { "Slovak" , "Náročnosť:" }, + } + }, + { "Zombies", new Dictionary + { + { "English" , "Zombies:" }, + { "French" , "Les Zombies:" }, + { "Italian" , "Zombi:" }, + { "German" , "Zombies:" }, + { "Spanish" , "Zombis:" }, + { "Portuguese" , "Zumbis:" }, + { "Filipino" , "Mga Zombie:" }, + { "Vietnamese" , "Thây Ma:" }, + { "Indonesian" , "Zombi:" }, + { "Russian" , "Зомби:" }, + { "Japanese" , "ゾンビ:" }, + { "Korean", "좀비:" }, + { "Javanese" , "Mayit:" }, + // { "Ukrainian" , "Зомбі:" }, + // { "Slovak" , "Zombíci:"} + } + } + + }; + + internal static void Init() + { + FileLoader.LoadStrings(); + } + + internal static void Reload() + { + translationString.Clear(); + translationStringRegex.Clear(); + FileLoader.LoadStrings(); + } + + public static TextMeshPro TranslateText(TextMeshPro originalTMP, bool isLog = false) + { + string currentLanguage = Utils.Language.ToString(); + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); + + string translatedText = TranslateText(originalTMP.text); + originalTMP.font = fontAsset; + originalTMP.text = translatedText; + + return originalTMP; + } + + public static TextMeshProUGUI TranslateText(TextMeshProUGUI originalTMP, bool isLog = false) + { + string currentLanguage = Utils.Language.ToString(); + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); + + string translatedText = TranslateText(originalTMP.text); + originalTMP.font = fontAsset; + originalTMP.text = translatedText; + + return originalTMP; + } + + public static string TranslateText(string originalText, bool isLog = false) + { + string text = DoTranslateText(originalText, false); + string checkText; + #if DEBUG + Regex regex = new("\\p{IsCJKUnifiedIdeographs}+"); + Match match = regex.Match(text); + + if(match.Success) + { + // Log.LogDebug("Untranslated String: " + match.Value); + // FileLoader.DumpUntranslatedStrings(text); + } + #endif + checkText = text; + return checkText; + } + + public static string DoTranslateText(string originalText, bool isLog = false) + { + if (string.IsNullOrEmpty(originalText)) + { + if (isLog) + Log.LogError("Text Null or Empty"); + + return string.Empty; + } + + if (translationString.ContainsKey(originalText)) + { + if (isLog) + Log.LogDebug($"Text '{originalText} found in translationString"); + return translationString[originalText]; + } + + // Regex-based dynamic translation + foreach (var entry in translationStringRegex) + { + var regex = new Regex(entry.Key); + if (regex.IsMatch(originalText)) + { + // Extract dynamic parts from the original text + var match = regex.Match(originalText); + int groupCount = match.Groups.Count; + + if (isLog) + Log.LogDebug("Text found in translationStringRegex {0}: {1}", match, groupCount); + + // 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 = translationString.ContainsKey(groupValue) + ? translationString[groupValue] + : groupValue; + dynamicParts.Add(translatedValue); + } + + // Format the output string with dynamic parts + return string.Format(entry.Value, [.. dynamicParts]); + } + } + + if (isLog) + Log.LogDebug($"Text '{originalText}' not translated"); + return originalText; + } + + private static TextAlignmentOptions TextAnchorToTMPAlignment(TextAnchor anchor) + { + return anchor switch + { + TextAnchor.UpperLeft => TextAlignmentOptions.TopLeft, + TextAnchor.UpperCenter => TextAlignmentOptions.Top, + TextAnchor.UpperRight => TextAlignmentOptions.TopRight, + TextAnchor.MiddleLeft => TextAlignmentOptions.MidlineLeft, + TextAnchor.MiddleCenter => TextAlignmentOptions.Center, + TextAnchor.MiddleRight => TextAlignmentOptions.MidlineRight, + TextAnchor.LowerLeft => TextAlignmentOptions.BottomLeft, + TextAnchor.LowerCenter => TextAlignmentOptions.Bottom, + TextAnchor.LowerRight => TextAlignmentOptions.BottomRight, + _ => TextAlignmentOptions.Center + }; + } + + static TextMeshProUGUI ConvertToTextMeshPro(UnityEngine.UI.Text oldText, TMP_FontAsset fontAsset, bool isLog = false) + { + if (oldText == null) + { + Log.LogError("UnityEngine.UI.Text component is null."); + return null; + } + + if (fontAsset == null) + { + Log.LogError("TMP_FontAsset is null. Conversion cannot proceed."); + return null; + } + + GameObject textObject = oldText.gameObject; + + // Preserve text content and settings + string originalText = oldText.text; + originalText = TranslateText(originalText, isLog); + TextAnchor alignment = oldText.alignment; + Color color = oldText.color; + + // Remove old Text component + UnityEngine.Object.DestroyImmediate(oldText); + + // Add TextMeshProUGUI component + TextMeshProUGUI newTMP = textObject.AddComponent(); + if (newTMP == null) + { + Log.LogError($"Failed to add TextMeshProUGUI to object: {textObject.name}"); + return null; + } + + // Configure TextMeshProUGUI + newTMP.text = originalText; + newTMP.color = color; + newTMP.alignment = TextAnchorToTMPAlignment(alignment); + newTMP.font = fontAsset; + + return newTMP; + } + + public static void TranslateTextTransform(Transform baseTransform, bool isAutoTextContainer = false, bool isLog = false) + { + if (!baseTransform) return; + + string currentLanguage = Utils.Language.ToString(); + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); + + if (fontAsset == null) + { + Log.LogError($"Font for language '{currentLanguage}' not found. Translation aborted."); + return; + } + + // Local function for processing transforms + void ProcessTextTransform(Transform textTransform) + { + if (!textTransform) return; + + // Handle TextMeshPro components + TextMeshPro textTMP = textTransform.GetComponent(); + if (textTMP) + { + textTMP.text = TranslateText(textTMP.text, isLog); + textTMP.autoSizeTextContainer = isAutoTextContainer; + textTMP.font = fontAsset; + } + + TextMeshProUGUI textTMPUGUI = textTransform.GetComponent(); + if (textTMPUGUI) + { + textTMPUGUI.text = TranslateText(textTMPUGUI.text, isLog); + textTMPUGUI.enableAutoSizing = isAutoTextContainer; + textTMPUGUI.font = fontAsset; + } + + // Handle UnityEngine.UI.Text components + UnityEngine.UI.Text textUI = textTransform.GetComponent(); + if (textUI) + { + ConvertToTextMeshPro(textUI, fontAsset, isLog); + } + } + + // Process specific text paths + ProcessTextTransform(baseTransform.Find("text")); + ProcessTextTransform(baseTransform.Find("text1")); + + Transform shadowTransform = baseTransform.Find("text/shadow"); + if (shadowTransform) ProcessTextTransform(shadowTransform); + + shadowTransform = baseTransform.Find("text1/shadow"); + if (shadowTransform) ProcessTextTransform(shadowTransform); + } + + public static void TranslateTextUI(TextMeshPro textTMP, bool? isAutoTextContainer = null, bool isLog = false) + { + string currentLanguage = Utils.Language.ToString(); + if (textTMP) + { + textTMP.text = TranslateText(textTMP.text, isLog); + if (isAutoTextContainer!=null) textTMP.autoSizeTextContainer = isAutoTextContainer.Value; + textTMP.font = FontStore.LoadTMPFont(currentLanguage); + } + } + public static void TranslateTextUI(TextMeshProUGUI textTMP, bool? isAutoTextContainer = null, bool isLog = false) + { + string currentLanguage = Utils.Language.ToString(); + if (textTMP) + { + string origText = textTMP.text; + + textTMP.text = TranslateText(origText, isLog) == "" ? origText : TranslateText(origText, isLog); + if (isAutoTextContainer != null) textTMP.autoSizeTextContainer = isAutoTextContainer.Value; + if (origText != textTMP.text) + textTMP.font = FontStore.LoadTMPFont(currentLanguage); + } + } + + public static void TranslateTextUI(TMP_InputField TextInput) + { + string currentLanguage = Utils.Language.ToString(); + if (TextInput) + { + string oriText = TextInput.m_Text; + TextInput.m_Text = TranslateText(oriText); + TextInput.m_OriginalText = TranslateText(oriText); + TextInput.fontAsset = FontStore.LoadTMPFont(currentLanguage); + } + } + + public static void LogAll() + { + Log.LogInfo("Logging all StringStore entries."); + Log.LogInfo("Regex Entries: {0}", translationStringRegex.Count); + Log.LogInfo("String Entries: {0}", translationString.Count); + } + } +} diff --git a/BepInEx/AssetStore/TextureStore.cs b/BepInEx/AssetStore/TextureStore.cs new file mode 100644 index 0000000..c4b1fa0 --- /dev/null +++ b/BepInEx/AssetStore/TextureStore.cs @@ -0,0 +1,63 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.AssetStore +{ + public static class TextureStore + { + internal static Dictionary textureDict = []; + + internal static void Init() => FileLoader.LoadTextures(); + + internal static void Reload() + { + textureDict.Clear(); + RestoreTextures(); + FileLoader.LoadDefaultTextures(); + FileLoader.LoadTextures(); + } + + public static IEnumerator ReplaceTexturesCoroutine() + { + while (true) + { + ReplaceTextures(); + yield return new WaitForSeconds(0.5f); // Adjust this interval as needed + } + } + + public static void ReplaceTextures() + { + Texture2D[] textures = Resources.FindObjectsOfTypeAll(); + foreach (Texture2D texture in textures) + { + if (texture.name.StartsWith("replaced_")) + continue; + + Utils.TryReplaceTexture2D(texture); + } + } + + public static void RestoreTextures() + { + Texture2D[] textures = Resources.FindObjectsOfTypeAll(); + foreach (Texture2D texture in textures) + { + if (texture != null) + { + texture.name = texture.name.Replace("replaced_", ""); + } + } + } + + 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/BepInEx/AssetStore/WarningStore.cs b/BepInEx/AssetStore/WarningStore.cs new file mode 100644 index 0000000..3e1cdaa --- /dev/null +++ b/BepInEx/AssetStore/WarningStore.cs @@ -0,0 +1,154 @@ +using System.Collections.Generic; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.AssetStore +{ + public static class WarningStore + { + private static Dictionary warningMessages = new() + { + { "English", ("The only valid source of this translation is from this community:\n" + + "discord.gg/DPAC5ZVJ8T. If you got this anywhere else like \n" + + "Plants Hybrid and superhybrid.online, they stole it.\n" + + "Stray away from other sources as they may contain viruses.\n" + + "Please visit our community for future updates.", + "Okay! Got it.") }, + { "French", ("La seule source valide pour cette traduction provient de cette\n" + + "communauté :discord.gg/DPAC5ZVJ8T. Si vous l'avez obtenue \n" + + "ailleurs, comme Plants Hybrid ou superhybrid.online, ils l'ont volée.\n" + + "Évitez les autres sources, car elles peuvent contenir des virus.\n" + + "Veuillez visiter notre communauté pour les mises à jour futures.", + "D'accord !") }, + { "Italian", ("L'unica fonte valida di questa traduzione è questa community:\n" + + "discord.gg/DPAC5ZVJ8T. Se l'hai ottenuta altrove, come \n" + + "Plants Hybrid e superhybrid.online, l'hanno rubata.\n" + + "Evita altre fonti, potrebbero contenere virus.\n" + + "Visita la nostra community per aggiornamenti futuri.", + "Va bene! Ho capito.") }, + { "German", ("Die einzige gültige Quelle für diese Übersetzung stammt aus\n" + + "dieser Community: discord.gg/DPAC5ZVJ8T. Wenn Sie diese \n" + + "irgendwo anders gefunden haben, z. B. bei Plants Hybrid oder \n" + + "superhybrid.online, dann haben sie sie gestohlen.\n" + + "Meiden Sie andere Quellen, da diese Viren enthalten könnten.\n" + + "Bitte besuchen Sie unsere Community für zukünftige Updates.", + "Okay, verstanden!") }, + { "Spanish", ("La única fuente válida de esta traducción proviene de esta\n" + + "comunidad: discord.gg/DPAC5ZVJ8T. Si la obtuvo en cualquier\n" + + "otro lugar como Plants Hybrid o superhybrid.online, la robaron.\n" + + "Manténgase alejado de otras fuentes, ya que podrían contener virus.\n" + + "Por favor, visite nuestra comunidad para futuras actualizaciones.", + "¡Entendido!") }, + { "Portuguese", ("O lugar original e seguro dessa tradução vem daqui:\n" + + "discord.gg/DPAC5ZVJ8T. Se você baixou ela de qualquer \n" + + "lugar como Plants Hybrid ou superhybrid.online, eles\n" + + "roubaram. Evite baixar deles, pode conter vírus.\n" + + "Por favor, visite nossa comunidade para atualizações futuras.", + "Okay, entendido.") }, + { "Filipino", ("Ang tanging opisyal na source ng pagsasaling ito ay mula\n" + + "lamang dito: discord.gg/DPAC5ZVJ8T. Kung nakuha nmo ito kahit \n" + + "saan pa tulad ng Plants Hybrid at superhybrid.online, ito ay ninakaw. \n" + + "Lumayo sa ibang source dahil posibleng may kasamang virus.\n" + + "Paki-bisita ang aming komunidad para sa mga darating na update." , + "Naiintindihan!") }, + { "Vietnamese", ("Nguồn duy nhất hợp lệ của bản dịch này là từ cộng\n" + + "đồng này: discord.gg/DPAC5ZVJ8T. Nếu bạn nhận \n" + + "được nó ở bất cứ nơi nào khác như Plants Hybrid \n" + + "hoặc superhybrid.online, họ đã ăn cắp nó.\n" + + "Tránh xa các nguồn khác vì chúng có thể chứa \n" + + "virus. Hãy ghé thăm cộng đồng của chúng tôi để \n" + + "cập nhật trong tương lai.", + "Đồng ý!") }, + { "Indonesian", ("Satu-satunya sumber resmi dari terjemahan ini adalah \n" + + "komunitas kami: discord.gg/DPAC5ZVJ8T. Jika Anda \n" + + "mendapatkannya dari sumber lain seperti Plants Hybrid \n" + + "dan superhybrid.online, mereka mencurinya. \n" + + "Jauhi sumber lain karena mungkin ada virus.\n" + + "Silakan kunjungi komunitas kami untuk pembaruan berikutnya.", + "Oke! Mengerti.") }, + { "Russian", ("Единственный проверенный источник этого перевода —\n" + + "сообщество discord.gg/DPAC5ZVJ8T.\n" + + "Или же его замена https://t.me/nekoshkindom\n" + + "Если вы скачали этот мод где-либо ещё, возможно он содержит вирусы.\n" + + "Программист перевода: LancerX0.\n" + + "Переводчик: Nekosha.", "Хорошо!") }, + { "Japanese", ("この翻訳の唯一の有効なソースは、このコミュニティからです:\n" + + "discord.gg/DPAC5ZVJ8T.Plants Hybridやsuperhybrid.online、\n" + + "YoutubeのBlue Flyが作っているもの、他のどこかでこれを入手した場合、\n" + + "彼らはそれを盗んだことになります。ウイルスが含まれている可能性があるので、\n" + + "他のソースからは離れてください。今後のアップデートについては、\n私たちのコミュニティをご覧ください。", + "了解しました!") }, + { "Korean", ("이 번역은 Bloom(discord.gg/DPAC5ZVJ8T)에서만\n" + + "제공됩니다. Bloom 디스코드 이외의 다른서드 파티 사이트, \n" + + "예를 들어 Plants Hybrid 및 superhybrid.online, 또는\n" + + "유튜브 Blue Fly등에서 제공하는 파일은 무단으로 재배포된 것이며,\n" + + "이런 사이트들에는 바이러스가 포함되어 있을 가능성이 높습니다. \n향후 업데이트를 위해 저희 디스코드를 방문해 주세요.", + "확인") }, + { "Javanese" , ("Sumber mung sing sah kanggo terjemahan iki saka komunitas iki:\n" + + "discord.gg/DPAC5ZVJ8T. Yen sampeyan nemokake iki ing papan\n" + + "liya kaya Plants Hybrid lan superhybrid.online, iku dicolong.\n" + + "Aja nyedhaki sumber liya amarga bisa ngandhut virus. Mangga\n" + + "ngunjungi komunitas kita kanggo nganyari ing mangsa ngarep.", + "Oke! Ngertos.") }, + }; + + public static (string, string) GetWarningMessage(Utils.LanguageEnum language) + { + if (warningMessages.TryGetValue(language.ToString(), out var message)) + { + + return message; + } + else + { + return warningMessages["English"]; // Default to English if language code is not found + } + } + + public static void WarningLoad() + { + GameAPP.theGameStatus = -2; + GameObject gameObject = UnityEngine.Object.Instantiate(Resources.Load("UI/MainMenu/HelpMenu"), GameAPP.canvas.transform); + gameObject.name = "WarningMessage"; + TextMeshProUGUI warning = gameObject.transform.GetChild(0).GetChild(0).GetComponent(); + TextMeshProUGUI warningShadow = gameObject.transform.GetChild(0).GetChild(1).GetComponent(); + Transform button = gameObject.transform.GetChild(1); + warning.transform.position = new Vector3(0.7f, 0.4f, 0f); + warningShadow.transform.position = new Vector3(0.7f, 0.4f, 0f); + + var (warningMessage, okayButton) = WarningStore.GetWarningMessage(Utils.Language); + + warning.text = warningMessage; + warningShadow.text = warningMessage; + warning.font = FontStore.LoadTMPFont(Utils.Language.ToString()); + warningShadow.font = FontStore.LoadTMPFont(Utils.Language.ToString()); + + button.GetComponent().buttonNumber = 10; + button.GetChild(0).GetComponent().text = okayButton; + button.GetChild(0).GetComponent().font = FontStore.LoadTMPFont(Utils.Language.ToString()); + button.GetChild(1).GetComponent().text = okayButton; + gameObject.SetActive(false); + gameObject.SetActive(true); + } + + public static bool isWarningMessageLoaded = false; + + public static void WarningReload(Utils.LanguageEnum language) + { + // Log.LogInfo("Current Language is " + Utils.OldLanguage); + // Log.LogInfo("Changed Language to " + language); + + if (Utils.OldLanguage.ToString() == language.ToString() && Utils.OldLanguage.ToString() != "English") + { + return; + } + if (!isWarningMessageLoaded) + { + WarningLoad(); + isWarningMessageLoaded = true; + } + + return; + } + } +} diff --git a/BepInEx/Core.cs b/BepInEx/Core.cs new file mode 100644 index 0000000..30dedf4 --- /dev/null +++ b/BepInEx/Core.cs @@ -0,0 +1,125 @@ +using BepInEx; +using BepInEx.Configuration; +using BepInEx.Unity.IL2CPP; +using BepInEx.Unity.IL2CPP.Utils; +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; +using System.IO; +using System.Reflection; +using UnityEngine; + +[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)] +[BepInProcess("PlantsVsZombiesRH.exe")] +public class Core : BasePlugin +{ + public string modsDirectory => Path.Combine(Paths.PluginPath, "PvZ_Fusion_Translator"); + + private static DateTime dtStart; + private static DateTime? dtStartToast; + private static string toast_txt; + public static Core Instance { get; private set; } + public static MonoBehaviour MonoInstance { get; private set; } + + private Coroutine replaceTextureRoutine = null; + + public ConfigEntry configDefaultTextures; + public ConfigEntry configDefaultAudio; + public ConfigEntry configLanguage; + + public override void Load() + { + Instance = this; + MonoInstance = AddComponent(); + Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly()); + LoadConfig(); + + FileLoader.LoadLanguage(); + + // AudioStore.Init(); + TextureStore.Init(); + StringStore.Init(); + FontStore.Init(); + + InitCoroutine(); + } + + public override bool Unload() + { + if (replaceTextureRoutine != null) + { + MonoInstance.StopCoroutine(replaceTextureRoutine); + Log.LogDebug("Coroutine Stopped"); + } + FileLoader.SaveLanguage(); + + #if OBFUSCATE && !RELEASE + CheckSumStore.ConvertMD5Json(); + #endif + + return true; + } + public void InitCoroutine() + { + if (replaceTextureRoutine != null) return; + replaceTextureRoutine = MonoInstance.StartCoroutine(TextureStore.ReplaceTexturesCoroutine()); + Log.LogDebug("Coroutine Started"); + } + public static void ShowToast(string message) + { + toast_txt = message; + dtStartToast = DateTime.Now; + } + + public void Update() + { + #if DEBUG + ModFeatures.OnLateUpdate(); + #endif + + if (Input.GetKeyDown(KeyCode.Insert)) + { + Utils.OpenSaveDirectory(); + } + + if (Input.GetKeyDown(KeyCode.Delete)) + { + Utils.OpenTrello(); + } + } + + public void OnGUI() + { + #if DEBUG + if (dtStartToast != null) + { + GUI.Button(new Rect(10f, 10f, 200f, 20f), "\n" + toast_txt + "\n"); + TimeSpan? timeSpan = DateTime.Now - dtStartToast; + TimeSpan t = new TimeSpan(0, 0, 2); + if (timeSpan > t) + { + dtStartToast = null; + } + } + #endif + } + + private void LoadConfig() + { + string mainCategory = "PvZ_Fusion_Translator"; + configDefaultTextures = Config.Bind(new ConfigDefinition(mainCategory, "DefaultTextures"), false, new ConfigDescription("Use Default Textures + Translation Textures", new AcceptableValueList(true, false))); + configDefaultAudio = Config.Bind(new ConfigDefinition(mainCategory, "DefaultAudio"), false, new ConfigDescription("Use Default Audio", new AcceptableValueList(true, false))); + configLanguage = Config.Bind(new ConfigDefinition(mainCategory, "Language"), "English", new ConfigDescription("Load the Game in this Language", new AcceptableValueList("English", "French", "Italian", "German", "Spanish", "Portuguese", "Indonesian", "Vietnamese", "Javanese", "Russian", "Japanese", "Korean"))); + } +} + +public class UnityCoroutineHelper : MonoBehaviour +{ + public static UnityCoroutineHelper Instance { get; private set; } + + public void Awake() + { + Instance = this; + } +} \ No newline at end of file diff --git a/BepInEx/FileLoader.cs b/BepInEx/FileLoader.cs new file mode 100644 index 0000000..b3640cf --- /dev/null +++ b/BepInEx/FileLoader.cs @@ -0,0 +1,344 @@ +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using PvZ_Fusion_Translator__BepInEx_.Patches.OtherManagers; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Encodings.Web; +using System.Text.Json; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_ +{ + internal static class FileLoader + { + internal enum AssetType + { + Textures, + Strings, + Dumps, + Almanac, + } + + public static string GetAssetDir(AssetType assetType, Utils.LanguageEnum? language = null) + { + string languagePath = language.HasValue ? ("Localization" + Path.DirectorySeparatorChar + language.ToString()) : string.Empty; + return Path.Combine(Core.Instance.modsDirectory, languagePath, assetType.ToString()); + } + + internal static void LoadStrings() => LoadStrings(Utils.Language); + internal static void LoadStrings(Utils.LanguageEnum language) + { + string stringDir = GetAssetDir(AssetType.Strings, Utils.Language); + if (!Directory.Exists(stringDir)) + { + Directory.CreateDirectory(stringDir); + } + try + { + foreach (string filepath in Directory.EnumerateFiles(stringDir, "*.json", SearchOption.AllDirectories)) + { + + #if OBFUSCATE + if (CheckSumStore.IsModified(filepath)) + { + Log.LogError("File {0} was modified!" , filepath); + continue; + } + #endif + + string fileName = Path.GetFileNameWithoutExtension(filepath); + StringStore.stringsDict[fileName] = filepath; + #if DEBUG + Log.LogInfo("Loading File : " + filepath); + #endif + string jsonString = File.ReadAllText(filepath); + if (fileName.EndsWith("_strings")) + { + Dictionary dictionary = JsonSerializer.Deserialize>(jsonString); + foreach (var (key, value) in dictionary) + { + StringStore.translationString[key] = value; + } + } + else if (fileName.EndsWith("_regexs")) + { + Dictionary dictionary = JsonSerializer.Deserialize>(jsonString); + foreach (var (key, value) in dictionary) + { + StringStore.translationStringRegex[key] = value; + } + } + } + SaveStrings(); + #if DEBUG + DumpJson(); + #endif + } + catch (Exception e) + { + Log.LogError("Error loading string."); + Log.LogError(e.GetType() + " " + e.Message); + } + Log.LogInfo("Strings loaded successfully."); + } + + public static bool loadDefaultTextures = Core.Instance.configDefaultTextures.Value; + internal static void LoadTextures() + { + // Default or Custom Texturse -> English Textures -> Localized Textures + try + { + if (loadDefaultTextures == true) + { + LoadDefaultTextures(); + } + else + { + LoadCustomTextures(); + } + } + catch (Exception e) + { + Log.LogError("Error loading texture setting."); + Log.LogError($"{e.GetType()} {e.Message}"); + } + + if (Utils.Language != Utils.LanguageEnum.English) + { + LoadLocalizedTextures(Utils.LanguageEnum.English); + } + LoadLocalizedTextures(Utils.Language); + + Log.LogInfo("Textures loaded successfully."); + } + + internal static void LoadLocalizedTextures(Utils.LanguageEnum? language = null) + { + string textureDir = GetAssetDir(AssetType.Textures, language); + + if (!Directory.Exists(textureDir)) + { + Directory.CreateDirectory(textureDir); + } + try + { + foreach (string filepath in Directory.EnumerateFiles(textureDir, "*.png", SearchOption.AllDirectories)) + { + if (filepath.Contains("[Custom Textures]", StringComparison.OrdinalIgnoreCase) && loadDefaultTextures) + { + continue; + } + + #if OBFUSCATE + if (CheckSumStore.IsModified(filepath)) + { + Log.LogError("File {0} was modified!" , filepath); + continue; + } + #endif + + #if DEBUG + Log.LogDebug("Loading File : " + filepath); + #endif + + Texture2D texture2D = Utils.LoadImage(filepath); + TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath; + } + } + + catch (Exception e) + { + Log.LogError("Error loading Texture."); + Log.LogError(e.GetType() + " " + e.Message); + } + } + + internal static void LoadDefaultTextures() + { + string textureDefaultDir = Path.Combine(Core.Instance.modsDirectory, AssetType.Dumps.ToString(), "Default Textures [Do Not Remove]"); + if (!Directory.Exists(textureDefaultDir)) + { + Directory.CreateDirectory(textureDefaultDir); + } + try + { + foreach (string filepath in Directory.EnumerateFiles(textureDefaultDir, "*.png", SearchOption.AllDirectories)) + { + #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; + } + } + + catch (Exception e) + { + Log.LogError("Error loading Texture."); + Log.LogError(e.GetType() + " " + e.Message); + } + } + + internal static void LoadCustomTextures() + { + string texturePackDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Textures]"); + + if (!Directory.Exists(texturePackDir)) + { + Directory.CreateDirectory(texturePackDir); + } + try + { + 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 + + Texture2D texture2D = Utils.LoadImage(filepath); + TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath; + } + } + + catch (Exception e) + { + Log.LogError("Error loading Texture."); + Log.LogError(e.GetType() + " " + e.Message); + } + } + + internal static void SaveStrings() + { + string stringDir = GetAssetDir(AssetType.Strings, Utils.Language); + if (!Directory.Exists(stringDir)) + { + Directory.CreateDirectory(stringDir); + } + + string translationStringRegex = JsonSerializer.Serialize(StringStore.translationStringRegex, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + + File.WriteAllText(Path.Combine(stringDir, "translation_regexs.json"), translationStringRegex); + + string translationString = JsonSerializer.Serialize(StringStore.translationString, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + + File.WriteAllText(Path.Combine(stringDir, "translation_strings.json"), translationString); + } + + #if DEBUG + public static void DumpJson() + { + string dumpDir = GetAssetDir(AssetType.Dumps); + + if (!Directory.Exists(dumpDir)) + { + Directory.CreateDirectory(dumpDir); + } + string LawnStrings = Resources.Load("LawnStrings").text; + string ZombieStrings = Resources.Load("ZombieStrings").text; + File.WriteAllText(Path.Combine(dumpDir, "LawnStrings.json"), LawnStrings); + File.WriteAllText(Path.Combine(dumpDir, "ZombieStrings.json"), ZombieStrings); + + 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)); + } + File.WriteAllText(Path.Combine(dumpDir, "AchievementsText.json"), JsonSerializer.Serialize(achievementsList, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + } + #endif + + #if DEBUG && MELON + public static void DumpUntranslatedStrings(string text) + { + string dumpDir = GetAssetDir(AssetType.Dumps); + string jsonFile = Path.Combine(dumpDir, "UntranslatedStrings.json"); + + if (!Directory.Exists(dumpDir)) + { + Directory.CreateDirectory(dumpDir); + } + + if (!File.Exists(jsonFile)) + { + File.WriteAllText(jsonFile, "{}"); // Initialize empty JSON object + } + + string json = File.ReadAllText(jsonFile); + JObject untranslatedStrings = JObject.Parse(json); + + if (!untranslatedStrings.ContainsKey(text)) + { + untranslatedStrings[text] = text; + File.WriteAllText(jsonFile, untranslatedStrings.ToString()); + } + } + #endif + + internal static void LoadLanguage() + { + try + { + // Load the language preference as a string and parse it into the enum + string languageName = Core.Instance.configLanguage.Value; + if (Enum.TryParse(languageName, out Utils.LanguageEnum loadedLanguage)) + { + Utils.Language = loadedLanguage; + } + else + { + Log.LogWarning($"Invalid language '{languageName}' found in preferences. Falling back to English."); + Utils.Language = Utils.LanguageEnum.English; // Default fallback + } + Log.LogWarning($"Loaded language {languageName}"); + } + catch (Exception e) + { + Log.LogError("Error loading language setting."); + Log.LogError($"{e.GetType()} {e.Message}"); + } + Log.LogInfo($"Language has been loaded: {Utils.Language}"); + } + + internal static void SaveLanguage() + { + try + { + // Save the current language as a string + if (Core.Instance.Config.TryGetEntry("PvZ_Fusion_Translator", "Language", out var languageEntry)) + { + languageEntry.Value = Utils.Language.ToString(); + } + + // Ensure changes are written to the config file + // MelonPreferences.Save(); + } + catch (Exception e) + { + Log.LogError("Error saving language setting."); + Log.LogError($"{e.GetType()} {e.Message}"); + } + // Log.LogInfo($"Language has been saved: {Utils.Language}"); + } + } +} diff --git a/BepInEx/FontHandler.cs b/BepInEx/FontHandler.cs new file mode 100644 index 0000000..af30ac7 --- /dev/null +++ b/BepInEx/FontHandler.cs @@ -0,0 +1,45 @@ +using BepInEx; +using PvZ_Fusion_Translator__BepInEx_; +using System.IO; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator +{ + public static class FontHandler + { + public static Font LoadFont(this string pathFromModsFolder, bool throwException) + { + string fontFilePath = Path.Combine(Paths.PluginPath, pathFromModsFolder); + if (!File.Exists(fontFilePath)) + { + if (throwException) + Log.LogWarning($"Font not found at path: '{fontFilePath}'."); + return null; + } + + Font font = new Font(); + Font.Internal_CreateFontFromPath(font, fontFilePath); // Default size, adjust as needed + return font; + } + + public static TMP_FontAsset ConvertToTMP(this Font font) + { + TMP_FontAsset fontAsset = TMP_FontAsset.CreateFontAsset(font); + if (fontAsset == null) + { + Log.LogWarning($"Failed to create TMP_FontAsset from font '{font.name}'."); + return null; + } + return fontAsset; + } + + public static TMP_FontAsset LoadTMPFont(this string pathFromModsFolder, bool throwException) + { + Font font = pathFromModsFolder.LoadFont(throwException); + if (font == null) + return null; + return font.ConvertToTMP(); + } + } +} \ No newline at end of file diff --git a/BepInEx/Log.cs b/BepInEx/Log.cs new file mode 100644 index 0000000..b9407bf --- /dev/null +++ b/BepInEx/Log.cs @@ -0,0 +1,25 @@ +using BepInEx.Logging; + +namespace PvZ_Fusion_Translator__BepInEx_ +{ + internal static class Log + { + private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("PvZ_Fusion_Translator"); + + public static void LogDebug(object txt) => Logger.LogDebug(txt); + public static void LogDebug(string txt) => Logger.LogDebug(txt); + public static void LogDebug(string txt, params object[] args) => Logger.LogDebug(string.Format(txt, args)); + + public static void LogInfo(object txt) => Logger.LogInfo(txt); + public static void LogInfo(string txt) => Logger.LogInfo(txt); + public static void LogInfo(string txt, params object[] args) => Logger.LogInfo(string.Format(txt, args)); + + public static void LogWarning(object txt) => Logger.LogWarning(txt); + public static void LogWarning(string txt) => Logger.LogWarning(txt); + public static void LogWarning(string txt, params object[] args) => Logger.LogWarning(string.Format(txt, args)); + + public static void LogError(object txt) => Logger.LogError(txt); + public static void LogError(string txt) => Logger.LogError(txt); + public static void LogError(string txt, params object[] args) => Logger.LogError(string.Format(txt, args)); + } +} \ No newline at end of file diff --git a/BepInEx/ModFeatures.cs b/BepInEx/ModFeatures.cs new file mode 100644 index 0000000..12d47fc --- /dev/null +++ b/BepInEx/ModFeatures.cs @@ -0,0 +1,79 @@ +#if DEBUG +using System; +using System.Collections.Generic; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_ +{ + public static class ModFeatures + { + public enum ModType + { + ReloadStrings, + ReloadTextures, + } + + private class ModFeature + { + public string Name { get; private set; } + public ModType ModType { get; private set; } + public KeyCode KeyCode { get; private set; } + public bool IsActive { get; set; } + + public ModFeature(string name, ModType modType, KeyCode keyCode, bool defaultValue = false) + { + Name = name; + ModType = modType; + KeyCode = keyCode; + IsActive = defaultValue; + } + + public void ToggleFeature() + { + if (ModType == ModType.ReloadStrings) + { + StringStore.Reload(); + Core.ShowToast("Strings Reloaded!"); + return; + } + + if (ModType == ModType.ReloadTextures) + { + TextureStore.Reload(); + Core.ShowToast("Textures Reloaded!"); + return; + } + } + } + + private static readonly Dictionary featureLists = new() + { + { ModType.ReloadStrings, new ModFeature("Reload Strings", ModType.ReloadStrings, KeyCode.Home, true) }, + { ModType.ReloadTextures, new ModFeature("Reload Textures", ModType.ReloadTextures, KeyCode.End, true) }, + }; + + public static void ToggleFeature(ModType modType) + { + if (!featureLists.ContainsKey(modType)) + return; + + featureLists[modType].ToggleFeature(); + } + + public static void OnLateUpdate() + { + foreach (var feature in featureLists.Values) + { + if (feature.KeyCode != KeyCode.None && Enum.IsDefined(typeof(KeyCode), feature.KeyCode)) + { + if (Input.GetKeyDown(feature.KeyCode)) + { + feature.ToggleFeature(); + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/BepInEx/Patches/BaseTextObjects/InGameText_Patch.cs b/BepInEx/Patches/BaseTextObjects/InGameText_Patch.cs new file mode 100644 index 0000000..16d22cf --- /dev/null +++ b/BepInEx/Patches/BaseTextObjects/InGameText_Patch.cs @@ -0,0 +1,25 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects +{ + [HarmonyPatch(typeof(InGameText))] + public static class InGameText_Patch + { + [HarmonyPatch(nameof(InGameText.EnableText), new Type[] { typeof(string), typeof(float), typeof(bool) })] + [HarmonyPrefix] + private static void EnableText(InGameText __instance, ref string text) => text = StringStore.TranslateText(text, true); + + [HarmonyPatch(nameof(InGameText.EnableText), new Type[] { typeof(string), typeof(float), typeof(bool) })] + [HarmonyPostfix] + private static void EnableText(InGameText __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + + __instance.t.text = StringStore.TranslateText(__instance.t.text, true); + __instance.t.font = fontAsset; + } + } +} diff --git a/BepInEx/Patches/BaseTextObjects/TMP_InputField_Patch.cs b/BepInEx/Patches/BaseTextObjects/TMP_InputField_Patch.cs new file mode 100644 index 0000000..ff6f318 --- /dev/null +++ b/BepInEx/Patches/BaseTextObjects/TMP_InputField_Patch.cs @@ -0,0 +1,23 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects +{ + [HarmonyPatch(typeof(TMP_InputField))] + public static class TMP_InputField_Patch + { + [HarmonyPatch(nameof(TMP_InputField.OnEnable))] + [HarmonyPostfix] + private static void OnEnable(TMP_InputField __instance) + { + if (!string.IsNullOrEmpty(__instance.text)) + { + string text = StringStore.TranslateText(__instance.text); + __instance.m_Text = StringStore.TranslateText(text); + __instance.m_OriginalText = StringStore.TranslateText(text); + __instance.m_TextComponent.text = StringStore.TranslateText(text); + } + } + } +} diff --git a/BepInEx/Patches/BaseTextObjects/TextMeshProUGUI_Patch.cs b/BepInEx/Patches/BaseTextObjects/TextMeshProUGUI_Patch.cs new file mode 100644 index 0000000..c7f9d29 --- /dev/null +++ b/BepInEx/Patches/BaseTextObjects/TextMeshProUGUI_Patch.cs @@ -0,0 +1,77 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine.UI; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects +{ + [HarmonyPatch(typeof(TextMeshProUGUI))] + public static class TextMeshProUGUI_Patch + { + [HarmonyPatch(nameof(TextMeshProUGUI.OnEnable))] + [HarmonyPostfix] + private static void OnEnable(TextMeshProUGUI __instance) + { + if (!string.IsNullOrEmpty(__instance.text)) + { + __instance = StringStore.TranslateText(__instance); + __instance.autoSizeTextContainer = false; + + if (__instance.name.StartsWith("LevelName")) + { + __instance.text = __instance.text.Replace("\n", " "); + } + if ((__instance.transform.parent != null) && (__instance.transform.parent.name.StartsWith("Window"))) + { + __instance.fontSizeMin = 10; + __instance.fontSize = 12; + } + + // __instance.ForceMeshUpdate(); + } + } + + [HarmonyPatch(nameof(TextMeshProUGUI.Awake))] + [HarmonyPostfix] + private static void Awake(TextMeshProUGUI __instance) + { + if (!string.IsNullOrEmpty(__instance.text)) + { + __instance = StringStore.TranslateText(__instance); + __instance.autoSizeTextContainer = false; + + if (__instance.name.StartsWith("LevelName")) + { + __instance.text = __instance.text.Replace("\n", " "); + } + if ((__instance.transform.parent != null) && (__instance.transform.parent.name.StartsWith("Window"))) + { + __instance.fontSizeMin = 10; + __instance.fontSize = 12; + } + + if (__instance.text == "Полный Хаос" && __instance.transform.parent.parent.Find("Image").GetComponent().activeSprite.name == "Present") + { + __instance.text += "\nБесконечно"; + } + + // __instance.ForceMeshUpdate(); + } + } + } + [HarmonyPatch(typeof(TMP_SubMeshUI))] + public static class TMP_SubMeshUI_Patch + { + [HarmonyPatch(nameof(TMP_SubMeshUI.OnEnable))] + [HarmonyPostfix] + public static void OnEnable(TMP_SubMeshUI __instance) + { + if (!string.IsNullOrEmpty(__instance.textComponent.text)) + { + string text = StringStore.TranslateText(__instance.textComponent.text); + __instance.m_TextComponent.text = StringStore.TranslateText(text); + __instance.textComponent.text = StringStore.TranslateText(text); + } + } + } +} diff --git a/BepInEx/Patches/BaseTextObjects/TextMeshPro_Patch.cs b/BepInEx/Patches/BaseTextObjects/TextMeshPro_Patch.cs new file mode 100644 index 0000000..2620cf5 --- /dev/null +++ b/BepInEx/Patches/BaseTextObjects/TextMeshPro_Patch.cs @@ -0,0 +1,27 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects +{ + [HarmonyPatch(typeof(TextMeshPro))] + public static class TextMeshPro_Patch + { + [HarmonyPatch(nameof(TextMeshPro.OnEnable))] + [HarmonyPostfix] + private static void OnEnable(TextMeshPro __instance) + { + if (!string.IsNullOrEmpty(__instance.text)) + { + if (__instance.transform.parent.name.StartsWith("AlmanacHelp")) + { + __instance = StringStore.TranslateText(__instance); + __instance.autoSizeTextContainer = false; + return; + } + __instance = StringStore.TranslateText(__instance); + __instance.autoSizeTextContainer = true; + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/ButtonObjects/Advanture_Btn_Patch.cs b/BepInEx/Patches/GameObjects/ButtonObjects/Advanture_Btn_Patch.cs new file mode 100644 index 0000000..e0273cf --- /dev/null +++ b/BepInEx/Patches/GameObjects/ButtonObjects/Advanture_Btn_Patch.cs @@ -0,0 +1,102 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects +{ + [HarmonyPatch(typeof(Advanture_Btn))] + public static class Advanture_Btn_Patch + { + [HarmonyPatch(nameof(Advanture_Btn.Start))] + [HarmonyPostfix] + private static void Start(Advanture_Btn __instance) + { + StringStore.TranslateTextTransform(__instance.transform, true); + Transform parentTransform = __instance.transform.parent.transform; + if (__instance.name == "Goback") + { + Transform backgroundTransform = parentTransform.Find("Background"); + backgroundTransform.Find("Name").GetComponent().autoSizeTextContainer = true; + backgroundTransform.Find("Shadow").GetComponent().autoSizeTextContainer = true; + } + + Transform levelTransform = parentTransform.Find("Levels"); + if (levelTransform != null) + { + + StringStore.TranslateTextTransform(levelTransform.Find("Nextpage")); + StringStore.TranslateTextTransform(levelTransform.Find("LastPage")); + + Transform pageMiniGamesTransform = levelTransform.transform.Find("PageMiniGames"); + if (pageMiniGamesTransform != null) + { + StringStore.TranslateTextTransform(pageMiniGamesTransform.Find("BackToIndex")); + StringStore.TranslateTextTransform(pageMiniGamesTransform.Find("Nextpage")); + StringStore.TranslateTextTransform(pageMiniGamesTransform.Find("LastPage")); + } + + Transform pageUnlockChallengeTransform = levelTransform.transform.Find("PageUnlockChallenge"); + if (pageUnlockChallengeTransform != null) + { + StringStore.TranslateTextTransform(pageUnlockChallengeTransform.Find("BackToIndex")); + } + + Transform pageFlagChallengeTransform = levelTransform.transform.Find("PageFlagChallenge"); + if (pageFlagChallengeTransform != null) + { + StringStore.TranslateTextTransform(pageFlagChallengeTransform.Find("BackToIndex")); + } + + Transform pageTravelExperienceTransform = levelTransform.transform.Find("PageTravelExperience"); + if (pageTravelExperienceTransform != null) + { + StringStore.TranslateTextTransform(pageTravelExperienceTransform.Find("BackToIndex")); + } + + Transform pageGardenProtectionTransform = levelTransform.transform.Find("PageGardenProtection"); + if (pageGardenProtectionTransform != null) + { + StringStore.TranslateTextTransform(pageGardenProtectionTransform.Find("BackToIndex")); + } + + Transform pageNormalTravelTransform = levelTransform.transform.Find("PageNormalTravel"); + if (pageNormalTravelTransform != null) + { + StringStore.TranslateTextTransform(pageNormalTravelTransform.Find("BackToIndex")); + } + + Transform pageRandomLevelTransform = levelTransform.transform.Find("PageRandomLevel"); + if (pageRandomLevelTransform != null) + { + StringStore.TranslateTextTransform(pageRandomLevelTransform.Find("BackToIndex")); + } + + Transform pageUltimateExperienceTransform = levelTransform.transform.Find("PageUltimateExprience"); + if (pageUltimateExperienceTransform != null) + { + StringStore.TranslateTextTransform(pageUltimateExperienceTransform.Find("BackToIndex")); + } + + Transform pageAdvantureLevelTransform = levelTransform.transform.Find("PageAdvantureLevel"); + if (pageAdvantureLevelTransform != null) + { + StringStore.TranslateTextTransform(pageAdvantureLevelTransform.Find("BackToIndex")); + StringStore.TranslateTextTransform(pageAdvantureLevelTransform.Find("Nextpage")); + StringStore.TranslateTextTransform(pageAdvantureLevelTransform.Find("LastPage")); + } + + Transform pageScaryPotTransform = levelTransform.transform.Find("PageScaryPot"); + if (pageScaryPotTransform != null) + { + StringStore.TranslateTextTransform(pageScaryPotTransform.Find("BackToIndex")); + StringStore.TranslateTextTransform(pageScaryPotTransform.Find("Nextpage")); + StringStore.TranslateTextTransform(pageScaryPotTransform.Find("LastPage")); + } + } + + StringStore.TranslateTextTransform(parentTransform.Find("CameraSize")); + StringStore.TranslateTextTransform(parentTransform.Find("CanvasSize")); + } + } +} diff --git a/BepInEx/Patches/GameObjects/ButtonObjects/EveBtn_Patch.cs b/BepInEx/Patches/GameObjects/ButtonObjects/EveBtn_Patch.cs new file mode 100644 index 0000000..466ce64 --- /dev/null +++ b/BepInEx/Patches/GameObjects/ButtonObjects/EveBtn_Patch.cs @@ -0,0 +1,41 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects +{ + [HarmonyPatch(typeof(EveBtn))] + public static class EveBtn_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(EveBtn.OnMouseUp))] + private static void OnMouseUp(EveBtn __instance) + { + Transform sceneText = __instance.transform.FindChild("text"); + if(sceneText != null) + { + TextMeshProUGUI sceneTextTMP = sceneText.transform.GetComponent(); + if(sceneTextTMP != null) + { + sceneTextTMP.text = StringStore.TranslateText(sceneTextTMP.text); + } + } + Transform sceneTextShadow = sceneText.transform.FindChild("text2"); + if(sceneTextShadow != null) + { + TextMeshProUGUI sceneTextShadowTMP = sceneTextShadow.transform.GetComponent(); + if (sceneTextShadowTMP != null) + { + sceneTextShadowTMP.text = StringStore.TranslateText(sceneTextShadowTMP.text); + } + } + + if (__instance.name.Equals("Balanced")) + { + __instance.gameObject.SetActive(false); + __instance.gameObject.SetActive(true); + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/ButtonObjects/InGameBtn_Patch.cs b/BepInEx/Patches/GameObjects/ButtonObjects/InGameBtn_Patch.cs new file mode 100644 index 0000000..a8d8e65 --- /dev/null +++ b/BepInEx/Patches/GameObjects/ButtonObjects/InGameBtn_Patch.cs @@ -0,0 +1,34 @@ +using HarmonyLib; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects +{ + [HarmonyPatch(typeof(InGameBtn))] + public static class InGameBtn_Patch + { + [HarmonyPatch(nameof(InGameBtn.Update))] + [HarmonyPostfix] + private static void Update(InGameBtn __instance) + { + Transform sceneText = __instance.transform.FindChild("SceneText"); + if(sceneText != null) + { + TextMeshProUGUI sceneTextTMP = sceneText.transform.GetComponent(); + if(sceneTextTMP != null) + { + sceneTextTMP = AssetStore.StringStore.TranslateText(sceneTextTMP); + } + Transform sceneTextShadow = sceneText.transform.FindChild("SceneText"); + if(sceneTextShadow != null) + { + TextMeshProUGUI sceneTextShadowTMP = sceneTextShadow.transform.GetComponent(); + if (sceneTextShadowTMP != null) + { + sceneTextShadowTMP = AssetStore.StringStore.TranslateText(sceneTextShadowTMP); + } + } + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/ButtonObjects/OptLanguageBtn_Patch.cs b/BepInEx/Patches/GameObjects/ButtonObjects/OptLanguageBtn_Patch.cs new file mode 100644 index 0000000..016c90d --- /dev/null +++ b/BepInEx/Patches/GameObjects/ButtonObjects/OptLanguageBtn_Patch.cs @@ -0,0 +1,213 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using TMPro; +using UnityEngine; +using Object = UnityEngine.Object; + +public class OptionButtonData +{ + public OptionBtn Button { get; set; } + public Vector3 Position { get; set; } + public Utils.LanguageEnum? Language { get; set; } // Null if it's the "Next" button + public bool IsNextButton { get; set; } +} + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects +{ + internal class OptLanguageBtn_Patch + { + public static Dictionary LanguageBtnDict = new(); + private static bool buttonsCreated = false; + private static OptionBtn cachedTemplateButton; + + private const float startX = 4.3241f + 2.56f; + private const float startY = 2.7769f; + private const float ySpacing = 1.2505f; + + private static List AvailableLanguages; + private const int LanguagesPerPage = 5; + private static int currentPage = 0; + private static OptionBtn[] buttonSlots = new OptionBtn[6]; // 5 language buttons + 1 next button + + public static void CreateLanguageButtons(OptionBtn templateButton) + { + if (buttonsCreated) return; + buttonsCreated = true; + cachedTemplateButton = templateButton; + + AvailableLanguages = Enum.GetValues(typeof(Utils.LanguageEnum)) + .Cast() + .Where(lang => lang != Utils.LanguageEnum.LANG_END) + .ToList(); + + for (int i = 0; i < 6; i++) + { + var newButton = Object.Instantiate(templateButton, templateButton.transform.parent); + newButton.optionType = 80 + i; + + float yPos = startY - i * ySpacing; + Vector3 pos = new(startX, yPos); + newButton.transform.position = pos; + + buttonSlots[i] = newButton; + + LanguageBtnDict[newButton.GetInstanceID()] = new OptionButtonData + { + Button = newButton, + Position = pos + }; + } + + UpdatePage(); + } + + private static void UpdatePage() + { + int startIndex = currentPage * LanguagesPerPage; + int langCount = AvailableLanguages.Count; + + for (int i = 0; i < 5; i++) + { + var btn = buttonSlots[i]; + var data = LanguageBtnDict[btn.GetInstanceID()]; + + if (startIndex + i < langCount) + { + var lang = AvailableLanguages[startIndex + i]; + data.Language = lang; + data.IsNextButton = false; + btn.gameObject.SetActive(true); + UpdateButtonText(btn, lang.ToString()); + } + else + { + data.Language = null; + data.IsNextButton = false; + btn.gameObject.SetActive(false); + } + } + + // "Next" button always visible at index 5 + var nextBtn = buttonSlots[5]; + var nextData = LanguageBtnDict[nextBtn.GetInstanceID()]; + nextData.Language = null; + nextData.IsNextButton = true; + nextBtn.gameObject.SetActive(true); + UpdateButtonText(nextBtn, "Next"); + } + + public static void UpdateButtonText(OptionBtn button, string languageName) + { + TMP_FontAsset defaultAsset = FontStore.LoadTMPFont("English"); + + for (int i = 0; i < 3; i++) + { + Transform textTransform = button.transform.GetChild(i); + if (textTransform != null) + { + if (i == 0) textTransform.gameObject.SetActive(false); + + TextMeshProUGUI text = textTransform.GetComponent(); + if (text != null) + { + if (i == 0) + { + text.text = ""; + text.color = Color.red; + } + else + { + text.text = languageName; + } + text.fontSize = 16; + text.font = defaultAsset; + text.autoSizeTextContainer = false; + } + } + } + } + + private static void FlashMessage(OptionBtn button, string message) + { + var child = button.transform.GetChild(0); + if (child != null) + { + var text = child.GetComponent(); + if (text != null) + { + text.text = message; + } + child.gameObject.SetActive(true); + + Task.Delay(1000).ContinueWith(_ => + { + if (button != null && child != null && child.gameObject.activeSelf) + { + child.gameObject.SetActive(false); + } + }); + } + } + + [HarmonyPatch(typeof(OptionBtn))] + public static class OptLangBtn_Patch + { + [HarmonyPatch(nameof(OptionBtn.Awake))] + [HarmonyPostfix] + private static void Awake(OptionBtn __instance) + { + if (!buttonsCreated || cachedTemplateButton == null) + { + buttonsCreated = false; + CreateLanguageButtons(__instance); + } + } + + [HarmonyPatch("OnMouseUpAsButton")] + [HarmonyPrefix] + private static void OnMouseUpAsButton(OptionBtn __instance) + { + if (LanguageBtnDict.TryGetValue(__instance.GetInstanceID(), out var btnData)) + { + if (btnData.IsNextButton) + { + currentPage = (currentPage + 1) % (int)Math.Ceiling((float)AvailableLanguages.Count / LanguagesPerPage); + UpdatePage(); + return; + } + + if (btnData.Language is Utils.LanguageEnum selectedLang) + { + string currentLang = Utils.Language.ToString(); + + if (currentLang == selectedLang.ToString()) + { + FlashMessage(btnData.Button, "Already Selected!"); + } + else + { + Utils.ChangeLanguage(selectedLang.ToString()); + Debug.Log($"Language changed to: {selectedLang}"); + FlashMessage(btnData.Button, "Language Changed!"); + } + } + } + } + + [HarmonyPatch(nameof(OptionBtn.Update))] + [HarmonyPostfix] + private static void Update(OptionBtn __instance) + { + if (LanguageBtnDict.TryGetValue(__instance.GetInstanceID(), out var btnData)) + { + btnData.Button.transform.position = btnData.Position; + } + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/ButtonObjects/OptionBtn_Patch.cs b/BepInEx/Patches/GameObjects/ButtonObjects/OptionBtn_Patch.cs new file mode 100644 index 0000000..2aef1a5 --- /dev/null +++ b/BepInEx/Patches/GameObjects/ButtonObjects/OptionBtn_Patch.cs @@ -0,0 +1,68 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects +{ + [HarmonyPatch(typeof(OptionBtn))] + public static class OptionBtn_Patch + { + [HarmonyPatch(nameof(OptionBtn.Awake))] + [HarmonyPostfix] + private static void Awake(OptionBtn __instance) + { + Transform text_1Transform = __instance.transform.GetChild(0)?.transform; + if (text_1Transform != null) + { + TextMeshProUGUI text_1 = text_1Transform.GetComponent(); + text_1 = StringStore.TranslateText(text_1); + text_1.autoSizeTextContainer = false; + } + + Transform textTransform = __instance.transform.GetChild(1)?.transform; + if (textTransform != null) + { + TextMeshProUGUI text = textTransform.GetComponent(); + text = StringStore.TranslateText(text); + text.autoSizeTextContainer = false; + } + + Transform text2Transform = __instance.transform.GetChild(2)?.transform; + if (text2Transform != null) + { + TextMeshProUGUI text2 = text2Transform.GetComponent(); + text2 = StringStore.TranslateText(text2); + text2.autoSizeTextContainer = false; + } + } + + [HarmonyPatch("OnMouseUpAsButton")] + [HarmonyPostfix] + private static void OnMouseUpAsButtonPostfix(OptionBtn __instance) + { + Transform text_1Transform = __instance.transform.GetChild(0)?.transform; + if (text_1Transform != null) + { + TextMeshProUGUI text_1 = text_1Transform.GetComponent(); + text_1 = StringStore.TranslateText(text_1); + text_1.autoSizeTextContainer = false; + } + + Transform textTransform = __instance.transform.GetChild(1)?.transform; + if (textTransform != null) + { + TextMeshProUGUI text = textTransform.GetComponent(); + text = StringStore.TranslateText(text); + text.autoSizeTextContainer = false; + } + + Transform text2Transform = __instance.transform.GetChild(2)?.transform; + if (text2Transform != null) + { + TextMeshProUGUI text2 = text2Transform.GetComponent(); + text2 = StringStore.TranslateText(text2); + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/ButtonObjects/PVPPotBtn_Patch.cs b/BepInEx/Patches/GameObjects/ButtonObjects/PVPPotBtn_Patch.cs new file mode 100644 index 0000000..4ade853 --- /dev/null +++ b/BepInEx/Patches/GameObjects/ButtonObjects/PVPPotBtn_Patch.cs @@ -0,0 +1,41 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects +{ + [HarmonyPatch(typeof(PVPPotBtn))] + public class PVPPotBtn_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(PVPPotBtn.OnMouseUpAsButton))] + public static void OnMouseUpAsButton(PVPPotBtn __instance) + { + Transform sceneText = __instance.transform.FindChild("text"); + if(sceneText != null) + { + TextMeshProUGUI sceneTextTMP = sceneText.transform.GetComponent(); + if(sceneTextTMP != null) + { + sceneTextTMP.text = StringStore.TranslateText(sceneTextTMP.text); + } + } + Transform sceneTextShadow = sceneText.transform.FindChild("text_1"); + if(sceneTextShadow != null) + { + TextMeshProUGUI sceneTextShadowTMP = sceneTextShadow.transform.GetComponent(); + if (sceneTextShadowTMP != null) + { + sceneTextShadowTMP.text = StringStore.TranslateText(sceneTextShadowTMP.text); + } + } + + if (__instance.name.Equals("ChangeBg_3") || __instance.name.Equals("ChangeBg_4")) + { + __instance.gameObject.SetActive(false); + __instance.gameObject.SetActive(true); + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/ButtonObjects/PauseMenu_Btn_Patch.cs b/BepInEx/Patches/GameObjects/ButtonObjects/PauseMenu_Btn_Patch.cs new file mode 100644 index 0000000..be33173 --- /dev/null +++ b/BepInEx/Patches/GameObjects/ButtonObjects/PauseMenu_Btn_Patch.cs @@ -0,0 +1,13 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects +{ + [HarmonyPatch(typeof(PauseMenu_Btn))] + public static class PauseMenu_Btn_Patch + { + [HarmonyPatch(nameof(PauseMenu_Btn.Start))] + [HarmonyPostfix] + private static void Start(PauseMenu_Btn __instance) => StringStore.TranslateTextTransform(__instance.transform); + } +} diff --git a/BepInEx/Patches/GameObjects/Close_Patch.cs b/BepInEx/Patches/GameObjects/Close_Patch.cs new file mode 100644 index 0000000..13c7e54 --- /dev/null +++ b/BepInEx/Patches/GameObjects/Close_Patch.cs @@ -0,0 +1,48 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(Close))] + public static class Close_Patch + { + [HarmonyPatch(nameof(Close.Start))] + [HarmonyPostfix] + private static void Close_Start(Close __instance) + { + TextMeshPro closeText = __instance.transform.GetChild(0).GetComponent(); + closeText.text = "合上"; + closeText = StringStore.TranslateText(closeText); + closeText.autoSizeTextContainer = true; + + Transform AlmanacTransform = __instance.transform.parent.transform; + + Transform nameTransform = AlmanacTransform.Find("Name"); + if (nameTransform != null) + { + TextMeshPro nameTMP = nameTransform.transform.GetComponent(); + if (nameTMP) + { + nameTMP = StringStore.TranslateText(nameTMP); + nameTMP.autoSizeTextContainer = true; + } + + Transform nameShadowTransform = nameTransform.Find("NameShadow"); + if (nameShadowTransform) + { + TextMeshPro nameShadowTMP = nameShadowTransform.transform.GetComponent(); + if (nameShadowTMP) + { + nameShadowTMP = StringStore.TranslateText(nameShadowTMP); + nameShadowTMP.autoSizeTextContainer = true; + } + } + } + StringStore.TranslateTextTransform(AlmanacTransform.Find("Back"), true); + StringStore.TranslateTextTransform(AlmanacTransform.Find("NextPage")); + StringStore.TranslateTextTransform(AlmanacTransform.Find("LastPage")); + } + } +} diff --git a/BepInEx/Patches/GameObjects/CustomSettings_Patch.cs b/BepInEx/Patches/GameObjects/CustomSettings_Patch.cs new file mode 100644 index 0000000..47f3f27 --- /dev/null +++ b/BepInEx/Patches/GameObjects/CustomSettings_Patch.cs @@ -0,0 +1,23 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.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); + } + } +} diff --git a/BepInEx/Patches/GameObjects/CustomSun_Patch.cs b/BepInEx/Patches/GameObjects/CustomSun_Patch.cs new file mode 100644 index 0000000..2909545 --- /dev/null +++ b/BepInEx/Patches/GameObjects/CustomSun_Patch.cs @@ -0,0 +1,44 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(CustomSun))] + public static class CustomSun_Patch + { + [HarmonyPatch(nameof(CustomSun.Awake))] + [HarmonyPostfix] + private static void Awake(CustomSun __instance) + { + if (__instance.inputField.gameObject.activeSelf) + { + string oriTextSun = __instance.inputField.m_Text; + __instance.inputField.gameObject.SetActive(false); + __instance.inputField.m_Text = StringStore.TranslateText(oriTextSun); + __instance.inputField.m_OriginalText = StringStore.TranslateText(oriTextSun); + __instance.inputField.gameObject.SetActive(true); + } + + if (__instance.setFlags.gameObject.activeSelf) + { + string oriTextFlags = __instance.setFlags.m_Text; + __instance.setFlags.gameObject.SetActive(false); + __instance.setFlags.m_Text = StringStore.TranslateText(oriTextFlags); + __instance.setFlags.m_OriginalText = StringStore.TranslateText(oriTextFlags); + __instance.setFlags.gameObject.SetActive(true); + } + + Transform lookZombieTransform = __instance.lookZombie.transform.GetChild(0).transform; + if (lookZombieTransform != null) + { + TextMeshProUGUI lookZombieTMP = lookZombieTransform.GetComponent(); + if (lookZombieTMP != null) + { + lookZombieTMP = StringStore.TranslateText(lookZombieTMP); + } + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/GardenPlant_Patch.cs b/BepInEx/Patches/GameObjects/GardenPlant_Patch.cs new file mode 100644 index 0000000..8f6bc29 --- /dev/null +++ b/BepInEx/Patches/GameObjects/GardenPlant_Patch.cs @@ -0,0 +1,23 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(GardenPlant))] + public static class GardenPlant_Patch + { + [HarmonyPatch(nameof(GardenPlant.Update))] + [HarmonyPostfix] + private static void Update(GardenPlant __instance) + { + __instance.infoText = StringStore.TranslateText(__instance.infoText); + } + + [HarmonyPatch(nameof(GardenPlant.UpdateInfo))] + [HarmonyPostfix] + private static void UpdateInfo(GardenPlant __instance) + { + __instance.infoText = StringStore.TranslateText(__instance.infoText); + } + } +} diff --git a/BepInEx/Patches/GameObjects/Help__Patch.cs b/BepInEx/Patches/GameObjects/Help__Patch.cs new file mode 100644 index 0000000..688d057 --- /dev/null +++ b/BepInEx/Patches/GameObjects/Help__Patch.cs @@ -0,0 +1,31 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(Help_))] + public class Help__Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(Help_.Start))] + private static void Start(Help_ __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + Transform warningTransform = __instance.transform.GetChild(0); + Transform warningTextTransform = warningTransform.FindChild("文字"); + Transform warningTextShadowTransform = warningTransform.FindChild("文字2"); + Transform[] array = [warningTextTransform, warningTextShadowTransform]; + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != null) + { + array[i].GetComponent().text = StringStore.TranslateText(array[i].GetComponent().text); + array[i].GetComponent().font = fontAsset; + } + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/DY_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/DY_Patch.cs new file mode 100644 index 0000000..365e37d --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/DY_Patch.cs @@ -0,0 +1,16 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(DY))] + public static class DY_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(DY.Update))] + private static void Update(DY __instance) + { + __instance.TextMeshPro.text = StringStore.TranslateText(__instance.TextMeshPro.text); + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/LanternUmbrella_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/LanternUmbrella_Patch.cs new file mode 100644 index 0000000..0de0d08 --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/LanternUmbrella_Patch.cs @@ -0,0 +1,17 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(LanternUmbrella))] + public class LanternUmbrella_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(LanternUmbrella.Update))] + private static void Update(LanternUmbrella __instance) + { + __instance.energyText = StringStore.TranslateText(__instance.energyText); + __instance.energyTextShadow = StringStore.TranslateText(__instance.energyTextShadow); + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/MagnetBox_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/MagnetBox_Patch.cs new file mode 100644 index 0000000..1b1342f --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/MagnetBox_Patch.cs @@ -0,0 +1,16 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(MagnetBox))] + public class MagnetBox_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(MagnetBox.Update))] + private static void Update(MagnetBox __instance) + { + StringStore.TranslateTextTransform(__instance.transform); + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/MagnetInterface_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/MagnetInterface_Patch.cs new file mode 100644 index 0000000..cc61fda --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/MagnetInterface_Patch.cs @@ -0,0 +1,16 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(MagnetInterface))] + public class MagnetInterface_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(MagnetInterface.Update))] + private static void Update(MagnetInterface __instance) + { + StringStore.TranslateTextTransform(__instance.transform); + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/Money_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/Money_Patch.cs new file mode 100644 index 0000000..198146c --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/Money_Patch.cs @@ -0,0 +1,17 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(Money))] + public static class Money_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(Money.Update))] + private static void Update(Money __instance) + { + __instance.beanCount.text = StringStore.TranslateText(__instance.beanCount.text); + __instance.beanCount2.text = StringStore.TranslateText(__instance.beanCount2.text); + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/Plant_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/Plant_Patch.cs new file mode 100644 index 0000000..29e17ad --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/Plant_Patch.cs @@ -0,0 +1,21 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(Plant))] + public static class Plant_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(Plant.UpdateHealthText))] + private static void UpdateHealthText(Plant __instance) + { + Transform healthTransform = __instance.transform.Find("health"); + if (healthTransform != null) + { + StringStore.TranslateTextTransform(__instance.transform); + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/PlayerName_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/PlayerName_Patch.cs new file mode 100644 index 0000000..68622f2 --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/PlayerName_Patch.cs @@ -0,0 +1,16 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(PlayerName))] + public static class PlayerName_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(PlayerName.Update))] + private static void Update(PlayerName __instance) + { + __instance.textMesh.text = StringStore.TranslateText(__instance.textMesh.text); + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/SelectYourPlants_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/SelectYourPlants_Patch.cs new file mode 100644 index 0000000..51923bd --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/SelectYourPlants_Patch.cs @@ -0,0 +1,20 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(SelectYourPlants))] + public static class SelectYourPlants_Patch + { + [HarmonyPatch(nameof(SelectYourPlants.Awake))] + [HarmonyPostfix] + private static void Awake(SelectYourPlants __instance) + { + __instance.TextMeshProUGUI = StringStore.TranslateText(__instance.TextMeshProUGUI); + __instance.TextMeshProUGUI.autoSizeTextContainer = true; + + __instance.TextMeshProUGUI2 = StringStore.TranslateText(__instance.TextMeshProUGUI2); + __instance.TextMeshProUGUI2.autoSizeTextContainer = true; + } + } +} diff --git a/BepInEx/Patches/GameObjects/MinorObjects/Zombie_Patch.cs b/BepInEx/Patches/GameObjects/MinorObjects/Zombie_Patch.cs new file mode 100644 index 0000000..185db33 --- /dev/null +++ b/BepInEx/Patches/GameObjects/MinorObjects/Zombie_Patch.cs @@ -0,0 +1,21 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects +{ + [HarmonyPatch(typeof(Zombie))] + public static class Zombie_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(Zombie.UpdateHealthText))] + private static void UpdateHealthText(Zombie __instance) + { + Transform healthTransform = __instance.transform.Find("health"); + if (healthTransform != null) + { + StringStore.TranslateTextTransform(__instance.transform); + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/TravelBuff_Patch.cs b/BepInEx/Patches/GameObjects/TravelBuff_Patch.cs new file mode 100644 index 0000000..3ce739b --- /dev/null +++ b/BepInEx/Patches/GameObjects/TravelBuff_Patch.cs @@ -0,0 +1,17 @@ +using HarmonyLib; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(TravelBuff))] + public static class TravelBuff_Patch + { + [HarmonyPatch(nameof(TravelBuff.OnMouseUpAsButton))] + [HarmonyPostfix] + private static void OnMouseUpAsButton() + { + if (TravelBuffMgr.Instance == null) return; + TravelBuffMgr.Instance.text = AssetStore.StringStore.TranslateText(TravelBuffMgr.Instance.text); + TravelBuffMgr.Instance.text2 = AssetStore.StringStore.TranslateText(TravelBuffMgr.Instance.text2); + } + } +} diff --git a/BepInEx/Patches/GameObjects/TravelRefresh_Patch.cs b/BepInEx/Patches/GameObjects/TravelRefresh_Patch.cs new file mode 100644 index 0000000..f932d7a --- /dev/null +++ b/BepInEx/Patches/GameObjects/TravelRefresh_Patch.cs @@ -0,0 +1,47 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(TravelRefresh))] + public static class TravelRefresh_Patch + { + [HarmonyPatch(nameof(TravelRefresh.Update))] + [HarmonyPostfix] + private static void Update(TravelRefresh __instance) + { + TextMeshProUGUI pointsText = __instance.transform.GetChild(0).GetComponent(); + pointsText = StringStore.TranslateText(pointsText); + pointsText.autoSizeTextContainer = true; + + Transform TravelMenuTransform = __instance.transform.parent.transform; + Transform refreshTransform = TravelMenuTransform.Find("Refresh2").transform.Find("bank"); + if (refreshTransform != null) + { + Transform text_1Transform = refreshTransform.Find("text_1"); + if (text_1Transform != null) + { + TextMeshProUGUI text_1 = text_1Transform.GetComponent(); + if (text_1) + { + text_1 = StringStore.TranslateText(text_1); + text_1.autoSizeTextContainer = true; + } + } + + Transform text_2Transform = refreshTransform.Find("text_2"); + if (text_2Transform != null) + { + TextMeshProUGUI text_2 = text_2Transform.GetComponent(); + if (text_2) + { + text_2 = StringStore.TranslateText(text_2); + text_2.autoSizeTextContainer = true; + } + } + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/TravelStore_Patch.cs b/BepInEx/Patches/GameObjects/TravelStore_Patch.cs new file mode 100644 index 0000000..1d7052b --- /dev/null +++ b/BepInEx/Patches/GameObjects/TravelStore_Patch.cs @@ -0,0 +1,38 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; +using TMPro; +using UnityEngine; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(TravelStore))] + internal class TravelStore_Patch + { + [HarmonyPatch(nameof(TravelStore.Update))] + [HarmonyPostfix] + private static void Update(TravelStore __instance) + { + foreach (TextMeshProUGUI text in __instance.introduces) + { + text.text = StringStore.TranslateText(text.text); + } + + Transform moneyTransform = __instance.transform.Find("Money"); + if (moneyTransform != null) + { + StringStore.TranslateTextTransform(moneyTransform); + } + } + + [HarmonyPatch(nameof(TravelStore.SetText), new Type[] { typeof(string)})] + [HarmonyPostfix] + private static void ShowText(TravelStore __instance) + { + foreach (TextMeshProUGUI text in __instance.introduces) + { + text.text = StringStore.TranslateText(text.text); + } + } + } +} diff --git a/BepInEx/Patches/GameObjects/UIDifficulty_Patch.cs b/BepInEx/Patches/GameObjects/UIDifficulty_Patch.cs new file mode 100644 index 0000000..a74e5f3 --- /dev/null +++ b/BepInEx/Patches/GameObjects/UIDifficulty_Patch.cs @@ -0,0 +1,22 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(UIDifficulty))] + public static class UIDifficulty_Patch + { + [HarmonyPatch(nameof(UIDifficulty.Update))] + [HarmonyPostfix] + private static void Update(UIDifficulty __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + string difficultyText = StringStore.patchesStore["Difficulty"][Utils.Language.ToString()]; + + __instance.t.text = string.Format(difficultyText + " {0}", GameAPP.difficulty); + __instance.t.autoSizeTextContainer = false; + __instance.t.font = fontAsset; + } + } +} diff --git a/BepInEx/Patches/GameObjects/UIZombieNum_Patch.cs b/BepInEx/Patches/GameObjects/UIZombieNum_Patch.cs new file mode 100644 index 0000000..6fe701e --- /dev/null +++ b/BepInEx/Patches/GameObjects/UIZombieNum_Patch.cs @@ -0,0 +1,21 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects +{ + [HarmonyPatch(typeof(UIZombieNum))] + public static class UIZombieNum_Patch + { + [HarmonyPatch(nameof(UIZombieNum.Update))] + [HarmonyPostfix] + private static void Update(UIZombieNum __instance) + { + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); + string zombieText = StringStore.patchesStore["Zombies"][Utils.Language.ToString()]; + + __instance.t.text = string.Format(zombieText + " {0}", Board.Instance.enermyCount); + __instance.t.font = fontAsset; + } + } +} diff --git a/BepInEx/Patches/Managers/AlmanacMgrZombie_Patch.cs b/BepInEx/Patches/Managers/AlmanacMgrZombie_Patch.cs new file mode 100644 index 0000000..364736c --- /dev/null +++ b/BepInEx/Patches/Managers/AlmanacMgrZombie_Patch.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using TMPro; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using static PvZ_Fusion_Translator__BepInEx_.FileLoader; +using UnityEngine; +using System.IO; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(AlmanacMgrZombie))] + public static partial class AlmanacMgrZombie_Patch + { + [HarmonyPatch(nameof(AlmanacMgrZombie.InitNameAndInfoFromJson))] + [HarmonyPrefix] + private static bool InitNameAndInfoFromJson(AlmanacMgrZombie __instance) + { + string currentLanguage = Utils.Language.ToString(); + string almanacDir = GetAssetDir(AssetType.Almanac, Utils.Language); + string path = Path.Combine(almanacDir, "ZombieStringsTranslate.json"); + + if (!File.Exists(path)) + { + Log.LogError($"ZombieStringsTranslate.json file not found at path: {path}"); + return true; + } + + #if OBFUSCATE + if (CheckSumStore.IsModified(path)) + { + Log.LogError("File {0} was modified!", path); + return true; + } + #endif + + string json; + json = File.ReadAllText(path); + + bool hasAlmanacFont = false; + TMP_FontAsset almanacFontAsset = null; + if (FontStore.fontAssetDictSecondary.ContainsKey(currentLanguage + "_Almanac") || FontStore.fontAssetDictSecondary.ContainsKey(currentLanguage)) + { + almanacFontAsset = FontStore.LoadTMPFontAlmanac(currentLanguage); + hasAlmanacFont = true; + } + + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); + + TextMeshPro component = __instance.info.GetComponent(); + TextMeshPro component2 = __instance.zombieName.GetComponent(); + TextMeshPro component3 = __instance.zombieName.transform.GetChild(0).GetComponent(); + + AlmanacMgrZombie.ZombieAlmanacData zombieData = JsonUtility.FromJson(json); + + foreach (AlmanacMgrZombie.ZombieInfo zombieInfo in zombieData.zombies) + { + if (zombieInfo.theZombieType == __instance.theZombieType) + { + component.text = zombieInfo.info + "\n\n" + zombieInfo.introduce; + component.overflowMode = TextOverflowModes.Page; + component2.text = zombieInfo.name; + component2.autoSizeTextContainer = true; + component3.text = Utils.RemoveColorTags(zombieInfo.name); + component3.autoSizeTextContainer = true; + + if (hasAlmanacFont) + component.font = almanacFontAsset; + else + component.font = fontAsset; + component2.font = fontAsset; + component3.font = fontAsset; + + return false; + } + } + + return true; + } + + [HarmonyPatch(nameof(AlmanacMgrZombie.OnMouseDown))] + [HarmonyPrefix] + private static bool OnMouseDown(AlmanacMgrZombie __instance) + { + TextMeshPro component = __instance.info.GetComponent(); + if (component != null) + { + component.pageToDisplay = component.pageToDisplay > component.m_pageNumber ? 1 : component.pageToDisplay + 1; + return false; + } + return true; + } + } +} diff --git a/BepInEx/Patches/Managers/AlmanacMgr_Patch.cs b/BepInEx/Patches/Managers/AlmanacMgr_Patch.cs new file mode 100644 index 0000000..24f421c --- /dev/null +++ b/BepInEx/Patches/Managers/AlmanacMgr_Patch.cs @@ -0,0 +1,99 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System.IO; +using TMPro; +using UnityEngine; +using static PvZ_Fusion_Translator__BepInEx_.FileLoader; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(AlmanacMgr))] + public static partial class AlmanacMgr_Patch + { + [HarmonyPatch(nameof(AlmanacMgr.InitNameAndInfoFromJson))] + [HarmonyPrefix] + private static bool InitNameAndInfoFromJson(AlmanacMgr __instance) + { + string currentLanguage = Utils.Language.ToString(); + string almanacDir = GetAssetDir(AssetType.Almanac, Utils.Language); + string path = Path.Combine(almanacDir, "LawnStringsTranslate.json"); + + if (!File.Exists(path)) + { + Log.LogError($"LawnStringsTranslate.json file not found at path: {path}"); + return true; + } + + #if OBFUSCATE + if (CheckSumStore.IsModified(path)) + { + Log.LogError("File {0} was modified!", path); + return true; + } + #endif + + string json; + json = File.ReadAllText(path); + + bool hasAlmanacFont = false; + TMP_FontAsset almanacFontAsset = null; + if (FontStore.fontAssetDictSecondary.ContainsKey(currentLanguage + "_Almanac") || FontStore.fontAssetDictSecondary.ContainsKey(currentLanguage)) + { + almanacFontAsset = FontStore.LoadTMPFontAlmanac(currentLanguage); + hasAlmanacFont = true; + } + + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); + + TextMeshPro component = __instance.info.GetComponent(); + TextMeshPro component2 = __instance.plantName.GetComponent(); + TextMeshPro component3 = __instance.plantName.transform.GetChild(0).GetComponent(); + TextMeshPro component4 = __instance.cost.GetComponent(); + + AlmanacMgr.PlantData plantData = JsonUtility.FromJson(json); + + foreach (AlmanacMgr.PlantInfo plantInfo in plantData.plants) + { + if (plantInfo.seedType == __instance.theSeedType) + { + component.text = plantInfo.info + "\n\n" + plantInfo.introduce; + component.overflowMode = TextOverflowModes.Page; + component2.text = plantInfo.name; + component2.autoSizeTextContainer = true; + component3.text = Utils.RemoveColorTags(plantInfo.name); + component3.autoSizeTextContainer = true; + component4.text = plantInfo.cost; + + if (hasAlmanacFont) + { + component.font = almanacFontAsset; + component4.font = almanacFontAsset; + } + else + { + component.font = fontAsset; + component4.font = fontAsset; + } + component2.font = fontAsset; + component3.font = fontAsset; + return false; + } + } + + return true; + } + + [HarmonyPatch(nameof(AlmanacMgr.OnMouseDown))] + [HarmonyPrefix] + private static bool OnMouseDown(AlmanacMgr __instance) + { + TextMeshPro component = __instance.info.GetComponent(); + if (component != null) + { + component.pageToDisplay = component.pageToDisplay > component.m_pageNumber ? 1 : component.pageToDisplay + 1; + return false; + } + return true; + } + } +} diff --git a/BepInEx/Patches/Managers/DifficultyMgr_Patch.cs b/BepInEx/Patches/Managers/DifficultyMgr_Patch.cs new file mode 100644 index 0000000..b24a68c --- /dev/null +++ b/BepInEx/Patches/Managers/DifficultyMgr_Patch.cs @@ -0,0 +1,17 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(DifficultyMgr))] + public static class DifficultyMgr_Patch + { + [HarmonyPatch(nameof(DifficultyMgr.Update))] + [HarmonyPostfix] + private static void DifficultyMgr_Update(DifficultyMgr __instance) + { + __instance.t = StringStore.TranslateText(__instance.t); + __instance.t.autoSizeTextContainer = false; + } + } +} diff --git a/BepInEx/Patches/Managers/EndlessMgr_Patch.cs b/BepInEx/Patches/Managers/EndlessMgr_Patch.cs new file mode 100644 index 0000000..06ad56b --- /dev/null +++ b/BepInEx/Patches/Managers/EndlessMgr_Patch.cs @@ -0,0 +1,27 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; +using UnityEngine; + + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(EndlessMgr))] + public static class EndlessMgr_Patch + { + [HarmonyPatch(nameof(EndlessMgr.Awake))] + [HarmonyPostfix] + private static void Awake(EndlessMgr __instance) + { + Transform textTransform = __instance.transform.GetChild(2); + if (textTransform != null && textTransform.gameObject.activeSelf) + { + TextMeshProUGUI textTMP = textTransform.GetComponent(); + if (textTMP != null) + { + textTMP = StringStore.TranslateText(textTMP); + } + } + } + } +} diff --git a/BepInEx/Patches/Managers/IZEMgr_Patch.cs b/BepInEx/Patches/Managers/IZEMgr_Patch.cs new file mode 100644 index 0000000..bdaa085 --- /dev/null +++ b/BepInEx/Patches/Managers/IZEMgr_Patch.cs @@ -0,0 +1,26 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(IZEMgr))] + public static class IZEMgr_Patch + { + [HarmonyPatch(nameof(IZEMgr.Start))] + [HarmonyPostfix] + public static void Start(IZEMgr __instance) + { + TextMeshProUGUI[] array = + [ + __instance.transform.GetChild(0).GetComponent(), + __instance.transform.GetChild(0).GetChild(0).GetComponent(), + ]; + for (int i = 0; i < array.Length; i++) + { + array[i] = StringStore.TranslateText(array[i]); + array[i].text = array[i].text.Replace("\n", " "); + } + } + } +} diff --git a/BepInEx/Patches/Managers/InGameUIMgr_Patch.cs b/BepInEx/Patches/Managers/InGameUIMgr_Patch.cs new file mode 100644 index 0000000..ba07abc --- /dev/null +++ b/BepInEx/Patches/Managers/InGameUIMgr_Patch.cs @@ -0,0 +1,32 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(InGameUIMgr))] + public static class InGameUIMgr_Patch + { + [HarmonyPatch(nameof(InGameUIMgr.Start))] + [HarmonyPostfix] + private static void Start(InGameUIMgr __instance) + { + TextMeshProUGUI[] array = new TextMeshProUGUI[] + { + __instance.transform.GetChild(4).GetComponent(), + __instance.transform.GetChild(4).GetChild(0).GetComponent(), + __instance.transform.GetChild(5).GetComponent(), + __instance.transform.GetChild(5).GetChild(0).GetComponent(), + __instance.transform.GetChild(6).GetComponent(), + __instance.transform.GetChild(6).GetChild(0).GetComponent() + }; + TextMeshProUGUI[] array2 = array; + for (int i = 0; i < array2.Length; i++) + { + + array2[i] = StringStore.TranslateText(array2[i]); + array2[i].text = array2[i].text.Replace("\n", " "); + } + } + } +} diff --git a/BepInEx/Patches/Managers/OppositeBuffManager_Patch.cs b/BepInEx/Patches/Managers/OppositeBuffManager_Patch.cs new file mode 100644 index 0000000..c14bb28 --- /dev/null +++ b/BepInEx/Patches/Managers/OppositeBuffManager_Patch.cs @@ -0,0 +1,28 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(OppositeBuffManager))] + public static class OppositeBuffManager_Patch + { + [HarmonyPatch(nameof(OppositeBuffManager.SetText), new Type[] { typeof(TextMeshProUGUI), typeof(BuffType), typeof(int)})] + [HarmonyPostfix] + private static void SetText(OppositeBuffManager __instance, ref TextMeshProUGUI text) + { + StringStore.TranslateTextUI(text); + } + + [HarmonyPatch(nameof(OppositeBuffManager.Awake))] + [HarmonyPostfix] + private static void Awake(OppositeBuffManager __instance) + { + StringStore.TranslateTextUI(__instance.textA_bad[0]); + StringStore.TranslateTextUI(__instance.textA_bad[1]); + StringStore.TranslateTextUI(__instance.textB_bad[0]); + StringStore.TranslateTextUI(__instance.textB_bad[1]); + } + } +} diff --git a/BepInEx/Patches/Managers/TravelBuffMgr_Patch.cs b/BepInEx/Patches/Managers/TravelBuffMgr_Patch.cs new file mode 100644 index 0000000..ef3d77f --- /dev/null +++ b/BepInEx/Patches/Managers/TravelBuffMgr_Patch.cs @@ -0,0 +1,26 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(TravelBuffMgr))] + public static class TravelBuffMgr_Patch + { + [HarmonyPatch(nameof(TravelBuffMgr.Awake))] + [HarmonyPostfix] + private static void Awake(TravelBuffMgr __instance) + { + __instance.text = StringStore.TranslateText(__instance.text); + __instance.text2 = StringStore.TranslateText(__instance.text2); + } + + [HarmonyPatch(nameof(TravelBuffMgr.ShowText), new Type[] { typeof(int), typeof(int) })] + [HarmonyPostfix] + private static void ShowText(TravelBuffMgr __instance) + { + __instance.text = StringStore.TranslateText(__instance.text); + __instance.text2 = StringStore.TranslateText(__instance.text2); + } + } +} diff --git a/BepInEx/Patches/Managers/TravelMenuMgr_Patch.cs b/BepInEx/Patches/Managers/TravelMenuMgr_Patch.cs new file mode 100644 index 0000000..7be6b1e --- /dev/null +++ b/BepInEx/Patches/Managers/TravelMenuMgr_Patch.cs @@ -0,0 +1,50 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(TravelMenuMgr))] + public static class TravelMenuMgr_Patch + { + [HarmonyPatch(nameof(TravelMenuMgr.Start))] + [HarmonyPostfix] + private static void Start(TravelMenuMgr __instance) + { + foreach(TextMeshProUGUI text in __instance.textMesh) + { + text.text = StringStore.TranslateText(text.text); + } + foreach(TextMeshProUGUI text in __instance.textMeshShadow) + { + text.text = StringStore.TranslateText(text.text); + } + } + [HarmonyPatch(nameof(TravelMenuMgr.SetText))] + [HarmonyPostfix] + private static void SetText(TravelMenuMgr __instance) + { + foreach(TextMeshProUGUI text in __instance.textMesh) + { + text.text = StringStore.TranslateText(text.text); + } + foreach(TextMeshProUGUI text in __instance.textMeshShadow) + { + text.text = StringStore.TranslateText(text.text); + } + } + [HarmonyPatch(nameof(TravelMenuMgr.SetRichText), [typeof(int), typeof(int), typeof(TextMeshProUGUI), typeof(string)])] + [HarmonyPostfix] + private static void SetRichText(TravelMenuMgr __instance) + { + foreach(TextMeshProUGUI text in __instance.textMesh) + { + text.text = StringStore.TranslateText(text.text); + } + foreach(TextMeshProUGUI text in __instance.textMeshShadow) + { + text.text = StringStore.TranslateText(text.text); + } + } + } +} diff --git a/BepInEx/Patches/Managers/UIMgr_Patch.cs b/BepInEx/Patches/Managers/UIMgr_Patch.cs new file mode 100644 index 0000000..347dac5 --- /dev/null +++ b/BepInEx/Patches/Managers/UIMgr_Patch.cs @@ -0,0 +1,17 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.Managers +{ + [HarmonyPatch(typeof(UIMgr))] + public class UIMgr_Patch + { + [HarmonyPatch(nameof(UIMgr.EnterMainMenu))] + [HarmonyPostfix] + private static void EnterMainMenu(UIMgr __instance) + { + // Log.LogInfo("Entered Main Menu"); + WarningStore.WarningReload(Utils.Language); + } + } +} diff --git a/BepInEx/Patches/OtherManagers/AchievementClip_Patch.cs b/BepInEx/Patches/OtherManagers/AchievementClip_Patch.cs new file mode 100644 index 0000000..2ad7705 --- /dev/null +++ b/BepInEx/Patches/OtherManagers/AchievementClip_Patch.cs @@ -0,0 +1,63 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using TMPro; +using static PvZ_Fusion_Translator__BepInEx_.FileLoader; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.OtherManagers +{ + [HarmonyPatch(typeof(AchievementClip))] + public static class AchievementClip_Patch + { + [HarmonyPatch(nameof(AchievementClip.Start))] + [HarmonyPostfix] + private static void Start(AchievementClip __instance) + { + string currentLanguage = Utils.Language.ToString(); + string achievementDir = GetAssetDir(AssetType.Almanac, Utils.Language); + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage); + string path = Path.Combine(achievementDir, "AchievementsTextTranslate.json"); + + #if OBFUSCATE + if (CheckSumStore.IsModified(path)) + { + Log.LogError("File {0} was modified!", path); + return; + } + #endif + + if (!File.Exists(path)) return; + + string json; + json = File.ReadAllText(path); + Dictionary achievementsTexts = JsonSerializer.Deserialize>(json); + + TextMeshProUGUI text1 = __instance.introduce.transform.GetChild(1).GetComponent(); + TextMeshProUGUI text2 = __instance.introduce.transform.GetChild(2).GetComponent(); + TextMeshProUGUI name1 = __instance.image.transform.GetChild(0).GetComponent(); + + text1.text = achievementsTexts[__instance._index].Name; + text1.font = fontAsset; + text2.text = achievementsTexts[__instance._index].Name; + text2.font = fontAsset; + name1.text = achievementsTexts[__instance._index].Text; + name1.font = fontAsset; + } + } + + public class AchievementObject + { + public Achievement achievement { get; set; } + public string Name { get; set; } + public string Text { get; set; } + + public AchievementObject(Achievement achievement = Achievement.Welcome, string name = "", string text = "") + { + this.achievement = achievement; + Name = name; + Text = text; + } + } +} diff --git a/BepInEx/Patches/OtherManagers/GardenUI_Patch.cs b/BepInEx/Patches/OtherManagers/GardenUI_Patch.cs new file mode 100644 index 0000000..9d923a0 --- /dev/null +++ b/BepInEx/Patches/OtherManagers/GardenUI_Patch.cs @@ -0,0 +1,17 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.OtherManagers +{ + [HarmonyPatch(typeof(GardenUI))] + public static class GardenUI_Patch + { + [HarmonyPatch(nameof(GardenUI.Update))] + [HarmonyPostfix] + public static void Update(GardenUI __instance) + { + __instance.currentPageText = StringStore.TranslateText(__instance.currentPageText, false); + __instance.currentPageText2 = StringStore.TranslateText(__instance.currentPageText2, false); + } + } +} diff --git a/BepInEx/Patches/OtherManagers/MenuText_Patch.cs b/BepInEx/Patches/OtherManagers/MenuText_Patch.cs new file mode 100644 index 0000000..8f32307 --- /dev/null +++ b/BepInEx/Patches/OtherManagers/MenuText_Patch.cs @@ -0,0 +1,21 @@ +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; +using TMPro; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.OtherManagers +{ + [HarmonyPatch(typeof(MenuText))] + public static class MenuText_Patch + { + [HarmonyPatch(nameof(MenuText.UpdateText), new Type[] { typeof(string) })] + [HarmonyPostfix] + private static void UpdateTextPatch(MenuText __instance) + { + TextMeshProUGUI text_1 = __instance.transform.GetChild(0).Find("text1").GetComponent(); + text_1.text = StringStore.TranslateText(text_1.text); + TextMeshProUGUI text = __instance.transform.GetChild(0).Find("text").GetComponent(); + text.text = StringStore.TranslateText(text_1.text); + } + } +} diff --git a/BepInEx/Patches/OtherManagers/ThanksMenu_Patch.cs b/BepInEx/Patches/OtherManagers/ThanksMenu_Patch.cs new file mode 100644 index 0000000..1928d36 --- /dev/null +++ b/BepInEx/Patches/OtherManagers/ThanksMenu_Patch.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TMPro; +using HarmonyLib; +using PvZ_Fusion_Translator__BepInEx_.AssetStore; + +namespace PvZ_Fusion_Translator__BepInEx_.Patches.OtherManagers +{ + [HarmonyPatch(typeof(ThanksMenu))] + public class ThanksMenu_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(ThanksMenu.Update))] + private static void Update(ThanksMenu __instance) + { + TextMeshProUGUI textTransform = __instance.transform.GetChild(0).GetComponent(); + if (textTransform != null) + { + textTransform.text = StringStore.TranslateText(textTransform.text); + textTransform.autoSizeTextContainer = true; + } + } + } +} diff --git a/BepInEx/PvZ Fusion Translator [BepInEx].csproj b/BepInEx/PvZ Fusion Translator [BepInEx].csproj new file mode 100644 index 0000000..f5c02f0 --- /dev/null +++ b/BepInEx/PvZ Fusion Translator [BepInEx].csproj @@ -0,0 +1,381 @@ + + + + net6.0 + PvZ_Fusion_Translator__BepInEx_ + BepInEx Port of PvZ Fusion Translator + 1.0.0 + true + latest + + https://api.nuget.org/v3/index.json; + https://nuget.bepinex.dev/v3/index.json; + https://nuget.samboy.dev/v3/index.json + + PvZ_Fusion_Translator__BepInEx_ + C:\Users\Estudio\Documents\LHC G\PVZF-Translation\PC_PVZ-Fusion_2.3 + AnyCPU;x64 + Debug;Release;DebugObfuscate;ReleaseObfuscate + + + + + + + + + + $(GamePath)\BepInEx\core\0Harmony.dll + + + $(GamePath)\BepInEx\core\AsmResolver.dll + + + $(GamePath)\BepInEx\core\AsmResolver.DotNet.dll + + + $(GamePath)\BepInEx\core\AsmResolver.PE.dll + + + $(GamePath)\BepInEx\core\AsmResolver.PE.File.dll + + + $(GamePath)\BepInEx\interop\Assembly-CSharp.dll + + + $(GamePath)\BepInEx\core\AssetRipper.CIL.dll + + + $(GamePath)\BepInEx\core\AssetRipper.Primitives.dll + + + $(GamePath)\BepInEx\core\BepInEx.Core.dll + + + $(GamePath)\BepInEx\core\BepInEx.Preloader.Core.dll + + + $(GamePath)\BepInEx\core\BepInEx.Unity.Common.dll + + + $(GamePath)\BepInEx\core\BepInEx.Unity.IL2CPP.dll + + + $(GamePath)\BepInEx\core\Cpp2IL.Core.dll + + + $(GamePath)\BepInEx\core\Disarm.dll + + + $(GamePath)\BepInEx\core\Gee.External.Capstone.dll + + + $(GamePath)\BepInEx\core\Iced.dll + + + $(GamePath)\BepInEx\core\Il2CppInterop.Common.dll + + + $(GamePath)\BepInEx\core\Il2CppInterop.Generator.dll + + + $(GamePath)\BepInEx\core\Il2CppInterop.HarmonySupport.dll + + + $(GamePath)\BepInEx\core\Il2CppInterop.Runtime.dll + + + $(GamePath)\BepInEx\interop\Il2CppMono.Security.dll + + + $(GamePath)\BepInEx\interop\Il2Cppmscorlib.dll + + + $(GamePath)\BepInEx\interop\Il2CppSystem.dll + + + $(GamePath)\BepInEx\interop\Il2CppSystem.Configuration.dll + + + $(GamePath)\BepInEx\interop\Il2CppSystem.Core.dll + + + $(GamePath)\BepInEx\interop\Il2CppSystem.Xml.dll + + + $(GamePath)\BepInEx\core\LibCpp2IL.dll + + + $(GamePath)\BepInEx\core\Mono.Cecil.dll + + + $(GamePath)\BepInEx\core\Mono.Cecil.Mdb.dll + + + $(GamePath)\BepInEx\core\Mono.Cecil.Pdb.dll + + + $(GamePath)\BepInEx\core\Mono.Cecil.Rocks.dll + + + $(GamePath)\BepInEx\core\MonoMod.RuntimeDetour.dll + + + $(GamePath)\BepInEx\core\MonoMod.Utils.dll + + + $(GamePath)\BepInEx\core\SemanticVersioning.dll + + + $(GamePath)\BepInEx\core\StableNameDotNet.dll + + + $(GamePath)\BepInEx\interop\Unity.2D.Animation.Runtime.dll + + + $(GamePath)\BepInEx\interop\Unity.Burst.dll + + + $(GamePath)\BepInEx\interop\Unity.Burst.Unsafe.dll + + + $(GamePath)\BepInEx\interop\Unity.Collections.dll + + + $(GamePath)\BepInEx\interop\Unity.Collections.LowLevel.ILSupport.dll + + + $(GamePath)\BepInEx\interop\Unity.InternalAPIEngineBridge.001.dll + + + $(GamePath)\BepInEx\interop\Unity.Mathematics.dll + + + $(GamePath)\BepInEx\interop\Unity.RenderPipeline.Universal.ShaderLibrary.dll + + + $(GamePath)\BepInEx\interop\Unity.RenderPipelines.Core.Runtime.dll + + + $(GamePath)\BepInEx\interop\Unity.RenderPipelines.Universal.Runtime.dll + + + $(GamePath)\BepInEx\interop\Unity.TextMeshPro.dll + + + $(GamePath)\BepInEx\interop\Unity.VisualScripting.Core.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.AccessibilityModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.AIModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.AndroidJNIModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.AnimationModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.AssetBundleModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.AudioModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ClothModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ClusterInputModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ClusterRendererModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ContentLoadModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.CoreModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.CrashReportingModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.DirectorModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.DSPGraphModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.GameCenterModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.GIModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.GridModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.HotReloadModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ImageConversionModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.IMGUIModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.InputLegacyModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.InputModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.JSONSerializeModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.LocalizationModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ParticleSystemModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.PerformanceReportingModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.Physics2DModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.PhysicsModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ProfilerModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.PropertiesModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.ScreenCaptureModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.SharedInternalsModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.SpriteMaskModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.SpriteShapeModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.StreamingModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.SubstanceModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.SubsystemsModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.TerrainModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.TerrainPhysicsModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.TextCoreFontEngineModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.TextCoreTextEngineModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.TextRenderingModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.TilemapModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.TLSModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UI.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UIElementsModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UIModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UmbraModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityAnalyticsCommonModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityAnalyticsModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityConnectModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityCurlModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityTestProtocolModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityWebRequestAssetBundleModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityWebRequestAudioModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityWebRequestModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityWebRequestTextureModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.UnityWebRequestWWWModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.VehiclesModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.VFXModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.VideoModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.VirtualTexturingModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.VRModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.WindModule.dll + + + $(GamePath)\BepInEx\interop\UnityEngine.XRModule.dll + + + $(GamePath)\BepInEx\core\WasmDisassembler.dll + + + $(GamePath)\BepInEx\interop\__Generated.dll + + + + + + + + diff --git a/BepInEx/Utils.cs b/BepInEx/Utils.cs new file mode 100644 index 0000000..6dcaf4b --- /dev/null +++ b/BepInEx/Utils.cs @@ -0,0 +1,128 @@ +using PvZ_Fusion_Translator__BepInEx_.AssetStore; +using System; +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; +using UnityEngine; +using UnityEngine.Experimental.Rendering; + +namespace PvZ_Fusion_Translator__BepInEx_ +{ + public class Utils + { + internal static bool TryReplaceTexture2D(Texture2D ogTexture) + { + if (ogTexture != null) + { + if (TextureStore.textureDict.TryGetValue(ogTexture.name, out string texturePath)) + { + try + { + ImageConversion.LoadImage(ogTexture, File.ReadAllBytes(texturePath)); + + Log.LogDebug("OK! Replaced Texture " + ogTexture.name); + + ogTexture.name = "replaced_" + ogTexture.name; + return true; + } + catch (Exception ex) + { + Log.LogError("Failed to replace texture: " + ogTexture.name + " at path: " + texturePath); + Log.LogError(ex.ToString()); + } + } + } + return false; + } + + internal static Texture2D LoadImage(string path) + { + if (!File.Exists(path)) + { + throw new FileNotFoundException($"The image file at path '{path}' does not exist."); + } + + byte[] array = File.ReadAllBytes(path); + 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) + { + + hex = hex.Replace("#", ""); + + float r = int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber) / 255f; + float g = int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber) / 255f; + float b = int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber) / 255f; + + return new Color(r, g, b); + } + + public static void OpenSaveDirectory() + { + string saveDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "AppData", "LocalLow", "LanPiaoPiao", "PlantsVsZombiesRH"); + Process.Start("explorer.exe", saveDirectory); + } + + public static void OpenTrello() + { + string website = "https://trello.com/b/DcdT1kUp"; + Process.Start(new ProcessStartInfo(website) { UseShellExecute = true }); + } + + public static string RemoveColorTags(string text) + { + return Regex.Replace(text, @"]+>", ""); + } + + internal static void ChangeLanguage(string language) + { + OldLanguage = Language; + + if (Enum.TryParse(language, out Utils.LanguageEnum lang)) + { + Utils.Language = lang; + } + else + { + // Handle invalid language string + Log.LogError($"Invalid language string: {language}"); + } + + WarningStore.isWarningMessageLoaded = false; + FontStore.Reload(); + StringStore.Reload(); + TextureStore.Reload(); + FileLoader.SaveLanguage(); + } + + public static Utils.LanguageEnum OldLanguage; + public static Utils.LanguageEnum Language; + public enum LanguageEnum + { + // first column + English, + French, + Italian, + German, + Spanish, + Portuguese, + + // second column + Javanese, //Filipino, + Vietnamese, + Indonesian, + Russian, + Japanese, + Korean, + + // third column + // Ukrainian, + // Slovak, + + LANG_END + } + } +} \ No newline at end of file