[HOWTO] How To: Create Dialogue Database At Runtime

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
User avatar
Tony Li
Posts: 20540
Joined: Thu Jul 18, 2013 1:27 pm

[HOWTO] How To: Create Dialogue Database At Runtime

Post by Tony Li »

This post contains information on manually creating and adding additional dialogue databases at runtime in a script.

Note that in addition to manually creating database contents, you can also import articy:draft XML and Chat Mapper XML at runtime. (See Import & Export.)

When creating a database, use the Template class. If the script runs in the editor, you can use TemplateTools.LoadFromEditorPrefs() to get a Template class that uses any template fields you've set up in the Dialogue Editor's Templates section. Otherwise use Template.FromDefault() like the example below. This example creates a new database and adds a conversation with a START node and one actual node:

Code: Select all

// Create database:
var database = ScriptableObject.CreateInstance<DialogueDatabase>();

// Set base ID that's unlikely to conflict with already-loaded databases:
database.baseID = 10000;

// Create a template, which provides helper methods for creating database content:
var template = Template.FromDefault();

// Create actors: (Note: You can skip this if already-loaded databases contain the actors you want to use.)
int playerID = template.GetNextActorID(database);
database.actors.Add(template.CreateActor(playerID, "Player", true));
int npcID = template.GetNextActorID(database);
database.actors.Add(template.CreateActor(npcID, "NPC", false));

// Create a conversation: [ID 0=START] --> [ID 1=Hello]
int conversationID = template.GetNextConversationID(database);
var conversationTitle = "My Conversation";
var conversation = template.CreateConversation(conversationID, conversationTitle);
conversation.ActorID = playerID;
conversation.ConversantID = npcID;
database.conversations.Add(conversation);

// START node: (Every conversation starts with a START node with ID 0)
var startNode = template.CreateDialogueEntry(0, conversation.id, "START");
startNode.ActorID = playerID;
startNode.ConversantID = npcID;
startNode.Sequence = "None()"; // START node usually shouldn't play a sequence.
conversation.dialogueEntries.Add(startNode);

// Actual dialogue node ("Hello") with ID 1: (could have used template.GetNextDialogueEntryID)
var helloNode = template.CreateDialogueEntry(1, conversation.id, string.Empty);
helloNode.ActorID = npcID; // NPC speaks this line.
helloNode.ConversantID = playerID;
helloNode.DialogueText = "Hello";
conversation.dialogueEntries.Add(helloNode);

// Link from START to Hello:
var link = new Link(conversation.id, startNode.id, conversation.id, helloNode.id);
startNode.outgoingLinks.Add(link);

// And what the heck - might as well add it to the runtime environment and play it:
DialogueManager.AddDatabase(database);
DialogueManager.StartConversation(conversationTitle);
Example scene: DS_RuntimeConversationExample_2020-07-31.unitypackage

If you want to add extra fields to something in the database, use Field.SetValue() like this:

Code: Select all

Field.SetValue(actor.fields, "Title", "Gunnery Sergeant");

Resolving ID Conflicts
Everything inside a database has an internal ID number: actors, items/quests, locations, variables, conversations, and dialogue entry nodes. They don't have to be sequential, but they do have to be unique among their type. That is, there should only be one actor with a specific ID, one conversation with a specific ID, etc. (But it's fine to have an actor with ID 42 and a conversation with ID 42 since they're different types.)

Internally, the Dialogue System looks up these resources by their IDs. If the initial database has a conversation with ID 42 and your newly-added database also has a conversation with ID 42, it won't know which one to use.

If you create multiple databases at design time, you can use the Unique ID Tool editor window to reassign IDs to resolve conflicts.

But if you're creating a database at runtime, you can't use this editor window. Instead, there are two ways to resolve the conflicts:

1. When you create your database in code, use ID numbers that are guaranteed not to be in the initial database. For example, start all of your IDs at 10000 by setting database.baseID=1000. I usually go with this solution since it's simple to use.

2. Or use the DatabaseMerger class. This is a static utility class that merges the contents of one database into another, resolving ID conflicts at the same time. Here's how you might use it:

Code: Select all

// Make a copy of the initial database:
var mergedDatabase = Instantiate(DialogueManager.instance.initialDatabase);
// Merge in the newly-created database:
DatabaseMerge.Merge(mergedDatabase, newlyCreatedDatabase, ConflictingIDRule.AssignUniqueIDs, false, true, true, true, true, true);
// Remove the initial database from the Dialogue System's runtime environment:
DialogueManager.RemoveDatabase(DialogueManager.instance.initialDatabase);
// And add the merged database:
DialogueManager.AddDatabase(mergedDatabase);
Post Reply