Data Persistence - Save & load your game state while avoiding common mistakes | Unity Tutorial

แชร์
ฝัง
  • เผยแพร่เมื่อ 25 พ.ย. 2024

ความคิดเห็น • 176

  • @zivv1147
    @zivv1147 7 หลายเดือนก่อน +3

    Absolutely fantastic video! TH-cam is full of tutorials for basic implementations, and you presenting the more complex and advanced topics, and doing a deep dive into them, is super useful and refreshing (and also important - this seems to be must-have knowledge to get a job in the industry as a developer).
    The presentation was fantastic, good explanations, and the pace is great.

  • @bassfight2936
    @bassfight2936 2 ปีที่แล้ว +29

    Thank you! It's SO hard to find tutorials that don't just say "use playerprefs lol" or indeed just refer to the binaryformatter.

    • @LlamAcademy
      @LlamAcademy  2 ปีที่แล้ว +3

      Glad I could help!

  • @mattomwit
    @mattomwit 7 หลายเดือนก่อน +4

    Hi. I wanted to thank you for this tutorial it really helped me out. I was retying your solution to test it out and noticed you are rethrowing the exception using "throw e" at 13:10. For anyone reading this comment please use just the "throw" keyword. If you use "throw e" you will remove part of the call stack. Sorry for pointing stuff like that out. This video is one of the best I've seen showing how to do things properly and I firugred my comment might save someone some pain in the future.

    • @LlamAcademy
      @LlamAcademy  6 หลายเดือนก่อน +3

      Great feedback, Thank you! I didn't know that killed your call stack.

  • @mutlugameofhalit
    @mutlugameofhalit 15 วันที่ผ่านมา +1

    Pls make a video about a real game demo which has different classes and entities and improve that save - load system for them. If you do that, you will be have the best Save Load Tutorial in the world!

  • @lucasdahl1118
    @lucasdahl1118 ปีที่แล้ว +6

    Thank you so much! I built a massive rpg world and have the story 90% done and this was up on my list, so thank you!

  • @poobagification
    @poobagification 2 ปีที่แล้ว +12

    Excellent topic. I've been playing with saving and loading in my project and it's a mess. I read not to use binary formatter but there weren't any replacements suggested. it's nice to see how it can be done safe and clean.

  • @harshjadon1662
    @harshjadon1662 ปีที่แล้ว +4

    Finally someone made video on this thnx.
    hi,
    Kindly make more videos of unity challenges n other projects/tutorials for beginners
    Thanks

  • @Francisco-Gutierrez
    @Francisco-Gutierrez ปีที่แล้ว +1

    Thank you, I always come back to this video to remember how to save data is done!

  • @benrobinson1454
    @benrobinson1454 ปีที่แล้ว +1

    Brilliant video that helped me set up a save system that has felt so daunting a task I've put it off for a long time (as a hobby coder).. Thank you!

  • @sqwert654
    @sqwert654 ปีที่แล้ว +2

    Thank you !! Working perfectly with my game, so much easier than my playerPref method , no conversion needed can remove so much code from older method :)

  • @glock6554
    @glock6554 ปีที่แล้ว +3

    best teacher ever

  • @martin.m.kloeckener
    @martin.m.kloeckener ปีที่แล้ว +5

    Good tutorial, thanks! However, I would make a backup of the previous save file and delete it only at the end when the new save file has been successfully created. That way, you can be sure that you won't lose the entire save file if the game or the PC crashes / an error occurs during the save.

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      That is a good suggestion, thanks!

    • @ibeatboxer_9673
      @ibeatboxer_9673 11 หลายเดือนก่อน

      What do you mean by that? In order to save a new file you should delete the previous isn't it right? Even if you create the new one how would you not have any conflict with the previous one?

    • @martin.m.kloeckener
      @martin.m.kloeckener 11 หลายเดือนก่อน

      @@ibeatboxer_9673 If you delete the previous file, then save the new one you are risking to lose the player's progress. If the game crashes during the file writing or the file writing fails, the previous file is still deleted, but you don't have a new file. So no save file at all anymore.
      I suggested to make a copy of the previous file, then write the new file and only if this was successful, delete the copied file.
      This surely is a very unlikely scenario but only one player losing progress is one player too much.

    • @Nomad1108
      @Nomad1108 6 หลายเดือนก่อน

      ​@@ibeatboxer_9673 Maybe change the file extension to .bck before creating a new .json, then delete .bck if the save was successful otherwise revert .bck to .json.

    • @neil_from_future
      @neil_from_future 5 หลายเดือนก่อน

      ​@@ibeatboxer_9673 I mean they have extra work under it where they would just: if exist > load it > create a new file with .bak > then do the work on real one > if something wrong happened with the original > load the .bak instead.

  • @soolydooly1234
    @soolydooly1234 11 หลายเดือนก่อน

    thanks for making this. Although I'm going to use BinaryWriter

  • @umairjamshaid2173
    @umairjamshaid2173 ปีที่แล้ว +1

    Super helpfully and beautifully explained!

  • @alon_vita
    @alon_vita ปีที่แล้ว +2

    Awesome Tutorial! thank you!

  • @superdahoho
    @superdahoho 9 หลายเดือนก่อน +3

    so how do you save complex data?
    I have a class(inventory item) with image, transform, an enum, a scriptable object and another gameobject as variable.
    i want to save it and unity is having a hard time converting that into data.
    do I have to manually break down the data into primitive variables and save them?

    • @LlamAcademy
      @LlamAcademy  9 หลายเดือนก่อน +1

      If you need to retain object references using JsonUtility is a little easier (you can still do it with Json.NET, but it’s a little extra work).
      For this type of thing I would have an item scriptable object that had references to the image and prefab and whatever other project files it needs. Whenever I need to instantiate the UI I would read the prefab from the SO and instantiate the prefab

  • @ericelnomada
    @ericelnomada ปีที่แล้ว +1

    Thank you bro! amazing tutorial!!

  • @cheezcola
    @cheezcola 10 หลายเดือนก่อน +1

    good tutorial. Thanks!

  • @sharat.achary
    @sharat.achary 2 ปีที่แล้ว +1

    Thank you, you explain it very well. 🤝

  • @evanlane1690
    @evanlane1690 ปีที่แล้ว +3

    Would it be safer to write a second save file if you find a save file already exists? Then when the file is written successfully, you delete the old save? That way if anything goes wrong during the save it can gracefully revert to the old save?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      Maybe? At some point you're going to want to write over the original save. I guess if the save to the temporary "new" file succeeds and the write to the "real" save file fails, you can use the temporary one. If the problem with writing persists (maybe disk space is full or something) then the next time you try to write to the temporary one, that may also fail. You could build a very robust system to manage this kind of thing, but in my opinion, the risk of this is very small. Having a cloud save or cloud backup would be the safest option to prevent total save file loss.

  • @imc0der
    @imc0der ปีที่แล้ว +1

    Nice tutorial thanks

  • @Coolae450
    @Coolae450 7 หลายเดือนก่อน +2

    I'm getting a NullRefrenceException whenever I try to call the Load method :/

  • @MagicPigGames
    @MagicPigGames 2 ปีที่แล้ว +2

    I've run into cases where my data structure goes > 10 layers deep, so Serialization fails. In those cases, I've found that I can store some data classes, like "Inventory" or what not, as a JSON string, and then just save the various strings. On Load, I can load all the data in two passes -- loading the saved data, then loading the saved JSON strings.
    I'll have to come back after the day job to learn why using JSON Utility is not good! :D

    • @LlamAcademy
      @LlamAcademy  2 ปีที่แล้ว +1

      Sounds like you already found one of the issues with JSONUtility 😉. I got some feedback as well instead of using Newtonsoft (JSON.NET) you could use System.Text.Json (docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer?view=net-6.0) which is C# native JSON support that works effectively the same, but can even be faster than JSON.NET

    • @MagicPigGames
      @MagicPigGames 2 ปีที่แล้ว

      @@LlamAcademy Oh thanks! I'll have to keep this in mind when I update my save/load system!!

  • @eetu16
    @eetu16 2 ปีที่แล้ว +3

    DateTime.Now.Ticks could be replaced with the Stopwatch class, but DateTime gets the job done as well. This is the best video on this subject that I have seen, thank you!

    • @LlamAcademy
      @LlamAcademy  2 ปีที่แล้ว

      I appreciate that, thank you 🙌

  • @erfrid
    @erfrid 2 ปีที่แล้ว +7

    Excellent lecture! Your coding style is clean and professional and teaches good programming habits. I have a hard time tackling Game Serialization and this video gave me some good ideas.
    One question if I may.
    I'm working on a Baldur's Gate-like game, with lot's of area transitions and after many days of brainstorming I still can't decide what approch to take for bringing the player party to another area with inventory and equipped armor/weapons. I'm going back and forth between DontDestroyOnLoad and using a persistent scene with additive scenes for each area, but both ways feel wrong and hacky. I seriously would prefer to save everything in a scene, destroy it and reload everything in the next.
    May I ask you and others, what approach you think would be best or which approach would be horrible to take?

    • @LlamAcademy
      @LlamAcademy  2 ปีที่แล้ว +1

      There's a lot of things to consider there. If you're okay having the kind of clunky "fade to black" or "loading screen" the full load of a new scene and just re-instantiating your player/group objects (including weapons/armor, etc..) at the "start point" on the next level is the simplest and most memory efficient way of handling that. For more of an open world feel, I think additively loading the scenes and keeping the players/group always active is the way to go.

    • @erfrid
      @erfrid 2 ปีที่แล้ว +1

      @@LlamAcademy Thank you for sharing your view! I think method 1 it is for now. With this serialization system it shouldn't be too hard to implement. I'd really love to see more videos about this topic.

    • @Micahiscoo
      @Micahiscoo ปีที่แล้ว

      @@erfrid did it work

  • @bravo7989
    @bravo7989 ปีที่แล้ว +1

    Great Videos! I am learning more every day. You mentioned that you shouldn't use the binary formater. Can you explain why?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Yes, but I think Microsoft does a better job at it than I can, you can see their guidance here: docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide

  • @FiceGamingTVStream
    @FiceGamingTVStream 7 หลายเดือนก่อน

    i really enjoyed your video. The only thing i have a gripe with is i still want evidence on why not using the unity JSONs for saving. You said it doesn't support complex types, but your example wasn't complex either and was just nested standard data types in the json object. If you could show in a video one day complex values being stored then maybe I would be swayed in the direction your talking about but your approach seems like there's overheard development without showing a true scenario of it working with the implementation. I still really love the video and watched it till the end

    • @LlamAcademy
      @LlamAcademy  7 หลายเดือนก่อน +2

      Well, even simple Dictionaries just don’t save with JsonUtility.
      I’m sure you could come up with an event/observable+visitor system that could collect all objects that have data that need to be saved and write only once to the disk without worrying about multiple things trying to write at once. That would be pretty sophisticated and cool

    • @FiceGamingTVStream
      @FiceGamingTVStream 7 หลายเดือนก่อน

      @@LlamAcademy thank you so much for that answer and ill definitely research that a bit more! You absolutely rock!

  • @gavinw77
    @gavinw77 7 หลายเดือนก่อน

    Saving to registry? As I understand it, MS are moving away from the registry style of storing data. UWP and W8 introduced ApplicationData (and the AppData folder). If apps store data there instead of the registry it makes for an easier cleanup, and prevents performance decay on long-life-installs.

    • @LlamAcademy
      @LlamAcademy  7 หลายเดือนก่อน +2

      This does not save to the registry

  • @cdreyer6266
    @cdreyer6266 2 หลายเดือนก่อน

    What do you think about using player perfs string to save an encrypted converted json?

    • @LlamAcademy
      @LlamAcademy  2 หลายเดือนก่อน +1

      That’s a feasible option if for some reason you can’t use or don’t want to use the persistent data path. Basically the same thing

  • @adslpiulentoditalia2545
    @adslpiulentoditalia2545 ปีที่แล้ว +2

    Hey Llam great video. It would be amazing if you can show how we can save Json to Google play services cloud there's no tutorials on that. It would be amazing keep storing Json somewhere from server side which is totally free. Could you make a video on that would be really helpful. I tried in many ways to save Json to Google cloud but unsuccessful. :)

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Hmm 🤔 I'll think about that. I didn't use Google Play services. For my game I used PlayFab which handles that. It's free up to a point, but eventually you have to pay. They don't recommend launching your game on the free tier because it doesn't have an SLA

    • @adslpiulentoditalia2545
      @adslpiulentoditalia2545 ปีที่แล้ว

      @@LlamAcademy i used a playfab but there's more limitations that you can expect for some reason playfab didn't mention that player even if you doesn't reach 100K it's calculating each player API call for every single 5 minutes that means that you cannot log-in after that time because of limitations and that gonna cause a lot issues. That's why I moved to google play services cloud which Is absolutely free no metter the amount of players the only things that you cannot do is see the data on the cloud which is stored into google drive account for each player. But at least you can store json or variables into cloud for absolutely free. Of course there is a limitations like you can only store 3MB of data file but I think that should be enough even for big projects since my json file is 3kb at least. But there is actually no documentation about that I see some old forums that they managed to save json to that cloud but I tried and no success maybe because I'm bad at coding :(
      I see many games storing data to this cloud but I have no idea how. I just managed how to save separately each variables but that's gonna be a mess since a have a lot of data

  • @NaviYT
    @NaviYT ปีที่แล้ว

    Hey there! Let me start out by saying AMAZING TUTORIAL! I love the way this system works and how clean and reusable the code is. I do have an issue though. While the file is being written to correctly, the data is not being retrieved correctly.
    For example. Let's say I have an array of weapon classes that I'm saving. The file gets written to as show below:
    {
    "Setup": {
    "ID": "WeaponClassSlot.1",
    "DisplayName": "a;sdkfja;sdlkfja;sdjf",
    "PrimaryWeapon": {
    "ID": "TestID",
    "DisplayName": "TestDisplayName",
    "WeaponRef": null,
    "WeaponSkins": [],
    "WeaponAttachments": []
    },
    "SecondaryWeapon": {
    "ID": "",
    "DisplayName": "",
    "WeaponRef": null,
    "WeaponSkins": [],
    "WeaponAttachments": []
    },
    "Knife": {},
    "Utility1": null,
    "Utility2": null,
    "Utility3": null
    },
    "name": "WeaponClass_Slot1",
    "hideFlags": 0
    },
    {
    "Setup": {
    "ID": "WeaponClassSlot.2",
    "DisplayName": "Weapon Class 2",
    "PrimaryWeapon": {
    "ID": "",
    "DisplayName": "",
    "WeaponRef": null,
    "WeaponSkins": [],
    "WeaponAttachments": []
    },
    "SecondaryWeapon": {
    "ID": "",
    "DisplayName": "",
    "WeaponRef": null,
    "WeaponSkins": [],
    "WeaponAttachments": []
    },
    "Knife": {},
    "Utility1": null,
    "Utility2": null,
    "Utility3": null
    },
    etc...
    However, when I use the load function and attempt to print the file to the console (similar to how you do with the text field) I get empty values like this:
    Any Idea on how I can fix this? Perhaps saving an array of a custom data set is not supported? But then that wouldn't make sense because the file gets correctly written to. It's only when trying to load the data back into an array of this data type that it returns all values as null. Thank you in advanced, and thank you for the video :)
    Loaded from file:
    [
    {
    "Setup": {
    "ID": null,
    "DisplayName": null,
    "PrimaryWeapon": null,
    "SecondaryWeapon": null,
    "Knife": null,
    "Utility1": null,
    "Utility2": null,
    "Utility3": null
    },
    "name": "WeaponClass_Slot1",
    "hideFlags": 0
    },
    {
    "Setup": {
    "ID": null,
    "DisplayName": null,
    "PrimaryWeapon": null,
    "SecondaryWeapon": null,
    "Knife": null,
    "Utility1": null,
    "Utility2": null,
    "Utility3": null
    },
    "name": "WeaponClass_Slot2",
    "hideFlags": 0
    },
    etc...

    • @NaviYT
      @NaviYT ปีที่แล้ว +1

      For anyone dealing with this in the future. My issues were not having public setters. I'll leave an example below.
      Normally for my values I incorporate private setters to prevent cheating. The way I go about this is:
      public bool MyBool => _myBool;
      [SerailizeField] private bool _myBool = false;
      Removing the private setter fixed the issue and now the Json deserializes correctly

  • @druvingame
    @druvingame ปีที่แล้ว +1

    I making a simple cannon shooting game for mobile, i can't decide whether i should save data on local or cloud for my game, i want to make it run on cloud to make sure internet stays on when playing game. what should i do?

    • @LlamAcademy
      @LlamAcademy  11 หลายเดือนก่อน +4

      I actually think if you can have your mobile game not require internet connection, you shouldn't. There are many use cases such as on a plane, train, and boat, where the device may not have internet and it would be cool to still be able to play it. I actually spent a good couple months ripping out the "always online" requirement for my game so it could be played offline in these scenarios.
      If you need it to be online for multiplayer and anti-cheat, sure. If it's "just because" I would advise against it.

  • @WelshGuitarDude
    @WelshGuitarDude 6 หลายเดือนก่อน

    How do you link data to a monbehavior since the reference is lost when you open unity again. Such as a graph node and the monbehavior that holds the node data

  • @DanWarrioR
    @DanWarrioR 9 หลายเดือนก่อน +1

    Is it possible to save GameObject properties, as an transform.position, rotation, scale etc. And for example a navmesh settings for enemy: target, path, something else. If is not possible which method i should use to do that in my project? Thanks for your help

    • @LlamAcademy
      @LlamAcademy  9 หลายเดือนก่อน +1

      Yes, but you will need to copy those into a data structure that can be serialized first (a simple class with those properties is fine) and apply them to your target objects on load

    • @supersentaimexicano1967
      @supersentaimexicano1967 7 หลายเดือนก่อน

      could you make a tutorial about it? It could be really helpfull pls @@LlamAcademy

  • @VamereDigitalCrafted
    @VamereDigitalCrafted ปีที่แล้ว

    Are you avaliable for personal mentoring?? Your chanel is amazing!!!

  • @indigotidd6663
    @indigotidd6663 ปีที่แล้ว +1

    What do I do if there is an exception error? it wont write to the persistent data path and I can't figure out why

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Not sure, what is the error?

  • @bassfight2936
    @bassfight2936 2 ปีที่แล้ว +2

    This saves data locally to our device. What would you recommend for managing data across devices using github? Me and my friend are both working on the same unity project, synched up via a git repository. Would it be best to simply sync the folder in appdata too?

    • @LlamAcademy
      @LlamAcademy  2 ปีที่แล้ว

      Do you need to synchronize the save files between members of your project?
      That's a little trickier... These are saved (on Windows) in the User directory. You could potentially create a separate git repo in that folder and push changes as needed. Maybe symlinking the persistent data path folder could get you there, but honestly, I haven't tried something like this before.
      The lowest-tech solution would be to create a folder in your main repo with like "base save files" and manually copy them around as needed

  • @Criss10_
    @Criss10_ ปีที่แล้ว +1

    Hi nice video! i have a question, where i can generate the key and the iv?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      Hi 👋 The Aes instance that is created here: 17:21 will automatically generate an IV and Key. What I did was just copy/paste the values out from one that was generated at this time and started using those every time as those strings you see at the top of the JsonDataService class.

  • @DanWarrioR
    @DanWarrioR 8 หลายเดือนก่อน +1

    Hello man, can you help me with this sytem because i can't understand how is it possible. FOr example, i have simple public class with fields and a few Lists with already added variables, for example in my projects it's screenResolutions list. I have list with
    new(1920, 1080),
    new(1024, 768),
    new(1152, 864),
    ......
    14 elements. For the first game starting, i'm trying to load data from my folder and it work for the first time, but if i want to restart my game(or start it again, 2x, 3x, and more). For all next game starting times my system load this data incorect. How i already said i have list with 14 elements(example) and for the first time system load this data corect, with all this 14 elements but for the next times amount of elements increasing on (amount of elements) + (default count of elements). For example, for the 2 game run my 14 elements become 14+14 =28, for the third 28+14 = 42 and so on.
    What is the reason for this error and how to fix it? Huge thank for the help!

    • @LlamAcademy
      @LlamAcademy  8 หลายเดือนก่อน

      Sounds like I when you start your game you’re adding to the file instead of writing a new file. You’ll have to check your code carefully to see how you initialize the data and how you read/write the data. You can easily add some breakpoints or debug.logs to see exactly what your code surrounding this system is doing and I think you’ll find it pretty quickly!

    • @DanWarrioR
      @DanWarrioR 8 หลายเดือนก่อน

      @@LlamAcademy I have already fixed this problem, thankfully. The problem caused my data saving with using List collections. I don't know why, but when i am using a List collection, the files reads wrong, that's why i got (amount of elements) + (default amount of elements) every time. I don't know why, but when i change it to simple array it started working

  • @Veil291
    @Veil291 2 ปีที่แล้ว +2

    hey, beginner game dev here I was making an arcade game (similar to flappy bird) and I wanted to be able to save the player high score so I could show it at the end of the run (or just at the top corner or something). Anyway I was wondering if you would still recommend this method and if so how would you alter it (as I think some of it might be a bit unnecessary just to save the player's high score). Thanks for any help :)

    • @LlamAcademy
      @LlamAcademy  2 ปีที่แล้ว +3

      You can use this method to save high scores. Honestly it may initially seem like a lot, but with the framework in place it’s quite easy to handle even multiple files.
      If you want to save more than just the highest score, for example the top 10 high scores, this will be very helpful.
      If you only ever want to store the single highest score, you can achieve that with simply using PlayerPrefs.SetInt(“HighScore”, score);
      PlayerPrefs.Save();
      And retrieve it with PlayerPrefs.GetInt(“HighScore”);
      That will work and will get you up and running pretty quick.
      If you plan to extend your game, you might want to go ahead and do this because otherwise you’ll have to undo all the other saving stuff and reimplement something more robust like this eventually anyway.
      Ultimately it’s up to you and the needs of your game 🙂

  • @lokeki8894
    @lokeki8894 ปีที่แล้ว +1

    Hi thank you for the great video! I have a slightly related(?) question regarding game data.
    When it comes down to having pre-existing data(such as a spreadsheet of enemy/item data), how should I go about packing the data for a game? I have heard people recommending against /Resources and I would like to hear how you would go about handling this data.

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Personally I would load the data from a spreadsheet into scriptable objects. I’m not a fan of using csv or excel to define these relationships. Editor fooling around scriptable objects makes it much easier to deal with.
      However if you and/or your team prefer to work like that, I don’t see a problem with the resources folder.

    • @lokeki8894
      @lokeki8894 ปีที่แล้ว

      @@LlamAcademy I see. Thank you for the quick reply and this amazing video!

  • @Nomad1108
    @Nomad1108 6 หลายเดือนก่อน

    Great video thank you! I was wondering if using a struct instead of a class for PlayerStats would be better performance-wise (thinking about an auto save system on mobile)?

    • @LlamAcademy
      @LlamAcademy  6 หลายเดือนก่อน +1

      Generally structs put less pressure on the heap so if you’re saving a lot during gameplay that could be better. I have always used a class for whatever reason and haven’t had issues with the performance, but I also haven’t saved extensively during gameplay where performance is critical.

    • @Nomad1108
      @Nomad1108 6 หลายเดือนก่อน

      @@LlamAcademy Good to know, thanks!

  • @N1ghtR1der666
    @N1ghtR1der666 5 หลายเดือนก่อน

    I don't think you should be deleting the only other save before creating a new one, that's a fast way to get a corrupted save that is unrecoverable, I would change it to have multiple saves before starting to overwrite the oldest or some similar system.

    • @LlamAcademy
      @LlamAcademy  5 หลายเดือนก่อน

      Yup. You can build out as much framework and multi-save as you want on top of this

  • @scdijkens
    @scdijkens ปีที่แล้ว +2

    Hi this looks great, I am struggling a bit with saving lists of Custom classes however. In my case I have 100's of "Character" classes each with their own "Family" class reference of the Family they belong to, but then the Family class has a list with references to all the Characters that are part of the Family. I believe this is what is causing the Serialization function to throw this error: Unable to save data due to: Self referencing loop detected. How do I still serialize those references etc.? Also for serializing unity colors do I need to turn them into rgba float arrays?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Usually when you have cyclical references like this, it’s an indication that the data model design is flawed.
      Without knowing the details of your game, it sounds to me like “Family” would be an object that HAS multiple “people” or “Characters”, not the other way around.
      If you do need these references, this stackoverflow may help: stackoverflow.com/questions/35869705/handling-circular-reference-with-newtonsoft-json

    • @scdijkens
      @scdijkens ปีที่แล้ว

      @@LlamAcademy Thanks I'll take a look. How did you format the JSON at 11:40 ? I googled and found CTRL K CTRL D but Visual Studio gives an error formatting is not currently available...

    • @scdijkens
      @scdijkens ปีที่แล้ว +1

      Nvm got it, apparently i didn't have the web component installed on VS.

  • @Maxroty
    @Maxroty ปีที่แล้ว

    Hi, I managed to successfully encrypt data and be able save it onto a file but whenever I try to load the encrypted file it gives me,
    "CryptographicException: Bad PKCS7 padding. Invalid length 53" which happens precisely at "string result = reader.ReadToEnd(); "
    I have the Key & IV auto-generated and set in variables. I don't know what I might be missing...

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      When I had that happen it was because I just was manually tweaking a Key/IV. If I let C# generate the Key/IV, write them to the console, then copy/paste those into variables and only use those from that point on, it was always good to go. Is that the process you did for this?

    • @Maxroty
      @Maxroty ปีที่แล้ว

      @@LlamAcademy Yes, that's the process I followed.
      I figured out what was missing, not closing the stream after encryption made decryption problematic. So all I was missing was a stream.Close().
      Thanks for replying.

  • @karthikeyanpandiyan7333
    @karthikeyanpandiyan7333 ปีที่แล้ว

    I'm getting the wrong key or iv error. I generated one using the commented out line and copy pasted it to my const KEY and IV. It saves the file but when i try to load the content, it gives me a Null output. Help!

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      This sounds like when saving or loading it is not receiving the Key or IV and a new instance with an automatically generated key and/or IV is being used for at least one of these operations.

  • @RideFixRepeat
    @RideFixRepeat 9 หลายเดือนก่อน

    Lets say you can create multi characters or even a online co-op host/client based game, can you name the file name dynamic? Like instead of the /player-stats.json you have, could you do /.json?

    • @LlamAcademy
      @LlamAcademy  9 หลายเดือนก่อน

      of course! In online games you frequently allow a player to change their name, so maybe the unique identifier for the player would be a better choice than their name though.

  • @scdijkens
    @scdijkens ปีที่แล้ว +1

    How would you go about merging different classes into the same json? like for example you used PlayerStats, how would you then add into the same file for example classes like BuildingData and EnemyStats etc etc?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      I would use separate files.
      This data sounds unrelated and probably needs to be handled by different classes.
      If it absolutely must be in the same file, I would make a new class with properties EnemyData, BuildingData, and PlayerStats and serialize / deserialize this class. I highly discourage that route unless there is no other option.

    • @scdijkens
      @scdijkens ปีที่แล้ว

      @@LlamAcademy Well most games have a single save file is why. That's kind of what I am aiming for as well. Maybe some sort of way to write to the file with Header text or symbols that break up the file into different strings upon deserialization? so you'd have a string for PlayerStats which is everything under the // PlayerStats header etc? similarly for // EnemyData ?

    • @scdijkens
      @scdijkens ปีที่แล้ว

      I could also make a folder that contains jsons for all the data seperately for each savegame. But I feel that would look a lot less elegant inside the File Explorer... (Say a player wants to do some save-editing?)

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      Yeah. Assuming each of those is a class that holds data about each thing, then just create a class that has a property of each of those classes and serialize that one instead. Like
      public class SaveData {
      public PlayerStats PlayerStats;
      public EnemyStats EnemyStats;
      public BuildingData BuildingData;
      …etc
      }
      And save / load from that

    • @scdijkens
      @scdijkens ปีที่แล้ว

      @@LlamAcademy Makes sense! I'll try that, thanks!

  • @dalima7342
    @dalima7342 ปีที่แล้ว +1

    Greate video,but how about saving data like:
    public class Item:ScriptableObject
    {
    public Sprite icon;
    public string name;
    }
    It went wrong when i try to save Sprite and load abstract class

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +4

      Sprite is not a serializable class. If you want to do that you may have like a sprite NAME and load that sprite after you read the file

    • @dalima7342
      @dalima7342 ปีที่แล้ว

      ​@@LlamAcademy Got it,thanks!

  • @ericgardiner7715
    @ericgardiner7715 8 หลายเดือนก่อน +1

    As a newcomer to coding I found this very difficult to follow because of the demo script that you don't write in this tutorial and I don't understand how to save and load the data across my other scrips in my game.

    • @LordZandaurgh
      @LordZandaurgh 6 หลายเดือนก่อน

      Yeah I'm having the same issue. Have you figured it out?

    • @ericgardiner7715
      @ericgardiner7715 6 หลายเดือนก่อน

      @@LordZandaurgh I sort of figured It out. You can't load and save the same JSON file in more than one script in your scene otherwise it overwrites in strange ways. Is there a particular part that's not working for you?

    • @LordZandaurgh
      @LordZandaurgh 6 หลายเดือนก่อน +1

      @@ericgardiner7715 Well I'm trying to use one script to store and alter the stats of my player and it would be convenient if I could call a function to save and load the data within that script. I'm also confused about the whole Demo script used in the video.

    • @ericgardiner7715
      @ericgardiner7715 6 หลายเดือนก่อน +1

      How I can explain it is you need two scripts: 1: that defines the JSON file that will be used for storing the data, 2: the script that gets the JSON file and creates an instance of it (Load the data), reads and edits that insane (Accessing and setting the data locally), and the replaces the JSON file with the edited instance (Saving the data). Note that I have not implemented Encryption even though I have created a bool for it.
      //this is what my first script is to define the JSON file is:
      using System;
      using System.Collections.Generic;
      [Serializable]
      public class CarData
      {
      public float SuspentionHeight;
      }
      //In my second script I declare the JsonDataService and the "local instance" of the data file that I defined in the previous script, as well as the unused encryption bool.
      using Newtonsoft.Json;
      using System;
      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      using UnityEngine.UI;
      public class CarCustomiser : MonoBehaviour
      {
      //Declare Data saving variables
      private IDataService DataService = new JsonDataService();
      private CarData CarData = new CarData();
      private bool EncryptionEnabled;
      void Start()
      {
      //load data in start
      CarData = DataService.LoadData("/Car-Data.json", EncryptionEnabled);
      }
      //this is how I read the data
      void ReadData()
      {
      float height = CarData.SuspentionHeight;
      }
      //this is how I set a new value on the "local instance"
      void SetData()
      {
      CarData.SuspentionHeight = 5;
      }
      //this is how I save the data by writing over the JSON file
      public void SerializeJson()
      {
      if(DataService.SaveData("/Car-Data.json", CarData, EncryptionEnabled))
      {
      }
      else
      {
      Debug.LogError("Could not save file.");
      }
      }
      }
      I hope that helps, or that you managed to figure it out in the meantime.

  • @willcroft5105
    @willcroft5105 6 หลายเดือนก่อน

    Could someone please explain how to use this in a basic game not having the Demo.cs stuff? Like I have a simple player with a health int, ammo int, etc.
    How do I use it? Do i have to modify the existing player controller to have all new Data stuff?

    • @LlamAcademy
      @LlamAcademy  6 หลายเดือนก่อน

      In this demo class here is just showing us the "game data" that is in PlayerStats. I think I didn't do a good job explaining in this video that you need a Serializable data structure to store to the file. If your game has all your data stored on a monobehavior you have to do some work or refactoring to have a "clean" serializable class to save/load on the disk.

  • @hailelam4112
    @hailelam4112 ปีที่แล้ว

    Can you share file json?

  • @anellaa5070
    @anellaa5070 7 หลายเดือนก่อน +1

    how to change and update the data?😭😭

    • @LlamAcademy
      @LlamAcademy  7 หลายเดือนก่อน

      You can load the data, make whatever changes, and re-save it

    • @anellaa5070
      @anellaa5070 7 หลายเดือนก่อน

      i only change 1 or 2 variables at a time but when I resave it the other variables that has been changed will reset to it defaults, how to save the new data but not changing other data?@@LlamAcademy

  • @akash.anand1
    @akash.anand1 ปีที่แล้ว

    Is Cryptostream.Dispose() called automatically? If yes, does it close the Filestream stream as well?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Yes! Because of the syntax we are using, dispose is automatically called

  • @SirFrosty84
    @SirFrosty84 10 หลายเดือนก่อน

    Whats the benefit of using Newton instead of JsonUtility

    • @LlamAcademy
      @LlamAcademy  10 หลายเดือนก่อน +1

      I talk about that around 3:30

  • @jimmmybacon9043
    @jimmmybacon9043 4 หลายเดือนก่อน

    Its telling me that the namespace newtonsoft could not be found despite me having just downloading it.

    • @TheRichardMarks
      @TheRichardMarks 3 หลายเดือนก่อน

      Rebuilding the project in visual studio solved this for me.

  • @Havie
    @Havie 9 หลายเดือนก่อน

    What happens if you have many many entities with multiple sub components and they all have nuanced references to one another ?

    • @LlamAcademy
      @LlamAcademy  9 หลายเดือนก่อน

      The data can be serialized like what's done here. For the references, when the objects are constructed via Prefabs or Instantiate() they should grab the references to one another. It's generally not a good idea to try to serialize all of the components of all of the objects in the entire scene.

  • @XxADONExX
    @XxADONExX ปีที่แล้ว

    does this method also work for persisting data between scenes?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      You could use this to persist some data on one scene and load it in another, yes!

  • @sqwert654
    @sqwert654 ปีที่แล้ว

    Is there not a problem using "/" on a Mac for the file format? @9.48

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      Nope, this is interpreted correctly by both windows and unix-based operating systems (including Mac)

    • @sqwert654
      @sqwert654 ปีที่แล้ว

      @@LlamAcademy fantastic!! Was using playerprefs in my 4 player Mahjong game. This is a much better solution.

  • @RonTzudik
    @RonTzudik วันที่ผ่านมา

    This is not working on mobile

  • @Fearofthemonster
    @Fearofthemonster ปีที่แล้ว

    If I understand correctly, this does not save monobehaviours. I have 100 gameobjects with multiple monobehaviours, including an AI for each gameObject (which is a finite state machine containing multiple classes). I am very confused on how I should proceed with saving.

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +3

      I would generally advise against trying to serialize the full state of your game including all game objects, monobehaviours, etc... The save size will become unreasonably large. Instead, I would recommend to save the core pieces of data you need and when loading, respawn objects into the game and set up your monobehaviours from the save file.
      For example if you have some enemy AI, most likely they are from prefabs. When you save, you can save the location and core stats such as ammo, hp, energy, position, and rotation for each enemy. When you load, you spawn the prefabs and apply the data from the save file. This way you don't need to save the (same, repeated) full prefab structure for each enemy AI.

  • @kiechannel8278
    @kiechannel8278 ปีที่แล้ว

    Hi I follow your video, I cannot use my own key and IV to encrypt data but I use your key it correct. Why?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      The most common issue I had with keys/IVs not working was an inconsistent use of them. Meaning on a write one set was used and on a read another was used. I think I mentioned in the video that to get these I made C# generate some valid key & IV then I copied those and used it. When I tried to manually make up some they didn’t work.

    • @kiechannel8278
      @kiechannel8278 ปีที่แล้ว

      @@LlamAcademy Thanks, I just generated my own Key and IV.

  • @BaldiModsAndroidStudio2
    @BaldiModsAndroidStudio2 2 หลายเดือนก่อน

    How about android? Did it work for android too?

  • @Hoang-nn8ot
    @Hoang-nn8ot ปีที่แล้ว

    how u can work with "using" in class my unity keep error at it

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      I think you may need to update your scripting API Compatibility level in the Project Settings > Player > Other Settings > Configuration > API Compatibility Level and set it to .NET Standard 2.1

    • @Hoang-nn8ot
      @Hoang-nn8ot ปีที่แล้ว

      @@LlamAcademy i think it my unity version problem. Can i not use "using" in "using FileStream"?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      @Hoang-nn8ot the “using” syntax used here is a newer c# feature. You can use the older syntax as well to get the same result learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using

  • @sayginisbay2365
    @sayginisbay2365 ปีที่แล้ว

    Is this same for the mobile games?

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Yup. I use this in my mobile game!

  • @thespacecowboy420
    @thespacecowboy420 8 หลายเดือนก่อน

    What with manifest json? what?

    • @Chubzdoomer
      @Chubzdoomer 8 หลายเดือนก่อน

      The manifest file should be located at YourProjectDirectory/Packages, where 'YourProjectDirectory' is the actual name of your project's directory.

  • @tomicz9850
    @tomicz9850 2 ปีที่แล้ว +1

    Does this work on mobile?

    • @tomicz9850
      @tomicz9850 2 ปีที่แล้ว +2

      It did work if anyone wonders. This is really high quality content!

    • @LlamAcademy
      @LlamAcademy  2 ปีที่แล้ว +1

      🙂 yup. It works on all platforms that have Application.persistentDataPath defined!

    • @deli5777
      @deli5777 ปีที่แล้ว

      Awesome, I was wondering, thanks!

  • @yourcommander3412
    @yourcommander3412 ปีที่แล้ว +2

    So I was trying to format Vector3 to three floats ... ohhh ... wait I actually want to store class objects... hmmm - hmmmmm.
    Nah, this is better.

    • @awmindiegame
      @awmindiegame ปีที่แล้ว

      tutorial in which this problem was solved th-cam.com/video/JLGhHjlYqjU/w-d-xo.html

    • @awmindiegame
      @awmindiegame ปีที่แล้ว

      there is a link to github in the tutorial description

  • @songerk7102
    @songerk7102 ปีที่แล้ว +1

    Great tutorial but you have one problem with the way you did it, it will only work with script that do not inherent from monobehaivor or any kind of inherent

  • @JustFor-dq5wc
    @JustFor-dq5wc ปีที่แล้ว +5

    I would change 2 things. 1) Don't save whole class, just data you need. Saving whole class can be heavy and its problematic when you change something (backwards compatibility). 2) AES is overkill to encrypt save. Key can't be securely stored anyway - you have to decrypt data client side. Simple XOR operation is much faster and do scrambling job just fine.
    Edit: one more thing. JsonUtility is one of the fastest parsers and create smallest amount of garbage. Source: "JSON Libraries Comparison in Unity 5.5"

    • @adslpiulentoditalia2545
      @adslpiulentoditalia2545 ปีที่แล้ว

      Yeah but xor doesn't read arrays and list back which AES does. I always have issues with xor. It could be in many ways unstable. For the key problem you just can encrypt byte itself to keep it safe

  • @seksan4843
    @seksan4843 ปีที่แล้ว

    Great Tutorial, you can teach me for design plain Model with your json. i can't deserialize my plain Model ;
    this is my plain model
    public class PlayerStat
    {
    [JsonProperty("Health")]
    public long Health { get; set; }
    [JsonProperty("Name")]
    public string Name { get; set; }
    [JsonProperty("BaseAttackSpeed")]
    public long BaseAttackSpeed { get; set; }
    [JsonProperty("Level")]
    public long Level { get; set; }
    [JsonProperty("HasUnlockedSomething")]
    public bool HasUnlockedSomething { get; set; }
    [JsonProperty("HasUnlockedSomethingElse")]
    public bool HasUnlockedSomethingElse { get; set; }

    public Dictionary Equipment { get; set; }
    [JsonProperty("Inventory")]
    public Inventory[] Inventory { get; set; }
    }
    stuck it can't deserialze dictionary
    "JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[LabJSON.Model.Slot,LabJSON.Model.Equipment]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
    To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array."

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว

      From what I read here, it seems that you have stored some data in an array and are trying to deserialize it into a Dictionary. To resolve that, whenever you are saving the data of "Equipment" make sure it is stored in a key-value format.

  • @thatguy9668
    @thatguy9668 ปีที่แล้ว +2

    While this is really well done, SERIOUSLY would be nice if you could slow down any time you are using intellisense to make connections/corrections on the errors. I have to slow the video down to 25% play speed to get a chance to see what option you clicked. Several parts where you just flew through like bat shit crazy on critical info... but then took your time talking forever on misc stuff I don't need to know day to day.

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      Thanks for the feedback. I will try to be sure to slow down or sit with the code on screen a little longer so it is easier to follow.

    • @thatguy9668
      @thatguy9668 ปีที่แล้ว

      @@LlamAcademy yep just a second to pause it, also thank you for replying. Additionally IdataService and JsonDataService need to be attached to something available in every scene correct? cause I am getting errors when trying to attach it as a component to my Game Manager. Saying needs to derive from monobehavior for jsondata, and then can't be abstract for idata

    • @LlamAcademy
      @LlamAcademy  ปีที่แล้ว +1

      @thatguy9668 no, these are not MonoBehaviors so you don’t need to attach them to a GameObject. You can use them like any standard C# class. If you want to use them in the game manager you can just instantiate an instance and you are good to go.
      The full project is on GitHub, so you can check out how it was done in the Demo.cs MonoBehavior github.com/llamacademy/persistent-data/

  • @graig2558
    @graig2558 ปีที่แล้ว

    No back up save? Ok well hopefully literally nothing EVER corrupts when your player saves and the code deletes the only copy of the save.

  • @alfuplus976
    @alfuplus976 ปีที่แล้ว +8

    with do respect, you just waste my time, your code is not clear and ambiguous. thanks for your kind effort through.

    • @Hoptronics
      @Hoptronics 2 หลายเดือนก่อน +1

      @@alfuplus976 thanks for the honest comment. So many times I'm 30-45mins into a video and there's " magic shit" missing making for a total waste of time. Appreciate it. Saved me 30+ mins today .

    • @LlamAcademy
      @LlamAcademy  2 หลายเดือนก่อน

      @Hoptronics no magic here 🙂

  • @jacopinolaringoiatra
    @jacopinolaringoiatra ปีที่แล้ว +10

    "com.unity.nuget.newtonsoft-json":"3.0.2",

  • @Tokaku-ft2rd
    @Tokaku-ft2rd 7 หลายเดือนก่อน +1

    Awesome tutorial! Thanks

    • @LlamAcademy
      @LlamAcademy  7 หลายเดือนก่อน

      You're welcome🧡