246 lines
10 KiB
C#
246 lines
10 KiB
C#
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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Process base dialogue node properties (for all node types)
|
|
ProcessDialogueNodeBase(dialogueNode, 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 lines based on line type
|
|
if (lineType == DialogueType.SayMultipleLines)
|
|
{
|
|
for (var i = 0; i < lineCount; i++)
|
|
{
|
|
var lineValue = GetPortValue<string>(node.GetInputPortByName($"DefaultDialogueLine{i + 1}"));
|
|
if (!string.IsNullOrEmpty(lineValue))
|
|
{
|
|
runtimeNode.dialogueLines.Add(lineValue);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var lineValue = GetPortValue<string>(node.GetInputPortByName("DefaultDialogueLine"));
|
|
if (!string.IsNullOrEmpty(lineValue))
|
|
{
|
|
runtimeNode.dialogueLines.Add(lineValue);
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// Process incorrect item lines
|
|
var incorrectItemLineTypeOption = node.GetNodeOptionByName("IncorrectItemDialogueLineType");
|
|
incorrectItemLineTypeOption.TryGetValue<DialogueType>(out var incorrectItemLineType);
|
|
|
|
var incorrectItemLineCountOption = node.GetNodeOptionByName("IncorrectItemNoLines");
|
|
incorrectItemLineCountOption.TryGetValue<int>(out var incorrectItemLineCount);
|
|
|
|
if (incorrectItemLineType == DialogueType.SayMultipleLines)
|
|
{
|
|
for (var i = 0; i < incorrectItemLineCount; i++)
|
|
{
|
|
var lineValue = GetPortValue<string>(node.GetInputPortByName($"IncorrectItemDialogueLine{i + 1}"));
|
|
if (!string.IsNullOrEmpty(lineValue))
|
|
{
|
|
runtimeNode.incorrectItemLines.Add(lineValue);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var lineValue = GetPortValue<string>(node.GetInputPortByName("IncorrectItemDialogueLine"));
|
|
if (!string.IsNullOrEmpty(lineValue))
|
|
{
|
|
runtimeNode.incorrectItemLines.Add(lineValue);
|
|
}
|
|
}
|
|
|
|
runtimeNode.loopThroughIncorrectLines =
|
|
GetPortValue<bool>(node.GetInputPortByName("LoopThroughIncorrectItemLines"));
|
|
|
|
// Process forbidden item lines
|
|
var forbiddenItemLineTypeOption = node.GetNodeOptionByName("ForbiddenItemDialogueLineType");
|
|
forbiddenItemLineTypeOption.TryGetValue<DialogueType>(out var forbiddenItemLineType);
|
|
|
|
var forbiddenItemLineCountOption = node.GetNodeOptionByName("ForbiddenItemNoLines");
|
|
forbiddenItemLineCountOption.TryGetValue<int>(out var forbiddenItemLineCount);
|
|
|
|
if (forbiddenItemLineType == DialogueType.SayMultipleLines)
|
|
{
|
|
for (var i = 0; i < forbiddenItemLineCount; i++)
|
|
{
|
|
var lineValue = GetPortValue<string>(node.GetInputPortByName($"ForbiddenItemDialogueLine{i + 1}"));
|
|
if (!string.IsNullOrEmpty(lineValue))
|
|
{
|
|
runtimeNode.forbiddenItemLines.Add(lineValue);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var lineValue = GetPortValue<string>(node.GetInputPortByName("ForbiddenItemDialogueLine"));
|
|
if (!string.IsNullOrEmpty(lineValue))
|
|
{
|
|
runtimeNode.forbiddenItemLines.Add(lineValue);
|
|
}
|
|
}
|
|
|
|
runtimeNode.loopThroughForbiddenLines =
|
|
GetPortValue<bool>(node.GetInputPortByName("LoopThroughForbiddenItemLines"));
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
} |