#if MULTI_LANGUAGE using HarmonyLib; using Il2Cpp; using Il2CppTMPro; using MelonLoader; using PvZ_Fusion_Translator; using PvZ_Fusion_Translator.AssetStore; using UnityEngine; using UnityEngine.UIElements; using static MelonLoader.MelonLogger; 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 Utils.ToggleEnum? Toggle { get; set; } // Null if it's the "Next" button public bool IsNextButton { get; set; } public bool shifted = false; } namespace PvZ_Fusion_Translator.Patches.GameObjects.ButtonObjects { internal class OptLanguageBtn_Patch { public static Dictionary LanguageBtnDict = new(); public static Dictionary ToggleBtnDict = new(); private static bool buttonsCreated = false; private static bool togglesCreated = false; private static OptionBtn cachedTemplateButton; private static OptionBtn cachedTemplateToggleButton; private const float startX = 4.3241f + 2.56f; private const float startY = 2.7769f; private const float ySpacing = 1.2505f; private const float toggleStartX = 4.3241f; private const float toggleStartY = -0.9746f; private static List AvailableLanguages; private static List AvailableToggles; private const int LanguagesPerPage = 5; private static int currentPage = 0; public static OptionBtn[] buttonSlots = new OptionBtn[6]; // 5 language buttons + 1 next button public static OptionBtn[] toggleSlots = new OptionBtn[3]; 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.tag = "LangOpt"; foreach(Transform child in newButton.GetComponentsInChildren()) { child.tag = "LangOpt"; } 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(); } public static void CreateToggleButtons(OptionBtn templateButton) { if (togglesCreated) return; togglesCreated = true; cachedTemplateToggleButton = templateButton; AvailableToggles = Enum.GetValues(typeof(Utils.ToggleEnum)) .Cast() .Where(lang => lang != Utils.ToggleEnum.TOGGLE_END) .ToList(); for (int i = 0; i < 3; i++) { var newButton = Object.Instantiate(templateButton, templateButton.transform.parent); newButton.tag = "LangOpt"; foreach(Transform child in newButton.GetComponentsInChildren()) { child.tag = "LangOpt"; } newButton.optionType = 100 + i; float yPos = toggleStartY - i * ySpacing; Vector3 pos = new(toggleStartX, yPos); newButton.transform.position = pos; toggleSlots[i] = newButton; ToggleBtnDict[newButton.GetInstanceID()] = new OptionButtonData { Button = newButton, Position = pos }; } UpdatePage(); } private static void UpdatePage() { int startIndex = currentPage * LanguagesPerPage; int langCount = AvailableLanguages.Count; int toggleCount = (togglesCreated) ? AvailableToggles.Count : 0; 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, Utils.LanguageNames[lang], FontStore.LoadTMPFont(lang.ToString())); } else { data.Language = null; data.IsNextButton = false; btn.gameObject.SetActive(false); } } if (togglesCreated) { for (int i = 0; i < 3; i++) { var btn = toggleSlots[i]; var data = ToggleBtnDict[btn.GetInstanceID()]; if (i < toggleCount) { var toggle = AvailableToggles[i]; data.Toggle = toggle; data.IsNextButton = false; btn.gameObject.SetActive(true); string buttonText = Utils.ToggleNames[toggle]; UpdateButtonText(btn, StringStore.TranslateText(buttonText), FontStore.LoadTMPFont(Utils.Language.ToString())); string sourceMsg = ""; switch(i) { case 0: sourceMsg = "" + (!(Utils.customTextures) ? "Texture Source:\nDefault" : "Texture Source:\nCustom"); FlashMessage(btn, sourceMsg, 0.1f, false); break; case 1: sourceMsg = "" + (!(Utils.customAudio) ? "Audio Source:\nDefault" : "Audio Source:\nCustom"); FlashMessage(btn, sourceMsg, 0.1f, false); break; case 2: sourceMsg = "" + (!(Utils.useLocal) ? "Translation Source:\nOnline" : "Translation Source:\nLocal"); FlashMessage(btn, sourceMsg, 0.1f, false); break; default: break; } } else { 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 fontAsset = null) { 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 = (fontAsset != null) ? fontAsset : defaultAsset; text.autoSizeTextContainer = false; } } } } public static void FlashMessage(OptionBtn button, string message, float yShift = 0.0f, bool useTimer = true) { var child = button.transform.GetChild(0); if (child != null) { var text = child.GetComponent(); string originalMsg = ""; if (text != null) { originalMsg = text.text; text.text = message; OptionButtonData data; bool isToggle = ToggleBtnDict.TryGetValue(button.GetInstanceID(), out data); if(isToggle) { text.transform.position = new Vector3(text.transform.position.x, text.transform.position.y + (ToggleBtnDict[button.GetInstanceID()].shifted ? 0.0f : yShift), text.transform.position.z); ToggleBtnDict[button.GetInstanceID()].shifted = true; } else { text.transform.position = new Vector3(text.transform.position.x, text.transform.position.y + (LanguageBtnDict[button.GetInstanceID()].shifted ? 0.0f : yShift), text.transform.position.z); LanguageBtnDict[button.GetInstanceID()].shifted = true; } } child.gameObject.SetActive(true); if(useTimer) { System.Threading.Tasks.Task.Delay(1000).ContinueWith(_ => { if (button != null && child != null && child.gameObject.activeSelf) { OptionButtonData buttonData = ToggleBtnDict[button.GetInstanceID()]; if(buttonData.Toggle != null) { string sourceMsg = originalMsg; switch(buttonData.Toggle) { case Utils.ToggleEnum.Textures: sourceMsg = "" + (!(Utils.customTextures) ? "Texture Source:\nDefault" : "Texture Source:\nCustom"); break; case Utils.ToggleEnum.Audio: sourceMsg = "" + (!(Utils.customAudio) ? "Audio Source:\nDefault" : "Audio Source:\nCustom"); break; default: break; } text.text = sourceMsg; } } }); } } } private static void ToggleCustomAssets(string type) { if (type != "Textures" && type != "Audio" && type != "SwapLocal") return; if(type == "Textures") { Utils.customTextures = !Utils.customTextures; MelonPreferences.SetEntryValue("PvZ_Fusion_Translator", "DefaultTextures", !Utils.customTextures); TextureStore.Reload(); object replaceTextureRoutine = MelonCoroutines.Start(TextureStore.ReplaceTexturesCoroutine()); } if (type == "Audio") { Utils.customAudio = (Utils.customAudio) ? false : true; MelonPreferences.SetEntryValue("PvZ_Fusion_Translator", "DefaultAudio", !Utils.customAudio); } if (type == "SwapLocal") { Utils.WarnLocalData(); } MelonPreferences.Save(); } [HarmonyPatch(typeof(OptionBtn))] public static class OptLangBtn_Patch { public static void Awake(OptionBtn __instance) { if (!buttonsCreated || cachedTemplateButton == null) { buttonsCreated = false; togglesCreated = false; CreateLanguageButtons(__instance); CreateToggleButtons(__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!"); } } } if (ToggleBtnDict.TryGetValue(__instance.GetInstanceID(), out var toggleData)) { string toggleType = toggleData.Toggle.ToString(); ToggleCustomAssets(toggleType); if (toggleType == "Textures") { FlashMessage(toggleData.Button, "Toggled custom textures!\n(Restart Required)", 0.1f); } else if (toggleType == "Audio") { FlashMessage(toggleData.Button, "Toggled custom audio!", 0.1f); } } } [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; } if (ToggleBtnDict.TryGetValue(__instance.GetInstanceID(), out var toggleData)) { toggleData.Button.transform.position = toggleData.Position; } } } } } #endif