Save / Load your game (Quick + In Depth Tutorial works on all devices including browsers)

Link to project file if you care to study it

Quick Tutorial

For saving/loading variables

Saving

This is for users who already did some stuff in gdevelop
Event

Action from above event
Be sure to pick Save a text

Loading

Event
*! Add TempSave variable in scene variables window

Actions from above event
Be sure to pick Load a text NOT a value

Be sure to pick Convert JSON to variable NOT object variable

You can test it here

Click here to learn how to load at beginning of the scene (Auto load)

And here how to create save data if save data don’t even exist
And how to load save data if it exist both at beginning of scene

And do the same but for key pressed (Could be done with button press)

In at beginning of scene variant we wait 1 sec in action 1st if save don’t exist to let variables from variable window load 1st then we perform a save

In e key pressed variant
We simply set these variables to some values then perform a save if save don’t exist

In both cases if save data exist or to be accurate if MyGroup exist in MyStorage then data will be loaded into variables

This is enough if you know what to do
If not then what is below is for you

Common mistakes

Read this before you come to me asking why it is not working
Double or even triple check have you done it correctly

Click here to read about most common mistakes
  • Putting “quotes” when you should not
    Pay close attention
    image
    Save action have ToJSON (Name of Global variable to save) then “group name” in quotes and “storage name” in quotes
    Load action have 1st “group name” then “storage name” in quotes then scene variable without quotes
    While convert to JSON have both scene variable and Global variable you are loading without quotes

  • Temporary scene variable gives you error? Add it in scene variables window

  • PAY CLOSE ATTENTION to names i am dyslectic i have no shame in it
    Yet i tend to write Stroage instead of Storage
    1 character missing or in wrong place can ruin here everything

  • Did you put storage and group names in proper fields?
    Same for variables
    To help you look at this pic again
    image
    In order from left to right top to bottom we have
    For SAVE
    ToJSON(Global variable you save) expression then GROUP NAME then STORAGE NAME
    For LOAD
    GROUP NAME then STORAGE NAME and Temp scene variable
    Temp scene variable then Global variable you load
    Or maybe this will help you
    image

  • Did you select Save/Load a text and NOT value?

  • Using WAIT action for saving or loading
    DO NOT DO IT
    I did it only cause its at beginning of the scene to create system where your vars will not be set to 0 and you don’t need to set your vars in actions before loading
    So their default values will be loaded from variable window

  • Issue with wait action is
    IF you have condition button clicked and action wait 1 sec then save
    Like here

  • Then if you click 3 times fast it will wait 1 sec from each click and save
    So if you spam that save button you have fair chance to corrupt your save data
    While if you would go with timer like here

  • Then clicking it resets it to 0 so even if you keep spamming it as fast as you can
    You are NOT gonna execute save action multiple times cause you did not let timer reach that 1 sec value
    That is why DO NOT use wait action in save/load events unless you absolutely know how/when to do it
    Go with timers instead or other means
    If you still don’t get it
    Think of it as wait action is throwing ball of stairs
    You can’t stop it
    Now resetting timer is like having little dog or cat
    And they wanna go away from you to your plate and eat your food
    And you are pulling them back to you
    So as long as your pet did not reach your plate your food was not consumed

Useful tips

My best practices what to do and what not to do when managing your save / load events

