Merge branch 'cassidy'

This commit is contained in:
SillyStar-Github 2026-05-15 18:12:40 -04:00
commit c5720a02ca
9 changed files with 486 additions and 158 deletions

View file

@ -14,6 +14,10 @@ namespace PvZ_Fusion_Translator.AssetStore
public static Dictionary<string, string> translationString = new();
public static Dictionary<string, string> customLevelStringRegex = new();
public static Dictionary<string, string> customLevelString = new();
public static Dictionary<string, string> izLevelTipDictionary = new();
public static Dictionary<string, string> 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<string> dynamicParts = [];
// List to hold formatted dynamic parts
List<string> 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<string> 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<string> 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))

View file

@ -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<string, string> dictionary = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(content);
foreach (var (key, value) in dictionary)
{
StringStore.customLevelString[key] = value;
}
}
internal static void LoadCustomLevelRegexs(string content)
{
Dictionary<string, string> dictionary = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(content);
foreach (var (key, value) in dictionary)
{
StringStore.customLevelStringRegex[key] = value;
}
}
internal static void LoadIZStrings(string content)
{
var izDump = DumpIZStrings();

View file

@ -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<CustomMenu>();
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<ModType, ModFeature> 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)}
};

View file

@ -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, @"(<color[^>]*>.*?</color>)", 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, @"(<color[^>]*>.*?</color>)", 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;
}
}
}

View file

@ -27,7 +27,14 @@ namespace PvZ_Fusion_Translator.Patches.Modes.Odyssey
foreach(TextMeshProUGUI txt in window.GetComponentsInChildren<TextMeshProUGUI>())
{
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);
}
}
}
}

View file

@ -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<ReferenceLevelData>(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<object> 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<RefId> 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; }
}*/
}

View file

@ -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")

View file

@ -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<ReferenceLevelData>(levelDataString);
EventNodeGraph eventNodeGraph = serializedLevelData.eventNodeGraph;
eventNodeGraph.BuildCache();
List<string> stringValueNodeIds = new List<string>();
List<string> stringConcatNodeIds = new List<string>();
List<string> showTextNodeIds = new List<string>();
List<string> addOptionNodeIds = new List<string>();
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<string, ValueTuple<string, string>> 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<string, string> 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<string, string>());
ValueTuple<string, string> 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<StringValueNode>();
stringValue = stringNode.value;
break;
case "FloatToStringNode":
stringValue = "([^\\s]+)";
break;
case "StringConcatNode":
StringConcatNode stringConcatNode = eventNodeBase.TryCast<StringConcatNode>();
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<string, string> dump = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(levelDumpDir));
foreach(string showTextNodeId in showTextNodeIds)
{
ShowTextNode showTextNode = eventNodeGraph.GetNodeById(showTextNodeId).TryCast<ShowTextNode>();
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<AddMultipleChoiceOptionNode>();
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<RefId> 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; }
}
}
}

View file

@ -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, "українська"},