diff --git a/ProjectFish/Binaries/Win64/ProjectFishEditor.target b/ProjectFish/Binaries/Win64/ProjectFishEditor.target index 1116c58..403a107 100644 --- a/ProjectFish/Binaries/Win64/ProjectFishEditor.target +++ b/ProjectFish/Binaries/Win64/ProjectFishEditor.target @@ -8040,6 +8040,26 @@ { "Path": "$(ProjectDir)/Plugins/DeskMode/Binaries/Win64/UnrealEditor.modules", "Type": "RequiredResource" + }, + { + "Path": "$(ProjectDir)/Plugins/Dialogue/Binaries/Win64/UnrealEditor-Dialogue.dll", + "Type": "DynamicLibrary" + }, + { + "Path": "$(ProjectDir)/Plugins/Dialogue/Binaries/Win64/UnrealEditor-Dialogue.pdb", + "Type": "SymbolFile" + }, + { + "Path": "$(ProjectDir)/Plugins/Dialogue/Binaries/Win64/UnrealEditor-DialogueEditor.dll", + "Type": "DynamicLibrary" + }, + { + "Path": "$(ProjectDir)/Plugins/Dialogue/Binaries/Win64/UnrealEditor-DialogueEditor.pdb", + "Type": "SymbolFile" + }, + { + "Path": "$(ProjectDir)/Plugins/Dialogue/Binaries/Win64/UnrealEditor.modules", + "Type": "RequiredResource" } ], "RuntimeDependencies": [ @@ -33775,6 +33795,10 @@ "Path": "$(ProjectDir)/Plugins/DeskMode/DeskMode.uplugin", "Type": "UFS" }, + { + "Path": "$(ProjectDir)/Plugins/Dialogue/Dialogue.uplugin", + "Type": "UFS" + }, { "Path": "$(ProjectDir)/ProjectFish.uproject", "Type": "UFS" @@ -33844,6 +33868,7 @@ "DatasmithContent", "DeformerGraph", "DeskMode", + "Dialogue", "DumpGPUServices", "EOSShared", "EditorDataStorage", diff --git a/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFish.dll b/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFish.dll index 8733269..092afe9 100644 Binary files a/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFish.dll and b/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFish.dll differ diff --git a/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFishEditor.dll b/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFishEditor.dll index 36ed6ac..36c0f9a 100644 Binary files a/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFishEditor.dll and b/ProjectFish/Binaries/Win64/UnrealEditor-ProjectFishEditor.dll differ diff --git a/ProjectFish/Content/DataAssets/Dialogue/5.uasset b/ProjectFish/Content/DataAssets/Dialogue/5.uasset new file mode 100644 index 0000000..2181f60 Binary files /dev/null and b/ProjectFish/Content/DataAssets/Dialogue/5.uasset differ diff --git a/ProjectFish/Content/DataAssets/Dialogue/Condition_False.uasset b/ProjectFish/Content/DataAssets/Dialogue/Condition_False.uasset new file mode 100644 index 0000000..76aedf2 Binary files /dev/null and b/ProjectFish/Content/DataAssets/Dialogue/Condition_False.uasset differ diff --git a/ProjectFish/Content/DataAssets/Dialogue/Condition_True.uasset b/ProjectFish/Content/DataAssets/Dialogue/Condition_True.uasset new file mode 100644 index 0000000..15df4d5 Binary files /dev/null and b/ProjectFish/Content/DataAssets/Dialogue/Condition_True.uasset differ diff --git a/ProjectFish/Content/Maps/TestDialogue.umap b/ProjectFish/Content/Maps/TestDialogue.umap new file mode 100644 index 0000000..3c66b50 Binary files /dev/null and b/ProjectFish/Content/Maps/TestDialogue.umap differ diff --git a/ProjectFish/Content/UI/TestUI/DialogueText.uasset b/ProjectFish/Content/UI/TestUI/DialogueText.uasset new file mode 100644 index 0000000..dedc056 Binary files /dev/null and b/ProjectFish/Content/UI/TestUI/DialogueText.uasset differ diff --git a/ProjectFish/Content/UI/TestUI/TestDialogueWidget.uasset b/ProjectFish/Content/UI/TestUI/TestDialogueWidget.uasset new file mode 100644 index 0000000..14688dc Binary files /dev/null and b/ProjectFish/Content/UI/TestUI/TestDialogueWidget.uasset differ diff --git a/ProjectFish/Plugins/DeskMode/Binaries/Win64/UnrealEditor-DeskMode.dll b/ProjectFish/Plugins/DeskMode/Binaries/Win64/UnrealEditor-DeskMode.dll index 3d350e9..8ed9fe7 100644 Binary files a/ProjectFish/Plugins/DeskMode/Binaries/Win64/UnrealEditor-DeskMode.dll and b/ProjectFish/Plugins/DeskMode/Binaries/Win64/UnrealEditor-DeskMode.dll differ diff --git a/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor-Dialogue.dll b/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor-Dialogue.dll new file mode 100644 index 0000000..4d7f97d Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor-Dialogue.dll differ diff --git a/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor-DialogueEditor.dll b/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor-DialogueEditor.dll new file mode 100644 index 0000000..f2092cc Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor-DialogueEditor.dll differ diff --git a/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor.modules b/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor.modules new file mode 100644 index 0000000..eb05314 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Binaries/Win64/UnrealEditor.modules @@ -0,0 +1,8 @@ +{ + "BuildId": "37670630", + "Modules": + { + "Dialogue": "UnrealEditor-Dialogue.dll", + "DialogueEditor": "UnrealEditor-DialogueEditor.dll" + } +} \ No newline at end of file diff --git a/ProjectFish/Plugins/Dialogue/Dialogue.uplugin b/ProjectFish/Plugins/Dialogue/Dialogue.uplugin new file mode 100644 index 0000000..b63af61 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Dialogue.uplugin @@ -0,0 +1,29 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "Dialogue", + "Description": "", + "Category": "Other", + "CreatedBy": "", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "CanContainContent": true, + "IsBetaVersion": false, + "IsExperimentalVersion": false, + "Installed": false, + "Modules": [ + { + "Name": "Dialogue", + "Type": "Runtime", + "LoadingPhase": "Default" + }, + { + "Name": "DialogueEditor", + "Type": "Editor", + "LoadingPhase": "Default" + } + ] +} \ No newline at end of file diff --git a/ProjectFish/Plugins/Dialogue/Resources/Icon128.png b/ProjectFish/Plugins/Dialogue/Resources/Icon128.png new file mode 100644 index 0000000..1231d4a Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/Icon128.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/condition.png b/ProjectFish/Plugins/Dialogue/Resources/condition.png new file mode 100644 index 0000000..f01b1e3 Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/condition.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/dialogue_16.png b/ProjectFish/Plugins/Dialogue/Resources/dialogue_16.png new file mode 100644 index 0000000..3b937c8 Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/dialogue_16.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/dialogue_64.png b/ProjectFish/Plugins/Dialogue/Resources/dialogue_64.png new file mode 100644 index 0000000..bea33dd Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/dialogue_64.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/event.png b/ProjectFish/Plugins/Dialogue/Resources/event.png new file mode 100644 index 0000000..b08d0ad Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/event.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/npcNode.png b/ProjectFish/Plugins/Dialogue/Resources/npcNode.png new file mode 100644 index 0000000..cf57619 Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/npcNode.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/playerNode.png b/ProjectFish/Plugins/Dialogue/Resources/playerNode.png new file mode 100644 index 0000000..40387a6 Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/playerNode.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/sound.png b/ProjectFish/Plugins/Dialogue/Resources/sound.png new file mode 100644 index 0000000..d84ab2d Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/sound.png differ diff --git a/ProjectFish/Plugins/Dialogue/Resources/startNode.png b/ProjectFish/Plugins/Dialogue/Resources/startNode.png new file mode 100644 index 0000000..f329b50 Binary files /dev/null and b/ProjectFish/Plugins/Dialogue/Resources/startNode.png differ diff --git a/ProjectFish/Plugins/Dialogue/Source/Dialogue/Dialogue.Build.cs b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Dialogue.Build.cs new file mode 100644 index 0000000..fda35df --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Dialogue.Build.cs @@ -0,0 +1,54 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class Dialogue : ModuleRules +{ + public Dialogue(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + //test + OptimizeCode = CodeOptimization.Never; + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/Dialogue.cpp b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/Dialogue.cpp new file mode 100644 index 0000000..933f69e --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/Dialogue.cpp @@ -0,0 +1,20 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "Dialogue.h" + +#define LOCTEXT_NAMESPACE "FDialogueModule" + +void FDialogueModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module +} + +void FDialogueModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FDialogueModule, Dialogue) \ No newline at end of file diff --git a/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/DialogueAsset.cpp b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/DialogueAsset.cpp new file mode 100644 index 0000000..4517da6 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/DialogueAsset.cpp @@ -0,0 +1,86 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "DialogueAsset.h" + +#include "UObject/ObjectSaveContext.h" + + +bool UDialogueConditions::IsConditionMet_Implementation() +{ + return true; +} + +void UDialogueAsset::BeginDialogue() +{ + CurrentNode = NodeDatas[0]; +} + +FText UDialogueAsset::GetNextNodeText() +{ + if (CurrentNode->OutputPins.Num() > 0 && CurrentNode->OutputPins[0]->Connections.Num() > 0) + { + UDialogueRuntimePin* Connection = CurrentNode->OutputPins[0]->Connections[0]; + UDialogueRuntimeNode* ConnectionParent = Connection->Parent; + + if (ConnectionParent->NodeType == EDialogueNodeType::NPC) + { + //处理下一个对话是npc的情况 + for (auto Pin: CurrentNode->OutputPins[0]->Connections) + { + UDialogueRuntimeNode* ConnectionNode = Pin->Parent; + if (ConnectionNode->NodeData->Conditionses.Num() != 0) + { + //判断是否符合条件 + bool ConditionMet = false; + for (auto Condition: ConnectionNode->NodeData->Conditionses) + { + ConditionMet = ConditionMet || Condition->IsConditionMet(); + } + if (ConditionMet) + { + CurrentNode = ConnectionNode; + return ConnectionNode->NodeData->Text; + } + } + else + { + CurrentNode = ConnectionNode; + return ConnectionNode->NodeData->Text; + } + + } + + } + else if (ConnectionParent->NodeType == EDialogueNodeType::Player) + { + //处理下一个对话是玩家选项的情况 + TArray Options; + for (UDialogueRuntimePin* Pin : CurrentNode->OutputPins[0]->Connections) + { + Options.Add(Pin->Parent->NodeData->Text); + } + OnNeedPlayerSelect.Broadcast(Options); + //返回值不变 + return CurrentNode->NodeData->Text; + } + } + else + { + UE_LOG(LogTemp, Warning, TEXT("DialogueNode has no output pin")); + } + return FText::FromString(TEXT("")); +} + +void UDialogueAsset::PlayerSelect(int32 index) +{ + CurrentNode = CurrentNode->OutputPins[0]->Connections[index]->Parent; +} + +void UDialogueAsset::PreSave(FObjectPreSaveContext saveContext) +{ + if (OnPreSaveListener) + { + OnPreSaveListener(); + } +} diff --git a/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/DialogueSettings.cpp b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/DialogueSettings.cpp new file mode 100644 index 0000000..c5d9334 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Private/DialogueSettings.cpp @@ -0,0 +1,4 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "DialogueSettings.h" diff --git a/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/Dialogue.h b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/Dialogue.h new file mode 100644 index 0000000..e32d5fd --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/Dialogue.h @@ -0,0 +1,14 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Modules/ModuleManager.h" + +class FDialogueModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/DialogueAsset.h b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/DialogueAsset.h new file mode 100644 index 0000000..f377169 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/DialogueAsset.h @@ -0,0 +1,124 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "DialogueAsset.generated.h" + +UCLASS(Blueprintable, BlueprintType, abstract, EditInlineNew, HideCategories = ("DoNotShow"), CollapseCategories, AutoExpandCategories = ("Default")) +class DIALOGUE_API UDialogueConditions : public UObject +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Dialogue Conditions") + bool IsConditionMet(); + +}; + +UENUM() +enum class EDialogueNodeType { + None, + Root, + NPC, + Player +}; +UCLASS() +class DIALOGUE_API UDialogueRuntimePin : public UObject +{ + GENERATED_BODY() + +public: + UPROPERTY() + FName PinName; + + UPROPERTY() + FGuid PinId; + + UPROPERTY() + TArray Connections; + + UPROPERTY() + class UDialogueRuntimeNode* Parent = nullptr; + + UPROPERTY() + int32 Direction; + bool operator ==(const UDialogueRuntimePin& other) const + { + return PinId == other.PinId; + } + friend uint32 GetTypeHash(const UDialogueRuntimePin& other) + { + return GetTypeHash(other.PinId); + } + +}; + +UCLASS() +class DIALOGUE_API UDialogueNodeData_Base : public UObject +{ + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Node", meta = (MultiLine = true)) + FText Text; + + UPROPERTY(Instanced, EditAnywhere, BlueprintReadWrite, Category = "Dialogue Node") + TArray Conditionses; + +}; + +UCLASS() +class DIALOGUE_API UDialogueRuntimeNode : public UObject +{ + GENERATED_BODY() + +public: + UPROPERTY() + UDialogueRuntimePin* InputPin; + + UPROPERTY() + TArray OutputPins; + + UPROPERTY() + FVector2D Position; + + UPROPERTY() + UDialogueNodeData_Base* NodeData = nullptr; + + UPROPERTY() + EDialogueNodeType NodeType = EDialogueNodeType::None; +}; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FNeedPlayeSelectDelegate, const TArray&, Options); +/** + * + */ +UCLASS(BlueprintType) +class DIALOGUE_API UDialogueAsset : public UDataAsset +{ + GENERATED_BODY() +public: + UFUNCTION(BlueprintCallable, Category = Dialogue) + void BeginDialogue(); + UFUNCTION(BlueprintPure, Category = Dialogue) + FText GetNextNodeText(); + UFUNCTION(BlueprintCallable, Category = Dialogue) + void PlayerSelect(int32 index); + +public: + //设置修改过程中回调 + void SetPreSaveListener(std::function InPreSaveListener) { OnPreSaveListener = InPreSaveListener; } + virtual void PreSave(FObjectPreSaveContext saveContext) override; +public: + UPROPERTY(BlueprintAssignable, Category=Dialogue) + FNeedPlayeSelectDelegate OnNeedPlayerSelect; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Dialogue) + TArray NodeDatas; +private: + UDialogueRuntimeNode* CurrentNode = nullptr; + std::function OnPreSaveListener = nullptr; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/DialogueSettings.h b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/DialogueSettings.h new file mode 100644 index 0000000..bff4be5 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/Dialogue/Public/DialogueSettings.h @@ -0,0 +1,16 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "DialogueSettings.generated.h" + +/** + * + */ +UCLASS(Config = Dialogue, DefaultConfig) +class DIALOGUE_API UDialogueSettings : public UObject +{ + GENERATED_BODY() +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/DialogueEditor.Build.cs b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/DialogueEditor.Build.cs new file mode 100644 index 0000000..4b25641 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/DialogueEditor.Build.cs @@ -0,0 +1,34 @@ +using UnrealBuildTool; + +public class DialogueEditor : ModuleRules +{ + public DialogueEditor(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + //test + OptimizeCode = CodeOptimization.Never; + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + "AssetTools" + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + "Dialogue", + "Projects", + "UnrealEd", + "GraphEditor", + "Kismet" + } + ); + + } +} \ No newline at end of file diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueAssetEditor.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueAssetEditor.cpp new file mode 100644 index 0000000..2218d4c --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueAssetEditor.cpp @@ -0,0 +1,345 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "DialogueAssetEditor.h" +#include "DialogueGraph.h" +#include "DialogueGraphSchema.h" +#include "DialogueEditorMode.h" +#include "DialogueGraphPanelNodeFactory.h" +#include "DialogueGraphPanelPinFactory.h" +#include "EdGraphUtilities.h" +#include "Kismet2/BlueprintEditorUtils.h" +#include "GraphEditorActions.h" +#include "Framework/Commands/GenericCommands.h" +#include "IDetailsView.h" +#include "Node/DialogueGraphNode_Base.h" +#include "Node/DialogueGraphNode_NPC.h" +#include "Node/DialogueGraphNode_Player.h" +#include "Node/DialogueGraphNode_Root.h" + +#define LOCTEXT_NAMESPACE "DialogueEditorToolkit" + +const FName DialogueEditorAppName = FName(TEXT("DialogueEditorApp")); + +void FDialogueAssetEditor::OnClose() +{ + SaveGraphData(); + DialogueBeingEdited->SetPreSaveListener(nullptr); + FWorkflowCentricApplication::OnClose(); +} + +FDialogueAssetEditor::FDialogueAssetEditor() + : DialogueGraph(nullptr) +{ +} + +FDialogueAssetEditor::~FDialogueAssetEditor() +{ +} + +FText FDialogueAssetEditor::GetBaseToolkitName() const +{ + return IsValid(DialogueBeingEdited) ? FText::FromString(DialogueBeingEdited->GetName()) : LOCTEXT("AppLabel", "Dialogue Editor"); +} + + + +void FDialogueAssetEditor::InitDialogueEditor(const EToolkitMode::Type Mode, + const TSharedPtr& InitToolkitHost, TObjectPtr InitDialogueAsset) +{ + DialogueBeingEdited = InitDialogueAsset; + //修改过程中保存 + DialogueBeingEdited->SetPreSaveListener([this] () { SaveGraphData();; }); + // 注册命令 + FGenericCommands::Register(); + FGraphEditorCommands::Register(); + BindGraphCommands(); + + //注册节点的创建 + FEdGraphUtilities::RegisterVisualNodeFactory(MakeShareable(new FDialogueGraphPanelNodeFactory())); + FEdGraphUtilities::RegisterVisualPinFactory(MakeShareable(new FDialogueGraphPanelPinFactory())); + + // 创建图表 + DialogueGraph = FBlueprintEditorUtils::CreateNewGraph( + DialogueBeingEdited.Get(), + NAME_None, + UDialogueGraph::StaticClass(), + UDialogueGraphSchema::StaticClass() + ); + + TArray ObjectsToEdit; + ObjectsToEdit.Add(InitDialogueAsset); + + // 初始化编辑器 + InitAssetEditor( + Mode, + InitToolkitHost, + DialogueEditorAppName, + FTabManager::FLayout::NullLayout, + true, + true, + ObjectsToEdit + ); + + // 添加应用模式 + AddApplicationMode(TEXT("DialogueEditorMode"), MakeShareable(new FDialogueEditorMode(SharedThis(this)))); + SetCurrentMode(TEXT("DialogueEditorMode")); + + //加载资源中的数据节点 + LoadGraphData(); +} + +void FDialogueAssetEditor::SetDetailsView(TSharedPtr InDetailsView) +{ + DetailsView = InDetailsView; + if (DetailsView.IsValid()) + { + DetailsView->OnFinishedChangingProperties().AddSP(this, &FDialogueAssetEditor::OnNodeDetailViewPropertiesUpdated); + } +} + +void FDialogueAssetEditor::OnGraphSelectionChanged(const FGraphPanelSelectionSet& Selection) +{ + if (!DetailsView.IsValid()) + return; + + if (UDialogueGraphNode_Base* SelectedNode = GetSelectedNode(Selection)) + { + DetailsView->SetObject(SelectedNode->GetDialogueNodeData()); + } + else + { + DetailsView->SetObject(nullptr); + } +} + +void FDialogueAssetEditor::SaveGraphData() +{ + if (!DialogueBeingEdited || !DialogueGraph) + { + return; + } + + + TArray> Connections; + TMap IdToPinMap; + DialogueBeingEdited->NodeDatas.Empty(); + for (UEdGraphNode* EditorNode : DialogueGraph->Nodes) + { + UDialogueRuntimeNode* RuntimeNode = NewObject(DialogueBeingEdited); + RuntimeNode->Position = FVector2D(EditorNode->NodePosX, EditorNode->NodePosY); + + for (UEdGraphPin* EditorPin : EditorNode->Pins) + { + UDialogueRuntimePin* RuntimePin = NewObject(RuntimeNode); + RuntimePin->PinName = EditorPin->PinName; + RuntimePin->PinId = EditorPin->PinId; + RuntimePin->Parent = RuntimeNode; + RuntimePin->Direction = EditorPin->Direction; + + if (EditorPin->HasAnyConnections()) + { + std::pair Connection = std::make_pair(EditorPin->PinId, EditorPin->LinkedTo[0]->PinId); + Connections.Add(Connection); + } + + IdToPinMap.Add(EditorPin->PinId, RuntimePin); + if (RuntimePin->Direction == EGPD_Input) + { + RuntimeNode->InputPin = RuntimePin; + } + else + { + RuntimeNode->OutputPins.Add(RuntimePin); + } + } + UDialogueGraphNode_Base* EditorDialogueNode = Cast(EditorNode); + RuntimeNode->NodeData = DuplicateObject(EditorDialogueNode->GetDialogueNodeData(), DialogueBeingEdited); + RuntimeNode->NodeType = EditorDialogueNode->GetDialogueNodeType(); + + DialogueBeingEdited->NodeDatas.Add(RuntimeNode); + + } + + for (std::pair Connection : Connections) + { + UDialogueRuntimePin* Pin1 = IdToPinMap[Connection.first]; + UDialogueRuntimePin* Pin2 = IdToPinMap[Connection.second]; + if (!Pin1->Connections.Contains(Pin2)) + { + Pin1->Connections.Add(Pin2); + if (Pin1->Direction == EGPD_Input) + { + if (!Pin2->Connections.Contains(Pin1)) + { + Pin2->Connections.Add(Pin1); + } + } + } + } + //标记数据更新 + DialogueBeingEdited->Modify(); +} + +void FDialogueAssetEditor::LoadGraphData() +{ + if (DialogueBeingEdited->NodeDatas.Num() == 0) + { + //空节点,创建默认Root节点 + DialogueGraph->GetSchema()->CreateDefaultNodesForGraph(*DialogueGraph); + UDialogueRuntimeNode* RootNode = NewObject(); + RootNode->NodeType = EDialogueNodeType::Root; + return; + } + //读取节点信息,创建pin及连线 + TArray> Connections; + TMap IdToPinMap; + for (UDialogueRuntimeNode* RuntimeNode: DialogueBeingEdited->NodeDatas) + { + UDialogueGraphNode_Base* EditorNode = nullptr; + switch (RuntimeNode->NodeType) + { + case EDialogueNodeType::Root: + EditorNode = NewObject(DialogueGraph); + break; + case EDialogueNodeType::NPC: + EditorNode = NewObject(DialogueGraph); + break; + case EDialogueNodeType::Player: + EditorNode = NewObject(DialogueGraph); + break; + default: ; + continue; + } + + EditorNode->CreateNewGuid(); + EditorNode->SetPostion(RuntimeNode->Position); + if (RuntimeNode->NodeData) + { + EditorNode->SetDialogueNodeData(DuplicateObject(RuntimeNode->NodeData, EditorNode)); + } + else + { + EditorNode->InitializeNodeData(); + } + + if (RuntimeNode->InputPin) + { + UDialogueRuntimePin* InputPin = RuntimeNode->InputPin; + FName Category = TEXT("Inputs"); + UEdGraphPin* EditorPin = EditorNode->CreatePin((EEdGraphPinDirection)InputPin->Direction, Category, InputPin->PinName); + EditorPin->PinId = InputPin->PinId; + + if (InputPin->Connections.Num() > 0) + { + Connections.Add(std::make_pair(InputPin->PinId, InputPin->Connections[0]->PinId)); + } + IdToPinMap.Add(InputPin->PinId, EditorPin); + } + + for (UDialogueRuntimePin* RuntimePin : RuntimeNode->OutputPins) + { + FName Category = TEXT("Outputs"); + UEdGraphPin* EditorPin = EditorNode->CreatePin((EEdGraphPinDirection)RuntimePin->Direction, Category, RuntimePin->PinName); + EditorPin->PinId = RuntimePin->PinId; + + if (RuntimePin->Connections.Num() > 0) + { + Connections.Add(std::make_pair(RuntimePin->PinId, RuntimePin->Connections[0]->PinId)); + } + IdToPinMap.Add(RuntimePin->PinId, EditorPin); + } + DialogueGraph->AddNode(EditorNode, true, true); + } + for (std::pair Connection : Connections) + { + UEdGraphPin* FromPin = IdToPinMap[Connection.first]; + UEdGraphPin* ToPin = IdToPinMap[Connection.second]; + FromPin->LinkedTo.Add(ToPin); + ToPin->LinkedTo.Add(FromPin); + } + +} + +void FDialogueAssetEditor::BindGraphCommands() +{ + ToolkitCommands->MapAction(FGenericCommands::Get().Delete, + FExecuteAction::CreateSP(this, &FDialogueAssetEditor::DeleteSelectedNodes), + FCanExecuteAction::CreateSP(this, &FDialogueAssetEditor::CanDeleteNodes)); +} + +void FDialogueAssetEditor::DeleteSelectedNodes() +{ + if (!GraphEditor.IsValid()) + return; + + const FScopedTransaction Transaction(FGenericCommands::Get().Delete->GetDescription()); + GraphEditor->GetCurrentGraph()->Modify(); + + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); + GraphEditor->ClearSelectionSet(); + + for (FGraphPanelSelectionSet::TConstIterator NodeIt(SelectedNodes); NodeIt; ++NodeIt) + { + + UEdGraphNode* EdNode = Cast(*NodeIt); + if (EdNode == nullptr || !EdNode->CanUserDeleteNode()) + continue;; + + if (UDialogueGraphNode_Base* EdNode_Node = Cast(EdNode)) + { + EdNode_Node->Modify(); + + const UEdGraphSchema* Schema = EdNode_Node->GetSchema(); + if (Schema != nullptr) + { + Schema->BreakNodeLinks(*EdNode_Node); + } + + EdNode_Node->DestroyNode(); + } + else + { + EdNode->Modify(); + EdNode->DestroyNode(); + } + } +} + +bool FDialogueAssetEditor::CanDeleteNodes() +{ + if (!GraphEditor.IsValid()) + return false; + + const FGraphPanelSelectionSet SelectedNodes = GraphEditor->GetSelectedNodes(); + for (FGraphPanelSelectionSet::TConstIterator SelectedIter(SelectedNodes); SelectedIter; ++SelectedIter) + { + UEdGraphNode* Node = Cast(*SelectedIter); + if (Node && Node->CanUserDeleteNode()) + { + return true; + } + } + return false; +} + +UDialogueGraphNode_Base* FDialogueAssetEditor::GetSelectedNode(const FGraphPanelSelectionSet& Selection) +{ + for (UObject* Obj : Selection) + { + if (UDialogueGraphNode_Base* Node = Cast(Obj)) + { + return Node; + } + } + return nullptr; +} + +void FDialogueAssetEditor::OnNodeDetailViewPropertiesUpdated(const FPropertyChangedEvent& Event) +{ + if (GraphEditor.IsValid()) + { + GraphEditor->NotifyGraphChanged(); + } +} + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueAssetFactory.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueAssetFactory.cpp new file mode 100644 index 0000000..1f62ae9 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueAssetFactory.cpp @@ -0,0 +1,35 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "DialogueAssetFactory.h" + +#include "DialogueAsset.h" + +#define LOCTEXT_NAMESPACE "DialoguePluginEditor" +UDialogueAssetFactory::UDialogueAssetFactory(const FObjectInitializer& ObjectInitializer) +{ + SupportedClass = UDialogueAsset::StaticClass(); +} + +UObject* UDialogueAssetFactory::FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, + UObject* Context, FFeedbackContext* Warn, FName CallingContext) +{ + UDialogueAsset* NewObjectAsset = NewObject(InParent, InClass, InName, Flags | RF_Transactional); + return NewObjectAsset; +} + +FString UDialogueAssetFactory::GetDefaultNewAssetName() const +{ + return FString(TEXT("NewDialogue")); +} + +bool UDialogueAssetFactory::ShouldShowInNewMenu() const +{ + return true; +} + +FText UDialogueAssetFactory::GetDisplayName() const +{ + return LOCTEXT("DialogueName", "Dialogue"); +} +#undef LOCATEXT_NAMESPACE \ No newline at end of file diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueDetailsTabSummoner.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueDetailsTabSummoner.cpp new file mode 100644 index 0000000..c88a3cd --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueDetailsTabSummoner.cpp @@ -0,0 +1,55 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "DialogueDetailsTabSummoner.h" +#include "DialogueAssetEditor.h" +#include "PropertyEditorModule.h" +#include "IDetailsView.h" + +#define LOCTEXT_NAMESPACE "DialogueDetailsTabSummoner" + +const FName DialogueDetailsTabId = FName(TEXT("DialogueDetailsTabId")); + +FDialogueDetailsTabSummoner::FDialogueDetailsTabSummoner(TSharedPtr InDialogueEditor) + : FWorkflowTabFactory(DialogueDetailsTabId, InDialogueEditor) +{ + DialogueEditor = InDialogueEditor; + TabLabel = LOCTEXT("DialogueDetailsTabLabel", "Details"); + ViewMenuDescription = LOCTEXT("DialogueDetails_ViewMenu_Desc", "Details"); + ViewMenuTooltip = LOCTEXT("DialogueDetails_ViewMenu_ToolTip", "Show the Details Panel"); +} + +TSharedRef FDialogueDetailsTabSummoner::CreateTabBody(const FWorkflowTabSpawnInfo& Info) const +{ + TSharedPtr Editor = DialogueEditor.Pin(); + FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked(TEXT("PropertyEditor")); + + FDetailsViewArgs DetailsViewArgs; + DetailsViewArgs.bAllowSearch = false; + DetailsViewArgs.bHideSelectionTip = true; + DetailsViewArgs.bLockable = false; + DetailsViewArgs.bSearchInitialKeyFocus = true; + DetailsViewArgs.bUpdatesFromSelection = false; + DetailsViewArgs.NotifyHook = nullptr; + DetailsViewArgs.bShowOptions = true; + DetailsViewArgs.bShowModifiedPropertiesOption = false; + DetailsViewArgs.bShowScrollBar = false; + + TSharedPtr DetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs); + DetailsView->SetObject(nullptr); + Editor->SetDetailsView(DetailsView); + + return SNew(SVerticalBox) + + SVerticalBox::Slot() + .FillHeight(1.0f) + .HAlign(HAlign_Fill) + [ + DetailsView.ToSharedRef() + ]; +} + +FText FDialogueDetailsTabSummoner::GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const +{ + return LOCTEXT("DialogueDetailsTooltip", "The details panel for selected nodes"); +} + +#undef LOCTEXT_NAMESPACE diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditor.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditor.cpp new file mode 100644 index 0000000..f1952df --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditor.cpp @@ -0,0 +1,64 @@ +#include "DialogueEditor.h" + +#include "AssetToolsModule.h" +#include "DialogueEditorStyle.h" +#include "DialogueSettings.h" +#include "FDialogueAssetTypeActions.h" +#include "IAssetTools.h" +#include "ISettingsModule.h" + +#define LOCTEXT_NAMESPACE "FDialogueEditorModule" + +void FDialogueEditorModule::StartupModule() +{ + //添加需要用到的图标资源 + FDialogueEditorStyle::Initialize(); + //添加对话相关属性设置 + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + SettingsModule->RegisterSettings("Project", "Plugins", "Dialogue Plugin", + LOCTEXT("SettinsName", "Dialogue Plugin"), + LOCTEXT("SettingsDes", "Configue Dialogue Plugin"), + GetMutableDefault() + ); + } + //添加对话资源创建菜单 + IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); + EAssetTypeCategories::Type DialogueAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("Dialogue")), LOCTEXT("Dialogue", "Dialogue")); + TSharedRef DialogueAssetTypeActions = MakeShareable(new FDialogueAssetTypeActions(DialogueAssetCategory)); + CreatedAssetTypeActions.Add(DialogueAssetTypeActions); + AssetTools.RegisterAssetTypeActions(DialogueAssetTypeActions); + + // //添加自定义的属性窗口 + // FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); + // PropertyModule.RegisterCustomClassLayout("DialogueAsset", FOnGetDetailCustomizationInstance::CreateStatic(&FDialogueAssetEditorDetails::MakeInstance)); + // PropertyModule.NotifyCustomizationModuleChanged(); +} + +void FDialogueEditorModule::ShutdownModule() +{ + //注销图标资源 + FDialogueEditorStyle::Shutdown(); + //注销setting + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + SettingsModule->UnregisterSettings("Project", "Plugins", "Dialogue Plugin"); + } + //注销typeaction + if (FModuleManager::Get().IsModuleLoaded("AssetTools")) + { + FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked("AssetTools"); + IAssetTools& AssetTools = AssetToolsModule.Get(); + for (auto Action : CreatedAssetTypeActions) + { + + AssetTools.UnregisterAssetTypeActions(Action.ToSharedRef()); + } + CreatedAssetTypeActions.Empty(); + } + +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FDialogueEditorModule, DialogueEditor) \ No newline at end of file diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditorMode.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditorMode.cpp new file mode 100644 index 0000000..c2a78c8 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditorMode.cpp @@ -0,0 +1,48 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "DialogueEditorMode.h" +#include "DialogueAssetEditor.h" +#include "DialogueGraphTabSummoner.h" +#include "DialogueDetailsTabSummoner.h" + +FDialogueEditorMode::FDialogueEditorMode(TSharedPtr InDialogueEditor) + : FApplicationMode(TEXT("DialogueEditorMode")) +{ + DialogueEditor = InDialogueEditor; + + // 注册Tab工厂 + TabFactories.RegisterFactory(MakeShared(InDialogueEditor)); + TabFactories.RegisterFactory(MakeShared(InDialogueEditor)); + + // 定义布局 + TabLayout = FTabManager::NewLayout("Standalone_DialogueEditor_Layout_v1") + ->AddArea + ( + FTabManager::NewPrimaryArea() + ->SetOrientation(Orient_Vertical) + ->Split + ( + FTabManager::NewSplitter() + ->SetOrientation(Orient_Horizontal) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.7f) + ->AddTab(FName(TEXT("DialogueGraphTabId")), ETabState::OpenedTab) + ) + ->Split + ( + FTabManager::NewStack() + ->SetSizeCoefficient(0.3f) + ->AddTab(FName(TEXT("DialogueDetailsTabId")), ETabState::OpenedTab) + ) + ) + ); +} + +void FDialogueEditorMode::RegisterTabFactories(TSharedPtr InTabManager) +{ + TSharedPtr Editor = DialogueEditor.Pin(); + Editor->PushTabFactories(TabFactories); + FApplicationMode::RegisterTabFactories(InTabManager); +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditorStyle.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditorStyle.cpp new file mode 100644 index 0000000..6508000 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueEditorStyle.cpp @@ -0,0 +1,45 @@ +#include "DialogueEditorStyle.h" + +#include "Styling/SlateStyle.h" +#include "Styling/SlateStyleRegistry.h" +#include "Interfaces/IPluginManager.h" +#include "Styling/SlateStyleRegistry.h" + +TSharedPtr< FSlateStyleSet > FDialogueEditorStyle::StyleSet = nullptr; +TSharedPtr< ISlateStyle > FDialogueEditorStyle::Get() { return StyleSet; } + +void FDialogueEditorStyle::Initialize() +{ + if (StyleSet.IsValid()) + { + return; + } + + StyleSet = MakeShareable(new FSlateStyleSet(FName(TEXT("DialogueEditorStyle")))); + FString ResourceDir = IPluginManager::Get().FindPlugin("Dialogue")->GetBaseDir() / TEXT("Resources"); + //加载图标相关资源 + StyleSet->Set("PlayerNodeStyle", new FSlateBoxBrush(ResourceDir/"playerNode.png", FMargin(5.f / 138.f, 5.f / 56.f, 5.f / 138.f, 5.f / 56.f))); // left top right bottom + StyleSet->Set("NpcNodeStyle", new FSlateBoxBrush(ResourceDir/"npcNode.png", FMargin(5.f / 138.f, 5.f / 56.f, 5.f / 138.f, 5.f / 56.f))); + StyleSet->Set("StartNodeStyle", new FSlateBoxBrush(ResourceDir/"startNode.png", FMargin(5.f / 138.f, 5.f / 56.f, 5.f / 138.f, 5.f / 56.f))); + + StyleSet->Set("EventIcon", new FSlateImageBrush(ResourceDir/"event.png", FVector2D(14, 16))); + StyleSet->Set("ConditionIcon", new FSlateImageBrush(ResourceDir/"condition.png", FVector2D(16, 16))); + StyleSet->Set("VoiceIcon", new FSlateImageBrush(ResourceDir/"sound.png", FVector2D(17, 16))); + + StyleSet->Set(FName(TEXT("ClassThumbnail.DialogueAsset")), new FSlateImageBrush(ResourceDir/"dialogue_64.png", FVector2D(64, 64))); + StyleSet->Set(FName(TEXT("ClassIcon.DialogueAsset")), new FSlateImageBrush(ResourceDir/"dialogue_16.png", FVector2D(16, 16))); + + FSlateStyleRegistry::RegisterSlateStyle(*StyleSet.Get()); +} + +void FDialogueEditorStyle::Shutdown() +{ + if (StyleSet.IsValid()) + { + FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSet.Get()); + StyleSet.Reset(); + } + + + +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraph.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraph.cpp new file mode 100644 index 0000000..cb12273 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraph.cpp @@ -0,0 +1,12 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "DialogueGraph.h" + +UDialogueGraph::UDialogueGraph() +{ +} + +void UDialogueGraph::AddNode(UEdGraphNode* NodeToAdd, bool bUserAction, bool bSelectNewNode) +{ + Super::AddNode(NodeToAdd, bUserAction, bSelectNewNode); +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphPanelNodeFactory.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphPanelNodeFactory.cpp new file mode 100644 index 0000000..da1f063 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphPanelNodeFactory.cpp @@ -0,0 +1,19 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "DialogueGraphPanelNodeFactory.h" + +#include "Node//DialogueGraphNode_NPC.h" +#include "Node/DialogueGraphNode_Player.h" +#include "Widget/DialogueGraphNode.h" + + +TSharedPtr FDialogueGraphPanelNodeFactory::CreateNode(class UEdGraphNode* InNode) const +{ + if (UDialogueGraphNode_NPC* NPCNode = Cast(InNode)) + return SNew(SDialogueGraphNode, NPCNode); + + if (UDialogueGraphNode_Player* PlayerNode = Cast(InNode)) + return SNew(SDialogueGraphNode, PlayerNode); + return nullptr; +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphPanelPinFactory.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphPanelPinFactory.cpp new file mode 100644 index 0000000..b3f9c9d --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphPanelPinFactory.cpp @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "DialogueGraphPanelPinFactory.h" + +#include "Node/DialogueGraphNode_Base.h" +#include "Node/DialogueGraphNode_NPC.h" +#include "Node/DialogueGraphNode_Player.h" +#include "Widget/DialogueGraphPin.h" + + +TSharedPtr FDialogueGraphPanelPinFactory::CreatePin(class UEdGraphPin* InPin) const +{ + UEdGraphNode* ParentNode = InPin->GetOwningNode(); + if (ParentNode->IsA(UDialogueGraphNode_NPC::StaticClass()) + || ParentNode->IsA(UDialogueGraphNode_Player::StaticClass())) + { + return SNew(SDialogueGraphPin, InPin); + } + else + { + return SNew(SDialogueNoneGraphPin, InPin); + } + // For response nodes, return horizontal box with textblock and pin + return nullptr; +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphSchema.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphSchema.cpp new file mode 100644 index 0000000..b5da6b9 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphSchema.cpp @@ -0,0 +1,84 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "DialogueGraphSchema.h" +#include "Node/DialogueGraphNode_Base.h" +#include "Node/DialogueGraphNode_NPC.h" +#include "Node/DialogueGraphNode_Player.h" +#include "Node/DialogueGraphNode_Root.h" + +#define LOCTEXT_NAMESPACE "DialogueGraphSchema" + +UEdGraphNode* FDialogueGraphSchemaAction_NewNode::PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode) +{ + UDialogueGraphNode_Base* NewNode = NewObject(ParentGraph, ClassTemplate); + NewNode->CreateNewGuid(); + NewNode->SetPostion(Location); + NewNode->InitializeNodeData(); + NewNode->AllocateDefaultPins(); + + ParentGraph->Modify(); + ParentGraph->AddNode(NewNode, true, bSelectNewNode); + + // 如果从某个Pin拖拽创建,自动连接 + if (FromPin && NewNode->Pins.Num() > 0) + { + for (UEdGraphPin* Pin : NewNode->Pins) + { + if (Pin->Direction != FromPin->Direction) + { + GetDefault()->TryCreateConnection(FromPin, Pin); + break; + } + } + } + + return NewNode; +} + +void UDialogueGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const +{ + FGraphNodeCreator NodeCreator(Graph); + UDialogueGraphNode_Root* MyNode = NodeCreator.CreateNode(true, UDialogueGraphNode_Root::StaticClass()); + NodeCreator.Finalize(); + SetNodeMetaData(MyNode, FNodeMetadata::DefaultGraphNode); +} + +void UDialogueGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const +{ + // 添加npc对话节点 + TSharedPtr NPCNodeAction = MakeShareable(new FDialogueGraphSchemaAction_NewNode( + UDialogueGraphNode_NPC::StaticClass(), + LOCTEXT("DialogueNode_NPC_Category", "NPC Dialogue"), + LOCTEXT("DialogueNode_NPC_Desc", "NPC Dialogue Node"), + LOCTEXT("DialogueNode_NPC_Tooltip", "Create a npc dialogue node") + )); + ContextMenuBuilder.AddAction(NPCNodeAction); + // 添加npc对话节点 + TSharedPtr PlayerNodeAction = MakeShareable(new FDialogueGraphSchemaAction_NewNode( + UDialogueGraphNode_Player::StaticClass(), + LOCTEXT("DialogueNode_Player_Category", "Player Dialogue"), + LOCTEXT("DialogueNode_Player_Desc", "Player Dialogue Node"), + LOCTEXT("DialogueNode_Player_Tooltip", "Create a Player dialogue node") + )); + ContextMenuBuilder.AddAction(PlayerNodeAction); + +} + +const FPinConnectionResponse UDialogueGraphSchema::CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const +{ + // 不能连接自己 + if (A->GetOwningNode() == B->GetOwningNode()) + { + return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("ConnectionSameNode", "Cannot connect to self")); + } + + // 必须一个输入一个输出 + if (A->Direction == B->Direction) + { + return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("ConnectionSameDirection", "Must connect input to output")); + } + + return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT("")); +} + +#undef LOCTEXT_NAMESPACE diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphTabSummoner.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphTabSummoner.cpp new file mode 100644 index 0000000..8ca3a59 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/DialogueGraphTabSummoner.cpp @@ -0,0 +1,42 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "DialogueGraphTabSummoner.h" +#include "DialogueAssetEditor.h" + +#define LOCTEXT_NAMESPACE "DialogueGraphTabSummoner" + +const FName DialogueGraphTabId = FName(TEXT("DialogueGraphTabId")); + +FDialogueGraphTabSummoner::FDialogueGraphTabSummoner(TSharedPtr InDialogueEditor) + : FWorkflowTabFactory(DialogueGraphTabId, InDialogueEditor) +{ + DialogueEditor = InDialogueEditor; + TabLabel = LOCTEXT("DialogueGraphTabLabel", "Dialogue Graph"); + ViewMenuDescription = LOCTEXT("DialogueGraph_ViewMenu_Desc", "Dialogue Graph"); + ViewMenuTooltip = LOCTEXT("DialogueGraph_ViewMenu_ToolTip", "Show the Dialogue Graph"); +} + +TSharedRef FDialogueGraphTabSummoner::CreateTabBody(const FWorkflowTabSpawnInfo& Info) const +{ + TSharedPtr Editor = DialogueEditor.Pin(); + + SGraphEditor::FGraphEditorEvents GraphEvents; + GraphEvents.OnSelectionChanged.BindSP(Editor.Get(), &FDialogueAssetEditor::OnGraphSelectionChanged); + + TSharedPtr GraphEditor = + SNew(SGraphEditor) + .IsEditable(true) + .GraphEvents(GraphEvents) + .GraphToEdit(Editor->GetDialogueGraph()); + + Editor->SetGraphEditor(GraphEditor); + + return GraphEditor.ToSharedRef(); +} + +FText FDialogueGraphTabSummoner::GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const +{ + return LOCTEXT("DialogueGraphTooltip", "The dialogue graph editor"); +} + +#undef LOCTEXT_NAMESPACE diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/FDialogueAssetTypeActions.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/FDialogueAssetTypeActions.cpp new file mode 100644 index 0000000..9304217 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/FDialogueAssetTypeActions.cpp @@ -0,0 +1,52 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "FDialogueAssetTypeActions.h" + +#include "DialogueAsset.h" +#include "DialogueAssetEditor.h" + +#define LOCTEXT_NAMESPACE "AssetTypeActions" + +FDialogueAssetTypeActions::FDialogueAssetTypeActions(uint32 InAssetCategory) +: MyAssetCategory(InAssetCategory) +{ +} + +FText FDialogueAssetTypeActions::GetName() const +{ + return LOCTEXT("DialogueAssetTypeActionsName", "Dialogue"); +} + +FColor FDialogueAssetTypeActions::GetTypeColor() const +{ + return FColor(255, 55, 220); +} + +UClass* FDialogueAssetTypeActions::GetSupportedClass() const +{ + return UDialogueAsset::StaticClass(); +} + +void FDialogueAssetTypeActions::OpenAssetEditor(const TArray& InObjects, + TSharedPtr EditWithinLevelEditor) +{ + EToolkitMode::Type Mode = EditWithinLevelEditor.IsValid() ? EToolkitMode::WorldCentric : EToolkitMode::Standalone; + + for (auto ObjIt = InObjects.CreateConstIterator(); ObjIt; ++ObjIt) + { + if (UDialogueAsset* DialogueAsset = Cast(*ObjIt)) + { + TSharedRef Editor = MakeShareable(new FDialogueAssetEditor()); + Editor->InitDialogueEditor(Mode, EditWithinLevelEditor, DialogueAsset); + } + } + //FAssetTypeActions_Base::OpenAssetEditor(InObjects, EditWithinLevelEditor); +} + +uint32 FDialogueAssetTypeActions::GetCategories() +{ + return MyAssetCategory; +} + +#undef LOCTEXT_NAMESPACE diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Base.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Base.cpp new file mode 100644 index 0000000..e086b91 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Base.cpp @@ -0,0 +1,34 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Node/DialogueGraphNode_Base.h" + +#define LOCTEXT_NAMESPACE "DialogueGraphNode" + +UDialogueGraphNode_Base::UDialogueGraphNode_Base() +{ +} + +void UDialogueGraphNode_Base::AllocateDefaultPins() +{ + DefaultInputPin = CreatePin(EGPD_Input, TEXT("PinCategory_Default"), TEXT("In")); + CreatePin(EGPD_Output, TEXT("PinCategory_Default"), TEXT("Out")); +} + +void UDialogueGraphNode_Base::SetPostion(FVector2D InPos) +{ + NodePosX = InPos.X; + NodePosY = InPos.Y; +} + +void UDialogueGraphNode_Base::InitializeNodeData() +{ + NodeData = NewObject(this); +} + +void UDialogueGraphNode_Base::OnPropertiesChanged() +{ + GetGraph()->NotifyNodeChanged(this); +} + +#undef LOCTEXT_NAMESPACE + diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_NPC.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_NPC.cpp new file mode 100644 index 0000000..0de83e4 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_NPC.cpp @@ -0,0 +1,14 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Node/DialogueGraphNode_NPC.h" + + +UDialogueGraphNode_NPC::UDialogueGraphNode_NPC() +{ + +} + + + + diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Player.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Player.cpp new file mode 100644 index 0000000..789015d --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Player.cpp @@ -0,0 +1,6 @@ +#include "Node/DialogueGraphNode_Player.h" + +UDialogueGraphNode_Player::UDialogueGraphNode_Player() +{ + +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Root.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Root.cpp new file mode 100644 index 0000000..d54e34f --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Node/DialogueGraphNode_Root.cpp @@ -0,0 +1,9 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Node/DialogueGraphNode_Root.h" + +void UDialogueGraphNode_Root::AllocateDefaultPins() +{ + CreatePin(EGPD_Output, TEXT("PinCategory_Default"), TEXT("In")); +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Widget/DialogueGraphNode.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Widget/DialogueGraphNode.cpp new file mode 100644 index 0000000..86166c6 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Widget/DialogueGraphNode.cpp @@ -0,0 +1,62 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Widget/DialogueGraphNode.h" + + +void SDialogueGraphNode::Construct(const FArguments& InArgs, UDialogueGraphNode_Base* InNode) +{ + GraphNode = InNode; + UpdateGraphNode(); +} + +FText SDialogueGraphNode::GetDialogueText() const +{ + UDialogueGraphNode_Base* DialogueNode = Cast(GraphNode); + return DialogueNode->GetDialogueNodeData()->Text; +} + +TSharedRef SDialogueGraphNode::CreateNodeContentArea() +{ + // NODE CONTENT AREA + return SNew(SBorder) + .BorderImage( FAppStyle::GetBrush("NoBorder") ) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + .Padding( FMargin(0,3) ) + [ + SNew(SHorizontalBox) + +SHorizontalBox::Slot() + .HAlign(HAlign_Left) + .FillWidth(1.0f) + [ + // LEFT + SAssignNew(LeftNodeBox, SVerticalBox) + ] + +SHorizontalBox::Slot() + .AutoWidth() + .HAlign(HAlign_Center) + .Padding(10.0f, 5.0f) + [ + SNew(SBorder) + .BorderBackgroundColor(FSlateColor(FLinearColor::Gray)) + .Padding(10.0f) + .Content() + [ + SAssignNew(DialogueText, STextBlock) + .MinDesiredWidth(260.0f) + .Text(this, &SDialogueGraphNode::GetDialogueText) + .WrapTextAt(250.0f) + ] + ] + +SHorizontalBox::Slot() + .AutoWidth() + .HAlign(HAlign_Right) + [ + // RIGHT + SAssignNew(RightNodeBox, SVerticalBox) + ] + ]; +} + + diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Widget/DialogueGraphPin.cpp b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Widget/DialogueGraphPin.cpp new file mode 100644 index 0000000..3a6cde1 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Private/Widget/DialogueGraphPin.cpp @@ -0,0 +1,36 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Widget/DialogueGraphPin.h" + +#include "Node/DialogueGraphNode_Base.h" + + +void SDialogueGraphPin::Construct(const FArguments& InArgs, UEdGraphPin* InPin) +{ + SGraphPin::Construct(SGraphPin::FArguments(), InPin); + // FullPinHorizontalRowWidget.Pin() + // ->InsertSlot(0) + // [ + // SNew(SBorder) + // .BorderBackgroundColor(FSlateColor(FLinearColor::Gray)) + // .Padding(10.0f) + // .Content() + // [ + // SAssignNew(DialogueText, STextBlock) + // .MinDesiredWidth(260.0f) + // .WrapTextAt(250.0f) + // .Text(this, &SDialogueGraphPin::GetDialogueText) + // ] + // ]; +} + +FText SDialogueGraphPin::GetDialogueText() const +{ + UEdGraphPin* ParentPin = GetPinObj(); + if (UDialogueGraphNode_Base* ResponseNode = Cast(ParentPin->GetOwningNode())) + { + return ResponseNode->GetDialogueNodeData()->Text; + } + return FText(); +} diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueAssetEditor.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueAssetEditor.h new file mode 100644 index 0000000..7c826cd --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueAssetEditor.h @@ -0,0 +1,75 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "DialogueAsset.h" +#include "GraphEditor.h" +#include "WorkflowOrientedApp/WorkflowCentricApplication.h" + +class UDialogueGraph; +class IDetailsView; +class UDialogueGraphNode_Base; + +/** + * 对话编辑器工具包 + */ +class DIALOGUEEDITOR_API FDialogueAssetEditor : public FWorkflowCentricApplication, public FEditorUndoClient, public FNotifyHook +{ +public: + /** IAssetEditorToolkit interface */ + virtual FName GetToolkitFName() const override { return FName("DialogueEditor"); } + virtual FText GetBaseToolkitName() const override; + virtual FString GetWorldCentricTabPrefix() const override { return TEXT("DialogueEditor"); } + virtual FLinearColor GetWorldCentricTabColorScale() const override { return FLinearColor::White; } + + virtual void OnClose() override; + /** IAssetEditorToolkit interface */ + + FDialogueAssetEditor(); + virtual ~FDialogueAssetEditor(); + +public: + void InitDialogueEditor(const EToolkitMode::Type Mode, const TSharedPtr& InitToolkitHost, TObjectPtr InitDialogueAsset); + + // 获取图表 + UEdGraph* GetDialogueGraph() const { return DialogueGraph; } + + // 设置图表编辑器 + void SetGraphEditor(TSharedPtr InGraphEditor) { GraphEditor = InGraphEditor; } + + // 设置细节面板 + void SetDetailsView(TSharedPtr InDetailsView); + + // 图表选择改变回调,传递属性页需要显示的内容 + void OnGraphSelectionChanged(const FGraphPanelSelectionSet& Selection); + +protected: + void SaveGraphData(); + void LoadGraphData(); +protected: + TObjectPtr DialogueBeingEdited; + + // 图表对象 + UEdGraph* DialogueGraph; + + // 图表编辑器Widget + TSharedPtr GraphEditor; + + // 细节面板 + TSharedPtr DetailsView; + +private: + // 绑定图表命令 + void BindGraphCommands(); + + // 删除选中节点 + void DeleteSelectedNodes(); + bool CanDeleteNodes(); + + // 获取选中节点 + UDialogueGraphNode_Base* GetSelectedNode(const FGraphPanelSelectionSet& Selection); + + // 属性更新回调 + void OnNodeDetailViewPropertiesUpdated(const FPropertyChangedEvent& Event); +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueAssetFactory.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueAssetFactory.h new file mode 100644 index 0000000..e660f8f --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueAssetFactory.h @@ -0,0 +1,23 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Factories/Factory.h" +#include "DialogueAssetFactory.generated.h" + +/** + * + */ +UCLASS() +class DIALOGUEEDITOR_API UDialogueAssetFactory : public UFactory +{ + GENERATED_BODY() +public: + UDialogueAssetFactory(const FObjectInitializer& ObjectInitializer); + + virtual UObject* FactoryCreateNew(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext) override; + virtual FText GetDisplayName() const override; + virtual FString GetDefaultNewAssetName() const override; + virtual bool ShouldShowInNewMenu() const override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueDetailsTabSummoner.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueDetailsTabSummoner.h new file mode 100644 index 0000000..cdae22c --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueDetailsTabSummoner.h @@ -0,0 +1,25 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "WorkflowOrientedApp/WorkflowTabFactory.h" + +class FDialogueAssetEditor; + +/** + * 细节面板Tab工厂 + */ +class FDialogueDetailsTabSummoner : public FWorkflowTabFactory +{ +public: + FDialogueDetailsTabSummoner(TSharedPtr InDialogueEditor); + +private: + TWeakPtr DialogueEditor; + +public: + /** FWorkflowTabFactory Interface */ + virtual TSharedRef CreateTabBody(const FWorkflowTabSpawnInfo& Info) const override; + virtual FText GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditor.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditor.h new file mode 100644 index 0000000..a2f9644 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditor.h @@ -0,0 +1,14 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +class FDialogueEditorModule : public IModuleInterface +{ +public: + virtual void StartupModule() override; + virtual void ShutdownModule() override; + +private: + TArray>CreatedAssetTypeActions; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditorMode.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditorMode.h new file mode 100644 index 0000000..0bc84ad --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditorMode.h @@ -0,0 +1,27 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "WorkflowOrientedApp/ApplicationMode.h" +#include "WorkflowOrientedApp/WorkflowTabManager.h" + + + +/** + * 对话编辑器模式 + */ +class FDialogueEditorMode : public FApplicationMode +{ +public: + FDialogueEditorMode(TSharedPtr InDialogueEditor); + +private: + TWeakPtr DialogueEditor; + FWorkflowAllowedTabSet TabFactories; + +public: + /** FApplicationMode */ + virtual void RegisterTabFactories(TSharedPtr InTabManager) override; + +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditorStyle.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditorStyle.h new file mode 100644 index 0000000..35eea23 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueEditorStyle.h @@ -0,0 +1,12 @@ +#pragma once + +class FDialogueEditorStyle +{ +public: + static void Initialize(); + static void Shutdown(); + + static TSharedPtr< class ISlateStyle > Get(); +private: + static TSharedPtr StyleSet; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraph.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraph.h new file mode 100644 index 0000000..b299c8d --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraph.h @@ -0,0 +1,23 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "EdGraph/EdGraph.h" +#include "DialogueGraph.generated.h" + + + +/** + * 对话图表类 + */ +UCLASS() +class DIALOGUEEDITOR_API UDialogueGraph : public UEdGraph +{ + GENERATED_BODY() + +public: + UDialogueGraph(); + /** UEdGraph interface */ + virtual void AddNode(UEdGraphNode* NodeToAdd, bool bUserAction, bool bSelectNewNode) override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphPanelNodeFactory.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphPanelNodeFactory.h new file mode 100644 index 0000000..1e1da6a --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphPanelNodeFactory.h @@ -0,0 +1,15 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "EdGraphUtilities.h" + +/** + * + */ +class DIALOGUEEDITOR_API FDialogueGraphPanelNodeFactory: public FGraphPanelNodeFactory +{ +public: + virtual TSharedPtr CreateNode(class UEdGraphNode* Node) const override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphPanelPinFactory.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphPanelPinFactory.h new file mode 100644 index 0000000..ebd6a14 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphPanelPinFactory.h @@ -0,0 +1,15 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "DialogueGraphPanelNodeFactory.h" + +/** + * + */ +class DIALOGUEEDITOR_API FDialogueGraphPanelPinFactory: public FGraphPanelPinFactory +{ +public: + virtual TSharedPtr CreatePin(class UEdGraphPin* InPin) const override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphSchema.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphSchema.h new file mode 100644 index 0000000..2daaafb --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphSchema.h @@ -0,0 +1,45 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "EdGraph/EdGraphSchema.h" +#include "DialogueGraphSchema.generated.h" + +/** + * 创建节点的Action + */ +USTRUCT() +struct FDialogueGraphSchemaAction_NewNode : public FEdGraphSchemaAction +{ + GENERATED_BODY() + +public: + FDialogueGraphSchemaAction_NewNode() : FEdGraphSchemaAction() {} + + FDialogueGraphSchemaAction_NewNode(UClass* InClassTemplate, FText InNodeCategory, FText InMenuDesc, FText InToolTip) + : FEdGraphSchemaAction(InNodeCategory, InMenuDesc, InToolTip, 0), ClassTemplate(InClassTemplate) {} + + virtual UEdGraphNode* PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode = true) override; + +protected: + UClass* ClassTemplate = nullptr; +}; + +/** + * 对话图表规则 + */ +UCLASS() +class DIALOGUEEDITOR_API UDialogueGraphSchema : public UEdGraphSchema +{ + GENERATED_BODY() + +public: + /** UEdGraphSchema */ + virtual void CreateDefaultNodesForGraph(UEdGraph& Graph) const override; + // 右键菜单创建节点 + virtual void GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const override; + + // 连接规则 + virtual const FPinConnectionResponse CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphTabSummoner.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphTabSummoner.h new file mode 100644 index 0000000..92dd602 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/DialogueGraphTabSummoner.h @@ -0,0 +1,25 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "WorkflowOrientedApp/WorkflowTabFactory.h" + +class FDialogueAssetEditor; + +/** + * 图表Tab工厂 + */ +class FDialogueGraphTabSummoner : public FWorkflowTabFactory +{ +public: + FDialogueGraphTabSummoner(TSharedPtr InDialogueEditor); + +private: + TWeakPtr DialogueEditor; + +public: + /** FWorkflowTabFactory Interface */ + virtual TSharedRef CreateTabBody(const FWorkflowTabSpawnInfo& Info) const override; + virtual FText GetTabToolTipText(const FWorkflowTabSpawnInfo& Info) const override; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/FDialogueAssetTypeActions.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/FDialogueAssetTypeActions.h new file mode 100644 index 0000000..65884aa --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/FDialogueAssetTypeActions.h @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "AssetTypeActions_Base.h" + +/** + * + */ +class DIALOGUEEDITOR_API FDialogueAssetTypeActions:public FAssetTypeActions_Base +{ +public: + FDialogueAssetTypeActions(uint32 InAssetCategory); + + /** IAssetTypeActions interface */ + virtual FText GetName() const override; + virtual FColor GetTypeColor() const override; + virtual UClass* GetSupportedClass() const override; + virtual void OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor = TSharedPtr()) override; + virtual uint32 GetCategories() override; + /** IAssetTypeActions interface */ + +private: + uint32 MyAssetCategory; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Base.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Base.h new file mode 100644 index 0000000..34057f9 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Base.h @@ -0,0 +1,48 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "DialogueAsset.h" +#include "DialogueGraph.h" +#include "EdGraph/EdGraphNode.h" +#include "DialogueGraphNode_Base.generated.h" + +/** + * 对话节点基类 + */ +UCLASS() +class DIALOGUEEDITOR_API UDialogueGraphNode_Base : public UEdGraphNode +{ + GENERATED_BODY() + +public: + UDialogueGraphNode_Base(); + /** UEdGraphNode */ + virtual bool CanUserDeleteNode() const override { return true; } + virtual void AllocateDefaultPins() override; + + void SetPostion(FVector2D InPos); + void SetDialogueNodeData(UDialogueNodeData_Base* InNodeData) { NodeData = InNodeData; } + virtual void InitializeNodeData(); + virtual void OnPropertiesChanged(); + UEdGraphPin* GetDefaultInputPin() { return DefaultInputPin; } + UDialogueNodeData_Base* GetDialogueNodeData() {return NodeData;} + virtual EDialogueNodeType GetDialogueNodeType() { return EDialogueNodeType::None; } + // // 节点标题 + // virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override; + // + // // 节点颜色 + // virtual FLinearColor GetNodeTitleColor() const override; + // + + +protected: + UEdGraphPin* DefaultInputPin = nullptr; + UPROPERTY() + UDialogueNodeData_Base* NodeData; + + +}; + + diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_NPC.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_NPC.h new file mode 100644 index 0000000..63a640f --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_NPC.h @@ -0,0 +1,24 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "DialogueGraphNode_Base.h" +#include "DialogueGraphNode_NPC.generated.h" +/** + * + */ +UCLASS() +class DIALOGUEEDITOR_API UDialogueGraphNode_NPC: public UDialogueGraphNode_Base +{ + GENERATED_BODY() +public: + UDialogueGraphNode_NPC(); + + /** UEdGraphNode Interface */ + virtual FText GetNodeTitle(ENodeTitleType::Type titalType) const override { return FText::FromString("NPC"); } + virtual FLinearColor GetNodeTitleColor() const override { return FLinearColor(FColor::Green); } + + + virtual EDialogueNodeType GetDialogueNodeType() override { return EDialogueNodeType::NPC;} +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Player.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Player.h new file mode 100644 index 0000000..686aa7e --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Player.h @@ -0,0 +1,19 @@ +#pragma once +#include "CoreMinimal.h" +#include "DialogueGraphNode_Base.h" +#include "DialogueGraphNode_Player.generated.h" + +UCLASS() +class UDialogueGraphNode_Player: public UDialogueGraphNode_Base +{ + GENERATED_BODY() +public: + UDialogueGraphNode_Player(); + + /** UEdGraphNode Interface */ + virtual FText GetNodeTitle(ENodeTitleType::Type titalType) const override { return FText::FromString("Player"); } + virtual FLinearColor GetNodeTitleColor() const override { return FLinearColor(FColor::Green); } + + + virtual EDialogueNodeType GetDialogueNodeType() override { return EDialogueNodeType::Player;} +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Root.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Root.h new file mode 100644 index 0000000..79eb3e6 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Node/DialogueGraphNode_Root.h @@ -0,0 +1,23 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "DialogueGraph.h" +#include "DialogueGraphNode_Base.h" +#include "DialogueGraphNode_Root.generated.h" +/** + * + */ +UCLASS() +class DIALOGUEEDITOR_API UDialogueGraphNode_Root: public UDialogueGraphNode_Base +{ + GENERATED_BODY() +public: + /** UEdGraphNode Interface */ + virtual FText GetNodeTitle(ENodeTitleType::Type titalType) const override { return FText::FromString("Start"); } + virtual FLinearColor GetNodeTitleColor() const override { return FLinearColor(FColor::Red); } + virtual bool CanUserDeleteNode() const override { return false; } + virtual void AllocateDefaultPins() override; + virtual EDialogueNodeType GetDialogueNodeType() override { return EDialogueNodeType::Root;} +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Widget/DialogueGraphNode.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Widget/DialogueGraphNode.h new file mode 100644 index 0000000..16fb009 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Widget/DialogueGraphNode.h @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Node/DialogueGraphNode_Base.h" +#include "SGraphNode.h" + +/** + * + */ +class DIALOGUEEDITOR_API SDialogueGraphNode: public SGraphNode +{ +public: + SLATE_BEGIN_ARGS(SDialogueGraphNode) + {} + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs, UDialogueGraphNode_Base* InNode); + FText GetDialogueText() const; + + /** SGraphNode Interface */ + virtual TSharedRef CreateNodeContentArea() override; +private: + TSharedPtr DialogueText; +}; diff --git a/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Widget/DialogueGraphPin.h b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Widget/DialogueGraphPin.h new file mode 100644 index 0000000..5fc8d63 --- /dev/null +++ b/ProjectFish/Plugins/Dialogue/Source/DialogueEditor/Public/Widget/DialogueGraphPin.h @@ -0,0 +1,48 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "SGraphPin.h" + +/** + * 空pin + */ + +class DIALOGUEEDITOR_API SDialogueNoneGraphPin: public SGraphPin +{ +public: + SLATE_BEGIN_ARGS(SDialogueNoneGraphPin) + {} + SLATE_END_ARGS() + void Construct(const FArguments& InArgs, UEdGraphPin* InGraphPinObj) { + SGraphPin::Construct(SGraphPin::FArguments(), InGraphPinObj); + } + +protected: + virtual FSlateColor GetPinColor() const override { + return FSlateColor(FLinearColor::White); + } + +}; + +/** + * 对话pin + */ +class DIALOGUEEDITOR_API SDialogueGraphPin: public SGraphPin +{ +public: + SLATE_BEGIN_ARGS(SDialogueGraphPin) + {} + SLATE_END_ARGS() + void Construct(const FArguments& InArgs, UEdGraphPin* InPin); + FText GetDialogueText() const; + +protected: + /** SGraphPin Interface */ + virtual FSlateColor GetPinColor() const override {return FSlateColor(FLinearColor::White);} + +private: + TSharedPtr DialogueText; + +};