Click here to read some tips i have for saving and loading
  • Do NOT name your storage the same for every game
    Cause if you gonna delete save to see if it works
    You gonna delete it for all projects you are testing since storage name for them are shared
    We are talking here about testing games in your gdevelop and in browser
    I go with GameNameStorage
    For example i made game called Expand When Four
    So i go with EWFStorage instead of MyStorage or just Storage

  • I would also suggest giving your nickname as prefix to storage name
    For example ZeroX4EWFStorage
    Cause if someone would follow this tutorial and made game called Even With Friend then he would name his storage EWFStorage so it would create shared storage for both our games (that is for ones played in browser)
    So after you get familiar with saving/loading storage you could forget about Storage suffix and just go with NicknameGameRelatedTag in my case ZeroX4EWF or any unique name i could go with 0104EWF
    0 zero 10 roman ten so X and 4 well four and here goes my nickname
    Even ZX4 would do or X4
    But again that is case just for browser games i believe
    And chance other person make game with same name of storage is slim
    YET not impossible
    Better to avoid such situation than be sorry for lost save data

  • When you separate your game save from your settings save
    Use group name as means to decide what you save/load and when
    While splitting stuff you save/load into separate structure vars
    For example


    Here i split game progress (game save) and settings save into two structure variables
    So saving settings and game progress is independent and don’t affect each other
    Now i could go with GameStorage for storage name and two groups
    SettingsGroup and GameGroup for group names so i could go with

    And so in 1st event i save each 10 secs (where 1st save starts at 5 sec) my game progress (Yeah i just made auto-save)
    TimeFromStart() is counting time from scene start
    modulo expression is looping that number around whatever you type there i did 10
    But it does not go 1 2 3 4 5 6 7 8 9 10
    Nah it goes 0 1 2 3 4 5 6 7 8 9 it starts from 0 not 1 where in both cases we have 10 numbers
    So checking if its greater than 10 would be stupid cause it will never reach 10
    (That is why i check if its greater than 5 i could check if its greater than 1 or 8
    Well i could check if its greater than 9 also
    BUT NOT from 0 cause it is always greater than 0 so condition would never return false)
    So 1st save is performed after 5 secs and then any following save is performed in 10 sec intervals

  • !!! DO NOT !!! Try to spam saving cause it can corrupt your storage and you can kiss your save bye bye
    If you don’t need to save often then don’t
    Saving each 10 sec is ok
    But if someone get idea to save every second then that is just dangerous for your save data

  • Since we are using different names for groups we can target which group we want to delete
    For example delete game progress which won’t affect settings since they are stored in different group


    But if you wanna go all out on it there is action to wipe out whole storage

    I added to my project that pressing space delete whole SLStorage

  • If you need to delay your save / load anywhere else than at beginning of scene
    DO NOT USE WAIT ACTION use timer or TImeFromStart() in compare two numbers condition if you know how to handle it
    WAIT action is asynchronous so if you press save button 2 times fast
    Game will try to save it 2 times after that WAIT time
    And so you are open to corrupting your save data
    Timer or TimeFromStart() would never have such problem
    YET TimeFromStart() is more tricky to set up
    Cause you would need to set variable to TImeFromStart()+1
    And now check if variable value is less than TimeFromStart()
    For example at the moment of when you click save button
    TimeFromStart()=5 if you go TimeFromStart()+1 it will be 6 while actual time IN THAT MOMENT is still 5
    And you set that variable to TimeFromStart()+1 so you did set it to 6
    And you have another event to check if your var is less than TimeFromStart() then only after it will be +1 sec from the moment of when you click save button
    Save would be performed
    Exactly like here

  • Doing exactly the same thing but instead of setting var to +1
    We check if var is less than TimeFromStart()-1

  • I show you this just so you could get the idea how it works
    It is confusing at 1st but can be used for A LOT of things

In Depth step by step tutorials

Saving/loading variables

This is for users that are totally lost and have 0 idea what is what and how to do it

