Skip to content

Dialogue manual

Daniel Butum edited this page May 22, 2023 · 46 revisions

1. Introduction

The plugin contains a dialogue backend system with proper editor support for unreal engine.

This document describes both the integration and the usage of the system, however it expects some general knowledge about the engine from the reader.

Using the plugin you will create Dialogue Assets in the content browser - they contain the static data with some logical expressions (they are similar to behavior trees, but not that complex). In those you will reference Dialogue Participants - they are objects implementing the proper interface functions.

In order to start a dialogue runtime you will need to provide an array of Dialogue Participants matching the ones referenced inside the dialogue. If the dialogue is started successfully you will get a Dialogue Context which can be used to control the dialogue and get information from its current state.

The Dialogue Memory will contain the visited nodes for each dialogue - this can be used for some of the conditions.

Both UI and serialization are outside of the scope of this plugin - we found them way too game specific to be included.

2. Dialogue

Creation

Create Dialogue Asset with Right Click -> Dialogue System -> Dialogue.

Export_CreateDialogue

The dialogue graph is constructed from different nodes and the edges between them. Some node contains text or texts, others are only there to build up more complicated logical behavior. The edges can represent player choices or in some case they are simply there to modify the flow of the dialogue.

Node Indices

Just like in the behavior tree, the children of a node are sorted based on the horizontal location of their visual representation: the one in the left is the first, and the one in the right is the last.

Each node has a number in the top right corner, that is the index of the node.

image_0

Node types

Start Node

start_node

Defines the entry point of the Dialogue - its children are evaluated at the beginning of the dialogue and the first successful child defines the first line of the dialogue. It does not contain any text, does not have any conditions, does not fire any event, and it is the only node without a node owner. The start node is already placed and can not be removed.

Speech Node

speech_node

A standard dialogue line - it has an owner (speaker) and a text. Optionally it can also contain a Sound Wave or a Dialogue Wave - you can select which to use (or hide both) globally in the dialogue dialogue settings.

Virtual Parent Node

The node has a bool property IsVirtualParent. If it is set the Node will list the children of its first satisfied child as its own - it is useful when you want to give the user the same player choices after different NPC lines. Virtual Parent dialogue speech nodes are displayed with gray background.

You can think of this node type as a helper/shortcut node.

Example:

  • With virtual parent node with_virtual_parent
  • Without virtual parent node without_virtual_parent

Speech Sequence Node

speech_sequence_node

The purpose of this node is to make the graph more organized - a single speech sequence node contains the data of multiple speech nodes and can be used instead of those in linear cases. You can extract a speech sequence node to a series of speech nodes via Right Click on the node and choosing Convert to speech nodes in the context menu. You can also convert more speech nodes into a sequence node, but only if they are connected with each other without any branches. Simply select them, right click on empty space in the grid and select Convert… from the context menu.

Selector Node

selector_node

This node type does not contain any text to display and the dialogue is not supposed to stop reaching these. When the node is entered its children are evaluated and one of them is selected immediately. Depending on the Selector Type the selected node is either the first satisfied child or a randomly picked one.

End Node

end_node

The dialogue is terminated when the execution flow reaches an end node. This node type does not have any text attached, but it can have conditions and it can trigger events.

Edges

Each edge can contain conditions and a text. The ones coming from a Selector node are evaluated and stepped over automatically. In other cases the game can get the data from the actual outgoing edges from the current node to provide them as choices to the player.

Edges that are part of the shortest way from start node to the target node are called Primary Edges, the rest are called Secondary edges. This categorization is purely for visual clarity: they can be displayed with different colors and each category can be hidden.

Building the graph

Base operations:

Add node: right click in the grid and select the desired node type under Dialogue Node category in the context menu.

Add edge: press and hold left mouse button on the (black) border area of the source node, then drag the mouse to the border of the target node.

Retarget edge: hold Ctrl and drag the edge via left mouse button to change its target node.

The graph editor also supports undo/redo and copy/paste.

To edit a graph or an edge simply select it via left click, then you can use the details panel to change its properties.

Conditions

Edges and nodes can contain enter conditions - a node is only reachable from an edge if the conditions belonging to the edge and to the node are all satisfied.

You can add a condition in the details panel of the edge or node:

condition_example_1

If a node or edge has a condition an icon is displayed in the graph:

condition_node condition_edge

The conditions are stored in arrays and the content of those arrays are evaluated together. The Strength of a condition can be strong or weak. A condition array is satisfied if it only contains satisfied strong conditions, and it has at least one satisfied weak condition, or none at all. In other words the condition array fails (and the node cannot be entered) if there are any failed strong conditions or all the weak conditions are failed ones (or both).

The Condition Type defines the behaviour of the condition

condition_type

Some condition asks for a variable from the owner participant and performs a logical operation on it. The supported variable types are Integer, Float, Boolean and Name. (Managing these variables are outside of the scope of the plugin, it simply uses an interface to request those values from the participants).

