halive.shootinoutside.common.core.game.map.GameMap.java Source code

Java tutorial

Introduction

Here is the source code for halive.shootinoutside.common.core.game.map.GameMap.java

Source

/*******************************************************************************
 * Copyright (c) HALive, 2015.
 * For Licence information see LICENSE.md
 ******************************************************************************/

package halive.shootinoutside.common.core.game.map;

import halive.shootinoutside.common.core.game.entities.player.Teams;
import halive.shootinoutside.common.util.Vector2D;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * This Class describes the Tile based Map.
 */
public class GameMap {

    public static final int TILE_WIDTH = 32;
    public static final int TILE_HEIGHT = 32;

    private String mapName;

    private int width;
    private int height;

    private GameMapTileType[][] tiles;
    private byte[] textureSheet;

    private ItemLayer itemLayer;

    private List<Vector2D>[] spawnPositions = new List[Teams.values().length];

    private Random rnd;

    private GameMap() {
        rnd = new Random();
        clearSpawnPositions();
    }

    public static GameMap createFromByteArray(byte[] b) throws IOException, ParseException {
        ByteArrayInputStream in = new ByteArrayInputStream(b);
        GZIPInputStream input = new GZIPInputStream(in);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int j;
        while ((j = input.read()) != -1) {
            out.write(j);
        }
        String s = new String(out.toByteArray());
        return loadGameMapFromJSONString(s);
    }

    public static GameMap createEmptyMap(int width, int height) {
        GameMap map = new GameMap();
        map.setMapName("EmptyMap");
        map.setSize(width, height);
        map.initTileArray();
        map.itemLayer = new ItemLayer();
        for (int x = 0; x < map.tiles.length; x++) {
            for (int y = 0; y < map.tiles[x].length; y++) {
                map.tiles[x][y] = GameMapTileType.FLOOR;
            }
        }
        for (int x = 0; x < map.tiles.length; x++) {
            map.tiles[x][0] = GameMapTileType.WALL_BOTTOM;
            map.tiles[x][map.height - 1] = GameMapTileType.WALL_TOP;
        }
        for (int y = 0; y < map.tiles[0].length; y++) {
            map.tiles[0][y] = GameMapTileType.WALL_LEFT;
            map.tiles[map.width - 1][y] = GameMapTileType.WALL_RIGHT;
        }
        map.tiles[0][0] = GameMapTileType.WALL;
        map.tiles[0][height - 1] = GameMapTileType.WALL;
        map.tiles[width - 1][0] = GameMapTileType.WALL;
        map.tiles[width - 1][height - 1] = GameMapTileType.WALL;
        map.textureSheet = loadDefaultTextureSheet();
        for (int i = 0; i < Teams.values().length; i++) {
            Teams team = Teams.values()[i];
            map.addSpawnPosition(team, new Vector2D(width / 2, height / 2));
        }
        return map;
    }

