123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- package me.hammerle.supersnuvi.gamelogic;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.Map.Entry;
- public class LevelData
- {
- private final static int STRING_ID = 1;
- private final static int INTEGER_ID = 2;
-
- // container for all custom data
- private final HashMap<String, Object> data;
-
- // layers up to bIndex (including) are considered background
- // the next layer is the entity spawn layer
- // every layer after that is foreground
- private int bIndex;
- private int width;
- private int height;
- private int layers;
-
- // storage for tiles
- // [layer][width][height]
- private int[][][] tiles;
-
- // the file of the level for saving and loading
- private final File file;
-
- public LevelData(File file)
- {
- this.file = file;
- this.data = new HashMap<>();
- this.bIndex = 0;
- this.width = 0;
- this.height = 0;
- this.layers = 0;
- this.tiles = null;
- }
-
- public LevelData(File file, int bIndex, int layer, int width, int height)
- {
- this.file = file;
- this.data = new HashMap<>();
- this.bIndex = bIndex;
- this.width = width;
- this.height = height;
- this.layers = layer;
- this.tiles = new int[layer][width][height];
- for(int l = 0; l < layer; l++)
- {
- for(int x = 0; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- tiles[l][x][y] = -1;
- }
- }
- }
- }
-
- // -------------------------------------------------------------------------
- // file writing / reading
- // -------------------------------------------------------------------------
-
- private void writeString(FileOutputStream out, String s, boolean identifier) throws IOException
- {
- // writing type identifier
- if(identifier)
- {
- out.write(STRING_ID);
- }
- // writing length of string
- byte[] b = s.getBytes();
- writeInt(out, b.length, false);
- // writing the bytes of the string
- out.write(b);
- }
-
- private String readString(FileInputStream in) throws IOException
- {
- int length = readInt(in);
- byte[] b = new byte[length];
- in.read(b);
- if(length > 1024 * 1024)
- {
- throw new IOException("invalid level file");
- }
- return new String(b);
- }
-
- private void writeInt(FileOutputStream out, int i, boolean identifier) throws IOException
- {
- // writing type identifier
- if(identifier)
- {
- out.write(INTEGER_ID);
- }
- // writing the int per byte
- out.write(i & 0xFF);
- out.write((i >> 8) & 0xFF);
- out.write((i >> 16) & 0xFF);
- out.write((i >> 24) & 0xFF);
- }
- private int readInt(FileInputStream in) throws IOException
- {
- int i = 0;
- i |= in.read();
- i |= in.read() << 8;
- i |= in.read() << 16;
- i |= in.read() << 24;
- return i;
- }
-
- private void writeRepeated(int count, int currentTile, FileOutputStream out) throws IOException
- {
- while(true)
- {
- if(count <= 0)
- {
- break;
- }
- else if(count >= 255)
- {
- count -= 255;
- out.write(255);
- writeInt(out, currentTile, false);
- }
- else
- {
- out.write(count);
- writeInt(out, currentTile, false);
- break;
- }
- }
- }
-
- public boolean save()
- {
- if(file == null)
- {
- return false;
- }
- try
- {
- try(FileOutputStream out = new FileOutputStream(file))
- {
- // writing number of data fields
- writeInt(out, data.size(), false);
- // writing keys and data, data varies, key are always strings
- for(Entry<String, Object> e : data.entrySet())
- {
- writeString(out, e.getKey(), false);
- if(e.getValue() instanceof Integer)
- {
- writeInt(out, (Integer) e.getValue(), true);
- }
- else
- {
- writeString(out, e.getValue().toString(), true);
- }
- }
-
- // write background index
- writeInt(out, bIndex, false);
- // write number of layers
- writeInt(out, layers, false);
- // write layer width
- writeInt(out, width, false);
- // write layer height
- writeInt(out, height, false);
-
- // write tiles
- if(layers > 0 && width > 0 && height > 0)
- {
- int count = 0;
- int currentTile = tiles[0][0][0];
- for(int x = 0; x < layers; x++)
- {
- for(int y = 0; y < width; y++)
- {
- for(int z = 0; z < height; z++)
- {
- if(currentTile == tiles[x][y][z])
- {
- count++;
- }
- else
- {
- writeRepeated(count, currentTile, out);
- count = 1;
- currentTile = tiles[x][y][z];
- }
- }
- }
- }
- writeRepeated(count, currentTile, out);
- }
-
- out.flush();
- out.close();
- }
- return true;
- }
- catch(IOException ex)
- {
- ex.printStackTrace();
- return false;
- }
- }
-
- public boolean load()
- {
- if(file == null)
- {
- return false;
- }
- try
- {
- try (FileInputStream in = new FileInputStream(file))
- {
- // getting the number of data fields
- int fields = readInt(in);
- // getting keys and data, data varies, key are always strings
- for(; fields > 0; fields--)
- {
- String key = readString(in);
- int id = in.read();
- switch(id)
- {
- case STRING_ID:
- data.put(key, readString(in));
- break;
- case INTEGER_ID:
- data.put(key, readInt(in));
- break;
- default:
- System.err.println("fucked up level data");
- return false;
- }
- }
- //data.forEach((k, v) -> System.out.println(k + " " + v + " " + v.getClass()));
-
- // getting background index
- bIndex = readInt(in);
- // getting number of layers
- layers = readInt(in);
- // getting layer width
- width = readInt(in);
- // getting layer height
- height = readInt(in);
-
- //System.out.println(layers + " " + width + " " + height);
-
- // init tiles
- tiles = new int[layers][width][height];
- // getting tiles
- if(layers > 0 && width > 0 && height > 0)
- {
- int count = 0;
- int currentTile = -1;
-
- for(int x = 0; x < layers; x++)
- {
- for(int y = 0; y < width; y++)
- {
- for(int z = 0; z < height; z++)
- {
- if(count == 0)
- {
- count = in.read();
- currentTile = readInt(in);
- //System.out.println(count + " " + currentTile);
- }
- tiles[x][y][z] = currentTile;
- count--;
- }
- }
- }
- }
-
- in.close();
-
- //save();
- }
-
- int x = bIndex + 1;
- for(int y = 0; y < width; y++)
- {
- for(int z = 0; z < height; z++)
- {
- if(tiles[x][y][z] == -1)
- {
- tiles[x][y][z] = 0;
- }
- }
- }
- return true;
- }
- catch(IOException ex)
- {
- ex.printStackTrace();
- return false;
- }
- }
-
- // -------------------------------------------------------------------------
- // variable level data
- // -------------------------------------------------------------------------
-
- public void setData(String name, int value)
- {
- data.put(name, value);
- }
-
- public void setData(String name, String value)
- {
- data.put(name, value);
- }
-
- public int getInt(String name, int error)
- {
- Object o = data.get(name);
- if(o == null || !(o instanceof Integer))
- {
- return error;
- }
- return (Integer) o;
- }
-
- public String getString(String name, String error)
- {
- Object o = data.get(name);
- if(o == null || !(o instanceof String))
- {
- return error;
- }
- return (String) o;
- }
-
- // -------------------------------------------------------------------------
- // level data getter / setter
- // -------------------------------------------------------------------------
- public int getBackgroundIndex()
- {
- return bIndex;
- }
-
- public void setBackgroundIndex(int bIndex)
- {
- this.bIndex = bIndex;
- }
-
- public int getLayers()
- {
- return layers;
- }
-
- public int getWidth()
- {
- return width;
- }
- public int getHeight()
- {
- return height;
- }
-
- // -------------------------------------------------------------------------
- // layer stuff
- // -------------------------------------------------------------------------
-
- public void clearLayer(int index)
- {
- if(index >= 0 && index < layers)
- {
- for(int x = 0; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- tiles[index][x][y] = -1;
- }
- }
- }
- }
-
- public void copyLayer(int fromIndex, int toIndex)
- {
- if(fromIndex >= 0 && fromIndex < layers && toIndex >= 0 && toIndex < layers)
- {
- for(int x = 0; x < width; x++)
- {
- System.arraycopy(tiles[fromIndex][x], 0, tiles[toIndex][x], 0, height);
- }
- }
- }
-
- public void addLayer()
- {
- int[][][] newLayers = new int[layers + 1][][];
- System.arraycopy(tiles, 0, newLayers, 0, layers);
- newLayers[layers] = new int[width][height];
- for(int x = 0; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- newLayers[layers][x][y] = -1;
- }
- }
- layers++;
- tiles = newLayers;
- }
-
- public void addLayer(int index)
- {
- if(index >= layers)
- {
- addLayer();
- return;
- }
- int[][][] newLayers = new int[layers + 1][][];
- System.arraycopy(tiles, 0, newLayers, 0, index);
- newLayers[index] = new int[width][height];
- for(int x = 0; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- newLayers[index][x][y] = -1;
- }
- }
- System.arraycopy(tiles, index, newLayers, index + 1, layers - index);
- layers++;
- tiles = newLayers;
- }
-
- public void removeLayer(int index)
- {
- if(layers <= 1)
- {
- layers = 0;
- tiles = new int[0][0][0];
- return;
- }
- int[][][] newLayers = new int[layers - 1][][];
- if(index > 0)
- {
- System.arraycopy(tiles, 0, newLayers, 0, index);
- }
- int left = layers - index - 1;
- if(left > 0)
- {
- System.arraycopy(tiles, index + 1, newLayers, index, left);
- }
- layers--;
- tiles = newLayers;
- }
-
- public void setLayerSize(int w, int h)
- {
- int[][][] newLayers = new int[layers][w][h];
-
- int cw = Math.min(w, width);
- int ch = Math.min(h, height);
- for(int l = 0; l < layers; l++)
- {
- for(int x = 0; x < cw; x++)
- {
- System.arraycopy(tiles[l][x], 0, newLayers[l][x], 0, ch);
- }
- }
-
- width = w;
- height = h;
- tiles = newLayers;
- }
-
- // -------------------------------------------------------------------------
- // tile getter / setter
- // -------------------------------------------------------------------------
-
- public int getInteractionTile(int x, int y)
- {
- if(x < 0 || y < 0 || x >= width || y >= height || bIndex >= layers)
- {
- return -1;
- }
- return tiles[bIndex][x][y];
- }
-
- public int getTile(int layer, int x, int y)
- {
- return tiles[layer][x][y];
- }
-
- public void setTile(int layer, int x, int y, int value)
- {
- tiles[layer][x][y] = value;
- }
-
- // -------------------------------------------------------------------------
- // entity layer
- // -------------------------------------------------------------------------
-
- public void deactivateEntity(int x, int y)
- {
- tiles[bIndex + 1][x][y] = -Math.abs(tiles[bIndex + 1][x][y]);
- }
-
- public void activateEntities()
- {
- int[][] ent = tiles[bIndex + 1];
- forEachEntity((x, y, tile) ->
- {
- if(tile < 0)
- {
- ent[x][y] = Math.abs(ent[x][y]);
- }
- }, 0, width, 0, height);
- }
-
- // -------------------------------------------------------------------------
- // tile iterators
- // -------------------------------------------------------------------------
-
- public void forEachBackground(TileConsumer c, int sx, int ex, int sy, int ey)
- {
- int max = Math.min(layers - 1, bIndex);
-
- sx = Math.max(0, sx);
- sy = Math.max(0, sy);
- ex = Math.min(width, ex);
- ey = Math.min(height, ey);
-
- for(int l = 0; l <= max; l++)
- {
- for(int x = sx; x < ex; x++)
- {
- for(int y = sy; y < ey; y++)
- {
- c.consume(x, y, tiles[l][x][y]);
- }
- }
- }
- }
-
- public void forEachInteractTile(TileConsumer c)
- {
- if(bIndex < layers)
- {
- for(int y = 0; y < width; y++)
- {
- for(int z = 0; z < height; z++)
- {
- c.consume(y, z, tiles[bIndex][y][z]);
- }
- }
- }
- }
-
- public void forEachEntity(TileConsumer c, int sx, int ex, int sy, int ey)
- {
- int l = bIndex + 1;
- if(l < layers)
- {
- sx = Math.max(0, sx);
- sy = Math.max(0, sy);
- ex = Math.min(width, ex);
- ey = Math.min(height, ey);
-
- int[][] ent = tiles[l];
-
- for(int x = sx; x < ex; x++)
- {
- for(int y = sy; y < ey; y++)
- {
- c.consume(x, y, ent[x][y]);
- }
- }
- }
- }
-
- public void forEachForeground(TileConsumer c, int sx, int ex, int sy, int ey)
- {
- sx = Math.max(0, sx);
- sy = Math.max(0, sy);
- ex = Math.min(width, ex);
- ey = Math.min(height, ey);
-
- for(int l = bIndex + 2; l < layers; l++)
- {
- for(int x = sx; x < ex; x++)
- {
- for(int y = sy; y < ey; y++)
- {
- c.consume(x, y, tiles[l][x][y]);
- }
- }
- }
- }
- }
|