The Check named condition expects the participant to execute a more complicated logical expression identified by the Condition Name.

condition_details_panel

The Was node already visited condition checks if the node with the given index was already visited or not.

If the Long Term Memory is checked the previous dialogues using the same Dialogue Asset are taken into account as well, otherwise the check is limited to the actual dialogue context.

Using random in any condition is not supported and can lead to undefined behavior. The dialogue system can call the conditions multiple time in an update and it expects to get the same results.

Check class variables

class_conditions

For check class variables please check the Reflection Variables section.

Events

event_node

Nodes can have enter events - these are executed each time the node is reached in the active dialogue context. Nodes with events are also marked with an icon (see image).

event_details_panel

Similarly to Conditions, events can either modify (or set) the value of a supported variable type, or it can simply execute a named event the participant have to handle.

Modify class variables

class_events

For modify class variables please check the Reflection Variables section.

3. Integration and usage

Participants

To start a dialogue some of your objects (e.g. your player character class/blueprint) need to implement the DlgDialogueParticipant interface. It supports both C++ and Blueprints.

In Blueprint you will get the functions you have to implement if you added the interface to the class using the Class Settings.

If you work with C++ check DlgDialogueParticipant.h.

Ensure your Character implements the DlgDialogueParticipant interface

Export_implement_interface_expanded

Functions

ParticipantInterface

Implement GetParticipantName Function

The only function you have to implement in all cases is the GetParticipantName - this should return a Name variable which has to be unique inside any Dialogue Asset - the participant is identified with this inside the Dialogue Editor.

Used for Event Functions

ℹ️️ Example Blueprint Using Dialogue Values

  • OnDialogueEvent - Used for the event type Event
  • ModifyNameValue - Used for the event type Modify Dialogue Name Value
  • ModifyIntValue - Used for the event type Modify Dialogue Int Value
  • ModifyBoolValue - Used for the event type Modify Dialogue Bool Value
  • ModifyFloatValue - Used for the event type Modify Dialogue Float Value

Used for Condition Functions

ℹ️️ Example Blueprint Using Dialogue Values

  • GetNameValue - Used for the condition type Check Dialogue Name Value
  • GetIntValue - Used for the condition type Check Dialogue Int Value
  • GetFloatValue - Used for the condition type Check Dialogue Float Value
  • GetBoolValue - Used for the condition type Check Dialogue Bool Value
  • CheckCondition - Used for the condition type Check Dialogue Named Condition

