Moving a savefile to a different slot number (to create multiple autosaves)

Started by Dave Gilbert, Thu 10/10/2024 22:04:05

Previous topic - Next topic

Dave Gilbert

So my game has an autosave, but it's only one file. I am trying to create a system that creates 4 autosave files, but I am having trouble.

I've earmarked 4 slots for autosaves: slots 96,97,98 and 99. After four autosaves, the savelist looks like this;

Slot 99: Autosave4
Slot 98: Autosave3
Slot 97: Autosave2
Slot 96: Autosave1

So far, it works perfectly. When the game autosaves for a fifth time, I want to delete slot 96 and move the rest down one slot so I can place the new save in the now empty slot 99. So it will now look like this:

Slot 99: Autosave5
Slot 98: Autosave4
Slot 97: Autosave3
Slot 96: Autosave2

Unfortunately, there doesn't seem to be a way to move a savefile to a different slot. Is there? Or is there a better way to handle this?

Any light-shedding apprecaited!

-Dave

Crimson Wizard

There's a way in 3.6.2 now. But not in previous versions. And unfortunately there's also no way to rename or copy a file directly (I am also adding this to 3.6.2).

This leaves 2 possible solutions:

1. Don't do anything with saves themselves, but instead find out which saves exist and use empty slots.
Create a custom file and write down the list in the order in which these saves has to be presented in your game, using pairs of My Index : Slot Index.
Basically, enumerate these saves not by their actual save slot number, but by their index order in your custom list.
You may even store their dates like that, and read these back if you need.

2. Move file by reading and writing their contents:
- File.Open existing slot for reading,
- File.Open destination slot for writing,
- Do File.ReadRawChar / File.WriteRawChar in a loop until reaching EOF.
WARNING: this is going to be much slower than the usual file rename, and then even more slower because you are doing this from AGS Script. So I strongly recommend the first solution.

Dave Gilbert

Maybe this is a "beginner" question, but I am not sure how to "sort" the saves. There doesn't seem to be any alternative to the FillSaveGameList() command. I could edit the savelist manually, but then the save slot information won't get updated as well, because ListBox.SaveGameSlots[] is read-only. I also saved screenshot information along with the savefile, and there is no other way to propogate that except with the FillSaveGameList() command, at least according to the manual.

Am I missing something? How can I sort a savelist by date, and propogate all the slot/screenshot data along with it?

Crimson Wizard

You need to iterate autosaves in "circular" manner, going back to the first one after last was already used.
You do not need to change files themselves for this, but simply keep and index of the last (or next) auto save to use. When it reaches last slot, you reset this index to the first slot, and continue from there.

Then, you need to write this last used autosave index in a custom file, and read it back for the next game launch.

That may be enough really.

But, if you like to go further, and also have exact dates, then store these in arrays:
Code: ags
#define MAX_AUTOSAVES 4
#define FIRST_AUTOSAVE_SLOT 96

int NextAutoSaveSlot; // goes from 0 to MAX_AUTOSAVES, and over again
DateTime *AutoSaveTime[MAX_AUTOSAVES];

When you make autosave, the real save slot will be "FIRST_AUTOSAVE_SLOT + NextAutoSaveSlot".
Get DateTime.Now and store in AutoSaveTime[NextAutoSaveSlot].
And advance NextAutoSaveSlot++. If NextAutoSaveSlot is >= MAX_AUTOSAVES, then reset it to 0.

Code: ags
int saveSlot = FIRST_AUTOSAVE_SLOT + NextAutoSaveSlot;
AutoSaveTime[NextAutoSaveSlot] = DateTime.Now;
SaveGameSlot(saveSlot, "description");
NextAutoSaveSlot++;
if (NextAutoSaveSlot >= MAX_AUTOSAVES)
    NextAutoSaveSlot = 0;

Then you have to write this NextAutoSaveSlot index and AutoSaveTime array into the custom file, do that each time after you make autosave, and read it back whenever the game is started: this will restore autosave counter next time the game is launched.




