QuestCondition bug report

Announcements, support questions, and discussion for Quest Machine.
Post Reply
AArtlone
Posts: 37
Joined: Tue Mar 09, 2021 2:54 am

QuestCondition bug report

Post by AArtlone »

Hi again, I have created the previous post where I described my problem.

In this post, I want to report the bug.

Steps to reproduce the bug:
  • Using an empty Unity project with only QuestMachine imported
    Locate "Pesky Rabbits" quest
    Set the "rabbits" counter value to 1
    In Autostart, add a CounterQuestCondition
    Set "Required Counter Value" to 1
This bug occurs because the QuestCondition is true at the moment the Quest is initialized by the QuestGiver, thus it sets the condition to true. This causes a StackOverflowException because the code goes into an infinite loop.

Code blocks related to the issue:

Code: Select all

[b]Quest.cs[/b]
public void BecomeUnofferable()
{
	try
        {
        	if (GetState() != QuestState.Disabled) SetState(QuestState.Disabled);
                	SetQuestIndicatorState(questGiverID, QuestIndicatorState.None);
        }
        catch (Exception e) // Don't let exceptions in user-added events break our code.
        {
                if (Debug.isDebugBuild) Debug.LogException(e);
        }
}

Code: Select all

[b]Quest.cs[/b]
public void SetState(QuestState newState, bool informListeners = true)
{
	if (QuestMachine.debug) Debug.Log("Quest Machine: " + GetEditorName() + ".SetState(" + newState + ", informListeners=" + informListeners + ")", this);

	m_state = newState;

	SetStartChecking(newState == QuestState.WaitingToStart);
	SetCounterListeners(newState == QuestState.Active || (newState == QuestState.WaitingToStart && (hasAutostartConditions || hasOfferConditions)));
	....
}
User avatar
Tony Li
Posts: 21925
Joined: Thu Jul 18, 2013 1:27 pm

Re: QuestCondition bug report

Post by Tony Li »

Thanks for reporting this bug. I'll investigate and provide a patch here later today.
User avatar
Tony Li
Posts: 21925
Joined: Thu Jul 18, 2013 1:27 pm

Re: QuestCondition bug report

Post by Tony Li »

AArtlone
Posts: 37
Joined: Tue Mar 09, 2021 2:54 am

Re: QuestCondition bug report

Post by AArtlone »

Great! Thanks a lot.
AArtlone
Posts: 37
Joined: Tue Mar 09, 2021 2:54 am

Re: QuestCondition bug report

Post by AArtlone »

Hi Tony!

I think there are more issues in regards to the Autostart.

I will try to explain it below.

So let us consider the following scenario:
  • We have a Quest that has an Autostart QuestCondition
  • The Quest is added to the player's QuestJournal
  • This condition is true at the moment the quest is started up by the QuestJournal
  • The Quest consists of 3 nodes, Start, Condition, and Success
  • The Condition QuetNode has some TestQuestCondition
  • This TestQuestCondition prints a "Subscribe" debug log when the StartChecking() is called
  • This TestQuestCondition prints an "Unsubscribe" debug log when the StopChecking() is called
The problem that occurs is the following:
  • We play the game
  • The Quest checks for the Autostart condition
  • The condition is true, thus the Quest state changes to Active
  • The Console prints out both "Subscribe" and "Unsubscribe" logs
The reason why I think this happens is the following:
  • It all has to do with the SetState() function in the Quest.cs
  • When the game starts, this method is called with newState = WaitingToStart
  • It then calls SetStartChecking(true), since newState == WaitingToStart
  • Consequently, it goes through the Autostart conditions
  • We only have 1 Autostart condition which is true
  • As a result, SetState() is called again with newState = Active. This happens before the previous SetState() method has finished!!!
  • This then calls StartChecking() on the only QuestCondition of our only CondiutionQuestNode, thus printы "Subscribe" to the console
  • Then, when the second SetState() method finishes execution, it goes back to the first SetState() execution!!!
  • Which then does the following check: if (newState == Active) StopNodeListeners();
  • Since this is the first iteration of the SetState() method, newState equals to WaitingToStart, therefore StopNodeListeners() is called.
  • Which consequently gets to our only Condition and prints out "Unsubscribe"

Code: Select all

public void SetState(QuestState newState, bool informListeners = true)
        {
            if (QuestMachine.debug) Debug.Log("Quest Machine: " + GetEditorName() + ".SetState(" + newState + ", informListeners=" + informListeners + ")", this);


            Debug.Log($"NewState: {newState}, MyState: {m_state}");

            m_state = newState;

            SetStartChecking(newState == QuestState.WaitingToStart);
            SetCounterListeners(newState == QuestState.Active || (newState == QuestState.WaitingToStart && (hasAutostartConditions || hasOfferConditions)));
            if (newState != QuestState.Active) StopNodeListeners();
	...
        }
I hope this explanation provides enough information, please let me know if you need any follow-up information from me.

Looking forward to your response.
User avatar
Tony Li
Posts: 21925
Joined: Thu Jul 18, 2013 1:27 pm

Re: QuestCondition bug report

Post by Tony Li »

Thank you for the breakdown. As you described, the SetState() method wasn't considering that the state may change after calling SetStartChecking(). This patch addresses that:

QM_QuestStatePatch_2021-06-04.unitypackage
Post Reply