Problems with conversation actor/conversant being static and proposed solutions

Announcements, support questions, and discussion for the Dialogue System.
niskander
Posts: 9
Joined: Thu Jan 07, 2021 2:58 pm

Problems with conversation actor/conversant being static and proposed solutions

Post by niskander »

Hi,
I've been using Dialogue for a few days now and it's mostly going well, but I ran into issues with conversation actor/conversant. As the docs state, the system is pretty flexible when getting the actor and conversant (can use dialogue actor, set it explicitly, or the game object is used).

However, that flexibility does not extend to the actor and conversant in the conversation (i.e. DialogueManager.CurrentConversant will be correct, but DialogueManager.ConversationModel.ConversantInfo will just be the static data from the conversation, and the data in the conversation will not match that of CurrentConversant)

To solve this, I had to update ConversationModel.GetCharacterInfo() so that it doesn't default to the static conversation actor/conversant ids.
I also updated ConversationModel.SetParticipants() so that it updates the actor and conversant on all the entries according to the ones returned by GetCharacterInfo(). (I'm matching IsPlayer with the actor and not IsPlayer with the conversant).

Ideally I don't like making local changes to plugins cause it makes it difficult to update said plugin. If there's a future version of Dialogue, my proposed solution would be to add the option to choose "Conversation actor" and "Conversation conversant" to the Actor/Conversant fields in the entries.

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

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by Tony Li »

Hi,
niskander wrote: Sun Jan 10, 2021 4:17 pmHowever, that flexibility does not extend to the actor and conversant in the conversation (i.e. DialogueManager.CurrentConversant will be correct, but DialogueManager.ConversationModel.ConversantInfo will just be the static data from the conversation, and the data in the conversation will not match that of CurrentConversant)
If ConversationModel.GetCharacterInfo(id, transform) is given a GameObject that has a Dialogue Actor component, it will use the ID of the actor associated with the Dialogue Actor component. Otherwise it will use the ID of the actor specified in the conversation.
niskander wrote: Sun Jan 10, 2021 4:17 pmI also updated ConversationModel.SetParticipants() so that it updates the actor and conversant on all the entries according to the ones returned by GetCharacterInfo(). (I'm matching IsPlayer with the actor and not IsPlayer with the conversant).
Are you talking about changing the dialogue entries' ActorID and ConversantID fields in the dialogue database at runtime?

Let's see if we can find a good way to do what you need to do without having to modify the actual source code. I'm happy to make additions to the source code as long it won't break existing API assumptions. But there may be a way to do it without that.

What was the original problem that you were trying to solve?
niskander
Posts: 9
Joined: Thu Jan 07, 2021 2:58 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by niskander »

Well conceptually the goal is to have generic conversations that several characters can use, so the actor and conversant of entries do need to change at runtime, otherwise the name/portrait/etc are wrong.
Also, there are several playable characters that the player can switch between, which requires even more flexibility.

I have it working right now with a few modifications.
If ConversationModel.GetCharacterInfo(id, transform) is given a GameObject that has a Dialogue Actor component, it will use the ID of the actor associated with the Dialogue Actor component. Otherwise it will use the ID of the actor specified in the conversation.
Unless the condition at the start of that function prevents this from happening (the one that checks caching based on the conversation's static actor/conversant ids).

There are situations where this can end up causing undesired behaviour, for instance:
- A conversation is set up in the DB between characters A and B. A and B exist in the scene and have had conversations before. Character C triggers a conversation with D, the function will still return A and B since they're cached. So you need to know not to use any of the characters you use in conversations in the scene.
- Is there a mechanic for clearing the cache when the actor is dirtied? Otherwise I think caching is not the right approach here.

Related: I think the CharacterInfo line has a bug, cause it uses id instead of actorId for the character type.

But aside from that function, a lot of places use the version that doesn't take a transform (for the entries mostly). Setting the entry conversant and actor dynamically is necessary for my usecase. Fortunately it wasn't that hard to accomplish! In the final iteration on this I added a "SpokenByPlayer" field to the entry. One of the triggering actor/conversant will be a player, so I match that one with the entries that have the bool checked.
niskander
Posts: 9
Joined: Thu Jan 07, 2021 2:58 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by niskander »

Oh I forgot to mention that a -1 id can get cached there as well, meaning that you can't leave your actors/conversants on None if you want them assigned dynamically.
User avatar
Tony Li
Posts: 22049
Joined: Thu Jul 18, 2013 1:27 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by Tony Li »

Hi,
niskander wrote: Mon Jan 11, 2021 1:00 amWell conceptually the goal is to have generic conversations that several characters can use, so the actor and conversant of entries do need to change at runtime, otherwise the name/portrait/etc are wrong.
I don't understand. If a GameObject has a Dialogue Actor component, and that GameObject is assigned to the Dialogue System Trigger's Conversant Conversant, then all conversant subtitles will use the name and portrait image of the Dialogue Actor's actor, not the actor originally assigned to the conversation. Is there a situation in which that doesn't happen?
niskander wrote: Mon Jan 11, 2021 1:00 amThere are situations where this can end up causing undesired behaviour, for instance:
- A conversation is set up in the DB between characters A and B. A and B exist in the scene and have had conversations before. Character C triggers a conversation with D, the function will still return A and B since they're cached. So you need to know not to use any of the characters you use in conversations in the scene.
- Is there a mechanic for clearing the cache when the actor is dirtied? Otherwise I think caching is not the right approach here.
Which cache are you talking about? Maybe we're talking about different things. There are two caches that I can think of:

1. In an active run of a conversation, that conversation maintains a dictionary cache mapping ID values to CharacterInfo. This cache only exists for that active conversation, and it's gone afterward.

2. Globally, the CharacterInfo class maintains a static registry of Dialogue Actor components registered by actor name. When a Dialogue Actor appears in a scene, it registers itself with this registry. When the Dialogue Actor disappears (e.g., destroyed or scene unloaded), it unregisters itself. This registry is not specific to a conversation.
niskander wrote: Mon Jan 11, 2021 1:00 amRelated: I think the CharacterInfo line has a bug, cause it uses id instead of actorId for the character type.
It's correct. The cache (Dictionary<int, CharacterInfo> m_characterInfoCache) uses the original actor ID for the key because this is what the conversation's dialogue entries reference. But the CharacterInfo value's ID will be the actual current actor (e.g., assigned to Dialogue Actor and Dialogue System Trigger's Conversation Conversant).
niskander wrote: Mon Jan 11, 2021 1:00 amBut aside from that function, a lot of places use the version that doesn't take a transform (for the entries mostly). Setting the entry conversant and actor dynamically is necessary for my usecase. Fortunately it wasn't that hard to accomplish! In the final iteration on this I added a "SpokenByPlayer" field to the entry. One of the triggering actor/conversant will be a player, so I match that one with the entries that have the bool checked.
Are you talking about modifying the database? Sorry, I still don't understand.
niskander wrote: Mon Jan 11, 2021 1:28 am Oh I forgot to mention that a -1 id can get cached there as well, meaning that you can't leave your actors/conversants on None if you want them assigned dynamically.
The conversation model's Dictionary<int, CharacterInfo> m_characterInfoCache is created fresh whenever a conversation starts. Can you please explain what isn't working about that?
niskander
Posts: 9
Joined: Thu Jan 07, 2021 2:58 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by niskander »

Can you please explain what isn't working about that?
Like I said, the actor and conversant are set incorrectly. Their names and portraits are wrong.
Removing the caching fixes most of the issues. As mentioned, you may want to check if the id is -1 and not cache it in this case.

If you want I can revert my changes to determine exactly which of them fixed the issues but there was definitely a bug earlier. I think it's the -1 ids.
User avatar
Tony Li
Posts: 22049
Joined: Thu Jul 18, 2013 1:27 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by Tony Li »

What scenario causes the names and portraits to be wrong?

For example: When assigning GameObjects with Dialogue Actor components to a Dialogue System Trigger's Conversation Actor and Conversant Conversant? When going by GameObject name (no Dialogue Actors)? When neither Dialogue Actor nor named GameObject matches? Is this for the primary actors assigned to the conversation, or extra actors used in the conversation?
niskander
Posts: 9
Joined: Thu Jan 07, 2021 2:58 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by niskander »

I reverted my changes to the dialogue source-code to double-check. I attached example screenshots with and without caching. As you can see in the example with caching, both the conversant and the actor are called "Alice" even though "Apple" is speaking (and is the conversant in that conversation). Simply removing the caching from GetCharacterInfo() fixes it.

(This is if all the actors/conversants are set in the conversation. If they're left on none, the behaviour will be even more broken with the caching.)

So that's the first issue. The second issue may be specific to my use-case, but in my conversations I want to assign entries based on who the player is, not based on ids.
So if I have a conversation set up like A(NPC) speaks entry 1 -> B(Player) gets 3 choices to respond, and during runtime A becomes the player and B becomes the NPC, A should get the 3 choices. So this is why I have to add the "SpokenByPlayer" bool to my entries.
Current behaviour is that if I switch who the player is at runtime, the player will get to speak the first entry, and the NPC will speak the first of the 3 choices.
Attachments
withoutCache.png
withoutCache.png (151.77 KiB) Viewed 613 times
withCache.png
withCache.png (152.52 KiB) Viewed 613 times
User avatar
Tony Li
Posts: 22049
Joined: Thu Jul 18, 2013 1:27 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by Tony Li »

Hi,

Do Apple and Alice have GameObjects?

If so, do those GameObjects have Dialogue Actor components?

While viewing the conversation in the Dialogue Editor's Conversations panel, please select Menu > Conversation Properties. Which actor is assigned to the conversation's Actor dropdown? Which to the Conversant dropdown?

How are you starting the conversation?

If you're using a Dialogue System Trigger, what's assigned to the Conversation Actor and Conversation Conversant fields?

If you're calling DialogueManager.StartConversation() in a C# script, are you passing the transforms of the actor and conversant you want to use? For example: DialogueManager.StartConversation("My Conversation", alice, apple);

Sorry for all the questions. I want to make sure I have a complete picture first. Thanks for bearing with me.
niskander
Posts: 9
Joined: Thu Jan 07, 2021 2:58 pm

Re: Problems with conversation actor/conversant being static and proposed solutions

Post by niskander »

Yeah they all have gameobjects with Dialogue Actor on it, and the conversation is triggered through Dialogue System Trigger
While viewing the conversation in the Dialogue Editor's Conversations panel, please select Menu > Conversation Properties. Which actor is assigned to the conversation's Actor dropdown? Which to the Conversant dropdown?
These were not set, so it was due to caching the -1 id.

After making sure every single field was set, another issue appeared in the conversation where the characters flip roles. In this case, the transform of the conversant was wrong!
Original conversation: Actor: Alice, Conversant: Bob
At runtime: Bob triggers the conversation with Alice (according to the selector), but Bob is set as both the actor and conversant. (I'm not sure why, didn't dig into it.)

The good news is that this was solvable without changing the code. The solution is to preset all conversation actors and conversants to actors that you will not use in the game. Now it behaves correctly even if I flip the player!
Attachments
Screen Shot 2021-01-11 at 8.15.48 PM.png
Screen Shot 2021-01-11 at 8.15.48 PM.png (54.13 KiB) Viewed 605 times
Post Reply