Files
AppleHillsProduction/Assets/Editor/Dialogue/DialogueGraphImporter.cs

327 lines
14 KiB
C#
Raw Normal View History

using UnityEngine;
using UnityEditor.AssetImporters;
using Unity.GraphToolkit.Editor;
using System;
using System.Collections.Generic;
using System.Linq;
using Dialogue;
using PuzzleS;
namespace Editor.Dialogue
{
[ScriptedImporter(1, DialogueGraph.AssetExtension)]
public class DialogueGraphImporter : ScriptedImporter
{
public override void OnImportAsset(AssetImportContext ctx)
{
DialogueGraph editorGraph = GraphDatabase.LoadGraphForImporter<DialogueGraph>(ctx.assetPath);
RuntimeDialogueGraph runtimeGraph = ScriptableObject.CreateInstance<RuntimeDialogueGraph>();
var nodeIDMap = new Dictionary<INode, string>();
// Generate stable GUIDs for each node
foreach (var node in editorGraph.GetNodes())
{
nodeIDMap[node] = Guid.NewGuid().ToString();
}
// Process start node to get entry point and speaker name
var startNode = editorGraph.GetNodes().OfType<StartNode>().FirstOrDefault();
if (startNode != null)
{
var entryPoint = startNode.GetOutputPorts().FirstOrDefault()?.firstConnectedPort;
if (entryPoint != null)
{
runtimeGraph.entryNodeID = nodeIDMap[entryPoint.GetNode()];
}
runtimeGraph.speakerName = GetPortValue<string>(startNode.GetInputPortByName("SpeakerName"));
}
// Process each node in the graph
foreach (var iNode in editorGraph.GetNodes())
{
if (iNode is StartNode || iNode is IVariableNode)
continue;
var runtimeNode = new RuntimeDialogueNode{ nodeID = nodeIDMap[iNode] };
// Process node based on its type
if (iNode is DialogueNode dialogueNode)
{
// Process base dialogue node properties (for all node types)
ProcessDialogueNodeBase(dialogueNode, runtimeNode);
if (iNode is WaitOnPuzzleStep puzzleNode)
{
ProcessPuzzleNode(puzzleNode, runtimeNode);
}
else if (iNode is WaitOnPickup pickupNode)
{
ProcessPickupNode(pickupNode, runtimeNode);
}
else if (iNode is WaitOnSlot slotNode)
{
ProcessSlotNode(slotNode, runtimeNode);
}
else if (iNode is WaitOnCombination combinationNode)
{
ProcessCombinationNode(combinationNode, runtimeNode);
}
}
else if (iNode is EndNode)
{
runtimeNode.nodeType = RuntimeDialogueNodeType.End;
// End nodes don't have next nodes, so we don't need to look for "out" ports
}
// Get next node connection (skip for EndNodes as they don't have out ports)
if (!(iNode is EndNode))
{
// Check if the node has output ports before trying to get one by name
var outputPorts = iNode.GetOutputPorts();
if (outputPorts != null && outputPorts.Any())
{
var outPort = outputPorts.FirstOrDefault(p => p.name == "out");
if (outPort != null && outPort.firstConnectedPort != null)
{
runtimeNode.nextNodeID = nodeIDMap[outPort.firstConnectedPort.GetNode()];
}
}
}
// Add node to runtime graph
runtimeGraph.allNodes.Add(runtimeNode);
}
ctx.AddObjectToAsset("RuntimeData", runtimeGraph);
ctx.SetMainObject(runtimeGraph);
Debug.Log($"Imported DialogueGraph with {runtimeGraph.allNodes.Count} nodes.");
}
private void ProcessDialogueNodeBase(DialogueNode node, RuntimeDialogueNode runtimeNode)
{
// Set default node type
runtimeNode.nodeType = RuntimeDialogueNodeType.Dialogue;
// Get line type and count options
var lineTypeOption = node.GetNodeOptionByName("DialogueLineType");
lineTypeOption.TryGetValue<DialogueType>(out var lineType);
var lineCountOption = node.GetNodeOptionByName("NoLines");
lineCountOption.TryGetValue<int>(out var lineCount);
// Process dialogue content
if (lineType == DialogueType.SayMultipleLines)
{
for (var i = 0; i < lineCount; i++)
{
var contentPort = node.GetInputPortByName($"DefaultDialogueContent{i + 1}");
var contentValue = GetPortValue<DialogueContent>(contentPort);
if (contentValue != null)
{
// Add to dialogueContent list
runtimeNode.dialogueContent.Add(contentValue);
// Also add to legacy dialogueLines list for backward compatibility
if (contentValue.ContentType == DialogueContentType.Text && !string.IsNullOrEmpty(contentValue.Text))
{
runtimeNode.dialogueLines.Add(contentValue.Text);
}
}
}
}
else
{
var contentPort = node.GetInputPortByName("DefaultDialogueContent");
var contentValue = GetPortValue<DialogueContent>(contentPort);
if (contentValue != null)
{
// Add to dialogueContent list
runtimeNode.dialogueContent.Add(contentValue);
// Also add to legacy dialogueLines list for backward compatibility
if (contentValue.ContentType == DialogueContentType.Text && !string.IsNullOrEmpty(contentValue.Text))
{
runtimeNode.dialogueLines.Add(contentValue.Text);
}
}
}
// Get loop through lines option
var loopThroughLines = GetPortValue<bool>(node.GetInputPortByName("LoopThroughDefaultLines"));
runtimeNode.loopThroughLines = loopThroughLines;
}
private void ProcessPuzzleNode(WaitOnPuzzleStep node, RuntimeDialogueNode runtimeNode)
{
runtimeNode.nodeType = RuntimeDialogueNodeType.WaitOnPuzzleStep;
var puzzleStep = GetPortValue<PuzzleStepSO>(node.GetInputPortByName("RequiredPuzzleStep"));
if (puzzleStep != null)
{
runtimeNode.puzzleStepID = puzzleStep.stepId;
}
2025-10-27 16:06:47 +01:00
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
}
private void ProcessPickupNode(WaitOnPickup node, RuntimeDialogueNode runtimeNode)
{
runtimeNode.nodeType = RuntimeDialogueNodeType.WaitOnPickup;
var pickup = GetPortValue<PickupItemData>(node.GetInputPortByName("RequiredPickup"));
if (pickup != null)
{
runtimeNode.pickupItemID = pickup.itemId;
}
2025-10-27 16:06:47 +01:00
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
}
private void ProcessSlotNode(WaitOnSlot node, RuntimeDialogueNode runtimeNode)
{
runtimeNode.nodeType = RuntimeDialogueNodeType.WaitOnSlot;
var slot = GetPortValue<PickupItemData>(node.GetInputPortByName("RequiredSlot"));
if (slot != null)
{
runtimeNode.slotItemID = slot.itemId;
}
2025-10-27 16:06:47 +01:00
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
// Get line type and count options for incorrect items
var incorrectItemLineTypeOption = node.GetNodeOptionByName("IncorrectItemDialogueLineType");
incorrectItemLineTypeOption.TryGetValue<DialogueType>(out var incorrectItemLineType);
var incorrectItemLineCountOption = node.GetNodeOptionByName("IncorrectItemNoLines");
incorrectItemLineCountOption.TryGetValue<int>(out var incorrectItemLineCount);
// Process incorrect item content
if (incorrectItemLineType == DialogueType.SayMultipleLines)
{
for (var i = 0; i < incorrectItemLineCount; i++)
{
var contentPort = node.GetInputPortByName($"IncorrectItemDialogueContent{i + 1}");
var contentValue = GetPortValue<DialogueContent>(contentPort);
if (contentValue != null)
{
// Add to incorrectItemContent list
runtimeNode.incorrectItemContent.Add(contentValue);
// Also add to legacy incorrectItemLines list for backward compatibility
if (contentValue.ContentType == DialogueContentType.Text && !string.IsNullOrEmpty(contentValue.Text))
{
runtimeNode.incorrectItemLines.Add(contentValue.Text);
}
}
}
}
else
{
var contentPort = node.GetInputPortByName("IncorrectItemDialogueContent");
var contentValue = GetPortValue<DialogueContent>(contentPort);
if (contentValue != null)
{
// Add to incorrectItemContent list
runtimeNode.incorrectItemContent.Add(contentValue);
// Also add to legacy incorrectItemLines list for backward compatibility
if (contentValue.ContentType == DialogueContentType.Text && !string.IsNullOrEmpty(contentValue.Text))
{
runtimeNode.incorrectItemLines.Add(contentValue.Text);
}
}
}
runtimeNode.loopThroughIncorrectLines =
GetPortValue<bool>(node.GetInputPortByName("LoopThroughIncorrectItemLines"));
// Get line type and count options for forbidden items
var forbiddenItemLineTypeOption = node.GetNodeOptionByName("ForbiddenItemDialogueLineType");
forbiddenItemLineTypeOption.TryGetValue<DialogueType>(out var forbiddenItemLineType);
var forbiddenItemLineCountOption = node.GetNodeOptionByName("ForbiddenItemNoLines");
forbiddenItemLineCountOption.TryGetValue<int>(out var forbiddenItemLineCount);
// Process forbidden item content
if (forbiddenItemLineType == DialogueType.SayMultipleLines)
{
for (var i = 0; i < forbiddenItemLineCount; i++)
{
var contentPort = node.GetInputPortByName($"ForbiddenItemDialogueContent{i + 1}");
var contentValue = GetPortValue<DialogueContent>(contentPort);
if (contentValue != null)
{
// Add to forbiddenItemContent list
runtimeNode.forbiddenItemContent.Add(contentValue);
// Also add to legacy forbiddenItemLines list for backward compatibility
if (contentValue.ContentType == DialogueContentType.Text && !string.IsNullOrEmpty(contentValue.Text))
{
runtimeNode.forbiddenItemLines.Add(contentValue.Text);
}
}
}
}
else
{
var contentPort = node.GetInputPortByName("ForbiddenItemDialogueContent");
var contentValue = GetPortValue<DialogueContent>(contentPort);
if (contentValue != null)
{
// Add to forbiddenItemContent list
runtimeNode.forbiddenItemContent.Add(contentValue);
// Also add to legacy forbiddenItemLines list for backward compatibility
if (contentValue.ContentType == DialogueContentType.Text && !string.IsNullOrEmpty(contentValue.Text))
{
runtimeNode.forbiddenItemLines.Add(contentValue.Text);
}
}
}
runtimeNode.loopThroughForbiddenLines =
GetPortValue<bool>(node.GetInputPortByName("LoopThroughForbiddenItemLines"));
}
// Add new method to process combination nodes
private void ProcessCombinationNode(WaitOnCombination node, RuntimeDialogueNode runtimeNode)
{
runtimeNode.nodeType = RuntimeDialogueNodeType.WaitOnCombination;
var resultItem = GetPortValue<PickupItemData>(node.GetInputPortByName("RequiredResultItem"));
if (resultItem != null)
{
runtimeNode.combinationResultItemID = resultItem.itemId;
}
2025-10-27 16:06:47 +01:00
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
}
private T GetPortValue<T>(IPort port)
{
if (port == null) return default(T);
if (port.isConnected)
{
if (port.firstConnectedPort.GetNode() is IVariableNode variableNode)
{
variableNode.variable.TryGetDefaultValue(out T value);
return value;
}
}
port.TryGetValue(out T fallbackValue);
return fallbackValue;
}
}
}