DialogueSystemTrigger Interrupt

Announcements, support questions, and discussion for the Dialogue System.
rakkar
Posts: 51
Joined: Mon Jan 13, 2020 10:39 pm

DialogueSystemTrigger Interrupt

Post by rakkar »

1. I use DialogueSystemTrigger to start the first conversation. This conversation warns the player he is under attack.
2. I use DialogueSystemTrigger to start the second conversation. This conversation tells the player he died.

If #2 attempts to start before #1 finishes, #2 does not start. I never get the OnConversationEnd callback from the second conversation. The game relies on this to continue and the player is unable to proceed.

How would I fix this?
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: DialogueSystemTrigger Interrupt

Post by Tony Li »

Hi,

What if you allow simultaneous conversations? (Dialogue Manager GameObject > Other Settings > Allow Simultaneous Conversations) This way #2 can start even if #1 is still active.

Alternatively, you can make a subclass of DialogueSystemTrigger that overrides DoConversationAction(). If another conversation is already active, it can wait until the previous conversation is finished. Example:

Code: Select all

protected override void DoConversationAction(Transform actor)
{
    StartCoroutine(StartConversationCoroutine(actor));
}
IEnumerator StartConversationCoroutine(Transform actor)
{
    while (DialogueManager.isConversationActive)
    {
        yield return null;
    }
    base.DoConversationAction(actor);
}
That's just an example to show the idea. You can implement it differently if you want of course.

Then use this subclass wherever you need conversations to wait for a previous one to finish.
rakkar
Posts: 51
Joined: Mon Jan 13, 2020 10:39 pm

Re: DialogueSystemTrigger Interrupt

Post by rakkar »

Thanks for the answer.

Is it possible to make it so any time one conversation attempts to start, any conversations in progress are ended immediately (and still notify the game they ended)?
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: DialogueSystemTrigger Interrupt

Post by Tony Li »

Hi,

I can add that as a core feature. In the meantime, you can subclass DialogueSystemTrigger and override DoConversationAction():

Code: Select all

protected override void DoConversationAction(Transform actor)
{
    DialogueManager.StopConversation();
    base.DoConversationAction(actor);
}
Or, if you don't want to override, you can allow simultaneous conversations. Then add a script that hooks into DialogueManager.instance.conversationStarted. Kill all active conversations except the last one started:

Code: Select all

DialogueManager.instance.conversationStarted += CheckActiveConversations;
...
void CheckActiveConversations(Transform actor)
{
    foreach (var activeConversation in DialogueManager.instance.activeConversations)
    {
        if (activeConversation.conversationModel.firstState.subtitle.dialogueEntry.conversationID != DialogueManager.lastConversationID)
        {
            activeConversation.conversationController.Close();
        }
    }
}
rakkar
Posts: 51
Joined: Mon Jan 13, 2020 10:39 pm

Re: DialogueSystemTrigger Interrupt

Post by rakkar »

Thanks, I'll try overriding DialogueSystemTrigger.

When I used allow multiple conversations it crashed in AbstractDialogueUI.cs ShowResponses() on this line "else if (this.transform == null)"

MissingReferenceException: The object of type 'StandardDialogUI2' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
PixelCrushers.DialogueSystem.AbstractDialogueUI.ShowResponses (PixelCrushers.DialogueSystem.Subtitle subtitle, PixelCrushers.DialogueSystem.Response[] responses, System.Single timeout) (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/UI/Abstract/Dialogue/AbstractDialogueUI.cs:292)
PixelCrushers.DialogueSystem.StandardDialogueUI.ShowResponses (PixelCrushers.DialogueSystem.Subtitle subtitle, PixelCrushers.DialogueSystem.Response[] responses, System.Single timeout) (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/UI/Standard/Dialogue/StandardDialogueUI.cs:215)
StandardDialogUI2.ShowResponses (PixelCrushers.DialogueSystem.Subtitle subtitle, PixelCrushers.DialogueSystem.Response[] responses, System.Single timeout) (at Assets/Mod/Export/BaseMod/Scenes/UI/ConversationDialog/StandardDialogUI2.cs:103)
PixelCrushers.DialogueSystem.ConversationView.StartResponses (PixelCrushers.DialogueSystem.Subtitle subtitle, PixelCrushers.DialogueSystem.Response[] responses) (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/MVC/View/View/ConversationView.cs:425)
PixelCrushers.DialogueSystem.ConversationController.OnFinishedSubtitle (System.Object sender, System.EventArgs e) (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/MVC/Controller/ConversationController.cs:276)
PixelCrushers.DialogueSystem.ConversationView.FinishSubtitle () (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/MVC/View/View/ConversationView.cs:397)
PixelCrushers.DialogueSystem.ConversationView.OnFinishedSubtitle () (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/MVC/View/View/ConversationView.cs:404)
PixelCrushers.DialogueSystem.Sequencer.FinishSequence () (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/MVC/Sequencer/Sequencer.cs:508)
PixelCrushers.DialogueSystem.Sequencer.Update () (at Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/MVC/Sequencer/Sequencer.cs:500)
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: DialogueSystemTrigger Interrupt

Post by Tony Li »

I think the DialogueSystemTrigger override will do what you want.

This may no longer be important to you but, for the error, you have done something that destroyed the dialogue UI's GameObject out from under it. When you run simultaneous conversations, make sure each one uses its own dialogue UI.
rakkar
Posts: 51
Joined: Mon Jan 13, 2020 10:39 pm

Re: DialogueSystemTrigger Interrupt

Post by rakkar »

The DialogueSystemTrigger override you suggested is incorrect; it calls OnConversationEnd(Transform actor) immediately on itself.