EDIT:

Hmm okay, so if you also want to put description with ever increasing number, then you will need a second counter that just goes up. So the code becomes:

Code: ags
#define MAX_AUTOSAVES 4
#define FIRST_AUTOSAVE_SLOT 96

int NextAutoSaveSlot; // goes from 0 to MAX_AUTOSAVES, and over again
DateTime *AutoSaveTime[MAX_AUTOSAVES];
int AutoSaveIndex = 1;

Code: ags
int saveSlot = FIRST_AUTOSAVE_SLOT + NextAutoSaveSlot;
AutoSaveTime[NextAutoSaveSlot] = DateTime.Now;
SaveGameSlot(saveSlot, String.Format("Autosave %d", AutoSaveIndex));
AutoSaveIndex++;
NextAutoSaveSlot++;
if (NextAutoSaveSlot >= MAX_AUTOSAVES)
    NextAutoSaveSlot = 0;

And you will need to write AutoSaveIndex into the custom file too.

Dave Gilbert


Crimson Wizard

I was adding a number of new things into 3.6.2 which could help to avoid having to do all this, but this of course is too late if you're not using 3.6.2.

These new things include:
- ListBox can fill any range of save slots.
- Can read date/time from a save slot.
- Can move save slots.
etc

Dave Gilbert

Hah! Missed it by that much. Since 3.6.2 is in alpha it's probably not a good idea for me to upgrade this late into a project. Oh well!

eri0o

You can set the name of the saveslot and you can also read the name of the saveslot, but if you write to the same slot number it will be overwritten - and the name will change.

I need to think on the logic but I think you can just save the file as "autosave_yyyy_mm_dd_hh_mm_ss_description", and then you can retrieve the dates from the name. I am in transit but I think there's some way to use this to workaround without the need to save in something else the saves information.

I use something on the effect here in my savegame interface in my small games: https://github.com/ericoporto/dont-give-up-the-cat/blob/fc2810d9d580f6e1b51742489fa388fbd96cdbd0/dont-give-up-the-cat/CustomSave.asc#L88

3.6.2 is in Beta, not sure when it will be marked as release though.

Crimson Wizard

Yes, indeed, you can write extra information into the save's description, and parse it back. If you go that way, then you don't need an extra file.

The save's description should store: date and incrementing save index.
In this case you can scan these 4 slots and find the one with either the earliest date or the lowest index in description, and write over it.

eri0o

Does YYMMDDhhmmss fits in an int32? If it does than this date can be sorted with a simple int sort.

Crimson Wizard

Quote from: eri0o on Fri 11/10/2024 00:24:42Does YYMMDDhhmmss fits in an int32? If it does than this date can be sorted with a simple int sort.

One can write DateTime.RawTime there if such sort is wanted.
https://adventuregamestudio.github.io/ags-manual/DateTime.html#datetimerawtime

EDIT: Strangely, there's no way to recreate DateTime from raw time...

eri0o

Oh, it would really be helpful if Datetime wasn't a static struct and instead all these properties were writable, so decoding the rawtime would be just a set value after parsing it out of the name, I think for now getting the time back from RawTime for presentation purposes would require re-implementing the date conversion in script. :/

I guess the easiest approach is to have an int in the name, a counter, that you get the biggest value and increment (add one to it) and then you save it in the slot that has the smallest value. So something like the name being "autosave_COUNTER_description", and then you parse back by just using the counter - the approach you mentioned in the previous comment, but ignoring the date.

Crimson Wizard

Quote from: eri0o on Fri 11/10/2024 01:54:37Oh, it would really be helpful if Datetime wasn't a static struct and instead all these properties were writable, so decoding the rawtime would be just a set value after parsing it out of the name, I think for now getting the time back from RawTime for presentation purposes would require re-implementing the date conversion in script. :/

Yes it would help to at least have a factory method that creates DateTime from raw time; and then perhaps one that creates it from year, month etc combination.

SMF spam blocked by CleanTalk