Is it possible/how to hook up all the things in code?

Announcements, support questions, and discussion for the Dialogue System.
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Is it possible/how to hook up all the things in code?

Post by tylerwsavatronix »

Hey there,

First let me say Dialogue System looks pretty amazing!

That said, I have a few questions to help us integrate it with our project;

1) None of our NPCs or our player exist pre scene start, they're made and instantiated into the scene in code. What components will we need to add to get them set up to work with Dialogue System?

2) We'll also need to instantiate the managers/whatever else is needed in code, what's the best way to figure out what needs to be created in terms of managers?

3) We have our own centralized input system. How would we go about integrating DS with that? Ideally our input system would recognize that the player is trying to talk to an NPC, and would send the command to Dialogue System (same for advancing through dialogue/choosing dialogue options). We shoot a spherecast our from the player, and have it set to recognize objects which are interactable (we don't use screen position/general proximity; the player has to be close and facing objects to interact with them).

4) We'll need to, at some point, load dialogue from json instead of putting it into the database at design time. Is the possible/what would we need to do to accomplish this?

I did browse through the documentation, but didn't see any answers to these questions in there.

Thanks much for any help you can give to point us in the right direction!
User avatar
Tony Li
Posts: 22108
Joined: Thu Jul 18, 2013 1:27 pm

Re: Is it possible/how to hook up all the things in code?

Post by Tony Li »

Hi,

Thanks for looking into the Dialogue System! Yes, it can do everything you asked.
tylerwsavatronix wrote:1) None of our NPCs or our player exist pre scene start, they're made and instantiated into the scene in code. What components will we need to add to get them set up to work with Dialogue System?
If you want to use any of the interaction components, such as Conversation Trigger, you can add them at runtime or, if you add them at design time, hook up the participant GameObjects at runtime. If you don't want to use these components, you can simply make calls like DialogueManager.StartConversation() in your own scripts to start a conversation.
tylerwsavatronix wrote:2) We'll also need to instantiate the managers/whatever else is needed in code, what's the best way to figure out what needs to be created in terms of managers?
The Dialogue System has one manager: a GameObject typically named "Dialogue Manager" that has a DialogueSystemController component. You can make this a prefab and instantiate it at runtime, or just keep it in your scene at design time. It doesn't depend on any other GameObjects, so it can hang around in the scene while you instantiate your other objects such as players and NPCs.
tylerwsavatronix wrote:3) We have our own centralized input system. How would we go about integrating DS with that? Ideally our input system would recognize that the player is trying to talk to an NPC, and would send the command to Dialogue System (same for advancing through dialogue/choosing dialogue options). We shoot a spherecast our from the player, and have it set to recognize objects which are interactable (we don't use screen position/general proximity; the player has to be close and facing objects to interact with them).
The Dialogue System has a modular design. The UI is decoupled from the core engine. You can plug in your own UI code and the Dialogue System will work happily with it. Other developers have replaced the traditional UIs with things like text-to-speech and voice recognition, interactive "cave" installations, etc. For other interaction, such as interacting with objects, you can just call API methods such as DialogueManager.StartConversation().
tylerwsavatronix wrote:4) We'll need to, at some point, load dialogue from json instead of putting it into the database at design time. Is the possible/what would we need to do to accomplish this?
At runtime, the Dialogue System has built-in support for two XML formats: Chat Mapper and articy:draft. These are your easiest options to load dialogue from a text-based format since it only takes one line of code. However, if you must use JSON format, you can manually create a dialogue database in code. The API is fully exposed to be able to do this.

Please feel free to try the evaluation version if you haven't already. The evaluation version contains all features and is fully compatible with the paid version. The only difference is that it has a watermark and no source code. And if you have any other questions, just let me know!
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Is it possible/how to hook up all the things in code?

Post by tylerwsavatronix »

Hey Tony,

Thanks for the quick reply. We actually bought DS a while ago, but are just now getting around to integrating it (that's my assigned user story ATM).

Couple of other quick questions;

This one is a bit more about how conversations and NPCs should be structured;

1) I noticed the conversation trigger component only supports 1 conversation at a time. This kind of implies that, but I wanted to get clarification since I'm not familiar with DS (or chatmapper, or any other dialogue system, heh); Is it a best practice to have one conversation tree per character? It makes sense given that conditions on nodes are in LUA and we probably wouldn't want to code up a secondary system to try and sort out which conversation an NPC should belong to at any point in time.