> Void ModV1.Source.Dialogue.DeleteGameObjectOnConversationEnd:OnConversationEnd (Transform)+0x1 at E:\Work\EmpireOfEmber\Client\DLL\ModV1\Source\Dialogue\DeleteGameObjectOnConversationEnd.cs:14 C#
Void PixelCrushers.DialogueSystem.ConversationModel:InformParticipants (String, Boolean)+0x5c at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\MVC\Model\Logic\Model\ConversationModel.cs:[194:37-194:117] C#
Void PixelCrushers.DialogueSystem.ConversationController:Close ()+0xa1 at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\MVC\Controller\ConversationController.cs:[171:17-171:92] C#
Void PixelCrushers.DialogueSystem.DialogueSystemController:StopConversation ()+0x15 at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\Manager\DialogueSystemController.cs:[910:17-910:50] C#
Void PixelCrushers.DialogueSystem.DialogueManager:StopConversation ()+0x14 at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\Manager\DialogueManager.cs:[484:13-484:41] C#
Void PixelCrushers.DialogueSystem.DialogueSystemTrigger:DoConversationAction (Transform)+0x1 at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\Triggers\Triggers\DialogueSystemTrigger.cs:[846:13-846:48] C#
Void PixelCrushers.DialogueSystem.DialogueSystemTrigger:Fire (Transform)+0x59 at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\Triggers\Triggers\DialogueSystemTrigger.cs:[635:13-635:41] C#
Void PixelCrushers.DialogueSystem.DialogueSystemTrigger:TryStart (Transform, Transform)+0x33 at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\Triggers\Triggers\DialogueSystemTrigger.cs:[617:21-617:33] C#
Void PixelCrushers.DialogueSystem.DialogueSystemTrigger:TryStart (Transform)+0x4 at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\Triggers\Triggers\DialogueSystemTrigger.cs:[603:13-603:36] C#
Void PixelCrushers.DialogueSystem.DialogueSystemTrigger:OnUse ()+0x1c at E:\Work\EmpireOfEmber\Client\Assets\Plugins\Pixel Crushers\Dialogue System\Scripts\Triggers\Triggers\DialogueSystemTrigger.cs:[494:75-494:90] C#
GameObject DialogueSystem:StartOneShotDialogue (GameObject, EventHandler`1, PrefabCampaignQuest2)+0x11b at E:\Work\EmpireOfEmber\Client\Assets\Scripts\DialogueSystem.cs:[103:13-103:29] C#
Attachments
DSFUDelete.PNG
DSFUDelete.PNG (91.38 KiB) Viewed 697 times
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: DialogueSystemTrigger Interrupt

Post by Tony Li »

Hi,

Shouldn't it call OnConversationEnd() since it's ending the first conversation?

Here's the example scene that I tested with:

DS_DialogueSystemTriggerCanInterrupt_2020-11-21.unitypackage

And here's the script from it:

DialogueSystemTriggerCanInterrupt

Code: Select all

using UnityEngine;
using PixelCrushers.DialogueSystem;

public class DialogueSystemTriggerCanInterrupt : DialogueSystemTrigger
{
    protected override void DoConversationAction(Transform actor)
    {
        if (DialogueManager.isConversationActive)
        {
            Debug.Log("Stopping conversation: " + DialogueManager.lastConversationStarted);
            DialogueManager.StopConversation();
        }
        Debug.Log("Starting conversation: " + conversation);
        base.DoConversationAction(actor);
    }
}
I added a ConversationLogger script to the Dialogue Manager so it will log messages such as OnConversationStart and OnConversationEnd.

If you play the scene and click the Interrupt button instead of the conversation's Continue button, it will interrupt the conversation with a new conversation.

If you don't want the first conversation to send its OnConversationEnd message when you stop it, you can import the DS patch from the Dialogue System Extras page. It's in the "Updated for 2.2.13" foldout. It exposes a static property DialogueSystemController.isWarmingUp. If this property is true, the Dialogue System won't send OnConversationStart/End/Line messages. So you could change DoConversationAction to:

Code: Select all

    protected override void DoConversationAction(Transform actor)
    {
        if (DialogueManager.isConversationActive)
        {
            Debug.Log("Stopping conversation: " + DialogueManager.lastConversationStarted);
            DialogueSystemController.isWarmingUp = true; // Temporarily suppress OnConversationXXX messages.
            DialogueManager.StopConversation();
            DialogueSystemController.isWarmingUp = false;
        }
        Debug.Log("Starting conversation: " + conversation);
        base.DoConversationAction(actor);
    }
rakkar
Posts: 51
Joined: Mon Jan 13, 2020 10:39 pm

Re: DialogueSystemTrigger Interrupt

Post by rakkar »

"Shouldn't it call OnConversationEnd() since it's ending the first conversation?"

There is only one conversation. I am starting a conversation, and immediately at the same time I start it I get OnConversationEnd() on the same conversation I am starting. OnConversationEnd() should be called when the conversation ends, not when it starts.
rakkar
Posts: 51
Joined: Mon Jan 13, 2020 10:39 pm

Re: DialogueSystemTrigger Interrupt

Post by rakkar »

In my prior topic I said "immediately on itself."

What I mean by this, with the code you pasted

protected override void DoConversationAction(Transform actor)
{
DialogueManager.StopConversation();
base.DoConversationAction(actor);
}

Current:
<New scene>
1. Start the one and only conversation
2. OnConversationEnd() IMMEDIATELY
3. Conversation plays out

Expected
<New scene>
1. Start the one and only conversation
2. Conversation plays out
3. OnConversationEnd()

*Edit* I noticed in your sample you have an extra line "if (DialogueManager.isConversationActive)"
I'll see if that fixes the problem.
Post Reply