Save & Load System in Unity - Bug Fixes, Scriptable Objects, Deleting Data, Backup Files, and More

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone my name's trevor and in this video i'm going to wrap up the other save and load system tutorials by addressing some bug fixes answering some frequently asked questions and adding a couple of things to the system to give some extra polish and reliability i organized this video by time stamps where each time stamp is going to be mostly independent from the others in the video so feel free to skip timestamps that you're not interested in of course thank you to everyone who's provided improvement recommendations clarified information or helped find and fix bugs from the previous tutorials in this series as many of the topics in this video come from discussions on my discord server or from the youtube comments in one way or another and as always you can find everything we're going to do on the github project which will be linked in the description of this video the first bug fix comes from the first video in the series on creating the save and load system itself i had a misunderstanding of how c sharp passes parameters by reference that i want to clear up in that video we passed around the game data using the ref keyword which we actually don't need to do at all because in c-sharp objects are automatically passed by reference furthermore by using the ref keyword it actually makes the game data object a bit more vulnerable than we need it to be if you're interested in learning more about the ref keyword and why this can be an issue i'll put a link to what i thought was a really good resource in the description of this video that covers the ref keyword in more detail and why we typically shouldn't use it to pass around objects in c sharp so while this won't necessarily break anything within the save and load system i do recommend removing the ref keyword entirely from the idata persistence interface and likewise from our data persistence manager in the save game method and finally in the save data method for each script that implements the idata persistence interface and we'll see that everything still works fine without the ref keyword the next bug fix i want to address comes from the second video in the series on saving and loading data across different scenes in that video we use some unity built-in events called scene loaded and seen unloaded to orchestrate how we load and save the game there's an issue with saving using the scene unloaded event though because in single mode scene loading the scene unloaded event actually fires after the previous scene has been destroyed so if we try to save our game there like i suggested in that video our system will try to save data for a bunch of scripts that have already been destroyed which will result in some missing reference exceptions this worked fine for what was shown in that video because our main menu scene didn't have any other scripts that needed to save or load data but as you could imagine if we want to transition from our gameplay scene to any other scene or maybe we do want to persist some data in our main menu scene we'll eventually run into this issue so in conclusion i wouldn't recommend saving the game using the scene unloaded event like we did in that previous tutorial because that event fires after the scene has been destroyed and instead we want to save the game before the scene gets destroyed we can do this by saving the game any time before we load a scene and thus the game will save before the current scene is destroyed rather than after so for our current system in the main menu scripts continue button on click method we'll add a call to save game there right before the load scene async call and then in the safe slots menu script in the save slot on click method we'll add another call to save game there and of course we should remove the scene unloaded event and the on-scene unloaded method entirely from the data persistence manager so that the game no longer tries to save after the scene has been destroyed and just to show that this now works i added some logic to go back to the main menu when we press the escape button on the keyboard if we were to play this before these changes we'd get some missing reference exception errors when trying to transition from the gameplay scene however now that we're saving the scene before the scene gets destroyed rather than after everything works fine when we transition scenes and the game saves properly in between scene transitions the next fix i want to go over comes from the third video in the series on creating save slots to handle multiple saved games in that video i suggested that we needed to set the current selected button in the event system using a co routine because otherwise the highlighting of that button would get screwed up but instead of using the event system to select that button we can use a method on the button itself called select which seems to work just as well and lets us get rid of that coroutine method so in the menu script we can change this using unity engine.event system statement to using unityengine.ui then we'll change the first selected variable to be a button instead of a game object and then in on enable instead of starting a co routine here we'll just call a method called set first selected and then pass in that button then we'll turn this coroutine method into a normal method by having it return void changing the parameter to b of type button and then rename the parameter and then simply call first selectedbutton.select and we'll also now need to pass in a button anytime we call this method so in the save slots menu script we can add a line to get the button component and then right below that instead of starting a co routine we'll just call the set first selected method directly and then pass in that button instead of the game object then back in unity we'll have to hook things back up by dragging in the first selected buttons we want each menu to start out on so for the main menu we'll set the first selected button to be the new game button and for the save slots menu we'll set it to be the first save slot and now if we play this we can navigate around between our main menu and save slots menu and we'll see that the first selected menu buttons are being selected appropriately the next thing i want to cover is a frequently asked question i've gotten about saving and loading game objects that are inactive or in other words are disabled in the scene hierarchy currently in the data persistence manager when we go to gather the list of i data persistence objects in the scene to be saved and loaded we use this link query here in the find all data persistence objects method to initialize that list the find objects of type method by default will only find objects in the scene that are active so for example for this coin in our scene that we've disabled the find objects of type method will no longer find that coin and hence our system will no longer be saving and loading data for that coin luckily the find objects of type method has an optional parameter we can pass it to detect inactive game objects so we just need to add that as true and then our query will find inactive game objects as well adding them to the idata persistence list and hence allowing us to save and load them next i've gotten a good amount of questions around saving and loading data that's stored in scriptable objects i will say that i'm personally not the most experienced with scriptable objects so take everything i'm going to say with a grain of salt but i did do quite a bit of research into this subject when helping other people troubleshoot and i thought it might be helpful to include a short section in this video on some of the things that i've learned about scriptable objects regarding this save and load system if you're not sure what a scriptable object is i'm not going to cover that in this video but i will include some resources that i found useful in the video's description anyways the first key point we should consider when persisting data from scriptable objects is to ask ourselves if we really need to or not by design scriptable objects seem to be best when storing static data that is we might play around with and fine-tune that data during development however that data would remain constant throughout the actual game in many cases state data meaning data that's going to change to keep track of some state that we need to persist in our save and load system seems to be usually better off stored in a mono behavior that's using that scriptable object rather than in the scriptable object itself with that said there are so many use cases for scriptable objects and i don't doubt that there are going to be cases where using them for state-related data might be a good idea however if you're finding yourself in the situation where you need to persist data from a scriptable object i would at least ask the question if it's more appropriate to let a monobehavior handle that state data and let your scriptable object only worry about static data the second key point we should consider when dealing with scriptable objects is that the data stored in them persists between playthroughs only if you're playing the game using the unity editor that means if you actually create a build and play that the data will no longer persist between playthroughs which is by design for scriptable objects this is important to keep in mind when troubleshooting because if you're only working with these in the unity editor you might be getting false positives when trying to persist related data with the save and load system and the third key point we need to consider is that scriptable objects are meant to be serializable by unity itself and for that reason they won't work directly with other methods of serialization such as the json utility that we're using so while you might think that we could just add a scriptable object to our game data that won't work instead what we can do is create another c-sharp class to mirror the data that we need to persist with our save and load system and then move that data between that class and the scriptable object when we save and load the game using a mono behavior for a quick example of this let's say we're storing player attributes like vitality strength and so on in a scriptable object which are expected to change as the game progresses we can create a new c-sharp script called attributes data to mirror the data that we want to persist from that scriptable object and in there we'll remove mono behavior add system.serializable and then add fields to mimic our scriptable object for the data that we want to persist as well as a constructor for what we want these fields to initialize to when we start a new game then in our game data class we can add that attributes data object and initialize it in the constructor there as well now in a mono behavior that's managing that scriptable object in this case we're just using our character controller and we can see the scriptable object here we'd implement the i data persistence interface as usual and then add the save and load methods when we load the game we'll want to take the values from our game data attributes data object and then set them on our scriptable object and likewise when we save the game we'll want to take the values in the scriptable object and then set them in our gamedata attributes data object as we can see here the attributes data class is acting as a proxy for persisting the scriptable object's data when we save and we're using that persistent information to set what the values should be in the scriptable object asset when we load the game and just to show that this is working really quick we can see that our scriptable object on the right here has all zeroes but when we play the game we'll see that it becomes all ones based on the values we put in the attributes data constructor but if we change the vitality to 5 and then exit play mode so that the game saves we can take a look at our data file to see that the vitality attribute is being saved as a five then no matter what the value is in our scriptable object so we'll change it back to a zero and then play the game we'll see that the data being stored in our data file is being used for the scriptable object just like we wanted so in summary when saving and loading data from scriptable objects first consider if the state data that we're storing in that scriptable object would be better handled by a mono behavior instead second keep in mind that data stored in scriptable objects will persist through playthroughs in the unity editor but won't persist that way in an actual build and third when saving data from scriptable objects it can't be done directly because of how they serialize but it can be done by moving that data to and from a serializable c-sharp object that mirrors the data that we want to store for that scriptable object next another question i've gotten pretty frequently is how to delete data through the game for a specific save slot just to note the player can already override a save slot by starting a new game with that save slot so it is worth considering if allowing the player to delete data is necessary or not for your game with that said many games do have this feature so if it's something you want to include let's jump into it by first adding some code to delete data for a specific profile id in the file data handler class we'll create a new method called delete that will take in a string for the profile id to be deleted first as kind of a defensive programming base case if the profile id comes in as null we'll return right away next we'll create the full path to the data file using path dot combine to combine the directory where the data lives with the profile id and then finally with the actual data file name then in a try catch block before we go to delete anything it's a good idea to make sure that data file actually exists this just helps mitigate if the full path ends up being something other than our data file for some reason so we don't accidentally delete a directory in our file system that's not our profile data so as long as that file exists at that path we'll delete the entire profile directory using directory.delete and then passing in path.getdirectoryname for the full path then we'll also add the second parameter as true which indicates that we should delete everything within that directory recursively of course if deleting an entire directory and the file system worries you at all you could alternatively only delete the data file using the file.delete method instead next it would be a good idea to add an else statement here and log a warning to let ourselves know that we tried to delete data but the data didn't exist and last we'll log in error if we caught an exception during this block to let ourselves know something went wrong when deleting the data then in the data persistence manager class we'll create a public method called delete profile data which takes in a string for the profile id to be deleted then we'll call the method we just created in our data handler but that's not all we'd want to do here since our data persistence manager initializes its selected profile id on startup and we might have just deleted that we'll want to initialize that selected profile id again and then reload the game so that the game data in the data persistence manager matches the selected profile id so we'll create a private method called initialize selected profile id then in the data persistence managers awake method we'll take this logic that's initializing the selected profile id cut it call that initialize selected profile id method in its place and then paste it into the initialize selected profile id method now that does it for the code needed to delete data for a profile so next we'll want to add a user interface that calls this code back in unity we'll disable the main menu and then enable the save slots menu in the scene hierarchy so that we can see the save slots menu while we work on it while there are a lot of ways we could go about this we're going to keep it really simple and just create a clear button to put next to each save slot we can duplicate the back button using control plus d on windows and then rename the duplicated object to clear button we'll move it up next to the first save slot in the scene rename the text to say clear in all caps and then change the size of it a width of 200 and height of 150 seem to be good and then for right now we'll remove the on click listener as well so that it doesn't confuse us later and to make it easier to modify later on we'll drag this clear button into the prefabs folder of the project to make it a prefab then we can duplicate it in the scene hierarchy creating four of them one for each save slot and then position them accordingly next let's add some logic to only show the clear button if there is data that exists for that save slot in the safe slot script we'll add a serialized field private button variable for the clear button that corresponds to that save slot then in the set data method when there isn't data we'll set the clear button game object to be inactive and when there is data we'll set it to be active and we'll also set the clear button to be interactable or not when we set that for the save slot by adding this line here then in the save slots menu script we'll add the method that will get called when we click the clear button called on clear clicked which will take in a save slot as a parameter in here we'll just call the data persistence manager delete profile data method passing in the profile id for the save slot that's passed into this function and we actually want to refresh the menu as well so that the save slot menu shows that the data has been deleted once we press the clear button which we can do by calling activate menu now back in unity let's first drag in the corresponding clear button for each of these save slots in our save slot script then for each clear button we'll need to create an on click listener drag in the save slots menu game object from the scene hierarchy into this slot here select the on clear clicked method and then finally drag in the save slot that this clear button corresponds to and of course we'll do this for each clear button making sure that we're linking up each clear button with the correct save slot finally we can disable the save slots menu enable the main menu and then enter play mode to see if this is working we can see that in the save slots menu we have a clear button for the save slot that contains data and if we click it it clears the saved data and refreshes our menu to reflect that but you'll notice that if we go back to the main menu we can still select the continue and load buttons and this is because we're not refreshing this in our main menu script at all so in the main menu script we can add a private method called disable buttons depending on data and we'll cut and paste this chunk of code from our start method into it then we'll call that method from our start method as well as in the activate menu method so that the buttons disable when the menu is activated if there's no data and if we go back into play mode and test this out we'll see that that fixes the issue the next thing that would be really nice to have is a confirmation prompt that warns us if we're about to overwrite our data when we start a new game or delete data when clicking the clear button how we're going to go about this is by adding a generalized confirmation pop-up menu that can be configured to show any question we want along with a confirm button and a cancel button each of which will correspond to different actions we'll take in our code so first let's create the confirmation pop-up menu ui in our main menu scene let's right-click on the canvas object in our scene hierarchy and create a new empty game object that we'll call confirmation pop-up menu then we'll right-click on that select ui image which is going to be the background of our panel so we can rename that to background we'll resize it a bit 750 by 400 will work for now and then last we'll change the color to be a solid black then we'll right click again and go to ui text text mesh pro and we'll call that game object display text then we'll position it on the panel towards the top change the text to be some placeholder text and then drag out this yellow box which represents the text boundary and next we'll center the text both vertically and horizontally and then change the font size to be just a bit larger we'll go with 46 then we'll duplicate the new game button from the main menu rename it to confirm button and then drag it under the confirmation pop-up menu in the scene hierarchy we'll change the button size to be a bit smaller change the text to say yes in all caps and then move it to the bottom left corner and of course we'll also remove the on click listener that was copied over when we duplicated the button then we can duplicate that button call this one the cancel button change the text to say cancel in all caps and then move that to the bottom right corner of the background panel now the idea here is that when this pops up we should only be able to move between the confirmation and cancel buttons if you don't see these navigation arrows at all be sure to click on the visualize button within the button component so you can see how they're going to navigate for the confirm button we'll select none from this drop down to deselect everything and then select explicit and then drag in the cancel button into the select on right slot and then we'll do the same thing for the cancel button except we'll drag in the confirm button to the select on left slot this just makes it where these two buttons can only navigate to each other which is exactly what we want for this menu next we can disable this in the scene hierarchy and then we'll add some code to support this in the scripts main menu directory of the project will create a new c-sharp script called confirmation pop-up menu and then double-click it to open it up first we'll remove these placeholder methods and have our script extend from menu instead of mono behavior we'll need to add a few using statements to the top of this script one for unity engine.ui another for unityengine.events and another for tm pro then we'll create serialize field private variables for the text mesh pro display text the confirm button and also the cancel button next we'll add a method called activate menu which is going to take in a string for the display text and two unity actions one for when the confirmation button is pressed and another for when the cancel button is pressed and if you're not familiar with unity actions don't worry too much all you need to understand here is that each action basically represents a block of code that we can execute by calling that action so first in this method we'll set the game object to be active to show it then we'll set the display text for the text mesh pro object to be the text that's passed in then for the confirm and cancel buttons we'll remove any existing listeners for good measure by calling the remove all listeners function on each and then we'll assign an on click function for each of them as well which will determine what happens when they get clicked for each one we'll deactivate the menu by calling a method that we'll create in just a second and then call the corresponding unity action and then of course we'll add a deactivate menu method where we just set this game object to be inactive which will hide it then in the save slots menu script we'll add a serialize field private variable for the confirmation pop-up menu first we'll get this pop-up working for when the player tries to start a new game with a save slot that already contains saved data let's refactor things just a bit to make this more clear we'll create a new method called save game and load scene where we'll put this chunk of code that saves the game and loads the gameplay scene we'll remove this chunk of code here and then break this up on a case-by-case basis for when the save slot is clicked for the case that we're loading the game using the save slot we'll check if is loading game is true and if it is we'll change the selected profile id and then call the save game and load scene method otherwise that means we're trying to start a new game in which we'll want to check if that save slot has any data or not so let's jump over to the safe slot script and give ourselves an easy way to determine that in the safe slot script we'll add a boolean parameter called has data and make it publicly gettable but only privately setable and initialize it to false then in the set data method in the case where we don't have data we'll set this to false and if we do have data we'll set it to true now back in the safe slots menu script we can reference that variable to determine if the save slot has data or not in the case where it does have data we want to show the confirmation pop-up menu to ensure that the player wants to overwrite that saved data we can do this by calling the confirmation pop-up menu's activate menu method and passing in the parameters the first being the display text that we want to display in the pop-up and the other two being functions of code we want to execute depending on which button is clicked the first block being for if the confirm button is clicked and the second for being if the cancel button is clicked if the confirm button is clicked we'll change the selected profile id create a new game and then call the save game and load scene method and we'll come back to if the cancel button is pressed in just a few but for now we'll put a to do comment here then the last case we need to account for is if we're starting a new game and the save slot is currently empty meaning that we can just start a new game directly we can do this by adding an else case here and then copying and pasting the chunk of code we're using for when the confirm button is pressed now when thinking about the cancel button case there are a couple of edge cases we need to account for since we're disabling all of the buttons when the save slot is clicked first if we hit cancel all of the buttons will still be disabled so we need to actually do something here to refresh the menu so to do so we'll call this.activatemenu and if we actually look at the disable all buttons method we'll see that it includes the back button as well and with how we have things set up right now it never becomes interactable again so in the activate menu method we'll add a line here to ensure that the back button is interactable anytime the menu is activated now back in unity we'll drag the confirmation pop-up menu script onto the confirmation pop-up menu game object in the scene hierarchy to add it and then we'll drag in all of the child components to the appropriate slots and for the first selected button we'll make that the cancel button so that if the player double clicks by accident they don't overwrite their save data without realizing it and then for the safe slots menu we'll drag in the confirmation pop-up menu game object to the confirmation pop-up menu slot now if we play this and try to start a new game with the save slot that has data already we'll see the confirmation pop-up menu if we hit cancel it doesn't start a new game at all however if we hit the confirm button it does start a new game and overwrites our data just as expected so real quick let's do the same thing for when we click the clear button to delete our game data back in the safe slots menu script for the on clear clicked method we'll call the disable menu buttons method to give it a more polished feel then we'll call confirmationpopupmenu.activatemenu passing in the display text as well as two functions for the yes and cancel buttons if we say yes we'll do these two lines of code here and if we cancel we'll just refresh the menu by calling activate menu and back in unity if we play this and click a clear button we'll see that confirmation menu pop-up in which we'll have to select yes to actually remove the data for that save slot the last couple things i want to talk about involve how to make this save and load system more reliable currently we have things set up in a way where the game will save when transitioning scenes as well as when the game is exited but let's say the player is playing the game for 5 hours straight without doing any scene transitions and hasn't exited the game at all and then all of a sudden their system crashes due to a hardware issue meaning the on application quit method of our code doesn't get called and the game never saves that means they've just lost 5 hours of progress and will probably be pretty frustrated one of the simplest things we can do to mitigate this is create an auto saving co-routine which constantly loops while the game is playing saving the game every minute or whatever we have it configured to then in the scenario mentioned the player would only lose a minute of progress when the game crashes rather than 5 hours of progress however something we should consider with this approach is that saving the game may lag the game slightly depending on how much data is being saved and the method of storage being used for that reason if there are moments in the game where this unwanted lag could cause a bad experience for the player we probably don't want to save during those moments and instead want to go with a more specific approach to that game for example in my game which is a precision platformer i have these birdhouses which act as checkpoints so one way i could go about auto saving in this game is saving every time the player reaches one of these birdhouses since these birdhouses are safe areas which don't require focus from the player if the game lags a bit it's not a big deal compared to if the game lags while they're trying to complete a platforming challenge and also if the game were to crash they'd have the most recent checkpoint and wouldn't have lost any meaningful progress of course you'll have to decide what works best for your own game however in this video we're just going to implement the simple auto saving code routine i previously mentioned since for minigames i believe that should work just fine back in the data persistence manager class we'll add a serialized field private float for the seconds in between each save for our auto saving code routine then we'll add a private co-routine variable so that we can keep track of the co-routine once we start it up and at the bottom of this class we'll add the coroutine method called autosave which returns an ienumerator and in there we'll create an infinitely looping while loop where we'll wait for the configured amount of seconds with this line and then save the game after that and we'll also put some login here to let us know that the game just auto-saved next we need to actually start this co-routine from somewhere i think a good place would be the on-scene loaded method since that's where we're first loading the game when the scene starts up we'll add some logic here to stop the auto-saving code routine if it exists so that way we never have more than one running at once and then we'll start the auto saving co-routine and assign it to that co-routine variable with this line here now back in unity we can configure the frequency of our auto saving here so we'll set it to 5 seconds just so we can see it quickly and then we can play the game from our gameplay scene and we'll see some logging indicating that the auto save and co routine is saving every 5 seconds with how we have it configured the last thing i want to talk about is backing up our saved data files if the system shuts down unexpectedly while the game is saving there's a possibility that the save file could get corrupted and the player could lose all of their progress while there are many ways we could go about mitigating this and depending on your method of data storage there might be some built-in ways for preventing this altogether we're going to go over an approach that pretty significantly mitigates this issue for file system storage in particular the idea is that every time we save the game we'll first write the data to a file just like we already are then we'll verify that the data saved successfully by attempting to load it which some might consider overkill but i personally like doing this just to add a bit more assurance that the data we're going to back up isn't corrupt for any reason then we'll copy that data file to another file with a slightly different file name in our case we'll just append the back extension which is fairly common for backup files like this and if we do this every time we save we'll always have a verified backup file that represents the most recent save with this in place let's say the system crashes when saving the game and our original data file gets corrupted in that case we can restore the original file using the backup file from the previous save and only lose data between when the game crashed and the most recent save likewise let's say the game crashes when creating the backup file and the backup file becomes corrupt in that case we would have already successfully saved and verified the original data file so we just load that as normal and then the backup file would get overwritten and no longer be corrupt the very next time we save so the only way we'd lose our data completely is if the system crashes twice in a row in two very specific spots in our code first when we're creating the backup file and then directly afterwards when we're writing to the original data file which in my opinion is extremely unlikely and would be really hard to make happen even if you were trying to do so with that said if you're concerned about this specific case hopefully what we're going to do in this example acts as a good base that you can build off of as there are many ways to mitigate this further for example storing multiple backup files keeping around old backup files and so on anyways let's jump into the code and start implementing this in the file data handler class we'll add a private read-only string called backup extension and set it to be dot back then in our save method above the try catch block we'll add a string called backup file path and set it to the full path with the backup extension appended onto it next down here after we've written the data to the file we'll verify that the file isn't corrupt by trying to load it and if the verified game data isn't null we'll create the backup file using the file.copy method where we'll copy the original data file to our backup file and this last parameter needs to be set so we can overwrite the previous backup file if it already exists and if for some reason the verified game data came back as null we'll throw an exception which will get caught in this catch block with some logging letting us know that the save file couldn't be verified and the backup wasn't created so that's good for creating the backup file but next we need to add some logic to roll back to that backup file if the original file becomes corrupt we'll create a private method called attempt rollback that returns a boolean and takes in a string for the full path to the original data file at the top we'll create a boolean called success and set it equal to false and then return it at the bottom which will set the true in this method if the rollback succeeds then we'll create the backup file path string by appending our backup extension onto the full path and next we'll create a try catch block where if we get an exception we'll log an error letting ourselves know that the rollback failed in the try block we'll first check if the backup file exists and if it does we'll use file.copy to copy the backup file to overwrite our original file in this case we'll set success to true and also log a warning to let ourselves know that we had to roll back and if for any reason we try to roll back but the backup file doesn't exist we'll throw an exception which will get caught in the catch block letting ourselves know that we tried to roll back but no backup file currently exists and now we just need to call this method when loading our data fails in the load method we can assume something is wrong with the game data if the load fails and the code enters this exception block we'll change this logging message to a warning letting ourselves know that the load failed and we're going to attempt to roll back then we'll call the attempt rollback method and if that's successful we'll try to load the data again recursively and while loading the data recursively like this will be seamless to the player in the case where we have to roll back there is potential here for an infinite recursion loop for one example of this if the attempt rollback method succeeds but the backup file still ends up being corrupt for some reason the load method will just continue to fail over and over again until we run out of space on the stack and the game crashes so one way we can account for that is by only attempting the rollback a single time so for the load method we'll add an optional parameter called allow restore from backup and default it to true then we'll add this conditional statement and only attempt the rollback when that's true and if it's false that means it failed a second time in that same recursive stack and we should log in error letting ourselves know that restoring from the backup file has failed and most importantly when we call the load method recursively we'll pass in false as the second parameter so it doesn't try to restore from the backup file if it fails again and that should do it so now let's try this out we'll just start a new game by overwriting this first save slot here and then we'll exit play mode then if we go view our data we'll see that it's creating the backup file just as expected and if we open up our original data file and we delete the bottom half of it to corrupt it and then start up the game we'll see some warning logging indicating that we had to roll back to our backup file and sure enough we're able to load the game as normal even though we wiped out half of our data file which shows that our backup system is working and that's it for this video thank you so much for watching this has definitely been a tough tutorial series to put together and i've personally learned tons myself through doing so i hope you found something in this video useful and if you did please give the video a thumbs up so more people see it and if you want to see more from me be sure to hit the subscribe button as well those things really help out the channel and i appreciate it a ton also be sure to keep an eye on the pinned comment for this video if there are other bug fixes or things worth mentioning that are found later on i'll try my best to keep that pinned comment up to date with any other issues and how to go about fixing them you're also welcome to come by my discord server which has been a great place to ask questions suggest a video topic or just hang out and show off the game that you're creating you can also follow me on twitter instagram or tiktok where i mostly post about the game that i'm creating anyways thanks again for watching and most of all i hope this was helpful [Music] you
Info
Channel: Shaped by Rain Studios
Views: 21,273
Rating: undefined out of 5
Keywords: trevermock, trevormock, trevor, trever, mock, unity save and load, save and load system, scriptable objects, saving scriptable objects, save and load scriptable objects, unity delete data, unity backup file, save system backup file, backup files, scene unloaded event, unity scene unloaded, unity save system, unity saving and loading data, unity save load, unity save and load system, save game unity, save data unity, save data between scenes unity, corrupt save file unity
Id: yTWPcimAdvY
Channel Id: undefined
Length: 33min 30sec (2010 seconds)
Published: Mon Jun 20 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.