Toggling Waypoints w/ Quest Journal and Beyond

Announcements, support questions, and discussion for Quest Machine.
Post Reply
cptscrimshaw
Posts: 113
Joined: Sun Sep 20, 2020 8:21 pm

Toggling Waypoints w/ Quest Journal and Beyond

Post by cptscrimshaw »

I have the basics of a waypoint system set up so that when a quest is toggled in the player's Quest Journal, it turns various waypoints on and off. It works great, but I'm running into a little bit of an issue when it comes to loading the game/switching scenes (don't I always?).

The code is fairly simple, but I'd like to extend it to account for Quest Nodes which may have their own individual waypoints. It checks if you toggle on/off a quest and checks through a list of GameObjects I have set up and sets them active or not (I'm sure there is a better way to do this, as I don't like having to name things similarly for it to work, but it's a start).

Code: Select all

using System.Collections.Generic;
using UnityEngine;
using PixelCrushers;
using PixelCrushers.QuestMachine;

public class Waypoints : SingletonMonobehaviour<Waypoints>, IMessageHandler
{
    public List<GameObject> waypoints = new List<GameObject>();
    private string waypointString;
    private string active;

    void OnEnable()
    {
        MessageSystem.AddListener(this, QuestMachineMessages.QuestTrackToggleChangedMessage, "");
    }

    void IMessageHandler.OnMessage(MessageArgs args)
    {
        SetQuestWaypoints(args);
    }

    public void SetQuestWaypoints(MessageArgs args)
    {
        //PixelCrushers.QuestMachine.Quest quest = QuestMachine.GetQuestInstance(args.parameter);
        //Debug.Log(quest);

        waypointString = "Waypoint - " + args.parameter.ToString();
        active = args.firstValue.ToString();

        foreach (var waypoint in waypoints)
        {
            if (waypoint.name == waypointString && active == "True")
            {
                waypoint.SetActive(true);
                Debug.Log("Turning " + waypoint.name + "waypoint on, because it's " + active);
            }
            else if (waypoint.name == waypointString && active == "False")
            {
                waypoint.SetActive(false);
                Debug.Log("Turning " + waypoint.name + "waypoint off, because it's " + active);
            }
        }
    }

    void OnDisable()
    {
        MessageSystem.RemoveListener(this, QuestMachineMessages.QuestTrackToggleChangedMessage, "");
    }
}
Here are my questions/problems:
  • The line in the code that is commented out: PixelCrushers.QuestMachine.Quest quest = QuestMachine.GetQuestInstance(args.parameter); does work. And I'll be using that to grab quest nodes and states in order to turn on/off waypoint markers. However, when the game loads, even though I'm getting the quest correctly in args.parameter, the quest instance is returning null. If a message comes through after the game has loaded it works fine. Is the Quest Journal not fully loaded at this point?
  • I have two quests in the Quest Database at the moment. If I accept one quest and not another, when I load a new scene (or the game), it will actually send a message for both quests (since my code is looking for all quests) and the quest that has not been accepted at all will return "True" from QuestTrackToggleChangedMessage. This only happens on scene change and on game load, but not when toggling anything in the Quest Journal. I'm assuming something is just wrong with my code. I'm definitely utilizing the fact that something (I assumed the Quest Journal, but maybe not) is sending a message on load or scene change, but I'm not sure why it's returning "True" for a quest that I have never even accepted and isn't in my player Quest Journal.
  • When a current node in a quest becomes true, I have it manually deactivate the waypoint game object that's associated with it in the Actions in the Quest Machine editor. This works great, but I assume it doesn't run these actions when the game is loaded, right?
  • I'm running into another issue, and I wonder if it's related. One of my quest nodes has a condition that looks to see if other nodes are true, and when I load the game, I get some warnings that the Quest Machine can't find a quest with the ID of the quest. (see screenshot) https://ibb.co/k4V861V The quest conditions works perfectly fine whenever I complete them in game, and this warning only shows up on game load.
  • Is there a better way to be doing all of this that I'm not thinking of? :)
