// Copyright Epic Games, Inc. All Rights Reserved. #include "SoundCueGraph/SoundCueGraph.h" #include "SoundCueGraph/SoundCueGraphSchema.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Sound/SoundCue.h" #include "Sound/SoundNode.h" #include "SoundCueGraph/SoundCueGraphNode.h" #include "SoundCueGraph/SoundCueGraphNode_Root.h" class FSoundCueAudioEditor : public ISoundCueAudioEditor { public: FSoundCueAudioEditor() { } ~FSoundCueAudioEditor() { } UEdGraph* CreateNewSoundCueGraph(USoundCue* InSoundCue) override { USoundCueGraph* SoundCueGraph = CastChecked(FBlueprintEditorUtils::CreateNewGraph(InSoundCue, NAME_None, USoundCueGraph::StaticClass(), USoundCueGraphSchema::StaticClass())); return SoundCueGraph; } void SetupSoundNode(UEdGraph* SoundCueGraph, USoundNode* InSoundNode, bool bSelectNewNode) override { FGraphNodeCreator NodeCreator(*SoundCueGraph); USoundCueGraphNode* GraphNode = NodeCreator.CreateNode(bSelectNewNode); GraphNode->SetSoundNode(InSoundNode); NodeCreator.Finalize(); } void LinkGraphNodesFromSoundNodes(USoundCue* SoundCue) override { // Use SoundNodes to make GraphNode Connections if (SoundCue->FirstNode != NULL) { // Find the root node TArray RootNodeList; SoundCue->SoundCueGraph->GetNodesOfClass(/*out*/ RootNodeList); check(RootNodeList.Num() == 1); RootNodeList[0]->Pins[0]->BreakAllPinLinks(); RootNodeList[0]->Pins[0]->MakeLinkTo(CastChecked(SoundCue->FirstNode->GetGraphNode())->GetOutputPin()); } for (TArray::TConstIterator It(SoundCue->AllNodes); It; ++It) { USoundNode* SoundNode = *It; if (SoundNode) { TArray InputPins; CastChecked(SoundNode->GetGraphNode())->GetInputPins(/*out*/ InputPins); check(InputPins.Num() == SoundNode->ChildNodes.Num()); for (int32 ChildIndex = 0; ChildIndex < SoundNode->ChildNodes.Num(); ChildIndex++) { USoundNode* ChildNode = SoundNode->ChildNodes[ChildIndex]; if (ChildNode) { InputPins[ChildIndex]->BreakAllPinLinks(); InputPins[ChildIndex]->MakeLinkTo(CastChecked(ChildNode->GetGraphNode())->GetOutputPin()); } } } } } void CompileSoundNodesFromGraphNodes(USoundCue* SoundCue) override { // Use GraphNodes to make SoundNode Connections TArray ChildNodes; TArray InputPins; for (int32 NodeIndex = 0; NodeIndex < SoundCue->SoundCueGraph->Nodes.Num(); ++NodeIndex) { USoundCueGraphNode* GraphNode = Cast(SoundCue->SoundCueGraph->Nodes[NodeIndex]); if (GraphNode && GraphNode->SoundNode) { // Set ChildNodes of each SoundNode GraphNode->GetInputPins(InputPins); ChildNodes.Empty(); for (int32 PinIndex = 0; PinIndex < InputPins.Num(); ++PinIndex) { UEdGraphPin* ChildPin = InputPins[PinIndex]; if (ChildPin->LinkedTo.Num() > 0) { USoundCueGraphNode* GraphChildNode = CastChecked(ChildPin->LinkedTo[0]->GetOwningNode()); ChildNodes.Add(GraphChildNode->SoundNode); } else { ChildNodes.AddZeroed(); } } GraphNode->SoundNode->SetFlags(RF_Transactional); GraphNode->SoundNode->Modify(); GraphNode->SoundNode->SetChildNodes(ChildNodes); GraphNode->SoundNode->PostEditChange(); } else { // Set FirstNode based on RootNode connection USoundCueGraphNode_Root* RootNode = Cast(SoundCue->SoundCueGraph->Nodes[NodeIndex]); if (RootNode) { SoundCue->Modify(); if (RootNode->Pins[0]->LinkedTo.Num() > 0) { SoundCue->FirstNode = CastChecked(RootNode->Pins[0]->LinkedTo[0]->GetOwningNode())->SoundNode; } else { SoundCue->FirstNode = nullptr; } SoundCue->PostEditChange(); } } } } void RemoveNullNodes(USoundCue* SoundCue) override { // Deal with SoundNode types being removed - iterate in reverse as nodes may be removed for (int32 idx = SoundCue->SoundCueGraph->Nodes.Num() - 1; idx >= 0; --idx) { USoundCueGraphNode* Node = Cast(SoundCue->SoundCueGraph->Nodes[idx]); if (Node && Node->SoundNode == NULL) { FBlueprintEditorUtils::RemoveNode(NULL, Node, true); } } } void CreateInputPin(UEdGraphNode* SoundCueNode) override { CastChecked(SoundCueNode)->CreateInputPin(); } void RenameNodePins(USoundNode* SoundNode) override { TArray InputPins; #if WITH_EDITORONLY_DATA CastChecked(SoundNode->GetGraphNode())->GetInputPins(InputPins); #endif for (int32 i = 0; i < InputPins.Num(); i++) { if (InputPins[i]) { InputPins[i]->PinName = *SoundNode->GetInputPinName(i).ToString(); } } } }; USoundCueGraph::USoundCueGraph(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { if (!USoundCue::GetSoundCueAudioEditor().IsValid()) { USoundCue::SetSoundCueAudioEditor(TSharedPtr(new FSoundCueAudioEditor())); } } USoundCue* USoundCueGraph::GetSoundCue() const { return CastChecked(GetOuter()); }