Search Unity

Question How do you save data?

Discussion in 'Scripting' started by LetmeDwight, Nov 18, 2020.

  1. LetmeDwight

    LetmeDwight

    Joined:
    Apr 9, 2020
    Posts:
    125
    How do I write and read values from a C # script like:
    bool, int, float, string and arrays.
    Which must continue to exist between scene changes?
    because I don't know how to address the component script of an object from the hirachy list that is in a DontdestroyOnLoad?

    And how exactly does it work with permanent storage? Do you save: "bool, int, float, string and arrays." in a playerpref or do you have to save it in a .txt file ?
     
  2. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    Wait wait, I use to preff playerprefs from local saves, but you shouldn't be using it between scenes. It's used for save data when the game is closed and opened later.

    Just you should find it as any regular script, only you can get it refered via inspector since it doesn't exist in the next scene. You should have a singleton/multiton pattern or somewhere stored it to address it through scripts.
     
    Last edited: Nov 18, 2020
  3. LetmeDwight

    LetmeDwight

    Joined:
    Apr 9, 2020
    Posts:
    125
    I have a counter that counts the npcs i killed, if i change the scene to a New level, erverything will be gone because the counter is a object in the hirachy list and habe a script as componment. But if i make a dontdestroyonload on the counter object, how do i acsess it if it is in the dontdestroyonload list?
     
  4. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    As i said you, via script. Any DontDestroyOnLoad gameObject is accessed as any regular one, just you can't refer it since it doesn't exist before the scene start, it's from another scene, so you can't have it attached to each gameObject on the new scene though inspector: Just try something like this:

    Code (CSharp):
    1. public class NPCKilledCounter : MonoBehaviour
    2. {
    3.     public static int Amount { get; private set; }
    4.  
    5.     public static void Add() => Amount++;
    6. }
    If your members are static you can refer it without to have any instance addressed:

    Code (CSharp):
    1. public class Enemy : MonoBehaviour
    2. {
    3.     //or your regular Kill method
    4.     private void OnDestroy() => NPCKilledCounter.Add();  
    5. }
    You just need to call NPCKilledCounter.Add() to add a new killed enemy, and NPCKilledCounter.Amount to know how much enemies have been killed.
     
  5. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    Hey! :)

    Well i wouldn't make everything static just because you want to access it in another scene,

    you do "save/load" between scene changes, lets say you have a Portal and your character walks in
    Scene 1 into it, the moment you want to go back you have to load the Position back again,

    also if you're doing a "POC" then you may want to use "PlayerPrefs" otherwise you want to go
    for something like a Json load/save system,

    depending on the device you also want to go for not only one type of saving since you have to think about phone crashes / phone getting destroyed etc... (local saves are gone) -> you need also somewhere else a storage and so on ..

    small Edit: To access a script in the new Scene , where the new Script is not an Singleton or the variable a static one, you can find the Object or the type of script and access it afterwards
     
  6. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    Well, I wouldn't too. I would make a singleton but since seems to be a score counter field and I didn't wanted to overload our friend with new information, so i though it would be enough with make it static for now.

    Well, you only have to save/load if something on your last scene should be saved in order to come back. In this case you shouldn't load anything, since the max score comes with you. You may save it for highscores purposes but you don't need to load a vale you've at a DontDestroyOnLoad script. For example, you would need to save the death positions in order to reload the corpses later, but it's not the case.
     
  7. Havyx

    Havyx

    Joined:
    Oct 20, 2020
    Posts:
    140
    This is incorrect. You should not use player prefs to persist data between sessions. Player Prefs is for exactly that... player preferences only, and can be opened (and modified) using a plain text editor.

    Additionally, because of it's location it's possible for this file to be lost or corrupted and therefore should only be used to persist player preferences between sessions.

    Any data persisted with Player Prefs should be data that can be lost without impacting the core of your game (things like screen resolution or the player's language selection).


    Again.... what? Making everything static is a terrible idea. When a variable or method is made static it stays in memory for the entire duration of the application and, therefore, only critical data or global functions should be used this way. I think you mean well but you really shouldn't encourage bad practices.

    So instead you decide to give them bad information? Telling them to use a method you wouldn't use yourself. If you're not going to bother to provide the correct method for doing something then why reply at all.

    Imagine someone saying "how do I paint my house?"

    "Well you can just throw buckets of paint at the walls... I mean I wouldn't do it that way myself - but we don't want to overload OP with information."

    "Not overloading OP with information" is a poor excuse. You should provide the information requested and leave OP to decide if it's too complex to implement (and they can ask for simpler methods/workarounds) instead of arbitrarily deciding OP is incompetent and providing bad advice in terms of implementation.

    The easiest method to persist data between scenes without having to use singletons or DontDestroyOnLoad is Scriptable Objects.


    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [CreateAssetMenu(fileName = "Data", menuName = "SO/Example", order = 1)]
    4. public class Example : ScriptableObject
    5. {
    6.     public int someNumber;
    7. }
    This will allow you to create a scriptable object asset that can be used to persist data between scenes.

    Scene 01

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Scene1 : MonoBehaviour
    4. {
    5.     Example exampleData;
    6.  
    7.     void Start()
    8.     {
    9.         exampleData.someNumber = 100;
    10.     }
    11. }
    Scene 02

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Scene2 : MonoBehaviour
    4. {
    5.     Example exampleData;
    6.  
    7.     void Start()
    8.     {
    9.         Debug.Log(exampleData.someNumber);
    10.     }
    11. }
    No. You should never save data you care about using Player Prefs... the reason being Player Prefs is for exactly that; Player Preferences, and can subsequently be edited using a plain text editor.

    For example, imagine you store the player's score this way. The player could just edit the file in notepad, change their score to 1,000,000 and load the game and their score will be 1,000,000.

    https://learn.unity.com/tutorial/persistence-saving-and-loading-data

    Watch the 2nd half of the video. It covers how to save data to a binary file (one of the correct methods of persisting data between sessions)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Runtime.Serialzation.Formatters.Binary;
    3.  
    4. public class DataPersistence : MonoBehaviour
    5. {
    6.     public int someNumber;
    7.  
    8.     public void Save()
    9.     {
    10.         BinaryFormatter binaryFormatter = new BinaryFormatter();
    11.         FileStream filestream = File.Create(Application.persistentDataPath + "/data.dat");
    12.  
    13.         CustomData data = new CustomData();
    14.         data.someNumber = someNumber;
    15.  
    16.         binaryFormatter.Serialize(filestream, data);
    17.         filestream.Close();
    18.     }
    19.  
    20.     public void Load()
    21.     {
    22.         if (File.Exists(Application.persistentDataPath + "/data.dat"))
    23.         {
    24.             BinaryFormatter binaryFormatter = new BinaryFormatter();
    25.             FileStream filestream = File.Open(Application.persistentDataPath + "/data.dat", FileMode.Open);
    26.             CustomData data = (CustomData)binaryFormatter.Deserialize(filestream);
    27.             filestream.Close();
    28.  
    29.             someNumber = data.someNumber;
    30.         }
    31.     }
    32. }
    33.  
    34. [Serializable]
    35. class CustomData
    36. {
    37.     public int someNumber;
    38. }
     
    Last edited: Nov 18, 2020
  8. rubcc95

    rubcc95

    Joined:
    Dec 27, 2019
    Posts:
    222
    I'm not encouraging anyone to make ALL static. Just it's an introduction of how static works. In my 1st post i said you could use a singleton pattern.

    " I use to preff playerprefs from local saves, but you shouldn't be using it between scenes." => Ok, this is wrong, player preffs is for much more, but not for the LetmeDwight's case. It could perfectly use PlayerPrefs if he wants to save it, but it shouldn't need to load it from player prefs since he still has this int value in the dontDestroyOnLoad instance.

    Just I mentioned Singleton pattern, he answered and I just tryied to simplify the pattern in order to make it easier for a newbie... But I'll try to be more carefully about this practices in order to not encourage anyone to do something wrong from now own.

    Finally... you think to have a single static int stored in ram is more expensive to access PlayerPreffs each time each time you want to get/set this int? It's an int value, each time you make a singleton pattern you're making static the whole monobehaviour, it is not a performance oriented practice, it is used to have a better structure.

    PD: A static method and an instance one it's the same. An instance method is an static with a hidden this argument.
     
    Havyx likes this.
  9. Havyx

    Havyx

    Joined:
    Oct 20, 2020
    Posts:
    140
    I get where you're coming from. I really think it's useful to preface advice with something like "this is the simplest implementation but not necessarily the best" and then maybe explain some of the pros and cons.

    Whilst most of your advice could be used to achieve what OP wants to do... the lack of caveats might lead OP to thinking this is the "standard" way of doing stuff.

    I agree having a few static variables/functions is basically nothing in memory, but if OP doesn't understand what making something static does (in terms of memory use) they might do this with every method and variable because it's "easier" so it can be helpful to say

    "Here is a really simple method.... but be aware of these potential negatives".

    or

    "here is a really simple method... but you should be aware of best-practices which are....."
     
    rubcc95 likes this.
  10. LetmeDwight

    LetmeDwight

    Joined:
    Apr 9, 2020
    Posts:
    125
    Is cheating the only Problem why you should not use playerpref?
    Because if you only make a singleplayer, it is not that horrible because the only person that the Cheater is tricking, is itself...
     
    PraetorBlue likes this.
  11. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    This is a non issue.

    It's also pretty much true for any way that exists for saving game data on the player's local machine. Saving data in a binary format doesn't help this problem in any significant way. If players want to cheat, they will cheat. They aren't ruining anyone's fun but their own. I mean hell, there's tools out there like Cheat Engine anyway. There's no good reason to try to prevent the player from modifying save files.

    The real reason for not using PlayerPrefs is that the API sucks. It's a simple key/value store with very limited data types and no explicit support for Collection types at all.
     
  12. Havyx

    Havyx

    Joined:
    Oct 20, 2020
    Posts:
    140
    True. You might not care about a single-player game and just store this data in player prefs. It really only makes a difference when there is an interactive element.

    - single player game with IAPs (player cheats and gets infinite free money/items)
    - single player game with a highscore (think mobile game)
    - multiplayer game (for obvious reasons)

    It is an issue. I presume you lock the front door of your house, right? Do you lock your car? Because according to your logic - there is no point in trying to secure your house or car because someone could just smash a window with a brick.

    Using binary files doesn't suddenly make your game hack-proof, however, it makes it considerably more difficult to get to the information (opening a binary) and therefore deters a lot of people.

    I guess because people might use hacks to reverse engineer your code there is no point in using any security. This also means I assume you will be leaving the front door of your house unlocked and open.... right? no point in trying to stop people from entering your house when they can circumvent a locked door by breaking a window.

    lol that's an absurd statement as there are many reasons to prevent the player from modifying save files.... You could argue for single-player games it's not an issue but it certainly matters for multiplayer.

    Lastly, this is just one example. There are more secure methods where you can encrypt that data but it's far beyond what OP would be able to implement so there is no point in mentioning it.

    Also you are vastly underselling the complexity of actually injecting new code or modifying that binary data.



    You're still going to have to pawn through memory and stuff which 99% of people aren't going to do... and if you need more security than that it's possible but complex (typically something you might pay for advice/help from Unity themselves through Unity's Integrated Success Services).

    I don't understand the logic of "you can't protect your data 100% so why bother trying to protect it at all". It's still worth it in a lot of circumstances imo.

    A lot of solo devs and indie devs might not bother with trying to secure data but it's certainly something that is important for small studios or multiplayer games (and large, single player games with IAPs... etc like mobile)
     
    Last edited: Nov 18, 2020
  13. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    This is a poor analogy. A user's saved-game data for a game I made is not my house or my car. In fact it's a thing that affects nobody else except that single user in the vast majority of cases.

    You pointed out a few cases where it might make sense to try to secure it. I guess that boils down to games with IAP and games with a multiplayer aspect. Those are some pretty narrow cases with specific needs.

    In fact in the case of multiplayer games it's almost completely irrelevant because the thing in a multiplayer game that you want to trust and verify is not the save data on the player's device but the data that the player's client transmits over the network to your server and other player's games. The real way to secure a multiplayer game is to use a server-authoritative system where the custodian of data is your trusted servers and databases, not the user's game client.

    So that leaves us perhaps with only IAP games. Sure I could see an argument for trying to put some hurdles in the way so that it's easier for the user just to pay you rather than try to circumvent it. But IAP games are a small subset of games. That's a really specific use case. So when you make a sweeping statement like this:
    I'd say never is way too strong of a qualifier. As always it depends on your particular game.
     
    Havyx likes this.
  14. matkoniecz

    matkoniecz

    Joined:
    Feb 23, 2020
    Posts:
    170
    If you design multiplayer game that trusts user to not modify data because "secured" by storing it in a binary form, then you failed.

    It matters only for rare cases of multiplayer games where you try to make modifying savegame outside game more complicated.
     
    Havyx likes this.
  15. Havyx

    Havyx

    Joined:
    Oct 20, 2020
    Posts:
    140
    I will try to take these things into consideration in the future. I spend 99% of my time working on multiplayer or games where data security is important (mobile IAPs etc) so I guess I can be bias when it comes to these things and forget that not everyone needs these kind of measures (another one being sending data to the player via a server so the server acts as an authority to guard the data).

    But as pointed out the people who need this are in the minority so I'll take that into account when offering advice in the future.
     
    PraetorBlue likes this.
  16. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Personally I think all 3 of you are right. Features like achievements and leaderboards are common today in even single player games. That's motivation to want to at least reduce trivially easy cheating to a minimum. The more difficult you make it to cheat, the less you will get, even though you are unlikely to reduce it to 0. Once you raise the skill level required to cheat above a novice level though, I expect you'll get diminishing returns on more investment in this.
     
    PraetorBlue and Havyx like this.
  17. LetmeDwight

    LetmeDwight

    Joined:
    Apr 9, 2020
    Posts:
    125
    I only do this as a free time hobby with developing games. I am also willing to pay one-off prices every now and then when I buy a few assets, but that's completely normal, hobbies also cost money. To operate a multiplayer would be impossible for me, because servers always cost a lot of money! And in my country this is very strictly regulated with making money on the side, which is why I would have to do it full-time with a very high risk of going bankrupt. That's why I can and will only stick to developing games for single-player games. Whether the players cheat and deceive themselves is not their decision? Some singleplayers even have built-in cheats such as GTA 5 or Minecraft e.g. with the creative mode ...