2) In our game, every NPC is unique (no shared dialogue). Given that, could we just make do using the OverrideActorName script and calling DialogueSystem.StartConversation() and (assuming #1 is the right way to do it) be good to go?

3) Is there any component we need to attach to the player in order to tell DS that this gameobject is the player, or just simply use the OverrideActorName component and set its name there to whatever we defined as the Player in the DB?

4) We were thinking JSON because we recently moved all our runtime loading to that format instead of XML, but given it's unsupported for DS at the moment, would the best way to handle it be to design in Unity, but export to chat mapper xml and then load that in at runtime (our goal is to allow modders to change/add dialogue)? Could you please point me towards the documentation for importing the xml at runtime?

5) Could you also please point me towards the documentation for creating a DB in code? Also what type would I use in the generic Resources.Load<>() to load a db at runtime?

Thanks very much again, these couple of posts with you are already saving me a ton of trial and error time. I greatly appreciate it!
User avatar
Tony Li
Posts: 22108
Joined: Thu Jul 18, 2013 1:27 pm

Re: Is it possible/how to hook up all the things in code?

Post by Tony Li »

tylerwsavatronix wrote:Hey Tony,

Thanks for the quick reply. We actually bought DS a while ago, but are just now getting around to integrating it (that's my assigned user story ATM).
Thanks for buying the Dialogue System! :-)
tylerwsavatronix wrote:1) I noticed the conversation trigger component only supports 1 conversation at a time. This kind of implies that, but I wanted to get clarification since I'm not familiar with DS (or chatmapper, or any other dialogue system, heh); Is it a best practice to have one conversation tree per character? It makes sense given that conditions on nodes are in LUA and we probably wouldn't want to code up a secondary system to try and sort out which conversation an NPC should belong to at any point in time.
The Dialogue System supports multiple simultaneous conversations. (Tick the Dialogue Manager's Allow Simultaneous Conversations checkbox/set the bool property.) And you can add more than one Conversation Trigger to a GameObject if you want, and control which one fires based on their Conditions.

But, to actually answer your question: Yes, it's easiest to have one conversation character, unless the character has a lot of dialogue. In this case, you might want to split each major topic into a separate conversation. You can link between conversations. You may also find it handy to use forward slashes ("/") in your conversation titles, such as "Fellowship/Gandalf/Birthday", "Fellowship/Gandalf/Moria", "Fellowship/Gandalf/Isengard", etc. The slashes will act as submenus in the dialogue editor and conversation trigger pop-up menus. But ultimately it's really up to how you want to organize it.
tylerwsavatronix wrote:2) In our game, every NPC is unique (no shared dialogue). Given that, could we just make do using the OverrideActorName script and calling DialogueSystem.StartConversation() and (assuming #1 is the right way to do it) be good to go?
Sure, or just pass the correct NPC GameObject to DialogueManager.StartConversation(), such as:

Code: Select all

DialogueManager.StartConversation("My Conversation", player.transform, someNPC.transform);
tylerwsavatronix wrote:3) Is there any component we need to attach to the player in order to tell DS that this gameobject is the player, or just simply use the OverrideActorName component and set its name there to whatever we defined as the Player in the DB?
No special component. Just pass the player to DialogueManager.StartConversation() or use OverrideActorName. However, you may want to add some utility components such as Set Component Enabled On Dialogue Event to disable player control during conversations or Set Animator State On Dialogue Event to put the player in an idle animation at the start of the conversation. See How to Set Up the Player for more info.
tylerwsavatronix wrote:4) We were thinking JSON because we recently moved all our runtime loading to that format instead of XML, but given it's unsupported for DS at the moment, would the best way to handle it be to design in Unity, but export to chat mapper xml and then load that in at runtime (our goal is to allow modders to change/add dialogue)? Could you please point me towards the documentation for importing the xml at runtime?
The static method ChatMapperProject.Load(filename) loads a Chat Mapper Project. You can use its ToDialogueDatabase() method to convert it to a dialogue database:

Code: Select all

