the-insides/2. Database

Databases can be handy if you want to store a massive amount of data somehow, or it requires a kind of order or system to handle and find your data easily. The CleverCommands offer some kinds of databases, which are based on the ZIP format and the java way of handling .zip files. I created a layered abstract inheritable preset to make you able to build up your own database, because you must code you own saving convesion to bytes, and back, or to string and back. But this is only for specified databases, if you are satisfied with the "one-string-for-one-block" database, you can use the ready-made StringChunkDatabase class, which fully functions. The databases handle data in ChunkData tiles, which are named similarly as the databases, you can see yourself which goes where:

  • ChunkDatabase : ChunkData
    • RawChunkDatabase : RawChunkData
      • SpecifiedChunkDatabase : SpecifiedChunkData
        • StringChunkDatabase : (StringChunkDatabase.ChunkData)

The data is made by the users, but we store it.

First of all, to sum it up, you will need to make at least 3 different classes to make your custom database work. The first is the data itself, simply write a class which has the fields to store your custom informations. Like you write an addon which gives players the avaibility to accumulate the energy of their love into blocks. Love is the most powerful power, it's good if you have some saved, don't ya? So.. let's code.

public class LoveStore {

  private short love = 0;
  public void addLove(short energy) { love += energy; }
  public void takeLove(short energy) { love -= energy; }
  public void setLove(short energy) { love = energy; }
  public short getLoveStored() { return love; }

}

So the basic class is written. But this is not all, your database must be able to create data for chunk itself. It is important, because if the player want to accumulate his or her love somewhere far away where noone had a journey before, than the database has no ChunkData for it. It must generate a new one. From now, there are two ways: using a StringChunkDatabase, which saves strings for blocks, or writing our own SpecifiedChunkDatabase class. I think I just don't need to say, that StringChunkDatabase is much easier, but on the other side SpecifiedChunkDatabase offers a lot more to write yourself and custimize how it works.

A, The easy way

When we use a StringChunkDatabase, we don't need to modify it. The only thing we modify is the data is stores under the strings.

<<UNFINISHED, UNDER WRITING>>

B, The complex way

But your data class can be complex enought to have its own special constructor. The database won't know itself, how to create a chunk of data on his own. So we must help him when he asks, and we can make this help with a Factory class, but before we make it, we should think about the ChunkData objects. First of all, the SpecifiedChunkData class is also an abstract one. It contains a very pure form of methods to take and give low-level form of data (bytes). If you create a SpecifiedChunkDatabase, you must declare your own kind of understanding the bytes, usually converting it to text and from there it does not seem that hard. But you must walk the way backwards too, your must be able to be converted to a bunch of bytes. But it may sounds hard, but it's much more easier to do. An example for specified chunkdata:

public class LovedChunk extends SpecifiedChunkData<LoveStore> {

  //variables to store the position
  private int x,y;
  private String w;

  //a constructor
  public LovedChunk(string world, int x, int y) {
    w = world;
    this.x = x;
    this.y = y;
  }

  @Override
  public LoveStore parseData(String world, BlockVector coords, byte[] data) {
    //here comes our conversion, from bytes to love energy on blocks
  }

  @Override
  public byte[] toOutputData() {
    //here we must convert all our love on the blocks of the chunk to bytes
    //it has a specific format of saving so... maybe in the future I'll replace this method
    //with a HashMap<BlockVector, byte[]> output.
  }

  /**Returns {@code null} if the block has no love!!*/
  public LoveStore getLoveFromBlock(Block b) {
    //TODO
    return null;
  }

  public int countLovedBlocksInChunk() {
    return blocks.size();
  }

  //a field already had without declaration
  //private HashMap<BlockVector, LoveStore> blocks = new HashMap<BlockVector, LoveStore>();

}

We must create a Factory, which helps the database, when it wants a new ChunkData from your special one. Writing your own class, it may have more complex contructor than the database could expect, so we must define a factory, which generates the ChunkData object for it (in this example, our ChunkData class is the LovedChunk class).

public class Factory extends ChunkDataFactory<LovedChunk> {

  //create a constructor if you want
  public Factory(Class<SpecifiedChunkData<BlockData>> type, Charset charset) {
    super(type, charset);
    // TODO Auto-generated constructor stub
  }

  @Override
  public LovedChunk createNew(String world, int cX, int cZ) {
    // TODO Auto-generated method stub
    return new LovedChunk(world, cX, cZ);
  }
}

When I write this, I usually put the static word between the public and the class keywords, and move it into the ChunkData (LovedChunk) class. This way they are together, as the ChunkData class contains its own factory class for making one of itself. But this is the way I like, may you do not, then you don't need to do this way. This way just results less .java files in your project.

<<UNFINISHED, UNDER WRITING>>


Comments

Posts Quoted:
Reply
Clear All Quotes