Skip to content
This repository has been archived by the owner on Sep 3, 2023. It is now read-only.

How to save and read data to from files

Malte Dostal edited this page May 26, 2021 · 6 revisions

DISCLAIMER: outdated and no longer relevant

Serialization

In computer science, in the context of data storage, serialization (or serialisation) is the process of translating data structures or object state into a [...] file [...]

The opposite operation, extracting a data structure from a series of bytes, is deserialization

~ From Wikipedia, the free encyclopedia

To save data into a file and read it again with Salty Engine, we use stdf, which is already included.

How to read/save data from/to a file:

  1. You make the class(es) (e.g. a GameObject) that need to save data implement de.edgelord.saltyengine.io.serialization.Serializable
  2. You override the methods void serialize(Species) and void deserialize(Species), as well as String getDataSetName()
  3. You add the class to the de.edgelord.saltyengine.io.serialization.Serializer
  4. Use void doSerialization(String) or void doSerialization() to save the data and void doDeserialization(String) or void doDeserialization() to read it again.

Now, in details:

  1. and 2. Code example (from de.edgelord.saltyengine.example.serialization):
import de.edgelord.saltyengine.io.serialization.Serializable;
import de.edgelord.stdf.Species;
import de.edgelord.stdf.reading.ValueToDataConverter;

public class Saver implements Serializable {

    private int highScore = 99;

    @Override
    public void serialize(Species species) {
        // This method saves the data. With the given Species, you can add tags and values to the file
        // for example the Integer highScore, saved with the tag-name "highScore". You could use any other name there
        species.addTag("highScore", highScore);

        // And that's it. The data is being saved into a file!
    }

    @Override
    public void deserialize(Species species) {
        // This method reads the data. With the given Species, you can read tag values. All tags you add to the species won't be
        // saved. You could say that the given Species is read-only.
        // ValueToDataConverter.convertToInteger converts the given value from the given species to an integer. There are more
        // types available.
        // ValueToListConverter converts a value to a list, see more in the class "AdvancedSaver"
        //
        // You can also read a String by simply calling species.getTagValue("highScore");
        highScore = ValueToDataConverter.convertToInteger(species, "highScore");
    }

    @Override
    public String getDataSetName() {
        return "saver";
    }
}
  1. and 4. Code example (from de.edgelord.saltyengine.example.serialization):
import de.edgelord.saltyengine.io.serialization.Serializer;

import java.io.IOException;

public class SerializationMain {

    public static void main(String[] args) {
      Game.init(GameConfig.config(0, 0, "Serialization Example", 5));
      // Add a new Saver to the list
      Serializer.add(new Saver());

      // read the data from the default save-file, called "save0.sdb".
      // you could also call e.g. Serializer.doDeserialization("save1") or Serializer.doDeserialization("unicorn")
      // When the file does not exist, it's being created and nothing is being read.
      //
      // It should be
      // in [Your homefolder]/.[game name]
      // In this example, we set the game name to be "Serialization Example" in the Game#init call.
      // The method could throw an IOException, so we have to put it into a try/catch structure.
      try {
          Serializer.doDeserialization();
      } catch (IOException e) {
          e.printStackTrace();
      }

      // save the data to the file. That also happens automatically when you close the game-window.
      // You could also save to a custom file by using
      // Serializer.doSerialization("save1"); or
      // Serializer.doSerialization("unicorn");
      try {
          Serializer.doSerialization();
      } catch (IOException e) {
          e.printStackTrace();
      }
    }
}

When you run that for the first time, You will se this message:

Never serialized something for saver so cannot deserialize for it!

That is because you never saved something to this file before. On the second and every further run, this message should not appear. You can save and read as many tags as you want, there are no limits (except for the files-size eventually).

And lastly, here is a little more extended example (from AdvancedSaver):

import de.edgelord.saltyengine.core.Game;
import de.edgelord.saltyengine.io.serialization.Serializable;
import de.edgelord.saltyengine.transform.Vector2f;
import de.edgelord.stdf.Species;
import de.edgelord.stdf.reading.ValueToDataConverter;
import de.edgelord.stdf.reading.ValueToListConverter;

import java.util.List;

public class AdvancedSaver implements Serializable {

  private int counter = 0;

  private final String CAMERA_POSITION_TAG = "camPos";
  private final String COUNTER_TAG = "counter";
  private final String REDUNDANT_MESSAGE_TAG = "message";

  @Override
  public void serialize(Species species) {
      species.addTag(COUNTER_TAG, ++counter);
      species.addTag(REDUNDANT_MESSAGE_TAG, "This is a redundant message to show that you don't have to encode spaces with these weird combinations of stars and underscores any more!");
      species.addTag(CAMERA_POSITION_TAG, Game.getCamera().getX() + "," + Game.getCamera().getY());
  }

  @Override
  public void deserialize(Species species) {
      counter = ValueToDataConverter.convertToInteger(species, COUNTER_TAG);

      List<String> cameraPosition = ValueToListConverter.convertToList(species, CAMERA_POSITION_TAG, ",");
      Game.getCamera().setPosition(new Coordinates2f(Float.valueOf(cameraPosition.get(0)), Float.valueOf(cameraPosition.get(1))));

      System.out.println("This example started " + counter + " times before on this computer!");
      System.out.println(species.getTagValue(REDUNDANT_MESSAGE_TAG));
  }

  @Override
  public String getDataSetName() {
      return "advancedSaver";
  }
}

This example also shows how you can store and read the position of the camera, with the following structure:

  1. species.addTag(CAMERA_POSITION_TAG, Game.getCamera().getX() + "," + Game.getCamera().getY()); adds a tag with the name "camPos" and the value x,y to the file. x and y being the coordinates of the camera. It looks e.g. like this: (camPos)3.14,314(*camPos)
  2. List<String> cameraPosition = ValueToListConverter.convertToList(species, CAMERA_POSITION_TAG, ","); creates a new list with the content of the tag "camPos", separated by ","
  3. Game.getCamera().setPosition(new Vector2f(Float.valueOf(cameraPosition.get(0)), Float.valueOf(cameraPosition.get(1)))); sets the first item in the list as the x and the second element as the y coordinate of the camera

After you ran this the first time, there should be a file in [your-homefolder]/.[game-name] called save0.sdb with the following content:

{saver}(highScore)99(*highScore){*saver}{advancedSaver}(camPos)0.0,0.0(*camPos)(message)This is a redundant message to show that you don't have to encode spaces with these weird combinations of stars and underscores any more!(*message)(counter)1(*counter){*advancedSaver}

Yes, everything in one line. But that is okay, because you don't want the user to edit this content by himself and may confuse or scare him off. But after a little work, you can clearly see how the data is being stored:

{saver}
    (highScore)99(*highScore)
{*saver}

{advancedSaver}
    (camPos)0.0,0.0(*camPos)
    (message)This is a redundant message to show that you don't have to encode spaces with these weird combinations of stars and underscores any more!(*message)
    (counter)1(*counter)
{*advancedSaver}

If you would save the file like that, stdf would still be able to read it.