Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,17 @@ bool UDlgHumanReadableTextCommandlet::ImportHumanReadableFormatIntoDialogue(cons
const bool bIsRootNode = HumanNode.NodeIndex <= RootNodeIndex;

// Node
UDlgNode* Node = bIsRootNode ? Dialogue->GetMutableStartNodes()[FMath::Abs(RootNodeIndex) - 1] : Dialogue->GetMutableNodeFromIndex(HumanNode.NodeIndex);
const int32 StartNodeIndex = FMath::Abs(HumanNode.NodeIndex) - 1;
UDlgNode* Node = nullptr;
if (bIsRootNode)
{
TArray<UDlgNode*>& StartNodes = Dialogue->GetMutableStartNodes();
Node = StartNodes.IsValidIndex(StartNodeIndex) ? StartNodes[StartNodeIndex] : nullptr;
}
else
{
Node = Dialogue->GetMutableNodeFromIndex(HumanNode.NodeIndex);
}
if (Node == nullptr)
{
UE_LOG(LogDlgHumanReadableTextCommandlet, Warning, TEXT("Invalid node index = %d, in Dialogue = `%s`. Ignoring."), HumanNode.NodeIndex, *Dialogue->GetPathName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ struct FDlgNodeSpeechSequence_FormatHumanReadable
public:
// Metadata
UPROPERTY()
int32 NodeIndex = INDEX_NONE - 1;
int32 NodeIndex = MIN_int32;

UPROPERTY()
FName Speaker;
Expand All @@ -114,12 +114,12 @@ struct FDlgNodeSpeech_FormatHumanReadable

public:
// INDEX_NONE is root node
bool IsValid() const { return NodeIndex >= INDEX_NONE; }
bool IsValid() const { return NodeIndex != MIN_int32; }

public:
// Metadata, NodeIndex
UPROPERTY()
int32 NodeIndex = INDEX_NONE - 1;
int32 NodeIndex = MIN_int32;

UPROPERTY()
FName Speaker;
Expand Down
14 changes: 14 additions & 0 deletions Source/DlgSystemEditor/DlgCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ void FDlgCommands::RegisterCommands()
FInputChord(EModifierKey::Control, EKeys::F)
);

UI_COMMAND(
ImportDialogueJSON,
"Import JSON...",
"Import dialogue data from a JSON file",
EUserInterfaceActionType::Button, FInputChord()
);

UI_COMMAND(
ExportDialogueJSON,
"Export JSON...",
"Export dialogue data to a JSON file",
EUserInterfaceActionType::Button, FInputChord()
);

UI_COMMAND(
HideNodes,
"HideNodes",
Expand Down
6 changes: 6 additions & 0 deletions Source/DlgSystemEditor/DlgCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ class DLGSYSTEMEDITOR_API FDlgCommands : public TCommands<FDlgCommands>
// Open find in current Dialogue tab
TSharedPtr<FUICommandInfo> FindInDialogue;

// Import dialogue from JSON
TSharedPtr<FUICommandInfo> ImportDialogueJSON;

// Export dialogue to JSON
TSharedPtr<FUICommandInfo> ExportDialogueJSON;

// Hide Selected Node
TSharedPtr<FUICommandInfo> HideNodes;

Expand Down
1 change: 1 addition & 0 deletions Source/DlgSystemEditor/DlgSystemEditor.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public DlgSystemEditor(ReadOnlyTargetRules Target) : base(Target)

// e.g. FPlatformApplicationMisc::ClipboardCopy
"ApplicationCore",
"DesktopPlatform",
});

#if UE_4_24_OR_LATER
Expand Down
139 changes: 139 additions & 0 deletions Source/DlgSystemEditor/Editor/DlgEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
#include "DlgSystemEditor/Search/DlgSearchManager.h"
#include "DlgSystemEditor/Search/SDlgFindInDialogues.h"
#include "Graph/SchemaActions/DlgConvertSpeechNodesToSpeechSequence_GraphSchemaAction.h"
#include "DlgSystemEditor/IO/DlgJsonDialogueHelper.h"
#include "DesktopPlatformModule.h"
#include "IDesktopPlatform.h"

#define LOCTEXT_NAMESPACE "DialogueEditor"

Expand Down Expand Up @@ -668,6 +671,18 @@ void FDlgEditor::BindEditorCommands()
FExecuteAction::CreateLambda([this] { SummonSearchUI(true); })
);

// Import JSON
ToolkitCommands->MapAction(
FDlgCommands::Get().ImportDialogueJSON,
FExecuteAction::CreateSP(this, &Self::OnCommandImportDialogueJSON)
);

// Export JSON
ToolkitCommands->MapAction(
FDlgCommands::Get().ExportDialogueJSON,
FExecuteAction::CreateSP(this, &Self::OnCommandExportDialogueJSON)
);

// Map the global actions
FDlgSystemEditorModule::MapActionsForFileMenuExtender(ToolkitCommands);
FDlgSystemEditorModule::MapActionsForHelpMenuExtender(ToolkitCommands);
Expand Down Expand Up @@ -783,6 +798,8 @@ void FDlgEditor::ExtendToolbar()
);

