mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-12-14 15:19:04 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8701007ad9 | ||
|
|
cfb8050cee | ||
|
|
da7d050661 | ||
|
|
3ee9b4be95 | ||
|
|
42421b7710 | ||
|
|
9979986c6a | ||
|
|
c5abe2efc5 | ||
|
|
fdfa568e07 | ||
|
|
1bf1682cb3 |
@@ -1,6 +1,7 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
|
import net.simon987.server.assembly.Memory;
|
||||||
import net.simon987.server.game.ControllableUnit;
|
import net.simon987.server.game.ControllableUnit;
|
||||||
import net.simon987.server.game.Direction;
|
import net.simon987.server.game.Direction;
|
||||||
import net.simon987.server.game.GameObject;
|
import net.simon987.server.game.GameObject;
|
||||||
@@ -29,6 +30,8 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
|||||||
|
|
||||||
private ArrayList<Integer> keyboardBuffer = new ArrayList<>();
|
private ArrayList<Integer> keyboardBuffer = new ArrayList<>();
|
||||||
|
|
||||||
|
private FloppyDisk floppyDisk;
|
||||||
|
|
||||||
private User parent;
|
private User parent;
|
||||||
|
|
||||||
private int energy;
|
private int energy;
|
||||||
@@ -181,4 +184,9 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
|||||||
public int getMaxEnergy() {
|
public int getMaxEnergy() {
|
||||||
return maxEnergy;
|
return maxEnergy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Memory getFloppyData() {
|
||||||
|
return ((CubotFloppyDrive) getParent().getCpu().getHardware(CubotFloppyDrive.DEFAULT_ADDRESS)).getFloppy().getMemory();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
107
Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java
Normal file
107
Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 {
|
||||||
|
if (cubot.spendEnergy(1)) {
|
||||||
|
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 {
|
||||||
|
if (cubot.spendEnergy(1)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,8 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
|
|||||||
return CubotHologram.deserialize(hwJson);
|
return CubotHologram.deserialize(hwJson);
|
||||||
case CubotBattery.HWID:
|
case CubotBattery.HWID:
|
||||||
return CubotBattery.deserialize(hwJson);
|
return CubotBattery.deserialize(hwJson);
|
||||||
|
case CubotFloppyDrive.HWID:
|
||||||
|
return CubotFloppyDrive.deserialize(hwJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
109
Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java
Normal file
109
Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Memory;
|
||||||
|
import net.simon987.server.io.JSONSerialisable;
|
||||||
|
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) {
|
||||||
|
|
||||||
|
if (sector <= 1440) {
|
||||||
|
cpuMemory.write(ramAddress, memory.getBytes(), sector * 1024, 1024);
|
||||||
|
|
||||||
|
//Calculate seek time
|
||||||
|
int deltaTrack = (sector / 80) - rwHeadTrack;
|
||||||
|
|
||||||
|
if (deltaTrack != 0) {
|
||||||
|
rwHeadTrack = (sector / 80);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
|
||||||
|
if (sector <= 1440) {
|
||||||
|
memory.write(sector * 512, cpuMemory.getBytes(), ramAddress * 2, 1024);
|
||||||
|
|
||||||
|
//Calculate seek time
|
||||||
|
int deltaTrack = (sector / 80) - rwHeadTrack;
|
||||||
|
|
||||||
|
if (deltaTrack != 0) {
|
||||||
|
rwHeadTrack = (sector / 80);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,8 @@ public class CpuInitialisationListener implements GameEventListener {
|
|||||||
emoteHw.setCpu(cpu);
|
emoteHw.setCpu(cpu);
|
||||||
CubotBattery batteryHw = new CubotBattery((Cubot) user.getControlledUnit());
|
CubotBattery batteryHw = new CubotBattery((Cubot) user.getControlledUnit());
|
||||||
batteryHw.setCpu(cpu);
|
batteryHw.setCpu(cpu);
|
||||||
|
CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit());
|
||||||
|
floppyHw.setCpu(cpu);
|
||||||
|
|
||||||
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
|
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(laserHw, CubotLaser.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(invHw, CubotInventory.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
|
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
|
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
|
||||||
|
cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -1,3 +1,11 @@
|
|||||||
# Much-Assembly-Required
|
# [Live demo](https://muchassemblyrequired.com)
|
||||||
|
Program the 8086-like microprocessor of a robot in a grid-based multiplayer world. The game is web based so no installation is required.
|
||||||
|
In its current state, players can walk around the game universe and collect Biomass blobs & Iron/copper ore using the online code editor.
|
||||||
|
|
||||||
https://muchassemblyrequired.com
|

|
||||||
|
|
||||||
|
Wiki: [GitHub](https://github.com/simon987/Much-Assembly-Required/wiki)
|
||||||
|
Chat: [Slack](https://join.slack.com/t/muchassemblyrequired/shared_invite/enQtMjY3Mjc1OTUwNjEwLTkyOTIwOTA5OGY4MDVlMGI4NzM5YzlhMWJiMGY1OWE2NjUxODQ1NWQ1YTcxMTA1NGZkYzNjYzMyM2E1ODdmNzg)
|
||||||
|
|
||||||
|
|
||||||
|
_Building instructions coming soon_
|
||||||
|
|||||||
@@ -104,11 +104,18 @@ public class GameServer implements Runnable {
|
|||||||
gameUniverse.incrementTime();
|
gameUniverse.incrementTime();
|
||||||
|
|
||||||
//Process user code
|
//Process user code
|
||||||
for(User user : gameUniverse.getUsers()){
|
ArrayList<User> users_ = gameUniverse.getUsers();
|
||||||
|
for (User user : users_) {
|
||||||
|
|
||||||
if(user.getCpu() != null){
|
if(user.getCpu() != null){
|
||||||
|
try {
|
||||||
user.getCpu().reset();
|
user.getCpu().reset();
|
||||||
user.getCpu().execute();
|
user.getCpu().execute();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.LOGGER.severe("Error executing " + user.getUsername() + "'s code");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ public class Assembler {
|
|||||||
* usage: constant_name EQU <immediate_value>
|
* usage: constant_name EQU <immediate_value>
|
||||||
* A constant treated the same way as a label.
|
* A constant treated the same way as a label.
|
||||||
*/
|
*/
|
||||||
|
line = line.trim();
|
||||||
String[] tokens = line.split("\\s+");
|
String[] tokens = line.split("\\s+");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,10 @@ public class CPU implements JSONSerialisable{
|
|||||||
instructionSet.add(new HwiInstruction(this));
|
instructionSet.add(new HwiInstruction(this));
|
||||||
instructionSet.add(new HwqInstruction(this));
|
instructionSet.add(new HwqInstruction(this));
|
||||||
instructionSet.add(new XchgInstruction(this));
|
instructionSet.add(new XchgInstruction(this));
|
||||||
|
instructionSet.add(new JcInstruction(this));
|
||||||
|
instructionSet.add(new JncInstruction(this));
|
||||||
|
instructionSet.add(new JnoInstruction(this));
|
||||||
|
instructionSet.add(new JoInstruction(this));
|
||||||
|
|
||||||
status = new Status();
|
status = new Status();
|
||||||
memory = new Memory(config.getInt("memory_size"));
|
memory = new Memory(config.getInt("memory_size"));
|
||||||
@@ -148,7 +152,7 @@ public class CPU implements JSONSerialisable{
|
|||||||
// LogManager.LOGGER.info(instruction.getMnemonic());
|
// LogManager.LOGGER.info(instruction.getMnemonic());
|
||||||
}
|
}
|
||||||
double elapsed = (System.currentTimeMillis() - startTime);
|
double elapsed = (System.currentTimeMillis() - startTime);
|
||||||
LogManager.LOGGER.fine("----------\n" + counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
|
LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void executeInstruction(Instruction instruction, int source, int destination) {
|
public void executeInstruction(Instruction instruction, int source, int destination) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.simon987.server.assembly;
|
package net.simon987.server.assembly;
|
||||||
|
|
||||||
import net.simon987.server.assembly.instruction.*;
|
import net.simon987.server.assembly.instruction.*;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
@@ -31,12 +32,18 @@ public class DefaultInstructionSet implements InstructionSet {
|
|||||||
add(new AndInstruction());
|
add(new AndInstruction());
|
||||||
add(new OrInstruction());
|
add(new OrInstruction());
|
||||||
add(new ShlInstruction());
|
add(new ShlInstruction());
|
||||||
|
add(new SalInstruction()); //Alias is added
|
||||||
add(new ShrInstruction());
|
add(new ShrInstruction());
|
||||||
add(new XorInstruction());
|
add(new XorInstruction());
|
||||||
add(new TestInstruction());
|
add(new TestInstruction());
|
||||||
add(new CmpInstruction());
|
add(new CmpInstruction());
|
||||||
add(new NegInstruction());
|
add(new NegInstruction());
|
||||||
add(new NotInstruction());
|
add(new NotInstruction());
|
||||||
|
add(new RorInstruction());
|
||||||
|
add(new RolInstruction());
|
||||||
|
add(new RclInstruction());
|
||||||
|
add(new RcrInstruction());
|
||||||
|
add(new SarInstruction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,6 +90,12 @@ public class DefaultInstructionSet implements InstructionSet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(Instruction instruction) {
|
public void add(Instruction instruction) {
|
||||||
|
if (instructionMap.containsKey(instruction.getOpCode())) {
|
||||||
|
LogManager.LOGGER.fine(instruction.getMnemonic() + " instruction is an alias for " +
|
||||||
|
instructionMap.get(instruction.getOpCode()).getMnemonic());
|
||||||
|
} else {
|
||||||
instructionMap.put(instruction.getOpCode(), instruction);
|
instructionMap.put(instruction.getOpCode(), instruction);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,16 +55,16 @@ public class Memory implements Target, JSONSerialisable {
|
|||||||
/**
|
/**
|
||||||
* Write x words from an array at an offset
|
* 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;
|
offset = (char)offset * 2;
|
||||||
|
|
||||||
|
|
||||||
if (offset + count > this.bytes.length || count < 0 || offset < 0) {
|
if (offset + count > this.bytes.length || count < 0 || offset < 0 || srcOffset >= bytes.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.arraycopy(bytes, 0, this.bytes, offset, count);
|
System.arraycopy(bytes, srcOffset, this.bytes, offset, count);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,18 +122,6 @@ public class Memory implements Target, JSONSerialisable {
|
|||||||
e.printStackTrace();
|
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;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,4 +145,8 @@ public class Memory implements Target, JSONSerialisable {
|
|||||||
|
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBytes(byte[] bytes) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.CPU;
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
public class JcInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 33;
|
||||||
|
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public JcInstruction(CPU cpu) {
|
||||||
|
super("jc", OPCODE);
|
||||||
|
this.cpu = cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target src, int srcIndex, Status status) {
|
||||||
|
if (status.isCarryFlag()) {
|
||||||
|
cpu.setIp((char) src.get(srcIndex));
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(int src, Status status) {
|
||||||
|
if (status.isCarryFlag()) {
|
||||||
|
cpu.setIp((char) src);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.CPU;
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
public class JncInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 34;
|
||||||
|
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public JncInstruction(CPU cpu) {
|
||||||
|
super("jnc", OPCODE);
|
||||||
|
this.cpu = cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target src, int srcIndex, Status status) {
|
||||||
|
if (!status.isCarryFlag()) {
|
||||||
|
cpu.setIp((char) src.get(srcIndex));
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(int src, Status status) {
|
||||||
|
if (!status.isCarryFlag()) {
|
||||||
|
cpu.setIp((char) src);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.CPU;
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
|
||||||
|
public class JnoInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 37;
|
||||||
|
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public JnoInstruction(CPU cpu) {
|
||||||
|
super("jno", OPCODE);
|
||||||
|
this.cpu = cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target src, int srcIndex, Status status) {
|
||||||
|
if (!status.isOverflowFlag()) {
|
||||||
|
cpu.setIp((char) src.get(srcIndex));
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(int src, Status status) {
|
||||||
|
if (!status.isOverflowFlag()) {
|
||||||
|
cpu.setIp((char) src);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.CPU;
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
public class JoInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 36;
|
||||||
|
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public JoInstruction(CPU cpu) {
|
||||||
|
super("jo", OPCODE);
|
||||||
|
this.cpu = cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target src, int srcIndex, Status status) {
|
||||||
|
if (status.isOverflowFlag()) {
|
||||||
|
cpu.setIp((char) src.get(srcIndex));
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(int src, Status status) {
|
||||||
|
if (status.isOverflowFlag()) {
|
||||||
|
cpu.setIp((char) src);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* +---------------------+
|
||||||
|
* | |
|
||||||
|
* CF < 0<0<0<0<0<0<0<0 <-+
|
||||||
|
*/
|
||||||
|
public class RclInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 39;
|
||||||
|
|
||||||
|
public RclInstruction() {
|
||||||
|
super("rcl", OPCODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
|
int count = src.get(srcIndex) % 17;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
int signBit = (destination & 0x8000);
|
||||||
|
|
||||||
|
if (status.isCarryFlag()) {
|
||||||
|
destination |= 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = (destination << count) | (destination >>> (17 - count));
|
||||||
|
|
||||||
|
status.setCarryFlag((destination & 0x10000) == 0x10000);
|
||||||
|
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x8000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
dst.set(dstIndex, destination & 0xFFFF);
|
||||||
|
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
|
|
||||||
|
int count = src % 17;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
int signBit = (destination & 0x8000);
|
||||||
|
|
||||||
|
if (status.isCarryFlag()) {
|
||||||
|
destination |= 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = (destination << count) | (destination >>> (17 - count));
|
||||||
|
|
||||||
|
status.setCarryFlag((destination & 0x10000) == 0x10000);
|
||||||
|
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x8000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
dst.set(dstIndex, destination & 0xFFFF);
|
||||||
|
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* +---------------------+
|
||||||
|
* | |
|
||||||
|
* CF < 0<0<0<0<0<0<0<0 <-+
|
||||||
|
*/
|
||||||
|
public class RcrInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 40;
|
||||||
|
|
||||||
|
public RcrInstruction() {
|
||||||
|
super("rcr", OPCODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
|
int count = src.get(srcIndex) % 17;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex) << 1;
|
||||||
|
int signBit = (destination & 0x10000);
|
||||||
|
|
||||||
|
if (status.isCarryFlag()) {
|
||||||
|
destination |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = (destination >>> count) | (destination << (17 - count));
|
||||||
|
|
||||||
|
status.setCarryFlag((destination & 1) == 1);
|
||||||
|
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x10000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
dst.set(dstIndex, destination >> 1);
|
||||||
|
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
|
|
||||||
|
int count = src % 17;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex) << 1;
|
||||||
|
int signBit = (destination & 0x10000);
|
||||||
|
|
||||||
|
if (status.isCarryFlag()) {
|
||||||
|
destination |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = (destination >>> count) | (destination << (17 - count));
|
||||||
|
|
||||||
|
status.setCarryFlag((destination & 1) == 1);
|
||||||
|
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x10000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
dst.set(dstIndex, destination >> 1);
|
||||||
|
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* +-----------------+
|
||||||
|
* | |
|
||||||
|
* CF < 0<0<0<0<0<0<0<0 <-+
|
||||||
|
*/
|
||||||
|
public class RolInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 35;
|
||||||
|
|
||||||
|
public RolInstruction() {
|
||||||
|
super("rol", OPCODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
|
int count = src.get(srcIndex) % 16;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
int signBit = (destination & 0x8000);
|
||||||
|
|
||||||
|
destination = (destination << count) | (destination >>> (16 - count));
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x8000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
status.setCarryFlag((destination & 1) == 1);
|
||||||
|
dst.set(dstIndex, destination);
|
||||||
|
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
|
|
||||||
|
int count = src % 16;
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
int signBit = (destination & 0x8000);
|
||||||
|
|
||||||
|
destination = (destination << count) | (destination >>> (16 - count));
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x8000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
status.setCarryFlag((destination & 1) == 1);
|
||||||
|
dst.set(dstIndex, destination);
|
||||||
|
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* +-----------------+
|
||||||
|
* | |
|
||||||
|
* +-> 0>0>0>0>0>0>0>0 > CF
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RorInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 32;
|
||||||
|
|
||||||
|
public RorInstruction() {
|
||||||
|
super("ror", OPCODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
|
int count = src.get(srcIndex) % 16;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
int signBit = (destination & 0x8000);
|
||||||
|
|
||||||
|
destination = (destination >>> count) | (destination << (16 - count));
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x8000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
dst.set(dstIndex, destination);
|
||||||
|
status.setCarryFlag((destination & 0x8000) == 0x8000);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
|
|
||||||
|
int count = src % 16;
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
int signBit = (destination & 0x8000);
|
||||||
|
|
||||||
|
destination = (destination >>> count) | (destination << (16 - count));
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag((destination & 0x8000) != signBit); //Set OF if sign bit changed
|
||||||
|
}
|
||||||
|
dst.set(dstIndex, destination);
|
||||||
|
status.setCarryFlag((destination & 0x8000) == 0x8000);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias of SHL instruction
|
||||||
|
*/
|
||||||
|
public class SalInstruction extends Instruction {
|
||||||
|
|
||||||
|
public SalInstruction() {
|
||||||
|
super("sal", ShlInstruction.OPCODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package net.simon987.server.assembly.instruction;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Instruction;
|
||||||
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.assembly.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SarInstruction extends Instruction {
|
||||||
|
|
||||||
|
private static final int OPCODE = 41;
|
||||||
|
|
||||||
|
public SarInstruction() {
|
||||||
|
super("sar", OPCODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
|
int count = src.get(srcIndex) % 16;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag(false); //sign doesn't change
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((destination & 0x8000) == 0x8000) {
|
||||||
|
destination |= 0xFFFF0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = destination >> (count - 1);
|
||||||
|
status.setCarryFlag((destination & 1) == 1);
|
||||||
|
destination = destination >> 1;
|
||||||
|
status.setZeroFlag(destination == 0);
|
||||||
|
|
||||||
|
dst.set(dstIndex, destination);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
|
int count = src % 16;
|
||||||
|
|
||||||
|
int destination = dst.get(dstIndex);
|
||||||
|
|
||||||
|
if (count == 1) {
|
||||||
|
status.setOverflowFlag(false); //sign doesn't change
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((destination & 0x8000) == 0x8000) {
|
||||||
|
destination |= 0xFFFF0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
destination = destination >> (count - 1);
|
||||||
|
status.setCarryFlag((destination & 1) == 1);
|
||||||
|
destination = destination >> 1;
|
||||||
|
status.setZeroFlag(destination == 0);
|
||||||
|
|
||||||
|
dst.set(dstIndex, destination);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,15 +5,13 @@ import net.simon987.server.assembly.Status;
|
|||||||
import net.simon987.server.assembly.Target;
|
import net.simon987.server.assembly.Target;
|
||||||
import net.simon987.server.assembly.Util;
|
import net.simon987.server.assembly.Util;
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Gilbert Fortier on 3/12/2017.
|
|
||||||
*/
|
|
||||||
public class XorInstruction extends Instruction {
|
public class XorInstruction extends Instruction {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opcode of the instruction
|
* Opcode of the instruction
|
||||||
*/
|
*/
|
||||||
public static final int OPCODE = 5;
|
public static final int OPCODE = 38;
|
||||||
|
|
||||||
public XorInstruction() {
|
public XorInstruction() {
|
||||||
super("xor", OPCODE);
|
super("xor", OPCODE);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.simon987.server.game;
|
package net.simon987.server.game;
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Memory;
|
||||||
import net.simon987.server.user.User;
|
import net.simon987.server.user.User;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -14,4 +15,6 @@ public interface ControllableUnit {
|
|||||||
|
|
||||||
ArrayList<Integer> getKeyboardBuffer();
|
ArrayList<Integer> getKeyboardBuffer();
|
||||||
|
|
||||||
|
Memory getFloppyData();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,14 @@ public abstract class GameObject implements JSONSerialisable {
|
|||||||
//Check if out of World bounds / collision
|
//Check if out of World bounds / collision
|
||||||
if(newX < 0) {
|
if(newX < 0) {
|
||||||
//Move object to adjacent World (left)
|
//Move object to adjacent World (left)
|
||||||
World leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() - 1, world.getY());
|
World leftWorld;
|
||||||
|
if (world.getX() == 0) {
|
||||||
|
//Warp around
|
||||||
|
leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(
|
||||||
|
GameServer.INSTANCE.getGameUniverse().getMaxWidth(), world.getY());
|
||||||
|
} else {
|
||||||
|
leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() - 1, world.getY());
|
||||||
|
}
|
||||||
|
|
||||||
if(leftWorld != null){
|
if(leftWorld != null){
|
||||||
world.getGameObjects().remove(this);
|
world.getGameObjects().remove(this);
|
||||||
@@ -82,7 +89,13 @@ public abstract class GameObject implements JSONSerialisable {
|
|||||||
}
|
}
|
||||||
} else if(newX >= World.WORLD_SIZE) {
|
} else if(newX >= World.WORLD_SIZE) {
|
||||||
//Move object to adjacent World (right)
|
//Move object to adjacent World (right)
|
||||||
World rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() + 1, world.getY());
|
World rightWorld;
|
||||||
|
if (world.getX() == GameServer.INSTANCE.getGameUniverse().getMaxWidth()) {
|
||||||
|
//Warp around
|
||||||
|
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(0, world.getY());
|
||||||
|
} else {
|
||||||
|
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() + 1, world.getY());
|
||||||
|
}
|
||||||
|
|
||||||
if(rightWorld != null){
|
if(rightWorld != null){
|
||||||
world.getGameObjects().remove(this);
|
world.getGameObjects().remove(this);
|
||||||
@@ -92,25 +105,39 @@ public abstract class GameObject implements JSONSerialisable {
|
|||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
} else if (newY < 0) {
|
} else if (newY < 0) {
|
||||||
//Move object to adjacent World (down)
|
|
||||||
World downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() - 1);
|
|
||||||
|
|
||||||
if(downWorld != null){
|
|
||||||
world.getGameObjects().remove(this);
|
|
||||||
downWorld.getGameObjects().add(this);
|
|
||||||
setWorld(downWorld);
|
|
||||||
|
|
||||||
y = World.WORLD_SIZE - 1;
|
|
||||||
}
|
|
||||||
} else if(newY >= World.WORLD_SIZE) {
|
|
||||||
//Move object to adjacent World (up)
|
//Move object to adjacent World (up)
|
||||||
World upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() + 1);
|
World upWorld;
|
||||||
|
if (world.getY() == 0) {
|
||||||
|
//Warp around
|
||||||
|
upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(),
|
||||||
|
GameServer.INSTANCE.getGameUniverse().getMaxWidth());
|
||||||
|
} else {
|
||||||
|
upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
if(upWorld != null){
|
if(upWorld != null){
|
||||||
world.getGameObjects().remove(this);
|
world.getGameObjects().remove(this);
|
||||||
upWorld.getGameObjects().add(this);
|
upWorld.getGameObjects().add(this);
|
||||||
setWorld(upWorld);
|
setWorld(upWorld);
|
||||||
|
|
||||||
|
y = World.WORLD_SIZE - 1;
|
||||||
|
}
|
||||||
|
} else if (newY >= World.WORLD_SIZE) {
|
||||||
|
//Move object to adjacent World (down)
|
||||||
|
World downWorld;
|
||||||
|
if (world.getY() == GameServer.INSTANCE.getGameUniverse().getMaxWidth()) {
|
||||||
|
//Warp around
|
||||||
|
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), 0);
|
||||||
|
} else {
|
||||||
|
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (downWorld != null) {
|
||||||
|
world.getGameObjects().remove(this);
|
||||||
|
downWorld.getGameObjects().add(this);
|
||||||
|
setWorld(downWorld);
|
||||||
|
|
||||||
y = 0;
|
y = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ public class GameUniverse implements JSONSerialisable{
|
|||||||
|
|
||||||
private int nextObjectId = 0;
|
private int nextObjectId = 0;
|
||||||
|
|
||||||
|
private int maxWidth = 0xFFFF;
|
||||||
|
|
||||||
public GameUniverse(ServerConfiguration config) {
|
public GameUniverse(ServerConfiguration config) {
|
||||||
|
|
||||||
worlds = new ArrayList<>(32);
|
worlds = new ArrayList<>(32);
|
||||||
@@ -50,15 +52,18 @@ public class GameUniverse implements JSONSerialisable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (x >= 0 && x <= maxWidth && y >= 0 && y <= maxWidth) {
|
||||||
//World does not exist
|
//World does not exist
|
||||||
LogManager.LOGGER.severe("Trying to read a World that does not exist!");
|
LogManager.LOGGER.severe("Trying to read a World that does not exist!");
|
||||||
|
|
||||||
World world = createWorld(x,y);
|
World world = createWorld(x, y);
|
||||||
|
|
||||||
worlds.add(world);
|
worlds.add(world);
|
||||||
|
|
||||||
return world;
|
return world;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public World createWorld(int x, int y) {
|
public World createWorld(int x, int y) {
|
||||||
@@ -108,9 +113,11 @@ public class GameUniverse implements JSONSerialisable{
|
|||||||
user.getCpu().getMemory().clear();
|
user.getCpu().getMemory().clear();
|
||||||
|
|
||||||
//Write assembled code to mem
|
//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);
|
user.getCpu().setCodeSegmentOffset(ar.origin);
|
||||||
|
|
||||||
|
//Init
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
user = new User(null);
|
user = new User(null);
|
||||||
}
|
}
|
||||||
@@ -129,8 +136,17 @@ public class GameUniverse implements JSONSerialisable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an object by id
|
||||||
|
* <br>
|
||||||
|
* ConcurrentModificationException risk when inside game loop
|
||||||
|
*
|
||||||
|
* @param id id of the game object
|
||||||
|
* @return GameObject, null if not found
|
||||||
|
*/
|
||||||
public GameObject getObject(int id) {
|
public GameObject getObject(int id) {
|
||||||
|
|
||||||
|
//
|
||||||
for (World world : worlds) {
|
for (World world : worlds) {
|
||||||
for(GameObject object : world.getGameObjects()){
|
for(GameObject object : world.getGameObjects()){
|
||||||
if(object.getObjectId() == id){
|
if(object.getObjectId() == id){
|
||||||
@@ -161,12 +177,14 @@ public class GameUniverse implements JSONSerialisable{
|
|||||||
|
|
||||||
JSONArray worlds = new JSONArray();
|
JSONArray worlds = new JSONArray();
|
||||||
|
|
||||||
for(World world : this.worlds){
|
ArrayList<World> worlds_ = new ArrayList<>(this.worlds);
|
||||||
|
for (World world : worlds_){
|
||||||
worlds.add(world.serialise());
|
worlds.add(world.serialise());
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONArray users = new JSONArray();
|
JSONArray users = new JSONArray();
|
||||||
for(User user : this.users){
|
ArrayList<User> users_ = new ArrayList<User>(this.users);
|
||||||
|
for (User user : users_){
|
||||||
if (!user.isGuest()) {
|
if (!user.isGuest()) {
|
||||||
users.add(user.serialise());
|
users.add(user.serialise());
|
||||||
}
|
}
|
||||||
@@ -245,4 +263,8 @@ public class GameUniverse implements JSONSerialisable{
|
|||||||
users.remove(user);
|
users.remove(user);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxWidth() {
|
||||||
|
return maxWidth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ public class World implements JSONSerialisable{
|
|||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
JSONArray objects = new JSONArray();
|
JSONArray objects = new JSONArray();
|
||||||
for(GameObject obj : gameObjects){
|
ArrayList<GameObject> gameObjects_ = new ArrayList<>(gameObjects);
|
||||||
|
for (GameObject obj : gameObjects_) {
|
||||||
objects.add(obj.serialise());
|
objects.add(obj.serialise());
|
||||||
}
|
}
|
||||||
json.put("objects", objects);
|
json.put("objects", objects);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package net.simon987.server.logging;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.logging.Formatter;
|
import java.util.logging.Formatter;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,24 +15,13 @@ public class GenericFormatter extends Formatter {
|
|||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
if (record.getLevel() == Level.FINE) {
|
|
||||||
//Chat message, maximum 50 char per line
|
|
||||||
if (record.getMessage().length() > 50) {
|
|
||||||
sb.append(record.getMessage().substring(0, 50));
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append(record.getMessage().substring(50));
|
|
||||||
} else {
|
|
||||||
sb.append(record.getMessage());
|
|
||||||
}
|
|
||||||
sb.append('\n');
|
|
||||||
} else {
|
|
||||||
//Regular record
|
//Regular record
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd HH:mm:ss:SSS"); //ex. 11/25 22:03:59:010
|
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd HH:mm:ss:SSS"); //ex. 11/25 22:03:59:010
|
||||||
|
|
||||||
sb.append(String.format("[%s] [%s] %s", sdf.format(date), record.getLevel(), record.getMessage()));
|
sb.append(String.format("[%s] [%s] %s", sdf.format(date), record.getLevel(), record.getMessage()));
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class CodeUploadHandler implements MessageHandler {
|
|||||||
user.getUser().getCpu().getMemory().clear();
|
user.getUser().getCpu().getMemory().clear();
|
||||||
|
|
||||||
//Write assembled code to mem
|
//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);
|
user.getUser().getCpu().setCodeSegmentOffset(ar.origin);
|
||||||
|
|
||||||
JSONObject response = new JSONObject();
|
JSONObject response = new JSONObject();
|
||||||
|
|||||||
36
Server/src/net/simon987/server/webserver/FloppyHandler.java
Normal file
36
Server/src/net/simon987/server/webserver/FloppyHandler.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package net.simon987.server.webserver;
|
|||||||
|
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.game.GameObject;
|
import net.simon987.server.game.GameObject;
|
||||||
import net.simon987.server.io.JSONSerialisable;
|
import net.simon987.server.game.World;
|
||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
import org.json.simple.JSONArray;
|
import org.json.simple.JSONArray;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
@@ -18,25 +18,28 @@ public class ObjectsRequestHandler implements MessageHandler {
|
|||||||
if (json.get("t").equals("object")) {
|
if (json.get("t").equals("object")) {
|
||||||
LogManager.LOGGER.info("(WS) Objects request from " + user.getUser().getUsername());
|
LogManager.LOGGER.info("(WS) Objects request from " + user.getUser().getUsername());
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
try {
|
||||||
|
x = Long.valueOf((long) json.get("x")).intValue();
|
||||||
|
y = Long.valueOf((long) json.get("y")).intValue();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.LOGGER.info("(WS) Malformed Objects request from " + user.getUser().getUsername());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (json.containsKey("x") && json.containsKey("y")) {
|
World world = GameServer.INSTANCE.getGameUniverse().getWorld(x, y);
|
||||||
int x = Long.valueOf((long) json.get("x")).intValue();
|
|
||||||
int y = Long.valueOf((long) json.get("y")).intValue();
|
|
||||||
|
|
||||||
ArrayList<GameObject> gameObjects = GameServer.INSTANCE.getGameUniverse().getWorld(x, y).getGameObjects();
|
if (world != null) {
|
||||||
|
ArrayList<GameObject> gameObjects = world.getGameObjects();
|
||||||
|
|
||||||
JSONObject response = new JSONObject();
|
JSONObject response = new JSONObject();
|
||||||
JSONArray objects = new JSONArray();
|
JSONArray objects = new JSONArray();
|
||||||
|
|
||||||
|
|
||||||
for (GameObject object : gameObjects) {
|
for (GameObject object : gameObjects) {
|
||||||
|
|
||||||
if (object instanceof JSONSerialisable) {
|
|
||||||
objects.add(object.serialise());
|
objects.add(object.serialise());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
response.put("t", "object");
|
response.put("t", "object");
|
||||||
response.put("objects", objects);
|
response.put("objects", objects);
|
||||||
|
|
||||||
@@ -44,8 +47,6 @@ public class ObjectsRequestHandler implements MessageHandler {
|
|||||||
if (user.getWebSocket().isOpen()) {
|
if (user.getWebSocket().isOpen()) {
|
||||||
user.getWebSocket().send(response.toJSONString());
|
user.getWebSocket().send(response.toJSONString());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
LogManager.LOGGER.info("(WS) Malformed Objects request from " + user.getUser().getUsername());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public class SocketServer extends WebSocketServer {
|
|||||||
messageEventDispatcher.addHandler(new CodeUploadHandler());
|
messageEventDispatcher.addHandler(new CodeUploadHandler());
|
||||||
messageEventDispatcher.addHandler(new CodeRequestHandler());
|
messageEventDispatcher.addHandler(new CodeRequestHandler());
|
||||||
messageEventDispatcher.addHandler(new KeypressHandler());
|
messageEventDispatcher.addHandler(new KeypressHandler());
|
||||||
|
messageEventDispatcher.addHandler(new FloppyHandler());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ import net.simon987.server.ServerConfiguration;
|
|||||||
import net.simon987.server.io.DatabaseManager;
|
import net.simon987.server.io.DatabaseManager;
|
||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.*;
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
class SocketServerDatabase extends DatabaseManager {
|
class SocketServerDatabase extends DatabaseManager {
|
||||||
|
|
||||||
@@ -48,4 +45,39 @@ class SocketServerDatabase extends DatabaseManager {
|
|||||||
return null;
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,19 @@ public class TerrainRequestHandler implements MessageHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(OnlineUser user, JSONObject json) {
|
public void handle(OnlineUser user, JSONObject json) {
|
||||||
if (json.get("t").equals("terrain")) {
|
if (json.get("t").equals("terrain") && json.containsKey("x") && json.containsKey("y")) {
|
||||||
|
|
||||||
LogManager.LOGGER.info("Terrain request from " + user.getUser().getUsername());
|
LogManager.LOGGER.info("Terrain request from " + user.getUser().getUsername());
|
||||||
|
World world;
|
||||||
World world = GameServer.INSTANCE.getGameUniverse().getWorld(
|
try {
|
||||||
|
world = GameServer.INSTANCE.getGameUniverse().getWorld(
|
||||||
Long.valueOf((long) json.get("x")).intValue(),
|
Long.valueOf((long) json.get("x")).intValue(),
|
||||||
Long.valueOf((long) json.get("y")).intValue());
|
Long.valueOf((long) json.get("y")).intValue());
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
LogManager.LOGGER.severe("FIXME: handle TerrainRequestHandler");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//todo It might be a good idea to cache this
|
//todo It might be a good idea to cache this
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
|
|||||||
@@ -14,26 +14,22 @@ public class UserInfoRequestHandler implements MessageHandler {
|
|||||||
if (message.get("t").equals("userInfo")) {
|
if (message.get("t").equals("userInfo")) {
|
||||||
|
|
||||||
LogManager.LOGGER.info("(WS) User info request from " + user.getUser().getUsername());
|
LogManager.LOGGER.info("(WS) User info request from " + user.getUser().getUsername());
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
if(user.isGuest()) {
|
if(user.isGuest()) {
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("t", "userInfo");
|
|
||||||
json.put("worldX", GameServer.INSTANCE.getConfig().getInt("new_user_worldX"));
|
json.put("worldX", GameServer.INSTANCE.getConfig().getInt("new_user_worldX"));
|
||||||
json.put("worldY", GameServer.INSTANCE.getConfig().getInt("new_user_worldY"));
|
json.put("worldY", GameServer.INSTANCE.getConfig().getInt("new_user_worldY"));
|
||||||
|
|
||||||
user.getWebSocket().send(json.toJSONString());
|
|
||||||
} else {
|
} else {
|
||||||
GameObject object = (GameObject)user.getUser().getControlledUnit();
|
GameObject object = (GameObject)user.getUser().getControlledUnit();
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("t", "userInfo");
|
|
||||||
json.put("worldX", object.getWorld().getX());
|
json.put("worldX", object.getWorld().getX());
|
||||||
json.put("worldY", object.getWorld().getY());
|
json.put("worldY", object.getWorld().getY());
|
||||||
|
|
||||||
user.getWebSocket().send(json.toJSONString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json.put("t", "userInfo");
|
||||||
|
json.put("maxWidth", GameServer.INSTANCE.getGameUniverse().getMaxWidth());
|
||||||
|
user.getWebSocket().send(json.toJSONString());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,14 +36,14 @@ public class MemoryTest {
|
|||||||
Memory memory = new Memory(memorySize);
|
Memory memory = new Memory(memorySize);
|
||||||
|
|
||||||
|
|
||||||
assertTrue(memory.write(0, new byte[memorySize], memorySize));
|
assertTrue(memory.write(0, new byte[memorySize], 0, memorySize));
|
||||||
assertFalse(memory.write(0, new byte[memorySize], memorySize + 1));
|
assertFalse(memory.write(0, new byte[memorySize], 0, memorySize + 1));
|
||||||
assertFalse(memory.write(0, new byte[memorySize], -1));
|
assertFalse(memory.write(0, new byte[memorySize], 0, -1));
|
||||||
assertFalse(memory.write(-1, new byte[memorySize], 10));
|
assertFalse(memory.write(-1, new byte[memorySize], 0, 10));
|
||||||
|
|
||||||
assertFalse(memory.write(memorySize / 2, new byte[15], 1));
|
assertFalse(memory.write(memorySize / 2, new byte[15], 0, 1));
|
||||||
assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 11));
|
assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 0, 11));
|
||||||
assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 10));
|
assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 0, 10));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user