317 lines
9.8 KiB
C#
317 lines
9.8 KiB
C#
using HarmonyLib;
|
|
using PvZ_Fusion_Translator.AssetStore;
|
|
using System.Text.Encodings.Web;
|
|
using System.Text.Json;
|
|
|
|
namespace PvZ_Fusion_Translator.Patches.Modes.Super_Editor.GameLevel;
|
|
|
|
[HarmonyPatch(typeof(LevelManager))]
|
|
public static class LevelManager_Patch
|
|
{
|
|
[HarmonyPatch(nameof(LevelManager.SaveLevelData)), HarmonyPrefix]
|
|
public static void Pre_SaveLevelData(LevelManager __instance, ref SerializedLevelData serializedLevelData)
|
|
{
|
|
if (serializedLevelData.name == "未命名关卡")
|
|
serializedLevelData.name = StringStore.TranslationString.ContainsKey("LEVEL_UNNAMED")
|
|
? StringStore.TranslateText("LEVEL_UNNAMED")
|
|
: "Unnamed";
|
|
}
|
|
|
|
public static void ExportLevelStrings(SerializedLevelData serializedLevelData)
|
|
{
|
|
var levelDataString = JsonUtility.ToJson(serializedLevelData);
|
|
var referenceLevelData = Newtonsoft.Json.JsonConvert.DeserializeObject<ReferenceLevelData>(levelDataString);
|
|
var eventNodeGraph = serializedLevelData.eventNodeGraph;
|
|
eventNodeGraph.BuildCache();
|
|
|
|
var stringValueNodeIds = new List<string>();
|
|
var stringConcatNodeIds = new List<string>();
|
|
var showTextNodeIds = new List<string>();
|
|
var addOptionNodeIds = new List<string>();
|
|
|
|
foreach (var reference in referenceLevelData.References.RefIds)
|
|
{
|
|
var nodeType = reference.Data.NodeType;
|
|
var nodeId = reference.Data.NodeId;
|
|
|
|
switch (nodeType)
|
|
{
|
|
case "ShowTextNode":
|
|
if (!showTextNodeIds.Contains(nodeId))
|
|
showTextNodeIds.Add(nodeId);
|
|
|
|
break;
|
|
case "AddMultipleChoiceOptionNode":
|
|
if (!addOptionNodeIds.Contains(nodeId))
|
|
addOptionNodeIds.Add(nodeId);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach (var reference in referenceLevelData.References.RefIds)
|
|
{
|
|
var nodeType = reference.Data.NodeType;
|
|
var nodeId = reference.Data.NodeId;
|
|
|
|
switch (nodeType)
|
|
{
|
|
case "StringValueNode":
|
|
case "FloatToStringNode":
|
|
case "StringConcatNode":
|
|
stringValueNodeIds.Add(nodeId);
|
|
|
|
if (nodeType == "StringConcatNode")
|
|
stringConcatNodeIds.Add(nodeId);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Dictionary<string, ValueTuple<string, string>> stringConcatNodePairs = new();
|
|
|
|
foreach (var connection in eventNodeGraph.connections)
|
|
{
|
|
var sourceNodeId = connection.sourceNodeId;
|
|
_ = connection.sourcePortName;
|
|
var targetNodeId = connection.targetNodeId;
|
|
var targetPortName = connection.targetPortName;
|
|
|
|
if (!stringValueNodeIds.Contains(sourceNodeId))
|
|
continue;
|
|
|
|
if (!stringConcatNodeIds.Contains(targetNodeId))
|
|
continue;
|
|
|
|
if (stringConcatNodePairs.ContainsKey(targetNodeId))
|
|
{
|
|
var temp = stringConcatNodePairs[targetNodeId];
|
|
|
|
switch (targetPortName)
|
|
{
|
|
case "A":
|
|
temp.Item1 = sourceNodeId;
|
|
stringConcatNodePairs[targetNodeId] = temp;
|
|
break;
|
|
case "B":
|
|
temp.Item2 = sourceNodeId;
|
|
stringConcatNodePairs[targetNodeId] = temp;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stringConcatNodePairs.Add(targetNodeId, new());
|
|
var temp = stringConcatNodePairs[targetNodeId];
|
|
|
|
switch (targetPortName)
|
|
{
|
|
case "A":
|
|
temp.Item1 = sourceNodeId;
|
|
stringConcatNodePairs[targetNodeId] = temp;
|
|
break;
|
|
case "B":
|
|
temp.Item2 = sourceNodeId;
|
|
stringConcatNodePairs[targetNodeId] = temp;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
string GetStringNodeValue(EventNodeBase eventNodeBase)
|
|
{
|
|
var stringValue = "";
|
|
|
|
switch (eventNodeBase.nodeType)
|
|
{
|
|
case "StringValueNode":
|
|
var stringNode = eventNodeBase.Cast<StringValueNode>();
|
|
stringValue = stringNode.value;
|
|
break;
|
|
case "FloatToStringNode":
|
|
stringValue = "([^\\s]+)";
|
|
break;
|
|
case "StringConcatNode":
|
|
var stringConcatNode = eventNodeBase.Cast<StringConcatNode>();
|
|
stringConcatNode.InitializeConnections(eventNodeGraph);
|
|
|
|
stringValue = GetStringNodeValue(stringConcatNode.aSourceNode) +
|
|
GetStringNodeValue(stringConcatNode.bSourceNode);
|
|
|
|
break;
|
|
}
|
|
|
|
return stringValue;
|
|
}
|
|
|
|
var baseDumpDir = FileLoader.GetAssetDir(FileLoader.AssetType.Dumps);
|
|
var levelDumpDir = Path.Combine(baseDumpDir, "CustomLevels.json");
|
|
|
|
if (!File.Exists(levelDumpDir))
|
|
File.WriteAllText(levelDumpDir, "{}");
|
|
|
|
var dump = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText(levelDumpDir));
|
|
|
|
foreach (var showTextNode in showTextNodeIds
|
|
.Select(showTextNodeId => eventNodeGraph.GetNodeById(showTextNodeId).Cast<ShowTextNode>()))
|
|
{
|
|
showTextNode.InitializeConnections(eventNodeGraph);
|
|
var value = GetStringNodeValue(showTextNode.textSourceNode);
|
|
dump.TryAdd(value, value);
|
|
}
|
|
|
|
foreach (var addOptionNode in addOptionNodeIds.Select(
|
|
addOptionId => eventNodeGraph.GetNodeById(addOptionId).Cast<AddMultipleChoiceOptionNode>()
|
|
))
|
|
{
|
|
addOptionNode.InitializeConnections(eventNodeGraph);
|
|
var titleValue = GetStringNodeValue(addOptionNode.titleSourceNode);
|
|
dump.TryAdd(titleValue, titleValue);
|
|
var descriptionValue = GetStringNodeValue(addOptionNode.descriptionSourceNode);
|
|
dump.TryAdd(descriptionValue, descriptionValue);
|
|
}
|
|
|
|
File.WriteAllText(
|
|
levelDumpDir,
|
|
JsonSerializer.Serialize(
|
|
dump,
|
|
new JsonSerializerOptions
|
|
{
|
|
WriteIndented = true,
|
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
// Reference level data classes.
|
|
public sealed class ReferenceLevelData
|
|
{
|
|
public References References { get; set; }
|
|
}
|
|
|
|
// ReSharper disable once ClassNeverInstantiated.Global
|
|
public sealed class Data
|
|
{
|
|
public string NodeId { get; set; }
|
|
|
|
public string NodeType { get; set; }
|
|
|
|
public Position Position { get; set; }
|
|
|
|
public string NodeName { get; set; }
|
|
|
|
public string PlantPortName { get; set; }
|
|
|
|
public string ColumnPortName { get; set; }
|
|
|
|
public string RowPortName { get; set; }
|
|
|
|
public string PlantTypePortName { get; set; }
|
|
|
|
public object Value { get; set; }
|
|
|
|
public string ValuePortName { get; set; }
|
|
|
|
public string PlantTypeAPortName { get; set; }
|
|
|
|
public string PlantTypeBPortName { get; set; }
|
|
|
|
public string EqualPortName { get; set; }
|
|
|
|
public string TriggerPortName { get; set; }
|
|
|
|
public string CountPortName { get; set; }
|
|
|
|
public string OutputPortName { get; set; }
|
|
|
|
public string IndexPortName { get; set; }
|
|
|
|
public string PlantsPortName { get; set; }
|
|
|
|
public string PlantListPortName { get; set; }
|
|
|
|
public string LoopBodyPortName { get; set; }
|
|
|
|
public string CurrentPlantPortName { get; set; }
|
|
|
|
public string CurrentIndexPortName { get; set; }
|
|
|
|
public string OnCompletedPortName { get; set; }
|
|
|
|
public string ConditionPortName { get; set; }
|
|
|
|
public string ThenPortName { get; set; }
|
|
|
|
public string ElsePortName { get; set; }
|
|
|
|
public string APortName { get; set; }
|
|
|
|
public string BPortName { get; set; }
|
|
|
|
public string ResultPortName { get; set; }
|
|
|
|
public string ShouldResetPortName { get; set; }
|
|
|
|
public string OnCountPortName { get; set; }
|
|
|
|
public int? StartValue { get; set; }
|
|
|
|
public string ValueAPortName { get; set; }
|
|
|
|
public string ValueBPortName { get; set; }
|
|
|
|
public string GreaterPortName { get; set; }
|
|
|
|
public string LessPortName { get; set; }
|
|
|
|
public string DisplayText { get; set; }
|
|
|
|
public double? Duration { get; set; }
|
|
|
|
public string TextPortName { get; set; }
|
|
|
|
public string DurationPortName { get; set; }
|
|
|
|
public string INTPortName { get; set; }
|
|
|
|
public string FloatPortName { get; set; }
|
|
}
|
|
|
|
// ReSharper disable once ClassNeverInstantiated.Global
|
|
public sealed class Position
|
|
{
|
|
public double X { get; set; }
|
|
|
|
public double Y { get; set; }
|
|
}
|
|
|
|
// ReSharper disable once ClassNeverInstantiated.Global
|
|
public sealed class References
|
|
{
|
|
public int Version { get; set; }
|
|
|
|
// ReSharper disable once CollectionNeverUpdated.Global
|
|
public List<RefId> RefIds { get; set; }
|
|
}
|
|
|
|
// ReSharper disable once ClassNeverInstantiated.Global
|
|
public sealed class RefId
|
|
{
|
|
public int Rid { get; set; }
|
|
|
|
public Type Type { get; set; }
|
|
|
|
public Data Data { get; set; }
|
|
}
|
|
|
|
// ReSharper disable once ClassNeverInstantiated.Global
|
|
public sealed class Type
|
|
{
|
|
public string Class { get; set; }
|
|
|
|
public string Ns { get; set; }
|
|
|
|
public string ASM { get; set; }
|
|
}
|
|
}
|