Gamebuino Save format

Academy

Sorunome

2 months ago

This will explain you how to use the gamebuino save format, the gb.save interface. First, this will explain the simple usage and after that the advanced, more customizable usage with config-gamebuino.h

Save Structure

The savefile is structured in blocks. A block can hold a number or a buffer. By default the savefile has 64 blocks.

Simple number usage

Handling numbers is very easily done:

gb.save.set(0, 42); // saves 42 in block 0
gb.save.set(1, -1337); // saves -1337 in block 1
int i = gb.save.get(0); // fetches block 0, which is 42
int j = gb.save.get(1); // fetches block 0, which is -1337
gb.save.del(0); // deletes block 0

Numbers default to zero (configurable, see advanced usage)

Blob usage

Now, instead of storing a number in a block, you can also store a blob. By default the size of a blob is 32 bytes.

Well, what is a blob? A blob can be literetally anything! You can store strings, buffers, objects or just about anything you'd want to store.

gb.save.set(2, "Foxes are awesome!"); // stores the string "Foxes are awesome!" in block 2

CustomObject obj;
gb.save.set(3, obj); // stores obj

void* buffer = malloc(10);
gb.save.set(4, buffer, 10); // stores a buffer of length 10

if these functions return true setting was possible, if they return false then something went wrong.

Now, how do you fetch those blobs?

char string[32];
gb.save.get(2, string);
gb.display.print(string); // prints block 2 as string, so "Foxes are awesome!"

CustomObject obj;
gb.save.get(3, obj); // fetches the custom object

void* buf = malloc(10);
gb.save.get(4, buf, 10); // fetches up to 10 bytes from block 4

if these blocks don't exist yet the buffer is filled with zeros (configurable, see advanced usage)

Important notice

Please note that after setting it is enforced weather the block is an int or a blob. For example:

// this will error
gb.save.set(0, 42);
gb.save.set(0, "blah"); // error, block is an int!!

// this will also error
gb.save.set(0, 42);
char name[10];
gb.save.get(0, name); // error, block is an int!

// this will work, though
gb.save.set(0, 42);
gb.save.del(0); // we delete the block
gb.save.set(0, "Foxies!");

Floats etc.

You can easily store floats / signed ints etc. as ints by casting them:

gb.save.set(0, (int32_t)3.14159);
float pi = (float)gb.save.get(0);

gb.save.set(1, (int32_t)true);
bool stuff = (bool)gb.save.get(1);


Advanced Usage

The basic idea of advanced usage is to pre-define which block is an int and which one is a blob and to allow custom defaults. For this we need to create an array of the type SaveDefault, passing that then on to gb.save.config:

const SaveDefault savefileDefaults[] = {
  SaveDefault( /* constructor */ ),
  SaveDefault( /* constructor */ ),
};

void setup() {
  gb.begin();

  // set the save defaults
  gb.save.config(savefileDefaults);
}

Now, there are multiple different SaveDefault constructors possible. The first argument is always the block number to configure, the second one which type that block must be (SAVETYPE_INT or SAVETYPE_BLOB). After that, it depends on if you use int or blob:

SAVETYPE_INT

As third argument you have to set the default value. So these all are valid SaveDefault constructors:

SaveDefault(0, SAVETYPE_INT, 9999)
SaveDefault(1, SAVETYPE_INT, -42)

SAVETYPE_BLOB

Blobs must have a third and optionally a fourth argument. With only three arguments the third one is the max length of the blob, with four arguments the third one is the default and the third one the max length.

The length of a blob can only be up to 255 bytes!

So these are valid blob constructors:

SaveDefault(2, SAVETYPE_BLOB, 20)
SaveDefault(3, SAVETYPE_BLOB, "Fox", 20)

Example

Ok, that was a lot to take in. So here is an example taking full use of all the features:

const SaveDefault savefileDefaults[] = {
  SaveDefault(SAVE_PLAYERNAME, SAVETYPE_BLOB, "Link", 20),
  SaveDefault(SAVE_HEARTS, SAVETYPE_INT, 3),
  SaveDefault(SAVE_SOMEBUFFER, SAVETYPE_BLOB, 25),
};

void setup() {
  gb.begin();

  gb.save.config(savefileDefaults);
}

// somewhere later in the code
char name[20];
gb.save.get(SAVE_PLAYERNAME, name);
gb.display.print(name); // prints "Link"

int hearts = gb.save.get(SAVE_HEARTS); // returns 3


I sure hope this helped you to understand how to use the save API to its full extend!

View full creation

You must be logged in in order to post a message on the forum

Log in