Click here to read step by step in depth tutorial
  • 1st of all you are not saving your game state nor does you are saving your game like making snapshot or screenshot of what you have at the moment
    You are saving and loading variables
    Then changing stuff to these variables so for example
    You set your sound to be played with volume of 100
    Instead you set your sound to be played with variable SaveGameVariable.VolumeSound
    And now you only change that variable from 0 to 100 to play it with different volume
    But if you want to save it you just save SaveGameVariable and then load it
    Instead of each individual variable

  • Next thing to address you most likely want to save global variables which are structures
    Global variables cause they exist globally in your game so like between scenes
    Think of it as your PC master volume it will affect every sound in your PC
    Where if you change sound on youtube it will affect only sound on youtube
    And only on your account

  • What are variables?
    Think of them as price tag
    image
    It is nothing else than just container of some information
    I can slap price tag on you and write on it $100 so you will be worth 100 dollars
    And when going shopping i can tell you to buy only stuff that are not more expensive than $5 (so you can’t buy yourself)
    So you can check price of each product and check if its lower higher or equal to 5
    Same exact story with variables
    Just for number vars you can do equations with them for example
    Player.HP+20 when you collide with healing item will add 20 to your player variable HP
    Where text variables stores text so you could save like player nickname in it or whatever
    And adding text to text var like adding 2 to 4 will end you up with 24

  • Why structure?
    Imagine having folder with your player images like 50 of them
    Wanna copy/paste them from one folder to another 1 by 1?
    No? So how about copy/paste whole folder?
    And that what structure variables are like a container
    You shove in your vars under some structure variable and only save/load that structure variable instead of each individual variable
    Or to put it simple
    If you save/load structure variable (or array)
    It will save/load all its child variables
    So exactly as you would copy paste folder

  • Step 1
    Let’s create some Global variable and call it SaveGameVariable

  • Open project manager panel in upper left of gdevelop
    image

  • Click Global variables and now add new variable call it SaveGameVariable
    It could be named anything but just for sake of simplicity UNTIL you learn what is what in these event let’s go with that
    Change it to structure
    And add to it child variables which you care to save
    I will go with 2 child variables called PlayerPosX and PlayerPosY


    And this will be used for game progress save

  • Step 2
    In your events sheet add event for when save will be performed
    For me it will be when Q key is pressed
    And i gonna add to it trigger once
    Saving SHOULD NOT run every frame but only once when condition is true
    Spamming it may corrupt your save data
    Next you will need to give name to your group and storage
    I gonna name mine SaveGameGroup for group and SLStorage for storage
    I suggest naming your storage with something related to your game name
    For example i could go with SaveLoadStorage
    But not to confuse ppl i went with SLStorage as in Save Load
    This way if i work on multiple projects i will not affect storage of other projects
    While not affecting games someone else use storage for with same name if i run games in browser

  • Pay attention here to select Save a text NOT a value

  • Because i want to save Player position
    I also need to 1st set Player position to variables BEFORE i perform my save
    And this would do it

  • Now i wanted you to see it with your own eyes
    On purpose i did choose so long name for my save variable
    Look how long it is in action itself
    This is perfect moment to use your brain to come up with shortest names possible
    Cause right now its one child variable so NameOfStructureVar.NameOfChild
    What if you would have multiple structures under structures?

  • I could totally go with save name like Save or even Sav
    But trust me keep it this way FOR NOW
    Just so you can learn where is what
    When you master this stuff you can rename it to S for all i care

  • Step 3
    Now for loading
    Event

  • And actions used in it
    Be sure to choose Load a text NOT value

  • And here Convert JSON to a variable NOT object variable

  • If variables you saved are some stats like HP variable or Score variable or LevelUnlocked vars then this is all

  • BUT if like me you saved your player position NOW you need to change your player position to variables you just loaded

  • Change position action will do the trick here
    So in my case it will look like

  • Pay attention that above when i was trying to save player position
    1st we had actions for setting player position to variables
    And BELOW it action to perform actual save
    Here we 1st load it then change position to variables
    Because in gdevelop all events are read from top to bottom
    So order is here crucial

  • Now how about we check does Q saves position of Player while E loads it?
    I made small example here
    So you can test it out
    There are bricks around player so move somewhere and use bricks as your reference to where you are
    Press Q to save move somewhere else and E to load
    Or just move somewhere press Q close example and open it again then press E

  • WASD or arrows to move around and well Q and E to save / load
    Save Load Example | Play on gd.games

I say it works pretty fine

Loading sound/music volume at beginning of the scene

And saving it while you change volume with sliders