ToolbarBuilder.AddToolBarButton(FDlgCommands::Get().ToggleShowEventsAndConditions);
ToolbarBuilder.AddToolBarButton(FDlgCommands::Get().ImportDialogueJSON);
ToolbarBuilder.AddToolBarButton(FDlgCommands::Get().ExportDialogueJSON);
}
ToolbarBuilder.EndSection();
})
Expand Down Expand Up @@ -1457,4 +1474,126 @@ void FDlgEditor::UpdateNodesHighlightedByProxy(const TSet<UObject*>& NewSelectio
// End of own functions
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void FDlgEditor::OnCommandImportDialogueJSON()
{
check(DialogueBeingEdited);

IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (!DesktopPlatform)
{
return;
}

TArray<FString> OpenFilenames;
const bool bOpened = DesktopPlatform->OpenFileDialog(
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
LOCTEXT("ImportDialogueJSON_Title", "Import Dialogue JSON").ToString(),
FPaths::ProjectDir(),
TEXT(""),
TEXT("Dialogue JSON (*.dlg_human.json)|*.dlg_human.json"),
EFileDialogFlags::None,
OpenFilenames
);

if (!bOpened || OpenFilenames.Num() == 0)
{
return;
}

const FString& FilePath = OpenFilenames[0];
FString ErrorMessage;

// Try updating matching existing nodes before offering to replace the whole dialogue.
if (FDlgJsonDialogueHelper::ImportDialogueNodeUpdatesFromJsonFile(FilePath, DialogueBeingEdited, &ErrorMessage))
{
Refresh(false);
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok,
*FString::Printf(TEXT("Successfully imported dialogue from:\n%s"), *FilePath),
TEXT("Import Successful"));
return;
}

// Regular import failed - offer destructive import with WARNING
const EAppReturnType::Type WarningResult = FPlatformMisc::MessageBoxExt(EAppMsgType::YesNo,
*FString::Printf(
TEXT("WARNING!\n\n"
"Import failed with error:\n%s\n\n"
"The dialogue structure does not match the JSON file.\n\n"
"Do you want to DESTRUCTIVELY OVERWRITE the dialogue?\n"
"This will DELETE all existing nodes and recreate them from the JSON file.\n\n"
"File: %s"),
*ErrorMessage, *FilePath),
TEXT("WARNING! Destructive Import"));

if (WarningResult == EAppReturnType::Yes)
{
FString DestructiveError;
if (FDlgJsonDialogueHelper::ImportDialogueFromJsonFileAsReplacement(FilePath, DialogueBeingEdited, &DestructiveError))
{
Refresh(false);
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok,
*FString::Printf(TEXT("Successfully imported dialogue (destructive) from:\n%s"), *FilePath),
TEXT("Import Successful"));
}
else
{
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok,
*FString::Printf(TEXT("Destructive import failed:\n%s"), *DestructiveError),
TEXT("Import Failed"));
}
}
}

void FDlgEditor::OnCommandExportDialogueJSON()
{
check(DialogueBeingEdited);

IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (!DesktopPlatform)
{
return;
}

FString SaveFilename = DialogueBeingEdited->GetDialogueFName().ToString() + TEXT(".dlg_human.json");
TArray<FString> SavePaths;
const bool bSaved = DesktopPlatform->SaveFileDialog(
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
LOCTEXT("ExportDialogueJSON_Title", "Export Dialogue JSON").ToString(),
FPaths::ProjectDir(),
*SaveFilename,
TEXT("Dialogue JSON (*.dlg_human.json)|*.dlg_human.json"),
EFileDialogFlags::None,
SavePaths
);

if (!bSaved || SavePaths.Num() == 0)
{
return;
}

const FString& SavePath = SavePaths[0];
FString JsonString;
if (FDlgJsonDialogueHelper::ExportDialogueToJson(DialogueBeingEdited, JsonString))
{
if (FFileHelper::SaveStringToFile(JsonString, *SavePath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM))
{
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok,
*FString::Printf(TEXT("Successfully exported dialogue to:\n%s"), *SavePath),
TEXT("Export Successful"));
}
else
{
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok,
*FString::Printf(TEXT("Failed to write file:\n%s"), *SavePath),
TEXT("Export Failed"));
}
}
else
{
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok,
TEXT("Failed to serialize dialogue to JSON."),
TEXT("Export Failed"));
}
}

#undef LOCTEXT_NAMESPACE
6 changes: 6 additions & 0 deletions Source/DlgSystemEditor/Editor/DlgEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ class DLGSYSTEMEDITOR_API FDlgEditor : public IDlgEditor, public FGCObject, publ
// Reloads the Dialogue from the file
void OnCommandDialogueReload() const;

// Imports the Dialogue from a JSON file
void OnCommandImportDialogueJSON();

// Exports the Dialogue to a JSON file
void OnCommandExportDialogueJSON();

//
// Graph events
//
Expand Down
Loading