Multiple Databases and scripting

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
urrmurrmur
Posts: 47
Joined: Wed May 05, 2021 1:57 pm

Multiple Databases and scripting

Post by urrmurrmur »

Hi,

Something is unclear to me concerning the use of multiple databases and scripting. I am using a master database containing some variables that should be shared between scenes, and all other content is stored in scene-specific databases.

I've set up my scene in such a way that I have a Dialogue System Controller (DSC) an Extra Databases (ED) component. My original idea was to set the master database as the initial database of the DSC (it's a prefab used in each scene), and set the scene-specific database in the ED component.

However, if I do it this way, I cannot access any of my conversations from a c# script, by using DialogueManager.StartConversation. It seems only the conversations loaded in the database from the DSC component are accessible from the DialogueManager class through scripting.

So I changed things around, this time setting the scene-specific DB in the DSC component and the master DB in the ED component. Now I can start my conversations with DialogueManager.StartConversation, but I run into a new problem when trying to use DialogueLua.Get/SetVariable. These calls work and seem to set and retrieve the value for the variables, but when I use these variables in conditions in a conversation, it seems like their value is not stored. I suspect this has something to do with how the "Sync from DB" option works, which I am using to gain access to the master DB's variables in my scene-specific DBs.


So, my general question is: how does scripting work together with the use of multiple databases? And two specific ones:
  • Is it possible to select which database is used by DialogueManager.StartConversation?
  • When using DialogueLua.Set/GetVariable with variables that are synced from a different DB, do the ones in the source DB get used or does this use a copy of the variables in the currently active DB?
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Multiple Databases and scripting

Post by Tony Li »

Hi,

To prevent confusion, I'm going to refer to your master database as your "global database."

Assign your global database to the Dialogue Manager GameObject's Dialogue System Controller component > Initial Database field.

Assign other databases to Extra Databases components.

For example, say your global database contains the game's actors, quests and variables.

Then you have two other databases named London Database and Paris Database containing conversations for NPCs in your London scene and your Paris scene, respectively. Note that these databases must have different internal IDs than the global database. (See Working With Multiple Databases)

Also say you also have two scenes: London and Paris.

When the game starts, the Dialogue Manager will load the Initial Database (your global database) into an in-memory master database accessed via the DialogueManager.masterDatabase property in C#.

When an Extra Databases component adds another database, the Dialogue Manager adds that database's content into DialogueManager.masterDatabase.

For example, say your London scene has an empty GameObject with an Extra Databases component that adds the London Database while in the scene. When playing in the London scene, DialogueManager.masterDatabase will contain the actors, quests, and variables from the global database and the conversations from London Database.

When a Dialogue System Trigger starts a conversation, it retrieves that conversation from DialogueManager.masterDatabase.

Note that the Dialogue System Trigger inspector's Reference Database field is only used at design time. It's not used at runtime. It's only used to populate the conversation title dropdown menu.
urrmurrmur
Posts: 47
Joined: Wed May 05, 2021 1:57 pm

Re: Multiple Databases and scripting

Post by urrmurrmur »

Thanks for the reply. Your response is how I understood things to work.

However, my issue comes when starting a conversation from an unrelated C# script. I usually do this by calling DialogueManager.StartConversation( "conversation title" ), which works perfectly fine when only using a single DB. However, if I do this when I have my scene set up for multiple databases, as you describe in your reply, only conversations from the DSC component's initial database are found. If I try to use one from the Extra Databases component (the London and Paris databases in your example), the conversation is not found (I get a warning informing me of this).
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Multiple Databases and scripting

Post by Tony Li »

That suggests that the extra database isn't actually loaded. Check that the Extra Databases component is enabled and configured to add the extra database when you expect.

Here's an example scene:

DS_ExtraDatabaseExample_2023-09-13.unitypackage

It's DemoScene1, except an ExtraDatabases component adds an extra database containing a simple conversation. If you interact with the computer terminal in the center of the room, it will start this simple conversation. If you interact with Private Hart, it will start a conversation from the initial database.
urrmurrmur
Posts: 47
Joined: Wed May 05, 2021 1:57 pm

Re: Multiple Databases and scripting

Post by urrmurrmur »

Hm, you're right, that's definitely related. I was starting the conversation from my script's Start method, and that didn't work. When I move it to a method that's triggered by a UI button, the conversation does trigger.