Thanks again!
User avatar
Tony Li
Posts: 21925
Joined: Thu Jul 18, 2013 1:27 pm

Re: Toggling Waypoints w/ Quest Journal and Beyond

Post by Tony Li »

cptscrimshaw wrote: Tue Oct 13, 2020 5:59 pmThe line in the code that is commented out: PixelCrushers.QuestMachine.Quest quest = QuestMachine.GetQuestInstance(args.parameter); does work. And I'll be using that to grab quest nodes and states in order to turn on/off waypoint markers. However, when the game loads, even though I'm getting the quest correctly in args.parameter, the quest instance is returning null. If a message comes through after the game has loaded it works fine. Is the Quest Journal not fully loaded at this point?
Correct. The Save System may take one or more frames to restore "Saver" components such as the Quest Journal. You can set the number of frames on the Save System component. (It's 'Frames To Wait Before Apply Data'.) These extra frames allow components to initialize themselves before receiving save data. You can usually set Frames To Wait Before Apply Data to 1, and often to zero if none of your scripts initialize themselves in OnEnable or Start in a manner that would undo the save data (e.g., they just use Awake).

Instead of using OnEnable (or in addition to it), hook into SaveSystem.saveDataApplied. Example:

Code: Select all

void Awake() {
    SaveSystem.saveDataApplied += OnSaveDataApplied;    
}
void OnDestroy() {
    SaveSystem.saveDataApplied -= OnSaveDataApplied;
}
void OnSaveDataApplied() {
    // Go through all quests in QuestJournal and set waypoints accordingly:
    foreach (var quest in QuestMachine.GetQuestJournal().questList) {
        if (quest.GetState() == QuestState.Active && quest.showInTrackHUD) {
            // (show waypoint)
        }
    }
}
cptscrimshaw wrote: Tue Oct 13, 2020 5:59 pmI have two quests in the Quest Database at the moment. If I accept one quest and not another, when I load a new scene (or the game), it will actually send a message for both quests (since my code is looking for all quests) and the quest that has not been accepted at all will return "True" from QuestTrackToggleChangedMessage. This only happens on scene change and on game load, but not when toggling anything in the Quest Journal. I'm assuming something is just wrong with my code. I'm definitely utilizing the fact that something (I assumed the Quest Journal, but maybe not) is sending a message on load or scene change, but I'm not sure why it's returning "True" for a quest that I have never even accepted and isn't in my player Quest Journal.
When you load or change scenes, the Quest Giver NPCs will also save and load their quest states. (Usually all of their quests will simply be restored to the WaitingToStart state.) You're probably getting messages from these.
cptscrimshaw wrote: Tue Oct 13, 2020 5:59 pmWhen a current node in a quest becomes true, I have it manually deactivate the waypoint game object that's associated with it in the Actions in the Quest Machine editor. This works great, but I assume it doesn't run these actions when the game is loaded, right?
That's correct. When you're just reloading a quest, it doesn't run any actions. Otherwise, for example, whenever you loaded a quest that was successfully completed and gave rewards, it would give the rewards all over again.
cptscrimshaw wrote: Tue Oct 13, 2020 5:59 pmI'm running into another issue, and I wonder if it's related. One of my quest nodes has a condition that looks to see if other nodes are true, and when I load the game, I get some warnings that the Quest Machine can't find a quest with the ID of the quest. (see screenshot) https://ibb.co/k4V861V The quest conditions works perfectly fine whenever I complete them in game, and this warning only shows up on game load.
Make sure all of your quests are added to the quest database asset(s) that are assigned to the Quest Machine GameObject.
cptscrimshaw wrote: Tue Oct 13, 2020 5:59 pmIs there a better way to be doing all of this that I'm not thinking of? :)
One thing to consider for the waypoints is to simply save the state of the waypoints. That way you don't have to analyze the quests to decide which waypoints to activate. This is the way the Compass Navigator Pro and HUD Waypoint System integrations work.
Post Reply