diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotDrill.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotDrill.java index b4207d8..1e0e3a3 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotDrill.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotDrill.java @@ -15,7 +15,9 @@ public class CubotDrill extends CpuHardware { public static final int DEFAULT_ADDRESS = 5; - private static final int GATHER = 1; + private static final int POLL = 1; + private static final int GATHER_SLOW = 2; + private static final int GATHER_FAST = 3; private Cubot cubot; @@ -32,7 +34,11 @@ public class CubotDrill extends CpuHardware { public void handleInterrupt(Status status) { int a = getCpu().getRegisterSet().getRegister("A").getValue(); - if (a == GATHER) { + if (a == POLL) { + + getCpu().getRegisterSet().getRegister("B").setValue(0); + + } else if (a == GATHER_SLOW || a == GATHER_FAST) { if (cubot.getAction() != CubotAction.IDLE) { int tile = cubot.getWorld().getTileMap().getTileAt(cubot.getX(), cubot.getY()); @@ -46,19 +52,18 @@ public class CubotDrill extends CpuHardware { cubot.setCurrentAction(CubotAction.DIGGING); } else { - System.out.println("FAILED: dig"); + //System.out.println("FAILED: dig"); } } - } } @Override public JSONObject serialise() { JSONObject json = new JSONObject(); - json.put("hwid", HWID); + json.put("hwid", (int) HWID); json.put("cubot", cubot.getObjectId()); return json; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotInventory.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotInventory.java index 649c1c5..7557366 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotInventory.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotInventory.java @@ -10,7 +10,7 @@ public class CubotInventory extends CpuHardware { /** * Hardware ID (Should be unique) */ - static final int HWID = 0x0006; + static final char HWID = 0x0006; public static final int DEFAULT_ADDRESS = 6; @@ -47,7 +47,7 @@ public class CubotInventory extends CpuHardware { public JSONObject serialise() { JSONObject json = new JSONObject(); - json.put("hwid", HWID); + json.put("hwid", (int) HWID); json.put("cubot", cubot.getObjectId()); return json; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotLaser.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotLaser.java index ab02c26..af33087 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotLaser.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotLaser.java @@ -15,7 +15,7 @@ public class CubotLaser extends CpuHardware { /** * Hardware ID (Should be unique) */ - static final int HWID = 0x0002; + static final char HWID = 0x0002; public static final int DEFAULT_ADDRESS = 2; @@ -42,7 +42,7 @@ public class CubotLaser extends CpuHardware { if(a == WITHDRAW) { - System.out.println("withdraw"); + //System.out.println("withdraw"); Point frontTile = cubot.getFrontTile(); ArrayList objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y); @@ -55,19 +55,19 @@ public class CubotLaser extends CpuHardware { if (((InventoryHolder) objects.get(0)).takeItem(b)) { cubot.setHeldItem(b); - System.out.println("took " + b); + //System.out.println("took " + b); cubot.setCurrentAction(CubotAction.WITHDRAWING); } else { //The inventory holder can't provide this item //todo Add emote here - System.out.println("DEBUG: FAILED: take (The inventory holder can't provide this item)"); + // System.out.println("DEBUG: FAILED: take (The inventory holder can't provide this item)"); } } } else { //Nothing in front - System.out.println("DEBUG: FAILED: take (Nothing in front or Cubot is busy)"); + // System.out.println("DEBUG: FAILED: take (Nothing in front or Cubot is busy)"); } } @@ -77,7 +77,7 @@ public class CubotLaser extends CpuHardware { public JSONObject serialise() { JSONObject json = new JSONObject(); - json.put("hwid", HWID); + json.put("hwid", (int) HWID); json.put("cubot", cubot.getObjectId()); return json; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotLeg.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotLeg.java index b95ed75..2fb905b 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotLeg.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotLeg.java @@ -19,7 +19,7 @@ public class CubotLeg extends CpuHardware implements JSONSerialisable { /** * Hardware ID (Should be unique) */ - static final int HWID = 0x0001; + static final char HWID = 0x0001; private Cubot cubot; @@ -68,7 +68,7 @@ public class CubotLeg extends CpuHardware implements JSONSerialisable { public JSONObject serialise() { JSONObject json = new JSONObject(); - json.put("hwid", HWID); + json.put("hwid", (int) HWID); json.put("cubot", cubot.getObjectId()); return json; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotRadar.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotLidar.java similarity index 86% rename from Plugin Cubot/src/net/simon987/cubotplugin/CubotRadar.java rename to Plugin Cubot/src/net/simon987/cubotplugin/CubotLidar.java index 87ca35c..23c88c5 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotRadar.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotLidar.java @@ -7,11 +7,12 @@ import net.simon987.server.game.World; import net.simon987.server.game.pathfinding.Node; import net.simon987.server.game.pathfinding.Pathfinder; import net.simon987.server.io.JSONSerialisable; +import net.simon987.server.logging.LogManager; import org.json.simple.JSONObject; import java.util.ArrayList; -public class CubotRadar extends CpuHardware implements JSONSerialisable { +public class CubotLidar extends CpuHardware implements JSONSerialisable { /** * Hardware ID (Should be unique) @@ -26,7 +27,10 @@ public class CubotRadar extends CpuHardware implements JSONSerialisable { private static final int GET_PATH = 2; private static final int GET_MAP = 3; - public CubotRadar(Cubot cubot) { + private static final int MEMORY_MAP_START = 0x0100; + private static final int MEMORY_PATH_START = 0x0000; + + public CubotLidar(Cubot cubot) { this.cubot = cubot; } @@ -104,13 +108,13 @@ public class CubotRadar extends CpuHardware implements JSONSerialisable { mem[counter] = -1; } - System.out.println("DEBUG: path to" + destX + "," + destY); + LogManager.LOGGER.fine("DEBUG: path to" + destX + "," + destY); break; case GET_MAP: char[][] mapInfo = cubot.getWorld().getMapInfo(); - int i = 0; + int i = MEMORY_MAP_START; for (int y = 0; y < World.WORLD_SIZE; y++) { for (int x = 0; x < World.WORLD_SIZE; x++) { getCpu().getMemory().set(i++, mapInfo[x][y]); @@ -125,13 +129,13 @@ public class CubotRadar extends CpuHardware implements JSONSerialisable { public JSONObject serialise() { JSONObject json = new JSONObject(); - json.put("hwid", HWID); + json.put("hwid", (int) HWID); json.put("cubot", cubot.getObjectId()); return json; } - public static CubotRadar deserialize(JSONObject hwJSON){ - return new CubotRadar((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int)(long)hwJSON.get("cubot"))); + public static CubotLidar deserialize(JSONObject hwJSON) { + return new CubotLidar((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot"))); } } diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java index d3a2940..60677f5 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java @@ -43,12 +43,14 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer, return CubotLeg.deserialize(hwJson); case CubotLaser.HWID: return CubotLaser.deserialize(hwJson); - case CubotRadar.HWID: - return CubotRadar.deserialize(hwJson); + case CubotLidar.HWID: + return CubotLidar.deserialize(hwJson); case CubotDrill.HWID: return CubotDrill.deserialize(hwJson); case CubotInventory.HWID: return CubotInventory.deserialize(hwJson); + case Keyboard.HWID: + return Keyboard.deserialize(hwJson); } return null; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/Keyboard.java b/Plugin Cubot/src/net/simon987/cubotplugin/Keyboard.java index bc7dd1c..46830d4 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/Keyboard.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/Keyboard.java @@ -58,7 +58,7 @@ public class Keyboard extends CpuHardware { public JSONObject serialise() { JSONObject json = new JSONObject(); - json.put("hwid", HWID); + json.put("hwid", (int) HWID); json.put("cubot", cubot.getObjectId()); return json; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java b/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java index 25024e5..bbd78c2 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java @@ -25,7 +25,7 @@ public class CpuInitialisationListener implements GameEventListener { legHw.setCpu(cpu); CubotLaser laserHw = new CubotLaser((Cubot) user.getControlledUnit()); laserHw.setCpu(cpu); - CubotRadar radarHw = new CubotRadar((Cubot) user.getControlledUnit()); + CubotLidar radarHw = new CubotLidar((Cubot) user.getControlledUnit()); radarHw.setCpu(cpu); Keyboard keyboard = new Keyboard((Cubot) user.getControlledUnit()); keyboard.setCpu(cpu); @@ -36,7 +36,7 @@ public class CpuInitialisationListener implements GameEventListener { cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS); cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS); - cpu.attachHardware(radarHw, CubotRadar.DEFAULT_ADDRESS); + cpu.attachHardware(radarHw, CubotLidar.DEFAULT_ADDRESS); cpu.attachHardware(keyboard, Keyboard.DEFAULT_ADDRESS); cpu.attachHardware(drillHw, CubotDrill.DEFAULT_ADDRESS); cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS); diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/event/UserCreationListener.java b/Plugin Cubot/src/net/simon987/cubotplugin/event/UserCreationListener.java index d9f94e7..72ed7cd 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/event/UserCreationListener.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/event/UserCreationListener.java @@ -25,7 +25,9 @@ public class UserCreationListener implements GameEventListener { Cubot cubot = new Cubot(); - cubot.setWorld(GameServer.INSTANCE.getGameUniverse().getWorld(0,0)); + cubot.setWorld(GameServer.INSTANCE.getGameUniverse().getWorld( + GameServer.INSTANCE.getConfig().getInt("new_user_worldX"), + GameServer.INSTANCE.getConfig().getInt("new_user_worldY"))); cubot.getWorld().getGameObjects().add(cubot); cubot.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId()); diff --git a/Server/src/net/simon987/server/GameServer.java b/Server/src/net/simon987/server/GameServer.java index 02c16ea..385eae7 100644 --- a/Server/src/net/simon987/server/GameServer.java +++ b/Server/src/net/simon987/server/GameServer.java @@ -116,6 +116,11 @@ public class GameServer implements Runnable { world.update(); } + //Save + if (gameUniverse.getTime() % config.getInt("save_interval") == 0) { + save(new File("save.json")); + } + socketServer.tick(); LogManager.LOGGER.info("Processed " + gameUniverse.getWorlds().size() + " worlds"); diff --git a/Server/src/net/simon987/server/Main.java b/Server/src/net/simon987/server/Main.java index f939735..e90c352 100644 --- a/Server/src/net/simon987/server/Main.java +++ b/Server/src/net/simon987/server/Main.java @@ -11,24 +11,24 @@ public class Main { public static void main(String[] args){ - //TODO: Object information Window (Hover, click ?) //TODO: Docs /* * - Intel 8086 p.14 design * - Memory: Storage organisation: From a storage pov, 8086 memory spaces are * organised as identical arrays of 16-bit words + * - Microprocessor + * - Instruction set + * - */ - //TODO: Website front page - //TODO: Account page - //TODO: Chat (Slack?) - //TODO: Change code documentation (Check for "Database" etc..) - //TODO: Load and save: handle no save / invalid save - // - Make sure the Hardware is saved and can be loaded - //TODO: Add more logs - //TODO: Clean sprites //--------------------------------- + //TODO: Random number generator + //TODO: favicon + //TODO: Email verification + //TODO: Real account page + // Change/reset password + //TODO: Object information Window (Hover, click ?) //TODO: Inventory indicator (Multiple items) //TODO: Software Interrupts (PIC): Interupt flag? /* @@ -54,7 +54,9 @@ public class Main { //TODO: Withdraw animation / action //TODO: Prevent World creation out of bounds, warp around universe //TODO: Multiple Biomass style (and yield, rarity) - + //TODO: Clean sprites + //TODO: Auto-resize + //TODO: Battery Hardware LogManager.initialize(); diff --git a/Server/src/net/simon987/server/assembly/Assembler.java b/Server/src/net/simon987/server/assembly/Assembler.java index cc5ccfa..34ce3c8 100755 --- a/Server/src/net/simon987/server/assembly/Assembler.java +++ b/Server/src/net/simon987/server/assembly/Assembler.java @@ -98,7 +98,7 @@ public class Assembler { line = line.substring(0, line.indexOf(':')); String label = line.trim(); - System.out.println("DEBUG: Label " + label + " @ " + (result.origin + currentOffset)); + LogManager.LOGGER.fine("DEBUG: Label " + label + " @ " + (result.origin + currentOffset)); result.labels.put(label, (char) (result.origin + currentOffset)); } } @@ -127,7 +127,7 @@ public class Assembler { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(bos); - System.out.println(line); + //System.out.println(line); if (line.substring(0, 2).toUpperCase().equals("DW")) { @@ -337,7 +337,7 @@ public class Assembler { } catch (AssemblyException e) { //Ignore error on pass 2 - System.out.println(e); + //System.out.println(e); } } diff --git a/Server/src/net/simon987/server/assembly/CPU.java b/Server/src/net/simon987/server/assembly/CPU.java index da65b40..06808f2 100755 --- a/Server/src/net/simon987/server/assembly/CPU.java +++ b/Server/src/net/simon987/server/assembly/CPU.java @@ -125,7 +125,7 @@ public class CPU implements JSONSerialisable{ if(counter % 1000 == 0){ if (System.currentTimeMillis() >= (startTime + timeout)) { - System.out.println("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double)counter/((double)timeout/1000)/1000000 + "MHz"); + LogManager.LOGGER.fine("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double) counter / ((double) timeout / 1000) / 1000000 + "MHz"); return; } } @@ -147,7 +147,7 @@ public class CPU implements JSONSerialisable{ // LogManager.LOGGER.info(instruction.getMnemonic()); } double elapsed = (System.currentTimeMillis() - startTime); - System.out.println("----------\n" + counter + " instruction in " + elapsed + "ms : " + (double)counter/(elapsed/1000)/1000000 + "MHz"); + LogManager.LOGGER.fine("----------\n" + counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz"); } public void executeInstruction(Instruction instruction, int source, int destination) { @@ -343,12 +343,9 @@ public class CPU implements JSONSerialisable{ CpuHardware hardware = attachedHardware.get(address); - if(hardware instanceof JSONSerialisable){ - - JSONObject serialisedHw = ((JSONSerialisable) hardware).serialise(); - serialisedHw.put("address", address); - hardwareList.add(serialisedHw); - } + JSONObject serialisedHw = hardware.serialise(); + serialisedHw.put("address", address); + hardwareList.add(serialisedHw); } json.put("hardware", hardwareList); diff --git a/Server/src/net/simon987/server/assembly/Instruction.java b/Server/src/net/simon987/server/assembly/Instruction.java index 23e14b8..e791987 100755 --- a/Server/src/net/simon987/server/assembly/Instruction.java +++ b/Server/src/net/simon987/server/assembly/Instruction.java @@ -203,7 +203,7 @@ public abstract class Instruction { //Destination bits are left blank - System.out.println("o1: " + o1.getType()); + //System.out.println("o1: " + o1.getType()); for (byte b : code.bytes()) { out.write(b); diff --git a/Server/src/net/simon987/server/assembly/RegisterSet.java b/Server/src/net/simon987/server/assembly/RegisterSet.java index 552b202..3979f28 100755 --- a/Server/src/net/simon987/server/assembly/RegisterSet.java +++ b/Server/src/net/simon987/server/assembly/RegisterSet.java @@ -149,7 +149,7 @@ public class RegisterSet implements Target, JSONSerialisable { register.put("index", index); register.put("name", getRegister(index).getName()); - register.put("value", getRegister(index).getValue()); + register.put("value", (int) getRegister(index).getValue()); registers.add(register); } diff --git a/Server/src/net/simon987/server/game/GameEffect.java b/Server/src/net/simon987/server/game/GameEffect.java index 87846d2..23cd743 100644 --- a/Server/src/net/simon987/server/game/GameEffect.java +++ b/Server/src/net/simon987/server/game/GameEffect.java @@ -5,11 +5,7 @@ import org.json.simple.JSONObject; /** * Represents a game effect in a World (e.g. Particles made when digging, Error animation, Attack effects etc..) - *

- * The game effect is generated by the server when certain circumstances are met, and inserted into the database. - * The client requests the list of game effects for this World each tick and handles it. This list (called queuedGameEffects) - * is cleared at the beginning of each tick. - *

+ *
* These effects are purely visual and could be changed or ignored by the client */ public class GameEffect implements JSONSerialisable{ diff --git a/Server/src/net/simon987/server/game/GameObject.java b/Server/src/net/simon987/server/game/GameObject.java index 74ea6bc..3ac815a 100755 --- a/Server/src/net/simon987/server/game/GameObject.java +++ b/Server/src/net/simon987/server/game/GameObject.java @@ -122,7 +122,7 @@ public abstract class GameObject implements JSONSerialisable { } else { //Display error when object is trying to walk in a wall //TODO Add emote here - System.out.println("DEBUG: FAILED walk"); + //System.out.println("DEBUG: FAILED walk"); return false; } diff --git a/Server/src/net/simon987/server/game/GameUniverse.java b/Server/src/net/simon987/server/game/GameUniverse.java index 9249876..5d7bc99 100644 --- a/Server/src/net/simon987/server/game/GameUniverse.java +++ b/Server/src/net/simon987/server/game/GameUniverse.java @@ -167,7 +167,10 @@ public class GameUniverse implements JSONSerialisable{ JSONArray users = new JSONArray(); for(User user : this.users){ - users.add(user.serialise()); + if (!user.isGuest()) { + users.add(user.serialise()); + } + } @@ -187,29 +190,35 @@ public class GameUniverse implements JSONSerialisable{ JSONParser parser = new JSONParser(); - try { - FileReader reader = new FileReader(file); - JSONObject universeJson = (JSONObject)parser.parse(reader); + if (file.isFile()) { + try { - time = (long)universeJson.get("time"); - nextObjectId = (int)(long)universeJson.get("nextObjectId"); + FileReader reader = new FileReader(file); + JSONObject universeJson = (JSONObject) parser.parse(reader); - for(JSONObject worldJson : (ArrayList)universeJson.get("worlds")){ - worlds.add(World.deserialize(worldJson)); + time = (long) universeJson.get("time"); + nextObjectId = (int) (long) universeJson.get("nextObjectId"); + + for (JSONObject worldJson : (ArrayList) universeJson.get("worlds")) { + worlds.add(World.deserialize(worldJson)); + } + + for (JSONObject userJson : (ArrayList) universeJson.get("users")) { + users.add(User.deserialize(userJson)); + } + + LogManager.LOGGER.info("Loaded " + worlds.size() + " worlds from file"); + + reader.close(); + + } catch (IOException | ParseException | CancelledException e) { + e.printStackTrace(); } - - for(JSONObject userJson : (ArrayList)universeJson.get("users")){ - users.add(User.deserialize(userJson)); - } - - System.out.println("Loaded " + worlds.size()); - - reader.close(); - - } catch (IOException | ParseException | CancelledException e) { - e.printStackTrace(); + } else { + LogManager.LOGGER.severe("Couldn't load save file save.json, creating empty game universe."); } + } public int getNextObjectId() { diff --git a/Server/src/net/simon987/server/game/World.java b/Server/src/net/simon987/server/game/World.java index 3b5814e..2d28595 100644 --- a/Server/src/net/simon987/server/game/World.java +++ b/Server/src/net/simon987/server/game/World.java @@ -2,6 +2,7 @@ package net.simon987.server.game; import net.simon987.server.game.pathfinding.Pathfinder; import net.simon987.server.io.JSONSerialisable; +import net.simon987.server.logging.LogManager; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -68,8 +69,8 @@ public class World implements JSONSerialisable{ for(GameObject object : gameObjects_){ if(object.isDead()){ - System.out.println("Removed" + object.getObjectId()); gameObjects.remove(object); + LogManager.LOGGER.fine("Removed object " + object + " id: " + object.getObjectId()); } if (object instanceof Updatable) { ((Updatable) object).update(); @@ -198,7 +199,7 @@ public class World implements JSONSerialisable{ if(!isTileBlocked(rx, ry)){ - Object path = Pathfinder.findPath(this, rx, ry, 1,1,0); + Object path = Pathfinder.findPath(this, rx, ry, 0, 6, 0); if(path != null) { return new Point(rx, ry); diff --git a/Server/src/net/simon987/server/user/User.java b/Server/src/net/simon987/server/user/User.java index 1db9e60..bf0c10b 100755 --- a/Server/src/net/simon987/server/user/User.java +++ b/Server/src/net/simon987/server/user/User.java @@ -22,6 +22,8 @@ public class User implements JSONSerialisable{ private ControllableUnit controlledUnit; + private boolean guest; + public User() throws CancelledException { GameEvent event = new UserCreationEvent(this); GameServer.INSTANCE.getEventDispatcher().dispatch(event); @@ -47,6 +49,8 @@ public class User implements JSONSerialisable{ json.put("cpu", cpu.serialise()); return json; + + } public static User deserialize(JSONObject userJson) throws CancelledException { @@ -96,5 +100,11 @@ public class User implements JSONSerialisable{ this.username = username; } + public boolean isGuest() { + return guest; + } + public void setGuest(boolean guest) { + this.guest = guest; + } } diff --git a/Server/src/net/simon987/server/webserver/OnlineUser.java b/Server/src/net/simon987/server/webserver/OnlineUser.java index be24b1f..076abbf 100644 --- a/Server/src/net/simon987/server/webserver/OnlineUser.java +++ b/Server/src/net/simon987/server/webserver/OnlineUser.java @@ -44,6 +44,7 @@ public class OnlineUser { public void setGuest(boolean guest) { this.guest = guest; + user.setGuest(guest); } public boolean isGuest() { diff --git a/Server/src/net/simon987/server/webserver/SocketServer.java b/Server/src/net/simon987/server/webserver/SocketServer.java index 7a192ed..c9fda9f 100644 --- a/Server/src/net/simon987/server/webserver/SocketServer.java +++ b/Server/src/net/simon987/server/webserver/SocketServer.java @@ -6,14 +6,34 @@ import net.simon987.server.logging.LogManager; import net.simon987.server.user.User; import org.java_websocket.WebSocket; import org.java_websocket.handshake.ClientHandshake; +import org.java_websocket.server.DefaultSSLWebSocketServerFactory; import org.java_websocket.server.WebSocketServer; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.xml.bind.DatatypeConverter; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; + public class SocketServer extends WebSocketServer { private OnlineUserManager userManager = new OnlineUserManager(); @@ -25,6 +45,21 @@ public class SocketServer extends WebSocketServer { public SocketServer(InetSocketAddress address, ServerConfiguration config) { super(address); + if (config.getInt("use_secure_webSocket") != 0) { + + SSLContext context = getContext(config.getString("cert_path")); + if (context != null) { + setWebSocketFactory(new DefaultSSLWebSocketServerFactory(context)); + + LogManager.LOGGER.info("(WS) Enabled secure webSocket"); + } else { + LogManager.LOGGER.severe("(WS) Failed to create SSL context"); + } + } + + setConnectionLostTimeout(30); + + database = new SocketServerDatabase(config); messageEventDispatcher.addHandler(new UserInfoRequestHandler()); @@ -94,7 +129,7 @@ public class SocketServer extends WebSocketServer { } else { - LogManager.LOGGER.info("(WS) FIXME: SocketServer:onMessage"); + LogManager.LOGGER.severe("(WS) FIXME: SocketServer:onMessage"); } @@ -103,12 +138,13 @@ public class SocketServer extends WebSocketServer { @Override public void onMessage(WebSocket conn, ByteBuffer message) { - System.out.println("received ByteBuffer from " + conn.getRemoteSocketAddress()); + //System.out.println("received ByteBuffer from " + conn.getRemoteSocketAddress()); } @Override public void onError(WebSocket conn, Exception ex) { - System.err.println("an error occured on connection " + conn.getRemoteSocketAddress() + ':' + ex); + + LogManager.LOGGER.severe("an error occured on connection " + conn.getRemoteSocketAddress() + ':' + ex); userManager.remove(userManager.getUser(conn)); conn.close(); @@ -162,4 +198,89 @@ public class SocketServer extends WebSocketServer { public OnlineUserManager getUserManager() { return userManager; } + + + /** + * See https://github.com/TooTallNate/Java-WebSocket/blob/master/src/main/example/SSLServerLetsEncryptExample.java + */ + /* + * * Copyright (c) 2010-2017 Nathan Rajlich + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + */ + private static SSLContext getContext(String pathTo) { + SSLContext context; + String password = "MAR"; + try { + context = SSLContext.getInstance("TLS"); + + byte[] certBytes = parseDERFromPEM(getBytes(new File(pathTo + File.separator + "cert.pem")), + "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----"); + byte[] keyBytes = parseDERFromPEM(getBytes(new File(pathTo + File.separator + "privkey.pem")), + "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"); + + X509Certificate cert = generateCertificateFromDER(certBytes); + RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes); + + KeyStore keystore = KeyStore.getInstance("JKS"); + keystore.load(null); + keystore.setCertificateEntry("cert-alias", cert); + keystore.setKeyEntry("key-alias", key, password.toCharArray(), new Certificate[]{cert}); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(keystore, password.toCharArray()); + + KeyManager[] km = kmf.getKeyManagers(); + + context.init(km, null, null); + } catch (Exception e) { + context = null; + } + return context; + } + + private static byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) { + String data = new String(pem); + String[] tokens = data.split(beginDelimiter); + tokens = tokens[1].split(endDelimiter); + return DatatypeConverter.parseBase64Binary(tokens[0]); + } + + private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException { + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); + + KeyFactory factory = KeyFactory.getInstance("RSA"); + + return (RSAPrivateKey) factory.generatePrivate(spec); + } + + private static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + + return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes)); + } + + private static byte[] getBytes(File file) { + byte[] bytesArray = new byte[(int) file.length()]; + + FileInputStream fis; + try { + fis = new FileInputStream(file); + fis.read(bytesArray); //read file into bytes[] + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bytesArray; + } } \ No newline at end of file