I don't understand why though. I check my script execution order, and both the Wrappers.ExtraDatabases and ExtraDatabases scripts are triggered before default time. My own script runs at default time. So I'd expect the loading to have finished by then.

Clearly something hasn't finished yet at default time though, otherwise it wouldn't work when doing it with a UI button. Is this intended behaviour? If so, is there a recommended workaround?
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Multiple Databases and scripting

Post by Tony Li »

Hi,

The Extra Databases Start() method runs at the end of the first frame, to allow other dependencies to initialize themselves first.

You can set up your script to start at the beginning of the next frame:

Code: Select all

IEnumerator Start()
{
    yield return null;
    DialogueManager.StartConversation("Your Conversation Title");
}
urrmurrmur
Posts: 47
Joined: Wed May 05, 2021 1:57 pm

Re: Multiple Databases and scripting

Post by urrmurrmur »

That did the trick. I had to use

Code: Select all

yield return new WaitForEndOfFrame()
but that may be because I started a new coroutine from my start method. Thanks!

My second question is about the use of variables. My global DB contains a number of variables that should be shared between scenes, and nothing else. I have synced these variables into my scene-specific DB, which works fine: I can use them in my conversation trees, get and set them, and everything works as expected.

However, if I try to manipulate them from code, I'm not getting the results I expect. Code snippet below is a coroutine I'm starting from my MonoBehaviour's Start method. "CLUE/test" is a synced variable from my global DB, "hoganNoticed" is a local variable in my scene-specific DB.

Code: Select all

private IEnumerator StartConversationCR()
        {
            yield return new WaitForEndOfFrame();

            Debug.Log( DialogueManager.masterDatabase.GetVariable( "CLUE/test" ) );
            Debug.Log( DialogueManager.masterDatabase.GetVariable( "hoganNoticed" ) );
            Debug.Log( DialogueLua.GetVariable( "CLUE/test" ).AsBool );
            Debug.Log( DialogueLua.GetVariable( "hoganNoticed" ).AsBool );
            DialogueLua.SetVariable( "CLUE/test", true );
            DialogueLua.SetVariable( "hoganNoticed", true );
            Debug.Log( DialogueLua.GetVariable( "CLUE/test" ).asBool );
            Debug.Log( DialogueLua.GetVariable( "hoganNoticed" ).asBool );

            DialogueManager.StartConversation( "Conversation/Test" );
        }
I'm ignoring the first two Debug.Log calls for a second. The two next ones print false, and the final two print true. So the SetVariable calls do something. However, only the "hoganNoticed" variable has the correct value the actual DB. conditions in my conversation that depend on it correctly assume that its value is true. "CLUE/test" on the other hand is treated as if it's false in the conversation tree.

So then we come to the first two Debug.Log calls. I'm not sure if this accesses the exact same variables as DialogueLua version, but here the first call prints null, while the second prints "PixelCrushers.DialogueSystem.Variable". I understand the latter is an encasing class, but the former being null indicates something is wrong in my approach.

Am I accessing the variables in an incorrect way for a multi-database system? Is it even possible to set the variables in the global DB from a C# AND keep it synced with the local one at all times?
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Multiple Databases and scripting

Post by Tony Li »

Hi,

Use DialogueLua to access variable values at runtime. Think of the dialogue database as a read-only source of data at runtime.

Maybe it's a script execution order issue. Try "yield return null;" as in:

Code: Select all

IEnumerator Start()
{
    yield return null;
    DialogueLua.SetVariable("CLUE/test", true);
    Debug.Log(DialogueLua.GetVariable("CLUE/test").asBool);
}
This is a long shot, but you haven't explicitly set "DialogueLua.replaceSlashWithUnderscore = false" in any of your scripts, have you?
urrmurrmur
Posts: 47
Joined: Wed May 05, 2021 1:57 pm

Re: Multiple Databases and scripting

Post by urrmurrmur »

Oh god. No I hadn't, but your remark did lead me to notice that the actual name of the variable is "CLUE.test" instead of "CLUE/test". I must've gotten confused with the naming conventions of conversations, but it was still a pretty dumb mistake. Apologies.

I have another question, but it's about something else entirely, so I'll probably make a new thread later (unless I can figure it out myself).
Post Reply