Save system 'S' shortcut

Hi, I am not using your project and I am new to the save systems. How come save is ‘s’ button? ‘s’ button is for going down in my game, form me it would be cmd+s. Is there a possibility to make it work? I am using following scripts in my projects: ISaveable, SaveableEntity, SavingSystem, SerializableVector3 (actually this one I am not sure if I need). And so far everything in my project works except saving.

In what tutorial are you explaining save system? I really like your tutorials, you guys doing heroic job, but this is for the third time in this tutorial you just say: this already works from GameDevTV.Saving system. I think it would be good to mention: Please see this tutorial: ‘name of the tutorial’ for learning more.

‘S’ is for ‘(S)ave’ in the course, and ‘L’ for ‘(L)oad’. The course doesn’t use WASD to move, so it’s not a problem. You really just need to change which keys the SavingWrapper listens to. I never use the ‘s’ or ‘l’ they use in the course. I come from a long time ago when Police Quest used F5 and F6 (or at least that’s how my moldy brain remembers it).

Using key modifiers in Unity is a bit meh. We want to know if 2 keys are pressed in this frame but the likelihood of that being the case is pretty small because frames are so fast. The simplest is to check if the Ctrl key is down already when the ‘S’ key is down in this frame

// Check if the ctrl key is pressed - any frame (GetKey)
bool controlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
// Check if the control is down _and_ 'S' is pressed in _this frame_ (GetKeyDown)
if (controlDown && Input.GetKeyDown(KeyCode.S))
{
    // Save
}