Click here to learn how to save/load volume using sliders
  • 1st we gonna add new structure variable called SaveSettings
    And add 2 child variables to it
    Naming one VolumeSound and other VolumeMusic

  • We need 2 sliders one called SoundSlider and other called MusicSlider
    There is no need to change anything
    I went with duplicating same slider and putting Sound on the left and Music on the right
    Design tip
    It would be cool to have text object above them explaining which is which
    Of course you can move them to hear which volume will change
    But it should be obvious just by looking at them

  • Anyway look at this black magic

  • Wanna bet it is ultra stupid? And more simple than you can imagine?
    Let’s read it from top to bottom

  • At beginning of scene
    1st sub event we check if SaveSettingsGroup DO NOT exist in SLStorage
    And if it does not we wait 1 sec
    Set our volume vars to bar values and create save

  • 2nd sub event we check if SaveSettingsGroup actually exist in SLStorage
    And if it does we load variables from storage
    And we change value of each slider to our volume variables
    (To clarify this sub event CANNOT run if 1st sub event did kick in
    Cause they are checked almost at the same time while 1st takes action 1 sec later
    So 2nd sub event will never be true if 1st was true cause 1st will become false 1 sec after it was detected of being true)

  • 3rd sub event we are playing music with play sound on channel action
    (Pro tip - play sound on channel action for playing music
    Play sound action to play sounds)
    Instead of providing volume number we are just typing there our variable
    And we are setting loop to yes so it start playing again after it finishes

  • SoundSlider is being dragged (TIP it actually checks if its pressed and not dragged so you can click and hold it)
    So as long as its pressed/dragged we are setting our sound volume var to value of this slider

  • In sub event we are using condition compare two numbers (that is its name)
    To check if mod(TimeFromStart(),1) is greater than 0.5
    Your game by default is counting time from scene start
    Think of it as native timer for each scene that is running
    If we use modulo expression MOD it will loop around whatever number we specified
    So if we put there 1 it only checks its mili seconds so from 0 to 0.9 and then it loops back to 0
    We check if its greater than 0.5
    And if it is with trigger once we play sound
    So when dragging this slider each half second you can hear sound so you have audio indication what actual volume level is
    And in play sound action we did not specify volume by number
    We did just put there our variable name so volume is set to that variable value

  • For clarification Play sound ON CHANNEL allows you to manipulate sound volume on that channel at any time
    While Play SOUND action only allows you to change volume of sound with which it will be played
    So after sound starts to play there is no way to change its volume
    Think of it as flying a drone vs throwing a ball
    When you fly a dron you can adjust its speed at any given moment (This is how play sound on channel works which should be used only for MUSIC)
    When you throw a ball with some speed you can’t change it
    As fast as you throw it that fast it will fly (This is how play sound action works which should be used to play your SOUND)
    And main reason is you can’t play more than ONE sound at a time on ONE channel

  • If you don’t understand what channel identifiers are (I did set my to 1 as you see)
    Its like variable that allows you to refer/identify in events this specific channel
    Literally imagine it is variable to which i just give value of 1
    Same as tween identifiers
    Or same as giving your object names
    You can tell which object is which just by its name and in events reference them by their names
    Here instead of names you have numbers

  • Next one is Music slider being dragged
    So as long as it being dragged/pressed we are changing our music var to to value of our slider
    While 2nd action is there to actually change volume of our music played on channel 1

  • Pay attention here since we had in event above to play sound on channel (our music) with volume of our variable
    We here are changing volume on channel to value of same exact variable

  • Here we have OR statement (If one of these conditions is true)
    To find it in conditions add condition and type OR in search bar then just add it
    What it does is check if at least ONE condition listed in it is true
    IF so it executes action
    And here i wanted to show how to use timers
    We are constantly resetting timer when at least one of sliders is being dragged/pressed (So its like setting it to 0 constantly as long as you hold it)
    So when we release it it starts counting time

  • And in last event we check if value of this timer (or if its time value) is greater than 1 sec
    And if yes we are performing a save and then we delete this timer from memory
    Idk if timers running forever affect your game but i know there are ppl
    That are sick about anything running when it does not need to
    So let’s just delete it
    USING Trigger once it is very important here
    Cause whole idea of this event is NOT to allow save spamming
    We just created AT LEAST 1 second gap between saves
    So clicking it will not allow it to be spammed
    While save will be performed 1 sec AFTER last interaction with slider
    And interacting with slider before that 1 second is reached will result in timer being set back to 0

  • So was it so much black magic after all?

  • Try it (Change volume with sliders and reload page)
    Save Load Example | Play on gd.games

Save/Load ALL your objects

Let’s go with something harder like creating fake save state of your scene

Click here to learn how to save your objects and their attributes

Screenshot for users that know what to do and are here just for events setup

  • I followed this tutorial from official gdevelop youtube channel
    https://youtu.be/9ReOBFoSD3g?si=em0aX62PSVJzSKql

  • What is below is same as in the video above
    Just with new variable system
    And explaining few things you should consider when doing such save/load system

  • I added hidden feature to my project which is different modes

  • You activate and switch modes by pressing Middle Mouse Button (MMB)
    I put all my building items and enemies in AllObjects group

  • All slimes have variable called HP

  • I added SaveAllObjects var to my global variables and changed it to array
    It have NO child vars


    And here 1st thing to consider
    Since to use object group variables you need to add it to all objects
    I added HP var to group AllObjects meaning all of them have now this variable where only enemies need it
    So this is the part that will hardly vary depending on your game
    BUT in most cases it won’t matter if you give empty vars to your objects

  • So let’s save everything

  • So let’s break it down (Again black magic)

  • What is in red rectangle is limitation for when you press any button Save/Load/Del so they can’t be pressed again for at 1 sec
    And this is NOT part of save/load system but something i added cause i wanted to prevent spamming and it to look better

  • Going from left to right top to bottom
    1st we have condition ButtonSave is pressed (i am using button state behavior just add to your object behavior and type button in search bar)
    So it checks if its interacted with (and that works perfectly for touch and mouse controls and nothing needs to be add here)
    In action we clear ALL child vars from our global array variable

  • 1st sub event is repeat for each object instance
    To add it right click any event or + in upper right corner of gdevelp and go to Add and then For each objectimage

  • In object name we put name of group of objects we want to save/load
    And in which we placed all our objects we wish to save/load

  • Leave conditions section empty

  • In actions section we are adding variable for each of our object to array as new child variable
    So each action is this one

  • And repeat it for all attributes we care to save (so add new child variable for each one)

  • Next we have loading by pressing ButtonLoad
    We are setting scene variable Climb to 0 (Climb is just number scene variable i added)
    Delete AllObjects group to delete them all
    Also i added here delete HPBar cause they are created dynamically and does not automatically get deleted by just deleting slimes but only by their HP variable going below 0

  • Now sub event which uses repeat event type and to add it
    Again either right click any event or press + in upper right corner of gdevelop
    Choose Add then Repeat
    image

  • In how many times to repeat it we use expression VariableChildCount(Name of our array variable) / how many variables actions we had in repeat for each object event above (save event)
    So since we are creating 7 child vars then it will be /7

  • Condition again empty but in Action we have
    1st we click add action and select our AllObjects group (groups are always on the bottom of object list)

  • And we gain access to new action called Create an object from its name
    And here we type SaveAllObjects[Climb] where SaveAllObjects is global array variable i use for saving/loading and Climb our scene var

  • 1st we have that SaveAllObjects[Climb] meaning we are putting here 1st child var from our array
    Then or X position of our object SaveAllObjects[Climb+1] so we are taking 2nd child var here at index 1 and then Y pos we get SaveAllObjects[Climb+2] so 3rd child variable at index 2
    Next we repeat it for Z order with SaveAllObjects[Climb+3]
    Opacity with SaveAllObjects[Climb+4]
    Angle with SaveAllObjects[Climb+5]
    HP variable with SaveAllObjects[Climb+6]
    And here we are adding 7 to our climb variable
    So next object will get next 7 set of child vars to it
    In same order it was saved
    So next name given to 2nd object will not be form 1st child but from 8th (which is child at index 7)
    Where next X pos will not be from 2nd child but from 9th since 7+2 = 9 (So again it should get 2nd child at index 1 but since we just add 7 to climb it will be 9th child at index 8 and so go on)
    Something important here to address
    Order of actions in which you save child vars
    Needs to be the same as order in which you load them (not actions but Climb+Number)

  • What i mean is if in save event 4th action was to add child to our array with object Z order
    Then in load event it does not matter what will be position of Z order change
    action but it does matter what number it have in SaveAllObjects[Cllimb+3] meaning it was 4th action when saving and now loading 4th child variable which index is 3
    It could be 2nd or last action
    But it would need always be +3 since it was 4th child we added
    BUT 1st action always needs to be create object (like top most action)
    So we are shoving in all other informations from variables to object that already exist

  • OK and lastly we have here delete button
    It is just delete action to delete all objects on scene which are in AllObjects group
    And again i need to manually delete here HPBars
    So now you can go to build mode paint something or in attack mode spawn slimes and delete them all at once if you don’t like their positions or whatever

  • So now we can place some objects in build mode with LMB then change their opacity with Z or angle with X
    Spawn some slimes in attack mode with RMB then damage them with LMB and click save button
    Now delete button to remove them
    Then we can click load button to load them and see how all attributes we wanted to save are saved and properly loaded

  • I wonder what would happen if i would add save/load storage from previous part of this tutorial here?
    Damn i think i did

  • Again gdevelop read stuff from top to bottom
    So 1st we save our info to array then perform storage save
    And in load we 1st load var from storage then load stuff from var

  • And that is pretty much it for saving and loading all objects
    Again does it still feel like black magic?
    Let’s test it (Press MMB and use Save Load Del buttons)
    Save Load Example | Play on gd.games

  • Something to pay attention to
    Look closely for what you are writing here and in which order
    Like does some actions are not above others and it looks now different from my tutorial
    Also does it is X pos then Y pos and not X and X pos two times
    OR 1st Y pos then X pos
    You think i am so smart? Yeah i am making this tutorial i for sure did to eat all brains and am so smart i could fart in frequency of PI number
    Well let’s see how it went for me when i was doing this save all objects for the 1st time
    [SOLVED] Save/load stuff from arrays while using child index

  • We ALL make mistakes have no shame in it
    We are here to learn something and its better to ask stupid questions than stay stupid (well did not work for me i am still stupid)
    If it does not work seek help either here or in gdevelop discord help channel
    Where most likely you just made some stupid mistake like i did

Saving timers between scenes

This will be ultra easy

Click here to learn how to save timers between scenes

It will work for any kind of timer
But just for this tutorial i went with countdown timer
We are counting from 100 to 0

  • I made global variable called it SaveTime and left it as number variable

  • In events this is all you need to count down running timer

  • We change text of our text object to ToString(roundTo(abs(TimerElapsedTime("CountdownTimer")-0.01-100)-SaveTime,2))+" Change Scene ->"

  • Just to clarify while i am counting down to 0 if you would let timer run in elapsed time to just count time as it goes then you would + variable instead of - variable so it would look like
    ToString(round(TimerElapsedTime("CountdownTimer")+SaveTime))

  • Where in counting down roundTo is rounding our number so we don’t get 99.0000000000
    abs is Absolute number so even if its negative -Number it will display it without minus
    TimerElapsedTime displays our timer
    -0.01 will make it stop at 0 and not 0.01
    -100 is from how much we are counting down so without abs we would go from -99 to -98 then -97 and so go on so again abs just removes -minus sign
    -SaveTime so we are subtracting any possible value of our global variable from timer itself
    And lastly ,2 is roundTo 2nd decimal digit so we are getting 0.00 not 0.000000000
    And Change Scene → is there cause i was too lazy to make button for changing scene so i used text object as button

  • Now when that text object is clicked we 1st save timer value to our
    global variable and then we change scene

  • And what we need in other scene for it to work?
    Pretty much same thing


    We just change scene back to our main scene here

  • Where in both cases whole magic is that timer is untouched
    We are only adding timer value to our global variable
    And we are displaying value of our timer - our global variable

  • Technically you could save this global variable to storage
    And now you can save game progress mid mission/level while some timer is running

  • Let’s see if it works (Press MMB to get to normal mode and follow instructions)
    Save Load Example | Play on gd.games

Dee Ent

4 Likes

What i noticed is that you use the wait action before saving and in at the beginning of the scene only (while i use wait even before loading and saving in any conditions).
but only when there is a condition in the game that doesn’t involve overloads…like in an empty room,save room ecc…

I’ve always wondered if it was the proper ways to do it…since the asynch timer.

To me it’s like to give the time to read and load all values before doing something,
but i honestly dunno if it’s really needed.

