diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java b/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java index bc75d55..e6a87c6 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java @@ -1,6 +1,7 @@ package net.simon987.cubotplugin; import net.simon987.server.GameServer; +import net.simon987.server.assembly.Memory; import net.simon987.server.game.ControllableUnit; import net.simon987.server.game.Direction; import net.simon987.server.game.GameObject; @@ -29,6 +30,8 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit { private ArrayList keyboardBuffer = new ArrayList<>(); + private FloppyDisk floppyDisk; + private User parent; private int energy; @@ -181,4 +184,9 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit { public int getMaxEnergy() { return maxEnergy; } + + @Override + public Memory getFloppyData() { + return ((CubotFloppyDrive) getParent().getCpu().getHardware(CubotFloppyDrive.DEFAULT_ADDRESS)).getFloppy().getMemory(); + } } diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java new file mode 100644 index 0000000..494c335 --- /dev/null +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java @@ -0,0 +1,105 @@ +package net.simon987.cubotplugin; + +import net.simon987.server.GameServer; +import net.simon987.server.assembly.CpuHardware; +import net.simon987.server.assembly.Status; +import org.json.simple.JSONObject; + +public class CubotFloppyDrive extends CpuHardware { + + /** + * Hardware ID (Should be unique) + */ + static final char HWID = 0x000B; + + public static final int DEFAULT_ADDRESS = 0x000B; + + private static final int POLL = 1; + private static final int READ_SECTOR = 2; + private static final int WRITE_SECTOR = 3; + + private Cubot cubot; + private FloppyDisk floppyDisk; + + public CubotFloppyDrive(Cubot cubot) { + this.cubot = cubot; + + this.floppyDisk = new FloppyDisk();//todo remove + } + + @Override + public void handleInterrupt(Status status) { + int a = getCpu().getRegisterSet().getRegister("A").getValue(); + + if (a == POLL) { + + if (floppyDisk != null) { + getCpu().getRegisterSet().getRegister("B").setValue(0); + } else { + getCpu().getRegisterSet().getRegister("B").setValue(1); + } + + } else if (a == READ_SECTOR) { + + if (floppyDisk == null) { + getCpu().getRegisterSet().getRegister("B").setValue(0); + } else { + getCpu().getRegisterSet().getRegister("B").setValue(1); + + int x = getCpu().getRegisterSet().getRegister("X").getValue(); + int y = getCpu().getRegisterSet().getRegister("Y").getValue(); + + floppyDisk.readSector(x, cubot.getParent().getCpu().getMemory(), y); + } + + + } else if (a == WRITE_SECTOR) { + if (floppyDisk == null) { + getCpu().getRegisterSet().getRegister("B").setValue(0); + } else { + getCpu().getRegisterSet().getRegister("B").setValue(1); + + int x = getCpu().getRegisterSet().getRegister("X").getValue(); + int y = getCpu().getRegisterSet().getRegister("Y").getValue(); + + floppyDisk.writeSector(x, cubot.getParent().getCpu().getMemory(), y); + } + } + + } + + @Override + public char getId() { + return HWID; + } + + @Override + public JSONObject serialise() { + JSONObject json = new JSONObject(); + json.put("hwid", (int) HWID); + json.put("cubot", cubot.getObjectId()); + + if (floppyDisk != null) { + json.put("floppy", floppyDisk.serialise()); + } + + return json; + } + + public static CubotFloppyDrive deserialize(JSONObject hwJSON) { + + CubotFloppyDrive drive = new CubotFloppyDrive((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot"))); + + if (hwJSON.containsKey("floppy")) { + drive.floppyDisk = FloppyDisk.deserialise((JSONObject) hwJSON.get("floppy")); + } else { + drive.floppyDisk = new FloppyDisk(); + } + + return drive; + } + + public FloppyDisk getFloppy() { + return floppyDisk; + } +} diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java index b96ad16..960deee 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotPlugin.java @@ -55,6 +55,8 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer, return CubotHologram.deserialize(hwJson); case CubotBattery.HWID: return CubotBattery.deserialize(hwJson); + case CubotFloppyDrive.HWID: + return CubotFloppyDrive.deserialize(hwJson); } return null; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java b/Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java new file mode 100644 index 0000000..f32e5a8 --- /dev/null +++ b/Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java @@ -0,0 +1,106 @@ +package net.simon987.cubotplugin; + + +import net.simon987.server.assembly.Memory; +import net.simon987.server.io.JSONSerialisable; +import net.simon987.server.logging.LogManager; +import org.json.simple.JSONObject; + +/** + * Represents a floppy disk that is inside a floppy drive. + * Floppies contains 80 tracks with 18 sectors per track. + * That's 1440 sectors of 512 words. (total 1,474,560 bytes / 737,280 words / 1.44Mb) + */ +public class FloppyDisk implements JSONSerialisable { + + /** + * Contents of the disk + */ + private Memory memory; + + /** + * Current location of the read/write head. + * Used to calculate seek time + */ + private int rwHeadTrack = 0; + + + public FloppyDisk() { + this.memory = new Memory(1024 * 1440); + } + + /** + * Read 512 words from the specified sector to cpu memory at specified address + * + * @param sector sector to read (0-1440) + * @param cpuMemory Cpu memory to write to + * @param ramAddress address of the data to write in CPU memory + * @return Whether or not the read operation was in the same track as the last r/w + */ + public boolean readSector(int sector, Memory cpuMemory, int ramAddress) { + + cpuMemory.write(ramAddress, memory.getBytes(), sector * 512, 1024); + + LogManager.LOGGER.fine("Read 512 words from floppy sector:" + sector + " to memory addr:" + ramAddress); + + //Calculate seek time + int deltaTrack = (sector / 80) - rwHeadTrack; + + if (deltaTrack != 0) { + rwHeadTrack = (sector / 80); + return false; + } else { + return true; + } + } + + /** + * Write 512 words to the specified sector from cpu memory at the specified address + * + * @param sector sector to write (0-1440) + * @param cpuMemory Cpu memory to read from + * @param ramAddress address of the data to read in CPU memory + * @return Whether or not the read operation was in the same track as the last r/w + */ + public boolean writeSector(int sector, Memory cpuMemory, int ramAddress) { + + memory.write(sector * 512, cpuMemory.getBytes(), ramAddress * 2, 1024); + + LogManager.LOGGER.fine("Wrote 512 words to floppy sector:" + sector + " from memory addr:" + ramAddress); + + //Calculate seek time + int deltaTrack = (sector / 80) - rwHeadTrack; + + if (deltaTrack != 0) { + rwHeadTrack = (sector / 80); + return false; + } else { + return true; + } + } + + + @Override + public JSONObject serialise() { + + JSONObject json = new JSONObject(); + json.put("rwHeadTrack", rwHeadTrack); + json.put("memory", memory.serialise()); + + return json; + } + + public static FloppyDisk deserialise(JSONObject json) { + + FloppyDisk floppyDisk = new FloppyDisk(); + + floppyDisk.rwHeadTrack = (int) (long) json.get("rwHeadTrack"); + floppyDisk.memory = Memory.deserialize((JSONObject) json.get("memory")); + + return floppyDisk; + } + + public Memory getMemory() { + return memory; + } +} diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java b/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java index 00df370..829ff35 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/event/CpuInitialisationListener.java @@ -37,6 +37,8 @@ public class CpuInitialisationListener implements GameEventListener { emoteHw.setCpu(cpu); CubotBattery batteryHw = new CubotBattery((Cubot) user.getControlledUnit()); batteryHw.setCpu(cpu); + CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit()); + floppyHw.setCpu(cpu); cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS); cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS); @@ -47,5 +49,6 @@ public class CpuInitialisationListener implements GameEventListener { cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS); cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS); cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS); + cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS); } } diff --git a/Server/src/net/simon987/server/assembly/Memory.java b/Server/src/net/simon987/server/assembly/Memory.java index d8cc9a9..97535f2 100755 --- a/Server/src/net/simon987/server/assembly/Memory.java +++ b/Server/src/net/simon987/server/assembly/Memory.java @@ -55,7 +55,7 @@ public class Memory implements Target, JSONSerialisable { /** * Write x words from an array at an offset */ - public boolean write(int offset, byte[] bytes, int count) { + public boolean write(int offset, byte[] bytes, int srcOffset, int count) { offset = (char)offset * 2; @@ -64,7 +64,7 @@ public class Memory implements Target, JSONSerialisable { return false; } - System.arraycopy(bytes, 0, this.bytes, offset, count); + System.arraycopy(bytes, srcOffset, this.bytes, offset, count); return true; } @@ -122,18 +122,6 @@ public class Memory implements Target, JSONSerialisable { e.printStackTrace(); } - //To deflate - - /* - ByteArrayOutputStream stream2 = new ByteArrayOutputStream(); - Inflater decompresser = new Inflater(true); - InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(stream2, decompresser); - inflaterOutputStream.write(output); - inflaterOutputStream.close(); - byte[] output2 = stream2.toByteArray(); - */ - - return json; } @@ -157,4 +145,8 @@ public class Memory implements Target, JSONSerialisable { return memory; } + + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } } diff --git a/Server/src/net/simon987/server/game/ControllableUnit.java b/Server/src/net/simon987/server/game/ControllableUnit.java index a08f7c6..2a4c714 100644 --- a/Server/src/net/simon987/server/game/ControllableUnit.java +++ b/Server/src/net/simon987/server/game/ControllableUnit.java @@ -1,5 +1,6 @@ package net.simon987.server.game; +import net.simon987.server.assembly.Memory; import net.simon987.server.user.User; import java.util.ArrayList; @@ -14,4 +15,6 @@ public interface ControllableUnit { ArrayList getKeyboardBuffer(); + Memory getFloppyData(); + } diff --git a/Server/src/net/simon987/server/game/GameUniverse.java b/Server/src/net/simon987/server/game/GameUniverse.java index 6f1b22a..0007246 100644 --- a/Server/src/net/simon987/server/game/GameUniverse.java +++ b/Server/src/net/simon987/server/game/GameUniverse.java @@ -29,7 +29,7 @@ public class GameUniverse implements JSONSerialisable{ private int nextObjectId = 0; - private int maxWidth = 3; //0xFFFF + private int maxWidth = 0xFFFF; public GameUniverse(ServerConfiguration config) { @@ -113,9 +113,11 @@ public class GameUniverse implements JSONSerialisable{ user.getCpu().getMemory().clear(); //Write assembled code to mem - user.getCpu().getMemory().write((short) ar.origin, ar.bytes, ar.bytes.length); + user.getCpu().getMemory().write((short) ar.origin, ar.bytes, 0, ar.bytes.length); user.getCpu().setCodeSegmentOffset(ar.origin); + //Init + } else { user = new User(null); } diff --git a/Server/src/net/simon987/server/webserver/CodeUploadHandler.java b/Server/src/net/simon987/server/webserver/CodeUploadHandler.java index f68f727..9aade12 100644 --- a/Server/src/net/simon987/server/webserver/CodeUploadHandler.java +++ b/Server/src/net/simon987/server/webserver/CodeUploadHandler.java @@ -28,7 +28,7 @@ public class CodeUploadHandler implements MessageHandler { user.getUser().getCpu().getMemory().clear(); //Write assembled code to mem - user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, ar.bytes.length); + user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, 0, ar.bytes.length); user.getUser().getCpu().setCodeSegmentOffset(ar.origin); JSONObject response = new JSONObject(); diff --git a/Server/src/net/simon987/server/webserver/FloppyHandler.java b/Server/src/net/simon987/server/webserver/FloppyHandler.java new file mode 100644 index 0000000..f6d8d03 --- /dev/null +++ b/Server/src/net/simon987/server/webserver/FloppyHandler.java @@ -0,0 +1,36 @@ +package net.simon987.server.webserver; + +import net.simon987.server.GameServer; +import net.simon987.server.logging.LogManager; +import org.json.simple.JSONObject; + +public class FloppyHandler implements MessageHandler { + + SocketServerDatabase db = new SocketServerDatabase(GameServer.INSTANCE.getConfig()); + + @Override + public void handle(OnlineUser user, JSONObject json) { + + if (json.get("t").equals("floppyDown")) { + + LogManager.LOGGER.info("(WS) Floppy download request from " + user.getUser().getUsername()); + + + //floppy + byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes(); + + user.getWebSocket().send(bytes); + + } else if (json.get("t").equals("floppyUp")) { + + LogManager.LOGGER.info("(WS) Floppy upload request from " + user.getUser().getUsername()); + + //Check newly uploaded file on the database + byte[] bytes = db.getFloppy(user.getUser().getUsername()); + + if (bytes != null) { + user.getUser().getControlledUnit().getFloppyData().setBytes(bytes); + } + } + } +} diff --git a/Server/src/net/simon987/server/webserver/SocketServer.java b/Server/src/net/simon987/server/webserver/SocketServer.java index c9fda9f..e81e8e0 100644 --- a/Server/src/net/simon987/server/webserver/SocketServer.java +++ b/Server/src/net/simon987/server/webserver/SocketServer.java @@ -68,6 +68,7 @@ public class SocketServer extends WebSocketServer { messageEventDispatcher.addHandler(new CodeUploadHandler()); messageEventDispatcher.addHandler(new CodeRequestHandler()); messageEventDispatcher.addHandler(new KeypressHandler()); + messageEventDispatcher.addHandler(new FloppyHandler()); } diff --git a/Server/src/net/simon987/server/webserver/SocketServerDatabase.java b/Server/src/net/simon987/server/webserver/SocketServerDatabase.java index dad9451..e938b82 100644 --- a/Server/src/net/simon987/server/webserver/SocketServerDatabase.java +++ b/Server/src/net/simon987/server/webserver/SocketServerDatabase.java @@ -4,10 +4,7 @@ import net.simon987.server.ServerConfiguration; import net.simon987.server.io.DatabaseManager; import net.simon987.server.logging.LogManager; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.sql.*; class SocketServerDatabase extends DatabaseManager { @@ -48,4 +45,39 @@ class SocketServerDatabase extends DatabaseManager { return null; } + byte[] getFloppy(String username) { + + Connection connection = null; + try { + connection = getConnection(); + + PreparedStatement p = connection.prepareStatement("SELECT floppyData FROM mar_user WHERE username=?"); + p.setString(1, username); + + ResultSet rs = p.executeQuery(); + + if (rs.next()) { + Blob blob = rs.getBlob("floppyData"); + + if (blob != null) { + return blob.getBytes(1, (int) blob.length() - 1); + } + } + + } catch (SQLException e) { + LogManager.LOGGER.severe("MySQL Error " + e.getErrorCode() + ": " + e.getMessage()); + + } finally { + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + return null; + + } + + + } diff --git a/Server/test/net/simon987/server/assembly/MemoryTest.java b/Server/test/net/simon987/server/assembly/MemoryTest.java index b26c3c2..22b1877 100644 --- a/Server/test/net/simon987/server/assembly/MemoryTest.java +++ b/Server/test/net/simon987/server/assembly/MemoryTest.java @@ -36,14 +36,14 @@ public class MemoryTest { Memory memory = new Memory(memorySize); - assertTrue(memory.write(0, new byte[memorySize], memorySize)); - assertFalse(memory.write(0, new byte[memorySize], memorySize + 1)); - assertFalse(memory.write(0, new byte[memorySize], -1)); - assertFalse(memory.write(-1, new byte[memorySize], 10)); + assertTrue(memory.write(0, new byte[memorySize], 0, memorySize)); + assertFalse(memory.write(0, new byte[memorySize], 0, memorySize + 1)); + assertFalse(memory.write(0, new byte[memorySize], 0, -1)); + assertFalse(memory.write(-1, new byte[memorySize], 0, 10)); - assertFalse(memory.write(memorySize / 2, new byte[15], 1)); - assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 11)); - assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 10)); + assertFalse(memory.write(memorySize / 2, new byte[15], 0, 1)); + assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 0, 11)); + assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 0, 10)); }