Page 1 of 1

Save Quest data [SOLVED]

Posted: Sun Dec 22, 2019 1:17 pm
by mschoenhals
How do I save quest data from one scene to another? I already have a portal system that I use to go from one scene to another and it saves other data like inventory and enemies killed. I would just like to have the quest info added to my portal class. I added Save System to my Quest Machine GameObject and it does persist from one scene to another but the saved quest data is not included.

Here's my portal code:

Code: Select all

using System;
using System.Collections;
using RPG.Saving;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
using RPG.Control;

namespace RPG.SceneManagement
{
    public class Portal : MonoBehaviour
    {
        enum DestinationIdentifier
        {
            A, B, C, D, E  // these are used to match up with the right portal (may have more than one portal per scene)
        }

        [SerializeField] int sceneToLoad = -1;
        [SerializeField] Transform spawnPoint;
        [SerializeField] DestinationIdentifier destination;
        [SerializeField] float fadeOutTime = 1f;
        [SerializeField] float fadeInTime = 2f;
        [SerializeField] float fadeWaitTime = 0.5f;
        [SerializeField] Character character = null;

        GameObject player;

        private void OnTriggerEnter(Collider other) {
            if (other.tag == "Player")
            {
                StartCoroutine(Transition());
            }
        }

        private IEnumerator Transition()
        {
            if (sceneToLoad < 0)
            {
                Debug.LogError("Scene to load not set.");
                yield break;
            }

            DontDestroyOnLoad(gameObject);

            Fader fader = FindObjectOfType<Fader>();
            SavingWrapper savingWrapper = FindObjectOfType<SavingWrapper>();
            player = GameObject.FindWithTag("Player");
            player.GetComponent<PlayerController>().enabled = false;  //disable player control

            yield return fader.FadeOut(fadeOutTime);

            character.OnSaveInventory();
            savingWrapper.Save();

            yield return SceneManager.LoadSceneAsync(sceneToLoad);
            player = GameObject.FindWithTag("Player");  // this is a new scene with a new player, so you need to find the player again.
            player.GetComponent<PlayerController>().enabled = false;
     
            savingWrapper.Load();
            
            Portal otherPortal = GetOtherPortal();
            UpdatePlayer(otherPortal);

            savingWrapper.Save();

            yield return new WaitForSeconds(fadeWaitTime);
            fader.FadeIn(fadeInTime);
            player.GetComponent<PlayerController>().enabled = true;

            Destroy(gameObject);
        }

        private void UpdatePlayer(Portal otherPortal)
        {
            GameObject player = GameObject.FindWithTag("Player");
            player.GetComponent<NavMeshAgent>().enabled = false;  // disable the navMeshAgent while we are placing the player
            player.transform.position = otherPortal.spawnPoint.position;
            player.transform.rotation = otherPortal.spawnPoint.rotation;
            player.GetComponent<NavMeshAgent>().enabled = true;  // renable navMeshAgent after placing player
        }

        private Portal GetOtherPortal()
        {
            foreach (Portal portal in FindObjectsOfType<Portal>())
            {
                if (portal == this) continue;
                if (portal.destination != destination) continue;

                return portal;
            }

            return null;
        }
    }
}

Re: Save Quest data

Posted: Sun Dec 22, 2019 3:47 pm
by Tony Li
Hi,

If you're already using another scene-changing system and don't want to use Quest Machine's SaveSystem.LoadScene(), then use these steps:

1. Set up the Save System (SaveSystem, a data serializer component, saver components) and tick "Include In Saved Games" on any QuestGivers that you want to save. Untick the SaveSystem's Save Current Scene checkbox.

2. Before changing scenes with your own system, call:

Code: Select all

PixelCrushers.SaveSystem.BeforeSceneChange();
PixelCrushers.SaveSystem.RecordSavedGameData();
BeforeSceneChange tells any components that listen for their GameObjects to be destroyed or deactivated that they are going to be destroyed because of a scene change; this allows them to ignore the destruction instead of, for example, increment a kill counter. RecordSavedGameData tells all saver components to record their data in the SaveSystem's memory.

3. After changing scenes with your own system, call:

Code: Select all

PixelCrushers.SaveSystem.ApplySavedGameData();
ApplySavedGameData tells all savers in the new scene to retrieve their data from the SaveSystem's memory.

Re: Save Quest data

Posted: Sun Dec 22, 2019 4:38 pm
by mschoenhals
So I gave this a try and didn't get it working. How does the journal get saved? I've got Save System as a component of the Quest Machine. I unchecked Save Current Scene on Save System. When I go into a different scene and then back to the original, I get the following error:
Quest Machine: Player Can't find quest seekOldman. Is it registered with Quest Machine?
SeekOldman is a quest in the database. The journal is also empty (but should show that seekOldman has been completed).

I made sure that the same database is being used on both scenes. The quest giver has both "Include In Saved Game Data" checked and "Save Across Scene Changes."

The player has the Quest Journal in both scenes and the Save Key is the same: Player_50056

Any ideas?

Re: Save Quest data

Posted: Sun Dec 22, 2019 5:40 pm
by Tony Li
Hi,

To keep the player's info, make sure the QuestJournal component's Save Settings > Include In Save Data and Save Across Scene Changes are ticked, as well as Remember Completed Quests.

Also make sure you don't destroy the Quest Machine GameObject, which has the SaveSystem component. The SaveSystem component sets the GameObject to DontDestroyOnLoad, so it should survive scene changes unless you explicitly destroy it.

Here's an example exported from Unity 2019.2:

QM_SceneChangeExample_2019-12-22.unitypackage

Add ExampleScene1 and ExampleScene2 to your build settings. Then play ExampleScene1. Pick up some quests. Verify that the player's quest journal looks correct. Then click the Goto Scene 2 button. This will load ExampleScene2. Verify that the player's quest journal still shows the player's quests.

If that doesn't help, please feel free to send a reproduction project to tony (at) pixelcrushers.com.

Re: Save Quest data

Posted: Sun Dec 22, 2019 7:26 pm
by mschoenhals
Ok,
It turns out that my test Quest was not added to the Quest Machine Database; hence the error. I can now go from one scene to another and the journal stays update.
Thanks for the help. :)

How can the save quest data be saved on quit and load?

Re: Save Quest data

Posted: Sun Dec 22, 2019 7:42 pm
by Tony Li
mschoenhals wrote: Sun Dec 22, 2019 7:26 pmHow can the save quest data be saved on quit and load?
If you quit using a menu item, you can configure that menu item to call SaveSystem.SaveToSlot(#) where # is a slot number. Slot numbers are arbitrary. They're just used to identify saved games. If you're using a UI button, you can add a SaveSystemMethods script to the button and configure the OnClick() event to call SaveSystemMethods.SaveToSlot.

If you're making a mobile game and want to automatically save on quit, add an AutoSaveLoad component to the SaveSystem. It has various options that you can configure to tell it when to save and load.

Re: Save Quest data

Posted: Sun Dec 22, 2019 8:24 pm
by mschoenhals
Sounds good, thank you!