    private static byte[] loadDefaultTextureSheet() {
        File f = new File("map/DefaultTileMap.png");
        try {
            return Files.readAllBytes(f.toPath());
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static GameMap loadGameMapFromJSONString(String s) throws ParseException {
        JSONParser parser = new JSONParser();
        Object obj = parser.parse(s);
        if (obj instanceof JSONObject) {
            JSONObject in = (JSONObject) obj;
            GameMap map = new GameMap();
            //Verify Validity
            if (!in.get("type").equals("soTileMap"))
                return null;
            //TODO Implement Determination of the Deserializer depending on the version
            //Load Width/Height and Mapname
            map.mapName = in.get("mapName").toString();
            map.width = (int) (long) in.get("width");
            map.height = (int) (long) in.get("height");
            //Load the Map Data
            byte[] mapData = Base64.getDecoder().decode((String) in.get("mapDataB64"));
            map.loadTilesFromByteArray(mapData);
            //Load the Spawnpositions
            int amtTeams = (int) (long) in.get("amtTeams");
            if (amtTeams != Teams.values().length) {
                return null;
            }
            for (int i = 0; i < amtTeams; i++) {
                JSONObject o = (JSONObject) in.get("spawn_team_" + i);
                int len = (int) (long) o.get("length");
                for (int j = 0; j < len; j++) {
                    JSONObject oj = (JSONObject) o.get("" + j);
                    map.spawnPositions[i].add(Vector2D.fromJSONObject(oj));
                }
            }
            //Load the ItemLayer
            map.itemLayer = ItemLayer.fromJSONObject((JSONObject) in.get("itemLayer"));
            //Read the Image
            map.textureSheet = Base64.getDecoder().decode(in.get("tileImageB64").toString());
            return map;
        } else {
            return null;
        }
    }

    public void saveMapToFile(File f) throws IOException {
        Files.write(f.toPath(), serializeMapToCompressedByteArray());
    }

    public JSONObject serializeMapToJSONObject() {
        JSONObject obj = new JSONObject();
        //Write Standard Header Info
        obj.put("type", "soTileMap");
        obj.put("version", "1.0");
        //Write misc Map Information
        obj.put("mapName", this.mapName);
        obj.put("width", this.width);
        obj.put("height", this.height);
        //Write the map Data (encoded in Base64
        byte[] map = getMapData();
        String mapData = Base64.getEncoder().encodeToString(map);
        obj.put("mapDataB64", mapData);
        //Write the ItemLayer
        obj.put("itemLayer", itemLayer.serializeToJSON());
        //write the SpawnPositions
        obj.put("amtTeams", spawnPositions.length);
        for (int i = 0; i < spawnPositions.length; i++) {
            JSONObject tmpObj = new JSONObject();
            tmpObj.put("length", spawnPositions[i].size());
            for (int j = 0; j < spawnPositions[i].size(); j++) {
                Vector2D v = spawnPositions[i].get(j);
                tmpObj.put("" + j, v.toJSONObject());
            }
            obj.put("spawn_team_" + i, tmpObj);
        }
        //Write the image File as Base64
        obj.put("tileImageB64", Base64.getEncoder().encodeToString(textureSheet));
        return obj;
    }

    public String serializeMapToJSONString() {
        return serializeMapToJSONObject().toJSONString();
    }

    public byte[] serializeMapToCompressedByteArray() throws IOException {
        //Compress data
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzipOut = new GZIPOutputStream(out);
        gzipOut.write(serializeMapToJSONString().getBytes());
        gzipOut.flush();
        gzipOut.finish();
        return out.toByteArray();
    }

    private byte[] getMapData() {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream output = new DataOutputStream(out);
        for (int x = 0; x < tiles.length; x++) {
            for (int y = 0; y < tiles[x].length; y++) {
                try {
                    output.write(tiles[x][y].getTileID());
                } catch (IOException e) {
                    return null;
                }
            }
        }
        return out.toByteArray();
    }

    private void setSize(int w, int h) {
        this.height = h;
        this.width = w;
    }

    public void setMapName(String mapName) {
        this.mapName = mapName;
    }

    private void initTileArray() {
        tiles = new GameMapTileType[width][height];
    }

    public void addSpawnPosition(Teams team, Vector2D pos) {
        spawnPositions[team.getTeamID()].add(pos);
    }

    public void clearSpawnPositions() {
        for (int i = 0; i < spawnPositions.length; i++) {
            spawnPositions[i] = Collections.synchronizedList(new ArrayList<Vector2D>());
        }
    }

    public Vector2D getSpawnPos(Teams team) {
        int teamID = team == null ? rnd.nextInt(spawnPositions.length) : team.getTeamID();
        int vecPos = spawnPositions[teamID].size() == 1 ? 0 : rnd.nextInt(spawnPositions[teamID].size());
        return allignPosition(spawnPositions[teamID].get(vecPos));
    }

    private Vector2D allignPosition(Vector2D v) {
        return new Vector2D(v.getX() * TILE_WIDTH + TILE_WIDTH / 2, v.getY() * TILE_HEIGHT + TILE_HEIGHT / 2);
    }

    private void loadTilesFromByteArray(byte[] b) {
        initTileArray();
        ByteArrayInputStream input = new ByteArrayInputStream(b);
        DataInputStream in = new DataInputStream(input);
        for (int x = 0; x < tiles.length; x++) {
            for (int y = 0; y < tiles[x].length; y++) {
                try {
                    tiles[x][y] = GameMapTileType.getTypeFomeTileID(in.read());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void debugMapLayout(PrintStream out) {
        out.println("Map name: " + mapName);
        for (int x = 0; x < width; x++) {
            out.print("X: " + x + " ");
            for (int y = 0; y < height; y++) {
                out.print(tiles[x][y].getTileID() + " ");
            }
            out.print("\n");
        }
        out.println("Texture Size " + textureSheet.length + " bytes");
    }

    public byte[] getTextureSheet() {
        return textureSheet;
    }

    public GameMapTileType[][] getTiles() {
        return tiles;
    }

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeightPixels() {
        return height * TILE_HEIGHT;
    }

    public int getWidthPixels() {
        return width * TILE_WIDTH;
    }
}