Also, the course that covers the saving system is the `Unity RPG Core Combat Creator: Learn Intermediate C# Coding’. Here’s a link. Not sure if it will work right 'cos it’s my link and I’m enrolled

down the line in the ‘Shops and Abilities’ course (the final series), when we expand on the main menu, they’ll eliminate that for proper save and load buttons, when you make the main menu

I know it’s irrelevant, I’m just saying :slight_smile:

The saving and loading keys can be adjusted in the SavingWrapper.cs script’s Update() method.

Look for

if(Input.GetKeyDown(KeyCode.S)
{
    Save();
}

Simply change the Keycode to anything you wish.

Hi thank you, I went through tutorials on saving system. It is little bit clear to me, and I am saving by ‘K’ button (nonsense, work in progress, it is close to L). But when I save the game, run unity game again and load it in quest list there is no quest. Where could be a problem? I tried to investigated logs and it seem that the file is saved and also loaded. Maybe some problem with UI update is it possible?

Also not sure where Saveable entity, Wraper and saving system should be. So I have game object PersistentObjects his child: SavingSystem (there is SavingSystem and SavingWrapper).
Other object is QuestUI here is Saveable entity. His child is: QuestList also Saveable entity. Is this correct?

Here are scripts: GameDevHelp - Google Drive

Hope you can access it. unfortunately it is not possible to upload zips here.

Thank you for any thoughts.


I have tried save/load player position and it works. So seems that save/load system works in general.

For future code pastes (and your security), rather than linking to a Google Drive, you can paste the scripts directly into the editor here. This also makes it significantly easier for us to read and access them to help you.

Let’s start with a quick check in QuestList CaptureState() and RestoreState(). We’ll add some Debugs to make sure that they’re getting called:

         public object CaptureState()
        {
            List<object> state = new List<object>();
            foreach (QuestStatus status in statuses)
            {
                Debug.Log($"Capturing {status.GetQuest().GetTitle()}");
                state.Add(status.CaptureState());
            }
            return state;
        }

        public void RestoreState(object state)
        {
            List<object> stateList = state as List<object>;
            if (stateList == null) return;

            statuses.Clear();
            foreach (object objectState in stateList)
            {
                QuestStatus status = QuestStatus(objectState);
                statuses.Add(status);
                Debug.Log($"Restoring {status.GetQuest().GetTitle()}");
            }
        }

Is it easier? I thought it is much easier to download all at once in zip (unfortunately zip is not an option here). In future I will past scripts here as always…

As for second debug I had an error: Assets/Scripts/UI/Quests/QuestList.cs(79,38): error CS1955: Non-invocable member ‘QuestStatus’ cannot be used like a method.
So a changed it to this:

QuestStatus status = new QuestStatus((Quest)objectState);

I hope it is correct for debugging outcome.

Regarding debugs, here is the console:

  1. Capturing Find golden sword
    UnityEngine.Debug:Log (object)
    RPG.Quests.QuestList:CaptureState () (at Assets/Scripts/UI/Quests/QuestList.cs:65)
    GameDevTV.Saving.SaveableEntity:CaptureState () (at Assets/Scripts/Saving/SaveableEntity.cs:32)
    GameDevTV.Saving.SavingSystem:CaptureState (System.Collections.Generic.Dictionary`2<string, object>) (at Assets/Scripts/Saving/SavingSystem.cs:92)
    GameDevTV.Saving.SavingSystem:Save (string) (at Assets/Scripts/Saving/SavingSystem.cs:43)
    GameDevTV.Saving.SavingWrapper:Update () (at Assets/Scripts/Saving/SavingWrapper.cs:15)

  2. InvalidCastException: Specified cast is not valid.
    RPG.Quests.QuestList.RestoreState (System.Object state) (at Assets/Scripts/UI/Quests/QuestList.cs:79)
    GameDevTV.Saving.SaveableEntity.RestoreState (System.Object state) (at Assets/Scripts/Saving/SaveableEntity.cs:53)
    GameDevTV.Saving.SavingSystem.RestoreState (System.Collections.Generic.Dictionary`2[TKey,TValue] state) (at Assets/Scripts/Saving/SavingSystem.cs:105)
    GameDevTV.Saving.SavingSystem.Load (System.String saveFile) (at Assets/Scripts/Saving/SavingSystem.cs:58)
    GameDevTV.Saving.SavingWrapper.Update () (at Assets/Scripts/Saving/SavingWrapper.cs:20)

No, for a number of reasons, the biggest of which is that by putting the scripts in here directly, they can be referred to as we converse. In the rare context that I do need your complete project, then I will provide an address to upload them to.

Yes, that was an error on my part, I fogot the new keyword.

That is quite odd… I’m not seeing any mismatch between what you’re passing to CaptureState (List<object>) and what is being passed to RestoreState (should be the same object List<object>)

So, that brings us to the need to take a closer look, which will call for a Zip…
Zip up your project and upload it to https://gdev.tv/projectupload/
Be sure to remove the Library folder once you’ve zipped it up.

Be aware that I won’t be doing any QA support during the Christmas holiday, so I’ll get to it as soon as I can on Tuesday.

Thank you very much. I’ve submitted the project you should see it.

This line was in your QuestList.RestoreState() as

QuestStatus status = QuestStatus((Quest)objectState);

Which was causing the invalid cast exception.

Other than that, it does appear to be working.

I should note: The player (Caveman) should have the UniqueIdentifier “Player”. Any scene containing the CaveMan should have this same UniqueIdentifier for it’s SaveableEntity

The SaveableEntities on the Quest List UI and Quest Item UI are unneeded and can be removed.

You may wish to consider switching to my Json Saving System which can be found here: Json 1 Introduction and Installation · Wiki · Brian K. Trotter / RPGMods · GitLab

Our old saving system is unsafe for distributing per Microsoft’s latest guidelines, and the Json system is significantly easier to debug while in development as it’s human readable.

1 Like

Hi, and is it working for you? Because if I adjust the code like this, I have following error: Assets/Scripts/UI/Quests/QuestList.cs(79,38): error CS1955: Non-invocable member ‘QuestStatus’ cannot be used like a method.

Here is the script:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using GameDevTV.Saving;

namespace RPG.Quests
{
    public class QuestList : MonoBehaviour, ISaveable
    {
        List<QuestStatus> statuses = new List<QuestStatus>();

        public event Action onUpdate;

        public void AddQuest(Quest quest)
        {
            if (HasQuest(quest)) return;
            QuestStatus newStatus = new QuestStatus(quest);
            statuses.Add(newStatus);
            if (onUpdate != null)
            {
                onUpdate();
            }
        }

        public void CompleteObjective(Quest quest, string objective)
        {
            QuestStatus status = GetQuestStatus(quest);
            status.CompleteObjective(objective);
            if (onUpdate != null)
            {
                onUpdate();
            }
        }

        public bool HasQuest(Quest quest)
        {
            return GetQuestStatus(quest) != null;
        }

        public IEnumerable<QuestStatus> GetStatuses()
        {
            return statuses;
        }

        private QuestStatus GetQuestStatus(Quest quest)
        {
            foreach (QuestStatus status in statuses)
            {
                if (status.GetQuest() == quest)
                {
                    return status;
                }
            }
            return null;
        }

        // Saving or loading quests does not working:
        public object CaptureState()
        {
            List<object> state = new List<object>();
            foreach (QuestStatus status in statuses)
            {
                Debug.Log($"Capturing {status.GetQuest().GetTitle()}");
                state.Add(status.CaptureState());
            }
            return state;
        }

        public void RestoreState(object state)
        {
            List<object> stateList = state as List<object>;
            if (stateList == null) return;

            statuses.Clear();
            foreach (object objectState in stateList)
            {
                QuestStatus status = QuestStatus(objectState);
                statuses.Add(new QuestStatus(objectState));
                Debug.Log($"Restoring {status.GetQuest().GetTitle()}"); 

            }
        }
    }
}

Still missing the new keyword. Add it, and then add that status to the list instead of creating a second copy

            foreach (object objectState in stateList)
            {
                QuestStatus status = new QuestStatus(objectState);
                statuses.Add(status);
                Debug.Log($"Restoring {status.GetQuest().GetTitle()}"); 

            }

Thank you, I’ve got it. No error right now.

But still no quest item in the quest list. But console is saying this: Restoring Find fluorescent mushroom
It means that object is here if I understand it correctly.

My bad there, I keep forgetting the new keyword when I type it out here.

Try adding this to the last line of QuestList.RestoreState() (after the foreach loop)

onUpdate?.Invoke();

This will inform the UI that something has changed.

It is working, thanks for easy and elegant solution. :+1:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms