TileMap now uses Tile instances instead of ints. No changes in the way it is stored in the database

This commit is contained in:
Simon
2018-11-15 12:08:44 -05:00
parent e50bcdeab7
commit 4be1bf2e8a
21 changed files with 268 additions and 100 deletions

View File

@@ -15,8 +15,7 @@ import net.simon987.server.game.debug.*;
import net.simon987.server.game.item.ItemCopper;
import net.simon987.server.game.item.ItemIron;
import net.simon987.server.game.objects.GameRegistry;
import net.simon987.server.game.world.DayNightCycle;
import net.simon987.server.game.world.World;
import net.simon987.server.game.world.*;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.PluginManager;
import net.simon987.server.user.User;
@@ -122,6 +121,12 @@ public class GameServer implements Runnable {
gameRegistry.registerItem(ItemCopper.ID, ItemCopper.class);
gameRegistry.registerItem(ItemIron.ID, ItemIron.class);
gameRegistry.registerTile(TileVoid.ID, TileVoid.class);
gameRegistry.registerTile(TilePlain.ID, TilePlain.class);
gameRegistry.registerTile(TileWall.ID, TileWall.class);
gameRegistry.registerTile(TileCopper.ID, TileCopper.class);
gameRegistry.registerTile(TileIron.ID, TileIron.class);
}
public GameUniverse getGameUniverse() {

View File

@@ -2,6 +2,7 @@ package net.simon987.server.game.objects;
import net.simon987.server.assembly.HardwareModule;
import net.simon987.server.game.item.Item;
import net.simon987.server.game.world.Tile;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
@@ -13,12 +14,14 @@ public class GameRegistry {
private HashMap<String, Class<? extends GameObject>> gameObjects;
private HashMap<String, Class<? extends HardwareModule>> hardware;
private HashMap<Integer, Class<? extends Item>> items;
private HashMap<Integer, Class<? extends Tile>> tiles;
public GameRegistry() {
gameObjects = new HashMap<>();
hardware = new HashMap<>();
items = new HashMap<>();
tiles = new HashMap<>();
}
public void registerGameObject(Class<? extends GameObject> clazz) {
@@ -33,6 +36,10 @@ public class GameRegistry {
items.put(id, clazz);
}
public void registerTile(int id, Class<? extends Tile> clazz) {
tiles.put(id, clazz);
}
public HardwareModule deserializeHardware(Document document, ControllableUnit controllableUnit) {
String type = document.getString("type");
@@ -119,6 +126,23 @@ public class GameRegistry {
}
}
public Tile makeTile(int tileId) {
if (tiles.containsKey(tileId)) {
try {
return tiles.get(tileId).getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException
| InvocationTargetException e) {
e.printStackTrace();
return null;
}
} else {
LogManager.LOGGER.severe("Trying to create an unknown Tile type: " + tileId);
return null;
}
}
public boolean isGameObjectRegistered(String type) {
return gameObjects.containsKey(type);
}

View File

@@ -1,21 +1,37 @@
package net.simon987.server.game.world;
import net.simon987.server.game.item.Item;
import net.simon987.server.game.objects.GameObject;
public abstract class Tile {
protected boolean blocked;
/**
* @return Unique id of the tile
*/
public abstract int getId();
public Item onDrill() {
/**
* Called when an object attempts to drill this tile
*
* @return The item obtained by drilling, return null for no item
*/
public Item drill() {
return null;
}
/**
* Called when a player attempts to walk on this tile
*
* @return true if the object can walk on this tile, false if blocked
*/
public boolean walk(GameObject object) {
return true;
}
/**
* Check if a tile should be considered 'blocked' (by the LiDAR, for example)
*/
public boolean isBlocked() {
return blocked;
return false;
}
}

View File

@@ -0,0 +1,19 @@
package net.simon987.server.game.world;
import net.simon987.server.game.item.Item;
import net.simon987.server.game.item.ItemCopper;
public class TileCopper extends Tile {
public static final int ID = 3;
@Override
public int getId() {
return ID;
}
@Override
public Item drill() {
return new ItemCopper();
}
}

View File

@@ -0,0 +1,19 @@
package net.simon987.server.game.world;
import net.simon987.server.game.item.Item;
import net.simon987.server.game.item.ItemIron;
public class TileIron extends Tile {
public static final int ID = 2;
@Override
public int getId() {
return ID;
}
@Override
public Item drill() {
return new ItemIron();
}
}

View File

@@ -1,38 +1,27 @@
package net.simon987.server.game.world;
import net.simon987.server.GameServer;
import net.simon987.server.game.objects.GameRegistry;
import net.simon987.server.io.JSONSerialisable;
import net.simon987.server.io.MongoSerializable;
import org.bson.Document;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Random;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
/**
* A 2D map of Tile objects of size width*height
*/
public class TileMap implements JSONSerialisable, MongoSerializable {
public static final int VOID = -1;
public static final int PLAIN_TILE = 0;
public static final int WALL_TILE = 1;
public static final int IRON_TILE = 2;
public static final int COPPER_TILE = 3;
public static final int VAULT_FLOOR = 4;
public static final int VAULT_WALL = 5;
/**
* The map of tile
*/
private int[][] tiles;
private Tile[][] tiles;
/**
* width, in tiles
@@ -51,10 +40,10 @@ public class TileMap implements JSONSerialisable, MongoSerializable {
this.width = width;
this.height = height;
tiles = new int[width][height];
tiles = new Tile[width][height];
}
public TileMap(int[][] tiles, int size) {
public TileMap(Tile[][] tiles, int size) {
this.width = size;
this.height = size;
@@ -63,40 +52,62 @@ public class TileMap implements JSONSerialisable, MongoSerializable {
/**
* Change the tile at a specified position
* Sets the modified flag
*
* @param tileId id of the new Tile
* @param x X coordinate of the tile to set
* @param y Y coordinate of the tile to set
*/
public void setTileAt(int tileId, int x, int y) {
setTileAt(GameServer.INSTANCE.getRegistry().makeTile(tileId), x, y);
}
/**
* Change the tile at a specified position
*
* @param tile new Tile
* @param x X coordinate of the tile to set
* @param y Y coordinate of the tile to set
*/
public void setTileAt(Tile tile, int x, int y) {
try {
tiles[x][y] = tileId;
tiles[x][y] = tile;
} catch (ArrayIndexOutOfBoundsException e) {
//Shouldn't happen
e.printStackTrace();
}
}
/**
* Get the tile id at a specific position
*
* @param x X coordinate of the tile to get
* @param y Y coordinate of the tile to get
* @return the tile id at the specified position, -1 if out of bounds
*/
public int getTileIdAt(int x, int y) {
try {
return tiles[x][y].getId();
} catch (ArrayIndexOutOfBoundsException e) {
return -1;
}
}
/**
* Get the tile at a specific position
*
* @param x X coordinate of the tile to get
* @param y Y coordinate of the tile to get
* @return the tile at the specified position, -1 if out of bounds
* @return the tile id at the specified position, null if out of bounds
*/
public int getTileAt(int x, int y) {
public Tile getTileAt(int x, int y) {
try {
return tiles[x][y];
} catch (ArrayIndexOutOfBoundsException e) {
return -1;
return null;
}
}
public int[][] getTiles() {
return tiles;
}
public int getWidth() {
@@ -111,28 +122,15 @@ public class TileMap implements JSONSerialisable, MongoSerializable {
public JSONObject jsonSerialise() {
JSONObject json = new JSONObject();
byte[] terrain = new byte[width * width];
JSONArray terrain = new JSONArray();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
terrain[x * width + y] = (byte) tiles[x][y];
terrain.add(tiles[y][x].getId());
}
}
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION, true);
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(stream, compressor);
deflaterOutputStream.write(terrain);
deflaterOutputStream.close();
byte[] compressedBytes = stream.toByteArray();
json.put("z", new String(Base64.getEncoder().encode(compressedBytes)));
} catch (IOException e) {
e.printStackTrace();
}
json.put("terrain", terrain);
return json;
}
@@ -152,7 +150,7 @@ public class TileMap implements JSONSerialisable, MongoSerializable {
for (int x = 0; x < this.width; x++) {
for (int y = 0; y < this.height; y++) {
bsonTiles.add(tiles[x][y]);
bsonTiles.add(tiles[x][y].getId());
}
}
@@ -165,19 +163,19 @@ public class TileMap implements JSONSerialisable, MongoSerializable {
public static TileMap deserialize(Document object, int size) {
ArrayList<Integer> terrain = (ArrayList<Integer>) object.get("tiles");
GameRegistry reg = GameServer.INSTANCE.getRegistry();
int[][] tiles = new int[size][size];
Tile[][] tiles = new Tile[size][size];
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
tiles[x][y] = terrain.get(x * size + y);
tiles[x][y] = reg.makeTile(terrain.get(x * size + y));
}
}
return new TileMap(tiles, size);
}
public Point getRandomTile(int tile) {
public Point getRandomTile(int tileId) {
Random random = new Random();
@@ -193,7 +191,7 @@ public class TileMap implements JSONSerialisable, MongoSerializable {
int rx = random.nextInt(width);
int ry = random.nextInt(height);
if (tiles[rx][ry] == tile) {
if (tiles[rx][ry].getId() == tileId) {
return new Point(rx, ry);
}
}

View File

@@ -0,0 +1,11 @@
package net.simon987.server.game.world;
public class TilePlain extends Tile {
public static final int ID = 0;
@Override
public int getId() {
return ID;
}
}

View File

@@ -0,0 +1,23 @@
package net.simon987.server.game.world;
import net.simon987.server.game.objects.GameObject;
public class TileVoid extends Tile {
public static final int ID = -1;
@Override
public int getId() {
return ID;
}
@Override
public boolean walk(GameObject object) {
return false; //Shouldn't happen!
}
@Override
public boolean isBlocked() {
return true;
}
}

View File

@@ -0,0 +1,23 @@
package net.simon987.server.game.world;
import net.simon987.server.game.objects.GameObject;
public class TileWall extends Tile {
public static final int ID = 1;
@Override
public int getId() {
return ID;
}
@Override
public boolean walk(GameObject object) {
return false; //always blocked
}
@Override
public boolean isBlocked() {
return true;
}
}

View File

@@ -25,6 +25,7 @@ public class World implements MongoSerializable {
*/
private int worldSize;
//TODO: This info should be pulled from the Tile class
private static final char INFO_BLOCKED = 0x8000;
private static final char INFO_IRON = 0x0200;
private static final char INFO_COPPER = 0x0100;
@@ -68,11 +69,7 @@ public class World implements MongoSerializable {
* Check if a tile is blocked, either by a game object or an impassable tile type
*/
public boolean isTileBlocked(int x, int y) {
int tile = tileMap.getTileAt(x, y);
return getGameObjectsBlockingAt(x, y).size() > 0 || tile == TileMap.WALL_TILE ||
tile == TileMap.VAULT_WALL || tile == TileMap.VOID;
return getGameObjectsBlockingAt(x, y).size() > 0 || tileMap.getTileAt(x, y).isBlocked();
}
/**
@@ -213,11 +210,10 @@ public class World implements MongoSerializable {
public String toString() {
StringBuilder str = new StringBuilder("World (" + x + ", " + y + ")\n");
int[][] tileMap = this.tileMap.getTiles();
for (int x = 0; x < worldSize; x++) {
for (int y = 0; y < worldSize; y++) {
str.append(tileMap[x][y]).append(" ");
str.append(tileMap.getTileIdAt(x, y)).append(" ");
}
str.append("\n");
}
@@ -260,22 +256,22 @@ public class World implements MongoSerializable {
public char[][] getMapInfo() {
char[][] mapInfo = new char[worldSize][worldSize];
int[][] tiles = tileMap.getTiles();
//Tile
for (int y = 0; y < worldSize; y++) {
for (int x = 0; x < worldSize; x++) {
if (tiles[x][y] == TileMap.PLAIN_TILE) {
if (tileMap.getTileIdAt(x, y) == TilePlain.ID) {
mapInfo[x][y] = 0;
} else if (tiles[x][y] == TileMap.WALL_TILE || tiles[x][y] == TileMap.VAULT_WALL) {
} else if (tileMap.getTileAt(x, y).isBlocked()) {
mapInfo[x][y] = INFO_BLOCKED;
} else if (tiles[x][y] == TileMap.COPPER_TILE) {
//TODO: Tiles should have their .getMapInfo() method
} else if (tileMap.getTileIdAt(x, y) == TileCopper.ID) {
mapInfo[x][y] = INFO_COPPER;
} else if (tiles[x][y] == TileMap.IRON_TILE) {
} else if (tileMap.getTileIdAt(x, y) == TileIron.ID) {
mapInfo[x][y] = INFO_IRON;
}
}

View File

@@ -159,7 +159,7 @@ public class WorldGenerator {
}
world.getTileMap().getTiles()[x][y] = tile;
world.getTileMap().setTileAt(tile, x, y);
}
}
@@ -169,18 +169,18 @@ public class WorldGenerator {
for (int i = 0; i < ironCount; i++) {
Point p = world.getTileMap().getRandomTile(TileMap.PLAIN_TILE);
Point p = world.getTileMap().getRandomTile(TilePlain.ID);
if (p != null) {
world.getTileMap().getTiles()[p.x][p.y] = TileMap.IRON_TILE;
world.getTileMap().setTileAt(new TileIron(), p.x, p.y);
}
}
for (int i = 0; i < copperCount; i++) {
Point p = world.getTileMap().getRandomTile(TileMap.PLAIN_TILE);
Point p = world.getTileMap().getRandomTile(TilePlain.ID);
if (p != null) {
world.getTileMap().getTiles()[p.x][p.y] = TileMap.COPPER_TILE;
world.getTileMap().setTileAt(new TileCopper(), p.x, p.y);
}
}

View File

@@ -3,7 +3,6 @@ package net.simon987.server.websocket;
import net.simon987.server.GameServer;
import net.simon987.server.game.world.World;
import net.simon987.server.logging.LogManager;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.io.IOException;
@@ -30,20 +29,10 @@ public class TerrainRequestHandler implements MessageHandler {
//todo It might be a good idea to cache this
if (world != null) {
JSONObject response = new JSONObject();
JSONArray terrain = new JSONArray();
int[][] tiles = world.getTileMap().getTiles();
for (int x = 0; x < world.getWorldSize(); x++) {
for (int y = 0; y < world.getWorldSize(); y++) {
terrain.add(tiles[y][x]);
}
}
JSONObject response = world.getTileMap().jsonSerialise();
response.put("t", "terrain");
response.put("ok", true);
response.put("terrain", terrain);
response.put("size", world.getWorldSize());
user.getWebSocket().getRemote().sendString(response.toJSONString());