Anyway good tutorial, imo
a tutorial thread sections should be opened and separated by all the others so everyone can find what needed easier.

If save do not exist we wait for variables to be loaded from variables window
I doubt it needs more than 0.01 sec
But just in case we are going here with 1 sec

In chronological order what is going on

1
Save data do not exist in storage
1st sub event kicks in
Wait 1 sec for default vars from variable window to load and perform a save

2nd sub event will not kick in since save data did not exist at beginning of scene
So there will be nothing loaded

2
Save data exist in storage
1st sub event will be skipped
2nd sub event will kick in cause that data exist so lets load it into var

So basically this configuration is there only for NOT setting your default vars to 0
And NOT requiring you to do this

Where you would need to set all default values in actions instead of variable window
If there would be no wait action then you would need to go with setting default values for vars via actions same as in picture above

And thx i gonna shove in here a lot more
BTW i like your idea about separate section for guides/tutorials

IDK why you waste time suggesting it here instead of going to feature request section with it

Yep these are the right steps…i’m just saying that ppl should not save a la Save State (like emulators do) in situations when there are too many things going on…In my game to be double sure that this not happen you can save just in empty rooms,save room ecc and even so i added a wait action before doing it (since you can for eg add a save animation, effects ecc…)…But… this has nothing to do with how to save/load which u explained perfectly, but it’s more on how i prefer when to save in a game.

hehe…you know what i think…some request looks so natural to me…that i prefer to not disturb moderators with superflual things…cos imo there is always something to works on that needs priority…

1 Like

Ow
That wait action is only there because its at beginning of the scene
I would not use wait action for saving/loading after at beginning of scene
Actually damn you i gonna add it to common mistakes and tips section

And as for feature request
Moderators are here to be distrupted
Feature request section exist there to be used
And not for you to feel bad for throwing your ideas
You should not worry

1 Like

I’ve an example that happened to me.

I’ve an item menu,… there are various things inside ,slot, items, text ecc…and it is hidden.

I’ve an action that for example move an item in a precise slot and when that item is at that position a var check the equipped item…this happen in milliseconds.

For debugging purpouse iv’e volountarily created a situation where a save happens between that and if u save before that, you gonna load that item in unwanted position and (at least in my game ) it gonna bug everything…thaz why i prefer the wait action before a save.

Now i wanna know why you need to save when placing items?
When i have settings for example (in your case i assume its inventory or something like that)

I perform save upon clicking open/close settings button (which are same button with different animations)
And NOT on every instance of interacting with settings since that would be risky

and you’re totally rite, in fact you can’t save if the menu is opened…
but i forced it on purpouse to see what happen and in fact it happened…and i don’t want it to happen…never…call me maniac…but this is how i debug.

Ofc i’ve setted up everyhting as you said

to be more precise: (this is not my case but) eg…if you close a menu and spam x for eg to save it may happen (in rare situations) that a position is not still reached bcs your inputs are faster…

1 Like

And i say this is perfect
So everyone can learn
Sometimes you need to burn yourself to learn not to put your hand into fire despite everything in the world telling you that its bad idea

I think i gonna add (as example) some soft lock to not let spam save/load
Come here with more ideas and suggestions
I am all open to it

Those are reeeeally rare situations…
cos at least if you’re not play like a kid spamming s…t everywhere (…lol) it will hardly happen

You should visit gdevelop help channel on discord more often
And you will start to believe some ppl are need to be told constantly that checking if there is electricity in the house with fork is bad idea

1 Like

Hi, thanks for the tutorial. In the past, I’ve created many save systems and never had any major issues (in my games, saving only happens at specific times, and there’s minimal data).

However, I’m quite concerned about save files getting corrupted, especially if there have been in-game purchases. I created this system to ensure a bit more security. What do you think?

1 Like

From what i did read in your post

You had pretty good idea
Make temp save then use it as saving measure and not go directly for saving into actual save file

And i wonder if there would be any better way from yours other than just multiplying what you did

Look best solution would be to save in multiple ways
To storage to text file to whatever else
But not all devices supports it especially android when it comes to gdevelop

