Problems with conversation actor/conversant being static and proposed solutions
Problems with conversation actor/conversant being static and proposed solutions
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!
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!
Re: Problems with conversation actor/conversant being static and proposed solutions
Hi,
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?
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 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)
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?
Re: Problems with conversation actor/conversant being static and proposed solutions
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.
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.
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.
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).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.
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.
Re: Problems with conversation actor/conversant being static and proposed solutions
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.
Re: Problems with conversation actor/conversant being static and proposed solutions
Hi,
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.
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?
Which cache are you talking about? Maybe we're talking about different things. There are two caches that I can think of: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.
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.
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).
Are you talking about modifying the database? Sorry, I still don't understand.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.
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?
Re: Problems with conversation actor/conversant being static and proposed solutions
Like I said, the actor and conversant are set incorrectly. Their names and portraits are wrong.Can you please explain what isn't working about that?
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.
Re: Problems with conversation actor/conversant being static and proposed solutions
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?
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?
Re: Problems with conversation actor/conversant being static and proposed solutions
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.
(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 (151.77 KiB) Viewed 615 times
-
- withCache.png (152.52 KiB) Viewed 615 times
Re: Problems with conversation actor/conversant being static and proposed solutions
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.
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.
Re: Problems with conversation actor/conversant being static and proposed solutions
Yeah they all have gameobjects with Dialogue Actor on it, and the conversation is triggered through Dialogue System Trigger
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!
These were not set, so it was due to caching the -1 id.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?
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 (54.13 KiB) Viewed 607 times