CG-Tespy / FungusSlotBasedSaveSystem_Unity

A replacement for the built-in Fungus Save System that is closer to the standard save systems you see in games.
MIT License
14 stars 3 forks source link

How to use the system across scenes? #12

Closed adrianhm13 closed 3 years ago

adrianhm13 commented 3 years ago

Hello, I'm trying to split my game into different scenes such Main menu, and main scene, how would be the flow to make it work? because I cant set the references of GameSaver to the flowcharts I want to be saved.

Thanks !

adrianhm13 commented 3 years ago

Well in the end I did like this (not sure if its the correct way to go, if not, please tell me which way it's the best to achieve it)

I put the save menu in DDOL, with the Game Loader to load (Menu Scene). Then the Game Saver component in the main scene where the events will occur, the thing it's that to save it couldn't because I cant attach the Game Saver component across scenes so I added if (gameSaver == null) gameSaver = FindObjectOfType(); in the SaveToSelectedSlot function so it can find it when it's gonna save.

Again, I'm not really sure that it's the best way to go so please if it's there any better/clean way just tell me.

Thanks!

adrianhm13 commented 3 years ago

Another thing I'm facing now, it's I didnt realize that when you change scene with public variables, all of them come back to default state.

I mean -> Load slot with values -> Go to another scene -> come back to the first scene -> values are in default again

adrianhm13 commented 3 years ago

Damn, okay I realized that I did a big mess xD, I guess this it's the way to go:

SaveMenu as DDOL, while adding GameSaver and GameLoader to every different scene.

I suppose this it's to find the gameLoader and gameSaver for every different scene from DDOL,

        if (gameLoader == null) gameLoader = FindObjectOfType<GameLoader>();
        if (gameSaver == null) gameSaver = FindObjectOfType<GameSaver>();

The thing it's that looks like it can't be found...

NullReferenceException: Object reference not set to an instance of an object CGTUnity.Fungus.SaveSystem.SaveManager.LoadSave (CGTUnity.Fungus.SaveSystem.GameSaveData saveData) (at Assets/[CGT] Fungus Slot-based Save System/Scripts/SaveManager.cs:367) CGTUnity.Fungus.SaveSystem.SaveMenu.LoadFromSelectedSlot () (at Assets/[CGT] Fungus Slot-based Save System/Scripts/UI/SaveMenu.cs:90)

adrianhm13 commented 3 years ago

Okay, so I solved the previous problem by adding this to the function

LoadSave and LoadFromSelectedSlot

    if (gameLoader == null) gameLoader = FindObjectOfType<GameLoader>();
    if (gameSaver == null) gameSaver = FindObjectOfType<GameSaver>();

It looks like it can't find it when it's invoked in Awake.

Now it's working fine but when I come back to a scene or go to another one the values of the variables come back to the default state. I'm gonna stop touching things until your answer xD

adrianhm13 commented 3 years ago

After a few attempts to make it work across scenes... I see that if I save in scene 1 into slot 1, it creates information about that scene and if a switch to scene 2 and save into the same slot, deletes the info of the previous scene to save the info from scene 2.

Totally lost to make it work to be honest. I thought it would take the information of all the scenes to save it into the file saveData.

CG-Tespy commented 3 years ago

Sorry for responding so late... For some reason, your thread didn't appear in my notifications ^^; So I can better understand your problem, why can't you just have the GameSaver reference the flowcharts you want to save? Also, what's DDOL?

adrianhm13 commented 3 years ago

Sorry, with DDOL I meant Don't Destroy On Load.

I'm gonna try to explain myself better, sorry for the mixed-up messages above.

Using your system with one scene works fine, I can Load/Save and also using the checkpoints to receive a welcome message.

The thing's that now I tried to set up different scenes (it's a sandbox/point 'nd click) which I want to split some new locations into new scenes. So in the first place, I tried to put the SaveMenu with don't destroy on load in the main menu to go across all the scenes and be able to load and save. In every scene, I added the prefab SaversAndLoaders with a correspondent SaveManager linked.

It didn't work so I tried to add SaveMenu's without don't destroy on load to every scene with SaversAndLoaders prefab and the SaveManager.

Now the problem I'm facing it's that when I load into another scene let's say scene location 2, and I save to a selected slot from that scene into slot 1 (a slot with the variable values from the scene 1) this action will override all the values previously saved in that saveData with the new data saved in the scene location 2. I realize about this opening the saveData files located in %AppDataPath (where the save data files are stored)

I saw the structure:

{ "sceneName": "Hospital", "description": "", "slotNumber": 9, "lastWrittenAsString": "2021-03-27T15:59:36.8313961+01:00", "items": [ { "sceneName": "", "dataType": "FlowchartData", "data": "{\n \"sceneName\": \"\",\n \"flowchartName\": \"Flowchart_Hospital\",\n \"vars\": {\n \"strings\": [],\n \"ints\": [\n {\n \"typeName\": \"\",\n \"key\": \"TestHospital\",\n \"value\": 0\n }\n ],\n \"floats\": [],\n \"bools\": [],\n \"colors\": [],\n \"vec2s\": [],\n \"vec3s\": []\n },\n \"blocks\": []\n}" } ], "progressMarkerKey": "" }

So this data will override all the written data from the other scene.

{ "sceneName": "The Diary", "description": "Text", "slotNumber": 0, "lastWrittenAsString": "2021-03-12T18:54:54.5184774+01:00", "items": [ { "sceneName": "", "dataType": "FlowchartData", "data": "{\n \"sceneName\": \"\",\n \"flowchartName\": \"UIActionHandler\",\n \"vars\": {\n \"strings\": [],\n \"ints\": [],\n \"floats\": [],\n \"bools\": [],\n \"colors\": [],\n \"vec2s\": [],\n \"vec3s\": []\n },\n \"blocks\": [\n {\n \"sceneName\": \"\",\n \"blockName\": \"SaveToSelectedSlot\",\n \"commandIndex\": 0\n }\n ]\n}" }, { "sceneName": "", "dataType": "FlowchartData",

I thought that if I save in the second scene, the save manager will store the values of every single scene into this saveData file, not only the information of that scene.

CG-Tespy commented 3 years ago

Ah, now I see the problem. I'll look into it

CG-Tespy commented 3 years ago

Try creating a prefab that you have in every scene, that has all the Flowchart variables you want to have saved between all scenes. Make sure they're all Global. That prefab will serve as a sort of variable database, much like what RPG Maker does. The save system should save and load it just fine.

Of course, this means changing Flowcharts in your scenes to use those global variables, instead of the public and private ones they may be using now.

Let me know how it goes

adrianhm13 commented 3 years ago

Oh, it was really simple, I have chosen to complicate my life xD, thanks a lot. I'm gonna start setting things up.

Being honest I thought the system would work in another way, creating information about every scene as the same it's doing with the different flowchartData from every flowchart in the scene.

adrianhm13 commented 3 years ago

Well in the end I did the next thing maybe it helps other people:

  1. Save Menu/Manager/Writers placed in Don't Destroy on Load, only this instance, you don't need more across scenes, because you will be saving the values from the global variables, later on, you will be assigning this saved values to the regular variables from your regular flowcharts.
  2. Flowchart prefab with all the variables of the game/scenes in Don't Destroy On Load with a letter to be slightly different from the regular/local variables, otherwise fungus will use the global variables instead of the local variables.
  3. In every scene I placed the prefab flowchart with all the global variables with two blocks, so this way the variables global from the Flowchart in Don't Destroy On Load will communicate with the flowchart placed in every scene as global variables too.
  4. the First block Save Global Variables into regular variables. this block will take the values from the local variables and will place them into the global variables something like GPlayerName (G from global) = PlayerName (the public/private variable from your regular flowchart)
  5. Another block Load Global Variables into the regular variables. this block will take the values from the global variable and place them into the regular variable from your flowchart: PlayerName = GPlayerName
  6. The functions of these blocks are to update the information that will go across the scenes but at the same time, this information will be used as a loading/saving function. So for that, you must call these blocks every time you switch scenes or you are going to save or load your game, this way the global values will be updated and the CG Tespy's system will save the variables from the flowchart placed in DDOL, meaning that all the variables will be saved with the updated information.

Example:

Going to another scene: Execute block updating your global variables from the regular ones before switching to the other scene GPlayerName = PlayerName. In the other scene, Execute block loading the values from the global variables into the regular variables. PlayerName = GPlayerName

Saving into a slot: Execute block to save the regular variables into the global ones. GPlayerName = PlayerName.

Loading from a slot: After loading a block with wait until finished to load the global variables into the regular ones. PlayerName = GPlayerName

CG-Tespy commented 3 years ago

I really don´t think it needs to be that complicated; I am using the approach I suggested for my own game, and it works fine. But it is still good to have alternatives

Nairdae commented 3 years ago

Could u elaborate then explaining your workflow? (When you have time, don't worry about it) I'm just curious and maybe I did something wrong cuz I couldn't set it up in an easy way, to be honest. Thanks a lot!

CG-Tespy commented 3 years ago

Alright. First, you set up a prefab with a Flowchart (or multiple nested Flowcharts, depending on how you want to organize things) that has all the variables set to Global. That's the aforementioned variable database. Make sure they're set to the initial values you want.

You then put an instance of that prefab in all scenes where other Flowcharts may want access to its values, and where the player would be allowed to save the game. The main reason for this is to make sure that the save system does its thing correctly with those global values. It's especially important you put the database in the pre-title screen scene!

Why? You see, global vars in Fungus work on a copy-based basis, kind of like a hive mind. To access them, you make your own copies of them; you add variables to Flowcharts with the exact same names and types as the originals, while making sure said copies are also set to Global (otherwise, Fungus will treat them as unique variables).

And said vars are initialized in runtime based on the first copy Fungus finds (which it will treat as the original). For example, if the first copy found of a global int called playerMoney is set to 5, then all other copies will be set to 5. Then, when any particular copy is changed to, say, 10, all other copies will become 10.

That's why you want the database in the pre-title screen; you'll have no other Flowcharts accessing its values, and thus Fungus will treat the database's copies as the originals.

And as global variables carry over between scenes, that's why you don't need DDOL on the database.

I hope this helps ^^ If you have any questions, let me know

Nairdae commented 3 years ago

Thanks a lot for the explanation! I see that in some way it's similar what we did but in different ways xD, you save your global variables per each scene with his correspondent save menu and writers and I do it from DDOL placed in my pre-title screen scene, the only thing it's that I sometimes need to use for example the variable playerMoney (global) and in order to sync it to a public variable so this way it can be used as If/else statements I have to do the step of set the variable playerMoney = GplayerMoney otherwise in my case will not sync. I will try your method in a clean project because maybe I screwed something with the syncing variables xD. Again, thanks for taking your time to explain how you are using it. I really appreciate it!

CG-Tespy commented 3 years ago

There haven't been any further problems in a while, so I'll close this