Extra Info Functions

  • GetParticipantIcon - Extra Information, Participant icon to display
  • GetParticipantDisplayName - Extra Information, UI name of this participant, what is displayed inside the UI`
  • GetParticipantGender - May be used for formatted node texts, check HERE for more information

Dialogue Control

To start a dialogue call the UDlgManager::StartDialogue static function. You will need to provide a dialogue asset and an array of objects (implementing the participant interface).

It returns with the DialogueContext which can be used to control the ongoing dialogue.

start_dialogue

After the dialogue is started it is already executed to the point where the first player choice is required - selecting the only available option is also considered to be a choice in this case.

You can get the active node data and the currently available options from the context using the following DlgContext functions: GetOptionNum, GetOptionText, GetActiveNodeText, GetActiveParticipant.

If it is possible that the result of the conditions can change during the dialogue after a node became available but before the user picked an option the active options can be refreshed via the ReevaluateChildren function.

Once the player selected an option you can call ChooseOption with the selected option index to proceed the dialogue. If the function returns with false the dialogue is ended and the context must be dropped.

Dialogue Memory

If you use the long term memory of the dialogue system (for conditions checking if a certain dialogue node was visited or not during the whole game) you will have to serialize the dialogue history.

When saving your game simply call UDlgManager::GetDialogueHistory, and save the returned data structure. On load you can use the loaded value via UDlgManager::SetDialogueHistory.

history_get_set

When a new game is started (e.g. with a different player profile) you should also clear the dialogue memory via calling the setter function with an empty map, otherwise the system may use the previously used one.

Clearing

To clear the memory you can use the helper method UDlgManager::ClearDialogueHistory in the StartPlay/BeginPlay of your GameMode.

function_clear_dialogue_history

But you don't need to do this by default because the memory is already cleared automatically by the plugin whenever a new world is loaded, change this setting in the dialogue settings under Clear Dialogue History Automatically name.

project_settings_category_runtime

Dialogue Console Commands

To enable commands you have to manually register them using UDlgManager::RegisterDialogueModuleConsoleCommands inside your StartPlay/BeginPlay of your GameMode and unregister them in EndPlay using UDlgManager::UnRegisterDialogueModuleConsoleCommands

console_commands

Example:

gamemode_example

Speaker States

Speaker states can be used to add an extra FName to your nodes and/or edges. The Speaker State of the active node is passed to the GetParticipantIcon() function if it is called via UDlgContext::GetActiveParticipantIcon(). It can be used e.g. to attach emotions to nodes like Happy, Sad, etc. - you can use different images for the different states in your UMG widget. The SpeakerState of an edge can be requested via UDlgContext::GetOptionSpeakerState().

To display SpeakerStates in the dialogue editor you have to change the SpeakerState Visibility property in the dialogue settings.

SpeakerStates also have custom UI picker, but the used values are stored in a global cache.

A Blueprint Select on SpeakerState node is also provided - it lists all used SpeakerState values as wildcard option pins.

SelectOnSpeakerState

Reflection Variables (aka Class Events and Conditions)

dlg_reflection

This feature is useful if you want to directly modify variables inside your Blueprint instead of using your own data storage structures.

For example for the following case:

dlg_class_example_event

The dialogue system will modify the variable Stamina to 20 inside the MrCube participant.

Where MrCube has the following variables defined:

dlg_class_example_event_bp

Autocompletion

Because the dialogue editor can't know what variables a participant might have you need to set the participant class for it to work. Click on an empty canvas inside the dialogue editor and on the left side (by default) you should see the property DlgParticipantClasses.

dlg_participant_classes

dlg_participant_classes_autocompletion

Text arguments (aka varstrings)

text_arguments

If you want replaceable portions inside your Text nodes just add {identifier} inside and set the value it should have at runtime.

For the class variables types autocompletion to work please check the reflection autocompletion section

Adding your own data to the nodes

NodeData

If you want to store any other data on the nodes, create an object based on DlgNodeData. Add your data to this object, mark the variables public and you will be able to set the object type as NodeData to your nodes. You can create and use different NodeData objects.

To get your data for the active node just call GetActiveNodeData on the DlgContext, and cast it to your own type.

4. Helper tools

Blueprint Nodes

blueprint_switch_nodes

The plugin contains some custom blueprint nodes to help out with the implementation of the condition and event related functions.

They copy the behaviour of the Switch and Select nodes, but they get the participant name of the owner blueprint using the IDlgParticipant interface and gather all the associated values from all dialogues.

blueprint_switch_on_event

blueprint_select_dialogue_int

Dialogue Browser

browser_window

Click on Window -> Dialogue Browser to open it. The purpose of this window is to gather and visualize dialogue related data.

You can see all your dialogue participants here, check on the dialogues they are referenced in and see the list of associated events and variables.

The events/variables/conditions are also organized by dialogues, and the containing nodes or edges are also listed. Clicking on those will open the dialogue with the associated node/edge being selected.

Search Window

You can use the search window to search in the dialogue texts.

If you want to search inside a single dialogue open the search window via pressing ctrl+f in the dialogue editor.

If you want to search globally use the ones under Window -> Find in dialogues.

search_window

Runtime Display (aka Dialogue Data Display)

You can use the Dialogue Data Display window runtime to list the active participants, their variables/events. It is also possible to modify the values, check conditions or fire events.

To open in editor you can use Window -> Dialogue Data Display

Alternative way to run is the console command Dlg.DlgDataDisplay. (This also works in non-editor builds.)

Before you can use the DlgDataDisplay Window you need to register the console commands of the Plugin. An example is provided in the section Dialogue Console Commands or in the C++ project here.

dialogue_data_display

Dialogue Editor Settings

NOTE: Previous to version 5.0 of the plugin the settings where located here Edit -> Editor Preferences -> Content Editors -> Dialogue Editor.

You can open the Dialogue editor settings via Edit -> Project Settings -> Editor -> Dialogue. Here you can change the layout and the behaviour of the dialogue system.

project_settings

Localization

You can autoset namespaces for each dialogue files inside the Dialogue settings, then you can File -> Save All Dialogues to apply the changes.

We use the unreal localization pipeline https://docs.unrealengine.com/5.2/en-US/localizing-content-in-unreal-engine/.

Twine

Download twine from here.

Pro tip there is a black theme in Twine.

image

Export

You can export the dialogues to twine for spellchecking or if you want your translators to view your dialogues in a graph format.

To export to twine run:

<path to engine bin>/UE4Editor.exe <path to uproject file> -Run=DlgExportTwine -OutputDirectory=<output directory> -Flatten

Inside the <output directory> you should see all the dialogue files in an html format.

Open Twine and select in the top menu Twine -> Show Library copy all the files from <output directory> into twine library folder.

Now restart twine and enjoy your dialogues.

Import

NOTE: this is not production ready and not meant to be used by anyone and not guaranteed to work

NOTE: that you can't modify the structure of the dialogues, aka you can't add new edges/nodes or delete new nodes/edges, you can only modify the existing nodes/edges text

You would need to execute some python scripts so you need at lesat python 3.4 installed

Convert twine files to intermediate "json human text" format:

<path to project>/Plugins/DlgSystem/Tools/DlgTwineToJsonHumanText.py <source_twine_dir> <destination_json_dir>

Import the "json human text" files into the project.

<path to engine bin>/UE4Editor.exe <path to uproject file> -Run=DlgHumanReadableText -Import -OutputInputDirectory=<directory of json files>
Clone this wiki locally