var myDialogueDatabase = ChatMapperProject.Load(filename).ToDialogueDatabase();
Then you can add it to the runtime environment using DialogueManager.AddDatabase():

Code: Select all

DialogueManager.AddDatabase(myDialogueDatabase);
However, in practice there's usually one extra concern. Dialogue database content (actors, conversations, etc.) are all referenced by ID numbers. When you create a dialogue database, the first conversation is assigned ID 1, the second conversation ID 2, etc.

If you create a second dialogue database, its first conversation will also have ID 1, etc.

If you add both databases to the runtime environment, ID 1 will be ambiguous because there will be two conversation with that ID number.

When you're creating your databases at design time in the editor, you can use the Unique ID Tool to adjust the ID numbers so they're unique across multiple databases.

If you're creating databases at runtime, however, the solution is to use the DatabaseMerger class to merge the contents of one database into another, which guarantees that everything's assigned a unique ID.
tylerwsavatronix wrote:5) Could you also please point me towards the documentation for creating a DB in code? Also what type would I use in the generic Resources.Load<>() to load a db at runtime?
The type is DialogueDatabase. It's a ScriptableObject asset.

Here's some example code to create a database. It uses a utility class named Template.

Code: Select all

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

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

// Create actors:
int playerID = 1;
int npcID = 2;
database.actors.Add(template.CreateActor(playerID, "Player", true));
database.actors.Add(template.CreateActor(npcID, "NPC", false));

// Create a conversation: [ID 0=START] --> [ID 1=Hello]
int conversationID = 1;
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");
node.ActorID = playerID;
node.ConversantID = npcID;
startNode.Sequence = "None()"; // START node usually shouldn't play a sequence.
conversation.dialogueEntries.Add(startNode);

// Actual dialogue node ("Hello") with ID 1:
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, node.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);
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Is it possible/how to hook up all the things in code?

Post by tylerwsavatronix »

Thanks! This is a lot of great info and it's clearing the path forward in my head!

Since right now we're just working on a playable demo (with the intent of both getting feedback, and shipping it aorund to secure funding) it sounds like, short term 1 conversation per NPC will be fine, but long term things'll get more complex/involved (we're looking at potentially having over 60 hours of dialogue total).

It also looks like we can simply add a property to our NPC info to load in "Conversation name" and just simply run that conversation and not worry about components at all (which means less code, yay).

It looks like instead of Set Animator State On Dialogue Event we would probably want to instead use Send Message On Dialogue Event or (probably actually) Dialogue System Events to enable us to shoot out a c# event via a wrapper method on Characters. This way we can notify the different systems of the players state (i.e. tell our InputMaster class that the character is in dialogue, and so movement commands shouldn't be processed, or notify the BehaviorDesigner tree for an NPC that it's now in a conversation).

We want to avoid having multiple places that can send input to mecanim/systems (easier to debug) and generally maintain as little coupling as possible. The fun part will be in figuring out how to integrate with Behavior Designer and finding the best way given our architecture to trigger NPC animations (but that'll be a different user story, so I'll put that off for now, heh).

The last question I have (for now :) ) is this:

What's the best way to expose c# variables to the lua environment? For example, having a condition where the dialogue isn't spoken unless the player has a skill level in blacksmithing of 15.

