mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-12-14 07:09:04 +00:00
Compare commits
150 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 | ||
|
|
2e9248ea2e | ||
|
|
4f1342593f | ||
|
|
3548928218 | ||
|
|
cd41db9e58 | ||
|
|
597118bd07 | ||
|
|
9dd9b45d2d | ||
|
|
9597a80edf | ||
|
|
d24363fd82 | ||
|
|
be45979ed0 | ||
|
|
29cac77e79 | ||
|
|
6be2a496c6 | ||
|
|
12db25e726 | ||
|
|
d004386b7b | ||
|
|
e09d2c1b16 | ||
|
|
c703dec3cf |
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"]
|
||||||
25
Plugin Cubot/Plugin Cubot.iml
Normal file
25
Plugin Cubot/Plugin Cubot.iml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<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="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<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" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
34
Plugin Cubot/pom.xml
Normal file
34
Plugin Cubot/pom.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
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>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.simon987.server</groupId>
|
||||||
|
<artifactId>server</artifactId>
|
||||||
|
<version>1.2a</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
308
Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java
Normal file
308
Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
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.*;
|
||||||
|
import net.simon987.server.user.User;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Cubot extends GameObject implements Updatable, ControllableUnit, Programmable {
|
||||||
|
|
||||||
|
private static final char MAP_INFO = 0x0080;
|
||||||
|
public static final int ID = 1;
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
private int hp;
|
||||||
|
private int heldItem;
|
||||||
|
|
||||||
|
private Action currentAction = Action.IDLE;
|
||||||
|
private Action lastAction = Action.IDLE;
|
||||||
|
|
||||||
|
private ArrayList<Integer> keyboardBuffer = new ArrayList<>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
private int energy;
|
||||||
|
private int maxEnergy;
|
||||||
|
|
||||||
|
private static final float SOLAR_PANEL_MULTIPLIER = 1;
|
||||||
|
private static final int CONSOLE_BUFFER_MAX_SIZE = 40;
|
||||||
|
|
||||||
|
public Cubot() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char getMapInfo() {
|
||||||
|
return MAP_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
|
||||||
|
storeEnergy((int) (SOLAR_PANEL_MULTIPLIER * GameServer.INSTANCE.getDayNightCycle().getSunIntensity()));
|
||||||
|
|
||||||
|
if (currentAction == Action.WALKING) {
|
||||||
|
if (spendEnergy(100)) {
|
||||||
|
if (!incrementLocation()) {
|
||||||
|
//Couldn't walk
|
||||||
|
currentAction = Action.IDLE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentAction = Action.IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CurrentAction is set during the code execution and this function is called right after
|
||||||
|
* If no action as been set, the action sent to the client is the action in currentAction that
|
||||||
|
* was set last tick (IDLE)
|
||||||
|
*/
|
||||||
|
lastAction = currentAction;
|
||||||
|
currentAction = Action.IDLE;
|
||||||
|
|
||||||
|
//Same principle for hologram
|
||||||
|
lastHologramMode = hologramMode;
|
||||||
|
hologramMode = HologramMode.CLEARED;
|
||||||
|
|
||||||
|
//And the console
|
||||||
|
lastConsoleMode = consoleMode;
|
||||||
|
consoleMode = ConsoleMode.NORMAL;
|
||||||
|
|
||||||
|
lastConsoleMessagesBuffer = new ArrayList<>(consoleMessagesBuffer);
|
||||||
|
consoleMessagesBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject serialise() {
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("i", getObjectId());
|
||||||
|
json.put("t", ID);
|
||||||
|
json.put("x", getX());
|
||||||
|
json.put("y", getY());
|
||||||
|
json.put("direction", getDirection().ordinal());
|
||||||
|
json.put("heldItem", heldItem);
|
||||||
|
json.put("hp", hp);
|
||||||
|
json.put("action", lastAction.ordinal());
|
||||||
|
json.put("holo", hologram);
|
||||||
|
json.put("holoStr", hologramString);
|
||||||
|
json.put("holoMode", lastHologramMode.ordinal());
|
||||||
|
json.put("holoC", hologramColor);
|
||||||
|
json.put("energy", energy);
|
||||||
|
|
||||||
|
if (parent != null) {
|
||||||
|
json.put("parent", parent.getUsername()); //Only used client-side for now
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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) 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeldItem(int heldItem) {
|
||||||
|
this.heldItem = heldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeldItem() {
|
||||||
|
return heldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setKeyboardBuffer(ArrayList<Integer> kbBuffer) {
|
||||||
|
keyboardBuffer = kbBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayList<Integer> getKeyboardBuffer() {
|
||||||
|
return keyboardBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearKeyboardBuffer() {
|
||||||
|
keyboardBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentAction(Action currentAction) {
|
||||||
|
this.currentAction = currentAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(User parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action getAction() {
|
||||||
|
return lastAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action getCurrentAction() {
|
||||||
|
return currentAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHologram(int hologram) {
|
||||||
|
this.hologram = hologram;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setHologramString(String hologramString) {
|
||||||
|
this.hologramString = hologramString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEnergy() {
|
||||||
|
return energy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnergy(int energy) {
|
||||||
|
this.energy = energy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean spendEnergy(int spent) {
|
||||||
|
|
||||||
|
if (energy - spent < 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
energy -= spent;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void storeEnergy(int qty) {
|
||||||
|
|
||||||
|
energy = Math.min(energy + qty, maxEnergy);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxEnergy(int maxEnergy) {
|
||||||
|
this.maxEnergy = maxEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxEnergy() {
|
||||||
|
return maxEnergy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Memory getFloppyData() {
|
||||||
|
|
||||||
|
CubotFloppyDrive drive = ((CubotFloppyDrive) getParent().getCpu().getHardware(CubotFloppyDrive.DEFAULT_ADDRESS));
|
||||||
|
|
||||||
|
if (drive.getFloppy() != null) {
|
||||||
|
return drive.getFloppy().getMemory();
|
||||||
|
} else {
|
||||||
|
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;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class CubotBattery extends CpuHardware {
|
public class CubotBattery extends CpuHardware {
|
||||||
|
|
||||||
@@ -15,8 +16,8 @@ public class CubotBattery extends CpuHardware {
|
|||||||
public static final char HWID = 0x000A;
|
public static final char HWID = 0x000A;
|
||||||
|
|
||||||
private Cubot cubot;
|
private Cubot cubot;
|
||||||
private static final int POLL = 1;
|
private static final int BATTERY_POLL = 1;
|
||||||
private static final int GET_MAX_CAPACITY = 2;
|
private static final int BATTERY_GET_MAX_CAPACITY = 2;
|
||||||
|
|
||||||
public CubotBattery(Cubot cubot) {
|
public CubotBattery(Cubot cubot) {
|
||||||
this.cubot = cubot;
|
this.cubot = cubot;
|
||||||
@@ -27,10 +28,10 @@ public class CubotBattery extends CpuHardware {
|
|||||||
|
|
||||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||||
|
|
||||||
if (a == POLL) {
|
if (a == BATTERY_POLL) {
|
||||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getEnergy());
|
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());
|
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getMaxEnergy());
|
||||||
} else if (a == 0xFFFF) {
|
} else if (a == 0xFFFF) {
|
||||||
cubot.setEnergy(cubot.getMaxEnergy());
|
cubot.setEnergy(cubot.getMaxEnergy());
|
||||||
@@ -44,16 +45,19 @@ public class CubotBattery extends CpuHardware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
|
||||||
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,10 +1,12 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
|
import net.simon987.server.game.Action;
|
||||||
import net.simon987.server.game.TileMap;
|
import net.simon987.server.game.TileMap;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class CubotDrill extends CpuHardware {
|
public class CubotDrill extends CpuHardware {
|
||||||
|
|
||||||
@@ -15,9 +17,8 @@ public class CubotDrill extends CpuHardware {
|
|||||||
|
|
||||||
public static final int DEFAULT_ADDRESS = 5;
|
public static final int DEFAULT_ADDRESS = 5;
|
||||||
|
|
||||||
private static final int POLL = 1;
|
private static final int DRILL_POLL = 1;
|
||||||
private static final int GATHER_SLOW = 2;
|
private static final int DRILL_GATHER = 2; // simplified gather
|
||||||
private static final int GATHER_FAST = 3;
|
|
||||||
|
|
||||||
private Cubot cubot;
|
private Cubot cubot;
|
||||||
|
|
||||||
@@ -34,23 +35,23 @@ public class CubotDrill extends CpuHardware {
|
|||||||
public void handleInterrupt(Status status) {
|
public void handleInterrupt(Status status) {
|
||||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||||
|
|
||||||
if (a == POLL) {
|
if (a == DRILL_POLL) {
|
||||||
|
|
||||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
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.spendEnergy(1400)) {
|
||||||
if (cubot.getAction() == CubotAction.IDLE) {
|
if (cubot.getCurrentAction() == Action.IDLE) {
|
||||||
int tile = cubot.getWorld().getTileMap().getTileAt(cubot.getX(), cubot.getY());
|
int tile = cubot.getWorld().getTileMap().getTileAt(cubot.getX(), cubot.getY());
|
||||||
|
|
||||||
if (tile == TileMap.IRON_TILE) {
|
if (tile == TileMap.IRON_TILE) {
|
||||||
cubot.setHeldItem(TileMap.ITEM_IRON);
|
cubot.setHeldItem(TileMap.ITEM_IRON);
|
||||||
cubot.setCurrentAction(CubotAction.DIGGING);
|
cubot.setCurrentAction(Action.DIGGING);
|
||||||
|
|
||||||
} else if (tile == TileMap.COPPER_TILE) {
|
} else if (tile == TileMap.COPPER_TILE) {
|
||||||
cubot.setHeldItem(TileMap.ITEM_COPPER);
|
cubot.setHeldItem(TileMap.ITEM_COPPER);
|
||||||
cubot.setCurrentAction(CubotAction.DIGGING);
|
cubot.setCurrentAction(Action.DIGGING);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,15 +62,17 @@ public class CubotDrill extends CpuHardware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
|
||||||
return json;
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
|
|
||||||
|
dbObject.put("hwid", (int) HWID);
|
||||||
|
dbObject.put("cubot", cubot.getObjectId());
|
||||||
|
|
||||||
|
return dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CubotDrill deserialize(JSONObject hwJSON){
|
public static CubotDrill deserialize(DBObject obj) {
|
||||||
return new CubotDrill((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int)(long)hwJSON.get("cubot")));
|
return new CubotDrill((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class CubotFloppyDrive extends CpuHardware {
|
public class CubotFloppyDrive extends CpuHardware {
|
||||||
|
|
||||||
@@ -14,22 +15,24 @@ public class CubotFloppyDrive extends CpuHardware {
|
|||||||
|
|
||||||
public static final int DEFAULT_ADDRESS = 0x000B;
|
public static final int DEFAULT_ADDRESS = 0x000B;
|
||||||
|
|
||||||
private static final int POLL = 1;
|
private static final int FLOPPY_POLL = 1;
|
||||||
private static final int READ_SECTOR = 2;
|
private static final int FLOPPY_READ_SECTOR = 2;
|
||||||
private static final int WRITE_SECTOR = 3;
|
private static final int FLOPPY_WRITE_SECTOR = 3;
|
||||||
|
|
||||||
private Cubot cubot;
|
private Cubot cubot;
|
||||||
private FloppyDisk floppyDisk;
|
private FloppyDisk floppyDisk;
|
||||||
|
|
||||||
public CubotFloppyDrive(Cubot cubot) {
|
public CubotFloppyDrive(Cubot cubot) {
|
||||||
this.cubot = cubot;
|
this.cubot = cubot;
|
||||||
|
|
||||||
|
floppyDisk = new FloppyDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleInterrupt(Status status) {
|
public void handleInterrupt(Status status) {
|
||||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||||
|
|
||||||
if (a == POLL) {
|
if (a == FLOPPY_POLL) {
|
||||||
|
|
||||||
if (floppyDisk != null) {
|
if (floppyDisk != null) {
|
||||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||||
@@ -37,7 +40,7 @@ public class CubotFloppyDrive extends CpuHardware {
|
|||||||
getCpu().getRegisterSet().getRegister("B").setValue(1);
|
getCpu().getRegisterSet().getRegister("B").setValue(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (a == READ_SECTOR) {
|
} else if (a == FLOPPY_READ_SECTOR) {
|
||||||
|
|
||||||
if (floppyDisk == null) {
|
if (floppyDisk == null) {
|
||||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||||
@@ -53,7 +56,7 @@ public class CubotFloppyDrive extends CpuHardware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else if (a == WRITE_SECTOR) {
|
} else if (a == FLOPPY_WRITE_SECTOR) {
|
||||||
if (floppyDisk == null) {
|
if (floppyDisk == null) {
|
||||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -76,26 +79,26 @@ public class CubotFloppyDrive extends CpuHardware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("hwid", (int) HWID);
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
dbObject.put("hwid", (int) HWID);
|
||||||
|
dbObject.put("cubot", cubot.getObjectId());
|
||||||
|
|
||||||
if (floppyDisk != null) {
|
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")) {
|
if (obj.containsField("floppy")) {
|
||||||
drive.floppyDisk = FloppyDisk.deserialise((JSONObject) hwJSON.get("floppy"));
|
drive.floppyDisk = FloppyDisk.deserialise((DBObject) obj.get("floppy"));
|
||||||
} else {
|
|
||||||
drive.floppyDisk = new FloppyDisk();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return drive;
|
return drive;
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
public class CubotHologram extends CpuHardware {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hardware ID (Should be unique)
|
||||||
|
*/
|
||||||
|
static final char HWID = 0x0009;
|
||||||
|
|
||||||
|
public static final int DEFAULT_ADDRESS = 9;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleInterrupt(Status status) {
|
||||||
|
|
||||||
|
char a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char getId() {
|
||||||
|
return HWID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CubotHologram deserialize(DBObject obj) {
|
||||||
|
return new CubotHologram((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BasicDBObject mongoSerialise() {
|
||||||
|
|
||||||
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
|
|
||||||
|
dbObject.put("hwid", (int) HWID);
|
||||||
|
dbObject.put("cubot", cubot.getObjectId());
|
||||||
|
|
||||||
|
return dbObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class CubotInventory extends CpuHardware {
|
public class CubotInventory extends CpuHardware {
|
||||||
|
|
||||||
@@ -16,8 +17,8 @@ public class CubotInventory extends CpuHardware {
|
|||||||
|
|
||||||
private Cubot cubot;
|
private Cubot cubot;
|
||||||
|
|
||||||
private static final int POLL = 1;
|
private static final int INV_CLEAR = 0;
|
||||||
private static final int CLEAR = 2;
|
private static final int INV_POLL = 1;
|
||||||
|
|
||||||
public CubotInventory(Cubot cubot) {
|
public CubotInventory(Cubot cubot) {
|
||||||
this.cubot = cubot;
|
this.cubot = cubot;
|
||||||
@@ -33,29 +34,35 @@ public class CubotInventory extends CpuHardware {
|
|||||||
|
|
||||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||||
|
|
||||||
if(a == POLL) {
|
if (a == INV_POLL) {
|
||||||
|
|
||||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getHeldItem());
|
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getHeldItem());
|
||||||
|
|
||||||
} else if (a == CLEAR) {
|
} else if (a == INV_CLEAR) {
|
||||||
if (cubot.spendEnergy(100)) {
|
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);
|
cubot.setHeldItem(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
|
||||||
return json;
|
dbObject.put("hwid", (int) HWID);
|
||||||
|
dbObject.put("cubot", cubot.getObjectId());
|
||||||
|
|
||||||
|
return dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CubotInventory deserialize(JSONObject hwJSON){
|
public static CubotInventory deserialize(DBObject obj) {
|
||||||
return new CubotInventory((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int)(long)hwJSON.get("cubot")));
|
return new CubotInventory((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
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;
|
public static final int DEFAULT_ADDRESS = 4;
|
||||||
|
|
||||||
private static final int CLEAR_BUFFER = 0;
|
private static final int KEYBOARD_CLEAR_BUFFER = 0;
|
||||||
private static final int FETCH_KEY = 1;
|
private static final int KEYBOARD_FETCH_KEY = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hardware ID (Should be unique)
|
* Hardware ID (Should be unique)
|
||||||
*/
|
*/
|
||||||
@@ -19,7 +20,7 @@ public class Keyboard extends CpuHardware {
|
|||||||
|
|
||||||
private Cubot cubot;
|
private Cubot cubot;
|
||||||
|
|
||||||
public Keyboard(Cubot cubot) {
|
public CubotKeyboard(Cubot cubot) {
|
||||||
this.cubot = cubot;
|
this.cubot = cubot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,14 +34,14 @@ public class Keyboard extends CpuHardware {
|
|||||||
|
|
||||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||||
|
|
||||||
if(a == CLEAR_BUFFER){
|
if (a == KEYBOARD_CLEAR_BUFFER) {
|
||||||
|
|
||||||
cubot.clearKeyboardBuffer();
|
cubot.clearKeyboardBuffer();
|
||||||
|
|
||||||
} else if (a == FETCH_KEY){
|
} else if (a == KEYBOARD_FETCH_KEY) {
|
||||||
//pop
|
//pop
|
||||||
int key = 0;
|
int key = 0;
|
||||||
if(cubot.getKeyboardBuffer().size() > 0){
|
if (cubot.getKeyboardBuffer().size() > 0) {
|
||||||
key = cubot.getKeyboardBuffer().get(0);
|
key = cubot.getKeyboardBuffer().get(0);
|
||||||
cubot.getKeyboardBuffer().remove(0);
|
cubot.getKeyboardBuffer().remove(0);
|
||||||
}
|
}
|
||||||
@@ -52,16 +53,17 @@ public class Keyboard extends CpuHardware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
|
||||||
return json;
|
dbObject.put("hwid", (int) HWID);
|
||||||
|
dbObject.put("cubot", cubot.getObjectId());
|
||||||
|
|
||||||
|
return dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Keyboard deserialize(JSONObject hwJSON){
|
public static CubotKeyboard deserialize(DBObject obj) {
|
||||||
return new Keyboard((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int)(long)hwJSON.get("cubot")));
|
return new CubotKeyboard((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
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.GameObject;
|
||||||
import net.simon987.server.game.InventoryHolder;
|
import net.simon987.server.game.InventoryHolder;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -21,9 +24,11 @@ public class CubotLaser extends CpuHardware {
|
|||||||
|
|
||||||
private Cubot cubot;
|
private Cubot cubot;
|
||||||
|
|
||||||
private static final int WITHDRAW = 1;
|
private static final int LASER_WITHDRAW = 1;
|
||||||
private static final int DEPOSIT = 2;
|
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) {
|
public CubotLaser(Cubot cubot) {
|
||||||
this.cubot = cubot;
|
this.cubot = cubot;
|
||||||
@@ -41,14 +46,13 @@ public class CubotLaser extends CpuHardware {
|
|||||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||||
|
|
||||||
|
|
||||||
if(a == WITHDRAW) {
|
if (a == LASER_WITHDRAW) {
|
||||||
|
|
||||||
|
|
||||||
Point frontTile = cubot.getFrontTile();
|
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.getCurrentAction() == Action.IDLE && objects.size() > 0) {
|
||||||
if (cubot.getAction() != CubotAction.IDLE && objects.size() > 0) {
|
|
||||||
//FIXME: Problem here if more than 1 object
|
//FIXME: Problem here if more than 1 object
|
||||||
if (objects.get(0) instanceof InventoryHolder) {
|
if (objects.get(0) instanceof InventoryHolder) {
|
||||||
if (((InventoryHolder) objects.get(0)).canTakeItem(b)) {
|
if (((InventoryHolder) objects.get(0)).canTakeItem(b)) {
|
||||||
@@ -57,30 +61,45 @@ public class CubotLaser extends CpuHardware {
|
|||||||
((InventoryHolder) objects.get(0)).takeItem(b);
|
((InventoryHolder) objects.get(0)).takeItem(b);
|
||||||
|
|
||||||
cubot.setHeldItem(b);
|
cubot.setHeldItem(b);
|
||||||
cubot.setCurrentAction(CubotAction.WITHDRAWING);
|
cubot.setCurrentAction(Action.WITHDRAWING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} 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
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
|
||||||
return json;
|
dbObject.put("hwid", (int) HWID);
|
||||||
|
dbObject.put("cubot", cubot.getObjectId());
|
||||||
|
|
||||||
|
return dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CubotLaser deserialize(JSONObject hwJSON){
|
public static CubotLaser deserialize(DBObject obj) {
|
||||||
return new CubotLaser((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int)(long)hwJSON.get("cubot")));
|
return new CubotLaser((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
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.Direction;
|
||||||
|
import net.simon987.server.io.JSONSerialisable;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
public class CubotLeg extends CpuHardware implements JSONSerialisable {
|
||||||
|
|
||||||
|
public static final int DEFAULT_ADDRESS = 1;
|
||||||
|
|
||||||
|
public static final String NAME = "Cubot Leg";
|
||||||
|
|
||||||
|
private static final int LEGS_SET_DIR = 1;
|
||||||
|
private static final int LEGS_SET_DIR_AND_WALK = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hardware ID (Should be unique)
|
||||||
|
*/
|
||||||
|
static final char HWID = 0x0001;
|
||||||
|
|
||||||
|
private Cubot cubot;
|
||||||
|
|
||||||
|
public CubotLeg(Cubot cubot) {
|
||||||
|
this.cubot = cubot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char getId() {
|
||||||
|
return HWID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleInterrupt(Status status) {
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject serialise() {
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("hwid", (int) HWID);
|
||||||
|
json.put("cubot", cubot.getObjectId());
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,7 +1,10 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
|
import net.simon987.server.assembly.Memory;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
import net.simon987.server.game.World;
|
import net.simon987.server.game.World;
|
||||||
import net.simon987.server.game.pathfinding.Node;
|
import net.simon987.server.game.pathfinding.Node;
|
||||||
@@ -23,10 +26,10 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
|||||||
|
|
||||||
private Cubot cubot;
|
private Cubot cubot;
|
||||||
|
|
||||||
private static final int GET_POS = 1;
|
private static final int LIDAR_GET_POS = 1;
|
||||||
private static final int GET_PATH = 2;
|
private static final int LIDAR_GET_PATH = 2;
|
||||||
private static final int GET_MAP = 3;
|
private static final int LIDAR_GET_MAP = 3;
|
||||||
private static final int GET_WORLD_POS = 4;
|
private static final int LIDAR_GET_WORLD_POS = 4;
|
||||||
|
|
||||||
private static final int MEMORY_MAP_START = 0x0100;
|
private static final int MEMORY_MAP_START = 0x0100;
|
||||||
private static final int MEMORY_PATH_START = 0x0000;
|
private static final int MEMORY_PATH_START = 0x0000;
|
||||||
@@ -46,12 +49,12 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
|||||||
|
|
||||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||||
|
|
||||||
switch (a){
|
switch (a) {
|
||||||
case GET_POS:
|
case LIDAR_GET_POS:
|
||||||
getCpu().getRegisterSet().getRegister("X").setValue(cubot.getX());
|
getCpu().getRegisterSet().getRegister("X").setValue(cubot.getX());
|
||||||
getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getY());
|
getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getY());
|
||||||
break;
|
break;
|
||||||
case GET_PATH:
|
case LIDAR_GET_PATH:
|
||||||
if (cubot.spendEnergy(50)) {
|
if (cubot.spendEnergy(50)) {
|
||||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
||||||
int destX = getCpu().getRegisterSet().getRegister("X").getValue();
|
int destX = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||||
@@ -62,7 +65,7 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
|||||||
destX, destY, b);
|
destX, destY, b);
|
||||||
|
|
||||||
//Write to memory
|
//Write to memory
|
||||||
byte[] mem = getCpu().getMemory().getBytes();
|
Memory mem = getCpu().getMemory();
|
||||||
|
|
||||||
int counter = MEMORY_PATH_START;
|
int counter = MEMORY_PATH_START;
|
||||||
|
|
||||||
@@ -80,32 +83,26 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
|||||||
|
|
||||||
if (n.x < lastNode.x) {
|
if (n.x < lastNode.x) {
|
||||||
//West
|
//West
|
||||||
mem[counter++] = 0;
|
mem.set(counter++, 3);
|
||||||
mem[counter++] = 3;
|
|
||||||
} else if (n.x > lastNode.x) {
|
} else if (n.x > lastNode.x) {
|
||||||
//East
|
//East
|
||||||
mem[counter++] = 0;
|
mem.set(counter++, 1);
|
||||||
mem[counter++] = 1;
|
|
||||||
} else if (n.y < lastNode.y) {
|
} else if (n.y < lastNode.y) {
|
||||||
//North
|
//North
|
||||||
mem[counter++] = 0;
|
mem.set(counter++, 0);
|
||||||
mem[counter++] = 0;
|
|
||||||
} else if (n.y > lastNode.y) {
|
} else if (n.y > lastNode.y) {
|
||||||
//South
|
//South
|
||||||
mem[counter++] = 0;
|
mem.set(counter++, 2);
|
||||||
mem[counter++] = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastNode = n;
|
lastNode = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Indicate end of path with 0xAAAA
|
//Indicate end of path with 0xAAAA
|
||||||
mem[counter++] = -86;
|
mem.set(counter, 0xAAAA);
|
||||||
mem[counter] = -86;
|
|
||||||
} else {
|
} else {
|
||||||
//Indicate invalid path 0xFFFF
|
//Indicate invalid path 0xFFFF
|
||||||
mem[counter++] = -1;
|
mem.set(counter, 0xFFFF);
|
||||||
mem[counter] = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager.LOGGER.fine("DEBUG: path to" + destX + "," + destY);
|
LogManager.LOGGER.fine("DEBUG: path to" + destX + "," + destY);
|
||||||
@@ -113,7 +110,7 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GET_MAP:
|
case LIDAR_GET_MAP:
|
||||||
if (cubot.spendEnergy(10)) {
|
if (cubot.spendEnergy(10)) {
|
||||||
char[][] mapInfo = cubot.getWorld().getMapInfo();
|
char[][] mapInfo = cubot.getWorld().getMapInfo();
|
||||||
|
|
||||||
@@ -126,7 +123,7 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case GET_WORLD_POS:
|
case LIDAR_GET_WORLD_POS:
|
||||||
getCpu().getRegisterSet().getRegister("X").setValue(cubot.getWorld().getX());
|
getCpu().getRegisterSet().getRegister("X").setValue(cubot.getWorld().getX());
|
||||||
getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getWorld().getY());
|
getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getWorld().getY());
|
||||||
break;
|
break;
|
||||||
@@ -146,7 +143,18 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CubotLidar deserialize(JSONObject hwJSON) {
|
@Override
|
||||||
return new CubotLidar((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
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,20 +1,21 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.cubotplugin.event.CpuInitialisationListener;
|
import net.simon987.cubotplugin.event.CpuInitialisationListener;
|
||||||
import net.simon987.cubotplugin.event.UserCreationListener;
|
import net.simon987.cubotplugin.event.UserCreationListener;
|
||||||
|
import net.simon987.server.ServerConfiguration;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.game.GameObject;
|
import net.simon987.server.game.GameObject;
|
||||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
import net.simon987.server.io.CpuHardwareDeserializer;
|
||||||
import net.simon987.server.io.GameObjectDeserializer;
|
import net.simon987.server.io.GameObjectDeserializer;
|
||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
import net.simon987.server.plugin.ServerPlugin;
|
import net.simon987.server.plugin.ServerPlugin;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer, CpuHardwareDeserializer{
|
public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer, CpuHardwareDeserializer {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(ServerConfiguration config) {
|
||||||
listeners.add(new CpuInitialisationListener());
|
listeners.add(new CpuInitialisationListener());
|
||||||
listeners.add(new UserCreationListener());
|
listeners.add(new UserCreationListener());
|
||||||
|
|
||||||
@@ -22,11 +23,11 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GameObject deserializeObject(JSONObject object) {
|
public GameObject deserializeObject(DBObject object) {
|
||||||
|
|
||||||
int objType = (int)(long)object.get("type");
|
int objType = (int) object.get("t");
|
||||||
|
|
||||||
if(objType == Cubot.ID) {
|
if (objType == Cubot.ID) {
|
||||||
|
|
||||||
return Cubot.deserialize(object);
|
return Cubot.deserialize(object);
|
||||||
}
|
}
|
||||||
@@ -35,28 +36,30 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CpuHardware deserializeHardware(JSONObject hwJson) {
|
public CpuHardware deserializeHardware(DBObject obj) {
|
||||||
int hwid = (int)(long)hwJson.get("hwid");
|
int hwid = (int) obj.get("hwid");
|
||||||
|
|
||||||
switch (hwid){
|
switch (hwid) {
|
||||||
case CubotLeg.HWID:
|
case CubotLeg.HWID:
|
||||||
return CubotLeg.deserialize(hwJson);
|
return CubotLeg.deserialize(obj);
|
||||||
case CubotLaser.HWID:
|
case CubotLaser.HWID:
|
||||||
return CubotLaser.deserialize(hwJson);
|
return CubotLaser.deserialize(obj);
|
||||||
case CubotLidar.HWID:
|
case CubotLidar.HWID:
|
||||||
return CubotLidar.deserialize(hwJson);
|
return CubotLidar.deserialize(obj);
|
||||||
case CubotDrill.HWID:
|
case CubotDrill.HWID:
|
||||||
return CubotDrill.deserialize(hwJson);
|
return CubotDrill.deserialize(obj);
|
||||||
case CubotInventory.HWID:
|
case CubotInventory.HWID:
|
||||||
return CubotInventory.deserialize(hwJson);
|
return CubotInventory.deserialize(obj);
|
||||||
case Keyboard.HWID:
|
case CubotKeyboard.HWID:
|
||||||
return Keyboard.deserialize(hwJson);
|
return CubotKeyboard.deserialize(obj);
|
||||||
case CubotHologram.HWID:
|
case CubotHologram.HWID:
|
||||||
return CubotHologram.deserialize(hwJson);
|
return CubotHologram.deserialize(obj);
|
||||||
case CubotBattery.HWID:
|
case CubotBattery.HWID:
|
||||||
return CubotBattery.deserialize(hwJson);
|
return CubotBattery.deserialize(obj);
|
||||||
case CubotFloppyDrive.HWID:
|
case CubotFloppyDrive.HWID:
|
||||||
return CubotFloppyDrive.deserialize(hwJson);
|
return CubotFloppyDrive.deserialize(obj);
|
||||||
|
case CubotComPort.HWID:
|
||||||
|
return CubotComPort.deserialize(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
package net.simon987.cubotplugin;
|
package net.simon987.cubotplugin;
|
||||||
|
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.assembly.Memory;
|
import net.simon987.server.assembly.Memory;
|
||||||
import net.simon987.server.io.JSONSerialisable;
|
import net.simon987.server.io.MongoSerialisable;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a floppy disk that is inside a floppy drive.
|
* Represents a floppy disk that is inside a floppy drive.
|
||||||
* Floppies contains 80 tracks with 18 sectors per track.
|
* 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)
|
* 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
|
* Contents of the disk
|
||||||
@@ -25,7 +26,7 @@ public class FloppyDisk implements JSONSerialisable {
|
|||||||
|
|
||||||
|
|
||||||
public FloppyDisk() {
|
public FloppyDisk() {
|
||||||
this.memory = new Memory(1024 * 1440);
|
this.memory = new Memory(512 * 1440);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +40,7 @@ public class FloppyDisk implements JSONSerialisable {
|
|||||||
public boolean readSector(int sector, Memory cpuMemory, int ramAddress) {
|
public boolean readSector(int sector, Memory cpuMemory, int ramAddress) {
|
||||||
|
|
||||||
if (sector <= 1440) {
|
if (sector <= 1440) {
|
||||||
cpuMemory.write(ramAddress, memory.getBytes(), sector * 1024, 1024);
|
cpuMemory.write(ramAddress, memory.getWords(), sector * 512, 512);
|
||||||
|
|
||||||
//Calculate seek time
|
//Calculate seek time
|
||||||
int deltaTrack = (sector / 80) - rwHeadTrack;
|
int deltaTrack = (sector / 80) - rwHeadTrack;
|
||||||
@@ -66,7 +67,7 @@ public class FloppyDisk implements JSONSerialisable {
|
|||||||
public boolean writeSector(int sector, Memory cpuMemory, int ramAddress) {
|
public boolean writeSector(int sector, Memory cpuMemory, int ramAddress) {
|
||||||
|
|
||||||
if (sector <= 1440) {
|
if (sector <= 1440) {
|
||||||
memory.write(sector * 512, cpuMemory.getBytes(), ramAddress * 2, 1024);
|
memory.write(sector * 512, cpuMemory.getWords(), ramAddress, 512);
|
||||||
|
|
||||||
//Calculate seek time
|
//Calculate seek time
|
||||||
int deltaTrack = (sector / 80) - rwHeadTrack;
|
int deltaTrack = (sector / 80) - rwHeadTrack;
|
||||||
@@ -82,23 +83,22 @@ public class FloppyDisk implements JSONSerialisable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
dbObject.put("rwHeadTrack", rwHeadTrack);
|
||||||
json.put("rwHeadTrack", rwHeadTrack);
|
dbObject.put("memory", memory.mongoSerialise());
|
||||||
json.put("memory", memory.serialise());
|
|
||||||
|
|
||||||
return json;
|
return dbObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FloppyDisk deserialise(JSONObject json) {
|
public static FloppyDisk deserialise(DBObject obj) {
|
||||||
|
|
||||||
FloppyDisk floppyDisk = new FloppyDisk();
|
FloppyDisk floppyDisk = new FloppyDisk();
|
||||||
|
|
||||||
floppyDisk.rwHeadTrack = (int) (long) json.get("rwHeadTrack");
|
floppyDisk.rwHeadTrack = (int) obj.get("rwHeadTrack");
|
||||||
floppyDisk.memory = Memory.deserialize((JSONObject) json.get("memory"));
|
floppyDisk.memory = Memory.deserialize((DBObject) obj.get("memory"));
|
||||||
|
|
||||||
return floppyDisk;
|
return floppyDisk;
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,6 @@ import net.simon987.server.assembly.CPU;
|
|||||||
import net.simon987.server.event.CpuInitialisationEvent;
|
import net.simon987.server.event.CpuInitialisationEvent;
|
||||||
import net.simon987.server.event.GameEvent;
|
import net.simon987.server.event.GameEvent;
|
||||||
import net.simon987.server.event.GameEventListener;
|
import net.simon987.server.event.GameEventListener;
|
||||||
import net.simon987.server.logging.LogManager;
|
|
||||||
import net.simon987.server.user.User;
|
import net.simon987.server.user.User;
|
||||||
|
|
||||||
public class CpuInitialisationListener implements GameEventListener {
|
public class CpuInitialisationListener implements GameEventListener {
|
||||||
@@ -16,10 +15,10 @@ public class CpuInitialisationListener implements GameEventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(GameEvent event) {
|
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();
|
CPU cpu = (CPU) event.getSource();
|
||||||
User user = ((CpuInitialisationEvent)event).getUser();
|
User user = ((CpuInitialisationEvent) event).getUser();
|
||||||
|
|
||||||
CubotLeg legHw = new CubotLeg((Cubot) user.getControlledUnit());
|
CubotLeg legHw = new CubotLeg((Cubot) user.getControlledUnit());
|
||||||
legHw.setCpu(cpu);
|
legHw.setCpu(cpu);
|
||||||
@@ -27,7 +26,7 @@ public class CpuInitialisationListener implements GameEventListener {
|
|||||||
laserHw.setCpu(cpu);
|
laserHw.setCpu(cpu);
|
||||||
CubotLidar radarHw = new CubotLidar((Cubot) user.getControlledUnit());
|
CubotLidar radarHw = new CubotLidar((Cubot) user.getControlledUnit());
|
||||||
radarHw.setCpu(cpu);
|
radarHw.setCpu(cpu);
|
||||||
Keyboard keyboard = new Keyboard((Cubot) user.getControlledUnit());
|
CubotKeyboard keyboard = new CubotKeyboard((Cubot) user.getControlledUnit());
|
||||||
keyboard.setCpu(cpu);
|
keyboard.setCpu(cpu);
|
||||||
CubotDrill drillHw = new CubotDrill((Cubot) user.getControlledUnit());
|
CubotDrill drillHw = new CubotDrill((Cubot) user.getControlledUnit());
|
||||||
drillHw.setCpu(cpu);
|
drillHw.setCpu(cpu);
|
||||||
@@ -39,16 +38,19 @@ public class CpuInitialisationListener implements GameEventListener {
|
|||||||
batteryHw.setCpu(cpu);
|
batteryHw.setCpu(cpu);
|
||||||
CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit());
|
CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit());
|
||||||
floppyHw.setCpu(cpu);
|
floppyHw.setCpu(cpu);
|
||||||
|
CubotComPort comPortHw = new CubotComPort((Cubot) user.getControlledUnit());
|
||||||
|
comPortHw.setCpu(cpu);
|
||||||
|
|
||||||
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
|
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS);
|
cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(radarHw, CubotLidar.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(drillHw, CubotDrill.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
|
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
|
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
|
||||||
cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS);
|
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 net.simon987.server.user.User;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class UserCreationListener implements GameEventListener {
|
public class UserCreationListener implements GameEventListener {
|
||||||
@Override
|
@Override
|
||||||
@@ -19,32 +20,35 @@ public class UserCreationListener implements GameEventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(GameEvent event) {
|
public void handle(GameEvent event) {
|
||||||
|
|
||||||
User user = (User)event.getSource();
|
Random random = new Random();
|
||||||
|
|
||||||
LogManager.LOGGER.fine("(Plugin) Handled User creation event (Cubot Plugin)");
|
|
||||||
|
|
||||||
|
User user = (User) event.getSource();
|
||||||
Cubot cubot = new Cubot();
|
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.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
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.setEnergy(GameServer.INSTANCE.getConfig().getInt("battery_max_energy"));
|
||||||
cubot.setMaxEnergy(GameServer.INSTANCE.getConfig().getInt("battery_max_energy"));
|
cubot.setMaxEnergy(GameServer.INSTANCE.getConfig().getInt("battery_max_energy"));
|
||||||
|
|
||||||
cubot.setParent(user);
|
cubot.setParent(user);
|
||||||
|
|
||||||
Point point = cubot.getWorld().getRandomPassableTile();
|
|
||||||
|
|
||||||
cubot.setX(point.x);
|
|
||||||
cubot.setY(point.y);
|
|
||||||
|
|
||||||
user.setControlledUnit(cubot);
|
user.setControlledUnit(cubot);
|
||||||
|
|
||||||
|
LogManager.LOGGER.fine("(Plugin) Handled User creation event (Cubot Plugin)");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
package net.simon987.cubotplugin;
|
|
||||||
|
|
||||||
import net.simon987.server.GameServer;
|
|
||||||
import net.simon987.server.assembly.Memory;
|
|
||||||
import net.simon987.server.game.ControllableUnit;
|
|
||||||
import net.simon987.server.game.Direction;
|
|
||||||
import net.simon987.server.game.GameObject;
|
|
||||||
import net.simon987.server.game.Updatable;
|
|
||||||
import net.simon987.server.user.User;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class Cubot extends GameObject implements Updatable, ControllableUnit {
|
|
||||||
|
|
||||||
private static final char MAP_INFO = 0x0080;
|
|
||||||
public static final int ID = 1;
|
|
||||||
|
|
||||||
private char hologram = 0;
|
|
||||||
private char lastHologram = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hit points
|
|
||||||
*/
|
|
||||||
private int hp;
|
|
||||||
private int heldItem;
|
|
||||||
|
|
||||||
private CubotAction currentAction = CubotAction.IDLE;
|
|
||||||
private CubotAction lastAction = CubotAction.IDLE;
|
|
||||||
|
|
||||||
private ArrayList<Integer> keyboardBuffer = new ArrayList<>();
|
|
||||||
|
|
||||||
private FloppyDisk floppyDisk;
|
|
||||||
|
|
||||||
private User parent;
|
|
||||||
|
|
||||||
private int energy;
|
|
||||||
private int maxEnergy;
|
|
||||||
|
|
||||||
public Cubot() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char getMapInfo() {
|
|
||||||
return MAP_INFO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
|
|
||||||
if (currentAction == CubotAction.WALKING) {
|
|
||||||
if (spendEnergy(100)) {
|
|
||||||
if (!incrementLocation()) {
|
|
||||||
//Couldn't walk
|
|
||||||
currentAction = CubotAction.IDLE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
currentAction = CubotAction.IDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CurrentAction is set during the code execution and this function is called right after
|
|
||||||
* If no action as been set, the action sent to the client is the action in currentAction that
|
|
||||||
* was set last tick (IDLE)
|
|
||||||
*/
|
|
||||||
lastAction = currentAction;
|
|
||||||
currentAction = CubotAction.IDLE;
|
|
||||||
|
|
||||||
//Same principle for hologram
|
|
||||||
lastHologram = hologram;
|
|
||||||
hologram = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject serialise() {
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("id", getObjectId());
|
|
||||||
json.put("type", ID);
|
|
||||||
json.put("x", getX());
|
|
||||||
json.put("y", getY());
|
|
||||||
json.put("direction", getDirection().ordinal());
|
|
||||||
json.put("heldItem", heldItem);
|
|
||||||
json.put("hp", hp);
|
|
||||||
json.put("action", lastAction.ordinal());
|
|
||||||
json.put("holo", (int) lastHologram);
|
|
||||||
json.put("energy", (int) lastHologram);
|
|
||||||
|
|
||||||
if (parent != null) {
|
|
||||||
json.put("parent", parent.getUsername()); //Only used client-side for now
|
|
||||||
}
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Cubot deserialize(JSONObject json) {
|
|
||||||
|
|
||||||
Cubot cubot = new Cubot();
|
|
||||||
cubot.setObjectId((int)(long)json.get("id"));
|
|
||||||
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.maxEnergy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy");
|
|
||||||
|
|
||||||
return cubot;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHeldItem(int heldItem) {
|
|
||||||
this.heldItem = heldItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeldItem() {
|
|
||||||
return heldItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setKeyboardBuffer(ArrayList<Integer> kbBuffer) {
|
|
||||||
keyboardBuffer = kbBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ArrayList<Integer> getKeyboardBuffer() {
|
|
||||||
return keyboardBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearKeyboardBuffer(){
|
|
||||||
keyboardBuffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentAction(CubotAction currentAction) {
|
|
||||||
this.currentAction = currentAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getParent() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParent(User parent) {
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CubotAction getAction() {
|
|
||||||
return lastAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHologram(char hologram) {
|
|
||||||
this.hologram = hologram;
|
|
||||||
}
|
|
||||||
|
|
||||||
public char getHologram() {
|
|
||||||
return lastHologram;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public int getEnergy() {
|
|
||||||
return energy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnergy(int energy) {
|
|
||||||
this.energy = energy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean spendEnergy(int spent) {
|
|
||||||
|
|
||||||
if (energy - spent < 0) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
energy -= spent;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxEnergy(int maxEnergy) {
|
|
||||||
this.maxEnergy = maxEnergy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxEnergy() {
|
|
||||||
return maxEnergy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Memory getFloppyData() {
|
|
||||||
return ((CubotFloppyDrive) getParent().getCpu().getHardware(CubotFloppyDrive.DEFAULT_ADDRESS)).getFloppy().getMemory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package net.simon987.cubotplugin;
|
|
||||||
|
|
||||||
public enum CubotAction {
|
|
||||||
IDLE,
|
|
||||||
DIGGING,
|
|
||||||
WALKING,
|
|
||||||
WITHDRAWING,
|
|
||||||
DEPOSITING
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package net.simon987.cubotplugin;
|
|
||||||
|
|
||||||
import net.simon987.server.GameServer;
|
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
|
||||||
import net.simon987.server.assembly.Status;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class CubotHologram extends CpuHardware {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hardware ID (Should be unique)
|
|
||||||
*/
|
|
||||||
static final char HWID = 0x0009;
|
|
||||||
|
|
||||||
public static final int DEFAULT_ADDRESS = 9;
|
|
||||||
|
|
||||||
private Cubot cubot;
|
|
||||||
|
|
||||||
public CubotHologram(Cubot cubot) {
|
|
||||||
this.cubot = cubot;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleInterrupt(Status status) {
|
|
||||||
|
|
||||||
char a = getCpu().getRegisterSet().getRegister("A").getValue();
|
|
||||||
cubot.setHologram(a);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char getId() {
|
|
||||||
return HWID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CubotHologram deserialize(JSONObject hwJSON) {
|
|
||||||
return new CubotHologram((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject serialise() {
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
package net.simon987.cubotplugin;
|
|
||||||
|
|
||||||
import net.simon987.server.GameServer;
|
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
|
||||||
import net.simon987.server.assembly.Status;
|
|
||||||
import net.simon987.server.game.Direction;
|
|
||||||
import net.simon987.server.io.JSONSerialisable;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class CubotLeg extends CpuHardware implements JSONSerialisable {
|
|
||||||
|
|
||||||
public static final int DEFAULT_ADDRESS = 1;
|
|
||||||
|
|
||||||
public static final String NAME = "Cubot Leg";
|
|
||||||
|
|
||||||
private static final int SET_DIR = 1;
|
|
||||||
private static final int SET_DIR_AND_WALK = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hardware ID (Should be unique)
|
|
||||||
*/
|
|
||||||
static final char HWID = 0x0001;
|
|
||||||
|
|
||||||
private Cubot cubot;
|
|
||||||
|
|
||||||
public CubotLeg(Cubot cubot) {
|
|
||||||
this.cubot = cubot;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char getId() {
|
|
||||||
return HWID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleInterrupt(Status status) {
|
|
||||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
|
||||||
int b = getCpu().getRegisterSet().getRegister("B").getValue();
|
|
||||||
|
|
||||||
if(a == SET_DIR){
|
|
||||||
|
|
||||||
|
|
||||||
Direction dir = Direction.getDirection(b);
|
|
||||||
|
|
||||||
if(dir != null){
|
|
||||||
if (cubot.spendEnergy(20)) {
|
|
||||||
cubot.setDirection(Direction.getDirection(b));
|
|
||||||
status.setErrorFlag(false);
|
|
||||||
}
|
|
||||||
} 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(CubotAction.WALKING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject serialise() {
|
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
json.put("cubot", cubot.getObjectId());
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CubotLeg deserialize(JSONObject hwJSON){
|
|
||||||
return new CubotLeg((Cubot)GameServer.INSTANCE.getGameUniverse().getObject((int)(long)hwJSON.get("cubot")));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,6 @@ public class CubotTest {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
assertEquals(1,2);
|
assertEquals(1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
classpath=net.simon987.kilnplugin.KilnPlugin
|
|
||||||
name=Kiln Plugin
|
|
||||||
version=1.0
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package net.simon987.kilnplugin;
|
|
||||||
|
|
||||||
import net.simon987.server.game.GameObject;
|
|
||||||
import net.simon987.server.io.GameObjectDeserializer;
|
|
||||||
import net.simon987.server.plugin.ServerPlugin;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class KilnPlugin extends ServerPlugin implements GameObjectDeserializer {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GameObject deserializeObject(JSONObject object) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
24
Plugin Misc HW/Plugin Misc HW.iml
Normal file
24
Plugin Misc HW/Plugin Misc HW.iml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<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$/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="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<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" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
32
Plugin Misc HW/pom.xml
Normal file
32
Plugin Misc HW/pom.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
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>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.simon987.server</groupId>
|
||||||
|
<artifactId>server</artifactId>
|
||||||
|
<version>1.2a</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package net.simon987.mischwplugin;
|
package net.simon987.mischwplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
import net.simon987.server.assembly.Util;
|
import net.simon987.server.assembly.Util;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class Clock extends CpuHardware {
|
public class Clock extends CpuHardware {
|
||||||
|
|
||||||
@@ -28,15 +28,18 @@ public class Clock extends CpuHardware {
|
|||||||
return HWID;
|
return HWID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Clock deserialize(JSONObject hwJSON) {
|
public static Clock deserialize() {
|
||||||
return new Clock();
|
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,31 +1,32 @@
|
|||||||
package net.simon987.mischwplugin;
|
package net.simon987.mischwplugin;
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.mischwplugin.event.CpuInitialisationListener;
|
import net.simon987.mischwplugin.event.CpuInitialisationListener;
|
||||||
|
import net.simon987.server.ServerConfiguration;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
import net.simon987.server.io.CpuHardwareDeserializer;
|
||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
import net.simon987.server.plugin.ServerPlugin;
|
import net.simon987.server.plugin.ServerPlugin;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class MiscHWPlugin extends ServerPlugin implements CpuHardwareDeserializer {
|
public class MiscHWPlugin extends ServerPlugin implements CpuHardwareDeserializer {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(ServerConfiguration config) {
|
||||||
listeners.add(new CpuInitialisationListener());
|
listeners.add(new CpuInitialisationListener());
|
||||||
|
|
||||||
LogManager.LOGGER.info("Initialised Misc Hardware Plugin");
|
LogManager.LOGGER.info("Initialised Misc Hardware Plugin");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CpuHardware deserializeHardware(JSONObject hwJson) {
|
public CpuHardware deserializeHardware(DBObject hwJson) {
|
||||||
int hwid = (int) (long) hwJson.get("hwid");
|
int hwid = (int) hwJson.get("hwid");
|
||||||
|
|
||||||
switch (hwid) {
|
switch (hwid) {
|
||||||
case RandomNumberGenerator.HWID:
|
case RandomNumberGenerator.HWID:
|
||||||
return RandomNumberGenerator.deserialize(hwJson);
|
return RandomNumberGenerator.deserialize();
|
||||||
case Clock.HWID:
|
case Clock.HWID:
|
||||||
return Clock.deserialize(hwJson);
|
return Clock.deserialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package net.simon987.mischwplugin;
|
package net.simon987.mischwplugin;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
import net.simon987.server.assembly.CpuHardware;
|
import net.simon987.server.assembly.CpuHardware;
|
||||||
import net.simon987.server.assembly.Status;
|
import net.simon987.server.assembly.Status;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
@@ -31,14 +31,16 @@ public class RandomNumberGenerator extends CpuHardware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("hwid", (int) HWID);
|
|
||||||
|
|
||||||
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();
|
return new RandomNumberGenerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
24
Plugin NPC/Plugin NPC.iml
Normal file
24
Plugin NPC/Plugin NPC.iml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<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$/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="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<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" />
|
||||||
|
<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>
|
||||||
31
Plugin NPC/pom.xml
Normal file
31
Plugin NPC/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
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>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.simon987.server</groupId>
|
||||||
|
<artifactId>server</artifactId>
|
||||||
|
<version>1.2a</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
210
Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java
Normal file
210
Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
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;
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Factory extends GameObject implements Updatable {
|
||||||
|
|
||||||
|
private static final int MAP_INFO = 0x0200;
|
||||||
|
static final int ID = 3;
|
||||||
|
|
||||||
|
private static final int MAX_NPC_COUNT = GameServer.INSTANCE.getConfig().getInt("factory_max_npc_count");
|
||||||
|
|
||||||
|
private static final int NPC_CREATION_COOLDOWN = NonPlayerCharacter.LIFETIME / MAX_NPC_COUNT;
|
||||||
|
|
||||||
|
private ArrayList<NonPlayerCharacter> npcs = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of ticks to wait until the Factory can spawn a new NPC
|
||||||
|
*/
|
||||||
|
private int cooldown = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary NPC objectId array. The Factory links the NPCs to itself when initialised,
|
||||||
|
* at the first call of update().
|
||||||
|
*/
|
||||||
|
private Object[] tmpNpcArray = new Object[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory are uninitialised until the first update() call
|
||||||
|
*/
|
||||||
|
private boolean initialised = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char getMapInfo() {
|
||||||
|
return MAP_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
|
||||||
|
if (!initialised) {
|
||||||
|
|
||||||
|
initialised = true;
|
||||||
|
|
||||||
|
for (Object id : tmpNpcArray) {
|
||||||
|
|
||||||
|
NonPlayerCharacter npc = (NonPlayerCharacter) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) id);
|
||||||
|
|
||||||
|
if (npc != null) {
|
||||||
|
npc.setFactory(this);
|
||||||
|
npcs.add(npc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (cooldown == 0) {
|
||||||
|
if (npcs.size() < MAX_NPC_COUNT) {
|
||||||
|
Point p = getAdjacentTile();
|
||||||
|
|
||||||
|
if (p != null) {
|
||||||
|
NonPlayerCharacter npc = new HarvesterNPC();
|
||||||
|
npc.setWorld(getWorld());
|
||||||
|
npc.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||||
|
npc.setX(p.x);
|
||||||
|
npc.setY(p.y);
|
||||||
|
getWorld().addObject(npc);
|
||||||
|
getWorld().incUpdatable();
|
||||||
|
npc.setFactory(this);
|
||||||
|
|
||||||
|
npcs.add(npc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cooldown += NPC_CREATION_COOLDOWN;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cooldown--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAt(int x, int y) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Object is 2x2 tiles, the (x,y) coordinates of the object being
|
||||||
|
* at top-left.
|
||||||
|
* # .
|
||||||
|
* . .
|
||||||
|
*/
|
||||||
|
return (x == getX() + 1 || x == getX()) && (y == getY() + 1 || y == getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject serialise() {
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
|
json.put("i", getObjectId());
|
||||||
|
json.put("x", getX());
|
||||||
|
json.put("y", getY());
|
||||||
|
json.put("t", ID);
|
||||||
|
|
||||||
|
JSONArray tmpNpcArray = new JSONArray();
|
||||||
|
|
||||||
|
for (NonPlayerCharacter npc : npcs) {
|
||||||
|
tmpNpcArray.add(npc.getObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
json.put("n", tmpNpcArray);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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) obj.get("i"));
|
||||||
|
factory.setX((int) obj.get("x"));
|
||||||
|
factory.setY((int) obj.get("y"));
|
||||||
|
|
||||||
|
factory.tmpNpcArray = ((BasicDBList) obj.get("n")).toArray();
|
||||||
|
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first non-blocked tile that is directly adjacent to the factory, starting from the north-east corner
|
||||||
|
* going clockwise.
|
||||||
|
*
|
||||||
|
* @return The coordinates of the first non-blocked tile, null otherwise.
|
||||||
|
*/
|
||||||
|
public Point getAdjacentTile() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (2,0)
|
||||||
|
* (2,1)
|
||||||
|
* (1,2)
|
||||||
|
* (0,2)
|
||||||
|
* (-1,1)
|
||||||
|
* (-1,0)
|
||||||
|
* (0,-1)
|
||||||
|
* (1,-1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!getWorld().isTileBlocked(getX() + 2, getY())) {
|
||||||
|
return new Point(getX() + 2, getY());
|
||||||
|
|
||||||
|
} else if (!getWorld().isTileBlocked(getX() + 2, getY() + 1)) {
|
||||||
|
return new Point(getX() + 2, getY() + 1);
|
||||||
|
|
||||||
|
} else if (!getWorld().isTileBlocked(getX() + 1, getY() + 2)) {
|
||||||
|
return new Point(getX() + 1, getY() + 2);
|
||||||
|
|
||||||
|
} else if (!getWorld().isTileBlocked(getX(), getY() + 2)) {
|
||||||
|
return new Point(getX(), getY() + 2);
|
||||||
|
|
||||||
|
} else if (!getWorld().isTileBlocked(getX() + -1, getY() + 1)) {
|
||||||
|
return new Point(getX() + -1, 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 if (!getWorld().isTileBlocked(getX() + 1, getY() + -1)) {
|
||||||
|
return new Point(getX() + 1, getY() + -1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<NonPlayerCharacter> getNpcs() {
|
||||||
|
return npcs;
|
||||||
|
}
|
||||||
|
}
|
||||||
100
Plugin NPC/src/main/java/net/simon987/npcplugin/HarvestTask.java
Normal file
100
Plugin NPC/src/main/java/net/simon987/npcplugin/HarvestTask.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package net.simon987.npcplugin;
|
||||||
|
|
||||||
|
|
||||||
|
import net.simon987.server.assembly.Util;
|
||||||
|
import net.simon987.server.game.Direction;
|
||||||
|
import net.simon987.server.game.GameObject;
|
||||||
|
import net.simon987.server.game.InventoryHolder;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class HarvestTask extends NPCTask {
|
||||||
|
|
||||||
|
private Random random;
|
||||||
|
|
||||||
|
private int pause;
|
||||||
|
|
||||||
|
public HarvestTask() {
|
||||||
|
random = new Random();
|
||||||
|
pause = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Direction nextWorldDirection = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkCompleted() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(NonPlayerCharacter npc) {
|
||||||
|
|
||||||
|
if (pause == 0) {
|
||||||
|
//Get biomass
|
||||||
|
/* 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;
|
||||||
|
GameObject minBiomass = null;
|
||||||
|
|
||||||
|
for (GameObject plant : biomass) {
|
||||||
|
|
||||||
|
int dist = Util.manhattanDist(npc.getX(), npc.getY(), plant.getX(), plant.getY());
|
||||||
|
|
||||||
|
if (dist < minDist) {
|
||||||
|
minDist = dist;
|
||||||
|
minBiomass = plant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Move towards it
|
||||||
|
if (minBiomass != null && minDist == 1) {
|
||||||
|
//Reached biomass, change direction to face it
|
||||||
|
Direction newDirection = Direction.getFacing(npc.getX(), npc.getY(),
|
||||||
|
minBiomass.getX(), minBiomass.getY());
|
||||||
|
|
||||||
|
if (newDirection != null) {
|
||||||
|
npc.setDirection(newDirection);
|
||||||
|
|
||||||
|
//Reached biomass, harvest it
|
||||||
|
if (minBiomass instanceof InventoryHolder) {
|
||||||
|
((InventoryHolder) minBiomass).takeItem(1);
|
||||||
|
pause += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LogManager.LOGGER.severe("FIXME: tick:HarvestTask, Direction is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
nextWorldDirection = null;
|
||||||
|
} else if (minBiomass != null && npc.moveTo(minBiomass.getX(), minBiomass.getY(), 1)) {
|
||||||
|
//Moving towards biomass...
|
||||||
|
nextWorldDirection = null;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (nextWorldDirection == null) {
|
||||||
|
|
||||||
|
while (!npc.gotoWorld(nextWorldDirection)) {
|
||||||
|
nextWorldDirection = Direction.getDirection(random.nextInt(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
pause += 6;
|
||||||
|
} else {
|
||||||
|
npc.gotoWorld(nextWorldDirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pause--;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
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());
|
||||||
|
|
||||||
|
setHp(MAX_HEALTH);
|
||||||
|
setMaxHp(MAX_HEALTH);
|
||||||
|
setHealRate(HEAL_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
|
||||||
|
super.update();
|
||||||
|
|
||||||
|
if (getFactory() != null) {
|
||||||
|
if (getTask().checkCompleted()) {
|
||||||
|
|
||||||
|
setTask(new HarvestTask());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
getTask().tick(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Self-destroy when age limit is reached
|
||||||
|
if (getAge() >= NonPlayerCharacter.LIFETIME) {
|
||||||
|
setDead(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
|
||||||
|
json.put("i", getObjectId());
|
||||||
|
json.put("x", getX());
|
||||||
|
json.put("y", getY());
|
||||||
|
json.put("direction", getDirection().ordinal());
|
||||||
|
json.put("hp", getHp());
|
||||||
|
json.put("energy", energy);
|
||||||
|
json.put("action", getAction().ordinal());
|
||||||
|
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("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) 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Plugin NPC/src/main/java/net/simon987/npcplugin/NPCTask.java
Normal file
10
Plugin NPC/src/main/java/net/simon987/npcplugin/NPCTask.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package net.simon987.npcplugin;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class NPCTask {
|
||||||
|
|
||||||
|
public abstract boolean checkCompleted();
|
||||||
|
|
||||||
|
public abstract void tick(NonPlayerCharacter npc);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
package net.simon987.npcplugin;
|
||||||
|
|
||||||
|
import net.simon987.server.GameServer;
|
||||||
|
import net.simon987.server.assembly.Util;
|
||||||
|
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, Attackable {
|
||||||
|
|
||||||
|
private static final int MAP_INFO = 0x0040;
|
||||||
|
|
||||||
|
private static final int MAX_FACTORY_DISTANCE = GameServer.INSTANCE.getConfig().getInt("npc_max_factory_distance");
|
||||||
|
|
||||||
|
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 energy;
|
||||||
|
int maxEnergy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current task
|
||||||
|
*/
|
||||||
|
private NPCTask task;
|
||||||
|
|
||||||
|
private Action lastAction = Action.IDLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory that created this NPC
|
||||||
|
*/
|
||||||
|
private Factory factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, the NPC will be destroyed next tick if it is
|
||||||
|
* not linked to a Factory
|
||||||
|
*/
|
||||||
|
private boolean selfDestroyNextTick = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Age of the npc, in ticks
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
|
||||||
|
age++;
|
||||||
|
|
||||||
|
//Destroy NPCs that are not linked with a Factory
|
||||||
|
if (factory == null) {
|
||||||
|
if (selfDestroyNextTick) {
|
||||||
|
setDead(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
selfDestroyNextTick = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Heal the NPC
|
||||||
|
heal(hpRegenerationRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to move the NPC to the specified coordinates
|
||||||
|
*
|
||||||
|
* @param range distance to the desired coordinates, in tiles
|
||||||
|
* @return true if the path is passable
|
||||||
|
*/
|
||||||
|
boolean moveTo(int x, int y, int range) {
|
||||||
|
|
||||||
|
ArrayList<Node> path = Pathfinder.findPath(getWorld(), getX(), getY(), x, y, range);
|
||||||
|
|
||||||
|
if (path != null && path.size() > 0) {
|
||||||
|
|
||||||
|
Node nextTile = path.get(1);
|
||||||
|
|
||||||
|
Direction newDirection = Direction.getFacing(getX(), getY(), nextTile.x, nextTile.y);
|
||||||
|
|
||||||
|
if (newDirection != null) {
|
||||||
|
setDirection(newDirection);
|
||||||
|
} else {
|
||||||
|
LogManager.LOGGER.severe("FIXME: moveTo:NonPlayerCharacter, Direction is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incrementLocation()) {
|
||||||
|
lastAction = Action.WALKING;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastAction = Action.IDLE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the next World in the specified Direction.
|
||||||
|
*
|
||||||
|
* @return true if the World in the specified Direction is within the max. distance from the Factory
|
||||||
|
*/
|
||||||
|
boolean gotoWorld(Direction direction) {
|
||||||
|
|
||||||
|
if (direction == Direction.NORTH) {
|
||||||
|
|
||||||
|
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
|
||||||
|
getWorld().getX(), getWorld().getY() - 1) <= MAX_FACTORY_DISTANCE) {
|
||||||
|
if (!moveTo(8, 0, 0)) {
|
||||||
|
setDirection(Direction.NORTH);
|
||||||
|
incrementLocation();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (direction == Direction.EAST) {
|
||||||
|
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
|
||||||
|
getWorld().getX() + 1, getWorld().getY()) <= MAX_FACTORY_DISTANCE) {
|
||||||
|
if (!moveTo(15, 7, 0)) {
|
||||||
|
setDirection(Direction.EAST);
|
||||||
|
incrementLocation();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (direction == Direction.SOUTH) {
|
||||||
|
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
|
||||||
|
getWorld().getX(), getWorld().getY() + 1) <= MAX_FACTORY_DISTANCE) {
|
||||||
|
if (!moveTo(8, 15, 0)) {
|
||||||
|
setDirection(Direction.SOUTH);
|
||||||
|
incrementLocation();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (direction == Direction.WEST) {
|
||||||
|
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
|
||||||
|
getWorld().getX() - 1, getWorld().getY()) <= MAX_FACTORY_DISTANCE) {
|
||||||
|
if (!moveTo(0, 7, 0)) {
|
||||||
|
setDirection(Direction.WEST);
|
||||||
|
incrementLocation();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTask(NPCTask task) {
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action getAction() {
|
||||||
|
return lastAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Factory getFactory() {
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFactory(Factory factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +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 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(DBObject obj) {
|
||||||
|
|
||||||
|
int objType = (int) obj.get("t");
|
||||||
|
|
||||||
|
if (objType == HarvesterNPC.ID) {
|
||||||
|
return HarvesterNPC.deserialize(obj);
|
||||||
|
} else if (objType == Factory.ID) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
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;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawn rate. Higher = rarer: A factory will be spawn about every FACTORY_SPAWN_RATE generated Worlds
|
||||||
|
*/
|
||||||
|
private static final int FACTORY_SPAWN_RATE = 35;
|
||||||
|
|
||||||
|
private Random random = new Random();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class getListenedEventType() {
|
||||||
|
return WorldGenerationEvent.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(GameEvent event) {
|
||||||
|
|
||||||
|
if (random.nextInt(FACTORY_SPAWN_RATE) == 0) {
|
||||||
|
|
||||||
|
World world = ((WorldGenerationEvent) event).getWorld();
|
||||||
|
|
||||||
|
outerLoopFactory:
|
||||||
|
for (int x = 2; x < 12; x++) {
|
||||||
|
for (int y = 2; y < 12; y++) {
|
||||||
|
|
||||||
|
if ((!world.isTileBlocked(x, y) && !world.isTileBlocked(x + 1, y) &&
|
||||||
|
!world.isTileBlocked(x, y + 1) && !world.isTileBlocked(x + 1, y + 1))) {
|
||||||
|
|
||||||
|
Factory factory = new Factory();
|
||||||
|
|
||||||
|
factory.setWorld(world);
|
||||||
|
factory.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||||
|
factory.setX(x);
|
||||||
|
factory.setY(y);
|
||||||
|
|
||||||
|
if (factory.getAdjacentTile() == null) {
|
||||||
|
//Factory has no non-blocked adjacent tiles
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Plugin NPC/src/main/resources/plugin.properties
Normal file
3
Plugin NPC/src/main/resources/plugin.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
classpath=net.simon987.npcplugin.NpcPlugin
|
||||||
|
name=NPC Plugin
|
||||||
|
version=1.0
|
||||||
24
Plugin Plant/Plugin Plant.iml
Normal file
24
Plugin Plant/Plugin Plant.iml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<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$/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="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<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" />
|
||||||
|
<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>
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
classpath=net.simon987.plantplugin.PlantPlugin
|
|
||||||
name=Plant Plugin
|
|
||||||
version=1.0
|
|
||||||
32
Plugin Plant/pom.xml
Normal file
32
Plugin Plant/pom.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
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>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.simon987.server</groupId>
|
||||||
|
<artifactId>server</artifactId>
|
||||||
|
<version>1.2a</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
public class BiomassBlob extends GameObject implements InventoryHolder {
|
||||||
|
|
||||||
|
private static final char MAP_INFO = 0x4000;
|
||||||
|
public static final int ID = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yield of the blob, in biomass units
|
||||||
|
*/
|
||||||
|
private int biomassCount;
|
||||||
|
/**
|
||||||
|
* Style of the blob (Only visual)
|
||||||
|
*/
|
||||||
|
// private int style;
|
||||||
|
|
||||||
|
private static final int ITM_BIOMASS = 1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char getMapInfo() {
|
||||||
|
return MAP_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject serialise() {
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
|
json.put("t", ID);
|
||||||
|
json.put("i", getObjectId());
|
||||||
|
json.put("x", getX());
|
||||||
|
json.put("y", getY());
|
||||||
|
json.put("b", biomassCount);
|
||||||
|
// json.put("style", style);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBiomassCount(int biomassCount) {
|
||||||
|
this.biomassCount = biomassCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public int getStyle() {
|
||||||
|
// return style;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void setStyle(int style) {
|
||||||
|
// this.style = style;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static BiomassBlob deserialize(DBObject obj) {
|
||||||
|
|
||||||
|
BiomassBlob biomassBlob = new BiomassBlob();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an object attempts to place an item in this BiomassBlob
|
||||||
|
*
|
||||||
|
* @param item item id (see MarConstants.ITEM_*)
|
||||||
|
* @return Always returns false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean placeItem(int item) {
|
||||||
|
//Why would you want to place an item in a blob?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canTakeItem(int item) {
|
||||||
|
return item == ITM_BIOMASS && biomassCount >= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an object attempts to take an item from this BiomassBlob.
|
||||||
|
* If the object requests biomass, it will be subtracted from biomassCount, and
|
||||||
|
* if it reaches 0, the plant is deleted
|
||||||
|
*
|
||||||
|
* @param item item id (see MarConstants.ITEM_*)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void takeItem(int item) {
|
||||||
|
|
||||||
|
if (item == ITM_BIOMASS) {
|
||||||
|
if (biomassCount > 1) {
|
||||||
|
biomassCount--;
|
||||||
|
} else {
|
||||||
|
//Delete plant
|
||||||
|
setDead(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
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;
|
||||||
|
import net.simon987.server.game.GameObject;
|
||||||
|
import net.simon987.server.io.GameObjectDeserializer;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
|
import net.simon987.server.plugin.ServerPlugin;
|
||||||
|
|
||||||
|
public class BiomassPlugin extends ServerPlugin implements GameObjectDeserializer {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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(DBObject object) {
|
||||||
|
|
||||||
|
int objType = (int) object.get("t");
|
||||||
|
|
||||||
|
if (objType == BiomassBlob.ID) {
|
||||||
|
|
||||||
|
return BiomassBlob.deserialize(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package net.simon987.biomassplugin;
|
||||||
|
|
||||||
|
import net.simon987.server.GameServer;
|
||||||
|
import net.simon987.server.game.World;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class WorldUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a list of biomass blobs for a world
|
||||||
|
*/
|
||||||
|
public static ArrayList<BiomassBlob> generateBlobs(World world, int minCount, int maxCount, int yield) {
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
int blobCount = random.nextInt(maxCount - minCount) + minCount;
|
||||||
|
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
|
||||||
|
int[][] tiles = world.getTileMap().getTiles();
|
||||||
|
int plainCount = 0;
|
||||||
|
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
||||||
|
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
||||||
|
|
||||||
|
if (tiles[x][y] == 0) {
|
||||||
|
plainCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blobCount > plainCount) {
|
||||||
|
blobCount = plainCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
outerLoop:
|
||||||
|
for (int i = 0; i < blobCount; i++) {
|
||||||
|
|
||||||
|
Point p = world.getTileMap().getRandomPlainTile();
|
||||||
|
if (p != null) {
|
||||||
|
|
||||||
|
//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.getGameObjectsAt(p.x, p.y).size() != 0) {
|
||||||
|
p = world.getTileMap().getRandomPlainTile();
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
if (counter > 25) {
|
||||||
|
continue outerLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BiomassBlob biomassBlob : biomassBlobs) {
|
||||||
|
if (biomassBlob.getX() == p.x && biomassBlob.getY() == p.y) {
|
||||||
|
//There is already a blob here
|
||||||
|
continue outerLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(yield);
|
||||||
|
biomassBlob.setX(p.x);
|
||||||
|
biomassBlob.setY(p.y);
|
||||||
|
biomassBlob.setWorld(world);
|
||||||
|
|
||||||
|
biomassBlobs.add(biomassBlob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager.LOGGER.info("Generated " + biomassBlobs.size() + " biomassBlobs for World (" + world.getX() + ',' +
|
||||||
|
world.getY() + ')');
|
||||||
|
|
||||||
|
return biomassBlobs;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package net.simon987.biomassplugin.event;
|
||||||
|
|
||||||
|
import net.simon987.biomassplugin.BiomassBlob;
|
||||||
|
import net.simon987.biomassplugin.WorldUtils;
|
||||||
|
import net.simon987.server.GameServer;
|
||||||
|
import net.simon987.server.event.GameEvent;
|
||||||
|
import net.simon987.server.event.GameEventListener;
|
||||||
|
import net.simon987.server.event.WorldGenerationEvent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class WorldCreationListener implements GameEventListener {
|
||||||
|
@Override
|
||||||
|
public Class getListenedEventType() {
|
||||||
|
return WorldGenerationEvent.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(GameEvent event) {
|
||||||
|
|
||||||
|
int minCount = GameServer.INSTANCE.getConfig().getInt("minBiomassCount");
|
||||||
|
int maxCount = GameServer.INSTANCE.getConfig().getInt("maxBiomassCount");
|
||||||
|
int yield = GameServer.INSTANCE.getConfig().getInt("biomass_yield");
|
||||||
|
|
||||||
|
ArrayList<BiomassBlob> biomassBlobs = WorldUtils.generateBlobs(((WorldGenerationEvent) event).getWorld(),
|
||||||
|
minCount, maxCount, yield);
|
||||||
|
|
||||||
|
for (BiomassBlob blob : biomassBlobs) {
|
||||||
|
((WorldGenerationEvent) event).getWorld().addObject(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package net.simon987.biomassplugin.event;
|
||||||
|
|
||||||
|
import net.simon987.biomassplugin.BiomassBlob;
|
||||||
|
import net.simon987.biomassplugin.WorldUtils;
|
||||||
|
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.WorldUpdateEvent;
|
||||||
|
import net.simon987.server.game.World;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
|
public class WorldUpdateListener implements GameEventListener {
|
||||||
|
|
||||||
|
private HashMap<World, Long> worldWaitMap = new HashMap<>(200);
|
||||||
|
|
||||||
|
private static int minBlobCount;
|
||||||
|
private static int maxBlobCount;
|
||||||
|
private static int blobYield;
|
||||||
|
private static int waitTime;
|
||||||
|
private static int blobThreshold;
|
||||||
|
|
||||||
|
public WorldUpdateListener(ServerConfiguration config) {
|
||||||
|
|
||||||
|
minBlobCount = config.getInt("minBiomassRespawnCount");
|
||||||
|
maxBlobCount = config.getInt("maxBiomassRespawnCount");
|
||||||
|
waitTime = config.getInt("biomassRespawnTime");
|
||||||
|
blobThreshold = config.getInt("biomassRespawnThreshold");
|
||||||
|
blobYield = config.getInt("biomass_yield");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class getListenedEventType() {
|
||||||
|
return WorldUpdateEvent.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(GameEvent event) {
|
||||||
|
|
||||||
|
World world = ((WorldUpdateEvent) event).getWorld();
|
||||||
|
|
||||||
|
//If there is less than the respawn threshold,
|
||||||
|
if (world.findObjects(BiomassBlob.class).size() < blobThreshold) {
|
||||||
|
|
||||||
|
//Set a timer for respawn_time ticks
|
||||||
|
if (!worldWaitMap.containsKey(world) || worldWaitMap.get(world) == 0L) {
|
||||||
|
worldWaitMap.put(world, GameServer.INSTANCE.getGameUniverse().getTime() + waitTime);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
long waitUntil = worldWaitMap.get(world);
|
||||||
|
|
||||||
|
if (GameServer.INSTANCE.getGameUniverse().getTime() >= waitUntil) {
|
||||||
|
|
||||||
|
//If the timer was set less than respawn_time ticks ago, respawn the blobs
|
||||||
|
ArrayList<BiomassBlob> newBlobs = WorldUtils.generateBlobs(world, minBlobCount,
|
||||||
|
maxBlobCount, blobYield);
|
||||||
|
for (BiomassBlob blob : newBlobs) {
|
||||||
|
world.addObject(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set the 'waitUntil' time to 0 to indicate that we are not waiting
|
||||||
|
worldWaitMap.replace(world, 0L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Plugin Plant/src/main/resources/plugin.properties
Normal file
3
Plugin Plant/src/main/resources/plugin.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
classpath=net.simon987.biomassplugin.BiomassPlugin
|
||||||
|
name=Biomass Plugin
|
||||||
|
version=1.0
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
package net.simon987.plantplugin;
|
|
||||||
|
|
||||||
import net.simon987.server.GameServer;
|
|
||||||
import net.simon987.server.game.GameObject;
|
|
||||||
import net.simon987.server.game.InventoryHolder;
|
|
||||||
import net.simon987.server.game.Updatable;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public class Plant extends GameObject implements Updatable, InventoryHolder{
|
|
||||||
|
|
||||||
private static final char MAP_INFO = 0x4000;
|
|
||||||
public static final int ID = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Grow time (see config.properties)
|
|
||||||
*/
|
|
||||||
private static final int GROW_TIME = GameServer.INSTANCE.getConfig().getInt("plant_grow_time");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Game time of the creation of this Plant
|
|
||||||
*/
|
|
||||||
private long creationTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the plant is grown or not
|
|
||||||
*/
|
|
||||||
private boolean grown;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Yield of the plant, in biomass units
|
|
||||||
*/
|
|
||||||
private int biomassCount;
|
|
||||||
/**
|
|
||||||
* Style of the plant (Only visual)
|
|
||||||
*/
|
|
||||||
private int style;
|
|
||||||
|
|
||||||
private static final int ITM_BIOMASS = 1;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char getMapInfo() {
|
|
||||||
return MAP_INFO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JSONObject serialise() {
|
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
|
|
||||||
json.put("type", ID);
|
|
||||||
json.put("id", getObjectId());
|
|
||||||
json.put("x", getX());
|
|
||||||
json.put("y", getY());
|
|
||||||
json.put("creationTime", creationTime);
|
|
||||||
json.put("grown", grown);
|
|
||||||
json.put("biomassCount", biomassCount);
|
|
||||||
json.put("style", style);
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called every tick
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
if (!grown) {
|
|
||||||
//Check grow
|
|
||||||
if (creationTime + GROW_TIME <= GameServer.INSTANCE.getGameUniverse().getTime()) {
|
|
||||||
grown = true;
|
|
||||||
biomassCount = GameServer.INSTANCE.getConfig().getInt("plant_yield");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCreationTime() {
|
|
||||||
return creationTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreationTime(long creationTime) {
|
|
||||||
this.creationTime = creationTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGrown() {
|
|
||||||
return grown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGrown(boolean grown) {
|
|
||||||
this.grown = grown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBiomassCount() {
|
|
||||||
return biomassCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBiomassCount(int biomassCount) {
|
|
||||||
this.biomassCount = biomassCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStyle() {
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStyle(int style) {
|
|
||||||
this.style = style;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Plant deserialize(JSONObject json){
|
|
||||||
|
|
||||||
Plant plant = new Plant();
|
|
||||||
|
|
||||||
plant.setObjectId((int)(long)json.get("id"));
|
|
||||||
plant.setX((int)(long)json.get("x"));
|
|
||||||
plant.setY((int)(long)json.get("y"));
|
|
||||||
plant.grown = (boolean)json.get("grown");
|
|
||||||
plant.creationTime = (long)json.get("creationTime");
|
|
||||||
plant.style = (int)(long)json.get("style");
|
|
||||||
plant.biomassCount = (int)(long)json.get("biomassCount");
|
|
||||||
|
|
||||||
return plant;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when an object attempts to place an item in this Plant
|
|
||||||
*
|
|
||||||
* @param item item id (see MarConstants.ITEM_*)
|
|
||||||
* @return Always returns false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean placeItem(int item) {
|
|
||||||
//Why would you want to place an item in a plant?
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canTakeItem(int item) {
|
|
||||||
return item == ITM_BIOMASS && grown && biomassCount >= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when an object attempts to take an item from this Plant.
|
|
||||||
* If the object requests biomass, it will be subtracted from biomassCount, and
|
|
||||||
* if it reaches 0, the plant is deleted
|
|
||||||
*
|
|
||||||
* @param item item id (see MarConstants.ITEM_*)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void takeItem(int item) {
|
|
||||||
|
|
||||||
if (item == ITM_BIOMASS) {
|
|
||||||
if (grown && biomassCount > 1) {
|
|
||||||
biomassCount--;
|
|
||||||
} else if (grown) {
|
|
||||||
//Delete plant
|
|
||||||
setDead(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package net.simon987.plantplugin;
|
|
||||||
|
|
||||||
import net.simon987.plantplugin.event.WorldCreationListener;
|
|
||||||
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 PlantPlugin extends ServerPlugin implements GameObjectDeserializer {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init() {
|
|
||||||
listeners.add(new WorldCreationListener());
|
|
||||||
LogManager.LOGGER.info("Initialised Plant plugin");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GameObject deserializeObject(JSONObject object) {
|
|
||||||
|
|
||||||
int objType = (int)(long)object.get("type");
|
|
||||||
|
|
||||||
if(objType == Plant.ID) {
|
|
||||||
|
|
||||||
return Plant.deserialize(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
package net.simon987.plantplugin.event;
|
|
||||||
|
|
||||||
import net.simon987.plantplugin.Plant;
|
|
||||||
import net.simon987.server.GameServer;
|
|
||||||
import net.simon987.server.event.GameEvent;
|
|
||||||
import net.simon987.server.event.GameEventListener;
|
|
||||||
import net.simon987.server.event.WorldGenerationEvent;
|
|
||||||
import net.simon987.server.game.World;
|
|
||||||
import net.simon987.server.logging.LogManager;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class WorldCreationListener implements GameEventListener {
|
|
||||||
@Override
|
|
||||||
public Class getListenedEventType() {
|
|
||||||
return WorldGenerationEvent.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(GameEvent event) {
|
|
||||||
|
|
||||||
ArrayList<Plant> plants = generatePlants(((WorldGenerationEvent)event).getWorld());
|
|
||||||
|
|
||||||
((WorldGenerationEvent)event).getWorld().getGameObjects().addAll(plants);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a list of plants for a world
|
|
||||||
*/
|
|
||||||
public ArrayList<Plant> generatePlants(World world) {
|
|
||||||
|
|
||||||
int minTreeCount = GameServer.INSTANCE.getConfig().getInt("minTreeCount");
|
|
||||||
int maxTreeCount = GameServer.INSTANCE.getConfig().getInt("maxTreeCount");
|
|
||||||
int plant_yield = GameServer.INSTANCE.getConfig().getInt("plant_yield");
|
|
||||||
|
|
||||||
Random random = new Random();
|
|
||||||
int treeCount = random.nextInt(maxTreeCount - minTreeCount) + minTreeCount;
|
|
||||||
ArrayList<Plant> plants = new ArrayList<>(maxTreeCount);
|
|
||||||
|
|
||||||
//Count number of plain tiles. If there is less plain tiles than desired amount of trees,
|
|
||||||
//set the desired amount of trees to the plain tile count
|
|
||||||
int[][] tiles = world.getTileMap().getTiles();
|
|
||||||
int plainCount = 0;
|
|
||||||
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
|
||||||
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
|
||||||
|
|
||||||
if (tiles[x][y] == 0) {
|
|
||||||
plainCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (treeCount > plainCount) {
|
|
||||||
treeCount = plainCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
outerLoop:
|
|
||||||
for (int i = 0; i < treeCount; i++) {
|
|
||||||
|
|
||||||
Point p = world.getTileMap().getRandomPlainTile();
|
|
||||||
if (p != null) {
|
|
||||||
|
|
||||||
//Don't block worlds
|
|
||||||
while (p.x == 0 || p.y == 0 || p.x == World.WORLD_SIZE - 1 || p.y == World.WORLD_SIZE - 1) {
|
|
||||||
p = world.getTileMap().getRandomPlainTile();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Plant plant : plants) {
|
|
||||||
if (plant.getX() == p.x && plant.getY() == p.y) {
|
|
||||||
//There is already a plant here
|
|
||||||
continue outerLoop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Plant plant = new Plant();
|
|
||||||
plant.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
|
||||||
plant.setStyle(0); //TODO: set style depending on difficulty level? or random? from config?
|
|
||||||
plant.setBiomassCount(plant_yield);
|
|
||||||
plant.setCreationTime(0); // Plants generated by the world generator always have creationTime of 0
|
|
||||||
plant.setX(p.x);
|
|
||||||
plant.setY(p.y);
|
|
||||||
plant.setWorld(world);
|
|
||||||
|
|
||||||
plants.add(plant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LogManager.LOGGER.info("Generated " + plants.size() + " plants for World (" + world.getX() + ',' +
|
|
||||||
world.getY() + ')');
|
|
||||||
|
|
||||||
return plants;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
79
README.md
79
README.md
@@ -4,8 +4,83 @@ In its current state, players can walk around the game universe and collect Biom
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Wiki: [GitHub](https://github.com/simon987/Much-Assembly-Required/wiki)
|
Wiki: [GitHub](https://github.com/simon987/Much-Assembly-Required/wiki)
|
||||||
Chat: [Slack](https://join.slack.com/t/muchassemblyrequired/shared_invite/enQtMjY3Mjc1OTUwNjEwLTkyOTIwOTA5OGY4MDVlMGI4NzM5YzlhMWJiMGY1OWE2NjUxODQ1NWQ1YTcxMTA1NGZkYzNjYzMyM2E1ODdmNzg)
|
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!
|
||||||
|
|||||||
23
Server/Server.iml
Normal file
23
Server/Server.iml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<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$/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="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>
|
||||||
134
Server/pom.xml
Normal file
134
Server/pom.xml
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
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>
|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<source>1.8</source>
|
||||||
|
<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>
|
||||||
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
|
<version>1.3.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>5.1.42</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<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>
|
||||||
277
Server/src/main/java/net/simon987/server/GameServer.java
Normal file
277
Server/src/main/java/net/simon987/server/GameServer.java
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
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.logging.LogManager;
|
||||||
|
import net.simon987.server.plugin.PluginManager;
|
||||||
|
import net.simon987.server.user.User;
|
||||||
|
import net.simon987.server.webserver.SocketServer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
public class GameServer implements Runnable {
|
||||||
|
|
||||||
|
public final static GameServer INSTANCE = new GameServer();
|
||||||
|
|
||||||
|
private GameUniverse gameUniverse;
|
||||||
|
private GameEventDispatcher eventDispatcher;
|
||||||
|
private PluginManager pluginManager;
|
||||||
|
|
||||||
|
private ServerConfiguration config;
|
||||||
|
|
||||||
|
private SocketServer socketServer;
|
||||||
|
|
||||||
|
private int maxExecutionTime;
|
||||||
|
|
||||||
|
private DayNightCycle dayNightCycle;
|
||||||
|
|
||||||
|
private MongoClient mongo = null;
|
||||||
|
|
||||||
|
public GameServer() {
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
|
||||||
|
dayNightCycle = new DayNightCycle();
|
||||||
|
|
||||||
|
//Load all plugins in plugins folder, if it doesn't exist, create it
|
||||||
|
File pluginDir = new File("plugins/");
|
||||||
|
File[] pluginDirListing = pluginDir.listFiles();
|
||||||
|
|
||||||
|
if (pluginDirListing != null) {
|
||||||
|
for (File pluginFile : pluginDirListing) {
|
||||||
|
|
||||||
|
if (pluginFile.getName().endsWith(".jar")) {
|
||||||
|
pluginManager.load(pluginFile, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!pluginDir.mkdir()) {
|
||||||
|
LogManager.LOGGER.severe("Couldn't create plugin directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventDispatcher = new GameEventDispatcher(pluginManager);
|
||||||
|
eventDispatcher.getListeners().add(dayNightCycle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameUniverse getGameUniverse() {
|
||||||
|
return gameUniverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameEventDispatcher getEventDispatcher() {
|
||||||
|
return eventDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
LogManager.LOGGER.info("(G) Started game loop");
|
||||||
|
|
||||||
|
long startTime; //Start time of the loop
|
||||||
|
long uTime; //update time
|
||||||
|
long waitTime; //time to wait
|
||||||
|
|
||||||
|
boolean running = true;
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
tick();
|
||||||
|
|
||||||
|
uTime = System.currentTimeMillis() - startTime;
|
||||||
|
waitTime = config.getInt("tick_length") - uTime;
|
||||||
|
|
||||||
|
LogManager.LOGGER.info("Wait time : " + waitTime + "ms | Update time: " + uTime + "ms | " + (int) (((double) uTime / waitTime) * 100) + "% load");
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (waitTime >= 0) {
|
||||||
|
Thread.sleep(waitTime);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tick() {
|
||||||
|
gameUniverse.incrementTime();
|
||||||
|
|
||||||
|
//Dispatch tick event
|
||||||
|
GameEvent event = new TickEvent(gameUniverse.getTime());
|
||||||
|
eventDispatcher.dispatch(event); //Ignore cancellation
|
||||||
|
|
||||||
|
|
||||||
|
//Process user code
|
||||||
|
for (User user : gameUniverse.getUsers()) {
|
||||||
|
|
||||||
|
if (user.getCpu() != null) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
int timeout = Math.min(user.getControlledUnit().getEnergy(), maxExecutionTime);
|
||||||
|
|
||||||
|
user.getCpu().reset();
|
||||||
|
int cost = user.getCpu().execute(timeout);
|
||||||
|
user.getControlledUnit().spendEnergy(cost);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.LOGGER.severe("Error executing " + user.getUsername() + "'s code");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Process each worlds
|
||||||
|
int updatedWorlds = 0;
|
||||||
|
for (World world : gameUniverse.getWorlds()) {
|
||||||
|
if (world.shouldUpdate()) {
|
||||||
|
world.update();
|
||||||
|
updatedWorlds++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Save
|
||||||
|
if (gameUniverse.getTime() % config.getInt("save_interval") == 0) {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
socketServer.tick();
|
||||||
|
|
||||||
|
LogManager.LOGGER.info("Processed " + gameUniverse.getWorldCount() + " worlds (" + updatedWorlds +
|
||||||
|
") updated");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void load() {
|
||||||
|
|
||||||
|
LogManager.LOGGER.info("Loading all data from MongoDB");
|
||||||
|
|
||||||
|
DB db = mongo.getDB("mar");
|
||||||
|
|
||||||
|
DBCollection worlds = db.getCollection("world");
|
||||||
|
DBCollection users = db.getCollection("user");
|
||||||
|
DBCollection server = db.getCollection("server");
|
||||||
|
|
||||||
|
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() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginManager getPluginManager() {
|
||||||
|
return pluginManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSocketServer(SocketServer socketServer) {
|
||||||
|
this.socketServer = socketServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DayNightCycle getDayNightCycle() {
|
||||||
|
return dayNightCycle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,19 +3,17 @@ package net.simon987.server;
|
|||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
import net.simon987.server.webserver.SocketServer;
|
import net.simon987.server.webserver.SocketServer;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args){
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||||
LogManager.initialize();
|
LogManager.initialize(config);
|
||||||
ServerConfiguration config = new ServerConfiguration(new File("config.properties"));
|
|
||||||
|
|
||||||
//Load
|
//Load
|
||||||
GameServer.INSTANCE.getGameUniverse().load(new File("save.json"));
|
GameServer.INSTANCE.load();
|
||||||
|
|
||||||
SocketServer socketServer = new SocketServer(new InetSocketAddress(config.getString("webSocket_host"),
|
SocketServer socketServer = new SocketServer(new InetSocketAddress(config.getString("webSocket_host"),
|
||||||
config.getInt("webSocket_port")), config);
|
config.getInt("webSocket_port")), config);
|
||||||
@@ -6,6 +6,7 @@ import net.simon987.server.logging.LogManager;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,11 +19,11 @@ public class ServerConfiguration {
|
|||||||
*/
|
*/
|
||||||
private Properties properties;
|
private Properties properties;
|
||||||
|
|
||||||
public ServerConfiguration(File file) {
|
public ServerConfiguration(String file) {
|
||||||
try {
|
try {
|
||||||
properties = new Properties();
|
properties = new Properties();
|
||||||
|
InputStream is = new FileInputStream("config.properties");
|
||||||
properties.load(new FileInputStream(file));
|
properties.load(is);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LogManager.LOGGER.severe("Problem loading server configuration: " + e.getMessage());
|
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.ServerConfiguration;
|
||||||
import net.simon987.server.assembly.exception.*;
|
import net.simon987.server.assembly.exception.*;
|
||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
|
import org.apache.commons.text.StringEscapeUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top-level class for assembly operations.
|
* Top-level class for assembly operations.
|
||||||
@@ -20,6 +24,8 @@ public class Assembler {
|
|||||||
|
|
||||||
private RegisterSet registerSet;
|
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) {
|
public Assembler(InstructionSet instructionSet, RegisterSet registerSet, ServerConfiguration config) {
|
||||||
this.instructionSet = instructionSet;
|
this.instructionSet = instructionSet;
|
||||||
this.registerSet = registerSet;
|
this.registerSet = registerSet;
|
||||||
@@ -47,11 +53,9 @@ public class Assembler {
|
|||||||
* @return The line without its label part
|
* @return The line without its label part
|
||||||
*/
|
*/
|
||||||
private static String removeLabel(String line) {
|
private static String removeLabel(String line) {
|
||||||
if (line.indexOf(':') != -1) {
|
|
||||||
return line.substring(line.indexOf(':') + 1);
|
return line.replaceAll("^\\s*\\b\\w*\\b:", "");
|
||||||
} else {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,10 +97,11 @@ public class Assembler {
|
|||||||
line = removeComment(line);
|
line = removeComment(line);
|
||||||
|
|
||||||
//Check for labels
|
//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(':'));
|
if (matcher.find()) {
|
||||||
String label = line.trim();
|
String label = matcher.group(0).substring(0, matcher.group(0).length() - 1).trim();
|
||||||
|
|
||||||
LogManager.LOGGER.fine("DEBUG: Label " + label + " @ " + (result.origin + currentOffset));
|
LogManager.LOGGER.fine("DEBUG: Label " + label + " @ " + (result.origin + currentOffset));
|
||||||
result.labels.put(label, (char) (result.origin + currentOffset));
|
result.labels.put(label, (char) (result.origin + currentOffset));
|
||||||
@@ -129,11 +134,12 @@ public class Assembler {
|
|||||||
|
|
||||||
//System.out.println(line);
|
//System.out.println(line);
|
||||||
|
|
||||||
if (line.substring(0, 2).toUpperCase().equals("DW")) {
|
if (line.length() >= 2 && line.substring(0, 2).toUpperCase().equals("DW")) {
|
||||||
|
|
||||||
try {
|
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) {
|
for (String value : values) {
|
||||||
|
|
||||||
@@ -144,6 +150,14 @@ public class Assembler {
|
|||||||
//Handle DUP operator
|
//Handle DUP operator
|
||||||
if (valueTokens.length == 2 && valueTokens[1].toUpperCase().contains("DUP(")) {
|
if (valueTokens.length == 2 && valueTokens[1].toUpperCase().contains("DUP(")) {
|
||||||
out.write(parseDUPOperator16(valueTokens, labels, currentLine));
|
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)) {
|
} else if (labels != null && labels.containsKey(value)) {
|
||||||
//Handle label
|
//Handle label
|
||||||
out.writeChar(labels.get(value));
|
out.writeChar(labels.get(value));
|
||||||
@@ -161,7 +175,18 @@ public class Assembler {
|
|||||||
out.writeChar(0);
|
out.writeChar(0);
|
||||||
|
|
||||||
} else {
|
} 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 {
|
try {
|
||||||
|
|
||||||
int factor = Integer.decode(valueTokens[0]);
|
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(')'));
|
String value = valueTokens[1].substring(4, valueTokens[1].lastIndexOf(')'));
|
||||||
|
|
||||||
//Handle label
|
//Handle label
|
||||||
@@ -208,7 +238,7 @@ public class Assembler {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
//Handle integer value
|
//Handle integer value
|
||||||
char s = (char)(int)Integer.decode(value);
|
char s = (char) (int) Integer.decode(value);
|
||||||
|
|
||||||
for (int i = 0; i < factor; i++) {
|
for (int i = 0; i < factor; i++) {
|
||||||
out.write(Util.getHigherByte(s));
|
out.write(Util.getHigherByte(s));
|
||||||
@@ -237,23 +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
|
* @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 {
|
int currentLine, int currentOffset) throws AssemblyException {
|
||||||
|
|
||||||
String[] tokens = line.split("\\s+");
|
String[] tokens = line.split("\\s+");
|
||||||
|
|
||||||
if (tokens[0].toUpperCase().equals(".TEXT")) {
|
if (tokens[0].toUpperCase().equals(".TEXT")) {
|
||||||
|
|
||||||
result.defineSegment(Segment.TEXT, currentLine, currentOffset);
|
result.defineSecton(Section.TEXT, currentLine, currentOffset);
|
||||||
throw new PseudoInstructionException(currentLine);
|
throw new PseudoInstructionException(currentLine);
|
||||||
|
|
||||||
} else if (tokens[0].toUpperCase().equals(".DATA")) {
|
} else if (tokens[0].toUpperCase().equals(".DATA")) {
|
||||||
|
|
||||||
result.defineSegment(Segment.DATA, currentLine, currentOffset);
|
LogManager.LOGGER.fine("DEBUG: .data @" + currentLine);
|
||||||
|
|
||||||
|
result.defineSecton(Section.DATA, currentLine, currentOffset);
|
||||||
throw new PseudoInstructionException(currentLine);
|
throw new PseudoInstructionException(currentLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,11 +307,11 @@ public class Assembler {
|
|||||||
String[] tokens = line.split("\\s+");
|
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) {
|
if (tokens[1].toUpperCase().equals("EQU") && tokens.length == 3) {
|
||||||
try {
|
try {
|
||||||
//Save value as a label
|
//Save value as a label
|
||||||
labels.put(tokens[0], (char)(int)Integer.decode(tokens[2]));
|
labels.put(tokens[0], (char) (int) Integer.decode(tokens[2]));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new InvalidOperandException("Usage: constant_name EQU immediate_value", currentLine);
|
throw new InvalidOperandException("Usage: constant_name EQU immediate_value", currentLine);
|
||||||
}
|
}
|
||||||
@@ -327,17 +359,23 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Pass 2: Save label names and location
|
//Pass 2: Save label names and location
|
||||||
char currentOffset = 0;
|
int currentOffset = 0;
|
||||||
for (currentLine = 0; currentLine < lines.length; currentLine++) {
|
for (currentLine = 0; currentLine < lines.length; currentLine++) {
|
||||||
try {
|
try {
|
||||||
checkForLabel(lines[currentLine], result, currentOffset);
|
checkForLabel(lines[currentLine], result, (char)currentOffset);
|
||||||
|
|
||||||
//Increment offset
|
//Increment offset
|
||||||
currentOffset += parseInstruction(lines[currentLine], currentLine, instructionSet).length / 2;
|
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
|
//Ignore error on pass 2
|
||||||
//System.out.println(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,17 +396,26 @@ public class Assembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Check for pseudo instructions
|
//Check for pseudo instructions
|
||||||
checkForSegmentDeclaration(line, result, currentLine, currentOffset);
|
checkForSectionDeclaration(line, result, currentLine, currentOffset);
|
||||||
checkForEQUInstruction(line, result.labels, currentLine);
|
checkForEQUInstruction(line, result.labels, currentLine);
|
||||||
checkForORGInstruction(line, result, currentLine);
|
checkForORGInstruction(line, result, currentLine);
|
||||||
|
|
||||||
//Encode instruction
|
//Encode instruction
|
||||||
byte[] bytes = parseInstruction(line, currentLine, result.labels, instructionSet);
|
byte[] bytes = parseInstruction(line, currentLine, result.labels, instructionSet);
|
||||||
currentOffset += bytes.length / 2;
|
currentOffset += bytes.length / 2;
|
||||||
|
|
||||||
|
if (currentOffset >= MEM_SIZE) {
|
||||||
|
throw new OffsetOverflowException(currentOffset, MEM_SIZE, currentLine);
|
||||||
|
}
|
||||||
|
|
||||||
out.write(bytes);
|
out.write(bytes);
|
||||||
|
|
||||||
} catch (EmptyLineException | PseudoInstructionException e) {
|
} catch (EmptyLineException | PseudoInstructionException e) {
|
||||||
//Ignore empty lines and pseudo-instructions
|
//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) {
|
} catch (AssemblyException asmE) {
|
||||||
//Save errors on pass3
|
//Save errors on pass3
|
||||||
result.exceptions.add(asmE);
|
result.exceptions.add(asmE);
|
||||||
@@ -377,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)");
|
LogManager.LOGGER.info("Assembled " + result.bytes.length + " bytes (" + result.exceptions.size() + " errors)");
|
||||||
for (AssemblyException e : result.exceptions) {
|
for (AssemblyException e : result.exceptions) {
|
||||||
124
Server/src/main/java/net/simon987/server/assembly/AssemblyResult.java
Executable file
124
Server/src/main/java/net/simon987/server/assembly/AssemblyResult.java
Executable file
@@ -0,0 +1,124 @@
|
|||||||
|
package net.simon987.server.assembly;
|
||||||
|
|
||||||
|
import net.simon987.server.ServerConfiguration;
|
||||||
|
import net.simon987.server.assembly.exception.AssemblyException;
|
||||||
|
import net.simon987.server.assembly.exception.DuplicateSectionException;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of an assembly attempt
|
||||||
|
*/
|
||||||
|
public class AssemblyResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The origin of the program, default is 0x200
|
||||||
|
*/
|
||||||
|
public int origin;
|
||||||
|
/**
|
||||||
|
* A list of labels
|
||||||
|
*/
|
||||||
|
HashMap<String, Character> labels = new HashMap<>(20);
|
||||||
|
/**
|
||||||
|
* List of exceptions encountered during the assembly attempt,
|
||||||
|
* they will be displayed in the editor
|
||||||
|
*/
|
||||||
|
public ArrayList<AssemblyException> exceptions = new ArrayList<>(50);
|
||||||
|
/**
|
||||||
|
* Offset of the code segment
|
||||||
|
*/
|
||||||
|
private int codeSectionOffset;
|
||||||
|
/**
|
||||||
|
* Line of the code segment definition
|
||||||
|
*/
|
||||||
|
private int codeSectionLine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoded user code (will be incomplete or invalid if the
|
||||||
|
* assembler encountered an error during assembly)
|
||||||
|
*/
|
||||||
|
public byte[] bytes;
|
||||||
|
/**
|
||||||
|
* Offset of the data segment
|
||||||
|
*/
|
||||||
|
private int dataSectionOffset;
|
||||||
|
/**
|
||||||
|
* Line of the data segment definition
|
||||||
|
*/
|
||||||
|
private int dataSectionLine;
|
||||||
|
/**
|
||||||
|
* Whether or not the code segment is set
|
||||||
|
*/
|
||||||
|
private boolean codeSectionSet = false;
|
||||||
|
/**
|
||||||
|
* Whether or not the data segment is set
|
||||||
|
*/
|
||||||
|
private boolean dataSectionSet = false;
|
||||||
|
|
||||||
|
AssemblyResult(ServerConfiguration config) {
|
||||||
|
origin = config.getInt("org_offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a section.
|
||||||
|
*
|
||||||
|
* @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 defineSecton(Section section, int currentLine, int currentOffset) throws DuplicateSectionException {
|
||||||
|
|
||||||
|
if (section == Section.TEXT) {
|
||||||
|
//Code section
|
||||||
|
|
||||||
|
if (!codeSectionSet) {
|
||||||
|
codeSectionOffset = origin + currentOffset;
|
||||||
|
codeSectionLine = currentLine;
|
||||||
|
|
||||||
|
LogManager.LOGGER.fine("DEBUG: .text offset @" + codeSectionOffset);
|
||||||
|
|
||||||
|
|
||||||
|
codeSectionSet = true;
|
||||||
|
} else {
|
||||||
|
throw new DuplicateSectionException(currentLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//Data section
|
||||||
|
if (!dataSectionSet) {
|
||||||
|
dataSectionOffset = origin + currentOffset;
|
||||||
|
dataSectionLine = currentLine;
|
||||||
|
|
||||||
|
LogManager.LOGGER.fine("DEBUG: .data offset @" + dataSectionOffset);
|
||||||
|
|
||||||
|
dataSectionSet = true;
|
||||||
|
} else {
|
||||||
|
throw new DuplicateSectionException(currentLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getWords() {
|
||||||
|
|
||||||
|
char[] assembledCode = new char[bytes.length / 2];
|
||||||
|
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().get(assembledCode);
|
||||||
|
|
||||||
|
return assembledCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCodeSectionOffset() {
|
||||||
|
if (codeSectionSet) {
|
||||||
|
return codeSectionOffset;
|
||||||
|
} else {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
package net.simon987.server.assembly;
|
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.GameServer;
|
||||||
import net.simon987.server.ServerConfiguration;
|
import net.simon987.server.ServerConfiguration;
|
||||||
import net.simon987.server.assembly.exception.CancelledException;
|
import net.simon987.server.assembly.exception.CancelledException;
|
||||||
import net.simon987.server.assembly.instruction.*;
|
import net.simon987.server.assembly.instruction.*;
|
||||||
import net.simon987.server.event.CpuInitialisationEvent;
|
import net.simon987.server.event.CpuInitialisationEvent;
|
||||||
import net.simon987.server.event.GameEvent;
|
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.logging.LogManager;
|
||||||
import net.simon987.server.user.User;
|
import net.simon987.server.user.User;
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
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 and execute them. A CPU object holds registers objects &
|
||||||
* a Memory object.
|
* 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;
|
private RegisterSet registerSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Offset of the code segment. The code starts to get
|
* Offset of the code section. The code starts to get
|
||||||
* executed at this address each tick. Defaults to 0x4000
|
* 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
|
* Instruction pointer, always points to the next instruction
|
||||||
@@ -60,21 +60,20 @@ public class CPU implements JSONSerialisable{
|
|||||||
|
|
||||||
private ServerConfiguration config;
|
private ServerConfiguration config;
|
||||||
|
|
||||||
private long timeout;
|
|
||||||
|
|
||||||
private int registerSetSize;
|
private int registerSetSize;
|
||||||
|
|
||||||
|
private static final char EXECUTION_COST_ADDR = 0x0050;
|
||||||
|
private static final char EXECUTED_INS_ADDR = 0x0051;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new CPU
|
* Creates a new CPU
|
||||||
*/
|
*/
|
||||||
public CPU(ServerConfiguration config, User user) throws CancelledException{
|
public CPU(ServerConfiguration config, User user) throws CancelledException {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
instructionSet = new DefaultInstructionSet();
|
instructionSet = new DefaultInstructionSet();
|
||||||
registerSet = new DefaultRegisterSet();
|
registerSet = new DefaultRegisterSet();
|
||||||
attachedHardware = new HashMap<>();
|
attachedHardware = new HashMap<>();
|
||||||
codeSegmentOffset = config.getInt("org_offset");
|
codeSectionOffset = config.getInt("org_offset");
|
||||||
|
|
||||||
timeout = config.getInt("user_timeout");
|
|
||||||
|
|
||||||
instructionSet.add(new JmpInstruction(this));
|
instructionSet.add(new JmpInstruction(this));
|
||||||
instructionSet.add(new JnzInstruction(this));
|
instructionSet.add(new JnzInstruction(this));
|
||||||
@@ -98,25 +97,27 @@ public class CPU implements JSONSerialisable{
|
|||||||
instructionSet.add(new JncInstruction(this));
|
instructionSet.add(new JncInstruction(this));
|
||||||
instructionSet.add(new JnoInstruction(this));
|
instructionSet.add(new JnoInstruction(this));
|
||||||
instructionSet.add(new JoInstruction(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();
|
status = new Status();
|
||||||
memory = new Memory(config.getInt("memory_size"));
|
memory = new Memory(config.getInt("memory_size"));
|
||||||
|
|
||||||
GameEvent event = new CpuInitialisationEvent(this, user);
|
GameEvent event = new CpuInitialisationEvent(this, user);
|
||||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
||||||
if(event.isCancelled()){
|
if (event.isCancelled()) {
|
||||||
throw new CancelledException();
|
throw new CancelledException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
status.clear();
|
status.clear();
|
||||||
registerSet.getRegister("SP").setValue(config.getInt("stack_bottom"));
|
ip = codeSectionOffset;
|
||||||
registerSet.getRegister("BP").setValue(config.getInt("stack_bottom"));
|
|
||||||
ip = codeSegmentOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute() {
|
public int execute(int timeout) {
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
@@ -128,10 +129,16 @@ public class CPU implements JSONSerialisable{
|
|||||||
while (!status.isBreakFlag()) {
|
while (!status.isBreakFlag()) {
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
if(counter % 1000 == 0){
|
if (counter % 10000 == 0) {
|
||||||
if (System.currentTimeMillis() >= (startTime + timeout)) {
|
if (System.currentTimeMillis() > (startTime + timeout)) {
|
||||||
LogManager.LOGGER.fine("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double) counter / ((double) timeout / 1000) / 1000000 + "MHz");
|
LogManager.LOGGER.fine("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double) counter / ((double) timeout / 1000) / 1000000 + "MHz");
|
||||||
return;
|
|
||||||
|
//Write execution cost and instruction count to memory
|
||||||
|
memory.set(EXECUTION_COST_ADDR, timeout);
|
||||||
|
memory.set(EXECUTED_INS_ADDR, Util.getHigherWord(counter));
|
||||||
|
memory.set(EXECUTED_INS_ADDR + 1, Util.getLowerWord(counter));
|
||||||
|
|
||||||
|
return timeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,8 +158,17 @@ public class CPU implements JSONSerialisable{
|
|||||||
executeInstruction(instruction, source, destination);
|
executeInstruction(instruction, source, destination);
|
||||||
// LogManager.LOGGER.info(instruction.getMnemonic());
|
// LogManager.LOGGER.info(instruction.getMnemonic());
|
||||||
}
|
}
|
||||||
double elapsed = (System.currentTimeMillis() - startTime);
|
int elapsed = (int) (System.currentTimeMillis() - startTime);
|
||||||
|
|
||||||
LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
|
LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
|
||||||
|
|
||||||
|
|
||||||
|
//Write execution cost and instruction count to memory
|
||||||
|
memory.set(EXECUTION_COST_ADDR, elapsed);
|
||||||
|
memory.set(EXECUTED_INS_ADDR, Util.getHigherWord(counter));
|
||||||
|
memory.set(EXECUTED_INS_ADDR + 1, Util.getLowerWord(counter));
|
||||||
|
|
||||||
|
return elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void executeInstruction(Instruction instruction, int source, int destination) {
|
public void executeInstruction(Instruction instruction, int source, int destination) {
|
||||||
@@ -205,8 +221,7 @@ public class CPU implements JSONSerialisable{
|
|||||||
if (destination == 0) {
|
if (destination == 0) {
|
||||||
//Single operand
|
//Single operand
|
||||||
ip++;
|
ip++;
|
||||||
instruction.execute(sourceValue, status);
|
instruction.execute(memory, memory.get(ip - 1), status);
|
||||||
instruction.execute(memory, memory.get(ip - 1), status); //For POP instruction
|
|
||||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||||
//Destination is an immediate value
|
//Destination is an immediate value
|
||||||
|
|
||||||
@@ -224,7 +239,7 @@ public class CPU implements JSONSerialisable{
|
|||||||
} else if (destination <= registerSetSize * 2) {
|
} else if (destination <= registerSetSize * 2) {
|
||||||
//Destination is [reg]
|
//Destination is [reg]
|
||||||
ip++;
|
ip++;
|
||||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), memory, sourceValue, status);
|
instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status);
|
||||||
} else {
|
} else {
|
||||||
//Assuming that destination is [reg + x]
|
//Assuming that destination is [reg + x]
|
||||||
ip += 2;
|
ip += 2;
|
||||||
@@ -268,7 +283,7 @@ public class CPU implements JSONSerialisable{
|
|||||||
if (destination == 0) {
|
if (destination == 0) {
|
||||||
//Single operand
|
//Single operand
|
||||||
ip++;
|
ip++;
|
||||||
instruction.execute(memory, registerSet.get(source), status);
|
instruction.execute(memory, registerSet.get(source - registerSetSize), status);
|
||||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||||
//Destination is an immediate value
|
//Destination is an immediate value
|
||||||
//this shouldn't happen
|
//this shouldn't happen
|
||||||
@@ -281,11 +296,11 @@ public class CPU implements JSONSerialisable{
|
|||||||
} else if (destination <= registerSetSize) {
|
} else if (destination <= registerSetSize) {
|
||||||
//Destination is a register
|
//Destination is a register
|
||||||
ip++;
|
ip++;
|
||||||
instruction.execute(registerSet, destination, memory, registerSet.get(source), status);
|
instruction.execute(registerSet, destination, memory, registerSet.get(source - registerSetSize), status);
|
||||||
} else if (destination <= registerSetSize * 2) {
|
} else if (destination <= registerSetSize * 2) {
|
||||||
//Destination is [reg]
|
//Destination is [reg]
|
||||||
ip++;
|
ip++;
|
||||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), memory, registerSet.get(source), status);
|
instruction.execute(memory, registerSet.get(destination - registerSetSize), memory, registerSet.get(source - registerSetSize), status);
|
||||||
} else {
|
} else {
|
||||||
//Assuming that destination is [reg + x]
|
//Assuming that destination is [reg + x]
|
||||||
ip += 2;
|
ip += 2;
|
||||||
@@ -313,7 +328,7 @@ public class CPU implements JSONSerialisable{
|
|||||||
ip += 2;
|
ip += 2;
|
||||||
instruction.execute(memory, memory.get(ip - 1), memory,
|
instruction.execute(memory, memory.get(ip - 1), memory,
|
||||||
registerSet.get(source - registerSetSize - registerSetSize) + sourceDisp, status);
|
registerSet.get(source - registerSetSize - registerSetSize) + sourceDisp, status);
|
||||||
} else if (destination < registerSetSize) {
|
} else if (destination <= registerSetSize) {
|
||||||
//Destination is a register
|
//Destination is a register
|
||||||
ip++;
|
ip++;
|
||||||
instruction.execute(registerSet, destination, memory,
|
instruction.execute(registerSet, destination, memory,
|
||||||
@@ -333,47 +348,47 @@ public class CPU implements JSONSerialisable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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());
|
BasicDBList hardwareList = new BasicDBList();
|
||||||
json.put("codeSegmentOffset", codeSegmentOffset);
|
|
||||||
|
|
||||||
JSONArray hardwareList = new JSONArray();
|
for (Integer address : attachedHardware.keySet()) {
|
||||||
|
|
||||||
for(Integer address : attachedHardware.keySet()){
|
|
||||||
|
|
||||||
CpuHardware hardware = attachedHardware.get(address);
|
CpuHardware hardware = attachedHardware.get(address);
|
||||||
|
|
||||||
JSONObject serialisedHw = hardware.serialise();
|
BasicDBObject serialisedHw = hardware.mongoSerialise();
|
||||||
serialisedHw.put("address", address);
|
serialisedHw.put("address", address);
|
||||||
hardwareList.add(serialisedHw);
|
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 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){
|
for (Object serialisedHw : hardwareList) {
|
||||||
CpuHardware hw = CpuHardware.deserialize(serialisedHw);
|
CpuHardware hardware = CpuHardware.deserialize((DBObject) serialisedHw);
|
||||||
hw.setCpu(cpu);
|
hardware.setCpu(cpu);
|
||||||
cpu.attachHardware(hw, (int)(long)serialisedHw.get("address"));
|
cpu.attachHardware(hardware, (int) ((BasicDBObject) serialisedHw).get("address"));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu.memory = Memory.deserialize((JSONObject)json.get("memory"));
|
cpu.memory = Memory.deserialize((DBObject) obj.get("memory"));
|
||||||
cpu.registerSet = RegisterSet.deserialize((JSONObject) json.get("registerSet"));
|
cpu.registerSet = RegisterSet.deserialize((DBObject) obj.get("registerSet"));
|
||||||
|
|
||||||
return cpu;
|
return cpu;
|
||||||
|
|
||||||
@@ -403,22 +418,22 @@ public class CPU implements JSONSerialisable{
|
|||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCodeSegmentOffset(int codeSegmentOffset) {
|
public void setCodeSectionOffset(int codeSectionOffset) {
|
||||||
this.codeSegmentOffset = codeSegmentOffset;
|
this.codeSectionOffset = codeSectionOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachHardware(CpuHardware hardware, int address){
|
public void attachHardware(CpuHardware hardware, int address) {
|
||||||
attachedHardware.put(address, hardware);
|
attachedHardware.put(address, hardware);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void detachHardware(int address){
|
public void detachHardware(int address) {
|
||||||
attachedHardware.remove(address);
|
attachedHardware.remove(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hardwareInterrupt(int address){
|
public boolean hardwareInterrupt(int address) {
|
||||||
CpuHardware hardware = attachedHardware.get(address);
|
CpuHardware hardware = attachedHardware.get(address);
|
||||||
|
|
||||||
if(hardware != null){
|
if (hardware != null) {
|
||||||
hardware.handleInterrupt(status);
|
hardware.handleInterrupt(status);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package net.simon987.server.assembly;
|
package net.simon987.server.assembly;
|
||||||
|
|
||||||
|
|
||||||
|
import com.mongodb.DBObject;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
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 net.simon987.server.plugin.ServerPlugin;
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
|
|
||||||
public abstract class CpuHardware implements JSONSerialisable {
|
public abstract class CpuHardware implements MongoSerialisable {
|
||||||
|
|
||||||
CPU cpu;
|
CPU cpu;
|
||||||
|
|
||||||
@@ -26,14 +26,14 @@ public abstract class CpuHardware implements JSONSerialisable {
|
|||||||
|
|
||||||
public abstract char getId();
|
public abstract char getId();
|
||||||
|
|
||||||
public static CpuHardware deserialize(JSONObject hwJson){
|
public static CpuHardware deserialize(DBObject obj) {
|
||||||
|
|
||||||
for(ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()){
|
for (ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()) {
|
||||||
|
|
||||||
if(plugin instanceof CpuHardwareDeserializer){
|
if (plugin instanceof CpuHardwareDeserializer) {
|
||||||
CpuHardware hw = ((CpuHardwareDeserializer) plugin).deserializeHardware(hwJson);
|
CpuHardware hw = ((CpuHardwareDeserializer) plugin).deserializeHardware(obj);
|
||||||
|
|
||||||
if(hw != null){
|
if (hw != null) {
|
||||||
return hw;
|
return hw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,8 @@ public class DefaultInstructionSet implements InstructionSet {
|
|||||||
add(new RclInstruction());
|
add(new RclInstruction());
|
||||||
add(new RcrInstruction());
|
add(new RcrInstruction());
|
||||||
add(new SarInstruction());
|
add(new SarInstruction());
|
||||||
|
add(new IncInstruction());
|
||||||
|
add(new DecInstruction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,10 +58,10 @@ public class DefaultInstructionSet implements InstructionSet {
|
|||||||
public Instruction get(int opcode) {
|
public Instruction get(int opcode) {
|
||||||
|
|
||||||
Instruction instruction = instructionMap.get(opcode);
|
Instruction instruction = instructionMap.get(opcode);
|
||||||
if(instruction != null){
|
if (instruction != null) {
|
||||||
return instruction;
|
return instruction;
|
||||||
} else {
|
} else {
|
||||||
// System.out.println("Invalid instruction " + opcode);
|
// System.out.println("Invalid instruction " + opcode);
|
||||||
//Todo: Notify user? Set error flag?
|
//Todo: Notify user? Set error flag?
|
||||||
return defaultInstruction;
|
return defaultInstruction;
|
||||||
}
|
}
|
||||||
@@ -120,8 +120,8 @@ public abstract class Instruction {
|
|||||||
* Whether or not the instruction is valid without any
|
* Whether or not the instruction is valid without any
|
||||||
* operands
|
* operands
|
||||||
*/
|
*/
|
||||||
private static boolean noOperandsValid() {
|
public boolean noOperandsValid() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getMnemonic() {
|
String getMnemonic() {
|
||||||
@@ -67,7 +67,6 @@ class MachineCode {
|
|||||||
LogManager.LOGGER.severe("Couldn't write the dst operand for instruction :" + dst);
|
LogManager.LOGGER.severe("Couldn't write the dst operand for instruction :" + dst);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//Src is the 5 most significant bits
|
|
||||||
value &= 0xF83F; //1111 1000 0011 1111
|
value &= 0xF83F; //1111 1000 0011 1111
|
||||||
dst <<= 6; //0000 0XXX XX00 0000
|
dst <<= 6; //0000 0XXX XX00 0000
|
||||||
value |= dst;
|
value |= dst;
|
||||||
167
Server/src/main/java/net/simon987/server/assembly/Memory.java
Executable file
167
Server/src/main/java/net/simon987/server/assembly/Memory.java
Executable file
@@ -0,0 +1,167 @@
|
|||||||
|
package net.simon987.server.assembly;
|
||||||
|
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
import net.simon987.server.GameServer;
|
||||||
|
import net.simon987.server.io.MongoSerialisable;
|
||||||
|
import net.simon987.server.logging.LogManager;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
import java.util.zip.InflaterOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the available memory for a CPU in the game universe
|
||||||
|
*/
|
||||||
|
public class Memory implements Target, MongoSerialisable {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contents of the memory
|
||||||
|
*/
|
||||||
|
private char[] words;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an empty Memory object
|
||||||
|
*
|
||||||
|
* @param size Size of the memory, in words
|
||||||
|
*/
|
||||||
|
public Memory(int size) {
|
||||||
|
words = new char[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value at an address
|
||||||
|
*
|
||||||
|
* @param address Address of the value
|
||||||
|
* @return 16-bit value at the specified address
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int get(int address) {
|
||||||
|
address = (char) address;
|
||||||
|
|
||||||
|
if (address >= words.length) {
|
||||||
|
LogManager.LOGGER.info("DEBUG: Trying to get memory out of bounds " + address);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return words[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write x words from an array at an offset
|
||||||
|
*/
|
||||||
|
public boolean write(int offset, char[] src, int srcOffset, int count) {
|
||||||
|
|
||||||
|
if (offset + count > this.words.length || srcOffset >= src.length || count < 0 || offset < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(src, srcOffset, this.words, offset, count);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value at an address
|
||||||
|
*
|
||||||
|
* @param address address of the value to change
|
||||||
|
* @param value 16-bit value to set
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void set(int address, int value) {
|
||||||
|
address = (char) address;
|
||||||
|
|
||||||
|
if (address >= words.length) {
|
||||||
|
LogManager.LOGGER.info("DEBUG: Trying to set memory out of bounds: " + address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
words[address] = (char) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the memory with 0s
|
||||||
|
*/
|
||||||
|
public void clear() {
|
||||||
|
Arrays.fill(words, (char) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get byte array of the Memory object
|
||||||
|
*/
|
||||||
|
public byte[] getBytes() {
|
||||||
|
|
||||||
|
byte[] bytes = new byte[words.length * 2];
|
||||||
|
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().put(words);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BasicDBObject mongoSerialise() {
|
||||||
|
|
||||||
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
Deflater compressor = new Deflater(Deflater.BEST_SPEED, true);
|
||||||
|
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(stream, compressor);
|
||||||
|
deflaterOutputStream.write(getBytes());
|
||||||
|
deflaterOutputStream.close();
|
||||||
|
byte[] compressedBytes = stream.toByteArray();
|
||||||
|
|
||||||
|
dbObject.put("zipBytes", new String(Base64.getEncoder().encode(compressedBytes)));
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Memory deserialize(DBObject obj) {
|
||||||
|
|
||||||
|
Memory memory = new Memory(0);
|
||||||
|
|
||||||
|
String zipBytesStr = (String) obj.get("zipBytes");
|
||||||
|
|
||||||
|
if (zipBytesStr != null) {
|
||||||
|
byte[] compressedBytes = Base64.getDecoder().decode((String) obj.get("zipBytes"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
Inflater decompressor = new Inflater(true);
|
||||||
|
InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(baos, decompressor);
|
||||||
|
inflaterOutputStream.write(compressedBytes);
|
||||||
|
inflaterOutputStream.close();
|
||||||
|
|
||||||
|
memory.setBytes(baos.toByteArray());
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogManager.LOGGER.severe("Memory was manually deleted");
|
||||||
|
memory = new Memory(GameServer.INSTANCE.getConfig().getInt("memory_size"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBytes(byte[] bytes) {
|
||||||
|
this.words = new char[bytes.length / 2];
|
||||||
|
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().get(this.words);
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getWords() {
|
||||||
|
return words;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -113,6 +113,18 @@ public class Operand {
|
|||||||
value = IMMEDIATE_VALUE;
|
value = IMMEDIATE_VALUE;
|
||||||
return true;
|
return true;
|
||||||
} catch (NumberFormatException e) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,11 +224,30 @@ public class Operand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//label is invalid
|
//label is invalid
|
||||||
|
|
||||||
data = Integer.decode(expr);
|
data = Integer.decode(expr);
|
||||||
value += registerSet.size() * 2; //refers to memory with disp
|
value += registerSet.size() * 2; //refers to memory with disp
|
||||||
return true;
|
return true;
|
||||||
} catch (NumberFormatException e) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
package net.simon987.server.assembly;
|
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 net.simon987.server.logging.LogManager;
|
||||||
import org.json.simple.JSONArray;
|
import org.json.simple.JSONArray;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
@@ -12,7 +15,7 @@ import java.util.HashMap;
|
|||||||
/**
|
/**
|
||||||
* A set of registers for a CPU
|
* A set of registers for a CPU
|
||||||
*/
|
*/
|
||||||
public class RegisterSet implements Target, JSONSerialisable {
|
public class RegisterSet implements Target, MongoSerialisable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of registers
|
* List of registers
|
||||||
@@ -87,7 +90,7 @@ public class RegisterSet implements Target, JSONSerialisable {
|
|||||||
|
|
||||||
Register register = registers.get(address);
|
Register register = registers.get(address);
|
||||||
|
|
||||||
if(register != null){
|
if (register != null) {
|
||||||
return register.getValue();
|
return register.getValue();
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -106,7 +109,7 @@ public class RegisterSet implements Target, JSONSerialisable {
|
|||||||
|
|
||||||
Register register = registers.get(address);
|
Register register = registers.get(address);
|
||||||
|
|
||||||
if(register != null){
|
if (register != null) {
|
||||||
register.setValue(value);
|
register.setValue(value);
|
||||||
} else {
|
} else {
|
||||||
LogManager.LOGGER.info("DEBUG: trying to set unknown reg index : " + address);
|
LogManager.LOGGER.info("DEBUG: trying to set unknown reg index : " + address);
|
||||||
@@ -142,9 +145,9 @@ public class RegisterSet implements Target, JSONSerialisable {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject serialise() {
|
public BasicDBObject mongoSerialise() {
|
||||||
JSONArray registers = new JSONArray();
|
BasicDBList registers = new BasicDBList();
|
||||||
for(Integer index : this.registers.keySet()){
|
for (Integer index : this.registers.keySet()) {
|
||||||
JSONObject register = new JSONObject();
|
JSONObject register = new JSONObject();
|
||||||
|
|
||||||
register.put("index", index);
|
register.put("index", index);
|
||||||
@@ -154,24 +157,42 @@ public class RegisterSet implements Target, JSONSerialisable {
|
|||||||
registers.add(register);
|
registers.add(register);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
BasicDBObject obj = new BasicDBObject();
|
||||||
json.put("registers", registers);
|
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) {
|
public static RegisterSet deserialize(JSONObject json) {
|
||||||
|
|
||||||
RegisterSet registerSet = new RegisterSet();
|
RegisterSet registerSet = new RegisterSet();
|
||||||
|
|
||||||
JSONArray registers = (JSONArray)json.get("registers");
|
JSONArray registers = (JSONArray) json.get("registers");
|
||||||
|
|
||||||
for(JSONObject jsonRegister : (ArrayList<JSONObject>)registers){
|
for (JSONObject jsonRegister : (ArrayList<JSONObject>) registers) {
|
||||||
|
|
||||||
Register register = new Register((String)jsonRegister.get("name"));
|
Register register = new Register((String) jsonRegister.get("name"));
|
||||||
register.setValue((int)(long)jsonRegister.get("value"));
|
register.setValue((int) (long) jsonRegister.get("value"));
|
||||||
|
|
||||||
registerSet.registers.put((int)(long)jsonRegister.get("index"), register);
|
registerSet.registers.put((int) (long) jsonRegister.get("index"), register);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +203,7 @@ public class RegisterSet implements Target, JSONSerialisable {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
String str = "";
|
String str = "";
|
||||||
|
|
||||||
for(Integer index: registers.keySet()){
|
for (Integer index : registers.keySet()) {
|
||||||
str += index + " " + registers.get(index).getName() + "=" + Util.toHex(registers.get(index).getValue()) + "\n";
|
str += index + " " + registers.get(index).getName() + "=" + Util.toHex(registers.get(index).getValue()) + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3,10 +3,9 @@ package net.simon987.server.assembly;
|
|||||||
/**
|
/**
|
||||||
* Section of a user-created program.
|
* Section of a user-created program.
|
||||||
* The execution will start at the beginning of the code
|
* The execution will start at the beginning of the code
|
||||||
* segment and a warning message will be displayed when execution
|
* segment.
|
||||||
* reached the data segment during debugging
|
|
||||||
*/
|
*/
|
||||||
public enum Segment {
|
public enum Section {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Code section of the program. Contains executable code
|
* Code section of the program. Contains executable code
|
||||||
@@ -132,4 +132,20 @@ public class Status {
|
|||||||
public void setErrorFlag(boolean errorFlag) {
|
public void setErrorFlag(boolean errorFlag) {
|
||||||
this.errorFlag = 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -41,8 +41,8 @@ public class Util {
|
|||||||
return s & 0x0000FFFF;
|
return s & 0x0000FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toHex(int a){
|
public static String toHex(int a) {
|
||||||
return String.format("%04X ", uShort(a));
|
return String.format("%04X ", a);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toHex(byte[] byteArray) {
|
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
|
* 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
|
* 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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,8 +8,8 @@ import net.simon987.server.assembly.Util;
|
|||||||
/**
|
/**
|
||||||
* Add two numbers together, the result is stored in the destination operand
|
* Add two numbers together, the result is stored in the destination operand
|
||||||
* <p>
|
* <p>
|
||||||
* ADD A, B
|
* ADD A, B
|
||||||
* A = A + B
|
* A = A + B
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class AddInstruction extends Instruction {
|
public class AddInstruction extends Instruction {
|
||||||
@@ -39,8 +39,8 @@ public class AddInstruction extends Instruction {
|
|||||||
@Override
|
@Override
|
||||||
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
int a = (char)dst.get(dstIndex);
|
int a = (char) dst.get(dstIndex);
|
||||||
int b = (char)src.get(srcIndex);
|
int b = (char) src.get(srcIndex);
|
||||||
|
|
||||||
return add(a, b, status, dst, dstIndex);
|
return add(a, b, status, dst, dstIndex);
|
||||||
}
|
}
|
||||||
@@ -48,8 +48,8 @@ public class AddInstruction extends Instruction {
|
|||||||
@Override
|
@Override
|
||||||
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
|
|
||||||
int a = (char)dst.get(dstIndex);
|
int a = (char) dst.get(dstIndex);
|
||||||
int b = (char)src;
|
int b = (char) src;
|
||||||
|
|
||||||
return add(a, b, status, dst, dstIndex);
|
return add(a, b, status, dst, dstIndex);
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,8 @@ import net.simon987.server.assembly.Util;
|
|||||||
/**
|
/**
|
||||||
* AND two numbers together, the result is stored in the destination operand
|
* AND two numbers together, the result is stored in the destination operand
|
||||||
* <p>
|
* <p>
|
||||||
* AND A, B
|
* AND A, B
|
||||||
* A = A & B
|
* A = A & B
|
||||||
* </p>
|
* </p>
|
||||||
* FLAGS: OF=0 S=* Z=* X=0
|
* FLAGS: OF=0 S=* Z=* X=0
|
||||||
*/
|
*/
|
||||||
@@ -27,8 +27,8 @@ public class AndInstruction extends Instruction {
|
|||||||
@Override
|
@Override
|
||||||
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
int a =(char)dst.get(dstIndex);
|
int a = (char) dst.get(dstIndex);
|
||||||
int b = (char)src.get(srcIndex);
|
int b = (char) src.get(srcIndex);
|
||||||
|
|
||||||
|
|
||||||
int result = (a & b);
|
int result = (a & b);
|
||||||
@@ -45,8 +45,8 @@ public class AndInstruction extends Instruction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
int a = (char)dst.get(dstIndex);
|
int a = (char) dst.get(dstIndex);
|
||||||
int b = (char)src;
|
int b = (char) src;
|
||||||
|
|
||||||
|
|
||||||
int result = (a & b);
|
int result = (a & b);
|
||||||
@@ -20,4 +20,8 @@ public class BrkInstruction extends Instruction {
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean noOperandsValid() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -23,15 +23,15 @@ public class CmpInstruction extends Instruction {
|
|||||||
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
public Status execute(Target dst, int dstIndex, Target src, int srcIndex, Status status) {
|
||||||
|
|
||||||
|
|
||||||
int a = (char)dst.get(dstIndex);
|
int a = (char) dst.get(dstIndex);
|
||||||
int b = (char)src.get(srcIndex);
|
int b = (char) src.get(srcIndex);
|
||||||
|
|
||||||
|
|
||||||
int result = a - b;
|
int result = a - b;
|
||||||
|
|
||||||
status.setSignFlag(Util.checkSign16(result));
|
status.setSignFlag(Util.checkSign16(result));
|
||||||
status.setZeroFlag((char) result == 0);
|
status.setZeroFlag((char) result == 0);
|
||||||
status.setOverflowFlag(Util.checkOverFlowAdd16(a, b));
|
status.setOverflowFlag(Util.checkOverFlowSub16(a, b));
|
||||||
status.setCarryFlag(Util.checkCarry16(result));
|
status.setCarryFlag(Util.checkCarry16(result));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@@ -40,8 +40,8 @@ public class CmpInstruction extends Instruction {
|
|||||||
@Override
|
@Override
|
||||||
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
public Status execute(Target dst, int dstIndex, int src, Status status) {
|
||||||
|
|
||||||
int a = (char)dst.get(dstIndex);
|
int a = (char) dst.get(dstIndex);
|
||||||
int b = (char)src;
|
int b = (char) src;
|
||||||
|
|
||||||
int result = a - b;
|
int result = a - b;
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user