mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-12-14 15:19:04 +00:00
Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7d1a00ae8 | ||
|
|
8d961ce572 | ||
|
|
c772abe0bf | ||
|
|
210e579995 | ||
|
|
33955d9639 | ||
|
|
6b91251b4e | ||
|
|
695341428a | ||
|
|
c610929809 | ||
|
|
54b72e89b3 | ||
|
|
59fd620e4a | ||
|
|
2fbc55d0dd | ||
|
|
e1dfb08635 | ||
|
|
7cbfb822b8 | ||
|
|
6fc583d6f0 | ||
|
|
d65660b5e9 | ||
|
|
593be7624e | ||
|
|
a14853b12c | ||
|
|
735a231767 | ||
|
|
1131e4d512 | ||
|
|
cfb02869bb | ||
|
|
cde03af8af | ||
|
|
ff9370fed5 | ||
|
|
eaef30eb49 | ||
|
|
f68027bb4d | ||
|
|
24d81d194e | ||
|
|
c7b9df0690 | ||
|
|
a8beb8c3e2 | ||
|
|
0bd25df977 | ||
|
|
8b0460f5f1 | ||
|
|
ce0584a49f | ||
|
|
0dc4ddca0f | ||
|
|
811a443a4e | ||
|
|
17359161fd | ||
|
|
afbbce215e | ||
|
|
1a39cf8454 | ||
|
|
9bc3cbf4ce | ||
|
|
9b908a5310 | ||
|
|
8ceeca564a | ||
|
|
d4fcf22550 | ||
|
|
d25d42534a | ||
|
|
58a378d77f | ||
|
|
cfaf46ad52 | ||
|
|
ba53212986 | ||
|
|
7bb5f68ff2 | ||
|
|
65ec6a2102 | ||
|
|
5a994fe437 | ||
|
|
415500faa9 | ||
|
|
3ded64cb16 | ||
|
|
1a0291d517 | ||
|
|
4e76d57ef9 | ||
|
|
2a5d6b5a13 | ||
|
|
e2763faeee | ||
|
|
2a8658c598 | ||
|
|
85548ec3cb | ||
|
|
0f7b40f3ae | ||
|
|
ee60216784 | ||
|
|
c3a0d1bd4d | ||
|
|
cd8d883134 | ||
|
|
c7946a6356 | ||
|
|
7ee361b0bc | ||
|
|
1e26c63358 | ||
|
|
d832f65535 | ||
|
|
e47e573b61 | ||
|
|
93786d92cb | ||
|
|
34178016b1 | ||
|
|
b31c187ad5 | ||
|
|
deb3859dff | ||
|
|
b21e33601e | ||
|
|
b2474494cc | ||
|
|
6b2e3c17ed | ||
|
|
079a63e39c | ||
|
|
347dc2bce0 | ||
|
|
90ad8e82eb | ||
|
|
04374e6e0a | ||
|
|
4a6ee4cce6 | ||
|
|
37e40d0329 | ||
|
|
99cefba245 | ||
|
|
7821d428e2 | ||
|
|
93bea49a3e | ||
|
|
cca68ba139 | ||
|
|
83f05efff6 | ||
|
|
ea3b06c54c | ||
|
|
1ed9e9e4db | ||
|
|
08f1aa8686 | ||
|
|
55d4c19fe1 | ||
|
|
2398219fab | ||
|
|
81767ed5cf | ||
|
|
2ef6f492c4 | ||
|
|
70a55dce59 | ||
|
|
fe0be03ab8 | ||
|
|
fd73a47796 | ||
|
|
eea9420192 | ||
|
|
9e402fe8a1 | ||
|
|
b3d88b2813 | ||
|
|
ef7f573256 | ||
|
|
5afa767b4a | ||
|
|
a9e580f2ce | ||
|
|
c4caf4ab0b | ||
|
|
0c06d0bf09 | ||
|
|
017b89f97f | ||
|
|
bd276e0a93 | ||
|
|
72d43fccf7 | ||
|
|
18aaf91991 | ||
|
|
bbcadbf253 | ||
|
|
3d60f9a67c | ||
|
|
b43cf9ac33 | ||
|
|
293795b215 | ||
|
|
fde79ed97e | ||
|
|
fcd339c315 | ||
|
|
59e3e9430e | ||
|
|
45ec7191b4 | ||
|
|
d9732557fc | ||
|
|
eced45a358 | ||
|
|
0fee35baec | ||
|
|
729debb1a3 | ||
|
|
2fb7d2f73e | ||
|
|
dab5cab602 | ||
|
|
c23ee0dc86 | ||
|
|
96cce8478e | ||
|
|
9d184cb515 | ||
|
|
09e00fd032 | ||
|
|
e1d0833c3a | ||
|
|
8a980fec6a | ||
|
|
e96b7982c8 | ||
|
|
21ec4ae704 | ||
|
|
690b7e8d31 | ||
|
|
d28ca387d0 | ||
|
|
f2b6387cc9 | ||
|
|
f3b20b3a2d | ||
|
|
f4fd3866eb | ||
|
|
965ca91cb6 | ||
|
|
556f443ec2 | ||
|
|
3158dd75ea | ||
|
|
1b6927c575 | ||
|
|
3bd34bfcba |
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
plugins/Plugin NPC.jar
|
||||
plugins/Plugin Misc HW.jar
|
||||
plugins/Plant.jar
|
||||
plugins/Cubot.jar
|
||||
.idea/*
|
||||
mar.log
|
||||
mar.log.lck
|
||||
*.iml
|
||||
*.class
|
||||
*/target/*
|
||||
plugins/*.jar
|
||||
save.json
|
||||
Server/Server.iml
|
||||
target/*
|
||||
Server/Server.iml
|
||||
Server/src/main/java/META-INF/MANIFEST.MF
|
||||
19
CONTRIBUTING.md
Normal file
19
CONTRIBUTING.md
Normal file
@@ -0,0 +1,19 @@
|
||||
## General guide
|
||||
|
||||
[Collaboration guide](https://github.com/simon987/Much-Assembly-Required/wiki/Collaboration-Guide)
|
||||
|
||||
## Before creating a pull request
|
||||
|
||||
Here small unordered list of guidelines to read before creating a pull request
|
||||
- Use java <= 1.8 features
|
||||
- Please follow [Google's Java style guide](https://google.github.io/styleguide/javaguide.html)
|
||||
- Constants (e.g. the energy cost of an in-game action) should be loaded from config.properties
|
||||
- The project is separated into multiple modules, the `Server` module and its plugins. Plugins should
|
||||
not depend on another plugin to compile or to run.
|
||||
(e.g. NPC plugin shouldn't import `net.simon987.biomassplugin` )
|
||||
- Use `Logmanager.LOGGER` to log messages to the console. Use `.fine()` for debugging messages and `.info()` for
|
||||
info for more important messages
|
||||
that are not too frequently used.
|
||||
- Do not submit a pull request for a new feature that has not been approved
|
||||
by [simon987](https://github.com/simon987) in an Issue beforehand
|
||||
- Please state what tests have been performed in the pull request
|
||||
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM alpine:3.7
|
||||
RUN apk add --no-cache maven openjdk8
|
||||
COPY /. /app/
|
||||
WORKDIR /app
|
||||
RUN mvn package \
|
||||
&& cp Server/src/main/resources/config.properties /app/
|
||||
CMD ["java", "-jar", "/app/target/server-1.2a.jar"]
|
||||
@@ -15,6 +15,9 @@
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: junit:junit:4.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
|
||||
|
||||
@@ -4,22 +4,16 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.simon987.server</groupId>
|
||||
<artifactId>server_root</artifactId>
|
||||
<version>1.2a</version>
|
||||
</parent>
|
||||
|
||||
<groupId>net.simon987.plugincubot</groupId>
|
||||
<artifactId>plugin-cubot</artifactId>
|
||||
<version>1.2a</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.Memory;
|
||||
import net.simon987.server.game.*;
|
||||
@@ -8,13 +10,18 @@ import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
public class Cubot extends GameObject implements Updatable, ControllableUnit, Programmable {
|
||||
|
||||
private static final char MAP_INFO = 0x0080;
|
||||
public static final int ID = 1;
|
||||
|
||||
private char hologram = 0;
|
||||
private char lastHologram = 0;
|
||||
public static int TYPE_ID = 2;
|
||||
|
||||
private int hologram = 0;
|
||||
private String hologramString = "";
|
||||
private HologramMode hologramMode = HologramMode.CLEARED;
|
||||
private HologramMode lastHologramMode = HologramMode.CLEARED;
|
||||
private int hologramColor = 0;
|
||||
|
||||
/**
|
||||
* Hit points
|
||||
@@ -27,7 +34,10 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
|
||||
private ArrayList<Integer> keyboardBuffer = new ArrayList<>();
|
||||
|
||||
private FloppyDisk floppyDisk;
|
||||
private ArrayList<char[]> consoleMessagesBuffer = new ArrayList<>(CONSOLE_BUFFER_MAX_SIZE);
|
||||
private ArrayList<char[]> lastConsoleMessagesBuffer = new ArrayList<>(CONSOLE_BUFFER_MAX_SIZE);
|
||||
private ConsoleMode consoleMode = ConsoleMode.NORMAL;
|
||||
private ConsoleMode lastConsoleMode = ConsoleMode.NORMAL;
|
||||
|
||||
private User parent;
|
||||
|
||||
@@ -35,6 +45,7 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
private int maxEnergy;
|
||||
|
||||
private static final float SOLAR_PANEL_MULTIPLIER = 1;
|
||||
private static final int CONSOLE_BUFFER_MAX_SIZE = 40;
|
||||
|
||||
public Cubot() {
|
||||
|
||||
@@ -70,8 +81,15 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
currentAction = Action.IDLE;
|
||||
|
||||
//Same principle for hologram
|
||||
lastHologram = hologram;
|
||||
hologram = 0;
|
||||
lastHologramMode = hologramMode;
|
||||
hologramMode = HologramMode.CLEARED;
|
||||
|
||||
//And the console
|
||||
lastConsoleMode = consoleMode;
|
||||
consoleMode = ConsoleMode.NORMAL;
|
||||
|
||||
lastConsoleMessagesBuffer = new ArrayList<>(consoleMessagesBuffer);
|
||||
consoleMessagesBuffer.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,7 +103,10 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
json.put("heldItem", heldItem);
|
||||
json.put("hp", hp);
|
||||
json.put("action", lastAction.ordinal());
|
||||
json.put("holo", (int) lastHologram);
|
||||
json.put("holo", hologram);
|
||||
json.put("holoStr", hologramString);
|
||||
json.put("holoMode", lastHologramMode.ordinal());
|
||||
json.put("holoC", hologramColor);
|
||||
json.put("energy", energy);
|
||||
|
||||
if (parent != null) {
|
||||
@@ -95,16 +116,41 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static Cubot deserialize(JSONObject json) {
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("i", getObjectId());
|
||||
dbObject.put("t", ID);
|
||||
dbObject.put("x", getX());
|
||||
dbObject.put("y", getY());
|
||||
dbObject.put("direction", getDirection().ordinal());
|
||||
dbObject.put("heldItem", heldItem);
|
||||
dbObject.put("hp", hp);
|
||||
dbObject.put("action", lastAction.ordinal());
|
||||
dbObject.put("holo", hologram);
|
||||
dbObject.put("holoStr", hologramString);
|
||||
dbObject.put("holoMode", lastHologramMode.ordinal());
|
||||
dbObject.put("holoC", hologramColor);
|
||||
dbObject.put("energy", energy);
|
||||
|
||||
if (parent != null) {
|
||||
dbObject.put("parent", parent.getUsername()); //Only used client-side for now
|
||||
}
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static Cubot deserialize(DBObject obj) {
|
||||
|
||||
Cubot cubot = new Cubot();
|
||||
cubot.setObjectId((long) json.get("i"));
|
||||
cubot.setX((int) (long) json.get("x"));
|
||||
cubot.setY((int) (long) json.get("y"));
|
||||
cubot.hp = (int) (long) json.get("hp");
|
||||
cubot.setDirection(Direction.getDirection((int) (long) json.get("direction")));
|
||||
cubot.heldItem = (int) (long) json.get("heldItem");
|
||||
cubot.energy = (int) (long) json.get("energy");
|
||||
cubot.setObjectId((long) obj.get("i"));
|
||||
cubot.setX((int) obj.get("x"));
|
||||
cubot.setY((int) obj.get("y"));
|
||||
cubot.hp = (int) obj.get("hp");
|
||||
cubot.setDirection(Direction.getDirection((int) obj.get("direction")));
|
||||
cubot.heldItem = (int) obj.get("heldItem");
|
||||
cubot.energy = (int) obj.get("energy");
|
||||
cubot.maxEnergy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy");
|
||||
|
||||
return cubot;
|
||||
@@ -149,14 +195,18 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
return lastAction;
|
||||
}
|
||||
|
||||
public void setHologram(char hologram) {
|
||||
public Action getCurrentAction() {
|
||||
return currentAction;
|
||||
}
|
||||
|
||||
public void setHologram(int hologram) {
|
||||
this.hologram = hologram;
|
||||
}
|
||||
|
||||
public char getHologram() {
|
||||
return lastHologram;
|
||||
}
|
||||
|
||||
public void setHologramString(String hologramString) {
|
||||
this.hologramString = hologramString;
|
||||
}
|
||||
|
||||
public int getEnergy() {
|
||||
return energy;
|
||||
@@ -201,4 +251,58 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAt(int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setHologramMode(HologramMode hologramMode) {
|
||||
this.hologramMode = hologramMode;
|
||||
}
|
||||
|
||||
public enum HologramMode {
|
||||
CLEARED,
|
||||
HEX,
|
||||
STRING,
|
||||
DEC
|
||||
}
|
||||
|
||||
public enum ConsoleMode {
|
||||
CLEAR,
|
||||
NORMAL
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAction(Action action) {
|
||||
currentAction = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendMessage(char[] message) {
|
||||
|
||||
if (consoleMessagesBuffer.size() < CONSOLE_BUFFER_MAX_SIZE) {
|
||||
consoleMessagesBuffer.add(message);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<char[]> getConsoleMessagesBuffer() {
|
||||
return lastConsoleMessagesBuffer;
|
||||
}
|
||||
|
||||
|
||||
public int getConsoleMode() {
|
||||
return lastConsoleMode.ordinal();
|
||||
}
|
||||
|
||||
public void setConsoleMode(ConsoleMode consoleMode) {
|
||||
this.consoleMode = consoleMode;
|
||||
}
|
||||
|
||||
public void setHologramColor(int hologramColor) {
|
||||
this.hologramColor = hologramColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class CubotBattery extends CpuHardware {
|
||||
|
||||
@@ -15,8 +16,8 @@ public class CubotBattery extends CpuHardware {
|
||||
public static final char HWID = 0x000A;
|
||||
|
||||
private Cubot cubot;
|
||||
private static final int POLL = 1;
|
||||
private static final int GET_MAX_CAPACITY = 2;
|
||||
private static final int BATTERY_POLL = 1;
|
||||
private static final int BATTERY_GET_MAX_CAPACITY = 2;
|
||||
|
||||
public CubotBattery(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
@@ -27,10 +28,10 @@ public class CubotBattery extends CpuHardware {
|
||||
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == POLL) {
|
||||
if (a == BATTERY_POLL) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getEnergy());
|
||||
|
||||
} else if (a == GET_MAX_CAPACITY) {
|
||||
} else if (a == BATTERY_GET_MAX_CAPACITY) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getMaxEnergy());
|
||||
} else if (a == 0xFFFF) {
|
||||
cubot.setEnergy(cubot.getMaxEnergy());
|
||||
@@ -44,16 +45,19 @@ public class CubotBattery extends CpuHardware {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
json.put("cubot", cubot.getObjectId());
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
return json;
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotBattery deserialize(JSONObject hwJSON) {
|
||||
return new CubotBattery((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
|
||||
public static CubotBattery deserialize(DBObject obj) {
|
||||
return new CubotBattery((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.Programmable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CubotComPort extends CpuHardware {
|
||||
|
||||
public static final char HWID = 0xD;
|
||||
public static final int DEFAULT_ADDRESS = 0xD;
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
private static final int COMPORT_BUFFER_CLEAR = 0;
|
||||
private static final int COMPORT_POLL = 1;
|
||||
private static final int COMPORT_FRONT_PORT_OUT = 2;
|
||||
private static final int COMPORT_SELF_OUT = 3;
|
||||
private static final int COMPORT_CONSOLE_CLEAR = 4;
|
||||
|
||||
public CubotComPort(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
|
||||
private static final int MESSAGE_LENGTH = 8;
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == COMPORT_BUFFER_CLEAR) {
|
||||
|
||||
cubot.getConsoleMessagesBuffer().clear();
|
||||
|
||||
} else if (a == COMPORT_CONSOLE_CLEAR) {
|
||||
|
||||
cubot.setConsoleMode(Cubot.ConsoleMode.CLEAR);
|
||||
|
||||
} else if (a == COMPORT_POLL) {
|
||||
|
||||
if (cubot.spendEnergy(4)) {
|
||||
|
||||
int x = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
|
||||
//Read all messages in the console buffer to memory at X
|
||||
|
||||
for (char[] message : cubot.getConsoleMessagesBuffer()) {
|
||||
if (x + MESSAGE_LENGTH >= getCpu().getMemory().getWords().length) {
|
||||
//todo set interrupt ?
|
||||
getCpu().getStatus().setErrorFlag(true);
|
||||
} else {
|
||||
System.arraycopy(message, 0, getCpu().getMemory().getWords(), x, MESSAGE_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
//Set B = number of messages
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getConsoleMessagesBuffer().size());
|
||||
|
||||
}
|
||||
|
||||
} else if (a == COMPORT_FRONT_PORT_OUT) {
|
||||
|
||||
if (cubot.spendEnergy(20)) {
|
||||
//Get object directly in front of the Cubot
|
||||
Point frontTile = cubot.getFrontTile();
|
||||
//Todo will have to add getGameObjectsBlockingAt to enable Factory
|
||||
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y);
|
||||
|
||||
if (objects.size() > 0 && objects.get(0) instanceof Programmable) {
|
||||
|
||||
int x = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
|
||||
if (x + MESSAGE_LENGTH >= getCpu().getMemory().getWords().length) {
|
||||
//todo set interrupt ?
|
||||
getCpu().getStatus().setErrorFlag(true);
|
||||
} else {
|
||||
|
||||
//Get MESSAGE_LENGTH-word message pointed by X
|
||||
char[] message = new char[MESSAGE_LENGTH];
|
||||
System.arraycopy(getCpu().getMemory().getWords(), x, message, 0, MESSAGE_LENGTH);
|
||||
|
||||
//Send it to the Programmable object
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(
|
||||
((Programmable) objects.get(0)).sendMessage(message) ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(0); //Failed
|
||||
|
||||
} else if (a == COMPORT_SELF_OUT) {
|
||||
|
||||
if (cubot.spendEnergy(1)) {
|
||||
|
||||
int x = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
|
||||
//Write a single message to console buffer
|
||||
if (x + MESSAGE_LENGTH >= getCpu().getMemory().getWords().length) {
|
||||
//todo set interrupt ?
|
||||
getCpu().getStatus().setErrorFlag(true);
|
||||
} else {
|
||||
|
||||
//Get MESSAGE_LENGTH-word message pointed by X
|
||||
char[] message = new char[MESSAGE_LENGTH];
|
||||
System.arraycopy(getCpu().getMemory().getWords(), x, message, 0, MESSAGE_LENGTH);
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.sendMessage(message) ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(0); //Failed
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotComPort deserialize(DBObject obj) {
|
||||
return new CubotComPort((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.game.Action;
|
||||
import net.simon987.server.game.TileMap;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class CubotDrill extends CpuHardware {
|
||||
|
||||
@@ -16,9 +17,8 @@ public class CubotDrill extends CpuHardware {
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 5;
|
||||
|
||||
private static final int POLL = 1;
|
||||
private static final int GATHER_SLOW = 2;
|
||||
private static final int GATHER_FAST = 3;
|
||||
private static final int DRILL_POLL = 1;
|
||||
private static final int DRILL_GATHER = 2; // simplified gather
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
@@ -35,14 +35,14 @@ public class CubotDrill extends CpuHardware {
|
||||
public void handleInterrupt(Status status) {
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == POLL) {
|
||||
if (a == DRILL_POLL) {
|
||||
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||
|
||||
} else if (a == GATHER_SLOW || a == GATHER_FAST) {
|
||||
} else if (a == DRILL_GATHER) {
|
||||
|
||||
if (cubot.spendEnergy(1400)) {
|
||||
if (cubot.getAction() == Action.IDLE) {
|
||||
if (cubot.getCurrentAction() == Action.IDLE) {
|
||||
int tile = cubot.getWorld().getTileMap().getTileAt(cubot.getX(), cubot.getY());
|
||||
|
||||
if (tile == TileMap.IRON_TILE) {
|
||||
@@ -62,15 +62,17 @@ public class CubotDrill extends CpuHardware {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
json.put("cubot", cubot.getObjectId());
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
return json;
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotDrill deserialize(JSONObject hwJSON) {
|
||||
return new CubotDrill((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
public static CubotDrill deserialize(DBObject obj) {
|
||||
return new CubotDrill((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
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 {
|
||||
|
||||
@@ -14,9 +15,9 @@ public class CubotFloppyDrive extends CpuHardware {
|
||||
|
||||
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 static final int FLOPPY_POLL = 1;
|
||||
private static final int FLOPPY_READ_SECTOR = 2;
|
||||
private static final int FLOPPY_WRITE_SECTOR = 3;
|
||||
|
||||
private Cubot cubot;
|
||||
private FloppyDisk floppyDisk;
|
||||
@@ -31,7 +32,7 @@ public class CubotFloppyDrive extends CpuHardware {
|
||||
public void handleInterrupt(Status status) {
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == POLL) {
|
||||
if (a == FLOPPY_POLL) {
|
||||
|
||||
if (floppyDisk != null) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||
@@ -39,7 +40,7 @@ public class CubotFloppyDrive extends CpuHardware {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(1);
|
||||
}
|
||||
|
||||
} else if (a == READ_SECTOR) {
|
||||
} else if (a == FLOPPY_READ_SECTOR) {
|
||||
|
||||
if (floppyDisk == null) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||
@@ -55,7 +56,7 @@ public class CubotFloppyDrive extends CpuHardware {
|
||||
}
|
||||
|
||||
|
||||
} else if (a == WRITE_SECTOR) {
|
||||
} else if (a == FLOPPY_WRITE_SECTOR) {
|
||||
if (floppyDisk == null) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||
} else {
|
||||
@@ -78,24 +79,26 @@ public class CubotFloppyDrive extends CpuHardware {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
json.put("cubot", cubot.getObjectId());
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
if (floppyDisk != null) {
|
||||
json.put("floppy", floppyDisk.serialise());
|
||||
dbObject.put("floppy", floppyDisk.mongoSerialise());
|
||||
}
|
||||
|
||||
return json;
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotFloppyDrive deserialize(JSONObject hwJSON) {
|
||||
public static CubotFloppyDrive deserialize(DBObject obj) {
|
||||
|
||||
CubotFloppyDrive drive = new CubotFloppyDrive((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
CubotFloppyDrive drive = new CubotFloppyDrive((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
|
||||
if (hwJSON.containsKey("floppy")) {
|
||||
drive.floppyDisk = FloppyDisk.deserialise((JSONObject) hwJSON.get("floppy"));
|
||||
if (obj.containsField("floppy")) {
|
||||
drive.floppyDisk = FloppyDisk.deserialise((DBObject) obj.get("floppy"));
|
||||
}
|
||||
|
||||
return drive;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class CubotHologram extends CpuHardware {
|
||||
|
||||
@@ -17,6 +18,14 @@ public class CubotHologram extends CpuHardware {
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
private static final int HOLO_CLEAR = 0;
|
||||
private static final int HOLO_DISPLAY_HEX = 1;
|
||||
private static final int HOLO_DISPLAY_STRING = 2;
|
||||
private static final int HOLO_DISPLAY_DEC = 3;
|
||||
private static final int HOLO_DISPLAY_COLOR = 4;
|
||||
|
||||
private static final int STR_MAX_LEN = 8;
|
||||
|
||||
public CubotHologram(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
@@ -25,7 +34,47 @@ public class CubotHologram extends CpuHardware {
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
char a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
cubot.setHologram(a);
|
||||
|
||||
if (a == HOLO_CLEAR) {
|
||||
cubot.setHologramMode(Cubot.HologramMode.CLEARED);
|
||||
} else if (a == HOLO_DISPLAY_HEX) {
|
||||
char b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||
cubot.setHologram(b);
|
||||
cubot.setHologramMode(Cubot.HologramMode.HEX);
|
||||
} else if (a == HOLO_DISPLAY_STRING) {
|
||||
char x = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
//Display zero-terminated string starting at X (max 8 chars)
|
||||
|
||||
StringBuilder holoString = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < STR_MAX_LEN; i++) {
|
||||
|
||||
char nextChar = (char) getCpu().getMemory().get(x + i);
|
||||
|
||||
if (nextChar != 0) {
|
||||
holoString.append((char) getCpu().getMemory().get(x + i));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cubot.setHologramString(holoString.toString());
|
||||
cubot.setHologramMode(Cubot.HologramMode.STRING);
|
||||
} else if (a == HOLO_DISPLAY_DEC) {
|
||||
//Display decimal number
|
||||
char b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||
cubot.setHologram(b);
|
||||
cubot.setHologramMode(Cubot.HologramMode.DEC);
|
||||
|
||||
} else if (a == HOLO_DISPLAY_COLOR) {
|
||||
|
||||
if (cubot.spendEnergy(4)) {
|
||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||
int c = getCpu().getRegisterSet().getRegister("C").getValue();
|
||||
|
||||
cubot.setHologramColor((c | (b << 16))); //B:C
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,16 +83,19 @@ public class CubotHologram extends CpuHardware {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
public static CubotHologram deserialize(JSONObject hwJSON) {
|
||||
return new CubotHologram((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
public static CubotHologram deserialize(DBObject obj) {
|
||||
return new CubotHologram((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
json.put("cubot", cubot.getObjectId());
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
return json;
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class CubotInventory extends CpuHardware {
|
||||
|
||||
@@ -16,8 +17,8 @@ public class CubotInventory extends CpuHardware {
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
private static final int POLL = 1;
|
||||
private static final int CLEAR = 2;
|
||||
private static final int INV_CLEAR = 0;
|
||||
private static final int INV_POLL = 1;
|
||||
|
||||
public CubotInventory(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
@@ -33,29 +34,35 @@ public class CubotInventory extends CpuHardware {
|
||||
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == POLL) {
|
||||
|
||||
if (a == INV_POLL) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getHeldItem());
|
||||
|
||||
} else if (a == CLEAR) {
|
||||
if (cubot.spendEnergy(100)) {
|
||||
} else if (a == INV_CLEAR) {
|
||||
if (cubot.getHeldItem() == 0x0001) {
|
||||
int energy = GameServer.INSTANCE.getConfig().getInt("biomassEnergyValue");
|
||||
cubot.storeEnergy(energy);
|
||||
cubot.setHeldItem(0);
|
||||
|
||||
} else if (cubot.spendEnergy(100)) {
|
||||
cubot.setHeldItem(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
json.put("cubot", cubot.getObjectId());
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
return json;
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotInventory deserialize(JSONObject hwJSON) {
|
||||
return new CubotInventory((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
public static CubotInventory deserialize(DBObject obj) {
|
||||
return new CubotInventory((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class Keyboard extends CpuHardware {
|
||||
public class CubotKeyboard extends CpuHardware {
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 4;
|
||||
|
||||
private static final int CLEAR_BUFFER = 0;
|
||||
private static final int FETCH_KEY = 1;
|
||||
private static final int KEYBOARD_CLEAR_BUFFER = 0;
|
||||
private static final int KEYBOARD_FETCH_KEY = 1;
|
||||
|
||||
/**
|
||||
* Hardware ID (Should be unique)
|
||||
@@ -19,7 +20,7 @@ public class Keyboard extends CpuHardware {
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
public Keyboard(Cubot cubot) {
|
||||
public CubotKeyboard(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
|
||||
@@ -33,11 +34,11 @@ public class Keyboard extends CpuHardware {
|
||||
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == CLEAR_BUFFER) {
|
||||
if (a == KEYBOARD_CLEAR_BUFFER) {
|
||||
|
||||
cubot.clearKeyboardBuffer();
|
||||
|
||||
} else if (a == FETCH_KEY) {
|
||||
} else if (a == KEYBOARD_FETCH_KEY) {
|
||||
//pop
|
||||
int key = 0;
|
||||
if (cubot.getKeyboardBuffer().size() > 0) {
|
||||
@@ -52,16 +53,17 @@ public class Keyboard extends CpuHardware {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
json.put("cubot", cubot.getObjectId());
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
return json;
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static Keyboard deserialize(JSONObject hwJSON) {
|
||||
return new Keyboard((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
public static CubotKeyboard deserialize(DBObject obj) {
|
||||
return new CubotKeyboard((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.game.Action;
|
||||
import net.simon987.server.game.Attackable;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.InventoryHolder;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
@@ -22,9 +24,11 @@ public class CubotLaser extends CpuHardware {
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
private static final int WITHDRAW = 1;
|
||||
private static final int DEPOSIT = 2;
|
||||
private static final int LASER_WITHDRAW = 1;
|
||||
private static final int LASER_DEPOSIT = 2;
|
||||
private static final int LASER_ATTACK = 3;
|
||||
|
||||
private static final int LASER_DAMAGE = 25;
|
||||
|
||||
public CubotLaser(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
@@ -42,14 +46,13 @@ public class CubotLaser extends CpuHardware {
|
||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||
|
||||
|
||||
if (a == WITHDRAW) {
|
||||
if (a == LASER_WITHDRAW) {
|
||||
|
||||
|
||||
Point frontTile = cubot.getFrontTile();
|
||||
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y);
|
||||
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsBlockingAt(frontTile.x, frontTile.y);
|
||||
|
||||
|
||||
if (cubot.getAction() != Action.IDLE && objects.size() > 0) {
|
||||
if (cubot.getCurrentAction() == Action.IDLE && objects.size() > 0) {
|
||||
//FIXME: Problem here if more than 1 object
|
||||
if (objects.get(0) instanceof InventoryHolder) {
|
||||
if (((InventoryHolder) objects.get(0)).canTakeItem(b)) {
|
||||
@@ -65,23 +68,38 @@ public class CubotLaser extends CpuHardware {
|
||||
}
|
||||
|
||||
|
||||
} else if (a == DEPOSIT) {
|
||||
} else if (a == LASER_DEPOSIT) {
|
||||
// TODO
|
||||
} else if (a == LASER_ATTACK) {
|
||||
|
||||
if (cubot.spendEnergy(70)) {
|
||||
|
||||
//Get object directly in front of the Cubot
|
||||
Point frontTile = cubot.getFrontTile();
|
||||
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y);
|
||||
|
||||
if (objects.size() > 0 && objects.get(0) instanceof Attackable) {
|
||||
((Attackable) objects.get(0)).damage(LASER_DAMAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
json.put("cubot", cubot.getObjectId());
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
return json;
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotLaser deserialize(JSONObject hwJSON) {
|
||||
return new CubotLaser((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
public static CubotLaser deserialize(DBObject obj) {
|
||||
return new CubotLaser((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
@@ -14,8 +16,8 @@ public class CubotLeg extends CpuHardware implements JSONSerialisable {
|
||||
|
||||
public static final String NAME = "Cubot Leg";
|
||||
|
||||
private static final int SET_DIR = 1;
|
||||
private static final int SET_DIR_AND_WALK = 2;
|
||||
private static final int LEGS_SET_DIR = 1;
|
||||
private static final int LEGS_SET_DIR_AND_WALK = 2;
|
||||
|
||||
/**
|
||||
* Hardware ID (Should be unique)
|
||||
@@ -35,36 +37,41 @@ public class CubotLeg extends CpuHardware implements JSONSerialisable {
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||
|
||||
if (a == SET_DIR) {
|
||||
if (cubot.getCurrentAction() == Action.IDLE) {
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||
|
||||
if (a == LEGS_SET_DIR) {
|
||||
|
||||
|
||||
Direction dir = Direction.getDirection(b);
|
||||
Direction dir = Direction.getDirection(b);
|
||||
|
||||
if (dir != null) {
|
||||
if (cubot.spendEnergy(20)) {
|
||||
cubot.setDirection(Direction.getDirection(b));
|
||||
status.setErrorFlag(false);
|
||||
if (dir != null) {
|
||||
if (cubot.spendEnergy(20)) {
|
||||
cubot.setDirection(Direction.getDirection(b));
|
||||
status.setErrorFlag(false);
|
||||
}
|
||||
} else {
|
||||
status.setErrorFlag(true);
|
||||
}
|
||||
|
||||
|
||||
} else if (a == LEGS_SET_DIR_AND_WALK) {
|
||||
|
||||
if (cubot.getMaxEnergy() >= 100) {
|
||||
Direction dir = Direction.getDirection(b);
|
||||
|
||||
if (dir != null) {
|
||||
cubot.setDirection(Direction.getDirection(b));
|
||||
status.setErrorFlag(false);
|
||||
} else {
|
||||
status.setErrorFlag(true);
|
||||
}
|
||||
|
||||
cubot.setCurrentAction(Action.WALKING);
|
||||
}
|
||||
} else {
|
||||
status.setErrorFlag(true);
|
||||
}
|
||||
|
||||
|
||||
} else if (a == SET_DIR_AND_WALK) {
|
||||
|
||||
Direction dir = Direction.getDirection(b);
|
||||
|
||||
if (dir != null) {
|
||||
cubot.setDirection(Direction.getDirection(b));
|
||||
status.setErrorFlag(false);
|
||||
} else {
|
||||
status.setErrorFlag(true);
|
||||
}
|
||||
|
||||
cubot.setCurrentAction(Action.WALKING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +85,19 @@ public class CubotLeg extends CpuHardware implements JSONSerialisable {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static CubotLeg deserialize(JSONObject hwJSON) {
|
||||
return new CubotLeg((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotLeg deserialize(DBObject obj) {
|
||||
return new CubotLeg((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Memory;
|
||||
@@ -24,10 +26,10 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
private static final int GET_POS = 1;
|
||||
private static final int GET_PATH = 2;
|
||||
private static final int GET_MAP = 3;
|
||||
private static final int GET_WORLD_POS = 4;
|
||||
private static final int LIDAR_GET_POS = 1;
|
||||
private static final int LIDAR_GET_PATH = 2;
|
||||
private static final int LIDAR_GET_MAP = 3;
|
||||
private static final int LIDAR_GET_WORLD_POS = 4;
|
||||
|
||||
private static final int MEMORY_MAP_START = 0x0100;
|
||||
private static final int MEMORY_PATH_START = 0x0000;
|
||||
@@ -48,11 +50,11 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
switch (a) {
|
||||
case GET_POS:
|
||||
case LIDAR_GET_POS:
|
||||
getCpu().getRegisterSet().getRegister("X").setValue(cubot.getX());
|
||||
getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getY());
|
||||
break;
|
||||
case GET_PATH:
|
||||
case LIDAR_GET_PATH:
|
||||
if (cubot.spendEnergy(50)) {
|
||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||
int destX = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
@@ -108,7 +110,7 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
||||
|
||||
break;
|
||||
|
||||
case GET_MAP:
|
||||
case LIDAR_GET_MAP:
|
||||
if (cubot.spendEnergy(10)) {
|
||||
char[][] mapInfo = cubot.getWorld().getMapInfo();
|
||||
|
||||
@@ -121,7 +123,7 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
||||
}
|
||||
|
||||
break;
|
||||
case GET_WORLD_POS:
|
||||
case LIDAR_GET_WORLD_POS:
|
||||
getCpu().getRegisterSet().getRegister("X").setValue(cubot.getWorld().getX());
|
||||
getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getWorld().getY());
|
||||
break;
|
||||
@@ -141,7 +143,18 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static CubotLidar deserialize(JSONObject hwJSON) {
|
||||
return new CubotLidar((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotLidar deserialize(DBObject obj) {
|
||||
return new CubotLidar((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.cubotplugin.event.CpuInitialisationListener;
|
||||
import net.simon987.cubotplugin.event.UserCreationListener;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
@@ -9,7 +10,6 @@ import net.simon987.server.io.CpuHardwareDeserializer;
|
||||
import net.simon987.server.io.GameObjectDeserializer;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer, CpuHardwareDeserializer {
|
||||
|
||||
@@ -23,9 +23,9 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameObject deserializeObject(JSONObject object) {
|
||||
public GameObject deserializeObject(DBObject object) {
|
||||
|
||||
int objType = (int) (long) object.get("t");
|
||||
int objType = (int) object.get("t");
|
||||
|
||||
if (objType == Cubot.ID) {
|
||||
|
||||
@@ -36,28 +36,30 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
|
||||
}
|
||||
|
||||
@Override
|
||||
public CpuHardware deserializeHardware(JSONObject hwJson) {
|
||||
int hwid = (int) (long) hwJson.get("hwid");
|
||||
public CpuHardware deserializeHardware(DBObject obj) {
|
||||
int hwid = (int) obj.get("hwid");
|
||||
|
||||
switch (hwid) {
|
||||
case CubotLeg.HWID:
|
||||
return CubotLeg.deserialize(hwJson);
|
||||
return CubotLeg.deserialize(obj);
|
||||
case CubotLaser.HWID:
|
||||
return CubotLaser.deserialize(hwJson);
|
||||
return CubotLaser.deserialize(obj);
|
||||
case CubotLidar.HWID:
|
||||
return CubotLidar.deserialize(hwJson);
|
||||
return CubotLidar.deserialize(obj);
|
||||
case CubotDrill.HWID:
|
||||
return CubotDrill.deserialize(hwJson);
|
||||
return CubotDrill.deserialize(obj);
|
||||
case CubotInventory.HWID:
|
||||
return CubotInventory.deserialize(hwJson);
|
||||
case Keyboard.HWID:
|
||||
return Keyboard.deserialize(hwJson);
|
||||
return CubotInventory.deserialize(obj);
|
||||
case CubotKeyboard.HWID:
|
||||
return CubotKeyboard.deserialize(obj);
|
||||
case CubotHologram.HWID:
|
||||
return CubotHologram.deserialize(hwJson);
|
||||
return CubotHologram.deserialize(obj);
|
||||
case CubotBattery.HWID:
|
||||
return CubotBattery.deserialize(hwJson);
|
||||
return CubotBattery.deserialize(obj);
|
||||
case CubotFloppyDrive.HWID:
|
||||
return CubotFloppyDrive.deserialize(hwJson);
|
||||
return CubotFloppyDrive.deserialize(obj);
|
||||
case CubotComPort.HWID:
|
||||
return CubotComPort.deserialize(obj);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.assembly.Memory;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public class FloppyDisk implements MongoSerialisable {
|
||||
|
||||
/**
|
||||
* Contents of the disk
|
||||
@@ -82,23 +83,22 @@ public class FloppyDisk implements JSONSerialisable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("rwHeadTrack", rwHeadTrack);
|
||||
json.put("memory", memory.serialise());
|
||||
dbObject.put("rwHeadTrack", rwHeadTrack);
|
||||
dbObject.put("memory", memory.mongoSerialise());
|
||||
|
||||
return json;
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static FloppyDisk deserialise(JSONObject json) {
|
||||
public static FloppyDisk deserialise(DBObject obj) {
|
||||
|
||||
FloppyDisk floppyDisk = new FloppyDisk();
|
||||
|
||||
floppyDisk.rwHeadTrack = (int) (long) json.get("rwHeadTrack");
|
||||
floppyDisk.memory = Memory.deserialize((JSONObject) json.get("memory"));
|
||||
floppyDisk.rwHeadTrack = (int) obj.get("rwHeadTrack");
|
||||
floppyDisk.memory = Memory.deserialize((DBObject) obj.get("memory"));
|
||||
|
||||
return floppyDisk;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.event.CpuInitialisationEvent;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
public class CpuInitialisationListener implements GameEventListener {
|
||||
@@ -16,7 +15,7 @@ public class CpuInitialisationListener implements GameEventListener {
|
||||
|
||||
@Override
|
||||
public void handle(GameEvent event) {
|
||||
LogManager.LOGGER.fine("(Plugin) Handled CPU Initialisation event (Cubot Plugin)");
|
||||
//LogManager.LOGGER.fine("(Plugin) Handled CPU Initialisation event (Cubot Plugin)");
|
||||
|
||||
CPU cpu = (CPU) event.getSource();
|
||||
User user = ((CpuInitialisationEvent) event).getUser();
|
||||
@@ -27,7 +26,7 @@ public class CpuInitialisationListener implements GameEventListener {
|
||||
laserHw.setCpu(cpu);
|
||||
CubotLidar radarHw = new CubotLidar((Cubot) user.getControlledUnit());
|
||||
radarHw.setCpu(cpu);
|
||||
Keyboard keyboard = new Keyboard((Cubot) user.getControlledUnit());
|
||||
CubotKeyboard keyboard = new CubotKeyboard((Cubot) user.getControlledUnit());
|
||||
keyboard.setCpu(cpu);
|
||||
CubotDrill drillHw = new CubotDrill((Cubot) user.getControlledUnit());
|
||||
drillHw.setCpu(cpu);
|
||||
@@ -39,16 +38,19 @@ public class CpuInitialisationListener implements GameEventListener {
|
||||
batteryHw.setCpu(cpu);
|
||||
CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit());
|
||||
floppyHw.setCpu(cpu);
|
||||
CubotComPort comPortHw = new CubotComPort((Cubot) user.getControlledUnit());
|
||||
comPortHw.setCpu(cpu);
|
||||
|
||||
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(radarHw, CubotLidar.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(keyboard, Keyboard.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(keyboard, CubotKeyboard.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(drillHw, CubotDrill.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(comPortHw, CubotComPort.DEFAULT_ADDRESS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Random;
|
||||
|
||||
public class UserCreationListener implements GameEventListener {
|
||||
@Override
|
||||
@@ -19,33 +20,35 @@ public class UserCreationListener implements GameEventListener {
|
||||
@Override
|
||||
public void handle(GameEvent event) {
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
User user = (User) event.getSource();
|
||||
|
||||
LogManager.LOGGER.fine("(Plugin) Handled User creation event (Cubot Plugin)");
|
||||
|
||||
Cubot cubot = new Cubot();
|
||||
|
||||
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.getWorld().incUpdatable();
|
||||
|
||||
cubot.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||
|
||||
cubot.setHeldItem(GameServer.INSTANCE.getConfig().getInt("new_user_item"));
|
||||
Point point = null;
|
||||
while (point == null || cubot.getWorld() == null) {
|
||||
int spawnX = GameServer.INSTANCE.getConfig().getInt("new_user_worldX") + random.nextInt(5);
|
||||
int spawnY = GameServer.INSTANCE.getConfig().getInt("new_user_worldY") + random.nextInt(5);
|
||||
cubot.setWorld(GameServer.INSTANCE.getGameUniverse().getWorld(spawnX, spawnY, true));
|
||||
|
||||
point = cubot.getWorld().getRandomPassableTile();
|
||||
}
|
||||
|
||||
cubot.setX(point.x);
|
||||
cubot.setY(point.y);
|
||||
cubot.getWorld().addObject(cubot);
|
||||
cubot.getWorld().incUpdatable();
|
||||
|
||||
cubot.setHeldItem(GameServer.INSTANCE.getConfig().getInt("new_user_item"));
|
||||
cubot.setEnergy(GameServer.INSTANCE.getConfig().getInt("battery_max_energy"));
|
||||
cubot.setMaxEnergy(GameServer.INSTANCE.getConfig().getInt("battery_max_energy"));
|
||||
|
||||
cubot.setParent(user);
|
||||
|
||||
Point point = cubot.getWorld().getRandomPassableTile();
|
||||
|
||||
cubot.setX(point.x);
|
||||
cubot.setY(point.y);
|
||||
|
||||
user.setControlledUnit(cubot);
|
||||
|
||||
LogManager.LOGGER.fine("(Plugin) Handled User creation event (Cubot Plugin)");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@ public class CubotTest {
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertEquals(1,2);
|
||||
assertEquals(1, 1);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,9 @@
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: junit:junit:4.10" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
|
||||
|
||||
@@ -4,23 +4,16 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.simon987.server</groupId>
|
||||
<artifactId>server_root</artifactId>
|
||||
<version>1.2a</version>
|
||||
</parent>
|
||||
|
||||
<groupId>net.simon987.pluginmischw</groupId>
|
||||
<artifactId>plugin-misc-hw</artifactId>
|
||||
<version>1.2a</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.simon987.server</groupId>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package net.simon987.mischwplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Util;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class Clock extends CpuHardware {
|
||||
|
||||
@@ -28,15 +28,18 @@ public class Clock extends CpuHardware {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
public static Clock deserialize(JSONObject hwJSON) {
|
||||
public static Clock deserialize() {
|
||||
return new Clock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
|
||||
return json;
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package net.simon987.mischwplugin;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.mischwplugin.event.CpuInitialisationListener;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class MiscHWPlugin extends ServerPlugin implements CpuHardwareDeserializer {
|
||||
|
||||
@@ -19,14 +19,14 @@ public class MiscHWPlugin extends ServerPlugin implements CpuHardwareDeserialize
|
||||
}
|
||||
|
||||
@Override
|
||||
public CpuHardware deserializeHardware(JSONObject hwJson) {
|
||||
int hwid = (int) (long) hwJson.get("hwid");
|
||||
public CpuHardware deserializeHardware(DBObject hwJson) {
|
||||
int hwid = (int) hwJson.get("hwid");
|
||||
|
||||
switch (hwid) {
|
||||
case RandomNumberGenerator.HWID:
|
||||
return RandomNumberGenerator.deserialize(hwJson);
|
||||
return RandomNumberGenerator.deserialize();
|
||||
case Clock.HWID:
|
||||
return Clock.deserialize(hwJson);
|
||||
return Clock.deserialize();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package net.simon987.mischwplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@@ -31,14 +31,16 @@ public class RandomNumberGenerator extends CpuHardware {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("hwid", (int) HWID);
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
return json;
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static RandomNumberGenerator deserialize(JSONObject hwJSON) {
|
||||
public static RandomNumberGenerator deserialize() {
|
||||
return new RandomNumberGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,5 +17,8 @@
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -4,21 +4,16 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.simon987.server</groupId>
|
||||
<artifactId>server_root</artifactId>
|
||||
<version>1.2a</version>
|
||||
</parent>
|
||||
|
||||
<groupId>net.simon987.pluginnpc</groupId>
|
||||
<artifactId>plugin-npc</artifactId>
|
||||
<version>1.2a</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package net.simon987.npcplugin;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.Updatable;
|
||||
@@ -51,9 +54,12 @@ public class Factory extends GameObject implements Updatable {
|
||||
for (Object id : tmpNpcArray) {
|
||||
|
||||
NonPlayerCharacter npc = (NonPlayerCharacter) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) id);
|
||||
npc.setFactory(this);
|
||||
|
||||
npcs.add(npc);
|
||||
if (npc != null) {
|
||||
npc.setFactory(this);
|
||||
npcs.add(npc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -68,7 +74,7 @@ public class Factory extends GameObject implements Updatable {
|
||||
npc.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||
npc.setX(p.x);
|
||||
npc.setY(p.y);
|
||||
getWorld().getGameObjects().add(npc);
|
||||
getWorld().addObject(npc);
|
||||
getWorld().incUpdatable();
|
||||
npc.setFactory(this);
|
||||
|
||||
@@ -117,14 +123,34 @@ public class Factory extends GameObject implements Updatable {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static Factory deserialise(JSONObject json) {
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("i", getObjectId());
|
||||
dbObject.put("x", getX());
|
||||
dbObject.put("y", getY());
|
||||
dbObject.put("t", ID);
|
||||
|
||||
BasicDBList tmpNpcArray = new BasicDBList();
|
||||
|
||||
for (NonPlayerCharacter npc : npcs) {
|
||||
tmpNpcArray.add(npc.getObjectId());
|
||||
}
|
||||
|
||||
dbObject.put("n", tmpNpcArray);
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static Factory deserialise(DBObject obj) {
|
||||
|
||||
Factory factory = new Factory();
|
||||
factory.setObjectId((long) json.get("i"));
|
||||
factory.setX((int) (long) json.get("x"));
|
||||
factory.setY((int) (long) json.get("y"));
|
||||
factory.setObjectId((long) obj.get("i"));
|
||||
factory.setX((int) obj.get("x"));
|
||||
factory.setY((int) obj.get("y"));
|
||||
|
||||
factory.tmpNpcArray = (Object[]) ((JSONArray) json.get("n")).toArray();
|
||||
factory.tmpNpcArray = ((BasicDBList) obj.get("n")).toArray();
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
@@ -33,14 +33,9 @@ public class HarvestTask extends NPCTask {
|
||||
|
||||
if (pause == 0) {
|
||||
//Get biomass
|
||||
ArrayList<GameObject> biomass = new ArrayList<>(10);
|
||||
|
||||
for (GameObject object : npc.getWorld().getGameObjects()) {
|
||||
//Plant MAP_INFO
|
||||
if ((object.getMapInfo() & 0x4000) == 0x4000) {
|
||||
biomass.add(object);
|
||||
}
|
||||
}
|
||||
/* todo replace by some sort of .collect call with object
|
||||
id (See https://github.com/simon987/Much-Assembly-Required/pull/66)*/
|
||||
ArrayList<GameObject> biomass = npc.getWorld().findObjects(0x4000);
|
||||
|
||||
//Get closest one
|
||||
int minDist = Integer.MAX_VALUE;
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
package net.simon987.npcplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.event.ObjectDeathEvent;
|
||||
import net.simon987.server.game.Direction;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
|
||||
public class HarvesterNPC extends NonPlayerCharacter {
|
||||
|
||||
public static final int ID = 10;
|
||||
|
||||
public static final int MAX_HEALTH = GameServer.INSTANCE.getConfig().getInt("harvester_hp_max");
|
||||
public static final int HEAL_RATE = GameServer.INSTANCE.getConfig().getInt("harvester_regen");
|
||||
|
||||
|
||||
public HarvesterNPC() {
|
||||
setTask(new HarvestTask());
|
||||
hp = 10;
|
||||
|
||||
setHp(MAX_HEALTH);
|
||||
setMaxHp(MAX_HEALTH);
|
||||
setHealRate(HEAL_RATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -31,11 +41,21 @@ public class HarvesterNPC extends NonPlayerCharacter {
|
||||
//Self-destroy when age limit is reached
|
||||
if (getAge() >= NonPlayerCharacter.LIFETIME) {
|
||||
setDead(true);
|
||||
getFactory().getNpcs().remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeadCallback() {
|
||||
|
||||
if (getFactory() != null && getFactory().getNpcs() != null) {
|
||||
getFactory().getNpcs().remove(this);
|
||||
}
|
||||
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(
|
||||
new ObjectDeathEvent(this, ID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = super.serialise();
|
||||
@@ -44,7 +64,7 @@ public class HarvesterNPC extends NonPlayerCharacter {
|
||||
json.put("x", getX());
|
||||
json.put("y", getY());
|
||||
json.put("direction", getDirection().ordinal());
|
||||
json.put("hp", hp);
|
||||
json.put("hp", getHp());
|
||||
json.put("energy", energy);
|
||||
json.put("action", getAction().ordinal());
|
||||
json.put("t", ID);
|
||||
@@ -52,16 +72,32 @@ public class HarvesterNPC extends NonPlayerCharacter {
|
||||
return json;
|
||||
}
|
||||
|
||||
public static HarvesterNPC deserialize(JSONObject json) {
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("i", getObjectId());
|
||||
dbObject.put("x", getX());
|
||||
dbObject.put("y", getY());
|
||||
dbObject.put("direction", getDirection().ordinal());
|
||||
dbObject.put("hp", getHp());
|
||||
// dbObject.put("energy", energy);
|
||||
dbObject.put("action", getAction().ordinal());
|
||||
dbObject.put("t", ID);
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static HarvesterNPC deserialize(DBObject obj) {
|
||||
|
||||
HarvesterNPC npc = new HarvesterNPC();
|
||||
npc.setObjectId((long) json.get("i"));
|
||||
npc.setX((int) (long) json.get("x"));
|
||||
npc.setY((int) (long) json.get("y"));
|
||||
npc.hp = (int) (long) json.get("hp");
|
||||
npc.setDirection(Direction.getDirection((int) (long) json.get("direction")));
|
||||
npc.energy = (int) (long) json.get("energy");
|
||||
npc.maxEnergy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy");
|
||||
npc.setObjectId((long) obj.get("i"));
|
||||
npc.setX((int) obj.get("x"));
|
||||
npc.setY((int) obj.get("y"));
|
||||
npc.setHp((int) obj.get("hp"));
|
||||
npc.setDirection(Direction.getDirection((int) obj.get("direction")));
|
||||
// npc.energy = (int) obj.get("energy");
|
||||
// npc.maxEnergy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy");
|
||||
|
||||
return npc;
|
||||
|
||||
|
||||
@@ -2,17 +2,14 @@ package net.simon987.npcplugin;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.Util;
|
||||
import net.simon987.server.game.Action;
|
||||
import net.simon987.server.game.Direction;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.Updatable;
|
||||
import net.simon987.server.game.*;
|
||||
import net.simon987.server.game.pathfinding.Node;
|
||||
import net.simon987.server.game.pathfinding.Pathfinder;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class NonPlayerCharacter extends GameObject implements Updatable {
|
||||
public abstract class NonPlayerCharacter extends GameObject implements Updatable, Attackable {
|
||||
|
||||
private static final int MAP_INFO = 0x0040;
|
||||
|
||||
@@ -20,8 +17,11 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
|
||||
|
||||
public static final int LIFETIME = GameServer.INSTANCE.getConfig().getInt("npc_lifetime");
|
||||
|
||||
// Set these just in case they aren't overridden in the subclass
|
||||
public static final int HP_MAX_DEFAULT = 100;
|
||||
public static final int HP_REGEN_RATE_DEFAULT = 0;
|
||||
|
||||
//Unused
|
||||
int hp;
|
||||
int energy;
|
||||
int maxEnergy;
|
||||
|
||||
@@ -48,6 +48,21 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
|
||||
*/
|
||||
private int age = 0;
|
||||
|
||||
/**
|
||||
* Current health of the npc
|
||||
*/
|
||||
private int hp = HP_MAX_DEFAULT;
|
||||
|
||||
/**
|
||||
* Health regeneration rate of the npc
|
||||
*/
|
||||
private int hpRegenerationRate = HP_REGEN_RATE_DEFAULT;
|
||||
|
||||
/**
|
||||
* Maximum health of the npc
|
||||
*/
|
||||
private int maxHp = HP_MAX_DEFAULT;
|
||||
|
||||
@Override
|
||||
public char getMapInfo() {
|
||||
return MAP_INFO;
|
||||
@@ -66,6 +81,9 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
|
||||
|
||||
selfDestroyNextTick = true;
|
||||
}
|
||||
|
||||
//Heal the NPC
|
||||
heal(hpRegenerationRate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,6 +176,52 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHealRate(int hp) {
|
||||
hpRegenerationRate = hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHp(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHp() {
|
||||
return maxHp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxHp(int hp) {
|
||||
this.maxHp = hp;
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void heal(int amount) {
|
||||
hp += amount;
|
||||
|
||||
//Can't heal above max
|
||||
if (hp > maxHp) {
|
||||
hp = maxHp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int amount) {
|
||||
hp -= amount;
|
||||
|
||||
//YOU ARE DEAD
|
||||
if (hp <= 0) {
|
||||
setDead(true);
|
||||
}
|
||||
}
|
||||
|
||||
public NPCTask getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
@@ -1,35 +1,65 @@
|
||||
package net.simon987.npcplugin;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.npcplugin.event.CpuInitialisationListener;
|
||||
import net.simon987.npcplugin.event.WorldCreationListener;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
||||
import net.simon987.server.io.GameObjectDeserializer;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer {
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer, CpuHardwareDeserializer {
|
||||
|
||||
/**
|
||||
* Radio tower cache
|
||||
*/
|
||||
private static ArrayList<RadioTower> radioTowers;
|
||||
|
||||
@Override
|
||||
public void init(ServerConfiguration configuration) {
|
||||
|
||||
listeners.add(new WorldCreationListener());
|
||||
listeners.add(new CpuInitialisationListener());
|
||||
|
||||
radioTowers = new ArrayList<>(32);
|
||||
|
||||
LogManager.LOGGER.info("Initialised NPC plugin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameObject deserializeObject(JSONObject object) {
|
||||
public GameObject deserializeObject(DBObject obj) {
|
||||
|
||||
int objType = (int) (long) object.get("t");
|
||||
int objType = (int) obj.get("t");
|
||||
|
||||
if (objType == HarvesterNPC.ID) {
|
||||
return HarvesterNPC.deserialize(object);
|
||||
return HarvesterNPC.deserialize(obj);
|
||||
} else if (objType == Factory.ID) {
|
||||
return Factory.deserialise(object);
|
||||
return Factory.deserialise(obj);
|
||||
} else if (objType == RadioTower.ID) {
|
||||
return RadioTower.deserialize(obj);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CpuHardware deserializeHardware(DBObject obj) {
|
||||
int hwid = (int) obj.get("hwid");
|
||||
|
||||
switch (hwid) {
|
||||
case RadioReceiverHardware.HWID:
|
||||
return RadioReceiverHardware.deserialize(obj);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ArrayList<RadioTower> getRadioTowers() {
|
||||
return radioTowers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package net.simon987.npcplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Util;
|
||||
import net.simon987.server.game.Action;
|
||||
import net.simon987.server.game.ControllableUnit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RadioReceiverHardware extends CpuHardware {
|
||||
|
||||
public static final char HWID = 0xC; //12
|
||||
|
||||
private static final int LISTEN = 1;
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 0xC;
|
||||
|
||||
private ControllableUnit cubot;
|
||||
|
||||
public RadioReceiverHardware(ControllableUnit cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
int x = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == LISTEN) {
|
||||
|
||||
//Find the nearest Radio Tower and query it
|
||||
cubot.setAction(Action.LISTENING);
|
||||
|
||||
ArrayList<char[]> messages = new ArrayList<>(6);
|
||||
|
||||
ArrayList<RadioTower> towers = new ArrayList<>(NpcPlugin.getRadioTowers()); //Avoid ConcurrentModificationException
|
||||
for (RadioTower tower : towers) {
|
||||
if (Util.manhattanDist(tower.getWorld().getX(), tower.getWorld().getY(), cubot.getWorld().getX(),
|
||||
cubot.getWorld().getY()) <= RadioTower.MAX_RANGE) {
|
||||
//Tower is in range
|
||||
messages.addAll(tower.getMessages());
|
||||
}
|
||||
}
|
||||
|
||||
//Write messages to memory
|
||||
int offset = 0;
|
||||
|
||||
for (char[] message : messages) {
|
||||
|
||||
getCpu().getMemory().write(x + offset, message, 0, message.length);
|
||||
offset += message.length;
|
||||
}
|
||||
|
||||
//Write the amount of messages received to B
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(messages.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static RadioReceiverHardware deserialize(DBObject obj) {
|
||||
return new RadioReceiverHardware((ControllableUnit) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
120
Plugin NPC/src/main/java/net/simon987/npcplugin/RadioTower.java
Normal file
120
Plugin NPC/src/main/java/net/simon987/npcplugin/RadioTower.java
Normal file
@@ -0,0 +1,120 @@
|
||||
package net.simon987.npcplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.Programmable;
|
||||
import net.simon987.server.game.Updatable;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RadioTower extends GameObject implements Programmable, Updatable {
|
||||
|
||||
private static final int MAP_INFO = 0x1000;
|
||||
|
||||
public static final int ID = 4;
|
||||
|
||||
public static final int MAX_RANGE = 3; //todo load from config
|
||||
|
||||
private static final int MAX_MESSAGES = 16;
|
||||
|
||||
@Override
|
||||
public char getMapInfo() {
|
||||
return MAP_INFO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Messages from the current tick
|
||||
*/
|
||||
private ArrayList<char[]> messages = new ArrayList<>(4);
|
||||
|
||||
/**
|
||||
* Messages from the last tick
|
||||
*/
|
||||
private ArrayList<char[]> lastMessages = new ArrayList<>(4);
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
lastMessages = new ArrayList<>(messages);
|
||||
messages.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendMessage(char[] message) {
|
||||
|
||||
if (message.length < MAX_MESSAGES) {
|
||||
messages.add(message);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
json.put("i", getObjectId());
|
||||
json.put("x", getX());
|
||||
json.put("y", getY());
|
||||
json.put("t", ID);
|
||||
|
||||
return json;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("i", getObjectId());
|
||||
dbObject.put("x", getX());
|
||||
dbObject.put("y", getY());
|
||||
dbObject.put("t", ID);
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static RadioTower deserialize(DBObject obj) {
|
||||
|
||||
RadioTower tower = new RadioTower();
|
||||
tower.setObjectId((long) obj.get("i"));
|
||||
tower.setX((int) obj.get("x"));
|
||||
tower.setY((int) obj.get("y"));
|
||||
|
||||
NpcPlugin.getRadioTowers().add(tower);
|
||||
|
||||
return tower;
|
||||
}
|
||||
|
||||
|
||||
public ArrayList<char[]> getMessages() {
|
||||
return lastMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first directly adjacent tile (starting east, going clockwise)
|
||||
*/
|
||||
public Point getAdjacentTile() {
|
||||
|
||||
if (!getWorld().isTileBlocked(getX() + 1, getY())) {
|
||||
return new Point(getX() + 1, getY());
|
||||
|
||||
} else if (!getWorld().isTileBlocked(getX(), getY() + 1)) {
|
||||
return new Point(getX(), getY() + 1);
|
||||
|
||||
} else if (!getWorld().isTileBlocked(getX() - 1, getY())) {
|
||||
return new Point(getX() - 1, getY());
|
||||
|
||||
} else if (!getWorld().isTileBlocked(getX(), getY() - 1)) {
|
||||
return new Point(getX(), getY() - 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.simon987.npcplugin.event;
|
||||
|
||||
import net.simon987.npcplugin.RadioReceiverHardware;
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.event.CpuInitialisationEvent;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
public class CpuInitialisationListener implements GameEventListener {
|
||||
@Override
|
||||
public Class getListenedEventType() {
|
||||
return CpuInitialisationEvent.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(GameEvent event) {
|
||||
CPU cpu = (CPU) event.getSource();
|
||||
User user = ((CpuInitialisationEvent) event).getUser();
|
||||
|
||||
RadioReceiverHardware radioHw = new RadioReceiverHardware(user.getControlledUnit());
|
||||
radioHw.setCpu(cpu);
|
||||
|
||||
cpu.attachHardware(radioHw, RadioReceiverHardware.DEFAULT_ADDRESS);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package net.simon987.npcplugin.event;
|
||||
|
||||
import net.simon987.npcplugin.Factory;
|
||||
import net.simon987.npcplugin.NpcPlugin;
|
||||
import net.simon987.npcplugin.RadioTower;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
@@ -8,6 +10,7 @@ import net.simon987.server.event.WorldGenerationEvent;
|
||||
import net.simon987.server.game.World;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Random;
|
||||
|
||||
public class WorldCreationListener implements GameEventListener {
|
||||
@@ -31,6 +34,7 @@ public class WorldCreationListener implements GameEventListener {
|
||||
|
||||
World world = ((WorldGenerationEvent) event).getWorld();
|
||||
|
||||
outerLoopFactory:
|
||||
for (int x = 2; x < 12; x++) {
|
||||
for (int y = 2; y < 12; y++) {
|
||||
|
||||
@@ -49,15 +53,45 @@ public class WorldCreationListener implements GameEventListener {
|
||||
continue;
|
||||
}
|
||||
|
||||
world.getGameObjects().add(factory);
|
||||
world.addObject(factory);
|
||||
world.incUpdatable();
|
||||
|
||||
LogManager.LOGGER.info("Spawned Factory at (" + world.getX() + ", " + world.getY() +
|
||||
") (" + x + ", " + y + ")");
|
||||
break outerLoopFactory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Also spawn a radio tower in the same World
|
||||
Point p = world.getRandomPassableTile();
|
||||
if (p != null) {
|
||||
while (p.x == 0 || p.x == World.WORLD_SIZE - 1 || p.y == World.WORLD_SIZE - 1 || p.y == 0) {
|
||||
p = world.getRandomPassableTile();
|
||||
|
||||
if (p == null) {
|
||||
//World is full
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RadioTower radioTower = new RadioTower();
|
||||
|
||||
radioTower.setWorld(world);
|
||||
radioTower.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||
radioTower.setX(p.x);
|
||||
radioTower.setY(p.y);
|
||||
|
||||
if (radioTower.getAdjacentTile() != null) {
|
||||
//Radio Tower has adjacent tiles
|
||||
world.addObject(radioTower);
|
||||
world.incUpdatable(); //In case the Factory couldn't be spawned.
|
||||
|
||||
NpcPlugin.getRadioTowers().add(radioTower);
|
||||
|
||||
LogManager.LOGGER.info("Spawned RadioTower at (" + world.getX() + ", " + world.getY() +
|
||||
") (" + p.x + ", " + p.y + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,5 +17,8 @@
|
||||
<orderEntry type="module" module-name="Server" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -4,21 +4,17 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.simon987.server</groupId>
|
||||
<artifactId>server_root</artifactId>
|
||||
<version>1.2a</version>
|
||||
</parent>
|
||||
|
||||
<groupId>net.simon987.pluginplant</groupId>
|
||||
<artifactId>plugin-biomassBlob</artifactId>
|
||||
<version>1.2a</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.simon987.biomassplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.InventoryHolder;
|
||||
import org.json.simple.JSONObject;
|
||||
@@ -40,6 +42,20 @@ public class BiomassBlob extends GameObject implements InventoryHolder {
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("t", ID);
|
||||
dbObject.put("i", getObjectId());
|
||||
dbObject.put("x", getX());
|
||||
dbObject.put("y", getY());
|
||||
dbObject.put("b", biomassCount);
|
||||
|
||||
return dbObject;
|
||||
|
||||
}
|
||||
|
||||
public int getBiomassCount() {
|
||||
return biomassCount;
|
||||
@@ -57,15 +73,15 @@ public class BiomassBlob extends GameObject implements InventoryHolder {
|
||||
// this.style = style;
|
||||
// }
|
||||
|
||||
public static BiomassBlob deserialize(JSONObject json) {
|
||||
public static BiomassBlob deserialize(DBObject obj) {
|
||||
|
||||
BiomassBlob biomassBlob = new BiomassBlob();
|
||||
|
||||
biomassBlob.setObjectId((long) json.get("i"));
|
||||
biomassBlob.setX((int) (long) json.get("x"));
|
||||
biomassBlob.setY((int) (long) json.get("y"));
|
||||
// biomassBlob.style = (int) (long) json.get("style");
|
||||
biomassBlob.biomassCount = (int) (long) json.get("b");
|
||||
biomassBlob.setObjectId((long) obj.get("i"));
|
||||
biomassBlob.setX((int) obj.get("x"));
|
||||
biomassBlob.setY((int) obj.get("y"));
|
||||
// biomassBlob.style = (int) json.get("style");
|
||||
biomassBlob.biomassCount = (int) obj.get("b");
|
||||
|
||||
return biomassBlob;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.simon987.biomassplugin;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.biomassplugin.event.ObjectDeathListener;
|
||||
import net.simon987.biomassplugin.event.WorldCreationListener;
|
||||
import net.simon987.biomassplugin.event.WorldUpdateListener;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
@@ -7,7 +9,6 @@ import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.io.GameObjectDeserializer;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class BiomassPlugin extends ServerPlugin implements GameObjectDeserializer {
|
||||
|
||||
@@ -16,14 +17,15 @@ public class BiomassPlugin extends ServerPlugin implements GameObjectDeserialize
|
||||
public void init(ServerConfiguration config) {
|
||||
listeners.add(new WorldCreationListener());
|
||||
listeners.add(new WorldUpdateListener(config));
|
||||
listeners.add(new ObjectDeathListener(config));
|
||||
|
||||
LogManager.LOGGER.info("Initialised Biomass plugin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameObject deserializeObject(JSONObject object) {
|
||||
public GameObject deserializeObject(DBObject object) {
|
||||
|
||||
int objType = (int) (long) object.get("t");
|
||||
int objType = (int) object.get("t");
|
||||
|
||||
if (objType == BiomassBlob.ID) {
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public class WorldUtils {
|
||||
|
||||
Random random = new Random();
|
||||
int blobCount = random.nextInt(maxCount - minCount) + minCount;
|
||||
ArrayList<BiomassBlob> biomassBlobs = new ArrayList<>(maxCount);
|
||||
ArrayList<BiomassBlob> biomassBlobs = new ArrayList<>(blobCount);
|
||||
|
||||
//Count number of plain tiles. If there is less plain tiles than desired amount of blobs,
|
||||
//set the desired amount of blobs to the plain tile count
|
||||
@@ -45,7 +45,7 @@ public class WorldUtils {
|
||||
//Don't block worlds
|
||||
int counter = 0;
|
||||
while (p.x == 0 || p.y == 0 || p.x == World.WORLD_SIZE - 1 || p.y == World.WORLD_SIZE - 1 ||
|
||||
world.isTileBlocked(p.x, p.y)) {
|
||||
world.getGameObjectsAt(p.x, p.y).size() != 0) {
|
||||
p = world.getTileMap().getRandomPlainTile();
|
||||
counter++;
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package net.simon987.biomassplugin.event;
|
||||
|
||||
import net.simon987.biomassplugin.BiomassBlob;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
import net.simon987.server.event.ObjectDeathEvent;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.World;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
/**
|
||||
* Handles ObjectDeathEvent events
|
||||
*/
|
||||
public class ObjectDeathListener implements GameEventListener {
|
||||
|
||||
private int biomassDropCount;
|
||||
|
||||
public ObjectDeathListener(ServerConfiguration config) {
|
||||
biomassDropCount = config.getInt("harvester_biomass_drop_count");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getListenedEventType() {
|
||||
return ObjectDeathEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(GameEvent event) {
|
||||
// TODO: setup enum with all GameObject type IDs
|
||||
if (((ObjectDeathEvent) event).getSourceObjectId() == 10) {
|
||||
//An HarvesterNPC ObjectDeathEvent is received
|
||||
GameObject dyingHarvesterNPC = (GameObject)event.getSource();
|
||||
|
||||
|
||||
//Don't spawn biomass on World border
|
||||
if (dyingHarvesterNPC.getX() != 0 && dyingHarvesterNPC.getX() != World.WORLD_SIZE - 1 &&
|
||||
dyingHarvesterNPC.getY() != 0 && dyingHarvesterNPC.getY() != World.WORLD_SIZE - 1) {
|
||||
//Create a new biomass
|
||||
BiomassBlob newBiomassBlob = createBiomassBlobAt(
|
||||
dyingHarvesterNPC.getX(), dyingHarvesterNPC.getY(), dyingHarvesterNPC.getWorld());
|
||||
//Add it to the world game objects
|
||||
dyingHarvesterNPC.getWorld().addObject(newBiomassBlob);
|
||||
LogManager.LOGGER.fine("Spawned biomass at (" + newBiomassBlob.getX() +
|
||||
", " + newBiomassBlob.getY() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a biomass at the given x, y coordinates and in the world
|
||||
* @param x x coord of biomass location
|
||||
* @param y y coord of biomass location
|
||||
* @param world world in which the biomass will be created in
|
||||
* @return the new BiomassBlob created
|
||||
*/
|
||||
private BiomassBlob createBiomassBlobAt(int x, int y, World world) {
|
||||
|
||||
BiomassBlob biomassBlob = new BiomassBlob();
|
||||
biomassBlob.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||
// biomassBlob.setStyle(0); //TODO: set style depending on difficulty level? or random? from config?
|
||||
biomassBlob.setBiomassCount(biomassDropCount);
|
||||
biomassBlob.setX(x);
|
||||
biomassBlob.setY(y);
|
||||
biomassBlob.setWorld(world);
|
||||
|
||||
return biomassBlob;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,9 @@ public class WorldCreationListener implements GameEventListener {
|
||||
ArrayList<BiomassBlob> biomassBlobs = WorldUtils.generateBlobs(((WorldGenerationEvent) event).getWorld(),
|
||||
minCount, maxCount, yield);
|
||||
|
||||
((WorldGenerationEvent) event).getWorld().getGameObjects().addAll(biomassBlobs);
|
||||
for (BiomassBlob blob : biomassBlobs) {
|
||||
((WorldGenerationEvent) event).getWorld().addObject(blob);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ public class WorldUpdateListener implements GameEventListener {
|
||||
|
||||
private HashMap<World, Long> worldWaitMap = new HashMap<>(200);
|
||||
|
||||
private int minBlobCount;
|
||||
private int maxBlobCount;
|
||||
private int blobYield;
|
||||
private int waitTime;
|
||||
private int blobThreshold;
|
||||
private static int minBlobCount;
|
||||
private static int maxBlobCount;
|
||||
private static int blobYield;
|
||||
private static int waitTime;
|
||||
private static int blobThreshold;
|
||||
|
||||
public WorldUpdateListener(ServerConfiguration config) {
|
||||
|
||||
@@ -45,7 +45,7 @@ public class WorldUpdateListener implements GameEventListener {
|
||||
World world = ((WorldUpdateEvent) event).getWorld();
|
||||
|
||||
//If there is less than the respawn threshold,
|
||||
if (world.getGameObjects(BiomassBlob.class).size() < blobThreshold) {
|
||||
if (world.findObjects(BiomassBlob.class).size() < blobThreshold) {
|
||||
|
||||
//Set a timer for respawn_time ticks
|
||||
if (!worldWaitMap.containsKey(world) || worldWaitMap.get(world) == 0L) {
|
||||
@@ -59,7 +59,9 @@ public class WorldUpdateListener implements GameEventListener {
|
||||
//If the timer was set less than respawn_time ticks ago, respawn the blobs
|
||||
ArrayList<BiomassBlob> newBlobs = WorldUtils.generateBlobs(world, minBlobCount,
|
||||
maxBlobCount, blobYield);
|
||||
world.getGameObjects().addAll(newBlobs);
|
||||
for (BiomassBlob blob : newBlobs) {
|
||||
world.addObject(blob);
|
||||
}
|
||||
|
||||
//Set the 'waitUntil' time to 0 to indicate that we are not waiting
|
||||
worldWaitMap.replace(world, 0L);
|
||||
|
||||
77
README.md
77
README.md
@@ -7,5 +7,80 @@ In its current state, players can walk around the game universe and collect Biom
|
||||
Wiki: [GitHub](https://github.com/simon987/Much-Assembly-Required/wiki)
|
||||
Chat: [Slack](https://join.slack.com/t/muchassemblyrequired/shared_invite/enQtMjY3Mjc1OTUwNjEwLTkyOTIwOTA5OGY4MDVlMGI4NzM5YzlhMWJiMGY1OWE2NjUxODQ1NWQ1YTcxMTA1NGZkYzNjYzMyM2E1ODdmNzg)
|
||||
|
||||
## VS Code Extensions
|
||||
- [Much Assembly Required (Upload on Save)](https://marketplace.visualstudio.com/items?itemName=tomhodder.much-assembly-required-upload-on-save) by tomhodder
|
||||
- [Much Assembly Required Language Support](https://marketplace.visualstudio.com/items?itemName=PJB3005.much-assembly-required-language-support) by PJB3005
|
||||
|
||||
_Building instructions coming soon_
|
||||
# Deploying the server
|
||||
|
||||
Note: You can find the frontend [here](https://github.com/simon987/Much-Assembly-Required-Frontend)
|
||||
|
||||
|
||||
## Linux (Ubuntu 16.04)
|
||||
```bash
|
||||
# Install tools
|
||||
sudo apt install git maven openjdk-8-jdk
|
||||
|
||||
# Obtain source files
|
||||
git clone https://github.com/simon987/Much-Assembly-Required.git
|
||||
|
||||
# Build
|
||||
cd Much-Assembly-Required
|
||||
mvn package
|
||||
|
||||
# Run
|
||||
cd target
|
||||
java -jar server-1.2a.jar
|
||||
```
|
||||
|
||||
## Windows (tested on Windows 10)
|
||||
|
||||
Installation instructions:
|
||||
1. Download the JDK from [here](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
||||
Install the JDK and update your PATH and JAVA_HOME enviroment variables.
|
||||
2. Download Maven from [here](https://maven.apache.org/).
|
||||
Install Maven (following the README) and update your PATH enviroment variable.
|
||||
3. Download Mongo DB Community from [here](https://www.mongodb.com/download-center#community).
|
||||
Install Mongo DB following the instructions [here](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/).
|
||||
Update your PATH enviroment variable.
|
||||
|
||||
Building instructions:
|
||||
```batch
|
||||
:: Builds the server
|
||||
cd Much-Assembly-Required
|
||||
mvn package
|
||||
```
|
||||
|
||||
Running instructions:
|
||||
1. In one Command Prompt window, run Mongo DB:
|
||||
```batch
|
||||
:: Runs Mongo DB
|
||||
mongod
|
||||
```
|
||||
2. In a second Command Prompt window, run the MAR server:
|
||||
```batch
|
||||
:: Runs the MAR server
|
||||
cd Much-Assembly-Required\target
|
||||
java -jar server-1.2a.jar
|
||||
```
|
||||
3. Run the frontend, following the instructions that you can find [here](https://github.com/simon987/Much-Assembly-Required-Frontend).
|
||||
|
||||
|
||||
## Docker
|
||||
### Requirements
|
||||
|
||||
1. [Docker Compose](https://docs.docker.com/compose/install/#install-compose) (and dependencies)
|
||||
|
||||
### Installation
|
||||
|
||||
Once Docker and Docker Compose are installed, you can build and start
|
||||
this application by running the following command inside this
|
||||
application's directory:
|
||||
|
||||
`docker-compose up`
|
||||
|
||||
This will start MySQL and then build and run this application. It will
|
||||
be available via http://localhost.
|
||||
|
||||
Note that there is currently no frontend web application serving the
|
||||
WebSocket feed served by the `Server` application!
|
||||
|
||||
@@ -4,18 +4,20 @@
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.java-websocket:Java-WebSocket:1.3.6" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.42" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:2.10.1" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -4,13 +4,38 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.simon987.server</groupId>
|
||||
<artifactId>server</artifactId>
|
||||
<version>1.2a</version>
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-resources</id>
|
||||
<!-- here the phase you need -->
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>../target/</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>../Server/src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>config.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<version>3.6.2</version>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
@@ -18,9 +43,54 @@
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>../target/libs</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<configuration>
|
||||
<outputDirectory>../target</outputDirectory>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>net.simon987.server.Main</mainClass>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>libs/</classpathPrefix>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.7.2</version>
|
||||
<configuration>
|
||||
<workingDirectory>./src/main/resources</workingDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<groupId>net.simon987.server</groupId>
|
||||
<artifactId>server</artifactId>
|
||||
<version>1.2a</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
@@ -43,7 +113,22 @@
|
||||
<artifactId>json-simple</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<!-- explicitly set build encoding so not altered by build platform defaults -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -1,32 +1,27 @@
|
||||
package net.simon987.server;
|
||||
|
||||
|
||||
import com.mongodb.*;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventDispatcher;
|
||||
import net.simon987.server.event.TickEvent;
|
||||
import net.simon987.server.game.DayNightCycle;
|
||||
import net.simon987.server.game.GameUniverse;
|
||||
import net.simon987.server.game.World;
|
||||
import net.simon987.server.io.FileUtils;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.plugin.PluginManager;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import net.simon987.server.user.User;
|
||||
import net.simon987.server.webserver.SocketServer;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class GameServer implements Runnable {
|
||||
|
||||
public final static GameServer INSTANCE = new GameServer();
|
||||
private final static String SAVE_JSON = "save.json";
|
||||
|
||||
private GameUniverse gameUniverse;
|
||||
private GameUniverse gameUniverse;
|
||||
private GameEventDispatcher eventDispatcher;
|
||||
private PluginManager pluginManager;
|
||||
|
||||
@@ -38,11 +33,20 @@ public class GameServer implements Runnable {
|
||||
|
||||
private DayNightCycle dayNightCycle;
|
||||
|
||||
private MongoClient mongo = null;
|
||||
|
||||
public GameServer() {
|
||||
|
||||
this.config = new ServerConfiguration(new File("config.properties"));
|
||||
this.config = new ServerConfiguration("config.properties");
|
||||
|
||||
try{
|
||||
mongo = new MongoClient("localhost", 27017);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
gameUniverse = new GameUniverse(config);
|
||||
gameUniverse.setMongo(mongo);
|
||||
pluginManager = new PluginManager();
|
||||
|
||||
maxExecutionTime = config.getInt("user_timeout");
|
||||
@@ -124,8 +128,7 @@ public class GameServer implements Runnable {
|
||||
|
||||
|
||||
//Process user code
|
||||
ArrayList<User> users_ = gameUniverse.getUsers();
|
||||
for (User user : users_) {
|
||||
for (User user : gameUniverse.getUsers()) {
|
||||
|
||||
if (user.getCpu() != null) {
|
||||
try {
|
||||
@@ -145,10 +148,8 @@ public class GameServer implements Runnable {
|
||||
}
|
||||
|
||||
//Process each worlds
|
||||
//Avoid concurrent modification
|
||||
ArrayList<World> worlds = new ArrayList<>(gameUniverse.getWorlds());
|
||||
int updatedWorlds = 0;
|
||||
for (World world : worlds) {
|
||||
for (World world : gameUniverse.getWorlds()) {
|
||||
if (world.shouldUpdate()) {
|
||||
world.update();
|
||||
updatedWorlds++;
|
||||
@@ -157,61 +158,105 @@ public class GameServer implements Runnable {
|
||||
|
||||
//Save
|
||||
if (gameUniverse.getTime() % config.getInt("save_interval") == 0) {
|
||||
save(new File("save.json"));
|
||||
save();
|
||||
}
|
||||
|
||||
// Clean up history files
|
||||
if(gameUniverse.getTime() % config.getInt("clean_interval") == 0) {
|
||||
FileUtils.cleanHistory(config.getInt("history_size"));
|
||||
}
|
||||
|
||||
socketServer.tick();
|
||||
|
||||
LogManager.LOGGER.info("Processed " + gameUniverse.getWorlds().size() + " worlds (" + updatedWorlds +
|
||||
LogManager.LOGGER.info("Processed " + gameUniverse.getWorldCount() + " worlds (" + updatedWorlds +
|
||||
") updated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Save game universe to file in JSON format
|
||||
*
|
||||
* @param file JSON file to save
|
||||
*/
|
||||
public void save(File file) {
|
||||
|
||||
boolean dirExists = FileUtils.prepDirectory(FileUtils.DIR_PATH);
|
||||
|
||||
if (new File(new File(SAVE_JSON).getAbsolutePath()).exists() && dirExists) {
|
||||
byte[] data = FileUtils.bytifyFile(new File(SAVE_JSON).toPath());
|
||||
try {
|
||||
FileUtils.writeSaveToZip(SAVE_JSON, data);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Failed to write " + SAVE_JSON + " to zip file");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
void load() {
|
||||
|
||||
try {
|
||||
FileWriter fileWriter = new FileWriter(file);
|
||||
LogManager.LOGGER.info("Loading all data from MongoDB");
|
||||
|
||||
JSONObject universe = gameUniverse.serialise();
|
||||
DB db = mongo.getDB("mar");
|
||||
|
||||
JSONArray plugins = new JSONArray();
|
||||
DBCollection worlds = db.getCollection("world");
|
||||
DBCollection users = db.getCollection("user");
|
||||
DBCollection server = db.getCollection("server");
|
||||
|
||||
for (ServerPlugin plugin : pluginManager.getPlugins()) {
|
||||
plugins.add(plugin.serialise());
|
||||
}
|
||||
|
||||
universe.put("plugins", plugins);
|
||||
|
||||
fileWriter.write(universe.toJSONString());
|
||||
fileWriter.close();
|
||||
|
||||
LogManager.LOGGER.info("Saved to file " + file.getName());
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
BasicDBObject whereQuery = new BasicDBObject();
|
||||
whereQuery.put("shouldUpdate", true);
|
||||
DBCursor cursor = worlds.find(whereQuery);
|
||||
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
|
||||
while (cursor.hasNext()) {
|
||||
World w = World.deserialize(cursor.next());
|
||||
universe.addWorld(w);
|
||||
}
|
||||
|
||||
//Load users
|
||||
cursor = users.find();
|
||||
while (cursor.hasNext()) {
|
||||
try {
|
||||
universe.addUser(User.deserialize(cursor.next()));
|
||||
} catch (CancelledException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
//Load misc server info
|
||||
cursor = server.find();
|
||||
if (cursor.hasNext()) {
|
||||
DBObject serverObj = cursor.next();
|
||||
gameUniverse.setTime((long) serverObj.get("time"));
|
||||
gameUniverse.setNextObjectId((long) serverObj.get("nextObjectId"));
|
||||
}
|
||||
|
||||
LogManager.LOGGER.info("Done loading! W:" + GameServer.INSTANCE.getGameUniverse().getWorldCount() +
|
||||
" | U:" + GameServer.INSTANCE.getGameUniverse().getUserCount());
|
||||
}
|
||||
|
||||
private void save() {
|
||||
|
||||
LogManager.LOGGER.info("Saving to MongoDB | W:" + gameUniverse.getWorldCount() + " | U:" + gameUniverse.getUserCount());
|
||||
try{
|
||||
DB db = mongo.getDB("mar");
|
||||
|
||||
int unloaded_worlds = 0;
|
||||
|
||||
DBCollection worlds = db.getCollection("world");
|
||||
DBCollection users = db.getCollection("user");
|
||||
DBCollection server = db.getCollection("server");
|
||||
|
||||
int insertedWorlds = 0;
|
||||
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
|
||||
for (World w : universe.getWorlds()) {
|
||||
// LogManager.LOGGER.fine("Saving world "+w.getId()+" to mongodb");
|
||||
insertedWorlds++;
|
||||
worlds.save(w.mongoSerialise());
|
||||
|
||||
// If the world should unload, it is removed from the Universe after having been saved.
|
||||
if (w.shouldUnload()){
|
||||
unloaded_worlds++;
|
||||
// LogManager.LOGGER.fine("Unloading world "+w.getId()+" from universe");
|
||||
universe.removeWorld(w);
|
||||
}
|
||||
}
|
||||
|
||||
for (User u : GameServer.INSTANCE.getGameUniverse().getUsers()) {
|
||||
|
||||
if (!u.isGuest()) {
|
||||
users.save(u.mongoSerialise());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BasicDBObject serverObj = new BasicDBObject();
|
||||
serverObj.put("_id","serverinfo"); // a constant id ensures only one entry is kept and updated, instead of a new entry created every save.
|
||||
serverObj.put("time", gameUniverse.getTime());
|
||||
serverObj.put("nextObjectId", gameUniverse.getNextObjectId());
|
||||
server.save(serverObj);
|
||||
|
||||
LogManager.LOGGER.info(""+insertedWorlds+" worlds saved, "+unloaded_worlds+" unloaded");
|
||||
LogManager.LOGGER.info("Done!");
|
||||
} catch (Exception e) {
|
||||
LogManager.LOGGER.severe("Problem happened during save function");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public ServerConfiguration getConfig() {
|
||||
|
||||
@@ -3,27 +3,23 @@ package net.simon987.server;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.webserver.SocketServer;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
LogManager.initialize();
|
||||
ServerConfiguration config = new ServerConfiguration(new File("config.properties"));
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
LogManager.initialize(config);
|
||||
|
||||
//Load
|
||||
GameServer.INSTANCE.getGameUniverse().load(new File("save.json"));
|
||||
|
||||
GameServer.INSTANCE.load();
|
||||
|
||||
SocketServer socketServer = new SocketServer(new InetSocketAddress(config.getString("webSocket_host"),
|
||||
config.getInt("webSocket_port")), config);
|
||||
|
||||
GameServer.INSTANCE.setSocketServer(socketServer);
|
||||
|
||||
|
||||
(new Thread(socketServer)).start();
|
||||
(new Thread(GameServer.INSTANCE)).start();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import net.simon987.server.logging.LogManager;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -18,11 +19,11 @@ public class ServerConfiguration {
|
||||
*/
|
||||
private Properties properties;
|
||||
|
||||
public ServerConfiguration(File file) {
|
||||
public ServerConfiguration(String file) {
|
||||
try {
|
||||
properties = new Properties();
|
||||
|
||||
properties.load(new FileInputStream(file));
|
||||
InputStream is = new FileInputStream("config.properties");
|
||||
properties.load(is);
|
||||
|
||||
} catch (IOException e) {
|
||||
LogManager.LOGGER.severe("Problem loading server configuration: " + e.getMessage());
|
||||
|
||||
@@ -3,11 +3,15 @@ package net.simon987.server.assembly;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.*;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Top-level class for assembly operations.
|
||||
@@ -20,6 +24,8 @@ public class Assembler {
|
||||
|
||||
private RegisterSet registerSet;
|
||||
|
||||
private static final int MEM_SIZE = 0x10000; // Size in words todo load from config
|
||||
|
||||
public Assembler(InstructionSet instructionSet, RegisterSet registerSet, ServerConfiguration config) {
|
||||
this.instructionSet = instructionSet;
|
||||
this.registerSet = registerSet;
|
||||
@@ -47,11 +53,9 @@ public class Assembler {
|
||||
* @return The line without its label part
|
||||
*/
|
||||
private static String removeLabel(String line) {
|
||||
if (line.indexOf(':') != -1) {
|
||||
return line.substring(line.indexOf(':') + 1);
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
|
||||
return line.replaceAll("^\\s*\\b\\w*\\b:", "");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,10 +97,11 @@ public class Assembler {
|
||||
line = removeComment(line);
|
||||
|
||||
//Check for labels
|
||||
if (line.indexOf(':') != -1) {
|
||||
Pattern pattern = Pattern.compile("^\\s*\\b\\w*\\b:");
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
|
||||
line = line.substring(0, line.indexOf(':'));
|
||||
String label = line.trim();
|
||||
if (matcher.find()) {
|
||||
String label = matcher.group(0).substring(0, matcher.group(0).length() - 1).trim();
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: Label " + label + " @ " + (result.origin + currentOffset));
|
||||
result.labels.put(label, (char) (result.origin + currentOffset));
|
||||
@@ -129,11 +134,12 @@ public class Assembler {
|
||||
|
||||
//System.out.println(line);
|
||||
|
||||
if (line.substring(0, 2).toUpperCase().equals("DW")) {
|
||||
if (line.length() >= 2 && line.substring(0, 2).toUpperCase().equals("DW")) {
|
||||
|
||||
try {
|
||||
|
||||
String[] values = line.substring(2, line.length()).split(",");
|
||||
//Special thanks to https://stackoverflow.com/questions/1757065/
|
||||
String[] values = line.substring(2, line.length()).split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
|
||||
|
||||
for (String value : values) {
|
||||
|
||||
@@ -144,6 +150,14 @@ public class Assembler {
|
||||
//Handle DUP operator
|
||||
if (valueTokens.length == 2 && valueTokens[1].toUpperCase().contains("DUP(")) {
|
||||
out.write(parseDUPOperator16(valueTokens, labels, currentLine));
|
||||
} else if (value.startsWith("\"") && value.endsWith("\"")) {
|
||||
//Handle string
|
||||
|
||||
//Unescape the string
|
||||
String string = value.substring(1, value.length() - 1);
|
||||
string = StringEscapeUtils.unescapeJava(string);
|
||||
|
||||
out.write(string.getBytes(StandardCharsets.UTF_16BE));
|
||||
} else if (labels != null && labels.containsKey(value)) {
|
||||
//Handle label
|
||||
out.writeChar(labels.get(value));
|
||||
@@ -161,7 +175,18 @@ public class Assembler {
|
||||
out.writeChar(0);
|
||||
|
||||
} else {
|
||||
throw new InvalidOperandException("Invalid operand \"" + value + '"', currentLine);
|
||||
|
||||
//Integer.decode failed, try binary
|
||||
if (value.startsWith("0b")) {
|
||||
try {
|
||||
out.writeChar(Integer.parseInt(value.substring(2), 2));
|
||||
} catch (NumberFormatException e2) {
|
||||
throw new InvalidOperandException("Invalid operand \"" + value + '"', currentLine);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidOperandException("Invalid operand \"" + value + '"', currentLine);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,6 +219,11 @@ public class Assembler {
|
||||
try {
|
||||
|
||||
int factor = Integer.decode(valueTokens[0]);
|
||||
|
||||
if (factor > MEM_SIZE) {
|
||||
throw new InvalidOperandException("Factor '"+factor+"' exceeds total memory size", currentLine);
|
||||
}
|
||||
|
||||
String value = valueTokens[1].substring(4, valueTokens[1].lastIndexOf(')'));
|
||||
|
||||
//Handle label
|
||||
@@ -237,25 +267,25 @@ public class Assembler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for and handle segment declarations (.text & .data)
|
||||
* Check for and handle section declarations (.text & .data)
|
||||
*
|
||||
* @param line Current line
|
||||
*/
|
||||
private static void checkForSegmentDeclaration(String line, AssemblyResult result,
|
||||
private static void checkForSectionDeclaration(String line, AssemblyResult result,
|
||||
int currentLine, int currentOffset) throws AssemblyException {
|
||||
|
||||
String[] tokens = line.split("\\s+");
|
||||
|
||||
if (tokens[0].toUpperCase().equals(".TEXT")) {
|
||||
|
||||
result.defineSegment(Segment.TEXT, currentLine, currentOffset);
|
||||
result.defineSecton(Section.TEXT, currentLine, currentOffset);
|
||||
throw new PseudoInstructionException(currentLine);
|
||||
|
||||
} else if (tokens[0].toUpperCase().equals(".DATA")) {
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: .data @" + currentLine);
|
||||
|
||||
result.defineSegment(Segment.DATA, currentLine, currentOffset);
|
||||
result.defineSecton(Section.DATA, currentLine, currentOffset);
|
||||
throw new PseudoInstructionException(currentLine);
|
||||
}
|
||||
}
|
||||
@@ -277,7 +307,7 @@ public class Assembler {
|
||||
String[] tokens = line.split("\\s+");
|
||||
|
||||
|
||||
if (line.toUpperCase().contains(" EQU ")) {
|
||||
if (line.toUpperCase().matches(".*\\bEQU\\b.*")) {
|
||||
if (tokens[1].toUpperCase().equals("EQU") && tokens.length == 3) {
|
||||
try {
|
||||
//Save value as a label
|
||||
@@ -329,17 +359,23 @@ public class Assembler {
|
||||
}
|
||||
|
||||
//Pass 2: Save label names and location
|
||||
char currentOffset = 0;
|
||||
int currentOffset = 0;
|
||||
for (currentLine = 0; currentLine < lines.length; currentLine++) {
|
||||
try {
|
||||
checkForLabel(lines[currentLine], result, currentOffset);
|
||||
checkForLabel(lines[currentLine], result, (char)currentOffset);
|
||||
|
||||
//Increment offset
|
||||
currentOffset += parseInstruction(lines[currentLine], currentLine, instructionSet).length / 2;
|
||||
|
||||
} catch (AssemblyException e) {
|
||||
if (currentOffset >= MEM_SIZE) {
|
||||
throw new OffsetOverflowException(currentOffset, MEM_SIZE, currentLine);
|
||||
}
|
||||
} catch (FatalAssemblyException e) {
|
||||
//Don't bother parsing the rest of the code, since it will not be assembled anyway
|
||||
break;
|
||||
} catch (AssemblyException e1) {
|
||||
//Ignore error on pass 2
|
||||
//System.out.println(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,17 +396,26 @@ public class Assembler {
|
||||
}
|
||||
|
||||
//Check for pseudo instructions
|
||||
checkForSegmentDeclaration(line, result, currentLine, currentOffset);
|
||||
checkForSectionDeclaration(line, result, currentLine, currentOffset);
|
||||
checkForEQUInstruction(line, result.labels, currentLine);
|
||||
checkForORGInstruction(line, result, currentLine);
|
||||
|
||||
//Encode instruction
|
||||
byte[] bytes = parseInstruction(line, currentLine, result.labels, instructionSet);
|
||||
currentOffset += bytes.length / 2;
|
||||
|
||||
if (currentOffset >= MEM_SIZE) {
|
||||
throw new OffsetOverflowException(currentOffset, MEM_SIZE, currentLine);
|
||||
}
|
||||
|
||||
out.write(bytes);
|
||||
|
||||
} catch (EmptyLineException | PseudoInstructionException e) {
|
||||
//Ignore empty lines and pseudo-instructions
|
||||
} catch (FatalAssemblyException asmE) {
|
||||
// Save error, but abort assembly at this line
|
||||
result.exceptions.add(asmE);
|
||||
break;
|
||||
} catch (AssemblyException asmE) {
|
||||
//Save errors on pass3
|
||||
result.exceptions.add(asmE);
|
||||
@@ -379,7 +424,26 @@ public class Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
result.bytes = out.toByteArray();
|
||||
//If the code contains OffsetOverFlowException(s), don't bother writing the assembled bytes to memory
|
||||
boolean writeToMemory = true;
|
||||
for (Exception e : result.exceptions) {
|
||||
if (e instanceof OffsetOverflowException) {
|
||||
writeToMemory = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (writeToMemory) {
|
||||
result.bytes = out.toByteArray();
|
||||
} else {
|
||||
result.bytes = new byte[0];
|
||||
LogManager.LOGGER.fine("Skipping writing assembled bytes to memory. (OffsetOverflowException)");
|
||||
}
|
||||
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
LogManager.LOGGER.info("Assembled " + result.bytes.length + " bytes (" + result.exceptions.size() + " errors)");
|
||||
for (AssemblyException e : result.exceptions) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.simon987.server.assembly;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.AssemblyException;
|
||||
import net.simon987.server.assembly.exception.DuplicateSegmentException;
|
||||
import net.simon987.server.assembly.exception.DuplicateSectionException;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -15,9 +15,8 @@ import java.util.HashMap;
|
||||
*/
|
||||
public class AssemblyResult {
|
||||
|
||||
|
||||
/**
|
||||
* The origin of the program, default is 0x400
|
||||
* The origin of the program, default is 0x200
|
||||
*/
|
||||
public int origin;
|
||||
/**
|
||||
@@ -28,15 +27,15 @@ public class AssemblyResult {
|
||||
* List of exceptions encountered during the assembly attempt,
|
||||
* they will be displayed in the editor
|
||||
*/
|
||||
ArrayList<AssemblyException> exceptions = new ArrayList<>(50);
|
||||
public ArrayList<AssemblyException> exceptions = new ArrayList<>(50);
|
||||
/**
|
||||
* Offset of the code segment
|
||||
*/
|
||||
private int codeSegmentOffset;
|
||||
private int codeSectionOffset;
|
||||
/**
|
||||
* Line of the code segment definition (for editor icons)
|
||||
* Line of the code segment definition
|
||||
*/
|
||||
private int codeSegmentLine;
|
||||
private int codeSectionLine;
|
||||
|
||||
/**
|
||||
* The encoded user code (will be incomplete or invalid if the
|
||||
@@ -44,62 +43,62 @@ public class AssemblyResult {
|
||||
*/
|
||||
public byte[] bytes;
|
||||
/**
|
||||
* Offset of the data segment, default is 0x4000
|
||||
* Offset of the data segment
|
||||
*/
|
||||
private int dataSegmentOffset;
|
||||
private int dataSectionOffset;
|
||||
/**
|
||||
* Line of the data segment definition (for editor icons)
|
||||
* Line of the data segment definition
|
||||
*/
|
||||
private int dataSegmentLine;
|
||||
private int dataSectionLine;
|
||||
/**
|
||||
* Whether or not the code segment is set
|
||||
*/
|
||||
private boolean codeSegmentSet = false;
|
||||
private boolean codeSectionSet = false;
|
||||
/**
|
||||
* Whether or not the data segment is set
|
||||
*/
|
||||
private boolean dataSegmentSet = false;
|
||||
private boolean dataSectionSet = false;
|
||||
|
||||
AssemblyResult(ServerConfiguration config) {
|
||||
origin = config.getInt("org_offset");
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a segment.
|
||||
* Define a section.
|
||||
*
|
||||
* @param segment Segment to define
|
||||
* @param currentOffset Current offset, in bytes of the segment
|
||||
* @param currentLine Line number of the segment declaration
|
||||
* @throws DuplicateSegmentException when a segment is defined twice
|
||||
* @param section Section to define
|
||||
* @param currentOffset Current offset, in bytes of the section
|
||||
* @param currentLine Line number of the section declaration
|
||||
* @throws DuplicateSectionException when a section is defined twice
|
||||
*/
|
||||
void defineSegment(Segment segment, int currentLine, int currentOffset) throws DuplicateSegmentException {
|
||||
void defineSecton(Section section, int currentLine, int currentOffset) throws DuplicateSectionException {
|
||||
|
||||
if (segment == Segment.TEXT) {
|
||||
//Code segment
|
||||
if (section == Section.TEXT) {
|
||||
//Code section
|
||||
|
||||
if (!codeSegmentSet) {
|
||||
codeSegmentOffset = origin + currentOffset;
|
||||
codeSegmentLine = currentLine;
|
||||
if (!codeSectionSet) {
|
||||
codeSectionOffset = origin + currentOffset;
|
||||
codeSectionLine = currentLine;
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: .text offset @" + codeSegmentOffset);
|
||||
LogManager.LOGGER.fine("DEBUG: .text offset @" + codeSectionOffset);
|
||||
|
||||
|
||||
codeSegmentSet = true;
|
||||
codeSectionSet = true;
|
||||
} else {
|
||||
throw new DuplicateSegmentException(currentLine);
|
||||
throw new DuplicateSectionException(currentLine);
|
||||
}
|
||||
|
||||
} else {
|
||||
//Data segment
|
||||
if (!dataSegmentSet) {
|
||||
dataSegmentOffset = origin + currentOffset;
|
||||
dataSegmentLine = currentLine;
|
||||
//Data section
|
||||
if (!dataSectionSet) {
|
||||
dataSectionOffset = origin + currentOffset;
|
||||
dataSectionLine = currentLine;
|
||||
|
||||
LogManager.LOGGER.fine("DEBUG: .data offset @" + dataSegmentOffset);
|
||||
LogManager.LOGGER.fine("DEBUG: .data offset @" + dataSectionOffset);
|
||||
|
||||
dataSegmentSet = true;
|
||||
dataSectionSet = true;
|
||||
} else {
|
||||
throw new DuplicateSegmentException(currentLine);
|
||||
throw new DuplicateSectionException(currentLine);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -114,9 +113,9 @@ public class AssemblyResult {
|
||||
return assembledCode;
|
||||
}
|
||||
|
||||
public int getCodeSegmentOffset() {
|
||||
if (codeSegmentSet) {
|
||||
return codeSegmentOffset;
|
||||
public int getCodeSectionOffset() {
|
||||
if (codeSectionSet) {
|
||||
return codeSectionOffset;
|
||||
} else {
|
||||
return origin;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.assembly.instruction.*;
|
||||
import net.simon987.server.event.CpuInitialisationEvent;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
@@ -20,7 +20,7 @@ import java.util.HashMap;
|
||||
* a Memory object and execute them. A CPU object holds registers objects &
|
||||
* a Memory object.
|
||||
*/
|
||||
public class CPU implements JSONSerialisable {
|
||||
public class CPU implements MongoSerialisable {
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -43,10 +43,10 @@ public class CPU implements JSONSerialisable {
|
||||
private RegisterSet registerSet;
|
||||
|
||||
/**
|
||||
* Offset of the code segment. The code starts to get
|
||||
* executed at this address each tick. Defaults to 0x4000
|
||||
* Offset of the code section. The code starts to get
|
||||
* executed at this address each tick. Defaults to org_offset@config.properties
|
||||
*/
|
||||
private int codeSegmentOffset;
|
||||
private int codeSectionOffset;
|
||||
|
||||
/**
|
||||
* Instruction pointer, always points to the next instruction
|
||||
@@ -73,7 +73,7 @@ public class CPU implements JSONSerialisable {
|
||||
instructionSet = new DefaultInstructionSet();
|
||||
registerSet = new DefaultRegisterSet();
|
||||
attachedHardware = new HashMap<>();
|
||||
codeSegmentOffset = config.getInt("org_offset");
|
||||
codeSectionOffset = config.getInt("org_offset");
|
||||
|
||||
instructionSet.add(new JmpInstruction(this));
|
||||
instructionSet.add(new JnzInstruction(this));
|
||||
@@ -97,6 +97,10 @@ public class CPU implements JSONSerialisable {
|
||||
instructionSet.add(new JncInstruction(this));
|
||||
instructionSet.add(new JnoInstruction(this));
|
||||
instructionSet.add(new JoInstruction(this));
|
||||
instructionSet.add(new PushfInstruction(this));
|
||||
instructionSet.add(new PopfInstruction(this));
|
||||
instructionSet.add(new JnaInstruction(this));
|
||||
instructionSet.add(new JaInstruction(this));
|
||||
|
||||
status = new Status();
|
||||
memory = new Memory(config.getInt("memory_size"));
|
||||
@@ -110,9 +114,7 @@ public class CPU implements JSONSerialisable {
|
||||
|
||||
public void reset() {
|
||||
status.clear();
|
||||
registerSet.getRegister("SP").setValue(config.getInt("stack_bottom"));
|
||||
registerSet.getRegister("BP").setValue(config.getInt("stack_bottom"));
|
||||
ip = codeSegmentOffset;
|
||||
ip = codeSectionOffset;
|
||||
}
|
||||
|
||||
public int execute(int timeout) {
|
||||
@@ -219,8 +221,7 @@ public class CPU implements JSONSerialisable {
|
||||
if (destination == 0) {
|
||||
//Single operand
|
||||
ip++;
|
||||
instruction.execute(sourceValue, status);
|
||||
instruction.execute(memory, memory.get(ip - 1), status); //For POP instruction
|
||||
instruction.execute(memory, memory.get(ip - 1), status);
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||
//Destination is an immediate value
|
||||
|
||||
@@ -238,7 +239,7 @@ public class CPU implements JSONSerialisable {
|
||||
} else if (destination <= registerSetSize * 2) {
|
||||
//Destination is [reg]
|
||||
ip++;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), memory, sourceValue, status);
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status);
|
||||
} else {
|
||||
//Assuming that destination is [reg + x]
|
||||
ip += 2;
|
||||
@@ -347,47 +348,47 @@ public class CPU implements JSONSerialisable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
dbObject.put("memory", memory.mongoSerialise());
|
||||
|
||||
json.put("memory", memory.serialise());
|
||||
dbObject.put("registerSet", registerSet.mongoSerialise());
|
||||
dbObject.put("codeSegmentOffset", codeSectionOffset);
|
||||
|
||||
json.put("registerSet", registerSet.serialise());
|
||||
json.put("codeSegmentOffset", codeSegmentOffset);
|
||||
|
||||
JSONArray hardwareList = new JSONArray();
|
||||
BasicDBList hardwareList = new BasicDBList();
|
||||
|
||||
for (Integer address : attachedHardware.keySet()) {
|
||||
|
||||
CpuHardware hardware = attachedHardware.get(address);
|
||||
|
||||
JSONObject serialisedHw = hardware.serialise();
|
||||
BasicDBObject serialisedHw = hardware.mongoSerialise();
|
||||
serialisedHw.put("address", address);
|
||||
hardwareList.add(serialisedHw);
|
||||
}
|
||||
|
||||
json.put("hardware", hardwareList);
|
||||
dbObject.put("hardware", hardwareList);
|
||||
|
||||
return dbObject;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static CPU deserialize(JSONObject json, User user) throws CancelledException {
|
||||
public static CPU deserialize(DBObject obj, User user) throws CancelledException {
|
||||
|
||||
CPU cpu = new CPU(GameServer.INSTANCE.getConfig(), user);
|
||||
|
||||
cpu.codeSegmentOffset = (int) (long) json.get("codeSegmentOffset");
|
||||
cpu.codeSectionOffset = (int) obj.get("codeSegmentOffset");
|
||||
|
||||
JSONArray hardwareList = (JSONArray) json.get("hardware");
|
||||
BasicDBList hardwareList = (BasicDBList) obj.get("hardware");
|
||||
|
||||
for (JSONObject serialisedHw : (ArrayList<JSONObject>) hardwareList) {
|
||||
CpuHardware hw = CpuHardware.deserialize(serialisedHw);
|
||||
hw.setCpu(cpu);
|
||||
cpu.attachHardware(hw, (int) (long) serialisedHw.get("address"));
|
||||
for (Object serialisedHw : hardwareList) {
|
||||
CpuHardware hardware = CpuHardware.deserialize((DBObject) serialisedHw);
|
||||
hardware.setCpu(cpu);
|
||||
cpu.attachHardware(hardware, (int) ((BasicDBObject) serialisedHw).get("address"));
|
||||
}
|
||||
|
||||
cpu.memory = Memory.deserialize((JSONObject) json.get("memory"));
|
||||
cpu.registerSet = RegisterSet.deserialize((JSONObject) json.get("registerSet"));
|
||||
cpu.memory = Memory.deserialize((DBObject) obj.get("memory"));
|
||||
cpu.registerSet = RegisterSet.deserialize((DBObject) obj.get("registerSet"));
|
||||
|
||||
return cpu;
|
||||
|
||||
@@ -417,8 +418,8 @@ public class CPU implements JSONSerialisable {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public void setCodeSegmentOffset(int codeSegmentOffset) {
|
||||
this.codeSegmentOffset = codeSegmentOffset;
|
||||
public void setCodeSectionOffset(int codeSectionOffset) {
|
||||
this.codeSectionOffset = codeSectionOffset;
|
||||
}
|
||||
|
||||
public void attachHardware(CpuHardware hardware, int address) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public abstract class CpuHardware implements JSONSerialisable {
|
||||
public abstract class CpuHardware implements MongoSerialisable {
|
||||
|
||||
CPU cpu;
|
||||
|
||||
@@ -26,12 +26,12 @@ public abstract class CpuHardware implements JSONSerialisable {
|
||||
|
||||
public abstract char getId();
|
||||
|
||||
public static CpuHardware deserialize(JSONObject hwJson) {
|
||||
public static CpuHardware deserialize(DBObject obj) {
|
||||
|
||||
for (ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()) {
|
||||
|
||||
if (plugin instanceof CpuHardwareDeserializer) {
|
||||
CpuHardware hw = ((CpuHardwareDeserializer) plugin).deserializeHardware(hwJson);
|
||||
CpuHardware hw = ((CpuHardwareDeserializer) plugin).deserializeHardware(obj);
|
||||
|
||||
if (hw != null) {
|
||||
return hw;
|
||||
|
||||
@@ -44,6 +44,8 @@ public class DefaultInstructionSet implements InstructionSet {
|
||||
add(new RclInstruction());
|
||||
add(new RcrInstruction());
|
||||
add(new SarInstruction());
|
||||
add(new IncInstruction());
|
||||
add(new DecInstruction());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -120,8 +120,8 @@ public abstract class Instruction {
|
||||
* Whether or not the instruction is valid without any
|
||||
* operands
|
||||
*/
|
||||
private static boolean noOperandsValid() {
|
||||
return true;
|
||||
public boolean noOperandsValid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
String getMnemonic() {
|
||||
|
||||
@@ -67,7 +67,6 @@ class MachineCode {
|
||||
LogManager.LOGGER.severe("Couldn't write the dst operand for instruction :" + dst);
|
||||
} else {
|
||||
|
||||
//Src is the 5 most significant bits
|
||||
value &= 0xF83F; //1111 1000 0011 1111
|
||||
dst <<= 6; //0000 0XXX XX00 0000
|
||||
value |= dst;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -20,7 +21,7 @@ import java.util.zip.InflaterOutputStream;
|
||||
/**
|
||||
* Represents the available memory for a CPU in the game universe
|
||||
*/
|
||||
public class Memory implements Target, JSONSerialisable {
|
||||
public class Memory implements Target, MongoSerialisable {
|
||||
|
||||
|
||||
/**
|
||||
@@ -105,35 +106,35 @@ public class Memory implements Target, JSONSerialisable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION, true);
|
||||
Deflater compressor = new Deflater(Deflater.BEST_SPEED, true);
|
||||
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(stream, compressor);
|
||||
deflaterOutputStream.write(getBytes());
|
||||
deflaterOutputStream.close();
|
||||
byte[] compressedBytes = stream.toByteArray();
|
||||
|
||||
json.put("zipBytes", new String(Base64.getEncoder().encode(compressedBytes)));
|
||||
dbObject.put("zipBytes", new String(Base64.getEncoder().encode(compressedBytes)));
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return json;
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static Memory deserialize(JSONObject json) {
|
||||
public static Memory deserialize(DBObject obj) {
|
||||
|
||||
Memory memory = new Memory(0);
|
||||
|
||||
String zipBytesStr = (String) json.get("zipBytes");
|
||||
String zipBytesStr = (String) obj.get("zipBytes");
|
||||
|
||||
if (zipBytesStr != null) {
|
||||
byte[] compressedBytes = Base64.getDecoder().decode((String) json.get("zipBytes"));
|
||||
byte[] compressedBytes = Base64.getDecoder().decode((String) obj.get("zipBytes"));
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
@@ -152,7 +153,6 @@ public class Memory implements Target, JSONSerialisable {
|
||||
memory = new Memory(GameServer.INSTANCE.getConfig().getInt("memory_size"));
|
||||
}
|
||||
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,18 @@ public class Operand {
|
||||
value = IMMEDIATE_VALUE;
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
//Try Binary number (format 0bXXXX)
|
||||
if (text.startsWith("0b")) {
|
||||
try {
|
||||
data = Integer.parseInt(text.substring(2), 2);
|
||||
value = IMMEDIATE_VALUE;
|
||||
return true;
|
||||
} catch (NumberFormatException e2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -212,11 +224,30 @@ public class Operand {
|
||||
}
|
||||
|
||||
//label is invalid
|
||||
|
||||
data = Integer.decode(expr);
|
||||
value += registerSet.size() * 2; //refers to memory with disp
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
//Integer.decode failed, try binary
|
||||
if (expr.startsWith("+0b")) {
|
||||
try {
|
||||
data = Integer.parseInt(expr.substring(3), 2);
|
||||
value += registerSet.size() * 2; //refers to memory with disp
|
||||
return true;
|
||||
} catch (NumberFormatException e2) {
|
||||
return false;
|
||||
}
|
||||
} else if (expr.startsWith("-0b")) {
|
||||
try {
|
||||
data = -Integer.parseInt(expr.substring(3), 2);
|
||||
value += registerSet.size() * 2; //refers to memory with disp
|
||||
return true;
|
||||
} catch (NumberFormatException e2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
@@ -12,7 +15,7 @@ import java.util.HashMap;
|
||||
/**
|
||||
* A set of registers for a CPU
|
||||
*/
|
||||
public class RegisterSet implements Target, JSONSerialisable {
|
||||
public class RegisterSet implements Target, MongoSerialisable {
|
||||
|
||||
/**
|
||||
* List of registers
|
||||
@@ -142,8 +145,8 @@ public class RegisterSet implements Target, JSONSerialisable {
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONArray registers = new JSONArray();
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBList registers = new BasicDBList();
|
||||
for (Integer index : this.registers.keySet()) {
|
||||
JSONObject register = new JSONObject();
|
||||
|
||||
@@ -154,10 +157,28 @@ public class RegisterSet implements Target, JSONSerialisable {
|
||||
registers.add(register);
|
||||
}
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("registers", registers);
|
||||
BasicDBObject obj = new BasicDBObject();
|
||||
obj.put("registers", registers);
|
||||
|
||||
return json;
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static RegisterSet deserialize(DBObject obj) {
|
||||
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
|
||||
BasicDBList registers = (BasicDBList) obj.get("registers");
|
||||
|
||||
for (Object sRegister : registers) {
|
||||
|
||||
Register register = new Register((String) ((DBObject) sRegister).get("name"));
|
||||
register.setValue((int) ((DBObject) sRegister).get("value"));
|
||||
|
||||
registerSet.registers.put((int) ((DBObject) sRegister).get("index"), register);
|
||||
|
||||
}
|
||||
|
||||
return registerSet;
|
||||
}
|
||||
|
||||
public static RegisterSet deserialize(JSONObject json) {
|
||||
|
||||
@@ -3,10 +3,9 @@ package net.simon987.server.assembly;
|
||||
/**
|
||||
* Section of a user-created program.
|
||||
* The execution will start at the beginning of the code
|
||||
* segment and a warning message will be displayed when execution
|
||||
* reached the data segment during debugging
|
||||
* segment.
|
||||
*/
|
||||
public enum Segment {
|
||||
public enum Section {
|
||||
|
||||
/**
|
||||
* Code section of the program. Contains executable code
|
||||
@@ -132,4 +132,20 @@ public class Status {
|
||||
public void setErrorFlag(boolean errorFlag) {
|
||||
this.errorFlag = errorFlag;
|
||||
}
|
||||
|
||||
public char toByte() {
|
||||
char stat = 0;
|
||||
stat = (char) (stat | ((signFlag ? 1 : 0) << 3));
|
||||
stat = (char) (stat | ((zeroFlag ? 1 : 0) << 2));
|
||||
stat = (char) (stat | ((carryFlag ? 1 : 0) << 1));
|
||||
stat = (char) (stat | (overflowFlag ? 1 : 0));
|
||||
return stat;
|
||||
}
|
||||
|
||||
public void fromByte(char stat) {
|
||||
setSignFlag((stat & (1 << 3)) != 0);
|
||||
setZeroFlag((stat & (1 << 2)) != 0);
|
||||
setCarryFlag((stat & (1 << 1)) != 0);
|
||||
setOverflowFlag((stat & 1) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class Util {
|
||||
}
|
||||
|
||||
public static String toHex(int a) {
|
||||
return String.format("%04X ", uShort(a));
|
||||
return String.format("%04X ", a);
|
||||
}
|
||||
|
||||
public static String toHex(byte[] byteArray) {
|
||||
|
||||
@@ -3,17 +3,17 @@ package net.simon987.server.assembly.exception;
|
||||
/**
|
||||
* Threw when a user attempts to define the same section twice
|
||||
*/
|
||||
public class DuplicateSegmentException extends AssemblyException {
|
||||
public class DuplicateSectionException extends AssemblyException {
|
||||
|
||||
/**
|
||||
* Message of the exception
|
||||
*/
|
||||
private static final String message = "Segments can only be defined once";
|
||||
private static final String message = "Sections can only be defined once";
|
||||
|
||||
/**
|
||||
* Create a new Duplicate Segment Exception
|
||||
* Create a new Duplicate Section Exception
|
||||
*/
|
||||
public DuplicateSegmentException(int line) {
|
||||
public DuplicateSectionException(int line) {
|
||||
super(message, line);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.simon987.server.assembly.exception;
|
||||
|
||||
/**
|
||||
* Class of exceptions that should stop assembly immediatly
|
||||
*/
|
||||
public class FatalAssemblyException extends AssemblyException {
|
||||
|
||||
/**
|
||||
* Message of the exception
|
||||
*/
|
||||
private static final String message = "A fatal assembly error has occurred";
|
||||
|
||||
/**
|
||||
* Create a new Duplicate Section Exception
|
||||
*/
|
||||
public FatalAssemblyException(String msg, int line) {
|
||||
super(msg, line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.simon987.server.assembly.exception;
|
||||
|
||||
/**
|
||||
* Threw when offset for stored instruction/data overflows the size of memory
|
||||
*/
|
||||
public class OffsetOverflowException extends FatalAssemblyException {
|
||||
|
||||
/**
|
||||
* Message of the exception
|
||||
*/
|
||||
private static final String message = "Program data exceeds memory size ";
|
||||
|
||||
/**
|
||||
* Create a new Offset Overflow Exception
|
||||
*/
|
||||
public OffsetOverflowException(int offset, int memsiz, int line) {
|
||||
super(message + offset + " > " + memsiz, line);
|
||||
}
|
||||
}
|
||||
@@ -20,4 +20,8 @@ public class BrkInstruction extends Instruction {
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
public boolean noOperandsValid() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class CmpInstruction extends Instruction {
|
||||
|
||||
status.setSignFlag(Util.checkSign16(result));
|
||||
status.setZeroFlag((char) result == 0);
|
||||
status.setOverflowFlag(Util.checkOverFlowAdd16(a, b));
|
||||
status.setOverflowFlag(Util.checkOverFlowSub16(a, b));
|
||||
status.setCarryFlag(Util.checkCarry16(result));
|
||||
|
||||
return status;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Target;
|
||||
import net.simon987.server.assembly.Util;
|
||||
|
||||
public class DecInstruction extends Instruction {
|
||||
|
||||
public static final int OPCODE = 0x2B;
|
||||
|
||||
public DecInstruction() {
|
||||
super("dec", OPCODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Target dst, int dstIndex, Status status) {
|
||||
char a = (char) dst.get(dstIndex);
|
||||
int result = a - 1;
|
||||
|
||||
// Like x86 Carry flag is preserved during INC/DEC
|
||||
// (Use ADD x, 1 to have carry flag change)
|
||||
// Other flags set according to result
|
||||
status.setSignFlag(Util.checkSign16(result));
|
||||
status.setZeroFlag((char) result == 0);
|
||||
status.setOverflowFlag(Util.checkOverFlowSub16(a, 1));
|
||||
|
||||
dst.set(dstIndex, result);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ public class DivInstruction extends Instruction {
|
||||
public Status execute(Target src, int srcIndex, Status status) {
|
||||
|
||||
//Source = Y:A
|
||||
int source = ((((char) cpu.getRegisterSet().getRegister("Y").getValue() & 0xFFFF) << 16)) |
|
||||
((char) cpu.getRegisterSet().getRegister("A").getValue() & 0xFFFF);
|
||||
int source = (((cpu.getRegisterSet().getRegister("Y").getValue() & 0xFFFF) << 16)) |
|
||||
(cpu.getRegisterSet().getRegister("A").getValue() & 0xFFFF);
|
||||
|
||||
if (src.get(srcIndex) == 0) {
|
||||
//Division by 0
|
||||
@@ -48,8 +48,8 @@ public class DivInstruction extends Instruction {
|
||||
|
||||
|
||||
//Source = Y:A
|
||||
int source = ((((char) cpu.getRegisterSet().getRegister("Y").getValue() & 0xFFFF) << 16)) |
|
||||
((char) cpu.getRegisterSet().getRegister("A").getValue() & 0xFFFF);
|
||||
int source = (((cpu.getRegisterSet().getRegister("Y").getValue() & 0xFFFF) << 16)) |
|
||||
(cpu.getRegisterSet().getRegister("A").getValue() & 0xFFFF);
|
||||
|
||||
if (src == 0) {
|
||||
//Division by 0
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Target;
|
||||
import net.simon987.server.assembly.Util;
|
||||
|
||||
public class IncInstruction extends Instruction {
|
||||
|
||||
public static final int OPCODE = 0x2A;
|
||||
|
||||
public IncInstruction() {
|
||||
super("inc", OPCODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Target dst, int dstIndex, Status status) {
|
||||
char a = (char) dst.get(dstIndex);
|
||||
int result = a + 1;
|
||||
|
||||
// Like x86 Carry flag is preserved during INC/DEC
|
||||
// (Use ADD x, 1 to have carry flag change)
|
||||
// Other flags set according to result
|
||||
status.setSignFlag(Util.checkSign16(result));
|
||||
status.setZeroFlag((char) result == 0);
|
||||
status.setOverflowFlag(Util.checkOverFlowAdd16(a, 1));
|
||||
|
||||
dst.set(dstIndex, result);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* Jump if above
|
||||
*/
|
||||
public class JaInstruction extends Instruction {
|
||||
|
||||
public static final int OPCODE = 46;
|
||||
|
||||
private CPU cpu;
|
||||
|
||||
public JaInstruction(CPU cpu) {
|
||||
super("ja", OPCODE);
|
||||
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Target src, int srcIndex, Status status) {
|
||||
if (!status.isCarryFlag() && !status.isZeroFlag()) {
|
||||
cpu.setIp((char) src.get(srcIndex));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(int src, Status status) {
|
||||
if (!status.isCarryFlag() && !status.isZeroFlag()) {
|
||||
cpu.setIp((char) src);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* Jump if not above
|
||||
*/
|
||||
public class JnaInstruction extends Instruction {
|
||||
|
||||
public static final int OPCODE = 47;
|
||||
|
||||
private CPU cpu;
|
||||
|
||||
public JnaInstruction(CPU cpu) {
|
||||
super("jna", OPCODE);
|
||||
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Target src, int srcIndex, Status status) {
|
||||
if (status.isCarryFlag() || status.isZeroFlag()) {
|
||||
cpu.setIp((char) src.get(srcIndex));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(int src, Status status) {
|
||||
if (status.isCarryFlag() || status.isZeroFlag()) {
|
||||
cpu.setIp((char) src);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,11 @@ public class MulInstruction extends Instruction {
|
||||
status.setOverflowFlag(true);
|
||||
status.setCarryFlag(true);
|
||||
cpu.getRegisterSet().getRegister("Y").setValue(hWord);//Don't overwrite Y register if it's blank
|
||||
} else {
|
||||
status.setOverflowFlag(false);
|
||||
status.setCarryFlag(false);
|
||||
}
|
||||
status.setOverflowFlag(false);
|
||||
status.setCarryFlag(false);
|
||||
|
||||
cpu.getRegisterSet().set(1, Util.getLowerWord(result));
|
||||
|
||||
return status;
|
||||
@@ -44,9 +46,11 @@ public class MulInstruction extends Instruction {
|
||||
status.setOverflowFlag(true);
|
||||
status.setCarryFlag(true);
|
||||
cpu.getRegisterSet().getRegister("Y").setValue(hWord);//Don't overwrite Y register if it's blank
|
||||
} else {
|
||||
status.setOverflowFlag(false);
|
||||
status.setCarryFlag(false);
|
||||
}
|
||||
status.setOverflowFlag(false);
|
||||
status.setCarryFlag(false);
|
||||
|
||||
cpu.getRegisterSet().getRegister("A").setValue(Util.getLowerWord(result));
|
||||
|
||||
return status;
|
||||
|
||||
@@ -14,7 +14,23 @@ public class NegInstruction extends Instruction {
|
||||
|
||||
@Override
|
||||
public Status execute(Target dst, int dstIndex, Status status) {
|
||||
dst.set(dstIndex, -dst.get(dstIndex));
|
||||
//If the operand is zero, the carry flag is cleared; in all other cases, the carry flag is set.
|
||||
|
||||
char destination = (char) dst.get(dstIndex);
|
||||
|
||||
if (destination == 0) {
|
||||
status.setCarryFlag(false);
|
||||
status.setZeroFlag(true);
|
||||
} else {
|
||||
status.setCarryFlag(true);
|
||||
}
|
||||
|
||||
//Attempting to negate a word containing -32,768 causes no change to the operand and sets the Overflow Flag.
|
||||
if (destination == 0x8000) {
|
||||
status.setOverflowFlag(true);
|
||||
} else {
|
||||
dst.set(dstIndex, -destination);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
import net.simon987.server.assembly.Register;
|
||||
import net.simon987.server.assembly.Status;
|
||||
|
||||
/**
|
||||
* Pops a single word off the top of the stack and sets the CPU flags to it.
|
||||
*/
|
||||
public class PopfInstruction extends Instruction {
|
||||
|
||||
/**
|
||||
* Opcode of the instruction
|
||||
*/
|
||||
public static final int OPCODE = 44;
|
||||
|
||||
private CPU cpu;
|
||||
|
||||
public PopfInstruction(CPU cpu) {
|
||||
super("popf", OPCODE);
|
||||
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Status status) {
|
||||
|
||||
Register sp = cpu.getRegisterSet().getRegister("SP");
|
||||
|
||||
// Get the word on the top of the stack
|
||||
char flags = (char) cpu.getMemory().get(sp.getValue());
|
||||
|
||||
// Overwrite the CPU flags
|
||||
status.fromByte(flags);
|
||||
|
||||
// Increment SP
|
||||
sp.setValue(sp.getValue() + 1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
public boolean noOperandsValid() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
import net.simon987.server.assembly.Register;
|
||||
import net.simon987.server.assembly.Status;
|
||||
|
||||
/**
|
||||
* Pushes the current CPU flags onto the stack.
|
||||
*/
|
||||
public class PushfInstruction extends Instruction {
|
||||
|
||||
/**
|
||||
* Opcode of the instruction
|
||||
*/
|
||||
public static final int OPCODE = 45;
|
||||
|
||||
private CPU cpu;
|
||||
|
||||
public PushfInstruction(CPU cpu) {
|
||||
super("pushf", OPCODE);
|
||||
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Status status) {
|
||||
|
||||
// Decrement SP
|
||||
Register sp = cpu.getRegisterSet().getRegister("SP");
|
||||
sp.setValue(sp.getValue() - 1);
|
||||
|
||||
// Push the current flags
|
||||
cpu.getMemory().set(sp.getValue(), status.toByte());
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
public boolean noOperandsValid() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,13 @@ public class RetInstruction extends Instruction {
|
||||
@Override
|
||||
public Status execute(int src, Status status) {
|
||||
cpu.setIp((char) cpu.getMemory().get(cpu.getRegisterSet().get(7))); //Jmp
|
||||
cpu.getRegisterSet().set(7, cpu.getRegisterSet().get(7) + src); //Inc SP
|
||||
cpu.getRegisterSet().set(7, cpu.getRegisterSet().get(7) + src + 1); //Inc SP
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean noOperandsValid() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class SubInstruction extends Instruction {
|
||||
|
||||
status.setSignFlag(Util.checkSign16(result));
|
||||
status.setZeroFlag((char) result == 0);
|
||||
status.setOverflowFlag(Util.checkOverFlowAdd16(a, b));
|
||||
status.setOverflowFlag(Util.checkOverFlowSub16(a, b));
|
||||
status.setCarryFlag(Util.checkCarry16(result));
|
||||
|
||||
dst.set(dstIndex, result);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.simon987.server.event;
|
||||
|
||||
/**
|
||||
* Event dispatched by a GameObject who has needed callbacks on death
|
||||
*/
|
||||
public class ObjectDeathEvent extends GameEvent {
|
||||
/**
|
||||
* The GameObject type ID of object that init this event
|
||||
*/
|
||||
private long sourceObjectId;
|
||||
|
||||
public ObjectDeathEvent(Object source, int sourceObjectId) {
|
||||
setSource(source);
|
||||
this.sourceObjectId = sourceObjectId;
|
||||
}
|
||||
|
||||
public long getSourceObjectId() {
|
||||
return sourceObjectId;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ public enum Action {
|
||||
DIGGING,
|
||||
WALKING,
|
||||
WITHDRAWING,
|
||||
DEPOSITING
|
||||
DEPOSITING,
|
||||
LISTENING
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
/**
|
||||
* Objects that can be attacked or healed
|
||||
*/
|
||||
public interface Attackable {
|
||||
|
||||
void setHealRate(int hp);
|
||||
|
||||
int getHp();
|
||||
void setHp(int hp);
|
||||
|
||||
int getMaxHp();
|
||||
void setMaxHp(int hp);
|
||||
|
||||
void heal(int amount);
|
||||
void damage(int amount);
|
||||
|
||||
}
|
||||
@@ -21,4 +21,15 @@ public interface ControllableUnit {
|
||||
|
||||
int getEnergy();
|
||||
|
||||
int getX();
|
||||
|
||||
int getY();
|
||||
|
||||
void setAction(Action listening);
|
||||
|
||||
World getWorld();
|
||||
|
||||
ArrayList<char[]> getConsoleMessagesBuffer();
|
||||
|
||||
int getConsoleMode();
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
/**
|
||||
* Types of GameEffects
|
||||
*/
|
||||
public enum EffectType {
|
||||
|
||||
/**
|
||||
* Warning icon
|
||||
*/
|
||||
WARNING,
|
||||
/**
|
||||
* Error icon
|
||||
*/
|
||||
ERROR,
|
||||
/**
|
||||
* Dig particle effect
|
||||
*/
|
||||
DIG,
|
||||
/**
|
||||
* 'A' Icon
|
||||
*/
|
||||
A_EMOTE
|
||||
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents a game effect in a World (e.g. Particles made when digging, Error animation, Attack effects etc..)
|
||||
* <br>
|
||||
* These effects are purely visual and could be changed or ignored by the client
|
||||
*/
|
||||
public class GameEffect implements JSONSerialisable {
|
||||
|
||||
|
||||
/**
|
||||
* Type of the effect
|
||||
*/
|
||||
private EffectType type;
|
||||
|
||||
private int x;
|
||||
|
||||
private int y;
|
||||
|
||||
public GameEffect(EffectType type, int x, int y) {
|
||||
this.type = type;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
json.put("x", x);
|
||||
json.put("y", y);
|
||||
json.put("type", type);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public EffectType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(EffectType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.io.GameObjectDeserializer;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
@@ -12,7 +14,7 @@ import java.awt.*;
|
||||
* An INSTANCE of an object (e.g. a Tree, a character ...) inside the
|
||||
* game universe
|
||||
*/
|
||||
public abstract class GameObject implements JSONSerialisable {
|
||||
public abstract class GameObject implements JSONSerialisable, MongoSerialisable {
|
||||
|
||||
private boolean dead;
|
||||
/**
|
||||
@@ -68,6 +70,7 @@ public abstract class GameObject implements JSONSerialisable {
|
||||
newY = y;
|
||||
}
|
||||
|
||||
|
||||
//Check if out of World bounds / collision
|
||||
if (newX < 0) {
|
||||
//Move object to adjacent World (left)
|
||||
@@ -75,15 +78,15 @@ public abstract class GameObject implements JSONSerialisable {
|
||||
if (world.getX() == 0) {
|
||||
//Warp around
|
||||
leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(
|
||||
GameServer.INSTANCE.getGameUniverse().getMaxWidth(), world.getY());
|
||||
GameServer.INSTANCE.getGameUniverse().getMaxWidth(), world.getY(), true);
|
||||
} else {
|
||||
leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() - 1, world.getY());
|
||||
leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() - 1, world.getY(), true);
|
||||
}
|
||||
|
||||
if (leftWorld != null) {
|
||||
world.getGameObjects().remove(this);
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
leftWorld.getGameObjects().add(this);
|
||||
leftWorld.addObject(this);
|
||||
leftWorld.incUpdatable();
|
||||
setWorld(leftWorld);
|
||||
|
||||
@@ -94,15 +97,15 @@ public abstract class GameObject implements JSONSerialisable {
|
||||
World rightWorld;
|
||||
if (world.getX() == GameServer.INSTANCE.getGameUniverse().getMaxWidth()) {
|
||||
//Warp around
|
||||
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(0, world.getY());
|
||||
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(0, world.getY(), true);
|
||||
} else {
|
||||
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() + 1, world.getY());
|
||||
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() + 1, world.getY(), true);
|
||||
}
|
||||
|
||||
if (rightWorld != null) {
|
||||
world.getGameObjects().remove(this);
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
rightWorld.getGameObjects().add(this);
|
||||
rightWorld.addObject(this);
|
||||
rightWorld.incUpdatable();
|
||||
setWorld(rightWorld);
|
||||
|
||||
@@ -114,15 +117,15 @@ public abstract class GameObject implements JSONSerialisable {
|
||||
if (world.getY() == 0) {
|
||||
//Warp around
|
||||
upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(),
|
||||
GameServer.INSTANCE.getGameUniverse().getMaxWidth());
|
||||
GameServer.INSTANCE.getGameUniverse().getMaxWidth(), true);
|
||||
} else {
|
||||
upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() - 1);
|
||||
upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() - 1, true);
|
||||
}
|
||||
|
||||
if (upWorld != null) {
|
||||
world.getGameObjects().remove(this);
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
upWorld.getGameObjects().add(this);
|
||||
upWorld.addObject(this);
|
||||
upWorld.incUpdatable();
|
||||
setWorld(upWorld);
|
||||
|
||||
@@ -133,16 +136,16 @@ public abstract class GameObject implements JSONSerialisable {
|
||||
World downWorld;
|
||||
if (world.getY() == GameServer.INSTANCE.getGameUniverse().getMaxWidth()) {
|
||||
//Warp around
|
||||
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), 0);
|
||||
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), 0, true);
|
||||
} else {
|
||||
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() + 1);
|
||||
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() + 1, true);
|
||||
}
|
||||
|
||||
|
||||
if (downWorld != null) {
|
||||
world.getGameObjects().remove(this);
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
downWorld.getGameObjects().add(this);
|
||||
downWorld.addObject(this);
|
||||
downWorld.incUpdatable();
|
||||
setWorld(downWorld);
|
||||
|
||||
@@ -223,12 +226,12 @@ public abstract class GameObject implements JSONSerialisable {
|
||||
return new JSONObject();
|
||||
}
|
||||
|
||||
public static GameObject deserialize(JSONObject objJson) {
|
||||
|
||||
public static GameObject deserialize(DBObject obj) {
|
||||
//
|
||||
for (ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()) {
|
||||
|
||||
if (plugin instanceof GameObjectDeserializer) {
|
||||
GameObject object = ((GameObjectDeserializer) plugin).deserializeObject(objJson);
|
||||
GameObject object = ((GameObjectDeserializer) plugin).deserializeObject(obj);
|
||||
|
||||
if (object != null) {
|
||||
return object;
|
||||
@@ -251,4 +254,9 @@ public abstract class GameObject implements JSONSerialisable {
|
||||
public void setDead(boolean dead) {
|
||||
this.dead = dead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before this GameObject is removed from the world - defaults to doing nothing
|
||||
*/
|
||||
public void onDeadCallback() { }
|
||||
}
|
||||
@@ -1,94 +1,175 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
import com.mongodb.*;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.Assembler;
|
||||
import net.simon987.server.assembly.AssemblyResult;
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class GameUniverse implements JSONSerialisable {
|
||||
public class GameUniverse {
|
||||
|
||||
private ArrayList<World> worlds;
|
||||
private ArrayList<User> users;
|
||||
//private ArrayList<World> worlds;
|
||||
private ConcurrentHashMap<String, World> worlds;
|
||||
//username:user
|
||||
private ConcurrentHashMap<String, User> users;
|
||||
private WorldGenerator worldGenerator;
|
||||
|
||||
private MongoClient mongo = null;
|
||||
|
||||
|
||||
private long time;
|
||||
|
||||
private int nextObjectId = 0;
|
||||
private long nextObjectId = 0;
|
||||
|
||||
private int maxWidth = 0xFFFF;
|
||||
|
||||
public GameUniverse(ServerConfiguration config) {
|
||||
|
||||
worlds = new ArrayList<>(32);
|
||||
users = new ArrayList<>(16);
|
||||
worlds = new ConcurrentHashMap<>(256);
|
||||
users = new ConcurrentHashMap<>(16);
|
||||
|
||||
worldGenerator = new WorldGenerator(config);
|
||||
}
|
||||
|
||||
public void setMongo(MongoClient mongo){
|
||||
this.mongo = mongo;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public World getWorld(int x, int y) {
|
||||
/**
|
||||
* Attempts loading a world from mongoDB by coordinates
|
||||
*
|
||||
* @param x the x coordinate of the world
|
||||
* @param y the y coordinate of the world
|
||||
*
|
||||
* @return World, null if not found
|
||||
*/
|
||||
private World loadWorld(int x, int y){
|
||||
|
||||
for (World world : worlds) {
|
||||
if (world.getX() == x && world.getY() == y) {
|
||||
return world;
|
||||
}
|
||||
DB db = mongo.getDB("mar");
|
||||
DBCollection worlds = db.getCollection("world");
|
||||
|
||||
BasicDBObject whereQuery = new BasicDBObject();
|
||||
whereQuery.put("_id", World.idFromCoordinates(x,y));
|
||||
DBCursor cursor = worlds.find(whereQuery);
|
||||
if (cursor.hasNext()) {
|
||||
World w = World.deserialize(cursor.next());
|
||||
return w;
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a world by coordinates, attempts to load from mongoDB if not found.
|
||||
*
|
||||
* @param x the x coordinate of the world
|
||||
* @param y the y coordinate of the world
|
||||
* @param createNew if true, a new world is created when a world with given coordinates is not found
|
||||
*
|
||||
* @return World, null if not found and not created.
|
||||
*/
|
||||
public World getWorld(int x, int y, boolean createNew) {
|
||||
|
||||
// Wrapping coordinates around cyclically
|
||||
x %= maxWidth+1;
|
||||
y %= maxWidth+1;
|
||||
|
||||
// Looks for a previously loaded world
|
||||
World world = getLoadedWorld(x,y);
|
||||
if (world != null){
|
||||
return world;
|
||||
}
|
||||
|
||||
if (x >= 0 && x <= maxWidth && y >= 0 && y <= maxWidth) {
|
||||
//World does not exist
|
||||
LogManager.LOGGER.severe("Trying to read a World that does not exist!");
|
||||
|
||||
World world = createWorld(x, y);
|
||||
|
||||
worlds.add(world);
|
||||
// Tries loading the world from the database
|
||||
world = loadWorld(x,y);
|
||||
if (world != null){
|
||||
addWorld(world);
|
||||
LogManager.LOGGER.fine("Loaded world "+(World.idFromCoordinates(x,y))+" from mongodb.");
|
||||
return world;
|
||||
}
|
||||
|
||||
// World does not exist
|
||||
if (createNew) {
|
||||
// Creates a new world
|
||||
world = createWorld(x, y);
|
||||
addWorld(world);
|
||||
LogManager.LOGGER.fine("Created new world "+(World.idFromCoordinates(x,y))+".");
|
||||
return world;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public World createWorld(int x, int y) {
|
||||
public World getLoadedWorld(int x, int y) {
|
||||
// Wrapping coordinates around cyclically
|
||||
x %= maxWidth+1;
|
||||
y %= maxWidth+1;
|
||||
|
||||
return worlds.get(World.idFromCoordinates(x,y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new or freshly loaded world to the universe (if not already present).
|
||||
*
|
||||
* @param world the world to be added
|
||||
*/
|
||||
public void addWorld(World world){
|
||||
World w = worlds.get(world.getId());
|
||||
if (w == null){
|
||||
world.setUniverse(this);
|
||||
worlds.put(world.getId(),world);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the world with given coordinates from the universe.
|
||||
*
|
||||
* @param x the x coordinate of the world to be removed
|
||||
* @param y the y coordinate of the world to be removed
|
||||
*/
|
||||
public void removeWorld(int x, int y){
|
||||
World w = worlds.remove(World.idFromCoordinates(x,y));
|
||||
if (w != null){
|
||||
w.setUniverse(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given world from the universe.
|
||||
*
|
||||
* @param world the world to be removed.
|
||||
*/
|
||||
public void removeWorld(World world){
|
||||
World w = worlds.remove(world.getId());
|
||||
if (w != null){
|
||||
w.setUniverse(null);
|
||||
}
|
||||
}
|
||||
|
||||
private World createWorld(int x, int y) {
|
||||
World world = null;
|
||||
try {
|
||||
world = worldGenerator.generateWorld(x, y);
|
||||
|
||||
|
||||
} catch (CancelledException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return world;
|
||||
}
|
||||
|
||||
public User getUser(String username) {
|
||||
|
||||
for (User user : users) {
|
||||
if (user.getUsername().equals(username)) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return users.get(username);
|
||||
}
|
||||
|
||||
public User getOrCreateUser(String username, boolean makeControlledUnit) {
|
||||
@@ -116,7 +197,7 @@ public class GameUniverse implements JSONSerialisable {
|
||||
char[] assembledCode = ar.getWords();
|
||||
|
||||
user.getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
|
||||
user.getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset());
|
||||
user.getCpu().setCodeSectionOffset(ar.getCodeSectionOffset());
|
||||
|
||||
|
||||
} else {
|
||||
@@ -125,7 +206,7 @@ public class GameUniverse implements JSONSerialisable {
|
||||
|
||||
user.setUsername(username);
|
||||
|
||||
users.add(user);
|
||||
addUser(user);
|
||||
|
||||
return user;
|
||||
|
||||
@@ -145,17 +226,17 @@ public class GameUniverse implements JSONSerialisable {
|
||||
* @param id id of the game object
|
||||
* @return GameObject, null if not found
|
||||
*/
|
||||
public GameObject getObject(int id) {
|
||||
public GameObject getObject(long id) {
|
||||
|
||||
//
|
||||
for (World world : worlds) {
|
||||
for (GameObject object : world.getGameObjects()) {
|
||||
if (object.getObjectId() == id) {
|
||||
return object;
|
||||
}
|
||||
for (World world : getWorlds()) {
|
||||
GameObject obj = world.findObject(id);
|
||||
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
LogManager.LOGGER.severe("Couldn't find object: " + id);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -164,81 +245,20 @@ public class GameUniverse implements JSONSerialisable {
|
||||
time++;
|
||||
}
|
||||
|
||||
public ArrayList<World> getWorlds() {
|
||||
return worlds;
|
||||
public Collection<World> getWorlds() {
|
||||
return worlds.values();
|
||||
}
|
||||
|
||||
public ArrayList<User> getUsers() {
|
||||
return users;
|
||||
public int getWorldCount() {
|
||||
return worlds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
JSONArray worlds = new JSONArray();
|
||||
|
||||
ArrayList<World> worlds_ = new ArrayList<>(this.worlds);
|
||||
for (World world : worlds_) {
|
||||
worlds.add(world.serialise());
|
||||
}
|
||||
|
||||
JSONArray users = new JSONArray();
|
||||
ArrayList<User> users_ = new ArrayList<User>(this.users);
|
||||
for (User user : users_) {
|
||||
if (!user.isGuest()) {
|
||||
users.add(user.serialise());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
json.put("users", users);
|
||||
json.put("worlds", worlds);
|
||||
json.put("time", time);
|
||||
json.put("nextObjectId", nextObjectId);
|
||||
|
||||
return json;
|
||||
public Collection<User> getUsers() {
|
||||
return users.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load game universe from JSON save file
|
||||
*
|
||||
* @param file JSON save file
|
||||
*/
|
||||
public void load(File file) {
|
||||
|
||||
JSONParser parser = new JSONParser();
|
||||
|
||||
if (file.isFile()) {
|
||||
try {
|
||||
|
||||
FileReader reader = new FileReader(file);
|
||||
JSONObject universeJson = (JSONObject) parser.parse(reader);
|
||||
|
||||
time = (long) universeJson.get("time");
|
||||
nextObjectId = (int) (long) universeJson.get("nextObjectId");
|
||||
|
||||
for (JSONObject worldJson : (ArrayList<JSONObject>) universeJson.get("worlds")) {
|
||||
worlds.add(World.deserialize(worldJson));
|
||||
}
|
||||
|
||||
for (JSONObject userJson : (ArrayList<JSONObject>) 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();
|
||||
}
|
||||
} else {
|
||||
LogManager.LOGGER.severe("Couldn't load save file save.json, creating empty game universe.");
|
||||
}
|
||||
|
||||
|
||||
public int getUserCount() {
|
||||
return users.size();
|
||||
}
|
||||
|
||||
public long getNextObjectId() {
|
||||
@@ -248,7 +268,7 @@ public class GameUniverse implements JSONSerialisable {
|
||||
public String getGuestUsername() {
|
||||
int i = 1;
|
||||
|
||||
while (i < 1000) { //todo get Max guest user cap from config
|
||||
while (i < 10000) { //todo get Max guest user cap from config
|
||||
if (getUser("guest" + String.valueOf(i)) != null) {
|
||||
i++;
|
||||
continue;
|
||||
@@ -261,12 +281,23 @@ public class GameUniverse implements JSONSerialisable {
|
||||
|
||||
}
|
||||
|
||||
public void removeUser(User user) {
|
||||
users.remove(user);
|
||||
public void addUser(User user) {
|
||||
users.put(user.getUsername(), user);
|
||||
}
|
||||
|
||||
public void removeUser(User user) {
|
||||
users.remove(user.getUsername());
|
||||
}
|
||||
|
||||
public int getMaxWidth() {
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public void setNextObjectId(long nextObjectId) {
|
||||
this.nextObjectId = nextObjectId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
public interface Programmable {
|
||||
|
||||
boolean sendMessage(char[] message);
|
||||
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.awt.*;
|
||||
@@ -17,7 +21,7 @@ import java.util.zip.InflaterOutputStream;
|
||||
/**
|
||||
* A 2D map of Tile objects of size width*height
|
||||
*/
|
||||
public class TileMap implements JSONSerialisable {
|
||||
public class TileMap implements JSONSerialisable, MongoSerialisable {
|
||||
|
||||
public static final int PLAIN_TILE = 0;
|
||||
public static final int WALL_TILE = 1;
|
||||
@@ -52,6 +56,13 @@ public class TileMap implements JSONSerialisable {
|
||||
tiles = new int[width][height];
|
||||
}
|
||||
|
||||
public TileMap(int[][] tiles) {
|
||||
this.width = World.WORLD_SIZE;
|
||||
this.height = World.WORLD_SIZE;
|
||||
|
||||
this.tiles = tiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the tile at a specified position
|
||||
* Sets the modified flag
|
||||
@@ -128,11 +139,37 @@ public class TileMap implements JSONSerialisable {
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("tiles", tiles);
|
||||
|
||||
return dbObject;
|
||||
|
||||
}
|
||||
|
||||
public static TileMap deserialize(DBObject object) {
|
||||
|
||||
BasicDBList terrain = (BasicDBList) object.get("tiles");
|
||||
|
||||
int[][] tiles = new int[World.WORLD_SIZE][World.WORLD_SIZE];
|
||||
|
||||
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
||||
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
||||
tiles[x][y] = (int) ((BasicDBList) terrain.get(x)).get(y);
|
||||
}
|
||||
}
|
||||
|
||||
return new TileMap(tiles);
|
||||
|
||||
}
|
||||
|
||||
public static TileMap deserialize(JSONObject object) {
|
||||
|
||||
TileMap tileMap = new TileMap(World.WORLD_SIZE, World.WORLD_SIZE);
|
||||
|
||||
|
||||
byte[] compressedBytes = Base64.getDecoder().decode((String) object.get("z"));
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.WorldUpdateEvent;
|
||||
import net.simon987.server.game.pathfinding.Pathfinder;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import org.json.simple.JSONArray;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class World implements JSONSerialisable {
|
||||
public class World implements MongoSerialisable {
|
||||
|
||||
/**
|
||||
* Size of the side of a world
|
||||
@@ -28,7 +32,7 @@ public class World implements JSONSerialisable {
|
||||
|
||||
private TileMap tileMap;
|
||||
|
||||
private ArrayList<GameObject> gameObjects = new ArrayList<>(16);
|
||||
private ConcurrentHashMap<Long, GameObject> gameObjects = new ConcurrentHashMap<>(8);
|
||||
|
||||
/**
|
||||
* If this number is greater than 0, the World will be updated.
|
||||
@@ -54,8 +58,29 @@ public class World implements JSONSerialisable {
|
||||
*/
|
||||
public boolean isTileBlocked(int x, int y) {
|
||||
|
||||
return getGameObjectsAt(x, y).size() > 0 || tileMap.getTileAt(x, y) == TileMap.WALL_TILE;
|
||||
return getGameObjectsBlockingAt(x, y).size() > 0 || tileMap.getTileAt(x, y) == TileMap.WALL_TILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the world's unique id from its coordinates.
|
||||
*
|
||||
* @param x the x coordinate of the world
|
||||
* @param y the y coordinate of the world
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public static String idFromCoordinates(int x, int y){
|
||||
return "w-"+"0x"+Integer.toHexString(x)+"-"+"0x"+Integer.toHexString(y);
|
||||
//return ((long)x)*(((long)maxWidth)+1)+((long)y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the world's unique id, computed with idFromCoordinates.
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public String getId(){
|
||||
return World.idFromCoordinates(x,y);
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
@@ -66,26 +91,48 @@ public class World implements JSONSerialisable {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the game objects that are instances of the specified class
|
||||
*/
|
||||
public ArrayList getGameObjects(Class<? extends GameObject> clazz) {
|
||||
public ArrayList<GameObject> findObjects(Class clazz) {
|
||||
|
||||
ArrayList<GameObject> objects = new ArrayList<>(gameObjects.size());
|
||||
ArrayList<GameObject> matchingObjects = new ArrayList<>(2);
|
||||
|
||||
for (GameObject object : gameObjects) {
|
||||
if (object.getClass().equals(clazz)) {
|
||||
objects.add(object);
|
||||
for (GameObject obj : gameObjects.values()) {
|
||||
|
||||
if (obj.getClass().equals(clazz)) {
|
||||
matchingObjects.add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return objects;
|
||||
return matchingObjects;
|
||||
}
|
||||
|
||||
public ArrayList<GameObject> getGameObjects() {
|
||||
return gameObjects;
|
||||
|
||||
public ArrayList<GameObject> findObjects(int mapInfo) {
|
||||
|
||||
ArrayList<GameObject> matchingObjects = new ArrayList<>(2);
|
||||
|
||||
for (GameObject obj : gameObjects.values()) {
|
||||
if ((obj.getMapInfo() & mapInfo) == mapInfo) {
|
||||
matchingObjects.add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return matchingObjects;
|
||||
}
|
||||
|
||||
public void addObject(GameObject object) {
|
||||
gameObjects.put(object.getObjectId(), object);
|
||||
}
|
||||
|
||||
public void removeObject(GameObject object) {
|
||||
gameObjects.remove(object.getObjectId());
|
||||
}
|
||||
|
||||
public GameObject findObject(long objectId) {
|
||||
return gameObjects.get(objectId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update this World and its GameObjects
|
||||
* <br>
|
||||
@@ -97,12 +144,11 @@ public class World implements JSONSerialisable {
|
||||
GameEvent event = new WorldUpdateEvent(this);
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event); //Ignore cancellation
|
||||
|
||||
ArrayList<GameObject> gameObjects_ = new ArrayList<>(gameObjects);
|
||||
|
||||
for (GameObject object : gameObjects_) {
|
||||
for (GameObject object : gameObjects.values()) {
|
||||
//Clean up dead objects
|
||||
if (object.isDead()) {
|
||||
gameObjects.remove(object);
|
||||
object.onDeadCallback();
|
||||
removeObject(object);
|
||||
//LogManager.LOGGER.fine("Removed object " + object + " id: " + object.getObjectId());
|
||||
} else if (object instanceof Updatable) {
|
||||
((Updatable) object).update();
|
||||
@@ -111,24 +157,28 @@ public class World implements JSONSerialisable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
JSONArray objects = new JSONArray();
|
||||
ArrayList<GameObject> gameObjects_ = new ArrayList<>(gameObjects);
|
||||
for (GameObject obj : gameObjects_) {
|
||||
objects.add(obj.serialise());
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
BasicDBList objects = new BasicDBList();
|
||||
for (GameObject obj : gameObjects.values()) {
|
||||
objects.add(obj.mongoSerialise());
|
||||
}
|
||||
json.put("o", objects);
|
||||
|
||||
json.put("t", tileMap.serialise());
|
||||
|
||||
json.put("x", x);
|
||||
json.put("y", y);
|
||||
dbObject.put("_id", getId());
|
||||
|
||||
json.put("u", updatable);
|
||||
dbObject.put("objects", objects);
|
||||
dbObject.put("terrain", tileMap.mongoSerialise());
|
||||
|
||||
return json;
|
||||
dbObject.put("x", x);
|
||||
dbObject.put("y", y);
|
||||
|
||||
dbObject.put("updatable", updatable);
|
||||
dbObject.put("shouldUpdate",shouldUpdate());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,21 +200,45 @@ public class World implements JSONSerialisable {
|
||||
|
||||
public static World deserialize(JSONObject json) {
|
||||
World world = new World();
|
||||
world.x = (int) (long) json.get("x");
|
||||
world.y = (int) (long) json.get("y");
|
||||
world.updatable = (int) (long) json.get("u");
|
||||
// world.x = (int) (long) json.get("x");
|
||||
// world.y = (int) (long) json.get("y");
|
||||
// world.updatable = (int) (long) json.get("u");
|
||||
//
|
||||
// world.tileMap = TileMap.deserialize((JSONObject) json.get("t"));
|
||||
//
|
||||
//
|
||||
// for (JSONObject objJson : (ArrayList<JSONObject>) json.get("o")) {
|
||||
//
|
||||
// GameObject object = GameObject.deserialize(objJson);
|
||||
//
|
||||
// object.setWorld(world);
|
||||
// world.gameObjects.add(object);
|
||||
// }
|
||||
|
||||
world.tileMap = TileMap.deserialize((JSONObject) json.get("t"));
|
||||
return world;
|
||||
}
|
||||
|
||||
for (JSONObject objJson : (ArrayList<JSONObject>) json.get("o")) {
|
||||
public static World deserialize(DBObject dbObject) {
|
||||
|
||||
GameObject object = GameObject.deserialize(objJson);
|
||||
World world = new World();
|
||||
world.x = (int) dbObject.get("x");
|
||||
world.y = (int) dbObject.get("y");
|
||||
world.updatable = (int) dbObject.get("updatable");
|
||||
|
||||
world.tileMap = TileMap.deserialize((BasicDBObject) dbObject.get("terrain"));
|
||||
|
||||
BasicDBList objects = (BasicDBList) dbObject.get("objects");
|
||||
|
||||
for (Object obj : objects) {
|
||||
|
||||
GameObject object = GameObject.deserialize((DBObject) obj);
|
||||
|
||||
object.setWorld(world);
|
||||
world.gameObjects.add(object);
|
||||
world.addObject(object);
|
||||
}
|
||||
|
||||
return world;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,7 +273,7 @@ public class World implements JSONSerialisable {
|
||||
}
|
||||
|
||||
//Objects
|
||||
for (GameObject obj : this.gameObjects) {
|
||||
for (GameObject obj : gameObjects.values()) {
|
||||
mapInfo[obj.getX()][obj.getY()] |= obj.getMapInfo();
|
||||
|
||||
}
|
||||
@@ -245,25 +319,46 @@ public class World implements JSONSerialisable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of game objects at a location
|
||||
* Get the list of game objects that are blocking a tile at a set of coordinates
|
||||
*
|
||||
* @param x X coordinate on the World
|
||||
* @param y Y coordinate on the World
|
||||
* @return the list of game objects blocking a location
|
||||
*/
|
||||
public ArrayList<GameObject> getGameObjectsBlockingAt(int x, int y) {
|
||||
|
||||
ArrayList<GameObject> objectsLooking = new ArrayList<>(2);
|
||||
for (GameObject obj : gameObjects.values()) {
|
||||
|
||||
if (obj.isAt(x, y)) {
|
||||
objectsLooking.add(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return objectsLooking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of game objects that are exactly at a given location
|
||||
* <br>
|
||||
* Note: Objects like the Factory that are more than 1x1 tiles wide will only be returned
|
||||
* when their exact coordinates are specified
|
||||
*
|
||||
* @param x X coordinate on the World
|
||||
* @param y Y coordinate on the World
|
||||
* @return the list of game objects at a location
|
||||
*/
|
||||
public ArrayList<GameObject> getGameObjectsAt(int x, int y) {
|
||||
|
||||
ArrayList<GameObject> gameObjects = new ArrayList<>(2);
|
||||
|
||||
for (GameObject obj : this.gameObjects) {
|
||||
ArrayList<GameObject> objectsAt = new ArrayList<>(2);
|
||||
for (GameObject obj : gameObjects.values()) {
|
||||
|
||||
if (obj.isAt(x, y)) {
|
||||
gameObjects.add(obj);
|
||||
objectsAt.add(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return gameObjects;
|
||||
return objectsAt;
|
||||
}
|
||||
|
||||
public void incUpdatable() {
|
||||
@@ -277,4 +372,76 @@ public class World implements JSONSerialisable {
|
||||
public boolean shouldUpdate() {
|
||||
return updatable > 0;
|
||||
}
|
||||
|
||||
|
||||
private GameUniverse universe = null;
|
||||
|
||||
public void setUniverse(GameUniverse universe){
|
||||
this.universe = universe;
|
||||
}
|
||||
|
||||
public ArrayList<World> getNeighbouringLoadedWorlds(){
|
||||
ArrayList<World> neighbouringWorlds = new ArrayList<>();
|
||||
|
||||
if (universe == null){
|
||||
return neighbouringWorlds;
|
||||
}
|
||||
|
||||
for (int dx=-1; dx<=+1; dx+=2){
|
||||
World nw = universe.getLoadedWorld(x+dx,y);
|
||||
if (nw != null){
|
||||
neighbouringWorlds.add(nw);
|
||||
}
|
||||
}
|
||||
for (int dy=-1; dy<=+1; dy+=2){
|
||||
World nw = universe.getLoadedWorld(x,y+dy);
|
||||
if (nw != null){
|
||||
neighbouringWorlds.add(nw);
|
||||
}
|
||||
}
|
||||
|
||||
return neighbouringWorlds;
|
||||
}
|
||||
|
||||
public ArrayList<World> getNeighbouringExistingWorlds(){
|
||||
ArrayList<World> neighbouringWorlds = new ArrayList<>();
|
||||
|
||||
if (universe == null){
|
||||
return neighbouringWorlds;
|
||||
}
|
||||
|
||||
for (int dx=-1; dx<=+1; dx+=2){
|
||||
World nw = universe.getWorld(x+dx,y,false);
|
||||
if (nw != null){
|
||||
neighbouringWorlds.add(nw);
|
||||
}
|
||||
}
|
||||
for (int dy=-1; dy<=+1; dy+=2){
|
||||
World nw = universe.getWorld(x,y+dy,false);
|
||||
if (nw != null){
|
||||
neighbouringWorlds.add(nw);
|
||||
}
|
||||
}
|
||||
|
||||
return neighbouringWorlds;
|
||||
}
|
||||
|
||||
|
||||
public boolean canUnload(){
|
||||
return updatable==0;
|
||||
}
|
||||
|
||||
public boolean shouldUnload(){
|
||||
boolean res = canUnload();
|
||||
|
||||
for (World nw : getNeighbouringLoadedWorlds() ){
|
||||
res &= nw.canUnload();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public Collection<GameObject> getGameObjects() {
|
||||
return gameObjects.values();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.WorldGenerationEvent;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.HashMap;
|
||||
@@ -93,7 +92,6 @@ public class WorldGenerator {
|
||||
* Create a randomly generated World
|
||||
*/
|
||||
public World generateWorld(int locX, int locY) throws CancelledException {
|
||||
LogManager.LOGGER.info("Generating random world");
|
||||
Random random = new Random();
|
||||
|
||||
World world = generateEmptyWorld(locX, locY);
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Class to compute paths in the game universe. It supports
|
||||
* paths between within the same World.
|
||||
* paths within the same World.
|
||||
*/
|
||||
public class Pathfinder {
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface CpuHardwareDeserializer {
|
||||
|
||||
|
||||
CpuHardware deserializeHardware(JSONObject hwJson);
|
||||
CpuHardware deserializeHardware(DBObject hwJson);
|
||||
}
|
||||
|
||||
@@ -1,186 +1,22 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
private static final int BUFFER_SIZE = 1024;
|
||||
private static final String STR_ENCODING = "UTF-8";
|
||||
private static final String DATE_FORMAT = "yyyyMMddHHmmss";
|
||||
private static final String FILE_TYPE = ".zip";
|
||||
private static final Path ROOT_DIR;
|
||||
private static final String DIR_NAME = "history";
|
||||
public static final Path DIR_PATH;
|
||||
|
||||
static {
|
||||
ROOT_DIR = Paths.get(".").normalize();
|
||||
DIR_PATH = ROOT_DIR.resolve(DIR_NAME);
|
||||
}
|
||||
|
||||
//Private constructor
|
||||
private FileUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new stamp containing the current date and time
|
||||
*
|
||||
* @return date and time stamp
|
||||
*/
|
||||
private static String getDateTimeStamp() {
|
||||
Date millisToDate = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat f = new SimpleDateFormat(DATE_FORMAT);
|
||||
return f.format(millisToDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Created a directory if none exists with the specified name
|
||||
*
|
||||
* @param directory folder to create
|
||||
* @return true is the file exists or create operation is successful
|
||||
*/
|
||||
public static boolean prepDirectory(Path directory) {
|
||||
File file = directory.toFile();
|
||||
|
||||
//If the directory exists or the directory created successfully return true
|
||||
if(file.exists() || file.mkdir()) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
System.out.println("Error creating directory: " + file.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a file into an array of bytes
|
||||
*
|
||||
* @param path the file to be converted into bytes
|
||||
* @return the byte array of the given file
|
||||
*/
|
||||
public static byte[] bytifyFile(Path path) {
|
||||
byte[] bytes = null;
|
||||
|
||||
try {
|
||||
bytes = Files.readAllBytes(path);
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println("Failed to extract bytes from: " + path);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes in a file that had been converted to a byte[] to be written to a new
|
||||
* zip file
|
||||
*
|
||||
* @param data
|
||||
* contains data in byte array form to be written, typically a file
|
||||
* that has been converted with bytifyFile()
|
||||
* @throws IOException
|
||||
* if an error occurs during the write process
|
||||
*/
|
||||
public static void writeSaveToZip(String name, byte[] data) throws IOException {
|
||||
|
||||
String newFile = DIR_PATH.resolve(getDateTimeStamp() + FILE_TYPE).toString();
|
||||
FileOutputStream output = new FileOutputStream(newFile);
|
||||
ZipOutputStream stream = new ZipOutputStream(output);
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
|
||||
|
||||
while ((bais.read(buffer)) > -1) {
|
||||
// File name
|
||||
ZipEntry entry = new ZipEntry(name);
|
||||
// Set to start of next entry in the stream.
|
||||
stream.putNextEntry(entry);
|
||||
// Data to write.
|
||||
stream.write(data);
|
||||
// Close the current entry.
|
||||
stream.closeEntry();
|
||||
}
|
||||
|
||||
stream.close();
|
||||
output.close();
|
||||
}
|
||||
|
||||
public static void cleanHistory(int size) {
|
||||
private static final String DATE_FORMAT = "yyyyMMddHHmmss";
|
||||
|
||||
|
||||
File[] files = new File(DIR_PATH.toString()).listFiles();
|
||||
File[] sorted = new File[size];
|
||||
/**
|
||||
* Creates a new stamp containing the current date and time
|
||||
*
|
||||
* @return date and time stamp
|
||||
*/
|
||||
private static String getDateTimeStamp() {
|
||||
Date millisToDate = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat f = new SimpleDateFormat(DATE_FORMAT);
|
||||
return f.format(millisToDate);
|
||||
}
|
||||
|
||||
File nextSortedFile = null;
|
||||
File currentFile = null;
|
||||
boolean changed = false;
|
||||
|
||||
for(int i = 0; i < files.length / 2; i++) {
|
||||
currentFile = files[i];
|
||||
files[i] = files[files.length - i - 1];
|
||||
files[files.length - i - 1] = currentFile;
|
||||
}
|
||||
|
||||
currentFile = null;
|
||||
|
||||
for(int f = 0; f < files.length; f++) {
|
||||
changed = false;
|
||||
long dirFile = Long.parseLong(files[f].getName().substring(0, (files[f].getName().length() -4)));
|
||||
|
||||
if(f < size && sorted[f] == null) {
|
||||
sorted[f] = files[f];
|
||||
|
||||
} else {
|
||||
|
||||
for(int s = 0; s < sorted.length; s++) {
|
||||
|
||||
long sortedFile = Long.parseLong(sorted[s].getName().substring(0, (sorted[s].getName().length() -4)));
|
||||
|
||||
if(dirFile > sortedFile) {
|
||||
|
||||
if(s == sorted.length - 1) {
|
||||
sorted[s] = files[f];
|
||||
|
||||
} else if(nextSortedFile == null) {
|
||||
nextSortedFile = sorted[s];
|
||||
sorted[s] = files[f];
|
||||
|
||||
} else {
|
||||
currentFile = sorted[s];
|
||||
sorted[s] = nextSortedFile;
|
||||
nextSortedFile = currentFile;
|
||||
}
|
||||
|
||||
nextSortedFile = null;
|
||||
currentFile = null;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(changed == false) {
|
||||
files[f].delete();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array into human readable format using the provided encoding
|
||||
*
|
||||
* @param bytes
|
||||
* data to be encoded to String
|
||||
* @return a String containing the encoded bytes
|
||||
*/
|
||||
public static String byteArrAsString(byte[] bytes) throws UnsupportedEncodingException {
|
||||
return new String(bytes, STR_ENCODING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface GameObjectDeserializer {
|
||||
|
||||
GameObject deserializeObject(JSONObject object);
|
||||
GameObject deserializeObject(DBObject object);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
|
||||
public interface MongoSerialisable {
|
||||
|
||||
BasicDBObject mongoSerialise();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package net.simon987.server.logging;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.*;
|
||||
|
||||
@@ -16,26 +18,50 @@ public class LogManager {
|
||||
/**
|
||||
* Initialises the logger
|
||||
*/
|
||||
public static void initialize() {
|
||||
public static void initialize(ServerConfiguration config) {
|
||||
LOGGER.setUseParentHandlers(false);
|
||||
|
||||
Handler handler = new ConsoleHandler();
|
||||
/*
|
||||
* Having warning/error directed to stderr
|
||||
*/
|
||||
Handler errHandler = new ConsoleHandler();
|
||||
errHandler.setFormatter(new GenericFormatter());
|
||||
errHandler.setLevel(Level.WARNING);
|
||||
|
||||
/*
|
||||
* Only have info and below directed to stdout
|
||||
*/
|
||||
Handler handler = new StreamHandler(System.out, new GenericFormatter()) {
|
||||
@Override
|
||||
public synchronized void publish(LogRecord record) {
|
||||
super.publish(record);
|
||||
flush();
|
||||
}
|
||||
};
|
||||
handler.setFilter(new Filter() {
|
||||
@Override
|
||||
public boolean isLoggable(LogRecord record) {
|
||||
return record.getLevel().intValue() <= Level.INFO.intValue();
|
||||
}
|
||||
});
|
||||
handler.setLevel(Level.ALL);
|
||||
handler.setFormatter(new GenericFormatter());
|
||||
|
||||
try {
|
||||
Handler fileHandler = new FileHandler("mar.log");
|
||||
Handler fileHandler = new FileHandler("mar-%g.log", config.getInt("log_limit"),
|
||||
config.getInt("log_count"));
|
||||
fileHandler.setLevel(Level.ALL);
|
||||
fileHandler.setFormatter(new GenericFormatter());
|
||||
|
||||
|
||||
LOGGER.addHandler(handler);
|
||||
LOGGER.addHandler(errHandler);
|
||||
LOGGER.addHandler(fileHandler);
|
||||
LOGGER.setLevel(Level.ALL);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
package net.simon987.server.user;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.UserCreationEvent;
|
||||
import net.simon987.server.game.ControllableUnit;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
|
||||
/**
|
||||
* Represents a User (or player) of the game
|
||||
*/
|
||||
public class User implements JSONSerialisable {
|
||||
public class User implements MongoSerialisable {
|
||||
|
||||
private String username;
|
||||
|
||||
@@ -39,33 +40,32 @@ public class User implements JSONSerialisable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
json.put("username", username);
|
||||
json.put("code", userCode);
|
||||
json.put("controlledUnit", controlledUnit.getObjectId());
|
||||
json.put("cpu", cpu.serialise());
|
||||
|
||||
return json;
|
||||
dbObject.put("_id", username); // a constant id ensures only one entry per user is kept and updated, instead of a new entry created every save for every user.
|
||||
dbObject.put("username", username);
|
||||
dbObject.put("code", userCode);
|
||||
dbObject.put("controlledUnit", controlledUnit.getObjectId());
|
||||
dbObject.put("cpu", cpu.mongoSerialise());
|
||||
|
||||
return dbObject;
|
||||
|
||||
}
|
||||
|
||||
public static User deserialize(JSONObject userJson) throws CancelledException {
|
||||
public static User deserialize(DBObject obj) throws CancelledException {
|
||||
|
||||
User user = new User((ControllableUnit) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) userJson.get("controlledUnit")));
|
||||
user.username = (String) userJson.get("username");
|
||||
user.userCode = (String) userJson.get("code");
|
||||
User user = new User((ControllableUnit) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("controlledUnit")));
|
||||
user.username = (String) obj.get("username");
|
||||
user.userCode = (String) obj.get("code");
|
||||
|
||||
user.getControlledUnit().setParent(user);
|
||||
|
||||
user.cpu = CPU.deserialize((JSONObject) userJson.get("cpu"), user);
|
||||
user.cpu = CPU.deserialize((DBObject) obj.get("cpu"), user);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
//----
|
||||
|
||||
public String getUserCode() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user