Search Unity

Loading savegame confusion

Discussion in 'Scripting' started by betaFlux, Mar 31, 2021.

  1. betaFlux

    betaFlux

    Joined:
    Jan 7, 2013
    Posts:
    112
    Hello,

    I'm in the phase of learning about data serialisation, since it's the next goal for my project to integrate a Saving/Loading system.

    Here is my current data structure in a simplified form:
    CellData - For now it's just the current scene buildindex, so a scene is a cell
    CellData.ActorDataArray - A state "register" storing all relevant character data for all actors who arrive in this cell, including the player
    MonoActor - The MonoBehaviour component that every character has
    MonoActor.ActorData - The relevant character data

    After trying a lot of stuff, this seems to be the most convenient way to store cells and actors in my case.

    A bit more info about the game:
    - The game consists of many scenes/cells, just like Skyrim's world, with an outdoor scene and a lot of trigger connected interior scenes
    - NPCs are free to move between scenes/cells like the player
    - Most characters have randomly chosen equipment (clothes, weapons, hairstyles)
    - All humanoid characters have an inventory

    What I'm struggling with is to understand how to load a savegame properly. NPCs, Player, all items, all equipped armor, hairstyles, etc.

    This is how I imagine how it could be done, if a savegame is loaded:
    1. Load the scene the player was in when the savegame was created
    2. Destroy NPCs who don't belong there
    3. Repopulate Player, NPCs from the ActorDataArray from basic character prefabs
    4. Instantiate all physical representations of equipment that had the equipped status of "true"
    5. In the player inventory UI load all equipment sprites and place them where they belong

    Does this seem to be ok or is there a better way to handle data in games like Skyrim?
    May be there is a way that might be better for saving and loading gameobjects and their hierarchies (clothes, weapons, hairstyles)?

    I would be really grateful for any insight, any help you can offer. How do YOU think this would best be done in Unity?
     
    Last edited: Mar 31, 2021
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    It sounds like you have a handle on it based on your list of items above. It really comes down to making your game in a way that it is easy to capture the full state, then restore the full state, and as you said it comes in phases: loading the scene, setting stuff up, loading more stuff, etc.

    And the key point is, every game is going to have subtle edge case requirements.

    I have randomly blathered about it before too, but it looks like you already have all these points down:

    https://forum.unity.com/threads/save-system-questions.930366/#post-6087384
     
  3. betaFlux

    betaFlux

    Joined:
    Jan 7, 2013
    Posts:
    112
    Thanks Kurt!

    This topic really gives me headaches. It also seems that, in a game with a lot of scene loading, singletons and DontDestroyOnLoad objects make things even harder to handle. Singletons loose references, static events have duplicated subscribers. Everything needs to be cleared and re-initialized manually or I'm doing something fundamentally wrong.

    I have the feeling it's better to create the save system first and then carefully build all other game systems on top of it.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    You're not wrong! And you are not alone in this.

    The trouble is that when you come up with your brand-spankin' new "HEY I GOT A GREAT IDEA!" game idea, the last thing you wanna do is think about load / save.

    And if you did, you would get discouraged and your great game idea would die in seedling form, completely missing the opportunity of rapid Unity3D development.

    About all you can do is keep the project and design flexible and refactorable enough that you can rearrange stuff to be compatible with load / save.

    And in any case, who knows what you even ultimately want to save. Do you need to save every bullethole in an FPS level? I guess you could... but I've rarely seen that done. There's just no value to the player.
     
  5. betaFlux

    betaFlux

    Joined:
    Jan 7, 2013
    Posts:
    112
    Yes, it's really troublesome. Now that I do, there is so much to re-evaluate and all the Unity start functions are a nightmare to handle.

    I wish there was a way to completely control the exact initialization process manually, by a single function call that calls everything else in a nice, tidy manner. I'm sure there is a way, but to find it I have to do more research.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    Load/Save engineering is in no way complicated by Unity.

    In fact, Unity has extremely clear lifecycles, dictated by the lifetime of scenes and Components on GameObjects.

    Remember, Unity is just GameObjects with Components, organized into Scenes and Prefabs, with Assets plugged into them. That's it. You get those things set back up properly, the game will continue without a hiccup.

    Here is some timing diagram help:

    https://docs.unity3d.com/Manual/ExecutionOrder.html

    It's just any other kind of engineering, one that could cut across your entire project.
     
    betaFlux likes this.
  7. schwmm

    schwmm

    Joined:
    Oct 20, 2020
    Posts:
    62
    What I found helpful is that Awake(), SceneManager.sceneLoaded and Start() are being called in this order, so at least you have 3 "tiers" of calling functions and setting things up.

    On a side note - and I hope I am not hijacking this thread - but is it generally a good practice to make the save / load functions (serialization + saving / loading from disc) a coroutine? I am thinking if the hard drive is busy / slow, could it crash the game if this function is not called as coroutine?
     
    betaFlux and Kurt-Dekker like this.
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    I would NOT reach for a coroutine for saving. You are saving a very specific state of the game at a very specific point in time: grab all that data, write it to disk and move on... if something crashes it will NOT be because of it being a coroutine or not.

    Remember what a coroutine is: it runs on the main thread and code within it is no different than any other code.

    https://forum.unity.com/threads/des...en-restarting-the-scene.1044247/#post-6758470

    https://forum.unity.com/threads/proper-way-to-stop-coroutine.704210/#post-4707821
     
    schwmm likes this.
  9. schwmm

    schwmm

    Joined:
    Oct 20, 2020
    Posts:
    62
    Thank you very much for your reply - the linked explanations regarding coroutines are also very helpful. They explain the cause of another issue I faced a while ago, when a coroutine wouldn't return properly because I deactivated the script calling it after it's first iteration.
     
    Kurt-Dekker likes this.
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,744
    This one is particularly vexing to me: when you set a GameObject to inactive, any running coroutines on all MonoBehaviors on that GameObject actually DIE, they don't just pause execution: they are toast forever.

    That just seems... wrong.

    Another weirdness is that disabling the MonoBehavior that the Coroutine is running on does NOT stop coroutines running on it... it doesn't even pause their execution!

    But once you know these quirks, coroutines can be useful for sure.
     
  11. betaFlux

    betaFlux

    Joined:
    Jan 7, 2013
    Posts:
    112
    I agree. I rather meant the way I set it up without considering serialization kicks my butt now. I sprinkled everything across all possible Awakes and Starts besides custom Init functions and it worked somehow. Now I'm left with a half baked code base that's missing a vital organ. Time for some surgery!

    The site about "Order of execution" is really helpful! Thanks!
     
    Kurt-Dekker likes this.