Migrating Level Manager to Dialogue System

Announcements, support questions, and discussion for the Dialogue System.
Mackerel_Sky
Posts: 111
Joined: Mon Apr 08, 2019 8:01 am

Re: Migrating Level Manager to Dialogue System

Post by Mackerel_Sky »

Hey Tony,

Thanks for the help so far. I got the player spawn point to work as intended. There's still an issue with the saver, however in that I don't think the save data is being pulled through correctly in ApplyData() when the scene is reloaded. I have made debug messages in the method like this:

Code: Select all

        public override void ApplyData(string data)
        {
            Debug.Log("looking for save data" + data);
            if (string.IsNullOrEmpty(data))
            {
                Debug.Log("no save detected, implementing original data");
            }
            else
            {
                List<ItemsContained> savedItems = SaveSystem.Deserialize<List<ItemsContained>>(data);
                Debug.Log("saved chest data detected, loading saved data");
                lootChest.itemList = savedItems;
            }
        }
However the debug output is

Code: Select all

looking for save data{}
Since we fixed the spawn point issue scene changes are handled entirely by Dialogue System now. Do you know why ApplyData doesn't correctly grab the key from the game object? I can see that the Saver.key property is correct from another debug message.
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: Migrating Level Manager to Dialogue System

Post by Tony Li »

Hmm, since the "if" and "else" blocks both have Debug.Log statements, a second line after "looking for save data()" should also be logged. Is Unity perhaps logging an error instead, but your Console window has turned on error logging?

Also, make sure the saver's Key value is unique across all scenes or is intentionally the same. Examples:
  • The player's inventory should remain the same when changing scenes, so the inventory savers in all scenes should use the same key.
  • However a chest in scene1 is different from a chest in scene2, so the chests' savers should use different keys.
Mackerel_Sky
Posts: 111
Joined: Mon Apr 08, 2019 8:01 am

Re: Migrating Level Manager to Dialogue System

Post by Mackerel_Sky »

Sorry, the console was actually logging "saved chest data detected, loading saved data" after the item, and the key is being read as "{}". I took another quick look through the code earlier today and still couldn't find why it was coming up like this.
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: Migrating Level Manager to Dialogue System

Post by Tony Li »

Is "{}" the key or data? That looks like it might be the data. I just noticed that you're serializing a List<>. By default, the save system uses Unity's serialization, which cannot directly serialize Lists or arrays. This would explain why the data is empty ({}).

The solution is to put your List inside a serializable class, such as:

Code: Select all

[Serializable]
public class ItemData
{
    public List<ItemsContained> itemsContained;
}
Then save it like this:

Code: Select all

ItemData itemData = new ItemData();
itemData.itemsContained = lootChest.savedItems;
return SaveSystem.Serialize(itemData);
And apply it like this:

Code: Select all

ItemData itemData = SaveSystem.Deserialize<ItemData>(data);
lootChest.itemList = itemData.itemsContained;
Mackerel_Sky
Posts: 111
Joined: Mon Apr 08, 2019 8:01 am

Re: Migrating Level Manager to Dialogue System

Post by Mackerel_Sky »

Hey Tony,

I must have misunderstood and thought the data string that ApplyData() implemented was the key used to access the actual data.

After putting the item list into a serializable class, it looks like the data is being read properly. Thanks for your patience and help on this.

I have one more question that came up while I was transitioning to the Dialogue System. I mentioned earlier that I have some items like NPCs, chests, etc. that need to get references to the player and UI upon starting. As these game objects are destroyed upon scene transition I need to reassign the references each time a scene is loaded. My legacy code involved the usage of a persistent game manager object, which communicated references to a level manager object in each scene. The level managers stored lists of every game object in their scenes requiring references to the player or UI and assigned them on scene load.

I felt like this might be a bit cumbersome, especially as I might end up making scenes with large amounts of these items and keeping track of everything might be a bit awkward. An alternative might have each game object use GameObject.Find, etc. on start, but I worry about performance and best practice. I was wondering if Dialogue System has any functionality or support for getting around this issue or if I'm better off looking into other areas- I still consider myself a novice at best so I am not sure if DS is even the right thing to be looking into for this.

Thanks again for your help on this!
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: Migrating Level Manager to Dialogue System

Post by Tony Li »

Hi,

I think that's outside the scope of what the Dialogue System does.

A common way to do this is to set a static variable. For example:

Code: Select all

public class Player : MonoBehaviour
{
    public static Player Instance {get; private set;}
    private void Awake()
    {
        Instance = this;
    }
}
Then your NPCs and chests and access the current player as Player.Instance.
Mackerel_Sky
Posts: 111
Joined: Mon Apr 08, 2019 8:01 am