Would we need to create a Lua variable reflecting that, and then sync where we keep that in a script to the lua environment (e.g. raise a c# event whenever a skill level is raised, and have an independent class handle that event by setting the corresponding Lua variable to match)? Or is there a better way to expose variables that we're tracking on our own scripts?

Thanks again!
User avatar
Tony Li
Posts: 22108
Joined: Thu Jul 18, 2013 1:27 pm

Re: Is it possible/how to hook up all the things in code?

Post by Tony Li »

Hi Tyler,
tylerwsavatronix wrote:It looks like instead of Set Animator State On Dialogue Event we would probably want to instead use Send Message On Dialogue Event or (probably actually) Dialogue System Events to enable us to shoot out a c# event via a wrapper method on Characters.
You can also add a script to your characters that contains OnConversationStart and/or OnConversationEnd methods. (See script messages.)
tylerwsavatronix wrote:The fun part will be in figuring out how to integrate with Behavior Designer and finding the best way given our architecture to trigger NPC animations (but that'll be a different user story, so I'll put that off for now, heh).
The Dialogue System has pretty good Behavior Designer integration, btw. A lot of developers use them together.
tylerwsavatronix wrote:What's the best way to expose c# variables to the lua environment?
Depending on your authors' preferences, here are two suggestions. The second one is my preference as a programmer, but the first one works well if your authors are working in Chat Mapper or articy and want to be able to playtest their conversations before bringing them into Unity.

1. Define parallel variables in Lua (i.e., in your dialogue database). In OnConversationStart, copy the values of your C# variables into Lua using the DialogueLua.SetVariable() method. In OnConversationEnd, copy them back to C# using DialogueLua.GetVariable(). Then your authors can use the point-and-click Lua wizards to generate Conditions such as:

Code: Select all

Variable["Blacksmithing"] >= 15
One of the drawbacks of this method is that the copy-back to C# only occurs at the end of the conversation.

2. Alternatively (again my preference), register your own C# methods with Lua. As a programmer, this is one of my favorite parts of the Dialogue System. Say you have a C# method GetSkillLevel("skillName"). If you register it with Lua, you can set the Conditions field to:

Code: Select all

GetSkillLevel("Blacksmithing") >= 15
This next bit is only tangentially related, but I'm throwing it in because a developer showed me this trick and I thought it was cool: You can add custom fields to any dialogue database content. One developer added fields named "OnActivate" and "OnSuccess" to their quest template. They put Lua code in these fields. The Lua code calls C# methods to do things like grant experience points and gold. When the player successfully completes a quest, they look up the "OnSuccess" field and run it through Lua.Run(). This allows the author to set up rewards and game states without having to bother the programmers.
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Is it possible/how to hook up all the things in code?

Post by tylerwsavatronix »

Thanks!

OnConversationStart/End is definitely useful right now, I still need to fully delve into the various events DS shoots out (I'll be scoping that out more in depth today).

I successfully worked DS into our existing interaction system and now it's just going to be refining/interacting with the other systems when a conversation happens.


As for the lua/c# variables; We are a programmer heavy team, so route 2 seems good, however from a c# design perspective it doesn't make a lot of sense to not use properties and instead use methods...

Out of curiosity, since properties are under-the-hood methods are they able to be registered with Dialogue System? I'm kind of thinking, from a design/composure point of view, option #1 may actually be preferable over 2 if going with 2 means we'll also need to add a bunch of methods specifically for DS to access properties that are already public and accessible to the rest of the codebase...

Which means we would want an additional component that has a reference to the character and bridges the gap...but at that point it might make more sense just to do #1 so we have fewer ifs/cases floating about... I'll have to stew on this a while.
User avatar
Tony Li
Posts: 22108
Joined: Thu Jul 18, 2013 1:27 pm

Re: Is it possible/how to hook up all the things in code?

Post by Tony Li »

I haven't looked into registering C# properties with Lua. I'm not sure the default Lua implementation, LuaInterpreter, can support this, but you can probably do it if you switch to NLua. I haven't confirmed this yet, though.

Either way (option 1 or option 2) will take at least a little bit of glue code.
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Is it possible/how to hook up all the things in code?

Post by tylerwsavatronix »

Yeah, it's just about where to do the glue code (it shouldn't be in the Character class) and which one ends up being less overall work/code to maintain.

Option 2 might be less overall, because if I'm understanding right (and I might not be) we would need to add a parallel variable for every variable we want exposed, for every character we want to expose it to which would end up potentially being in the thousands (though maybe with templates we can simplify this).
User avatar
Tony Li
Posts: 22108
Joined: Thu Jul 18, 2013 1:27 pm

Re: Is it possible/how to hook up all the things in code?

Post by Tony Li »

The DialogueLua class also lets you set fields in the Actor[] table. (Tables are Lua's parlance for arrays). So if you went with option 1 you could, for example, set the Lua field Actor["Fred"].Gold using a C# call like this:

C# code:

Code: Select all

DialogueLua.SetActorField("Fred", "Gold", 42); 
Or, if you go with option 2, you can write something like the S-Inventory integration's Lua functions, in which you pass a GameObject name such as:

Lua code:

Code: Select all

SetCurrency("Fred", "Gold", 42); 
Post Reply