So sticking with storage
I would simply create 1 temp save
Save it 3 times to different storage or group
And compare it against each other are they are 100% 1 to 1 copies of themselves

And i would guess this is how saves on old consoles did work
When you seen message “saving please don’t turn off power”
And it took like 3-5 secs
It was not saving all the time it was comparing copies of saves it made against each other before accepting that what was deployed was in fact proper save

Don’t BS yourself you can’t fight data corruption
Too many factors beyond your control can cause data corruption
And all you can do is only try to minimize possible corruption
I would say creating 3 saves one by one then checking are they are exact copies of them selves would be enough
You would have one save you will use and 2 backup copies you could use

Going for anything beyond that having only one means to save would be stupid in my eyes
Like you can buy 2nd keyboard in case your current keyboard will get broken
But buying 5 just in case?
Unless there was some supper extra deal or high discount it would just be stupid

2 Likes

Thank you for the response. I didn’t know that old games used to compare data in save files. It’s a great idea, and I’ll definitely consider it among the possible alternatives.

I replied to you yesterday and it is still waiting approval


Anyway that is all from my side by now you should have better idea what can you do and should you do anything more above what you already did
GL

In fact idk if that is how they work
It is easy to check i bet it is easy to find some info most emulation sites or even on romhacking.net

YET i heard more stories that for some games (with built in batter to save data or memory card when it comes to playstation) that they can’t save anymore even after replacing battery

Where i heard only few about each save becoming corrupted

So i assume there is check while saving and then check while loading
Where check in loading is more of checking if there is correct (not exact) value in each place

For example you save player X and Y pos
So you check if variable holding it have some number and not text
While also checking does every single variable/position did in fact store some data
Where you would never leave ANY information by default as 0
For example change it to variable-1
So when you create save all stuff that is 0 by default will have 1
And so in loading process you simply subtract 1 from each value
And that is how it verify does save data was corrupted

While sole message that saving failed proves that there is a check when saving does saving was done properly checking copy against copy

So i say if you really want to get some practical knowledge better go to some emulation site or romhacking
And you will find how saving was done when dinosaurs still ruled this planet
I mean you at least gonna get some old new ideas what you can do

1 Like

Thank you for the information, really useful. In my post, I also attached the answer I found on ChatGPT 10-Preview, which suggested creating a temporary file that is then checked and finally overwritten.

This might work on PC, where saves are on external files, but on Android (from what I understand), saves are internal, so this approach isn’t feasible.

Corrupted saves seem rare in GDevelop, but if a simple and more secure system could be found, I’d include it without hesitation.

Maybe an extension in the future?

1 Like

Saving to different format won’t SAVE you
You are still open for data corruption so it does not really matter how you gonna save but how you gonna check save integrity

If your data that you care to save change real time
Then as stupid as it sounds
You should have 2 or 3 save slots
Where you have 2 choices for approaching comparing

In both cases you would use different storage name to perform save
For example MyStorag1 MyStorage2 MyStorage3
Also in each case you create separate TWO temp variables TempVar1 TempVar2 with whatever you want to save just to compare it against saves
And another var to hold loaded data

Option A
You crate save in each slot now you load from slot1 data to TempVar1
Where in TempVar2 you have what you were saving
You check if TempVar1 = TempVar2 like compare all it child vars against each other
And if they match you are done saved is successful
If they are not equal you then load from slot 2 to TempVar1 and compare it against TempVar2
And if its equal then you are done if not you load from slot 3 to TempVar1
If all failed you repeat saving process
While you have some var to repeat whole process of checking all 3 slots
Like idk 3 or 5 times
if all 5 attempts failed save filed and you need to create save data again

Option B
Is pretty much the same
But instead of creating all 2-3 slots at the same time you create 1
Load from it to TempVar1 check it against TempVar2 and if its ok you are done
If not you create new save in slot 2
And same story
But case here is If you made a save in slot 1 it did not match TempVar2
You have option to either repeat same process on save slot 1 or try it on save slot 2
OR load data from save slot 2 since it was last correct save data
OR do nothing

And i think it would be possible to make extension out of it
Yet don’t look at me i suck with extensions

1 Like