diff --git a/MelonLoader/AssetStore/StringStore.cs b/MelonLoader/AssetStore/StringStore.cs index 270059e..9c6f39c 100644 --- a/MelonLoader/AssetStore/StringStore.cs +++ b/MelonLoader/AssetStore/StringStore.cs @@ -14,6 +14,10 @@ namespace PvZ_Fusion_Translator.AssetStore public static Dictionary translationString = new(); + public static Dictionary customLevelStringRegex = new(); + + public static Dictionary customLevelString = new(); + public static Dictionary izLevelTipDictionary = new(); public static Dictionary izTipCollectionString = new(); @@ -80,6 +84,8 @@ namespace PvZ_Fusion_Translator.AssetStore { translationString.Clear(); translationStringRegex.Clear(); + customLevelString.Clear(); + customLevelStringRegex.Clear(); izLevelTipDictionary.Clear(); izTipCollectionString.Clear(); fsLevelTipDictionary.Clear(); @@ -158,37 +164,70 @@ namespace PvZ_Fusion_Translator.AssetStore public static string TranslateText(string originalText, string pattern, bool isLog = false) { - if (TestRegex(originalText, pattern) && translationStringRegex.ContainsKey(pattern)) - { - // Extract dynamic parts from the original text - var regex = new Regex(pattern); - var match = regex.Match(originalText); - int groupCount = match.Groups.Count; + if (TestRegex(originalText, pattern)) + { + if(translationStringRegex.ContainsKey(pattern)) + { + // Extract dynamic parts from the original text + var regex = new Regex(pattern); + var match = regex.Match(originalText); + int groupCount = match.Groups.Count; - if (isLog) - Log.LogDebug("Text found in translationStringRegex {0}: {1}", match, groupCount); + if (isLog) + Log.LogDebug("Text found in translationStringRegex {0}: {1}", match, groupCount); - // List to hold formatted dynamic parts - List dynamicParts = []; + // 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); - } + // 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(translationStringRegex[pattern], [.. dynamicParts]); - } + // Format the output string with dynamic parts + return string.Format(translationStringRegex[pattern], [.. dynamicParts]); + } + else if(customLevelStringRegex.ContainsKey(pattern)) + { + // Extract dynamic parts from the original text + var regex = new Regex(pattern); + var match = regex.Match(originalText); + int groupCount = match.Groups.Count; + + if (isLog) + Log.LogDebug("Text found in customLevelStringRegex {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 = customLevelString.ContainsKey(groupValue) + ? customLevelString[groupValue] + : groupValue; + dynamicParts.Add(translatedValue); + } + + // Format the output string with dynamic parts + return string.Format(customLevelStringRegex[pattern], [.. dynamicParts]); + } + else + { + return originalText; + } + } else { - if (isLog) - Log.LogDebug($"Text '{originalText}' not translated"); - FileLoader.DumpUntranslatedStrings(originalText); + if (isLog) + Log.LogDebug($"Text '{originalText}' not translated"); + FileLoader.DumpUntranslatedStrings(originalText); return originalText; } } @@ -228,6 +267,15 @@ namespace PvZ_Fusion_Translator.AssetStore return fsTipCollectionString[originalText]; } + if(customLevelString.ContainsKey(originalText)) + { + if(isLog) + { + Log.LogDebug($"Text '{originalText}' found in customLevelString"); + } + return customLevelString[originalText]; + } + // Regex-based dynamic translation foreach (var entry in translationStringRegex) { @@ -259,6 +307,36 @@ namespace PvZ_Fusion_Translator.AssetStore } } + foreach (var entry in customLevelStringRegex) + { + if (TestRegex(originalText, entry.Key)) + { + // Extract dynamic parts from the original text + var regex = new Regex(entry.Key); + var match = regex.Match(originalText); + int groupCount = match.Groups.Count; + + if (isLog) + Log.LogDebug("Text found in customLevelRegex {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 = customLevelString.ContainsKey(groupValue) + ? customLevelString[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"); if(Utils.CheckForUntranslatedText(originalText)) diff --git a/MelonLoader/FileLoader.cs b/MelonLoader/FileLoader.cs index 59356de..d838940 100644 --- a/MelonLoader/FileLoader.cs +++ b/MelonLoader/FileLoader.cs @@ -80,6 +80,37 @@ namespace PvZ_Fusion_Translator } } + string customLevelStringsContent = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Strings/customlevel_strings.json").Result; + + if(customLevelStringsContent != null) + { + LoadCustomLevelStrings(customLevelStringsContent); + } + else + { + string customLevelStringsPath = Path.Combine(GetAssetDir(AssetType.Strings, Utils.Language), "customlevel_strings.json"); + if(File.Exists(customLevelStringsPath)) + { + LoadCustomLevelStrings(File.ReadAllText(customLevelStringsPath)); + } + } + + // load translationRegexs + string customLevelRegexsContent = Utils.GetDataFromWeb($"https://raw.githubusercontent.com/Teyliu/PVZF-Translation/refs/heads/main/PvZ_Fusion_Translator/Localization/{Utils.Language.ToString()}/Strings/customlevel_regexs.json").Result; + + if(customLevelRegexsContent != null) + { + LoadCustomLevelRegexs(customLevelRegexsContent); + } + else + { + string customLevelRegexsPath = Path.Combine(GetAssetDir(AssetType.Strings, Utils.Language), "customlevel_regexs.json"); + if(File.Exists(customLevelRegexsPath)) + { + LoadCustomLevelRegexs(File.ReadAllText(customLevelRegexsPath)); + } + } + // load changelog LoadChangelogText(); @@ -200,14 +231,22 @@ namespace PvZ_Fusion_Translator Log.LogInfo("Loading File : " + filepath); #endif string jsonString = File.ReadAllText(filepath); - if (fileName.EndsWith("_strings")) + if (fileName.EndsWith("translation_strings")) { LoadTranslationStrings(jsonString); } - else if (fileName.EndsWith("_regexs")) + else if (fileName.EndsWith("translation_regexs")) { LoadTranslationRegexs(jsonString); } + else if (fileName.EndsWith("customlevel_strings")) + { + LoadCustomLevelStrings(jsonString); + } + else if (fileName.EndsWith("customlevel_regexs")) + { + LoadCustomLevelRegexs(jsonString); + } else if(fileName.EndsWith("tips_iz")) { LoadIZStrings(jsonString); @@ -280,6 +319,24 @@ namespace PvZ_Fusion_Translator Zombie_Patch.LoadHPStrings(); } + internal static void LoadCustomLevelStrings(string content) + { + Dictionary dictionary = System.Text.Json.JsonSerializer.Deserialize>(content); + foreach (var (key, value) in dictionary) + { + StringStore.customLevelString[key] = value; + } + } + + internal static void LoadCustomLevelRegexs(string content) + { + Dictionary dictionary = System.Text.Json.JsonSerializer.Deserialize>(content); + foreach (var (key, value) in dictionary) + { + StringStore.customLevelStringRegex[key] = value; + } + } + internal static void LoadIZStrings(string content) { var izDump = DumpIZStrings(); diff --git a/MelonLoader/ModFeatures.cs b/MelonLoader/ModFeatures.cs index 37054bb..ca2703b 100644 --- a/MelonLoader/ModFeatures.cs +++ b/MelonLoader/ModFeatures.cs @@ -1,4 +1,6 @@ //#if DEBUG +using Il2Cpp; +using Il2CppGameLevel; using PvZ_Fusion_Translator.AssetStore; using PvZ_Fusion_Translator.Patches.Modes.Super_Editor; using UnityEngine; @@ -10,7 +12,8 @@ namespace PvZ_Fusion_Translator public enum ModType { ReloadStrings, - ReloadTextures + ReloadTextures, + ExportLevelStrings } private class ModFeature @@ -43,13 +46,26 @@ namespace PvZ_Fusion_Translator Core.ShowToast("Textures Reloaded!"); return; } + + if (this.ModType == ModType.ExportLevelStrings) + { + CustomMenu customMenu = UnityEngine.Object.FindObjectOfType(); + if (!customMenu) return; + if(customMenu.isActiveAndEnabled) + { + Patches.Modes.Super_Editor.GameLevel.LevelManager_Patch.ExportLevelStrings(customMenu.LevelData); + Core.ShowToast("Dumped level strings!"); + } + return; + } } } private static 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)} + {ModType.ReloadTextures,new ModFeature("Reload Textures",ModType.ReloadTextures,KeyCode.End, true)}, + {ModType.ExportLevelStrings,new ModFeature("Export Level Strings",ModType.ExportLevelStrings,KeyCode.N, true)} }; diff --git a/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs b/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs index 87eb32b..3b77165 100644 --- a/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs +++ b/MelonLoader/Patches/BaseTextObjects/InGameText_Patch.cs @@ -73,6 +73,7 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects int godsGachaCheck = CheckGodsGachaPopup(originalText); string godsGachaMatch = ""; string superEditorPlantMatch = CheckSuperEditorPopup(originalText); + string customLevelRegexMatch = CheckCustomLevelRegex(originalText); switch(godsGachaCheck) { @@ -119,7 +120,15 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects { txt.text = lockedPlantMatch; } - else if((Regex.Match(txt.text, @"(]*>.*?)", RegexOptions.Singleline).Success) && (!StringStore.translationString.ContainsKey(txt.text) && !StringStore.fsTipCollectionString.ContainsKey(txt.text) && !StringStore.izTipCollectionString.ContainsKey(txt.text))) + else if(customLevelRegexMatch != "") + { + txt.text = customLevelRegexMatch; + } + else if((Regex.Match(txt.text, @"(]*>.*?)", RegexOptions.Singleline).Success) && + !StringStore.translationString.ContainsKey(txt.text) && + !StringStore.fsTipCollectionString.ContainsKey(txt.text) && + !StringStore.izTipCollectionString.ContainsKey(txt.text) && + !StringStore.customLevelString.ContainsKey(txt.text)) { txt.text = StringStore.TranslateColorText(txt.text, true); if (txt.gameObject.name.Contains("main")) @@ -348,5 +357,19 @@ namespace PvZ_Fusion_Translator.Patches.BaseTextObjects return res; } + + public static string CheckCustomLevelRegex(string originalText) + { + string res = ""; + + foreach(var pair in StringStore.customLevelStringRegex) + { + if(StringStore.TestRegex(originalText, pair.Key)) + { + res = StringStore.TranslateText(originalText, pair.Key); + } + } + return res; + } } } \ No newline at end of file diff --git a/MelonLoader/Patches/Modes/Odyssey/MultipleChoiceMenu_Patch.cs b/MelonLoader/Patches/Modes/Odyssey/MultipleChoiceMenu_Patch.cs index 4b4f61c..acd06b3 100644 --- a/MelonLoader/Patches/Modes/Odyssey/MultipleChoiceMenu_Patch.cs +++ b/MelonLoader/Patches/Modes/Odyssey/MultipleChoiceMenu_Patch.cs @@ -27,7 +27,14 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey foreach(TextMeshProUGUI txt in window.GetComponentsInChildren()) { txt.font = fontAsset; - txt.text = StringStore.translationString.ContainsKey(txt.text + "_MC") ? StringStore.TranslateText(txt.text + "_MC") : StringStore.TranslateText(txt.text); + if(StringStore.customLevelString.ContainsKey(txt.text)) + { + txt.text = StringStore.customLevelString[txt.text]; + } + else + { + txt.text = StringStore.translationString.ContainsKey(txt.text + "_MC") ? StringStore.TranslateText(txt.text + "_MC") : StringStore.TranslateText(txt.text); + } } } } diff --git a/MelonLoader/Patches/Modes/Super Editor/CustomButton_enterGame_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/CustomButton_enterGame_Patch.cs index aea1f43..a99986d 100644 --- a/MelonLoader/Patches/Modes/Super Editor/CustomButton_enterGame_Patch.cs +++ b/MelonLoader/Patches/Modes/Super Editor/CustomButton_enterGame_Patch.cs @@ -69,7 +69,15 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor else { TranslatedLevelData dumpedLevelData = new TranslatedLevelData(level.onlineLevelInfo.levelName, serializedLevel.boardConfig.startTip); - dumpData.Add(levelId, dumpedLevelData); + + if (dumpData.ContainsKey(levelId)) + { + dumpData[levelId] = dumpedLevelData; + } + else + { + dumpData.Add(levelId, dumpedLevelData); + } } /*level.levelData.SerializedLevelData @@ -93,123 +101,4 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor })); } } - - /*[HarmonyPatch(typeof(LevelManager))] - public static class Test - { - [HarmonyPatch(nameof(LevelManager.SaveLevelData))] - [HarmonyPostfix] - public static void SaveLevelData(LevelManager __instance, ref SerializedLevelData serializedLevelData) - { - Log.LogDebug("hi 2"); - string json = JsonUtility.ToJson(serializedLevelData); - ReferenceLevelData references = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - foreach(var reference in references.references.RefIds) - { - ReferenceLevelData.Data nodeData = reference.data; - string nodeType = nodeData.nodeType; - - if(nodeType == "StringConcatNode") - { - Log.LogDebug(nodeData.value.ToString()); - } - - if(nodeType == "StringValueNode") - { - Log.LogDebug(nodeData.value.ToString()); - } - } - } - } - - - - public class ReferenceLevelData - { - public class Data - { - public string nodeId { get; set; } - public string nodeType { get; set; } - public Position position { get; set; } - public string nodeName { get; set; } - public string plant_PortName { get; set; } - public string column_PortName { get; set; } - public string row_PortName { get; set; } - public string plantType_PortName { get; set; } - public object value { get; set; } - public string value_PortName { get; set; } - public string plantTypeA_PortName { get; set; } - public string plantTypeB_PortName { get; set; } - public string equal_PortName { get; set; } - public string trigger_PortName { get; set; } - public string count_PortName { get; set; } - public string output_PortName { get; set; } - public string index_PortName { get; set; } - public string plants_PortName { get; set; } - public string plantList_PortName { get; set; } - public string loopBody_PortName { get; set; } - public string currentPlant_PortName { get; set; } - public string currentIndex_PortName { get; set; } - public string onCompleted_PortName { get; set; } - public string condition_PortName { get; set; } - public string then_PortName { get; set; } - public string else_PortName { get; set; } - public string a_PortName { get; set; } - public string b_PortName { get; set; } - public string result_PortName { get; set; } - public string shouldReset_PortName { get; set; } - public string onCount_PortName { get; set; } - public int? startValue { get; set; } - public string valueA_PortName { get; set; } - public string valueB_PortName { get; set; } - public string greater_PortName { get; set; } - public string less_PortName { get; set; } - public string displayText { get; set; } - public double? duration { get; set; } - public string text_PortName { get; set; } - public string duration_PortName { get; set; } - public string int_PortName { get; set; } - public string float_PortName { get; set; } - } - - public class GodShootingConfig - { - public List plants { get; set; } - } - - public class Position - { - public double x { get; set; } - public double y { get; set; } - } - - public class References - { - public int version { get; set; } - public List RefIds { get; set; } - } - - public class RefId - { - public int rid { get; set; } - public Type type { get; set; } - public Data data { get; set; } - } - - public class Type - { - public string @class { get; set; } - public string ns { get; set; } - public string asm { get; set; } - } - - public class ZombiesWithRow - { - public int zombieType { get; set; } - public int row { get; set; } - } - - public EventNodeGraph eventNodeGraph { get; set; } - public References references { get; set; } - }*/ } \ No newline at end of file diff --git a/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeNodeUI_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeNodeUI_Patch.cs index f197ac5..bcf303d 100644 --- a/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeNodeUI_Patch.cs +++ b/MelonLoader/Patches/Modes/Super Editor/GameLevel/EventNodes/RuntimeNodeUI_Patch.cs @@ -26,6 +26,8 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel.EventNodes [HarmonyPostfix] public static void Awake(RuntimeNodeUI __instance) { + if (!__instance.isActiveAndEnabled) return; + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); if(__instance.dropdownPrefab) @@ -56,6 +58,8 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel.EventNodes [HarmonyPostfix] public static void UpdateDisplay(RuntimeNodeUI __instance) { + if (!__instance.isActiveAndEnabled) return; + TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString()); if(__instance.Node.nodeType == "PlantTypeValueNode") diff --git a/MelonLoader/Patches/Modes/Super Editor/GameLevel/LevelManager_Patch.cs b/MelonLoader/Patches/Modes/Super Editor/GameLevel/LevelManager_Patch.cs index 5c620ad..57b919a 100644 --- a/MelonLoader/Patches/Modes/Super Editor/GameLevel/LevelManager_Patch.cs +++ b/MelonLoader/Patches/Modes/Super Editor/GameLevel/LevelManager_Patch.cs @@ -1,12 +1,16 @@ -using System; +using HarmonyLib; +using Il2Cpp; +using Il2CppGameLevel; +using Il2CppGameLevel.EventNodes; +using MelonLoader; +using PvZ_Fusion_Translator.AssetStore; +using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; using System.Threading.Tasks; -using HarmonyLib; -using Il2Cpp; -using Il2CppGameLevel; -using PvZ_Fusion_Translator.AssetStore; using UnityEngine; namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel @@ -18,10 +22,259 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel [HarmonyPrefix] public static void Pre_SaveLevelData(LevelManager __instance, ref SerializedLevelData serializedLevelData) { - if(serializedLevelData.name == "未命名关卡") + if (serializedLevelData.name == "未命名关卡") { serializedLevelData.name = StringStore.translationString.ContainsKey("LEVEL_UNNAMED") ? StringStore.TranslateText("LEVEL_UNNAMED") : "Unnamed"; } } + + public static void ExportLevelStrings(SerializedLevelData serializedLevelData) + { + string levelDataString = JsonUtility.ToJson(serializedLevelData); + ReferenceLevelData referenceLevelData = Newtonsoft.Json.JsonConvert.DeserializeObject(levelDataString); + EventNodeGraph eventNodeGraph = serializedLevelData.eventNodeGraph; + eventNodeGraph.BuildCache(); + + List stringValueNodeIds = new List(); + List stringConcatNodeIds = new List(); + List showTextNodeIds = new List(); + List addOptionNodeIds = new List(); + + foreach (var reference in referenceLevelData.references.RefIds) + { + string nodeType = reference.data.nodeType; + string nodeId = reference.data.nodeId; + + if (nodeType == "ShowTextNode") + { + if(!showTextNodeIds.Contains(nodeId)) + { + showTextNodeIds.Add(nodeId); + } + } + else if (nodeType == "AddMultipleChoiceOptionNode") + { + if(!addOptionNodeIds.Contains(nodeId)) + { + addOptionNodeIds.Add(nodeId); + } + } + } + + foreach (var reference in referenceLevelData.references.RefIds) + { + string nodeType = reference.data.nodeType; + string nodeId = reference.data.nodeId; + + switch(nodeType) + { + case "StringValueNode": + case "FloatToStringNode": + case "StringConcatNode": + stringValueNodeIds.Add(nodeId); + if(nodeType == "StringConcatNode") + { + stringConcatNodeIds.Add(nodeId); + } + break; + default: + break; + } + } + + Dictionary> stringConcatNodePairs = new(); + + foreach(var connection in eventNodeGraph.connections) + { + string sourceNodeId = connection.sourceNodeId; + string sourcePortName = connection.sourcePortName; + string targetNodeId = connection.targetNodeId; + string targetPortName = connection.targetPortName; + + if(stringValueNodeIds.Contains(sourceNodeId)) + { + if(stringConcatNodeIds.Contains(targetNodeId)) + { + if(stringConcatNodePairs.ContainsKey(targetNodeId)) + { + ValueTuple temp = stringConcatNodePairs[targetNodeId]; + switch(targetPortName) + { + case "A": + temp.Item1 = sourceNodeId; + stringConcatNodePairs[targetNodeId] = temp; + break; + case "B": + temp.Item2 = sourceNodeId; + stringConcatNodePairs[targetNodeId] = temp; + break; + default: + break; + } + } + else + { + stringConcatNodePairs.Add(targetNodeId, new ValueTuple()); + ValueTuple temp = stringConcatNodePairs[targetNodeId]; + switch(targetPortName) + { + case "A": + temp.Item1 = sourceNodeId; + stringConcatNodePairs[targetNodeId] = temp; + break; + case "B": + temp.Item2 = sourceNodeId; + stringConcatNodePairs[targetNodeId] = temp; + break; + default: + break; + } + } + } + } + } + + string GetStringNodeValue(EventNodeBase eventNodeBase) + { + string stringValue = ""; + + switch(eventNodeBase.nodeType) + { + case "StringValueNode": + StringValueNode stringNode = eventNodeBase.TryCast(); + stringValue = stringNode.value; + break; + case "FloatToStringNode": + stringValue = "([^\\s]+)"; + break; + case "StringConcatNode": + StringConcatNode stringConcatNode = eventNodeBase.TryCast(); + stringConcatNode.InitializeConnections(eventNodeGraph); + stringValue = GetStringNodeValue(stringConcatNode.aSourceNode) + GetStringNodeValue(stringConcatNode.bSourceNode); + break; + default: + break; + } + + return stringValue; + } + + string baseDumpDir = FileLoader.GetAssetDir(FileLoader.AssetType.Dumps); + string levelDumpDir = Path.Combine(baseDumpDir, "CustomLevels.json"); + if (!File.Exists(levelDumpDir)) File.WriteAllText(levelDumpDir, "{}"); + Dictionary dump = JsonSerializer.Deserialize>(File.ReadAllText(levelDumpDir)); + + foreach(string showTextNodeId in showTextNodeIds) + { + ShowTextNode showTextNode = eventNodeGraph.GetNodeById(showTextNodeId).TryCast(); + showTextNode.InitializeConnections(eventNodeGraph); + string value = GetStringNodeValue(showTextNode.textSourceNode); + if (!dump.ContainsKey(value)) + { + dump.Add(value, value); + } + } + + foreach(string addOptionId in addOptionNodeIds) + { + AddMultipleChoiceOptionNode addOptionNode = eventNodeGraph.GetNodeById(addOptionId).TryCast(); + addOptionNode.InitializeConnections(eventNodeGraph); + string titleValue = GetStringNodeValue(addOptionNode.titleSourceNode); + if (!dump.ContainsKey(titleValue)) + { + dump.Add(titleValue, titleValue); + } + string descriptionValue = GetStringNodeValue(addOptionNode.descriptionSourceNode); + if (!dump.ContainsKey(descriptionValue)) + { + dump.Add(descriptionValue, descriptionValue); + } + } + + File.WriteAllText(levelDumpDir, JsonSerializer.Serialize(dump, new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + })); + } + + // reference level data classes + + public class ReferenceLevelData + { + public References references { get; set; } + } + + public class Data + { + public string nodeId { get; set; } + public string nodeType { get; set; } + public Position position { get; set; } + public string nodeName { get; set; } + public string plant_PortName { get; set; } + public string column_PortName { get; set; } + public string row_PortName { get; set; } + public string plantType_PortName { get; set; } + public object value { get; set; } + public string value_PortName { get; set; } + public string plantTypeA_PortName { get; set; } + public string plantTypeB_PortName { get; set; } + public string equal_PortName { get; set; } + public string trigger_PortName { get; set; } + public string count_PortName { get; set; } + public string output_PortName { get; set; } + public string index_PortName { get; set; } + public string plants_PortName { get; set; } + public string plantList_PortName { get; set; } + public string loopBody_PortName { get; set; } + public string currentPlant_PortName { get; set; } + public string currentIndex_PortName { get; set; } + public string onCompleted_PortName { get; set; } + public string condition_PortName { get; set; } + public string then_PortName { get; set; } + public string else_PortName { get; set; } + public string a_PortName { get; set; } + public string b_PortName { get; set; } + public string result_PortName { get; set; } + public string shouldReset_PortName { get; set; } + public string onCount_PortName { get; set; } + public int? startValue { get; set; } + public string valueA_PortName { get; set; } + public string valueB_PortName { get; set; } + public string greater_PortName { get; set; } + public string less_PortName { get; set; } + public string displayText { get; set; } + public double? duration { get; set; } + public string text_PortName { get; set; } + public string duration_PortName { get; set; } + public string int_PortName { get; set; } + public string float_PortName { get; set; } + } + + public class Position + { + public double x { get; set; } + public double y { get; set; } + } + + public class References + { + public int version { get; set; } + public List RefIds { get; set; } + } + + public class RefId + { + public int rid { get; set; } + public Type type { get; set; } + public Data data { get; set; } + } + + public class Type + { + public string @class { get; set; } + public string ns { get; set; } + public string asm { get; set; } + } } } diff --git a/MelonLoader/Utils.cs b/MelonLoader/Utils.cs index 8e61ec0..b47ae57 100644 --- a/MelonLoader/Utils.cs +++ b/MelonLoader/Utils.cs @@ -549,7 +549,7 @@ namespace PvZ_Fusion_Translator //Javanese, //Filipino, Vietnamese, - //Indonesian, + Indonesian, //Russian, //NOTE: legacy language Japanese, @@ -574,6 +574,7 @@ namespace PvZ_Fusion_Translator { LanguageEnum.German, "Deutsch"}, { LanguageEnum.Spanish, "Español"}, { LanguageEnum.Vietnamese, "Tiếng Việt"}, + { LanguageEnum.Indonesian, "Bahasa Indonesia"}, { LanguageEnum.Japanese, "日本語"}, { LanguageEnum.Korean, "한국어"}, { LanguageEnum.Ukrainian, "українська"},