Hey everyone! SInce making this video, Microsoft have recommended not using the Binary Formatter for security reasons. Which you can read about here: docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide I'm keeping the video up because the overall content is still relevant, *but* I suggest looking at the XML/DataContractSerializer as the method for storing your data instead. The info of which can be found here -> docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer?view=net-5.0 Your overall approach should be roughly the same with one of the other serialization methods, so hopefully there's still something useful you can grab from the video. - Matt.
I'm having a very hard time seeing the security risk for the case you're illustrating here. The risk takes place when data is transmitted between machines (Eg: the internet) as far as I can tell. The closest I can see a Unity game coming to having this risk is if it's saving/loading data across a cloud platform (Eg: Steam). For a multiplayer/onine game, this would be a huge problem. But for a game that only saves and loads data from the computer it's installed on, it seems the Binary Formatter should be completely fine. And even if someone hacked a remote save file, isn't the worst they could do be to ruin your game data? Please anyone let me know if I'm missing something and there's a way this could open up someone to a Trojan or other hazard. I'm definitely not a hacker or security expert. Edit: I did find this useful example of how it could be abused. Apparently a blob that couldn't be deserialized still has a dispose() method called on it which can execute malicious code, including file deletion commands.
Any chance for a 2021 remake of this video using XML/DataContractSerializer? Loved the toy example, great way to teach saving prefabs and its instanced positions for base building projects!
@@UrbanArT69 I've since gone back and used the BinaryReader and BinaryWriter. You can use it to read/write a raw string from/to a file. Once you do that, you can deserialize the string into your Serialized objects using the JSON utility with Unity. Not sure yet on performance as I'm still just on POC. This also means all the objects you already serialized before stay exactly the same (in theory). You're just using the JSON utility instead of the Binary Formatter to read the data into the objects.
As far as I understand about security, binary seems more secured for me since the data inside the saved file is in binary state. XML is more human readable, easier to be changed. Am I wrong ? I realy don't see the security issue here :(
@@alextreme98 The issue is that the Binary Formatter executes a dispose method on any object whether it can successfully deserialize it or not. Hackers can create data objects that contain exploitative code in the dispose logic that gets run when you try (and fail) to parse the data. It's not really an issue except in network IT. But then, I'm always surprised by how hackers find exploits in infrastructure in the first place. Practically speaking, even if you had a single player game that only saved/loaded from your local HD, if you were to publish your game on Steam and use its cloud storage, and someone were able to hack Steam and modify the save files there, they could use your game to execute malicious code via your remotely saved and corrupted data. It's pretty far-fetched IMO, but still. If I were a new programmer who just wanted results, I'd go ahead with the Binary Formatter anyway. It's quick and easy to get running. You can address security concerns later during development after you have a functional prototype. And if you do switch to a more secure save system, all the classes you've marked [Serializable] will basically be the same if you use JSON instead (which is what I recommend). HTH
For anybody having the error "Property or indexer 'SaveData.current' cannot be assigned to -- it is read only", this may offer a solution. In your SaveData class you should currently have the code below: private static SaveData _current; public static SaveData current { get { if(_current == null) { _current = new SaveData(); } return _current; } } Below is an edited version of that, which allows this to have a value assigned to it, which is what we are doing when loading. private static SaveData _current; public static SaveData current { get { if(_current == null) { _current = new SaveData(); } return _current; } set { if(value != null) { _current = value; } } } And also make sure that the SaveData class has [System.Serializable] above it. This should hopefully fix the problem.
I guess Binary Serialization only works for windows systems. I'd personally use XML or JSON serialization. Pretty much the same amount of code, but more universal.
if anyone wants to go above and beyond, I suggest, during the saving process the system should take a snapshot of the current view of the gameplay and save it along with the file. That way, the player can have a screenshot of the state of the save in the menu.
Just dropping a comment to tell you the videos are amazing. I had never heard of the surrogates until I saw this video. I love that you don't hold your viewer's hand, and instead explain quickly and concisely what you're doing and how you go about it.
Oh boy! I'm embarrassed to admit I didn't watch the entire episode for I already have my own save system implemented. But it was pure gold what I missed. Back then I already liked but for anyone there reading this is the best saving system tutorial in unity. Thanks for sharing!
This topic needs a revisit I think. I've spent the last 2 weeks trying to get this to work & have with varying degrees of success for how I wanted it Implemented. After doing my own research there's actually huge chunks of info in this that are skipped over & just not mentioned in order to get it to work/understand it's limitations. I get the idea behind getting viewers to do their own research & learning how to do it on their own, but I think this video is a step to far beyond that and needs to include a few more steps for it to be a tutorial people can actually follow along.
hey, can you give more information about the things he skipped please ? With only his tutorial, I've managed to do what I wanted to do for my (simple) project. idk if I've missed something tho
@@Nicoblabla one thing he skipped was an event manager that he created off camera without telling us, which was used in the toyhandler script. The people who didn't know this would not have their save system work.
There is also another reason this topic needs a revisit. Even though this is a great tutorial and a great way introduction to the saving system. The binary format is not safe to use and it is easy to hack and make consumer load virus and malware. Even Microsoft actively encourages you to remove it from your games. But thanks to this tutorial, I actually had to do some reason on my own and came across this article. Source: docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide So also think a revisit would be a good thing, so people don't make their first game, filled with security threats.
Just stopping by to say that your video is the only tutorial on saves that deals with objects in a scene and thus, the interesting parts of the whole thing. Nice work.
Thank you for sharing your system. I'm just starting out learning Unity and this is the first "system" I've implemented in the game I'm tinkering with. It took me a whole day to get your system working but I see now I've made the right decision in following your solution. Everything updates itself automatically !! Wow, I wasn't actually expecting that when I started, but its turned out fantastic. Thank you :)
you and Jason Weimann along with some others have the best unity videos . I want to be able to come up with system like these .this video and the one with tab system helped me a lot
With this video i realize that in my game if you die you will never start on a saved level XD . Its hard to make a save system. But the video is awesome men ! You are great Thanks!
Awesome guides! Built my first save/load system in a similar fashion but this has some improvements my uses arguments to change obj and casting. Like the short conciseness and the speed up of code of your presenting style. Keep it up dude
dude! your tutorials are pretty useful and straightforward. Also, you always try to code in the standard way which makes it reliable. ;) please create more!
very great video everything seems professional the only problem is that sometimes its hard to follow what you are doing sometimes there are not enough explanation and your pace is too fast for people who are starting to learn
Amazing video! One small question. I think 'toys' is a collection of gameObjects of all the prefabs. How do you go about creating the toys collection in the code?
Love the tutorial, it seems like a great save system. Can you please upload the missing steps to really follow along what you do in the video, it's impossible to do so.
you actually covered shit that would be an actual concern for a game that's not just a mindless smartphone game - you talk about saving/loading gameobjects and states regarding those game objects, and even go the extra mile of covering the concept of multiple save slots. Very useful.
This is a very informative video and I picked up some things that I can use. However, watching the video is like starting a book and realizing that some key chapters are missing. I understand that this is an intermediate guide covering some underlying concepts for developing a save system, but referencing objects and classes that are not discussed is inconsistent with the video title in my opinion. The title of the video "How to Build A Save System in Unity" should read "Tips and Tricks for Building a Save System in Unity"
Another great video! PlayerPrefs is incredibility slow and I I've done JSON before prefixed with a salted hash. I touched the binary formatter before in a sample project but never went in depth, I'll give it another look. Thanks for the vid!
Hey ! Amazing tutorial BUT, I have a problem at 7:26 with you're 25 line which is the SaveData.current, my code told me that this variable is on read only :/ How did you patch this ? What's on the top of the ToyManager script and the GameEvents ? You don't show them. Thx for help
Hey! i get an error on line: GameObject obj = Instantiate(toys[(int)currentPlayerData.objectType]); cannot find the name "toys", where is that from? Thanks for your response
Hi, i really like your tutorial. Thank you it was so helpful. Is there any chance that you upload the codes or project to github? Because i think i m doing something wrong.
It does feel like he could add 1 minute to the video and have everything explained in full... This tutorial is written for a very small margin of people, it's kinda mind boggling lol. I understand a good chunk of it, but there's so much just randomly left out, for unexplained reasons. For example, right off the bat, in the first 3 minutes he adds some name spaces, doesn't mention it at all, for a noob it's kinda difficult to follow along.
Having recently written some serialization in C++ it looks like way more boiler platey in C#. As long as you don't have any pointers or references in your class it's just: std::ofstream file("savename", std::ofstream::out | std::ofstream::binary); file.write(reinterpret_cast(&save), sizeof(save)); file.close();
Great video! Question: suppose you were making something a bit more complex where you wanted more types of objects with their own savable data (say a RTS game or RPG). Which approach would you go with for the ToyData class? 1-Make one universal ToyData class that holds all the data you might ever want to save 2-Make subclasses of ToyData with their own additional data, possibly making use of interfaces for accessing data 3-Make ToyData into an Entity style class that is mostly empty but can hold components that are accessed with generic GetComponent function All of these have pros and cons...1 is potentially clunky if you need to add more data, but is also the simplest and fastest. 2 runs into the issue of inheritance vs composition. 3 has composition, but that also means accessing the components may have a performance cost, plus you now need to worry about the actual composition (might need to make factory classes for example).
This seemed like a great tutorial before I actually tried to implement it. Watched through the video once, yeah I understood everything, so decided to follow along. Nope... it turns out there are critical pieces missing from this tutorial right before you build the UI. I followed up to this point, and don't understand how the saving is working when you press the save button. Can't progress any further due to errors with the load path and SaveData instancing. Looks like wasted time, unfortunately. I recommend on this one you go back through your video following along to see where you have missed these key components. I've followed a few of your other videos very easily to completion, so it looks like you just missed a key explanation here.
if it's any use I quickly made a bare-bones example of how to use it, but instead of cars and dolls I've used coins and notes. I hope this helps you understand how it works public void SaveProgress() { SaveData.current.coins = coins; SaveData.current.notes = notes; SerializationManager.Save("example", SaveData.current); } public void LoadProgress() { SaveData.current = (SaveData)SerializationManager.Load(Application.persistentDataPath + "/saves/example.save"); coins = SaveData.current.coins; notes = SaveData.current.notes; }
I belive he rasies a GameEvent OnLoad and Onsave, that all objects that can be saved/loaded can subscribe to. See his previous making custom event videos on how it works and how to raise one
@@81gamer81 how the hell does he instances 'PlayerProfile'? everytime i try to access profile from SaveData.current.profile it gives me that the thing doesn't exist! instantiating it also doesn't work, whatahell did he do??? i hate this so much!
I'm a beginner and i have a fair question. On a certain point of the video he uses the save button which was not ever mentioned how in the heck it was scripted. so how could i script the save button so it actually updates the data that i will load pressing the load button.
Hey! Hope This Helps! ----------------------------------------------------------------------------------------------------------------------------------------------------------- public void OnLoadGame() { //this is the load function assign this to the load button SaveData.current = (SaveData)SerializationManager.Load(Application.persistentDataPath + "/saves/Save.save"); } public void OnSaveGame() { //This is the save function, "Save" is the name of the save file, and save data is the object from the script in the video, assign this to the save button. SerializationManager.Save("Save", SaveData.current); } -Chris
@@danielmakac583 put t n save data and then you can call t from another script if needed. I think you can do public SaveData saveData; and then when you need the save method to be called saveData.Save or Load not sure this was long ago.
Could you provide the source code in the description for vids like this? You kind of breezed past writing the actual save and load functions and as a beginner it left me very lost. Being able to look back on all your code would help a lot.
Yea he needs to redo this video and make it better. so much is missing. Very hard to understand if your new and if your not new no need to watch it because your skills are beyond this.
Underrated! Me: sitting and codding universal save system that will save any stuff in any way and load any stuff in any way. When i saw this video i was like: "What a fuck! Well it's not bad, but it's not cool to be called SAVE SYSTEM". Well, the thing that pretend to be a save system must next feature: save any anything, and load anything with no inside code reworks
Nice and well made tutorial, thanks! How would you handle loading saves from different versions of the game? For example, if you have removed a unit/building that is in a save, or perhaps added new properties to something existing. Also, it would be really cool to see your approach on a replay system, e.g. replaying a full match/game (like Starcraft) or just recording a sequence of a game for review later.
old question but, you can have a version number on save files so when you change something in save, you change version number and keep old version readers all the time if u want to have backward compatibility.
Great Question. So, the fields that haven't changed will still load correctly - even if you've changed the structure of the class. (I actually used the same save data file here for the two versions) It just didn't assign the old data anywhere because it no longer existed. What I tend to do, is add a string field into the save data that tracks the version of the game. Then, when the game loads depending on what I've changed between versions I'll either try to parse that data, or replace it with the new data / fields instead. It's really up to you how you handle dealing with changed fields though. It'll be a bespoke solution depending on your project structure, but I'd suggest starting by tagging each save with a version and doing some kind of comparison on load.
Hey! Thank you so much for this content! One question: do you see some kind of problem when applying this to save and load augmented reality sessions? I mean, for an android app?
Hello, I'm very beginning in c# (and programmation in general), so I don't understand everything in this tutorial, so I don't really understand how it works, to save do I have to put all the variables I want to save in save data (from all objects I have) or I have to create a SaveData script for each object?
good but can i use binary format file ,to be stored in database like Mysql or Mongodb , so the player can keep his game persistent despite changing the devices , which file format and database do you recommend
When SaveData.current can't be assigned a value because it's read only just add the following below the body of the get statement in the SaveData class's singleton: set { _current = value; } It worked for me... I think😊
Hey, would you mind helping? I am getting a non instance of object, when using the current.profile.characterName. I am not sure how this is null? How does one set data then?
At 4:44 you've got a few functions recording the data based on a button press. If I have a bunch of thing I need to keep track of (like what what the player's stats are, what's in their inventory list, what story triggers they've been through etc.) would I need to use separate functions for all those things? I kind of just want to save everything about the player all at once (my game is text based).
This is what the GameData class is for. As discussed in the video. If you put everything you need to save in a single serialised class such as GameData you can just save that GameData class. If you've got classes all over the place with data you need to save, I would either refactor it so the saved data is in one place OR write methods to call to those classes and pass the data on save/load accordingly.
"If you found anything useful in the video" Me: All of it!!. Playerprefs starts to become a real mess, real fast. It's like that draw or cupboard you have in your house, you know, the one full of junk that you don't even want to spend more than 20 seconds looking in LOL.
Hi i'm getting an error when i try to implement this code (first half of the video) I get a "NullReferenceException: object reference not set to an instance of an object" when i try to refer to the save data. So im trying to add to the save data: SaveData.current.profile.partyNames.Add("Blah"); but i get that error. do i need to do something like, resources.load or have the SaveData script attached to something and referance that object? Im not sure if ive missed something in your video or? Cheers
I have no idea what i've done wrong or what he's done that he's not shown. I've followed his code exactly up to the 5 minute mark. Did anyone else have this issue? I just cant seem to access the data, for example: SaveData.current.profile.currency -= 200; results in the error i've mentioned above. So is he referancing the class in some way he's not shown or what? is that code he's doing in a specific script? (PlayerProfile, SaveData, SerilizedManager) does anyone know whats happening here as im pulling my hair out trying to get it to work.
public void OnLoadGame() { SaveData.current = (SaveData)SerializationManager.Load(Application.persistentDataPath + "/saves/Save.save"); } This line gives out an error when I put it in any script and says can't assign current cause its read only? can you help me with that? I did get rid of the error by adding a set method after get so setting current = value; not sure if this is the correct way of doing it but it got rid of the error.
hello, I have a GTA style project. I am looking for the Save Load system, you have made the purchase part in the save load window you wrote, but I want the player to continue from where it left off by pressing the Load button registered in the load section. What kind of way should I follow?
I feel like these serialization surrogates are harder then it should be. Looking at it, it makes sense, but you can just as well store a Vector3 as 3 separate floats without this surrogate method, imo that's faster and easier to read.
I feel ignorant, but can you include a link to these files, I somehow cannot follow which script and which place you are entering these codes. I'm learning C# "by ear" if you will, and tailoring it to fit my Classes... I get how things are linking, but I'm not finding how you linked them to the buttons, and I can't tell which object to toss the script on. Very great video, just hard to follow somehow... just me I'm sure... ADHD and sleep deprivation from work aren't helping.
I am confused, at 3:32 you created the SaveData as a singleton, with _current, but after, at 4:54 at current can be assigned, 5:37, _current no longer exists. :?
If you were to do an open world save system, how would you save/load/unload data with additive scene loading? Would you add an int for the scene index of each object and only load if the matching scene is loaded? Would the save function work modularly?
So, I would keep the game state data independent from any scene. That way all the save data for your game would be serialised no matter what scene you're in. But, if you need to serialise chunks of data for each scene, such as object positions, or specific world changes, etc.. you could create a list of game data classes and save/load each item in that list for each scene index. When a scene loads, you could query the master game state and ask for the save data for that scene.
Game Dev Guide I’m not sure I completely understand. So if I had scene A and B and I wanted to save scene A’s data list when I move to scene B, would I save scene A’s list, load and delete scene B’s list and then save scene B’s list when I need to? Or would I only save scene At list then load scene B’s list and then save it when I need to? Would it automatically overwrite or just add onto the previously saved scene B list? Perhaps a video would help me more, I’m having trouble working this out in my head 😅
@@CamNicPet CamNicPet Everything you need to know is already covered in this video in regards to saving and loading classes. But, it sounds like you're unsure how references and lists/arrays work. I'll try to clarify, my approach to this I would be to have a Game Data class that holds all of the data in my game I want to save. This would not be tied to any scene, which means that it can be accessed anywhere and hold all of the data for your game. (This is shown in the video) Inside my GameData class, I would probably have a list/array of a LevelData class which would hold level specific data I need to store. Any scene I have in my game would require a reference to a LevelData class. So, when I load a scene, I just get the coresponding LevelData class from the list of them in my GameData class. If I were to reference and retrieve the LevelData from my GameData class, any changes I make to the LevelData when my scene is loaded would actually be made in the GameData class due to it being a reference. So when I save my GameData Class, it saves all of my level data too.
What exactly makes a data type not serializable? Aren't they all just collections of data stored in memory? Wouldn't elements be stored/accessed in a particular order anyway?
It tells me that The name 'loadArea' does not exist in the current context. But I can't seem to see any reference to a "loadArea" in the SaveManager script in the video. Is there a reference? if so what is the reference?
Hey everyone! SInce making this video, Microsoft have recommended not using the Binary Formatter for security reasons. Which you can read about here: docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
I'm keeping the video up because the overall content is still relevant, *but* I suggest looking at the XML/DataContractSerializer as the method for storing your data instead. The info of which can be found here -> docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer?view=net-5.0
Your overall approach should be roughly the same with one of the other serialization methods, so hopefully there's still something useful you can grab from the video.
- Matt.
I'm having a very hard time seeing the security risk for the case you're illustrating here. The risk takes place when data is transmitted between machines (Eg: the internet) as far as I can tell. The closest I can see a Unity game coming to having this risk is if it's saving/loading data across a cloud platform (Eg: Steam). For a multiplayer/onine game, this would be a huge problem. But for a game that only saves and loads data from the computer it's installed on, it seems the Binary Formatter should be completely fine. And even if someone hacked a remote save file, isn't the worst they could do be to ruin your game data? Please anyone let me know if I'm missing something and there's a way this could open up someone to a Trojan or other hazard. I'm definitely not a hacker or security expert. Edit: I did find this useful example of how it could be abused. Apparently a blob that couldn't be deserialized still has a dispose() method called on it which can execute malicious code, including file deletion commands.
Any chance for a 2021 remake of this video using XML/DataContractSerializer? Loved the toy example, great way to teach saving prefabs and its instanced positions for base building projects!
@@UrbanArT69 I've since gone back and used the BinaryReader and BinaryWriter. You can use it to read/write a raw string from/to a file. Once you do that, you can deserialize the string into your Serialized objects using the JSON utility with Unity. Not sure yet on performance as I'm still just on POC. This also means all the objects you already serialized before stay exactly the same (in theory). You're just using the JSON utility instead of the Binary Formatter to read the data into the objects.
As far as I understand about security, binary seems more secured for me since the data inside the saved file is in binary state. XML is more human readable, easier to be changed. Am I wrong ? I realy don't see the security issue here :(
@@alextreme98 The issue is that the Binary Formatter executes a dispose method on any object whether it can successfully deserialize it or not. Hackers can create data objects that contain exploitative code in the dispose logic that gets run when you try (and fail) to parse the data. It's not really an issue except in network IT. But then, I'm always surprised by how hackers find exploits in infrastructure in the first place. Practically speaking, even if you had a single player game that only saved/loaded from your local HD, if you were to publish your game on Steam and use its cloud storage, and someone were able to hack Steam and modify the save files there, they could use your game to execute malicious code via your remotely saved and corrupted data. It's pretty far-fetched IMO, but still. If I were a new programmer who just wanted results, I'd go ahead with the Binary Formatter anyway. It's quick and easy to get running. You can address security concerns later during development after you have a functional prototype. And if you do switch to a more secure save system, all the classes you've marked [Serializable] will basically be the same if you use JSON instead (which is what I recommend). HTH
For anybody having the error "Property or indexer 'SaveData.current' cannot be assigned to -- it is read only", this may offer a solution.
In your SaveData class you should currently have the code below:
private static SaveData _current;
public static SaveData current
{
get
{
if(_current == null)
{
_current = new SaveData();
}
return _current;
}
}
Below is an edited version of that, which allows this to have a value assigned to it, which is what we are doing when loading.
private static SaveData _current;
public static SaveData current
{
get
{
if(_current == null)
{
_current = new SaveData();
}
return _current;
}
set
{
if(value != null)
{
_current = value;
}
}
}
And also make sure that the SaveData class has [System.Serializable] above it.
This should hopefully fix the problem.
THANK YOU, this is a blessing!
Thank you !! I knew someone would come thru in the comments :)
THANK YOU SO MUCH
why the hell didn't he do that in the tutorial man, jesus. this is so lackluster, he leaves that part unfinished and shows it working just fine!
thanks
One of the best save system tutorial I've watched.
Straightforward and Concise.
Good job
I guess Binary Serialization only works for windows systems. I'd personally use XML or JSON serialization. Pretty much the same amount of code, but more universal.
@@neeeeeck9005 Binary serialization works for any platform. JSON is certainly less universal than a simple binary file.
How is it in any way concise? It skips over far to much.
@Blackstorm JSON and XML are way more unsecure too cuz u can very easely modify the code
if anyone wants to go above and beyond, I suggest, during the saving process the system should take a snapshot of the current view of the gameplay and save it along with the file. That way, the player can have a screenshot of the state of the save in the menu.
Good thinking
Just dropping a comment to tell you the videos are amazing. I had never heard of the surrogates until I saw this video. I love that you don't hold your viewer's hand, and instead explain quickly and concisely what you're doing and how you go about it.
Oh boy! I'm embarrassed to admit I didn't watch the entire episode for I already have my own save system implemented. But it was pure gold what I missed. Back then I already liked but for anyone there reading this is the best saving system tutorial in unity.
Thanks for sharing!
This topic needs a revisit I think. I've spent the last 2 weeks trying to get this to work & have with varying degrees of success for how I wanted it Implemented. After doing my own research there's actually huge chunks of info in this that are skipped over & just not mentioned in order to get it to work/understand it's limitations. I get the idea behind getting viewers to do their own research & learning how to do it on their own, but I think this video is a step to far beyond that and needs to include a few more steps for it to be a tutorial people can actually follow along.
hey, can you give more information about the things he skipped please ?
With only his tutorial, I've managed to do what I wanted to do for my (simple) project. idk if I've missed something tho
@@Nicoblabla one thing he skipped was an event manager that he created off camera without telling us, which was used in the toyhandler script. The people who didn't know this would not have their save system work.
There is also another reason this topic needs a revisit. Even though this is a great tutorial and a great way introduction to the saving system. The binary format is not safe to use and it is easy to hack and make consumer load virus and malware. Even Microsoft actively encourages you to remove it from your games. But thanks to this tutorial, I actually had to do some reason on my own and came across this article.
Source: docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
So also think a revisit would be a good thing, so people don't make their first game, filled with security threats.
@@chazzwazzler
Is there someone who can solve this problem?
Your tutorials are really straight forward and not those 50 minute videos, which explain useless stuff. Thank you so much for making these.
Greatest Unity save load tutorial video I can find. Thanks!
Just stopping by to say that your video is the only tutorial on saves that deals with objects in a scene and thus, the interesting parts of the whole thing. Nice work.
Hey there, I just wanted to say I love your funny, straight to the point videos. You deserve a lot more subscribers! Keep being awesome.
Thank you for sharing your system.
I'm just starting out learning Unity and this is the first "system" I've implemented in the game I'm tinkering with. It took me a whole day to get your system working but I see now I've made the right decision in following your solution. Everything updates itself automatically !! Wow, I wasn't actually expecting that when I started, but its turned out fantastic. Thank you :)
Would love to see you do a dialog system!
Yeah
That is so easy to do, and u don't need code, I'll have a vid on that soon!
you and Jason Weimann along with some others have the best unity videos . I want to be able to come up with system like these .this video and the one with tab system helped me a lot
With this video i realize that in my game if you die you will never start on a saved level XD . Its hard to make a save system. But the video is awesome men ! You are great Thanks!
First minute of watching: why am I not subscribed to you? This is gold!
This is so helpful. I learned file systems at my university but it was in C++ and I have had trouble learning how C# does it.
This is one of the most useful unity tutorial channel I ever found ! Thanks, I learn a lot with your videos !
just 100% what I need atm. I wanted to save positions of spawned objects and you just shown me how to do that! subscribed!
Awesome guides! Built my first save/load system in a similar fashion but this has some improvements my uses arguments to change obj and casting. Like the short conciseness and the speed up of code of your presenting style. Keep it up dude
dude! your tutorials are pretty useful and straightforward. Also, you always try to code in the standard way which makes it reliable. ;)
please create more!
OMG. This is what I've been looking for for a whole month. Really appreciate your channel. Thank you.
Your videos are so underrated
Awesome, thank you! I saw something similar years ago and I've been searching for another guide. Great job!
very great video everything seems professional the only problem is that sometimes its hard to follow what you are doing sometimes there are not enough explanation and your pace is too fast for people who are starting to learn
Amazing video! One small question. I think 'toys' is a collection of gameObjects of all the prefabs. How do you go about creating the toys collection in the code?
This is exactly the sort of more intermediate channel I was looking for.
this was by far the most helpful thing I have found yet, thank you so much.
Love the tutorial, it seems like a great save system. Can you please upload the missing steps to really follow along what you do in the video, it's impossible to do so.
you actually covered shit that would be an actual concern for a game that's not just a mindless smartphone game - you talk about saving/loading gameobjects and states regarding those game objects, and even go the extra mile of covering the concept of multiple save slots. Very useful.
extremely excellent storage system .The option to save multiple files :) Thank you I have been looking for something like this . Excellent video!
This is a very informative video and I picked up some things that I can use. However, watching the video is like starting a book and realizing that some key chapters are missing. I understand that this is an intermediate guide covering some underlying concepts for developing a save system, but referencing objects and classes that are not discussed is inconsistent with the video title in my opinion. The title of the video "How to Build A Save System in Unity" should read "Tips and Tricks for Building a Save System in Unity"
Another great video! PlayerPrefs is incredibility slow and I I've done JSON before prefixed with a salted hash. I touched the binary formatter before in a sample project but never went in depth, I'll give it another look. Thanks for the vid!
Hey ! Amazing tutorial BUT, I have a problem at 7:26 with you're 25 line which is the SaveData.current, my code told me that this variable is on read only :/ How did you patch this ? What's on the top of the ToyManager script and the GameEvents ? You don't show them. Thx for help
same, kind of makes it hard to follow along and take notes when a key part of the system isn't there
Add a set instruction to the public property, like so:
public static SaveData Current {
get {
if (_current == null)
_current = new SaveData();
return _current;
} set {
_current = value;
}
}
You'll need to make a reference to it
@@terdell thank you very much ;-)
@@patrevizani hey, can you help me? What did you do?
Hey! i get an error on line: GameObject obj = Instantiate(toys[(int)currentPlayerData.objectType]);
cannot find the name "toys", where is that from? Thanks for your response
he created a GameObject array of his prefabs called "toys" which also drove me mad trying to figure out since he does not explain that he did it.
@@IsaiahC86 where did he create him? In SaveData or in ToyData?
Hi, i really like your tutorial. Thank you it was so helpful. Is there any chance that you upload the codes or project to github? Because i think i m doing something wrong.
Very nice tutorial! I did learn a few new concepts and even though I am not using unity they seem pretty universal concepts.
Thank you! Finally found what I was exactly looking for!
Use Path.Combine because different operating systems use different seperators.
Perfect tutorial .
subscribed in a minute.
Thank oyu it6 was very useful. The surogates was totlly new to me. thx! you are great!
It does feel like he could add 1 minute to the video and have everything explained in full... This tutorial is written for a very small margin of people, it's kinda mind boggling lol. I understand a good chunk of it, but there's so much just randomly left out, for unexplained reasons.
For example, right off the bat, in the first 3 minutes he adds some name spaces, doesn't mention it at all, for a noob it's kinda difficult to follow along.
I've been looking at your tutorials! Great stuff!!
Well explained, to the point, clear and the example at the end was very helpfull!
Having recently written some serialization in C++ it looks like way more boiler platey in C#. As long as you don't have any pointers or references in your class it's just:
std::ofstream file("savename", std::ofstream::out | std::ofstream::binary);
file.write(reinterpret_cast(&save), sizeof(save));
file.close();
Fantastic explanation. Cheers pal.
If it were possible I'd subscribe twice.
thanks you saved my life
Great video! Question: suppose you were making something a bit more complex where you wanted more types of objects with their own savable data (say a RTS game or RPG). Which approach would you go with for the ToyData class?
1-Make one universal ToyData class that holds all the data you might ever want to save
2-Make subclasses of ToyData with their own additional data, possibly making use of interfaces for accessing data
3-Make ToyData into an Entity style class that is mostly empty but can hold components that are accessed with generic GetComponent function
All of these have pros and cons...1 is potentially clunky if you need to add more data, but is also the simplest and fastest. 2 runs into the issue of inheritance vs composition. 3 has composition, but that also means accessing the components may have a performance cost, plus you now need to worry about the actual composition (might need to make factory classes for example).
This seemed like a great tutorial before I actually tried to implement it. Watched through the video once, yeah I understood everything, so decided to follow along. Nope... it turns out there are critical pieces missing from this tutorial right before you build the UI. I followed up to this point, and don't understand how the saving is working when you press the save button. Can't progress any further due to errors with the load path and SaveData instancing. Looks like wasted time, unfortunately. I recommend on this one you go back through your video following along to see where you have missed these key components. I've followed a few of your other videos very easily to completion, so it looks like you just missed a key explanation here.
Same boat... I am now trying to figure out how to write the actual save function...
if it's any use I quickly made a bare-bones example of how to use it, but instead of cars and dolls I've used coins and notes. I hope this helps you understand how it works
public void SaveProgress()
{
SaveData.current.coins = coins;
SaveData.current.notes = notes;
SerializationManager.Save("example", SaveData.current);
}
public void LoadProgress()
{
SaveData.current = (SaveData)SerializationManager.Load(Application.persistentDataPath + "/saves/example.save");
coins = SaveData.current.coins;
notes = SaveData.current.notes;
}
I belive he rasies a GameEvent OnLoad and Onsave, that all objects that can be saved/loaded can subscribe to. See his previous making custom event videos on how it works and how to raise one
@@81gamer81 how the hell does he instances 'PlayerProfile'? everytime i try to access profile from SaveData.current.profile it gives me that the thing doesn't exist! instantiating it also doesn't work, whatahell did he do??? i hate this so much!
This video is a piece of cake, love it
I'm a beginner and i have a fair question.
On a certain point of the video he uses the save button which was not ever mentioned how in the heck it was scripted.
so how could i script the save button so it actually updates the data that i will load pressing the load button.
Hey! Hope This Helps!
-----------------------------------------------------------------------------------------------------------------------------------------------------------
public void OnLoadGame()
{
//this is the load function assign this to the load button
SaveData.current = (SaveData)SerializationManager.Load(Application.persistentDataPath + "/saves/Save.save");
}
public void OnSaveGame()
{
//This is the save function, "Save" is the name of the save file, and save data is the object from the script in the video, assign this to the save button.
SerializationManager.Save("Save", SaveData.current);
}
-Chris
@@kristerskarklins4722 where do i place this ? is this inside the SaveData class or can be anywhere else or in the different class?
@@danielmakac583 put t n save data and then you can call t from another script if needed.
I think you can do
public SaveData saveData;
and then when you need the save method to be called
saveData.Save or Load not sure this was long ago.
@@kristerskarklins4722 yeah i did. I eventaully it figured hahaha. but thanks for replying
Thanks for this. I never knew there're binary surrogates class
very nice - does something like this exist for multiplayer games as well?
What command do you use in the Save button ?
No Set {} in the SaveData ?
Could you provide the source code in the description for vids like this? You kind of breezed past writing the actual save and load functions and as a beginner it left me very lost. Being able to look back on all your code would help a lot.
Yea he needs to redo this video and make it better. so much is missing. Very hard to understand if your new and if your not new no need to watch it because your skills are beyond this.
PlayerPrefs.SetString("PlayerName", "KillMeNow");
lol
Underrated!
Me: sitting and codding universal save system that will save any stuff in any way and load any stuff in any way. When i saw this video i was like: "What a fuck! Well it's not bad, but it's not cool to be called SAVE SYSTEM". Well, the thing that pretend to be a save system must next feature: save any anything, and load anything with no inside code reworks
@@nikolaynakorkeshko448 is this even possible for different classes? your "the universal save system"?
Another games: Some save files saved in documents
Unity games: Where are my save files?
I would love a "for dummies" version of this, and i know this is pretty straightforward but i really suck at programming for now.
Does this system work in mobile games for Android or iOS?
Nice and well made tutorial, thanks! How would you handle loading saves from different versions of the game? For example, if you have removed a unit/building that is in a save, or perhaps added new properties to something existing.
Also, it would be really cool to see your approach on a replay system, e.g. replaying a full match/game (like Starcraft) or just recording a sequence of a game for review later.
old question but, you can have a version number on save files so when you change something in save, you change version number and keep old version readers all the time if u want to have backward compatibility.
what's going to happen if you make changes to an object and add new fields then try to load an older version?
Great Question.
So, the fields that haven't changed will still load correctly - even if you've changed the structure of the class. (I actually used the same save data file here for the two versions) It just didn't assign the old data anywhere because it no longer existed.
What I tend to do, is add a string field into the save data that tracks the version of the game. Then, when the game loads depending on what I've changed between versions I'll either try to parse that data, or replace it with the new data / fields instead.
It's really up to you how you handle dealing with changed fields though. It'll be a bespoke solution depending on your project structure, but I'd suggest starting by tagging each save with a version and doing some kind of comparison on load.
Thanks a lot, you helped me ❤❤❤
Does this also work for WebGL platform? Like, will the files be stored in the browser cache or machine folder?
Thank you so much! (And the guys improving the code in the comments too)
Hey! Thank you so much for this content! One question: do you see some kind of problem when applying this to save and load augmented reality sessions? I mean, for an android app?
Hi, awesome video! One question, it's better to use this system or to use a JSON system? In any case, this video helped a lot, thanks!
is the data saved automatically on google/ google play services as well or we have to do something extra for it as well?
Does this work for mobile Apps too?
Hello, I'm very beginning in c# (and programmation in general), so I don't understand everything in this tutorial, so I don't really understand how it works, to save do I have to put all the variables I want to save in save data (from all objects I have) or I have to create a SaveData script for each object?
I have a very specific question, would this system support serializing scriptable objects or do I need to create a surrogate for those as well?
good but can i use binary format file ,to be stored in database like Mysql or Mongodb , so the player can keep his game persistent despite changing the devices , which file format and database do you recommend
Nice! Thank you 👍
Thank you very match!!! Very useful! Great work!!!!
wow I'm so confused , where did you get GameEvents.current.dispatchLoadevent ?
When SaveData.current can't be assigned a value because it's read only just add the following below the body of the get statement in the SaveData class's singleton: set { _current = value; }
It worked for me... I think😊
Hey, would you mind helping? I am getting a non instance of object, when using the current.profile.characterName. I am not sure how this is null? How does one set data then?
@@CyberStudios if characterName is a string, try setting it equal to "" in the player data class.
At 4:44 you've got a few functions recording the data based on a button press. If I have a bunch of thing I need to keep track of (like what what the player's stats are, what's in their inventory list, what story triggers they've been through etc.) would I need to use separate functions for all those things? I kind of just want to save everything about the player all at once (my game is text based).
This is what the GameData class is for. As discussed in the video. If you put everything you need to save in a single serialised class such as GameData you can just save that GameData class.
If you've got classes all over the place with data you need to save, I would either refactor it so the saved data is in one place OR write methods to call to those classes and pass the data on save/load accordingly.
@@GameDevGuide Okay thanks that makes sense!
Great tutorial! could you please upload the project or post the link if it's already uploaded ?
"If you found anything useful in the video"
Me: All of it!!.
Playerprefs starts to become a real mess, real fast. It's like that draw or cupboard you have in your house, you know, the one full of junk that you don't even want to spend more than 20 seconds looking in LOL.
Amazing tutorial, thank you!
Hi i'm getting an error when i try to implement this code (first half of the video)
I get a "NullReferenceException: object reference not set to an instance of an object"
when i try to refer to the save data.
So im trying to add to the save data:
SaveData.current.profile.partyNames.Add("Blah");
but i get that error. do i need to do something like, resources.load or have the SaveData script attached to something and referance that object? Im not sure if ive missed something in your video or?
Cheers
I have no idea what i've done wrong or what he's done that he's not shown. I've followed his code exactly up to the 5 minute mark. Did anyone else have this issue?
I just cant seem to access the data, for example:
SaveData.current.profile.currency -= 200;
results in the error i've mentioned above. So is he referancing the class in some way he's not shown or what? is that code he's doing in a specific script? (PlayerProfile, SaveData, SerilizedManager)
does anyone know whats happening here as im pulling my hair out trying to get it to work.
@@Rorymclean12 got the same issue with SaveData.current.profile.characterSelection = PlayerPrefs.GetInt("CharacterSelected", characterSelection);
public void OnLoadGame()
{
SaveData.current = (SaveData)SerializationManager.Load(Application.persistentDataPath + "/saves/Save.save");
}
This line gives out an error when I put it in any script and says can't assign current cause its read only? can you help me with that?
I did get rid of the error by adding a set method after get so setting current = value;
not sure if this is the correct way of doing it but it got rid of the error.
hello, I have a GTA style project. I am looking for the Save Load system, you have made the purchase part in the save load window you wrote, but I want the player to continue from where it left off by pressing the Load button registered in the load section. What kind of way should I follow?
hey! wait, is It going to work even for mobile game?
DUDE, YOU ARE AWESOME!!!
I feel like these serialization surrogates are harder then it should be. Looking at it, it makes sense, but you can just as well store a Vector3 as 3 separate floats without this surrogate method, imo that's faster and easier to read.
I feel ignorant, but can you include a link to these files, I somehow cannot follow which script and which place you are entering these codes. I'm learning C# "by ear" if you will, and tailoring it to fit my Classes... I get how things are linking, but I'm not finding how you linked them to the buttons, and I can't tell which object to toss the script on. Very great video, just hard to follow somehow... just me I'm sure... ADHD and sleep deprivation from work aren't helping.
I am confused, at 3:32 you created the SaveData as a singleton, with _current, but after, at 4:54 at current can be assigned, 5:37, _current no longer exists. :?
If you were to do an open world save system, how would you save/load/unload data with additive scene loading? Would you add an int for the scene index of each object and only load if the matching scene is loaded? Would the save function work modularly?
So, I would keep the game state data independent from any scene. That way all the save data for your game would be serialised no matter what scene you're in. But, if you need to serialise chunks of data for each scene, such as object positions, or specific world changes, etc.. you could create a list of game data classes and save/load each item in that list for each scene index. When a scene loads, you could query the master game state and ask for the save data for that scene.
Game Dev Guide I’m not sure I completely understand. So if I had scene A and B and I wanted to save scene A’s data list when I move to scene B, would I save scene A’s list, load and delete scene B’s list and then save scene B’s list when I need to?
Or would I only save scene At list then load scene B’s list and then save it when I need to? Would it automatically overwrite or just add onto the previously saved scene B list?
Perhaps a video would help me more, I’m having trouble working this out in my head 😅
@@CamNicPet CamNicPet Everything you need to know is already covered in this video in regards to saving and loading classes. But, it sounds like you're unsure how references and lists/arrays work.
I'll try to clarify, my approach to this I would be to have a Game Data class that holds all of the data in my game I want to save. This would not be tied to any scene, which means that it can be accessed anywhere and hold all of the data for your game. (This is shown in the video)
Inside my GameData class, I would probably have a list/array of a LevelData class which would hold level specific data I need to store.
Any scene I have in my game would require a reference to a LevelData class. So, when I load a scene, I just get the coresponding LevelData class from the list of them in my GameData class.
If I were to reference and retrieve the LevelData from my GameData class, any changes I make to the LevelData when my scene is loaded would actually be made in the GameData class due to it being a reference.
So when I save my GameData Class, it saves all of my level data too.
Thank you so much! You've saved my life (literally, but also a joke ;-;)
LOVE THIS!
How did you assign functions to save and load button? cuz you didn't show it in the video
thx im making a game with a complex level building system so i need to save a lot of data :)
What exactly makes a data type not serializable? Aren't they all just collections of data stored in memory? Wouldn't elements be stored/accessed in a particular order anyway?
It tells me that The name 'loadArea' does not exist in the current context. But I can't seem to see any reference to a "loadArea" in the SaveManager script in the video. Is there a reference? if so what is the reference?
Quick Question. How do you find out what all these terms mean?
If I make an inventory system in the game will it save the things in the inventory?
Holy shit I got it working!
Thank you!!
Question, how do I get the load buttons to display the save data information rather than just the name?
hello. will this work when developing a console game. for example would this save system work when building an xbox game? Thanks