great video as always. One small extension you can add to avoid possible data corruption on crashes: before you write the save file, check if it exists, copy it, change extension to .bak, save the new data and delete the .bak. in this way if your game or computer crashes mid game/save on load you can check for a .bak file, check if the date is newer, if so, rename current sav to .temp, restore the .bak and recover the data, delete the temp file. There are some other fun tricks you can do like a sha1 hash to tell if a save file has been user tampered with outside of the game too, but that is imo far less important that ensure save files dont corrupt.
I have recently read a series of worrying articles about the vulnerabilities in the binaryformatter deserialization. How does the industry react to that? What's the preferred alternative (if any)?
@@captainufo4587 I mean what reason is there to care? Binary has always been "hackable", it's just a matter of looking for the patterns. But truthfully, why put in the time to prevent this, it's the player's choice to modify their files
@@chris.davidoff I wasn't referring to that. Personally I think that if someone wants to cheat in their single player, they are free to do it. I was mentioning articles like this: docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide#preferred-alternatives
Dude you've been on point about the subjects I wanted to see tutorials in : Photon networking, ML Agents, save systems... Awesome job, man, your channel is a gold mine
@@DapperDinoCodingTutorials great work, please make a tutorial about auto saving and loading using photon multiplayer, when ever the player logs in, his saved state loads up from the server .
This is really great. I keep on refactoring my code every time I watch your videos. These are the kind of tutorials that help me finish my projects instead of having this constant demotivating feeling that something in the code is going to cause problems later on.
i didn't watch the video yet but maybe make it so they save their position/stat on update and store it to the save? cloned stuff would have the scripts you give them
@@oculusquest6703 i posted this when i didn't know how much on update lags when used incorrectly, better solution would be to save their position when you exit/pause/autosave the game and load them when you enter the game
After I watched several videos, this one by far was the best saving system. Even though this is a little bit more complicated than others, this one probably will do my job with a little modification in the design if needed.
Good video. I often like to see what other developers do as a bit of a sanity check for myself. I have a game save manager within my persistence scene and as game objects spawn / get destroyed, they register and unregister themselves from various managers, including the game save manager. I did however over complicate my game save system by using generics, but I may change it now to use a simple object like you have. It'd definitely help reduce some coupling issues.
I was looking for a solution and considering different alternatives. This convinced me right away, it's clean, simple and scalable. Implemented it right away :) Thank you!
From the Microsoft documentation: "Warning BinaryFormatter is insecure and can't be made secure. For more information, see the BinaryFormatter security guide."
I could have saved myself a lot of time and frustration if I'd seen this a week ago. Still, better late than never! Thank you, this was by far the best tutorial for this I've seen on youtube.
Great video (as always) but is there an alternative to using Guid for objects I want to save but created at runtime? Also, following on from your other great videos on DOTs wouldnt this be a good candidate for conversion, as it is performing many similar actions across multiple objects?
Hello, I was following your item system and rpg system tutorial series and was wondering if I need to implement your saving system for saving the inventory, if so how would you recommend going about it? It keeps spouting out null references exptions when I put savable entity on the inventory slots which doesn't happen with other things, thanks.
This is all good like all the others but. so many miss that this will not work for items that are not in the game and has to be spawn. No how to that shows how to spawn the items back and set them to the transform. and the only one showing how to do this is missing half the stuff in the video.
Excellent video, thank you. Is there a simple way to make the saved data even less human readable, without some obfuscation plugin? Perhaps via the formatter?
Nobody is going to point out that he never mentions how to make the Guid??? I couldn't proceed further in the tutorial because of that... For those that wondered like myself, its actually by : using System;
Question: I see you are using FindObjectsOfType to restore all states, and that works great if the scene already contains the objects for which you want to restore the data. But what would you do if you also had to initialize the objects themselves? For example, in a tower defence game where you want to load up the game with a save file that instantiates the previously placed towers, and then restores the state. How would you manage the instantiation process? I'm currently using a save file to save the tower-type-id and position of the tower. Then go through a list (saved in a scriptable object) that contains all the different tower prefabs and allows you to compare the id's to find the correct one.
My first guess would be to use a factory class with a SaveableEntity component which handles spawning objects. This would keep a reference to all objects of that specific type created and would pull relevant data from them in its CaptureState() method. Then in RestoreState() method it could re-instantiate the objects initialized with the data pulled from the state object. I may be oversimplifying it though, I haven't given it enough thought.
Very nice codes. Exactly what I needed, although I still need a bit of help. How do we save sprites? How do we destroy, let's say, a newly spawned object if they were after the save? Thanks!
Hey man, great stuff! I wonder how this save system could work with ScriptableObjects. The standard with SO seems to be to serialize the entire object and then override it completely when loading. I used such solutions in SO heavy projects but sometimes you can't just use SO everywhere and you want to save some MonoBehaviours too. The goal is to have a all-in-one solution if possible because using and maintaining 2 save systems is really not ideal. Do you think your save system could work with SO?
Thanks for this, useful tutorial. I have questions, Save file can be modified, if you load it then you can modify saving data by saving file ? Is there a way to encrypt the save file ?
I'm a bit confused at what you're asking with your first question and the answer to your second question is yes. There are plenty of encryption methods online and all you have to do is encrypt the data before it is saved to a file and then decrypt as soon as you load from the file.
@@DapperDinoCodingTutorials My first question was if we save a file from our game and we go to the file it is possible to change the content and modify what it will be loaded. I'll try to encrypt save file to avoid modification.
Every time I follow a tutorial on saving, even if I copy everything 1 to 1 I can't get it to work. it throws up errors everywhere. I double, triple check every singe word on the page and nothing is different from what was on screen. I was planning on copying it all to then make the changes I needed as time went on while I adjust for what will fit better for my game. I can't do that if I can't even get the original script to work. Currently the only thing left for me to fix is the SaveableEntity script. it's throwing up errors about Guid, File, FileMode, BinaryFormatter not existing in the current context... but the worst thing of all that is the bane of my existance right now. It says that Dictionary has no definition for a comma. A COMMA. it's the one between the ()
This is great! Always good stuff on your channel. Although for any other brainless ones out there like me make sure you lower case the object reference on the interface🤦♀️
So if I understand right, this wouldn't save the state of other inactive scenes? I know you said it loads a save file and overwrites only what is necessary but what happens if the player plays through a scene without saving in it? There would need to be some autosave functionality but having the ability to save be dependent on the existence of a previous save seems a bit finicky. | What if instead the scene, right before it unloads, stores its own state in a singleton game object which also implements ISaveable, has a SaveableEntity component, and uses DontDestroyOnLoad function to have it persist between scenes. This game object would just contain a dictionary of states for all scenes. Then when it's time to save, the current scene would save its own updated state into this game object which is then serialized into a file. | Would that be better or have I gravely misunderstood something here? | EDIT: Of course, the singleton object would also store what was the last active scene so only that scene is restored on load. | (TH-cam is not letting me add newlines unless I do this terribleness)
Question: If I have a prefab, should I generate its id, and then copy paste it in every scene it comes in? I tried generating the id in the prefab menu, but it doesn't reflect in scenes
First thing First, Amazing work mate really good tutorial this is some next-level stuff!! Second, a question: let's say I want to update the "levelSystem" file data from other scripts, is there a good way to do it? (Considering that the values are private and if I use any type of update it forces it to go one way)
Not sure exactly how this scales into truly complex save-systems , think Total War style game where you have a bunch of factions, characters, armies and things all running around, a bunch of runtime data and 'non mono' classes being instantiated at runtime and held in potentially circular references. 🤔
im a begginer, is the namespace thing at the top needed? or is it just there? because i think the script is only in the public class's brackets but im not sure
If systems are in different namespaces, other systems can have scripts/classes with the same names and it won't matter. This becomes more of a thing as you add new features and systems to your project.
you might also want to check if(!(_saveable.GetType().ToString() == "SaveableEntity")) or whatever the Saveable Entity script is called for you, otherwise you'll get recursions and get a massive amount of data leaks! Hope this helps if you get this issue :)
Bunny83 made a UUID script that guarantees uniqueness. If one is very concerned about the seemingly extremely low risk of dupes. Dupes would be a pain to debug/detect I think if someone reports it
Hey, I have a question. How to make the saving work automatically? For example, I join the game and I want the data to automatically load, without the player needing to press anything. And when the player leaves the game, his data should be automatically saved. I heard from a tutorial that I would have to do it with "OnEnable()" and "OnDisable" but I am not sure. I hope that someone can help me with this.
Hey, I'm having an issue while deserializing, on the "private Dictionary LoadFile()" function I have the exact same lines of code but I'm getting an error: SerializationException: End of Stream encountered before parsing was completed. Searched online for a solution but didn't find it :( I thought I was using the wrong namespace, but doesn't seem to be the case, anyone can help me pleeeease!!! (Unity 2019.4.11f1)
if (stateDictionary.TryGetValue(typeName, out object value)) line 36 Assets/Scripts/SaveableEntity.cs(34,51): error CS1644: Feature `declaration expression' cannot be used because it is not part of the C# 6.0 language specification plz help im using unity version 2017.4.40f1
Can't do much, I use the 2018 and was able to access a feature that allows me to use a newer version of unity, but I'm pretty sure its what that causes me some issues right now...
I get the error " The type or namespace name 'Serializable' could not be found (are you missing a using directive or an assembly reference?" on the Level System tab. Can anybody give assistance.
@@MedicMainDave nope same thing happened to me.. brackets are there I added the using statement using system; and it worked but I don't understand why it didn't have that problem in the video. I've literally copied 1 to 1 but things are not working at all. nothing but errors coming up from saveable entity
EDIT: Nevermind! I accidentally put SaveableEntity on the same gameobject as another ISaveable script. OOPS! I'm getting a "SerializationException: End of Stream encountered before parsing was completed" error. The console is pointing me towards LoadFile(). Specifically the line returning the deserialized filestream. Am I missing something obvious or is the binary formatter just not working in this instance? i'm using Unity 2019.4.21.
Something small I made on the script, will auto-generate it once a prefab is brought into the scene. If there is someone who can expand upon this by all means, please. I followed this to make overworld items save once picked up in my game and it works perfectly. Thank you for your help! public class SaveableEntity : MonoBehaviour { void OnValidate() { if (gameObject.scene.name != null || gameObject.scene.rootCount != 0 && string.IsNullOrEmpty(id)) GenerateID(); }
Amazing tutorial. I also have a save system playlist series. It covers from player-pref to Firebase. I am currently editing the video with NodeJS as the back-end server for saving data. Any feedback on it will be really helpful.
SerializationException: Type 'UnityEngine.ScriptableObject' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. lmao what an error
great video as always.
One small extension you can add to avoid possible data corruption on crashes: before you write the save file, check if it exists, copy it, change extension to .bak, save the new data and delete the .bak. in this way if your game or computer crashes mid game/save on load you can check for a .bak file, check if the date is newer, if so, rename current sav to .temp, restore the .bak and recover the data, delete the temp file. There are some other fun tricks you can do like a sha1 hash to tell if a save file has been user tampered with outside of the game too, but that is imo far less important that ensure save files dont corrupt.
Would you mind explaining the gist of your sha1 hash trick for detecting if the file has been hampered with? Much appreciated. Thanks.
This is a beautiful gem to find in the comments! Thank you!
I have recently read a series of worrying articles about the vulnerabilities in the binaryformatter deserialization. How does the industry react to that? What's the preferred alternative (if any)?
@@captainufo4587 I mean what reason is there to care? Binary has always been "hackable", it's just a matter of looking for the patterns. But truthfully, why put in the time to prevent this, it's the player's choice to modify their files
@@chris.davidoff I wasn't referring to that. Personally I think that if someone wants to cheat in their single player, they are free to do it. I was mentioning articles like this: docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide#preferred-alternatives
Dude you've been on point about the subjects I wanted to see tutorials in : Photon networking, ML Agents, save systems... Awesome job, man, your channel is a gold mine
Glad I've been able to help so much recently! Hope you continue to enjoy the content :)
@@DapperDinoCodingTutorials great work, please make a tutorial about auto saving and loading using photon multiplayer, when ever the player logs in, his saved state loads up from the server .
@@DapperDinoCodingTutorials how would i go about saving a keycode with this ?
I learn more listening to you speak for 15 minutes than listening to an hour of most tutorials. Thanks for the great content!
This is really great. I keep on refactoring my code every time I watch your videos. These are the kind of tutorials that help me finish my projects instead of having this constant demotivating feeling that something in the code is going to cause problems later on.
Great to hear! Glad I can help :)
yeah dude, the scalability factor is a must and i’m relieved that a 16 minute video can provide me with that.
got yourself a new sub!!!
Thanks! What about spawned objects on runtime? How to restore a spawned aobjects? And how to store referenced values?
i didn't watch the video yet but maybe make it so they save their position/stat on update and store it to the save? cloned stuff would have the scripts you give them
@@craftlofer9974 Not on update thats to inefficient maybe every few seconds
@@oculusquest6703 i posted this when i didn't know how much on update lags when used incorrectly, better solution would be to save their position when you exit/pause/autosave the game and load them when you enter the game
After I watched several videos, this one by far was the best saving system. Even though this is a little bit more complicated than others, this one probably will do my job with a little modification in the design if needed.
Good video. I often like to see what other developers do as a bit of a sanity check for myself. I have a game save manager within my persistence scene and as game objects spawn / get destroyed, they register and unregister themselves from various managers, including the game save manager. I did however over complicate my game save system by using generics, but I may change it now to use a simple object like you have. It'd definitely help reduce some coupling issues.
I was looking for a solution and considering different alternatives. This convinced me right away, it's clean, simple and scalable. Implemented it right away :) Thank you!
From the Microsoft documentation: "Warning
BinaryFormatter is insecure and can't be made secure. For more information, see the BinaryFormatter security guide."
I could have saved myself a lot of time and frustration if I'd seen this a week ago. Still, better late than never! Thank you, this was by far the best tutorial for this I've seen on youtube.
Great video (as always) but is there an alternative to using Guid for objects I want to save but created at runtime?
Also, following on from your other great videos on DOTs wouldnt this be a good candidate for conversion, as it is performing many similar actions across multiple objects?
Hello, I was following your item system and rpg system tutorial series and was wondering if I need to implement your saving system for saving the inventory, if so how would you recommend going about it? It keeps spouting out null references exptions when I put savable entity on the inventory slots which doesn't happen with other things, thanks.
This is amazing, I've been thinking of how I might come up with a solution like this and.. here you've already shown the world how to do it :P
This is pretty awesome content and the kind of topics we need! Keep em coming please 🙏🙏🙏
Thank you! Will do!
This is all good like all the others but. so many miss that this will not work for items that are not in the game and has to be spawn. No how to that shows how to spawn the items back and set them to the transform. and the only one showing how to do this is missing half the stuff in the video.
Great stuff!
Thanks for sharing.
Excellent video, thank you. Is there a simple way to make the saved data even less human readable, without some obfuscation plugin? Perhaps via the formatter?
Could you make version of this with Json?
Nobody is going to point out that he never mentions how to make the Guid??? I couldn't proceed further in the tutorial because of that...
For those that wondered like myself, its actually by : using System;
Thank you my dude
Thanks! For those interested: can be seen at 1:24 of the video
Question: I see you are using FindObjectsOfType to restore all states, and that works great if the scene already contains the objects for which you want to restore the data. But what would you do if you also had to initialize the objects themselves? For example, in a tower defence game where you want to load up the game with a save file that instantiates the previously placed towers, and then restores the state. How would you manage the instantiation process?
I'm currently using a save file to save the tower-type-id and position of the tower. Then go through a list (saved in a scriptable object) that contains all the different tower prefabs and allows you to compare the id's to find the correct one.
My first guess would be to use a factory class with a SaveableEntity component which handles spawning objects. This would keep a reference to all objects of that specific type created and would pull relevant data from them in its CaptureState() method. Then in RestoreState() method it could re-instantiate the objects initialized with the data pulled from the state object. I may be oversimplifying it though, I haven't given it enough thought.
I think ISavable should have a generic type so you won't have to write object.
Very nice codes. Exactly what I needed, although I still need a bit of help.
How do we save sprites?
How do we destroy, let's say, a newly spawned object if they were after the save?
Thanks!
Hey man, great stuff! I wonder how this save system could work with ScriptableObjects. The standard with SO seems to be to serialize the entire object and then override it completely when loading. I used such solutions in SO heavy projects but sometimes you can't just use SO everywhere and you want to save some MonoBehaviours too. The goal is to have a all-in-one solution if possible because using and maintaining 2 save systems is really not ideal. Do you think your save system could work with SO?
Im using scriptable object instances for storing items on chests, wondering how to implement this save system to account for this. I am so lost
Is it posible to make an addition to this to save object that are created during play time by the player
Thanks for this, useful tutorial.
I have questions, Save file can be modified, if you load it then you can modify saving data by saving file ?
Is there a way to encrypt the save file ?
I'm a bit confused at what you're asking with your first question and the answer to your second question is yes. There are plenty of encryption methods online and all you have to do is encrypt the data before it is saved to a file and then decrypt as soon as you load from the file.
@@DapperDinoCodingTutorials My first question was if we save a file from our game and we go to the file it is possible to change the content and modify what it will be loaded.
I'll try to encrypt save file to avoid modification.
Every time I follow a tutorial on saving, even if I copy everything 1 to 1 I can't get it to work. it throws up errors everywhere. I double, triple check every singe word on the page and nothing is different from what was on screen. I was planning on copying it all to then make the changes I needed as time went on while I adjust for what will fit better for my game. I can't do that if I can't even get the original script to work. Currently the only thing left for me to fix is the SaveableEntity script. it's throwing up errors about Guid, File, FileMode, BinaryFormatter not existing in the current context... but the worst thing of all that is the bane of my existance right now. It says that Dictionary has no definition for a comma. A COMMA. it's the one between the ()
3:23 Wouldn't this be the ocasion to use ISaveable here?
why? What are you going to do with T in the interface?
Thank you Master!
Amazing design! I love this solution. Thanks for the advice.
This is great! Always good stuff on your channel. Although for any other brainless ones out there like me make sure you lower case the object reference on the interface🤦♀️
So if I understand right, this wouldn't save the state of other inactive scenes? I know you said it loads a save file and overwrites only what is necessary but what happens if the player plays through a scene without saving in it? There would need to be some autosave functionality but having the ability to save be dependent on the existence of a previous save seems a bit finicky.
|
What if instead the scene, right before it unloads, stores its own state in a singleton game object which also implements ISaveable, has a SaveableEntity component, and uses DontDestroyOnLoad function to have it persist between scenes. This game object would just contain a dictionary of states for all scenes. Then when it's time to save, the current scene would save its own updated state into this game object which is then serialized into a file.
|
Would that be better or have I gravely misunderstood something here?
|
EDIT: Of course, the singleton object would also store what was the last active scene so only that scene is restored on load.
|
(TH-cam is not letting me add newlines unless I do this terribleness)
Question: If I have a prefab, should I generate its id, and then copy paste it in every scene it comes in?
I tried generating the id in the prefab menu, but it doesn't reflect in scenes
First thing First, Amazing work mate really good tutorial this is some next-level stuff!!
Second, a question: let's say I want to update the "levelSystem" file data from other scripts, is there a good way to do it? (Considering that the values are private and if I use any type of update it forces it to go one way)
Don't mind me rushing to the comment section, I found the solution by making a property for each field. So just thank you now :D
Not sure exactly how this scales into truly complex save-systems , think Total War style game where you have a bunch of factions, characters, armies and things all running around, a bunch of runtime data and 'non mono' classes being instantiated at runtime and held in potentially circular references. 🤔
im a begginer, is the namespace thing at the top needed? or is it just there? because i think the script is only in the public class's brackets but im not sure
If systems are in different namespaces, other systems can have scripts/classes with the same names and it won't matter. This becomes more of a thing as you add new features and systems to your project.
Does this function with Mirror Networking as well?
So...what if an object is destroyed and you save? how would you go about removing that on save so on load the object is not still there...
Would this work for mobile games?
A GameObject internally already has a GUID. Any specific reason for not just using that instead of generating a new one?
Because that GUID can change at any time.
you might also want to check if(!(_saveable.GetType().ToString() == "SaveableEntity")) or whatever the Saveable Entity script is called for you, otherwise you'll get recursions and get a massive amount of data leaks! Hope this helps if you get this issue :)
how we can deserialize the txt file and save it to check out inside the file and manage it?
Bunny83 made a UUID script that guarantees uniqueness. If one is very concerned about the seemingly extremely low risk of dupes. Dupes would be a pain to debug/detect I think if someone reports it
Wow thank you for this
No problem, hope you find it useful!
So will this save the position of my character? I for some reason didn’t understand
no you must implement that yourself
Hey, I have a question. How to make the saving work automatically?
For example, I join the game and I want the data to automatically load, without the player needing to press anything. And when the player leaves the game, his data should be automatically saved. I heard from a tutorial that I would have to do it with "OnEnable()" and "OnDisable" but I am not sure.
I hope that someone can help me with this.
Hey, I'm having an issue while deserializing, on the "private Dictionary LoadFile()" function
I have the exact same lines of code but I'm getting an error: SerializationException: End of Stream encountered before parsing was completed.
Searched online for a solution but didn't find it :(
I thought I was using the wrong namespace, but doesn't seem to be the case, anyone can help me pleeeease!!!
(Unity 2019.4.11f1)
I have same issue did you find solution?
It keeps giveing me "Guid dose not exsist in this curent context"
if (stateDictionary.TryGetValue(typeName, out object value))
line 36
Assets/Scripts/SaveableEntity.cs(34,51): error CS1644: Feature `declaration expression' cannot be used because it is not part of the C# 6.0 language specification
plz help
im using unity version 2017.4.40f1
Can't do much, I use the 2018 and was able to access a feature that allows me to use a newer version of unity, but I'm pretty sure its what that causes me some issues right now...
I get the error " The type or namespace name 'Serializable' could not be found (are you missing a using directive or an assembly reference?" on the Level System tab. Can anybody give assistance.
I am guessing you forgot to put the [] brackets around the Serializable tag?
@@MedicMainDave nope same thing happened to me.. brackets are there
I added the using statement using system; and it worked but I don't understand why it didn't have that problem in the video. I've literally copied 1 to 1 but things are not working at all. nothing but errors coming up from saveable entity
This Doesnt work, typed it line for line, triple and quadruple checked it. however it is throwing errors left and right
can you please help me for save system in my project?
inventory save load system
EDIT: Nevermind! I accidentally put SaveableEntity on the same gameobject as another ISaveable script. OOPS!
I'm getting a "SerializationException: End of Stream encountered before parsing was completed" error. The console is pointing me towards LoadFile(). Specifically the line returning the deserialized filestream. Am I missing something obvious or is the binary formatter just not working in this instance? i'm using Unity 2019.4.21.
Hello, I'm currently running into the same issue but I don't fully get how you dealt with the problem. Could you elaborate please?
hello sir,
how to use anti memory hacking or
how to make code like no one can hack ?
can u make a tutorials on it ?
Something small I made on the script, will auto-generate it once a prefab is brought into the scene. If there is someone who can expand upon this by all means, please. I followed this to make overworld items save once picked up in my game and it works perfectly. Thank you for your help!
public class SaveableEntity : MonoBehaviour
{
void OnValidate()
{
if (gameObject.scene.name != null || gameObject.scene.rootCount != 0 && string.IsNullOrEmpty(id)) GenerateID();
}
hello!
Hellooooo
Hello
Hi
Amazing tutorial.
I also have a save system playlist series.
It covers from player-pref to Firebase.
I am currently editing the video with NodeJS as the back-end server for saving data.
Any feedback on it will be really helpful.
Hello The Harrowing
SerializationException: Type 'UnityEngine.ScriptableObject' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
lmao what an error
I had the same problem, it occurred because I'd marked the SaveData as [SerializeField] and not [Serializable]
Can't serialize scriptableobjects, have to make another class or whatever and save the stats there and then serialize that.
*cough* driver creation in C++ next?
definitely want to destroy vanguard out here, it is already destroying my PC enough.
I'm currently a C++ noob, rarely use it right now :p
Dapper Dino ahah, rip bro
it was a joke anyway, but you probably don’t get it.
NarkYT advanced joke
for the sake of my mental state, please tell me how to link the save and load functions to actual buttons on the canvas Pleaseeeee!!!!!!
Mal video