Re: Migrating Level Manager to Dialogue System

Post by Mackerel_Sky »

Hi Tony,

Sorry for bringing this thread back from the dead but it might be easier to just add onto this topic as my issue is a natural extension of this.

I have started on piecing together a pretty standard save/load system that will allow the player to save at a save location, quit to menu or close the game, then come back to the save point with all the game information intact.

Regarding the transfer of player and UI issue earlier in this thread, I somehow smashed together a disgusting 2 second fix based on scriptable objects that I promptly forgot about and now need to subsequently fix by using static references as you suggested. The reason the scriptable objects code failed was because I had envisioned the game to load a initialisation scene where the SO would grab all the references it needed before loading the actual saved level to return to. This worked fine for transferring references in between levels (though Unity would freak out at me in the inspector) but I now realise to continue extending this to save/load would result in me having to store all information to be saved and loaded into the scriptable object which is probably somewhat more difficult than just refactoring it and finishing the migration like I had originally intended.

I have tried calling SaveSystem.LoadFromSlot in the load game button (after saving) but the player and other critical objects don't spawn back in like they are supposed to - the scene just loads without them. I took a look at the Save System video but I think the player is already in the demo scene and its position is just being set to the correct spawn point - maybe I am not interpreting it properly.

Would you know the correct process to allow the player to exit to title/the game entirely and reenter at their last position and scene correctly? Off the top of my head I would maybe spawn the player and UI in at the title screen and hide them from view or something. I think I would also need to write custom savers to record the player's inventories (a couple of lists of scriptable objects) and their health.

Thanks for your time and effort teaching me - I haven't fully tested what exactly is going wrong but I have a feeling I might be going down the wrong track here. ;_;
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: Migrating Level Manager to Dialogue System

Post by Tony Li »

Hi,

Since your player is spawned in after the scene loads, I can suggest two options. (An identical approach would probably apply to anything else that gets spawned in at runtime.)

1. This first suggestion assumes that some script of yours spawns the player prefab into the scene. Add a Position Saver component to your player prefab. If you know the player is spawned and initialized in the first 2 frames of the scene's lifetime, then set the Save System's Frames To Wait Before Apply Data to 2. The Save System will wait 2 frames, allowing time for the player to be spawned, before telling the player's Position Saver and all other Saver components to restore their states.

2. Alternatively, you can write a custom Saver component that records which player prefab was spawned in, and where. Put this Saver on a GameObject that's guaranteed to be active in the scene when it's loaded. In its ApplyData method, spawn the player prefab and move it into position.

In both cases, you can tick the Save System's Save Current Scene checkbox to record the scene that the player is in when they save. When loading a saved game, the Save System will load this scene. Then it will wait for the specified number of frames and then tell Savers to restore their states.


For miscellaneous things that get spawned into the scene, such as items that the player drops, use a Spawned Object Manager. (See Plugins / Pixel Crushers / Common / Documentation / Save_System_Manual.pdf for details.)
Mackerel_Sky
Posts: 111
Joined: Mon Apr 08, 2019 8:01 am

Re: Migrating Level Manager to Dialogue System

Post by Mackerel_Sky »

Hey Tony,

Thanks for the reply. I actually don't want to spawn the player immediately into the scene- my original plan was to go to a initialisation scene where I spawn the player and UI, set them up, then load them into whatever scene needed to be loaded.

Out of curiosity I tried again after migrating the rest of my code out of the scriptableobject placeholder and it seems like SaveToSlot and LoadFromSlot are working almost as intended right out of the box with the static instances, at least for quitting to title and loading via slot. I don't have enough time tonight to dive into why I can't load between play sessions (I haven't built/exported the project yet) but I think it's probably worth the effort continuing to work from here? Is there anything that SaveToSlot and LoadFromSlot don't save or I should be looking out for when using these two methods?
User avatar
Tony Li
Posts: 22051
Joined: Thu Jul 18, 2013 1:27 pm

Re: Migrating Level Manager to Dialogue System

Post by Tony Li »

Hi,

SaveToSlot only saves what its Saver components record. If you've added a Dialogue System Saver to the Dialogue Manager, it saves the Dialogue System's Lua state (variables, quest states, etc.). If you've added a Position Saver to an NPC, it saves the NPC's position, etc. If a Saver's Save Across Scene Changes is ticked, then its data will stay in the saved game even when changing to other scenes. This way, when you return to the Saver's scene, the Saver will be able to restore its state.

Here's the SaveToSlot Flowchart:

Image
Post Reply