 So cool. We have our backups and our saves Okay, so let's open it up. It should look something like this Hello guys crypto grounds here. Welcome back to another unity C sharp idle game tutorial video this episode 35 tanker me Improving our current save system If you enjoyed this video, make sure you smash that like button leave your suggestions and your advice and all that Good stuff in the comments below subscribe if you're new and turn on notifications for all my future videos And to check out my other videos in this top corner right there. You'll find a lot of helpful stuff also just a heads up I have like 70 more videos planned out like not recorded But like I have a list of videos to do so I got lots of stuff I need to do so if you think I'm running out of content you're completely mistaken I got lots of stuff to teach lots of stuff to show and Some of that stuff in the 70s includes like special videos like 1,000 subscribers or 2,000 subscribers special 3,000 subscriber specials like here. I'll show you my list So you see I have like a huge list huge list. I got like a gameplay series I got extra coding tutorials extra unity tutorials. So here I have I'm gonna continue the adventure capitalist series I'm gonna do 2,000 subscribers gonna be adventure communists 3,000 is gonna be turn-based games such like an R basic RPG game 4k tap Titans 5k idle minor tycoon 6k idle merge games So such as like scrap clicker 2 7k make a game based on like comment section So this be kind of like a special one So maybe I'll do like a 6 or 7.5 k where I get to choose Like everyone gets to choose what I get to do with the game next for like 10 episodes and see how it turns out 8k farming games 9k crafting game 10k crypto clickers and five patreon's anti-matter dimensions I will be any at any moment when I hit five patreon's I will do an anti-matter dimension series and I'm currently on two patreon So if you want to help me out Links in the links in the description. I have my idle idle game series and yes so far. I have planned up to episode 50 Crash course. I have planned up to like episode 42 and clicker heroes. I'm gonna continue that as well So improving our safe system. What is that gonna look like? Well In our previous safe system there was kind of a bit of issue I guess we could have we couldn't properly save lists and We yeah, we couldn't save lists arrays were kind of hard to manage like to create new rays to adjust them It was kind of it was kind of an hassle So this should fix all of it and we aren't gonna be saving in json anymore We're just gonna be we're using binary formatter. So basically we're converting it to a binary like format or like where it took a bunch of If you've seen those weird windows in or those weird symbols and like a dot exe it kind of looks something like that But it's not completely encrypted and the thing is that it won't work with the export system So we got to convert that with base 64 and simple a yes, which is what we've been doing in this Previous system just not in json anymore. All right. So let's hop into our save system script Okay, so we still have our player data Class right so We're gonna keep this of course now the cool thing with the save system is that we can create multiple Classes so you can have some dedicated to like For example earth Mars you can have some different classes dedicated to that specifically which is going to be really cool Now I'll show you how we manage that Okay, and in this full reset system this can also all moved to the player data Constructor because what we can do is if we want a full reset. Let's hear. Let's do this real quick. So let's grab our full reset Full reset. Where is it right here? So instead of doing data dot full reset? We can just do data equals data or Our data equals new player data. Okay now this basically just creates a whole brand new player data project or Object with these parameters right here our defaults, right? So instead of doing that full reset method We can just do it in the constructor itself. Okay, so there's a lot of blue lines going here. So I'm gonna kind of just like Enhanced things are replacing the with stuff placing all this Replacing all these are I cannot speak I'm more remater again But replacing all these blue lines stuff with bar because these are already kind of predefined objects All right, or the code already knows what type it is so we can just replace it with bar Just what I'm doing right now Fundamentally nothing really is changing in our save system However, the issue with upgrading this is that if you've already released your game for some reason or for whatever reason The saves are gonna be different, okay So everyone's gonna lose their data because we aren't using JSON anymore JSON I feel like it's it'll take too much data, I guess and there's some benefits to not saving to JSON Basically here. I'll explain how things work after I start writing things out. Okay, so let's see What do we have here? We have our create file load player convert import Okay, let's just ignore these for now Clear fields ignore that for now. We really need to focus on we can get rid of create file Create get rid of that and honestly, let's just restart and scratch I Think that's the most appropriate thing to do Okay so in our save path We're gonna create a different like We're gonna do something different. Okay So I can't exactly like always remember that the top what I need to do because it's kind of hard to memorize everything But I'm looking at my other save system here that I created It took me quite a bit to do so I'm trying to find it Okay, so what we're gonna do is our safe path is going to be application dot What is it? resistant data path and we're gonna add a plus Saves okay, so we're save all of our normal saves in this folder, right? So now this is where having numerous saves comes to play We can have different save files in here instead of having numerous ones We can just have one And also this will make it easier to export some code or like our data is that we could export a certain like Like for example or earth like let's say there's something wrong with earth And I only need the earth you can just send or the person you're you only need to know what's wrong with the earth You can just export this earth. You can debug it. So just like that. Okay So this is mirror save path a safe path backup is gonna be the same thing, but it's gonna be backups, okay So we're gonna be saving to both saves and backups, okay, also another thing I I believe This is much safer Than to do what we've been previously doing and we shouldn't get any more of those sharing violation errors anymore because This isn't much more properly done All right, so let's start with our Public static void save our save player. Okay, so a few things we're gonna do differently is we need to Add a type Okay t t Data we're just gonna call this data and we need to add a key now This key is the file name so we can actually just call this file name or no not not file name It's just gonna be key or name name. That's fine Okay Now so why do we have this here? It's for when we call it when we in our script. We do this save System dot save player see it ask for a type now We can just put player data and then do Player data as the type and then our this would be Let's see now again. We're not in our main script So let's actually move this to our main script here for example Whereas our save save so it would be player data and then data and then our file like with the data we want to do Or the name of it is going to be called. I don't know player data Now you you can call this like if you do different planets like earth mars You can call this earth and then you can have like a an earth class Okay to organize some things and now you see this is grayed out. This is redundant So you can just get rid of that, but this also kind of helps It's like show you what kind of Object this is so what the type is But this will do okay And what happens if we get rid of this then we can't use the generic type, which is what t is Okay, so we have to have this in here Okay, so we can we can keep this in here honestly and get rid of this because we're going to use it in anyways So save system dot save player data colon comma, why did I say colon? I was like, wait, did I say colon or comma? Okay comma player data Um Yeah, that should be good Oh, we also have another Wait, is this load? Oh, this is load player. Okay. Yeah, so this will be our load player Uh, we will get to that But our save player right here will be this Okay Okay, so what we need to do now is create a folder or a directory and we do directory dot create directory and we have our Save path. Okay. So now we're just creating a new folder if it doesn't exist already Okay And now we're going to start um writing step to the file. So we're going to do using stream Stream writer Writer is equal to and also this can be var. But we're just going to create it first new stream writer and this is just our Um, our path right here our stream. Where is this going to and that will be save path plus name Plus dot text. Okay. So remember this Player data now it will be called player data dot text. Okay dot txt Okay, and we can make this a var All right. So now we need to create a A binary formatter Equals a new binary formatter and again, that's going to be var We need to create a memory stream. So we're just going to call this ms or memory stream Is going to be equal to new memory stream And now we need to serialize our data our data right here. So we do formatter No formatter dot deserialize and serialize memory stream And our data Okay, so now we have serialized our uh data into memory stream. We can now Uh convert it to simply a yes or encrypt it. Well, we want to do um base 64 first or however you want to encrypt it you can include that if you want to or not But we're going to include it anyways, okay So we're going to do var data to write and this is going to be a string This is going to be equal to simple a yes dot encrypt Encrypt string is encrypt string. Why is it not showing up? Oh, yeah, okay. That was weird. It wasn't showing up. So encrypt string Uh convert dot to base 64 to um to base 64 string Uh ms or memory stream to array And we're going to encrypt this key Just like that. We're missing something. What's wrong? Okay, I guess I had to make encrypt string static Okay, I might as well make decrypt string static as well. Okay, so I guess that's what I was suggesting earlier So make sure you're encrypt string and you decrypt string I need to take off these I need to take these out for tutorials because it's it's kind of difficult to talk because there's something in my mouth all the time Um, but yeah, so we need to make both of these static in order to use it. Um, wherever Uh, okay, so we're done. Oh wait. No, we're not We're going to do writer dot write line data to write now We have successfully converted everything to base 64 And that's a well a base 64 string And then we encrypted it with simple aes with our encrypt key which we've created in the past This can be marked as private We don't even I don't even think we need this jason anymore. I don't we'll see So we have our save player, but we haven't done our save backup yet. Okay, so let's see. We have our backup count here Uh, let's add it Add one every time Okay, so now let's just have an if statement if backup count Uh mod four Equals zero so every five times we're going to save it to both the backup and saves Okay, or no, we can just do backups only just in case the backup saved corrupts, but the save one doesn't So, um, yeah, we're gonna have this if or this else statement here Okay, and basically it's the same thing as here Except we are replacing the save path with their save back path backup. Okay So now we can simplify this Okay, so let's just create a method here called void save Okay, now we need our string path What else do we need we need our No, we don't need data. We just need the path. All right Yep, that looks correct to me. So now we have our void to save Um, string path right here. All we need to do here is this in this if l statement. We can just do save Uh, so normally it would go to save path Okay Otherwise if it's we're doing on a backup save, it'll just save to our backup Okay, and we can simplify this to a question mark operator so save backup Uh backup mod four equals zero question mark if it's true If it's every five times if it's true, then we're going to do our backup. Otherwise, we're going to do the regular save There we go. That's our save player Now we need to do the void or we need to do load player Okay, so before we continue, this is not void. We are loading a data type. Okay, so we're going to replace this with t we're going to add Uh generic type t here and our key will be the path or the file name. Okay And this will be name Okay, so this is very similar to Um, kind of what we've done here with the using except we're using streamwriter instead. Okay So we're going to create a directory as well just in case it doesn't exist Uh, also we should create a we need to create our backup directory to I forgot about that So make sure you create a backup directory Okay Um, all right. So now we need to create a generic type real quick. We're just going to call this uh return value Okay, now we're going to be uh setting. Okay, we're going to be returning t type t again. This is the generic type. Okay So in here we're going to be using uh var reader equals new stream reader And it's the same path here. Okay, so we will have this same backup Okay, but for now we're just going to copy and paste this And use the regular save path and then we'll develop into our Safe thing and basically we're only going to load the backup if the safe if the normal one doesn't exist Or if it's corrupted or if something's wrong with it. Okay, and we can do this by doing try catch Okay, and I'll do that. Additionally, we're going to create a formatter Okay, and we need to do, uh We're going to create another string variable called data to read and we're going to do reader dot Read to end. So basically it's going to read the entire file and set it to the string And we need to create a memory stream var memory stream Is equal to a new memory stream Okay, now we're going to convert our string From we're going to decrypt it. We're going to decrypt the a s because that's like the final layer And then we're going to convert it from base 64 back to stream and then we're going to uh decrypt that. Okay We're going to deserialize that Okay, so we're going to convert dot from base string Okay, so what we're going to do first of all, let's just start with the simple a yes, okay So we're going to do simple a yes dot decrypt string and this will be our data to read And our encrypt key Okay, so we have our simple a yes now we need to convert this base 64 string into a normal string A deserializable string Um, okay So we do convert dot from base 64 string And then we have that go around the simple a s e uh dot decrypt string And there we go. We should be good Okay, so now we're going to try catch here Now we can get rid of this exception because we don't really need to throw these errors Okay, so now what we're going to do is we're going to set return value equal to um formatter dot Deserialize memory stream Okay, so now the issue here is that it doesn't know what type it is right So we need to cast this as type t or generic. Okay So now what if this doesn't work? Okay, we're going to set return value Equal to default so basically this what it does is that it takes whatever class it is And it sets it equal to the default which is for player data. This is our default right here. Okay And now at the end we need to return Uh return value And there we go. So now we need to get our backup save or our backup system to work so what we can do here is Now I think I might as well just call a different method I think I have an idea Because I don't want to call this inside reader because Readers open and that will call that will cause a sharing violation. So we need to have it do it afterwards Okay, so let's have a bull Uh Let's just do backup needed We're going to set equal to false Okay, and we're going to set Backup needed equal to true Okay, so if backup needed is true Then we're going to do this all over again except with the backup path the save backup Okay, and now We're going to do We're going to get rid of that and we're just going to return this as a default again Okay So basically If this backup is needed then we're going to do this again, but with the save backup the save path backup and We can honestly get rid of this return value right here Oh, we might actually need it Shoot, okay. I thought this would solve it Or maybe this will and then we can get rid of this No Okay Okay, well, this is pretty lengthy I'm sure we can shorten this If we create this into a method this will kind of cause an issue Um, okay, let's do this Let's convert this into Void load And again, we only need our path string path Okay, and now in here We're going to do backup needed again for both because honestly, I'd rather have shorter code So if the backup's needed then we're going to do load Mac up needed No, no, no, no, it's backup path Okay, and then otherwise originally we're just going to do Save path, okay Okay, this should be good. So first it'll try the regular save path and then we'll do our backup path Yeah, that's much shorter And then we'll return that Okay, so we have our save and load player. So let's get this load player into the actual script So again, we need in here we need our uh player data And in here we just need the key. So which is player data Cool. Now you see we do need this because we don't specify a type in like as a parameter unlike we do for save right here so, yeah This is needed And it's not needed for our save but If you want to see what type this is then you can just add it for quality of life But I prefer not to see grays. So I just get rid of it and I know data as player is type player data. So okay Now we need to do our our devil Well, let's okay. So it doesn't look like we need this We need to do export and import Okay, so this shouldn't be too bad. We're just going to be um Basically just calling this load player from import player With the string, okay So I haven't done this in this script yet. So I'm gonna give it a shot But I believe we're gonna use uh var reader equals new stream reader The thing is that is is this a stream reader in here? Yeah, so we're using a stream reader inside of a stream reader. Okay. Well, that's an issue Uh I hate doing this and I guess Well, one actually well, we're not reading from a path Okay I think I have an idea. I think we should just copy this right here and Do this. Okay So import. We don't need this We need a string path No, not path Well, you see here It seems here. We're gonna be having multiple say an import button. So we can have a string path here Or actually, you know what let's do int id and what we can do Is have uh a switch id. I mean we only have two So let's just create this and then I can shorten it. So if it's zero, then we're gonna be using Var save Uh Var path equals empty string And we'll set path equal to save path break Case one path is equal to backup And break and again, it's probably gonna ask us the shortness No Okay, well, I I guess that's fine Because we can expand this if you have more Save paths. Actually, no, we don't need this backup path. Okay So this is really used if you have more than one save path Like if you have one for earth if you have one for mars Something like that. So we only have one So let's just keep it simple even though we can simplify this with just an ifs with an ifl statement But this can be easily expanded. So just know I'm gonna keep it here for you to expand on it. If if you don't need it convert it to an if statement It's just simple as that Like that. Okay So now we need to use our path here Yeah, so we have path. Okay. Yeah We create a formatter Data to read No, but we're doing okay, we're doing this or no This is like I think this is more like a save player rather than A load player now that I'm thinking about it Okay, so we have our path we write our okay, so we need our data data Okay, I think this is what I was like kind of wanting to figure out instead instead of saving So we have our We have our string here, right? So Yeah, all we need to do is import the string So let's see. Where's this import value dot text? I think that's it right here We just need to do we don't even need to serialize this We just need to do yeah, because we already do this data to write Because it's already encrypted I think this is all we need to do in our In our streamwriter. I'm guessing So I'm guessing this is all we need to do for import player Export that's just that's just the the load That's the load player. All right, except we're exporting it So actually we can do Okay, yeah, we still need to do this type thing here. It's like here. Let's just copy paste this Um We're gonna have this bull backup need it again We're not gonna return anything We don't need to deserialize anything We just need to read this Yeah, we just need this right here var data to read Okay, so what we can do is try catch this here And if it doesn't exist and then we are just going to Um Set this to true Okay In our data to read, where is this? Oh, it's a variable. Oh, I see. Well, we can just create a string right here Okay And at the end of this we can return This is oh, no, no, no, we don't we don't want to do that. We want to do export Value dot text is equal to data dot read or data to read. Oh my gosh. This is this is This is a crap load of stuff to do we can get rid of this exception too Okay, I think we're done I hope So again, all of our data should be cleared wiped and this should be brand new Better than ever This was a lot. I mean I should have done this beforehand So I know I was doing but hey, we all learn something new every day So let's see how this works Offline manager I don't even use offline manager Yeah, what did I do with offline manager? Uh, shoot. Okay. Well, hold on. Let me pull up github Okay, I see what I did in our save We need to add Well, this is kind of an issue here because offline progress check is not in every single type, right? Okay, I feel like if data is player data Then Okay, well what I'm going to do here. I'm going to do this inside I'm going to do this out here So when we save I'm going to do data dot offline progress check. You will show. Okay. That's just the same thing And this can honestly be done Uh, where are we? Where is our save system? I like lost it. But what happened? Okay Um, right here. We can honestly do this offline time Some more else, but it's not going to matter because it's not like we're doing it in a class or we're not changing a variable in an object So I guess that doesn't really matter Okay So one more thing we need to do we need to check if this file actually exists. Okay So this is a simple bool. So we're just going to create a public static bool Save exists And this is going to be a string key And basically our var path is going to be equal to um Our save path. Oh, yeah, we're just going to do We're going to try catch this so we're going to try So basically we're going to set path equal to uh save path plus key Like this right here Okay, and then we're going to check to see um Yeah, let's create a bool our var Exits equals false Okay, now we're going to do here is we're going to set it to equals file dot exists or file exists File dot exists We can honestly just not do this in a try catch, but what might as well Let's not do this in a try catch. This is unnecessary So we're basically in here. We're going to do if Exits is false Then we're going to check We're going to do the backup one now And then we're going to return the actual result if a save exists Actually, you know what? I think we're checking for the actual save. So we're just not going to do this right here Okay, this can be done here. You're going to that Um, all right. So if save exists, we're doing that Okay, so now this is where we use save system. So we're going to go back to where we load our data Let's see. Where is that load okay, so now what we're going to do is save system dot save exists question mark if it does exist Player data it's our keys our file name if it's true, then we're going to load our player. Otherwise, we're just going to do a new player data and let's just do data equals Okay, now the reason why did data equal first of all because save system dot load player is returning t the generic type Which is whatever we put in player data, for example and If we just do this right here, it's like that it's not going to do it. It won't give you an error But it's not going to do anything. It's not setting anything equal to You know if we do data that if we do data equals save system dot load player Player data player data Then it'll work. Okay. So otherwise if it doesn't exist and we're just going to create a new player data object Got it. That's all we need to do there And I think we're good to go. So let's check this out We need to kind of Adjust our Let's see We need to go to settings Our import It's the import right here missing save system It's a save system Import player into this is zero Export player. Yep, we're good. Okay. So let's just try this out. See if it works Okay, we should be error free. No, we got some errors. Okay. Well, that's not good Uh What oh I see what we did wrong Save system I think this is because it's mono behavior. Is that really why? Since when was application dot persistent date data path What Since when was this not allowed in mono behavior? Call it in awake or start instead What I have never oh, I think I see why is it this I think it's whenever we access it. I see I think that makes sense Okay, so we gotta make we're gonna make this a property by adding the arrow See if you hover over this it's a property and this is a field. Okay, so the difference between our field Is we're setting something initially While a property is something that is already defined like this. So this is a property. This is a field. Okay So, okay, this should work now error free. Hopefully cross our fingers Oh, we're error free. Okay. So now let's go find our Let's go find it Okay, so we're here. It's in a local disc users username eight app data Local low default company or whatever your company name is what you should have done in like your player settings And your project name. So cool. We have our backups and our saves Okay, so let's open it up. It should look something like this See, this is much smaller than what it used to be. This is actually pretty small Now I let's see. Can I grab? Okay. So here let's compare. So it looks like it's a bit bigger. Let's open this Uh, oh, it is a bit bigger, but that's okay. It's okay if it's a bit bigger now Again, this is more efficient. You can do much more with this. So I guess it's an upgrade in a way But this is bigger sadly, but it's okay So we have our saves and we have our backups very and cool And our back or Our saves and backups should be the same Cool. So now let's start playing Uh, here's my some upgrades Let's get some achievements in Okay Now we got some stuff let it save. So let's see. Let's where is our main game right here When is it saving? Okay, so it just saved now we should load in correctly Cool We did it So let's see. Did our upgrade save? Yep. Cool. So now we know that the system can definitely works I want to kind of sort I want to try to shorten this real quick if it if I don't then I'm just going to skip this Okay, so yeah, I looked I don't see a really Like an easy way around this. So let's see. We can delete some of this stuff. We can delete offline We can make this private Private Cool And yeah, this is we don't we don't use this. So in summary, I will show you what I have so far If you're in a rush, what's this? Okay, so, oh my gosh, we have a bunch of stuff Yeah, we're getting rid of this Okay, so we have our simple aes class right here. This is what it looks like I will be sure to provide this in the comments below. So just make sure all you gotta do is change encrypt key Change the init vector Change the Customize your Your path names make sure you replace the save systems here Okay, so I highly suggest you to watch this entire video just so you understand how this works Okay, here we go Anyways, if you enjoyed this video, make sure you smash that like button Leave your comments below subscribe my channel if you're new and turn on those notifications So you get notified for every single video It helps me and liking the video and subscribing and all that good stuff helps me a lot as well And I very appreciate it. Anyways, thank you for watching. Have a good day or night