mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-12-14 15:19:04 +00:00
Compare commits
252 Commits
v1.4a
...
refactor-1
| Author | SHA1 | Date | |
|---|---|---|---|
| 18a6858edd | |||
| 9315111793 | |||
| 60c763167d | |||
| 3ae119072c | |||
| 2ace932b52 | |||
| 50b95d1a9c | |||
| ad08a5ac4f | |||
| 84a9132f5e | |||
| 2ff19f24eb | |||
| b1d7121b22 | |||
| 51c0d4c3c7 | |||
| 421a983910 | |||
| 73dc9b1dca | |||
| fe299fe061 | |||
| 319abad130 | |||
| ad0124508c | |||
| ba78d2fd93 | |||
| cc5627902e | |||
| 21a391e077 | |||
| 3b7cff6ac7 | |||
| 304c063887 | |||
| cd9e555e86 | |||
|
|
7c0187f514 | ||
| ac27250f98 | |||
|
|
84f59a5fa2 | ||
| a0193621a8 | |||
| 922162660f | |||
| 014dab49da | |||
|
|
4c81937edc | ||
| 2597b558e6 | |||
| ea1ec1b1b3 | |||
| 8b55466e7c | |||
|
|
03ff2e5527 | ||
|
|
634af8859f | ||
|
|
39ca4d5143 | ||
|
|
5f3c34911c | ||
|
|
638c5b3bb3 | ||
|
|
50e0baa6ec | ||
|
|
3a35f3fdfc | ||
|
|
2982fcbbc1 | ||
|
|
fb97415ee7 | ||
|
|
f37ae36262 | ||
|
|
556b46badc | ||
|
|
d57f8d2970 | ||
|
|
629dac6ea3 | ||
|
|
55fdd93d9d | ||
|
|
2f7d2cd85a | ||
|
|
6e4b2358af | ||
|
|
f9c7f02870 | ||
|
|
86b331fc60 | ||
|
|
35b6f06687 | ||
|
|
bcd96be625 | ||
|
|
f99f327480 | ||
|
|
d71b3dc97c | ||
|
|
e378016c56 | ||
|
|
c50cc8c364 | ||
|
|
bf9cdc7b29 | ||
|
|
75410cc0db | ||
|
|
e0ed1e0e6f | ||
|
|
0fbd1d1a6b | ||
|
|
8018fb3e30 | ||
|
|
fb8fdac9c3 | ||
|
|
a3253e8e3a | ||
|
|
9ee754e5be | ||
|
|
e72e8b45c5 | ||
|
|
311889bc93 | ||
|
|
9cb2c29f0f | ||
|
|
f3ae97c060 | ||
|
|
e8033f3291 | ||
|
|
b19eb0568d | ||
|
|
9aa876df62 | ||
|
|
b1da29d7fb | ||
|
|
12f20d178a | ||
|
|
a030e9fc5d | ||
|
|
439547102f | ||
|
|
d5ddb8e439 | ||
|
|
4f4cecf60c | ||
|
|
a1136f9056 | ||
|
|
d2e7084354 | ||
|
|
1157bd5df5 | ||
|
|
0ff671713c | ||
|
|
2590e8ec64 | ||
|
|
a768cf0f4b | ||
|
|
7b3839f046 | ||
|
|
4958c3d9a0 | ||
|
|
f8eec652ae | ||
|
|
762bad758b | ||
|
|
3e2422775e | ||
|
|
993838651f | ||
|
|
ce8c5375ee | ||
|
|
91ebb51389 | ||
|
|
d113f635a1 | ||
|
|
78a9f78a54 | ||
|
|
4f8eb2725e | ||
|
|
ff4f6c23eb | ||
|
|
c5a34c7a3f | ||
|
|
1d3d441996 | ||
|
|
7ba46ec36e | ||
|
|
63cdfb22ac | ||
|
|
f9898f57f4 | ||
|
|
2548242da8 | ||
|
|
46d5c9b51e | ||
|
|
7fd1c35f7a | ||
|
|
0dbec1d258 | ||
|
|
45d3b84dd0 | ||
|
|
af4ddbdd89 | ||
|
|
84ca3acb52 | ||
|
|
0973548b71 | ||
|
|
5f95c17aed | ||
|
|
b361f87154 | ||
|
|
e4a06e79d4 | ||
|
|
955d61ce99 | ||
|
|
201d83f8d8 | ||
|
|
94b8ef5395 | ||
|
|
70eeb1442d | ||
|
|
bbaa338469 | ||
|
|
5de909cd9c | ||
|
|
71e88afdc9 | ||
|
|
ae41bd9cb9 | ||
|
|
de45eb1827 | ||
|
|
6c7a2f0a73 | ||
|
|
3776070689 | ||
|
|
54ed05b86c | ||
|
|
b361583252 | ||
|
|
04c837d692 | ||
|
|
aaeb18068d | ||
|
|
e848fd8b8a | ||
|
|
1435d31d36 | ||
|
|
950f6b6b4b | ||
|
|
6a9cfb3acb | ||
|
|
4be1bf2e8a | ||
|
|
e50bcdeab7 | ||
|
|
c8214236ab | ||
|
|
37b7bbff98 | ||
|
|
be7304aa0b | ||
|
|
0845438297 | ||
|
|
564a692c2e | ||
|
|
a40a0712f0 | ||
|
|
f89c39c756 | ||
|
|
a6f0ce1dfb | ||
|
|
2f80205b2a | ||
|
|
71f96f27d1 | ||
|
|
98402dd45b | ||
|
|
548d756e90 | ||
|
|
1a2332bc32 | ||
|
|
9a73b7b7d1 | ||
|
|
d860591cc8 | ||
|
|
268acda773 | ||
|
|
6d66e19dc5 | ||
|
|
40e7899cf6 | ||
|
|
abb92bfc75 | ||
|
|
becf6e5feb | ||
|
|
8af652482d | ||
|
|
205845d6af | ||
|
|
64193ecf7a | ||
|
|
a1cf279b6f | ||
|
|
6074238131 | ||
|
|
fa62c49fa8 | ||
|
|
a0aaee7ee7 | ||
|
|
96fc3ed68c | ||
|
|
e69111ff3c | ||
|
|
e7e9a3e6fb | ||
|
|
a73aa7c3a5 | ||
|
|
e8543082ce | ||
|
|
4b7ebd7ad6 | ||
|
|
c389bbc92e | ||
|
|
78f98c8227 | ||
|
|
92008e553a | ||
|
|
45d34c37ad | ||
|
|
a9cc9662f4 | ||
|
|
df9c466827 | ||
|
|
b65c57ceba | ||
|
|
2f74dd45fc | ||
|
|
07160138aa | ||
|
|
b6a206f3c7 | ||
|
|
ed1c4cff0b | ||
|
|
a005e2b163 | ||
|
|
a7bdbd2513 | ||
|
|
ee9eeeef55 | ||
|
|
4b67798180 | ||
|
|
be8dd14d36 | ||
|
|
80f45f1eb0 | ||
|
|
3368268924 | ||
|
|
4cd58c86a5 | ||
|
|
8d029cf621 | ||
|
|
10f088cb66 | ||
|
|
159c217d59 | ||
|
|
c5cb5df335 | ||
|
|
854863ede9 | ||
|
|
e98575b23f | ||
|
|
1a5d12a19f | ||
|
|
1678be25c5 | ||
|
|
9c41c16079 | ||
|
|
e97ecbe380 | ||
|
|
083af31b84 | ||
|
|
2c856aae80 | ||
|
|
315e33055e | ||
|
|
e025b6d2da | ||
|
|
e3a650a4fc | ||
|
|
113aa50d87 | ||
|
|
dc034d1437 | ||
|
|
3492e133e1 | ||
|
|
bd5f8573e8 | ||
|
|
3c5bfdb30b | ||
|
|
9349ae108b | ||
|
|
292adb5483 | ||
|
|
e479d89375 | ||
|
|
41d674d74a | ||
|
|
227f7ce5aa | ||
|
|
a091071d55 | ||
|
|
f1b8f3dc6d | ||
|
|
e62a51ee2e | ||
|
|
217c997788 | ||
|
|
ff61433c4b | ||
|
|
cbde2450fa | ||
|
|
1d780f7d9b | ||
|
|
cbb07891fc | ||
|
|
2565d3338c | ||
|
|
e4269b83c4 | ||
|
|
9cac665101 | ||
|
|
dc19176dc8 | ||
|
|
8ed192f8d0 | ||
|
|
d1a3cf9307 | ||
|
|
f8c5dac969 | ||
|
|
0a75cb557d | ||
|
|
f35e6c5a9a | ||
|
|
0ada6c29d4 | ||
|
|
156deb8f4e | ||
|
|
039088ac00 | ||
|
|
f530dafdee | ||
|
|
817dbcc6c4 | ||
|
|
62f1403cb3 | ||
|
|
8c6e580ea9 | ||
|
|
6a1519d97d | ||
|
|
95a14ad1ab | ||
|
|
187a828c79 | ||
|
|
ffca185fe5 | ||
|
|
815f3de234 | ||
|
|
3505a466bb | ||
|
|
3d10e4306b | ||
|
|
a285b3104e | ||
|
|
947deea784 | ||
|
|
4293fc0315 | ||
|
|
f1c1f8f807 | ||
|
|
a04207b5e0 | ||
|
|
46483b2bf8 | ||
|
|
9bb0dc9034 | ||
|
|
1da894959e | ||
|
|
7e773699b6 | ||
|
|
bc29c36204 | ||
|
|
eb3deba544 | ||
|
|
c7da764505 |
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
src/main/resources/static/css/bootstrap4-neon-glow.min linguist-vendored
|
||||
src/main/resources/static/css/bootstrap-grid.min linguist-vendored
|
||||
src/main/resources/static/css/bootstrap-reboot.min linguist-vendored
|
||||
src/main/resources/static/js/* linguist-vendored
|
||||
src/main/resources/static/js/ace/* linguist-vendored
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,8 +1,4 @@
|
||||
|
||||
plugins/Plugin NPC.jar
|
||||
plugins/Plugin Misc HW.jar
|
||||
plugins/Plant.jar
|
||||
plugins/Cubot.jar
|
||||
.idea/*
|
||||
mar.log
|
||||
mar.log.lck
|
||||
@@ -13,5 +9,10 @@ plugins/*.jar
|
||||
save.json
|
||||
Server/Server.iml
|
||||
target/*
|
||||
Server/Server.iml
|
||||
Server/src/main/java/META-INF/MANIFEST.MF
|
||||
src/main/java/META-INF/MANIFEST.MF
|
||||
src/main/resources/static/js/mar.js
|
||||
.settings
|
||||
.project
|
||||
.classpath
|
||||
# VSCode Workspace
|
||||
.vscode/
|
||||
|
||||
@@ -8,12 +8,7 @@ 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
|
||||
- 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
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
FROM alpine:3.7
|
||||
RUN apk add --no-cache maven openjdk8
|
||||
FROM maven:3.5-jdk-8
|
||||
COPY /. /app/
|
||||
WORKDIR /app
|
||||
RUN mvn package \
|
||||
&& cp Server/src/main/resources/config.properties /app/
|
||||
CMD ["java", "-jar", "/app/target/server-1.2a.jar"]
|
||||
RUN mvn package
|
||||
WORKDIR /app/target
|
||||
CMD ["java", "-jar", "/app/target/server-1.6a.jar"]
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,308 +0,0 @@
|
||||
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,63 +0,0 @@
|
||||
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 CubotBattery extends CpuHardware {
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 0x000A;
|
||||
|
||||
/**
|
||||
* Hardware ID (Should be unique)
|
||||
*/
|
||||
public static final char HWID = 0x000A;
|
||||
|
||||
private Cubot cubot;
|
||||
private static final int BATTERY_POLL = 1;
|
||||
private static final int BATTERY_GET_MAX_CAPACITY = 2;
|
||||
|
||||
public CubotBattery(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == BATTERY_POLL) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getEnergy());
|
||||
|
||||
} else if (a == BATTERY_GET_MAX_CAPACITY) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getMaxEnergy());
|
||||
} else if (a == 0xFFFF) {
|
||||
cubot.setEnergy(cubot.getMaxEnergy());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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 CubotBattery deserialize(DBObject obj) {
|
||||
return new CubotBattery((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.game.Action;
|
||||
import net.simon987.server.game.TileMap;
|
||||
|
||||
public class CubotDrill extends CpuHardware {
|
||||
|
||||
/**
|
||||
* Hardware ID (Should be unique)
|
||||
*/
|
||||
static final char HWID = 0x0005;
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 5;
|
||||
|
||||
private static final int DRILL_POLL = 1;
|
||||
private static final int DRILL_GATHER = 2; // simplified gather
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
public CubotDrill(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == DRILL_POLL) {
|
||||
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(0);
|
||||
|
||||
} else if (a == DRILL_GATHER) {
|
||||
|
||||
if (cubot.spendEnergy(1400)) {
|
||||
if (cubot.getCurrentAction() == Action.IDLE) {
|
||||
int tile = cubot.getWorld().getTileMap().getTileAt(cubot.getX(), cubot.getY());
|
||||
|
||||
if (tile == TileMap.IRON_TILE) {
|
||||
cubot.setHeldItem(TileMap.ITEM_IRON);
|
||||
cubot.setCurrentAction(Action.DIGGING);
|
||||
|
||||
} else if (tile == TileMap.COPPER_TILE) {
|
||||
cubot.setHeldItem(TileMap.ITEM_COPPER);
|
||||
cubot.setCurrentAction(Action.DIGGING);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotDrill deserialize(DBObject obj) {
|
||||
return new CubotDrill((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
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,68 +0,0 @@
|
||||
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 CubotInventory extends CpuHardware {
|
||||
|
||||
/**
|
||||
* Hardware ID (Should be unique)
|
||||
*/
|
||||
static final char HWID = 0x0006;
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 6;
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
private static final int INV_CLEAR = 0;
|
||||
private static final int INV_POLL = 1;
|
||||
|
||||
public CubotInventory(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == INV_POLL) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getHeldItem());
|
||||
|
||||
} else if (a == INV_CLEAR) {
|
||||
if (cubot.getHeldItem() == 0x0001) {
|
||||
int energy = GameServer.INSTANCE.getConfig().getInt("biomassEnergyValue");
|
||||
cubot.storeEnergy(energy);
|
||||
cubot.setHeldItem(0);
|
||||
|
||||
} else if (cubot.spendEnergy(100)) {
|
||||
cubot.setHeldItem(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotInventory deserialize(DBObject obj) {
|
||||
return new CubotInventory((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.game.Action;
|
||||
import net.simon987.server.game.Attackable;
|
||||
import net.simon987.server.game.GameObject;
|
||||
import net.simon987.server.game.InventoryHolder;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CubotLaser extends CpuHardware {
|
||||
|
||||
/**
|
||||
* Hardware ID (Should be unique)
|
||||
*/
|
||||
static final char HWID = 0x0002;
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 2;
|
||||
|
||||
private Cubot cubot;
|
||||
|
||||
private static final int LASER_WITHDRAW = 1;
|
||||
private static final int LASER_DEPOSIT = 2;
|
||||
private static final int LASER_ATTACK = 3;
|
||||
|
||||
private static final int LASER_DAMAGE = 25;
|
||||
|
||||
public CubotLaser(Cubot cubot) {
|
||||
this.cubot = cubot;
|
||||
}
|
||||
|
||||
@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 == LASER_WITHDRAW) {
|
||||
|
||||
|
||||
Point frontTile = cubot.getFrontTile();
|
||||
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsBlockingAt(frontTile.x, frontTile.y);
|
||||
|
||||
if (cubot.getCurrentAction() == Action.IDLE && objects.size() > 0) {
|
||||
//FIXME: Problem here if more than 1 object
|
||||
if (objects.get(0) instanceof InventoryHolder) {
|
||||
if (((InventoryHolder) objects.get(0)).canTakeItem(b)) {
|
||||
if (cubot.spendEnergy(30)) {
|
||||
//Take the item
|
||||
((InventoryHolder) objects.get(0)).takeItem(b);
|
||||
|
||||
cubot.setHeldItem(b);
|
||||
cubot.setCurrentAction(Action.WITHDRAWING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else if (a == LASER_DEPOSIT) {
|
||||
// TODO
|
||||
} else if (a == LASER_ATTACK) {
|
||||
|
||||
if (cubot.spendEnergy(70)) {
|
||||
|
||||
//Get object directly in front of the Cubot
|
||||
Point frontTile = cubot.getFrontTile();
|
||||
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y);
|
||||
|
||||
if (objects.size() > 0 && objects.get(0) instanceof Attackable) {
|
||||
((Attackable) objects.get(0)).damage(LASER_DAMAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
dbObject.put("cubot", cubot.getObjectId());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static CubotLaser deserialize(DBObject obj) {
|
||||
return new CubotLaser((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
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,67 +0,0 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.cubotplugin.event.CpuInitialisationListener;
|
||||
import net.simon987.cubotplugin.event.UserCreationListener;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
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;
|
||||
|
||||
public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer, CpuHardwareDeserializer {
|
||||
|
||||
|
||||
@Override
|
||||
public void init(ServerConfiguration config) {
|
||||
listeners.add(new CpuInitialisationListener());
|
||||
listeners.add(new UserCreationListener());
|
||||
|
||||
LogManager.LOGGER.info("Initialised Cubot plugin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameObject deserializeObject(DBObject object) {
|
||||
|
||||
int objType = (int) object.get("t");
|
||||
|
||||
if (objType == Cubot.ID) {
|
||||
|
||||
return Cubot.deserialize(object);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CpuHardware deserializeHardware(DBObject obj) {
|
||||
int hwid = (int) obj.get("hwid");
|
||||
|
||||
switch (hwid) {
|
||||
case CubotLeg.HWID:
|
||||
return CubotLeg.deserialize(obj);
|
||||
case CubotLaser.HWID:
|
||||
return CubotLaser.deserialize(obj);
|
||||
case CubotLidar.HWID:
|
||||
return CubotLidar.deserialize(obj);
|
||||
case CubotDrill.HWID:
|
||||
return CubotDrill.deserialize(obj);
|
||||
case CubotInventory.HWID:
|
||||
return CubotInventory.deserialize(obj);
|
||||
case CubotKeyboard.HWID:
|
||||
return CubotKeyboard.deserialize(obj);
|
||||
case CubotHologram.HWID:
|
||||
return CubotHologram.deserialize(obj);
|
||||
case CubotBattery.HWID:
|
||||
return CubotBattery.deserialize(obj);
|
||||
case CubotFloppyDrive.HWID:
|
||||
return CubotFloppyDrive.deserialize(obj);
|
||||
case CubotComPort.HWID:
|
||||
return CubotComPort.deserialize(obj);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package net.simon987.cubotplugin.event;
|
||||
|
||||
import net.simon987.cubotplugin.*;
|
||||
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) {
|
||||
//LogManager.LOGGER.fine("(Plugin) Handled CPU Initialisation event (Cubot Plugin)");
|
||||
|
||||
CPU cpu = (CPU) event.getSource();
|
||||
User user = ((CpuInitialisationEvent) event).getUser();
|
||||
|
||||
CubotLeg legHw = new CubotLeg((Cubot) user.getControlledUnit());
|
||||
legHw.setCpu(cpu);
|
||||
CubotLaser laserHw = new CubotLaser((Cubot) user.getControlledUnit());
|
||||
laserHw.setCpu(cpu);
|
||||
CubotLidar radarHw = new CubotLidar((Cubot) user.getControlledUnit());
|
||||
radarHw.setCpu(cpu);
|
||||
CubotKeyboard keyboard = new CubotKeyboard((Cubot) user.getControlledUnit());
|
||||
keyboard.setCpu(cpu);
|
||||
CubotDrill drillHw = new CubotDrill((Cubot) user.getControlledUnit());
|
||||
drillHw.setCpu(cpu);
|
||||
CubotInventory invHw = new CubotInventory((Cubot) user.getControlledUnit());
|
||||
invHw.setCpu(cpu);
|
||||
CubotHologram emoteHw = new CubotHologram((Cubot) user.getControlledUnit());
|
||||
emoteHw.setCpu(cpu);
|
||||
CubotBattery batteryHw = new CubotBattery((Cubot) user.getControlledUnit());
|
||||
batteryHw.setCpu(cpu);
|
||||
CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit());
|
||||
floppyHw.setCpu(cpu);
|
||||
CubotComPort comPortHw = new CubotComPort((Cubot) user.getControlledUnit());
|
||||
comPortHw.setCpu(cpu);
|
||||
|
||||
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(radarHw, CubotLidar.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(keyboard, CubotKeyboard.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(drillHw, CubotDrill.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(comPortHw, CubotComPort.DEFAULT_ADDRESS);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package net.simon987.cubotplugin.event;
|
||||
|
||||
import net.simon987.cubotplugin.Cubot;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
import net.simon987.server.event.UserCreationEvent;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Random;
|
||||
|
||||
public class UserCreationListener implements GameEventListener {
|
||||
@Override
|
||||
public Class getListenedEventType() {
|
||||
return UserCreationEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(GameEvent event) {
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
User user = (User) event.getSource();
|
||||
Cubot cubot = new Cubot();
|
||||
cubot.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||
|
||||
Point point = null;
|
||||
while (point == null || cubot.getWorld() == null) {
|
||||
int spawnX = GameServer.INSTANCE.getConfig().getInt("new_user_worldX") + random.nextInt(5);
|
||||
int spawnY = GameServer.INSTANCE.getConfig().getInt("new_user_worldY") + random.nextInt(5);
|
||||
cubot.setWorld(GameServer.INSTANCE.getGameUniverse().getWorld(spawnX, spawnY, true));
|
||||
|
||||
point = cubot.getWorld().getRandomPassableTile();
|
||||
}
|
||||
|
||||
cubot.setX(point.x);
|
||||
cubot.setY(point.y);
|
||||
cubot.getWorld().addObject(cubot);
|
||||
cubot.getWorld().incUpdatable();
|
||||
|
||||
cubot.setHeldItem(GameServer.INSTANCE.getConfig().getInt("new_user_item"));
|
||||
cubot.setEnergy(GameServer.INSTANCE.getConfig().getInt("battery_max_energy"));
|
||||
cubot.setMaxEnergy(GameServer.INSTANCE.getConfig().getInt("battery_max_energy"));
|
||||
|
||||
cubot.setParent(user);
|
||||
user.setControlledUnit(cubot);
|
||||
|
||||
LogManager.LOGGER.fine("(Plugin) Handled User creation event (Cubot Plugin)");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
classpath=net.simon987.cubotplugin.CubotPlugin
|
||||
name=Cubot Plugin
|
||||
version=1.0
|
||||
@@ -1,19 +0,0 @@
|
||||
package net.simon987.cubotplugin;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class CubotTest {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertEquals(1, 1);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?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,45 +0,0 @@
|
||||
package net.simon987.mischwplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Util;
|
||||
|
||||
public class Clock extends CpuHardware {
|
||||
|
||||
public static final char HWID = 0x0008;
|
||||
|
||||
public static final char DEFAULT_ADDRESS = 0x0008;
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
int time = (int) GameServer.INSTANCE.getGameUniverse().getTime();
|
||||
|
||||
//Will need to be changed to quadword in about 136 years
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(Util.getHigherWord(time));
|
||||
getCpu().getRegisterSet().getRegister("C").setValue(Util.getLowerWord(time));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
public static Clock deserialize() {
|
||||
return new Clock();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package net.simon987.mischwplugin;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.mischwplugin.event.CpuInitialisationListener;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
|
||||
public class MiscHWPlugin extends ServerPlugin implements CpuHardwareDeserializer {
|
||||
|
||||
|
||||
@Override
|
||||
public void init(ServerConfiguration config) {
|
||||
listeners.add(new CpuInitialisationListener());
|
||||
|
||||
LogManager.LOGGER.info("Initialised Misc Hardware Plugin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CpuHardware deserializeHardware(DBObject hwJson) {
|
||||
int hwid = (int) hwJson.get("hwid");
|
||||
|
||||
switch (hwid) {
|
||||
case RandomNumberGenerator.HWID:
|
||||
return RandomNumberGenerator.deserialize();
|
||||
case Clock.HWID:
|
||||
return Clock.deserialize();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package net.simon987.mischwplugin;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
import net.simon987.server.assembly.Status;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomNumberGenerator extends CpuHardware {
|
||||
|
||||
public static final char HWID = 0x0007;
|
||||
|
||||
public static final char DEFAULT_ADDRESS = 0x0007;
|
||||
|
||||
private Random random;
|
||||
|
||||
public RandomNumberGenerator() {
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(random.nextInt(0xFFFF));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("hwid", (int) HWID);
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
public static RandomNumberGenerator deserialize() {
|
||||
return new RandomNumberGenerator();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package net.simon987.mischwplugin.event;
|
||||
|
||||
import net.simon987.mischwplugin.Clock;
|
||||
import net.simon987.mischwplugin.RandomNumberGenerator;
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.event.CpuInitialisationEvent;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
|
||||
public class CpuInitialisationListener implements GameEventListener {
|
||||
|
||||
@Override
|
||||
public Class getListenedEventType() {
|
||||
return CpuInitialisationEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(GameEvent event) {
|
||||
|
||||
CPU cpu = (CPU) event.getSource();
|
||||
|
||||
RandomNumberGenerator rngHW = new RandomNumberGenerator();
|
||||
rngHW.setCpu(cpu);
|
||||
Clock clock = new Clock();
|
||||
clock.setCpu(cpu);
|
||||
|
||||
cpu.attachHardware(rngHW, RandomNumberGenerator.DEFAULT_ADDRESS);
|
||||
cpu.attachHardware(clock, Clock.DEFAULT_ADDRESS);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
classpath=net.simon987.mischwplugin.MiscHWPlugin
|
||||
name=Misc HW Plugin
|
||||
version=1.0
|
||||
@@ -1,24 +0,0 @@
|
||||
<?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,31 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,210 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package net.simon987.npcplugin.event;
|
||||
|
||||
import net.simon987.npcplugin.RadioReceiverHardware;
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.event.CpuInitialisationEvent;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
public class CpuInitialisationListener implements GameEventListener {
|
||||
@Override
|
||||
public Class getListenedEventType() {
|
||||
return CpuInitialisationEvent.class;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(GameEvent event) {
|
||||
CPU cpu = (CPU) event.getSource();
|
||||
User user = ((CpuInitialisationEvent) event).getUser();
|
||||
|
||||
RadioReceiverHardware radioHw = new RadioReceiverHardware(user.getControlledUnit());
|
||||
radioHw.setCpu(cpu);
|
||||
|
||||
cpu.attachHardware(radioHw, RadioReceiverHardware.DEFAULT_ADDRESS);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
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 + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
classpath=net.simon987.npcplugin.NpcPlugin
|
||||
name=NPC Plugin
|
||||
version=1.0
|
||||
@@ -1,24 +0,0 @@
|
||||
<?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,32 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,126 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
classpath=net.simon987.biomassplugin.BiomassPlugin
|
||||
name=Biomass Plugin
|
||||
version=1.0
|
||||
114
README.md
114
README.md
@@ -1,26 +1,42 @@
|
||||
# [Live demo](https://muchassemblyrequired.com)
|
||||
### [Official website](https://muchassemblyrequired.com)
|
||||
|
||||
[](https://www.codefactor.io/repository/github/simon987/much-assembly-required)
|
||||
[](https://ci.simon987.net/job/Much-Assembly-Required/)
|
||||
|
||||
Program the 8086-like microprocessor of a robot in a grid-based multiplayer world. The game is web based so no installation is required.
|
||||
In its current state, players can walk around the game universe and collect Biomass blobs & Iron/copper ore using the online code editor.
|
||||
|
||||

|
||||
|
||||
Wiki: [GitHub](https://github.com/simon987/Much-Assembly-Required/wiki)
|
||||
Chat: [Slack](https://join.slack.com/t/muchassemblyrequired/shared_invite/enQtMjY3Mjc1OTUwNjEwLTkyOTIwOTA5OGY4MDVlMGI4NzM5YzlhMWJiMGY1OWE2NjUxODQ1NWQ1YTcxMTA1NGZkYzNjYzMyM2E1ODdmNzg)
|
||||
|
||||
## VS Code Extensions
|
||||
- [Much Assembly Required (Upload on Save)](https://marketplace.visualstudio.com/items?itemName=tomhodder.much-assembly-required-upload-on-save) by tomhodder
|
||||
- [Much Assembly Required Language Support](https://marketplace.visualstudio.com/items?itemName=PJB3005.much-assembly-required-language-support) by PJB3005
|
||||
Chat: [Slack](https://join.slack.com/t/muchassemblyrequired/shared_invite/enQtMjY3Mjc1OTUwNjEwLWRjMjRkZTg2N2EyNWRjN2YyMDc0YzIyMTUyYzFiNTBmMTU3OGQ1ZjA0MWY0M2IyYjUxZTA4NjRkMWVkNDk2NzY)
|
||||
|
||||
# Deploying the server
|
||||
|
||||
Note: You can find the frontend [here](https://github.com/simon987/Much-Assembly-Required-Frontend)
|
||||
## Linux
|
||||
|
||||
**Installing tools**
|
||||
|
||||
## Linux (Ubuntu 16.04)
|
||||
On Ubuntu 16.04:
|
||||
```bash
|
||||
# Install tools
|
||||
sudo apt install git maven openjdk-8-jdk
|
||||
sudo apt install git maven openjdk-8-jdk mongodb
|
||||
sudo npm install -g typescript
|
||||
```
|
||||
|
||||
On Arch:
|
||||
``` bash
|
||||
sudo pacman -S git maven mongodb jdk8-opendjk
|
||||
sudo npm install -g typescript
|
||||
|
||||
# Don't forget to start mongodb
|
||||
sudo systemctl start mongodb.service
|
||||
```
|
||||
|
||||
*If needed, visit [troubleshooting mongodb](https://wiki.archlinux.org/index.php/MongoDB#Troubleshooting).*
|
||||
|
||||
**Deploying server**
|
||||
|
||||
``` bash
|
||||
# Obtain source files
|
||||
git clone https://github.com/simon987/Much-Assembly-Required.git
|
||||
|
||||
@@ -30,7 +46,7 @@ mvn package
|
||||
|
||||
# Run
|
||||
cd target
|
||||
java -jar server-1.2a.jar
|
||||
java -jar muchassemblyrequired-*.jar
|
||||
```
|
||||
|
||||
## Windows (tested on Windows 10)
|
||||
@@ -61,10 +77,69 @@ mongod
|
||||
```batch
|
||||
:: Runs the MAR server
|
||||
cd Much-Assembly-Required\target
|
||||
java -jar server-1.2a.jar
|
||||
java -jar muchassemblyrequired-*.jar
|
||||
```
|
||||
3. Run the frontend, following the instructions that you can find [here](https://github.com/simon987/Much-Assembly-Required-Frontend).
|
||||
|
||||
## macOS (tested on Sierra 10.12.6)
|
||||
|
||||
**Installation**
|
||||
|
||||
1. Install [Maven3](https://maven.apache.org/)
|
||||
-Add Maven bin to your path
|
||||
```bash
|
||||
export PATH=/path/to/maven/bin.:$PATH
|
||||
```
|
||||
2. Install [MongoDB](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/?_ga=2.201359831.774868398.1539369140-197602459.1539369140).
|
||||
-Via Brew:
|
||||
```bash
|
||||
#Update brew
|
||||
brew update
|
||||
|
||||
#Install mongodb
|
||||
brew install mongodb
|
||||
|
||||
#Install latest development release
|
||||
brew install mongodb --devel
|
||||
```
|
||||
-Via .tar.gz
|
||||
```bash
|
||||
#Extract files:
|
||||
tar -zxvf mongodb-osx-ssl-x86_64-4.0.3.tgz
|
||||
|
||||
#Ensure binaries are in your path
|
||||
export PATH=<mongodb-install-directory>/bin:$PATH
|
||||
```
|
||||
If you do not wish to use the default data directory (/data/db), follow the steps for running MongoDB in the install doc.
|
||||
|
||||
**Deploying Server**
|
||||
|
||||
1. Begin MongoDB service
|
||||
```bash
|
||||
#If brew:
|
||||
#Launch on login
|
||||
brew services start mongodb
|
||||
#Or, if you don't want/need a background service you can just run:
|
||||
mongod --config /usr/local/etc/mongod.conf
|
||||
|
||||
#If binary:
|
||||
mongod
|
||||
#Optional, set data directory path:
|
||||
mongod --dbpath <path to data directory>
|
||||
```
|
||||
|
||||
2. Deploy server:
|
||||
```bash
|
||||
# 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 muchassemblyrequired-*.jar
|
||||
```
|
||||
|
||||
## Docker
|
||||
### Requirements
|
||||
@@ -79,8 +154,13 @@ application's directory:
|
||||
|
||||
`docker-compose up`
|
||||
|
||||
This will start MySQL and then build and run this application. It will
|
||||
be available via http://localhost.
|
||||
Make sure to change `mongo_address` in `config.properties` to `mongodb`.
|
||||
|
||||
Note that there is currently no frontend web application serving the
|
||||
WebSocket feed served by the `Server` application!
|
||||
|
||||
# Running
|
||||
|
||||
Once the server is running, you should be able to connect to `http://localhost:4567` with your browser
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?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
134
Server/pom.xml
@@ -1,134 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,277 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package net.simon987.server;
|
||||
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.webserver.SocketServer;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
LogManager.initialize(config);
|
||||
|
||||
//Load
|
||||
GameServer.INSTANCE.load();
|
||||
|
||||
SocketServer socketServer = new SocketServer(new InetSocketAddress(config.getString("webSocket_host"),
|
||||
config.getInt("webSocket_port")), config);
|
||||
|
||||
GameServer.INSTANCE.setSocketServer(socketServer);
|
||||
|
||||
(new Thread(socketServer)).start();
|
||||
(new Thread(GameServer.INSTANCE)).start();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package net.simon987.server;
|
||||
|
||||
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Wrapper for Java Property
|
||||
*/
|
||||
public class ServerConfiguration {
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
private Properties properties;
|
||||
|
||||
public ServerConfiguration(String file) {
|
||||
try {
|
||||
properties = new Properties();
|
||||
InputStream is = new FileInputStream("config.properties");
|
||||
properties.load(is);
|
||||
|
||||
} catch (IOException e) {
|
||||
LogManager.LOGGER.severe("Problem loading server configuration: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return Integer.valueOf((String) properties.get(key));
|
||||
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
|
||||
return (String) properties.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,473 +0,0 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.assembly.instruction.*;
|
||||
import net.simon987.server.event.CpuInitialisationEvent;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* CPU: Central Processing Unit. A CPU is capable of reading bytes from
|
||||
* a Memory object and execute them. A CPU object holds registers objects &
|
||||
* a Memory object.
|
||||
*/
|
||||
public class CPU implements MongoSerialisable {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Status status;
|
||||
|
||||
/**
|
||||
* Memory associated with the CPU, 64kb max
|
||||
*/
|
||||
private Memory memory;
|
||||
|
||||
/**
|
||||
* set of instructions of this CPU
|
||||
*/
|
||||
private InstructionSet instructionSet;
|
||||
|
||||
/**
|
||||
* set of registers of this CPU
|
||||
*/
|
||||
private RegisterSet registerSet;
|
||||
|
||||
/**
|
||||
* Offset of the code section. The code starts to get
|
||||
* executed at this address each tick. Defaults to org_offset@config.properties
|
||||
*/
|
||||
private int codeSectionOffset;
|
||||
|
||||
/**
|
||||
* Instruction pointer, always points to the next instruction
|
||||
*/
|
||||
private int ip;
|
||||
|
||||
/**
|
||||
* List of attached hardware, 'modules'
|
||||
*/
|
||||
private HashMap<Integer, CpuHardware> attachedHardware;
|
||||
|
||||
private ServerConfiguration config;
|
||||
|
||||
private int registerSetSize;
|
||||
|
||||
private static final char EXECUTION_COST_ADDR = 0x0050;
|
||||
private static final char EXECUTED_INS_ADDR = 0x0051;
|
||||
|
||||
/**
|
||||
* Creates a new CPU
|
||||
*/
|
||||
public CPU(ServerConfiguration config, User user) throws CancelledException {
|
||||
this.config = config;
|
||||
instructionSet = new DefaultInstructionSet();
|
||||
registerSet = new DefaultRegisterSet();
|
||||
attachedHardware = new HashMap<>();
|
||||
codeSectionOffset = config.getInt("org_offset");
|
||||
|
||||
instructionSet.add(new JmpInstruction(this));
|
||||
instructionSet.add(new JnzInstruction(this));
|
||||
instructionSet.add(new JzInstruction(this));
|
||||
instructionSet.add(new JgInstruction(this));
|
||||
instructionSet.add(new JgeInstruction(this));
|
||||
instructionSet.add(new JleInstruction(this));
|
||||
instructionSet.add(new JlInstruction(this));
|
||||
instructionSet.add(new PushInstruction(this));
|
||||
instructionSet.add(new PopInstruction(this));
|
||||
instructionSet.add(new CallInstruction(this));
|
||||
instructionSet.add(new RetInstruction(this));
|
||||
instructionSet.add(new MulInstruction(this));
|
||||
instructionSet.add(new DivInstruction(this));
|
||||
instructionSet.add(new JnsInstruction(this));
|
||||
instructionSet.add(new JsInstruction(this));
|
||||
instructionSet.add(new HwiInstruction(this));
|
||||
instructionSet.add(new HwqInstruction(this));
|
||||
instructionSet.add(new XchgInstruction(this));
|
||||
instructionSet.add(new JcInstruction(this));
|
||||
instructionSet.add(new JncInstruction(this));
|
||||
instructionSet.add(new JnoInstruction(this));
|
||||
instructionSet.add(new JoInstruction(this));
|
||||
instructionSet.add(new PushfInstruction(this));
|
||||
instructionSet.add(new PopfInstruction(this));
|
||||
instructionSet.add(new JnaInstruction(this));
|
||||
instructionSet.add(new JaInstruction(this));
|
||||
|
||||
status = new Status();
|
||||
memory = new Memory(config.getInt("memory_size"));
|
||||
|
||||
GameEvent event = new CpuInitialisationEvent(this, user);
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
||||
if (event.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
status.clear();
|
||||
ip = codeSectionOffset;
|
||||
}
|
||||
|
||||
public int execute(int timeout) {
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
int counter = 0;
|
||||
status.clear();
|
||||
|
||||
registerSetSize = registerSet.size();
|
||||
|
||||
// status.breakFlag = true;
|
||||
while (!status.isBreakFlag()) {
|
||||
counter++;
|
||||
|
||||
if (counter % 10000 == 0) {
|
||||
if (System.currentTimeMillis() > (startTime + timeout)) {
|
||||
LogManager.LOGGER.fine("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double) counter / ((double) timeout / 1000) / 1000000 + "MHz");
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
|
||||
//fetch instruction
|
||||
int machineCode = memory.get(ip);
|
||||
|
||||
/*
|
||||
* Contents of machineCode should look like this:
|
||||
* SSSS SDDD DDOO OOOO
|
||||
* Where S is source, D is destination and O is the opCode
|
||||
*/
|
||||
Instruction instruction = instructionSet.get(machineCode & 0x03F); // 0000 0000 00XX XXXX
|
||||
|
||||
int source = (machineCode >> 11) & 0x001F; // XXXX X000 0000 0000
|
||||
int destination = (machineCode >> 6) & 0x001F; // 0000 0XXX XX00 0000
|
||||
|
||||
executeInstruction(instruction, source, destination);
|
||||
// LogManager.LOGGER.info(instruction.getMnemonic());
|
||||
}
|
||||
int elapsed = (int) (System.currentTimeMillis() - startTime);
|
||||
|
||||
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) {
|
||||
|
||||
|
||||
//Execute the instruction
|
||||
if (source == 0) {
|
||||
//No operand (assuming that destination is also null)
|
||||
ip++;
|
||||
instruction.execute(status);
|
||||
} else if (source == Operand.IMMEDIATE_VALUE) {
|
||||
ip++;
|
||||
int sourceValue = memory.get(ip);
|
||||
|
||||
if (destination == 0) {
|
||||
//Single operand
|
||||
ip++;
|
||||
instruction.execute(sourceValue, status);
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||
//Destination is an immediate value too
|
||||
//this shouldn't happen
|
||||
LogManager.LOGGER.severe("Trying to execute an instruction with 2" +
|
||||
"immediate values as operands"); //todo remove debug info
|
||||
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE_MEM) {
|
||||
//Destination is memory immediate
|
||||
ip += 2;
|
||||
instruction.execute(memory, memory.get(ip - 1), sourceValue, status);
|
||||
} else if (destination <= registerSetSize) {
|
||||
//Destination is a register
|
||||
ip++;
|
||||
instruction.execute(registerSet, destination, sourceValue, status);
|
||||
|
||||
} else if (destination <= registerSetSize * 2) {
|
||||
//Destination is [reg]
|
||||
ip++;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status);
|
||||
} else {
|
||||
//Assuming that destination is [reg + x]
|
||||
ip += 2;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1),
|
||||
sourceValue, status);
|
||||
}
|
||||
|
||||
} else if (source == Operand.IMMEDIATE_VALUE_MEM) {
|
||||
//Source is [x]
|
||||
ip++;
|
||||
int sourceValue = memory.get(memory.get(ip));
|
||||
|
||||
if (destination == 0) {
|
||||
//Single operand
|
||||
ip++;
|
||||
instruction.execute(memory, memory.get(ip - 1), status);
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||
//Destination is an immediate value
|
||||
|
||||
//this shouldn't happen
|
||||
LogManager.LOGGER.severe("Trying to execute an instruction with an" +
|
||||
"immediate values as dst operand"); //todo remove debug info
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE_MEM) {
|
||||
//Destination is memory immediate too
|
||||
ip += 2;
|
||||
instruction.execute(memory, memory.get(ip - 1), sourceValue, status);
|
||||
} else if (destination <= registerSetSize) {
|
||||
//Destination is a register
|
||||
ip++;
|
||||
instruction.execute(registerSet, destination, sourceValue, status);
|
||||
} else if (destination <= registerSetSize * 2) {
|
||||
//Destination is [reg]
|
||||
ip++;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), sourceValue, status);
|
||||
} else {
|
||||
//Assuming that destination is [reg + x]
|
||||
ip += 2;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1), sourceValue, status);
|
||||
}
|
||||
|
||||
} else if (source <= registerSetSize) {
|
||||
//Source is a register
|
||||
|
||||
if (destination == 0) {
|
||||
//Single operand
|
||||
ip++;
|
||||
instruction.execute(registerSet, source, status);
|
||||
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||
//Destination is an immediate value
|
||||
//this shouldn't happen
|
||||
LogManager.LOGGER.severe("Trying to execute an instruction with an" +
|
||||
"immediate values as dst operand"); //todo remove debug info
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE_MEM) {
|
||||
//Destination is memory immediate
|
||||
ip += 2;
|
||||
instruction.execute(memory, memory.get(ip - 1), registerSet, source, status);
|
||||
} else if (destination <= registerSetSize) {
|
||||
//Destination is a register too
|
||||
ip++;
|
||||
instruction.execute(registerSet, destination, registerSet, source, status);
|
||||
} else if (destination <= registerSetSize * 2) {
|
||||
//Destination is [reg]
|
||||
ip++;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), registerSet, source, status);
|
||||
} else {
|
||||
//Assuming that destination is [reg + x]
|
||||
ip += 2;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1),
|
||||
registerSet, source, status);
|
||||
}
|
||||
|
||||
} else if (source <= registerSetSize * 2) {
|
||||
//Source is [reg]
|
||||
if (destination == 0) {
|
||||
//Single operand
|
||||
ip++;
|
||||
instruction.execute(memory, registerSet.get(source - registerSetSize), status);
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||
//Destination is an immediate value
|
||||
//this shouldn't happen
|
||||
LogManager.LOGGER.severe("Trying to execute an instruction with an" +
|
||||
"immediate values as dst operand"); //todo remove debug info
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE_MEM) {
|
||||
//Destination is an memory immediate
|
||||
ip++;
|
||||
instruction.execute(memory, memory.get(ip++), memory, registerSet.get(source - registerSetSize), status);
|
||||
} else if (destination <= registerSetSize) {
|
||||
//Destination is a register
|
||||
ip++;
|
||||
instruction.execute(registerSet, destination, memory, registerSet.get(source - registerSetSize), status);
|
||||
} else if (destination <= registerSetSize * 2) {
|
||||
//Destination is [reg]
|
||||
ip++;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), memory, registerSet.get(source - registerSetSize), status);
|
||||
} else {
|
||||
//Assuming that destination is [reg + x]
|
||||
ip += 2;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1),
|
||||
memory, registerSet.get(source - registerSetSize), status);
|
||||
}
|
||||
} else {
|
||||
//Assuming that source is [reg + X]
|
||||
|
||||
ip++;
|
||||
int sourceDisp = memory.get(ip);
|
||||
|
||||
if (destination == 0) {
|
||||
//Single operand
|
||||
ip += 1;
|
||||
instruction.execute(memory, registerSet.get(source - registerSetSize - registerSetSize) + memory.get(ip - 1), status);
|
||||
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE) {
|
||||
//Destination is an immediate value
|
||||
//this shouldn't happen
|
||||
LogManager.LOGGER.severe("Trying to execute an instruction with an" +
|
||||
"immediate values as dst operand"); //todo remove debug info
|
||||
} else if (destination == Operand.IMMEDIATE_VALUE_MEM) {
|
||||
//Destination is memory immediate
|
||||
ip += 2;
|
||||
instruction.execute(memory, memory.get(ip - 1), memory,
|
||||
registerSet.get(source - registerSetSize - registerSetSize) + sourceDisp, status);
|
||||
} else if (destination <= registerSetSize) {
|
||||
//Destination is a register
|
||||
ip++;
|
||||
instruction.execute(registerSet, destination, memory,
|
||||
registerSet.get(source - registerSetSize - registerSetSize) + sourceDisp, status);
|
||||
} else if (destination <= registerSetSize * 2) {
|
||||
//Destination is [reg]
|
||||
ip++;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize), memory,
|
||||
registerSet.get(source - registerSetSize - registerSetSize) + sourceDisp, status);
|
||||
} else {
|
||||
//Assuming that destination is [reg + x]
|
||||
ip += 2;
|
||||
instruction.execute(memory, registerSet.get(destination - registerSetSize - registerSetSize) + memory.get(ip - 1),
|
||||
memory, registerSet.get(source - registerSetSize - registerSetSize) + sourceDisp, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("memory", memory.mongoSerialise());
|
||||
|
||||
dbObject.put("registerSet", registerSet.mongoSerialise());
|
||||
dbObject.put("codeSegmentOffset", codeSectionOffset);
|
||||
|
||||
BasicDBList hardwareList = new BasicDBList();
|
||||
|
||||
for (Integer address : attachedHardware.keySet()) {
|
||||
|
||||
CpuHardware hardware = attachedHardware.get(address);
|
||||
|
||||
BasicDBObject serialisedHw = hardware.mongoSerialise();
|
||||
serialisedHw.put("address", address);
|
||||
hardwareList.add(serialisedHw);
|
||||
}
|
||||
|
||||
dbObject.put("hardware", hardwareList);
|
||||
|
||||
return dbObject;
|
||||
|
||||
}
|
||||
|
||||
public static CPU deserialize(DBObject obj, User user) throws CancelledException {
|
||||
|
||||
CPU cpu = new CPU(GameServer.INSTANCE.getConfig(), user);
|
||||
|
||||
cpu.codeSectionOffset = (int) obj.get("codeSegmentOffset");
|
||||
|
||||
BasicDBList hardwareList = (BasicDBList) obj.get("hardware");
|
||||
|
||||
for (Object serialisedHw : hardwareList) {
|
||||
CpuHardware hardware = CpuHardware.deserialize((DBObject) serialisedHw);
|
||||
hardware.setCpu(cpu);
|
||||
cpu.attachHardware(hardware, (int) ((BasicDBObject) serialisedHw).get("address"));
|
||||
}
|
||||
|
||||
cpu.memory = Memory.deserialize((DBObject) obj.get("memory"));
|
||||
cpu.registerSet = RegisterSet.deserialize((DBObject) obj.get("registerSet"));
|
||||
|
||||
return cpu;
|
||||
|
||||
}
|
||||
|
||||
public InstructionSet getInstructionSet() {
|
||||
return instructionSet;
|
||||
}
|
||||
|
||||
public RegisterSet getRegisterSet() {
|
||||
return registerSet;
|
||||
}
|
||||
|
||||
public Memory getMemory() {
|
||||
return memory;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public int getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(char ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public void setCodeSectionOffset(int codeSectionOffset) {
|
||||
this.codeSectionOffset = codeSectionOffset;
|
||||
}
|
||||
|
||||
public void attachHardware(CpuHardware hardware, int address) {
|
||||
attachedHardware.put(address, hardware);
|
||||
}
|
||||
|
||||
public void detachHardware(int address) {
|
||||
attachedHardware.remove(address);
|
||||
}
|
||||
|
||||
public boolean hardwareInterrupt(int address) {
|
||||
CpuHardware hardware = attachedHardware.get(address);
|
||||
|
||||
if (hardware != null) {
|
||||
hardware.handleInterrupt(status);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void hardwareQuery(int address) {
|
||||
CpuHardware hardware = attachedHardware.get(address);
|
||||
|
||||
if (hardware != null) {
|
||||
|
||||
registerSet.getRegister("B").setValue(hardware.getId());
|
||||
} else {
|
||||
registerSet.getRegister("B").setValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
String str = "------------------------\n";
|
||||
str += registerSet.toString();
|
||||
str += status.toString();
|
||||
str += "------------------------\n";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public CpuHardware getHardware(int address) {
|
||||
|
||||
return attachedHardware.get(address);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.io.CpuHardwareDeserializer;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
|
||||
public abstract class CpuHardware implements MongoSerialisable {
|
||||
|
||||
CPU cpu;
|
||||
|
||||
/**
|
||||
* Handle an HWI instruction
|
||||
*/
|
||||
public abstract void handleInterrupt(Status status);
|
||||
|
||||
public CPU getCpu() {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
public void setCpu(CPU cpu) {
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
public abstract char getId();
|
||||
|
||||
public static CpuHardware deserialize(DBObject obj) {
|
||||
|
||||
for (ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()) {
|
||||
|
||||
if (plugin instanceof CpuHardwareDeserializer) {
|
||||
CpuHardware hw = ((CpuHardwareDeserializer) plugin).deserializeHardware(obj);
|
||||
|
||||
if (hw != null) {
|
||||
return hw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
/**
|
||||
* RegisterSet with default values
|
||||
*/
|
||||
class DefaultRegisterSet extends RegisterSet {
|
||||
|
||||
|
||||
DefaultRegisterSet() {
|
||||
super();
|
||||
|
||||
addRegister(1, new Register("A"));
|
||||
addRegister(2, new Register("B"));
|
||||
addRegister(3, new Register("C"));
|
||||
addRegister(4, new Register("D"));
|
||||
addRegister(5, new Register("X"));
|
||||
addRegister(6, new Register("Y"));
|
||||
addRegister(7, new Register("SP"));
|
||||
addRegister(8, new Register("BP"));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A set of registers for a CPU
|
||||
*/
|
||||
public class RegisterSet implements Target, MongoSerialisable {
|
||||
|
||||
/**
|
||||
* List of registers
|
||||
*/
|
||||
private HashMap<Integer, Register> registers = new HashMap<>(8);
|
||||
|
||||
|
||||
/**
|
||||
* Create an empty Register set
|
||||
*/
|
||||
public RegisterSet() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of a Register by its name
|
||||
* This method assumes that the
|
||||
*
|
||||
* @param name Name of the register
|
||||
* @return index of the register, -1 if not found
|
||||
*/
|
||||
int getIndex(String name) {
|
||||
|
||||
name = name.toUpperCase();
|
||||
|
||||
for (Integer i : registers.keySet()) {
|
||||
if (registers.get(i).getName().equals(name)) {
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a register by its index
|
||||
*
|
||||
* @param index index of the register
|
||||
*/
|
||||
public Register getRegister(int index) {
|
||||
return registers.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a register by its name (e.g. "AX")
|
||||
*
|
||||
* @param name Name of the register, case insensitive
|
||||
*/
|
||||
public Register getRegister(String name) {
|
||||
|
||||
name = name.toUpperCase();
|
||||
|
||||
for (Register r : registers.values()) {
|
||||
if (r.getName().equals(name)) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a register
|
||||
*
|
||||
* @param address Address of the value. Can refer to a memory address or the index
|
||||
* of a register
|
||||
* @return 16-bit value of a register
|
||||
*/
|
||||
@Override
|
||||
public int get(int address) {
|
||||
|
||||
Register register = registers.get(address);
|
||||
|
||||
if (register != null) {
|
||||
return register.getValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a register
|
||||
*
|
||||
* @param address index of the value to change
|
||||
* @param value value to set
|
||||
*/
|
||||
@Override
|
||||
public void set(int address, int value) {
|
||||
|
||||
Register register = registers.get(address);
|
||||
|
||||
if (register != null) {
|
||||
register.setValue(value);
|
||||
} else {
|
||||
LogManager.LOGGER.info("DEBUG: trying to set unknown reg index : " + address);
|
||||
}
|
||||
}
|
||||
|
||||
public void put(int index, Register register) {
|
||||
registers.put(index, register);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
for (Register register : registers.values()) {
|
||||
register.setValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a register to the register set
|
||||
* <p>
|
||||
* the register set will break if the indexes of the registers
|
||||
* are not consecutive, starting at address 1.
|
||||
*
|
||||
* @param index Index of the register
|
||||
* @param reg Register to add
|
||||
*/
|
||||
void addRegister(int index, Register reg) {
|
||||
registers.put(index, reg);
|
||||
}
|
||||
|
||||
int size() {
|
||||
return registers.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
BasicDBList registers = new BasicDBList();
|
||||
for (Integer index : this.registers.keySet()) {
|
||||
JSONObject register = new JSONObject();
|
||||
|
||||
register.put("index", index);
|
||||
register.put("name", getRegister(index).getName());
|
||||
register.put("value", (int) getRegister(index).getValue());
|
||||
|
||||
registers.add(register);
|
||||
}
|
||||
|
||||
BasicDBObject obj = new BasicDBObject();
|
||||
obj.put("registers", registers);
|
||||
|
||||
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) {
|
||||
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
|
||||
JSONArray registers = (JSONArray) json.get("registers");
|
||||
|
||||
for (JSONObject jsonRegister : (ArrayList<JSONObject>) registers) {
|
||||
|
||||
Register register = new Register((String) jsonRegister.get("name"));
|
||||
register.setValue((int) (long) jsonRegister.get("value"));
|
||||
|
||||
registerSet.registers.put((int) (long) jsonRegister.get("index"), register);
|
||||
|
||||
}
|
||||
|
||||
return registerSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String str = "";
|
||||
|
||||
for (Integer index : registers.keySet()) {
|
||||
str += index + " " + registers.get(index).getName() + "=" + Util.toHex(registers.get(index).getValue()) + "\n";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
import net.simon987.server.assembly.Status;
|
||||
import net.simon987.server.assembly.Target;
|
||||
|
||||
/**
|
||||
* Send hardware interupt
|
||||
* Used to interact with the World using hardware
|
||||
* </p>
|
||||
*/
|
||||
public class HwiInstruction extends Instruction {
|
||||
|
||||
public static final int OPCODE = 9;
|
||||
|
||||
private CPU cpu;
|
||||
|
||||
public HwiInstruction(CPU cpu) {
|
||||
super("hwi", OPCODE);
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(Target src, int srcIndex, Status status) {
|
||||
status.setErrorFlag(cpu.hardwareInterrupt(src.get(srcIndex)));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status execute(int src, Status status) {
|
||||
|
||||
status.setErrorFlag(cpu.hardwareInterrupt(src));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
|
||||
/**
|
||||
* NOP (No operation instruction).
|
||||
* Does nothing
|
||||
*/
|
||||
public class NopInstruction extends Instruction {
|
||||
|
||||
public NopInstruction() {
|
||||
super("nop", 63);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.assembly.Instruction;
|
||||
|
||||
/**
|
||||
* Alias of SHL instruction
|
||||
*/
|
||||
public class SalInstruction extends Instruction {
|
||||
|
||||
public SalInstruction() {
|
||||
super("sal", ShlInstruction.OPCODE);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package net.simon987.server.event;
|
||||
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
public class CpuInitialisationEvent extends GameEvent {
|
||||
|
||||
private User user;
|
||||
|
||||
public CpuInitialisationEvent(CPU cpu, User user) {
|
||||
setSource(cpu);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package net.simon987.server.event;
|
||||
|
||||
import net.simon987.server.plugin.PluginManager;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class GameEventDispatcher {
|
||||
|
||||
private PluginManager pluginManager;
|
||||
|
||||
private ArrayList<GameEventListener> listeners;
|
||||
|
||||
public GameEventDispatcher(PluginManager pluginManager) {
|
||||
this.pluginManager = pluginManager;
|
||||
listeners = new ArrayList<>(5);
|
||||
}
|
||||
|
||||
public void dispatch(GameEvent event) {
|
||||
|
||||
//Dispatch to 'local' listeners
|
||||
for (GameEventListener listener : listeners) {
|
||||
if (event.getClass().equals(listener.getListenedEventType())) {
|
||||
listener.handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
//Dispatch to plugins
|
||||
for (ServerPlugin plugin : pluginManager.getPlugins()) {
|
||||
for (GameEventListener listener : plugin.getListeners()) {
|
||||
if (event.getClass().equals(listener.getListenedEventType())) {
|
||||
listener.handle(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ArrayList<GameEventListener> getListeners() {
|
||||
return listeners;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package net.simon987.server.event;
|
||||
|
||||
/**
|
||||
* Event dispatched by a GameObject who has needed callbacks on death
|
||||
*/
|
||||
public class ObjectDeathEvent extends GameEvent {
|
||||
/**
|
||||
* The GameObject type ID of object that init this event
|
||||
*/
|
||||
private long sourceObjectId;
|
||||
|
||||
public ObjectDeathEvent(Object source, int sourceObjectId) {
|
||||
setSource(source);
|
||||
this.sourceObjectId = sourceObjectId;
|
||||
}
|
||||
|
||||
public long getSourceObjectId() {
|
||||
return sourceObjectId;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
public enum Action {
|
||||
IDLE,
|
||||
DIGGING,
|
||||
WALKING,
|
||||
WITHDRAWING,
|
||||
DEPOSITING,
|
||||
LISTENING
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
import net.simon987.server.assembly.Memory;
|
||||
import net.simon987.server.user.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface ControllableUnit {
|
||||
|
||||
long getObjectId();
|
||||
|
||||
void setKeyboardBuffer(ArrayList<Integer> kbBuffer);
|
||||
|
||||
void setParent(User user);
|
||||
|
||||
ArrayList<Integer> getKeyboardBuffer();
|
||||
|
||||
Memory getFloppyData();
|
||||
|
||||
boolean spendEnergy(int energy);
|
||||
|
||||
int getEnergy();
|
||||
|
||||
int getX();
|
||||
|
||||
int getY();
|
||||
|
||||
void setAction(Action listening);
|
||||
|
||||
World getWorld();
|
||||
|
||||
ArrayList<char[]> getConsoleMessagesBuffer();
|
||||
|
||||
int getConsoleMode();
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.io.GameObjectDeserializer;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import net.simon987.server.plugin.ServerPlugin;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* An INSTANCE of an object (e.g. a Tree, a character ...) inside the
|
||||
* game universe
|
||||
*/
|
||||
public abstract class GameObject implements JSONSerialisable, MongoSerialisable {
|
||||
|
||||
private boolean dead;
|
||||
/**
|
||||
* Object's unique identifier
|
||||
*/
|
||||
private long objectId;
|
||||
|
||||
/**
|
||||
* X coordinate of the object in its World
|
||||
*/
|
||||
private int x;
|
||||
|
||||
/**
|
||||
* Y coordinate of the object in its World
|
||||
*/
|
||||
private int y;
|
||||
|
||||
/**
|
||||
* Direction of the object
|
||||
*/
|
||||
private Direction direction = Direction.NORTH;
|
||||
|
||||
/**
|
||||
* Current World of the object
|
||||
*/
|
||||
private World world;
|
||||
|
||||
|
||||
//--------
|
||||
|
||||
/**
|
||||
* Increment the location of the game object by 1 tile
|
||||
* Collision checks happen here
|
||||
*/
|
||||
public boolean incrementLocation() {
|
||||
|
||||
int newX = 0, newY = 0;
|
||||
|
||||
if (direction == Direction.NORTH) {
|
||||
newX = x;
|
||||
newY = (y - 1);
|
||||
|
||||
} else if (direction == Direction.EAST) {
|
||||
newX = (x + 1);
|
||||
newY = y;
|
||||
|
||||
} else if (direction == Direction.SOUTH) {
|
||||
newX = x;
|
||||
newY = (y + 1);
|
||||
|
||||
} else if (direction == Direction.WEST) {
|
||||
newX = (x - 1);
|
||||
newY = y;
|
||||
}
|
||||
|
||||
|
||||
//Check if out of World bounds / collision
|
||||
if (newX < 0) {
|
||||
//Move object to adjacent World (left)
|
||||
World leftWorld;
|
||||
if (world.getX() == 0) {
|
||||
//Warp around
|
||||
leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(
|
||||
GameServer.INSTANCE.getGameUniverse().getMaxWidth(), world.getY(), true);
|
||||
} else {
|
||||
leftWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() - 1, world.getY(), true);
|
||||
}
|
||||
|
||||
if (leftWorld != null) {
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
leftWorld.addObject(this);
|
||||
leftWorld.incUpdatable();
|
||||
setWorld(leftWorld);
|
||||
|
||||
x = World.WORLD_SIZE - 1;
|
||||
}
|
||||
} else if (newX >= World.WORLD_SIZE) {
|
||||
//Move object to adjacent World (right)
|
||||
World rightWorld;
|
||||
if (world.getX() == GameServer.INSTANCE.getGameUniverse().getMaxWidth()) {
|
||||
//Warp around
|
||||
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(0, world.getY(), true);
|
||||
} else {
|
||||
rightWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX() + 1, world.getY(), true);
|
||||
}
|
||||
|
||||
if (rightWorld != null) {
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
rightWorld.addObject(this);
|
||||
rightWorld.incUpdatable();
|
||||
setWorld(rightWorld);
|
||||
|
||||
x = 0;
|
||||
}
|
||||
} else if (newY < 0) {
|
||||
//Move object to adjacent World (up)
|
||||
World upWorld;
|
||||
if (world.getY() == 0) {
|
||||
//Warp around
|
||||
upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(),
|
||||
GameServer.INSTANCE.getGameUniverse().getMaxWidth(), true);
|
||||
} else {
|
||||
upWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() - 1, true);
|
||||
}
|
||||
|
||||
if (upWorld != null) {
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
upWorld.addObject(this);
|
||||
upWorld.incUpdatable();
|
||||
setWorld(upWorld);
|
||||
|
||||
y = World.WORLD_SIZE - 1;
|
||||
}
|
||||
} else if (newY >= World.WORLD_SIZE) {
|
||||
//Move object to adjacent World (down)
|
||||
World downWorld;
|
||||
if (world.getY() == GameServer.INSTANCE.getGameUniverse().getMaxWidth()) {
|
||||
//Warp around
|
||||
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), 0, true);
|
||||
} else {
|
||||
downWorld = GameServer.INSTANCE.getGameUniverse().getWorld(world.getX(), world.getY() + 1, true);
|
||||
}
|
||||
|
||||
|
||||
if (downWorld != null) {
|
||||
world.removeObject(this);
|
||||
world.decUpdatable();
|
||||
downWorld.addObject(this);
|
||||
downWorld.incUpdatable();
|
||||
setWorld(downWorld);
|
||||
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
//Check collision
|
||||
else if (!world.isTileBlocked(newX, newY)) {
|
||||
//Tile is passable
|
||||
x = newX;
|
||||
y = newY;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public abstract char getMapInfo();
|
||||
|
||||
public Point getFrontTile() {
|
||||
|
||||
if (direction == Direction.NORTH) {
|
||||
return new Point(x, y - 1);
|
||||
} else if (direction == Direction.EAST) {
|
||||
return new Point(x + 1, y);
|
||||
} else if (direction == Direction.SOUTH) {
|
||||
return new Point(x, y + 1);
|
||||
} else {
|
||||
return new Point(x - 1, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public long getObjectId() {
|
||||
return objectId;
|
||||
}
|
||||
|
||||
public void setObjectId(long objectId) {
|
||||
this.objectId = objectId;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(Direction direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public void setWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
return new JSONObject();
|
||||
}
|
||||
|
||||
public static GameObject deserialize(DBObject obj) {
|
||||
//
|
||||
for (ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()) {
|
||||
|
||||
if (plugin instanceof GameObjectDeserializer) {
|
||||
GameObject object = ((GameObjectDeserializer) plugin).deserializeObject(obj);
|
||||
|
||||
if (object != null) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public boolean isAt(int x, int y) {
|
||||
return this.x == x && this.y == y;
|
||||
}
|
||||
|
||||
public boolean isDead() {
|
||||
return dead;
|
||||
}
|
||||
|
||||
public void setDead(boolean dead) {
|
||||
this.dead = dead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before this GameObject is removed from the world - defaults to doing nothing
|
||||
*/
|
||||
public void onDeadCallback() { }
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
|
||||
public interface InventoryHolder {
|
||||
|
||||
/**
|
||||
* Place an item into the inventory
|
||||
*
|
||||
* @param item item id (see MarConstants.ITEM_*)
|
||||
*/
|
||||
boolean placeItem(int item);
|
||||
|
||||
/**
|
||||
* Take an item from the inventory
|
||||
*
|
||||
* @param item Desired item id (see MarConstants.ITEM_*)
|
||||
*/
|
||||
void takeItem(int item);
|
||||
|
||||
/**
|
||||
* @param item item to take
|
||||
* @return true if the InventoryHolder can provide this item
|
||||
*/
|
||||
boolean canTakeItem(int item);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
public interface Programmable {
|
||||
|
||||
boolean sendMessage(char[] message);
|
||||
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
package net.simon987.server.game;
|
||||
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.Random;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterOutputStream;
|
||||
|
||||
/**
|
||||
* A 2D map of Tile objects of size width*height
|
||||
*/
|
||||
public class TileMap implements JSONSerialisable, MongoSerialisable {
|
||||
|
||||
public static final int PLAIN_TILE = 0;
|
||||
public static final int WALL_TILE = 1;
|
||||
public static final int IRON_TILE = 2;
|
||||
public static final int COPPER_TILE = 3;
|
||||
|
||||
public static final int ITEM_IRON = 3;
|
||||
public static final int ITEM_COPPER = 4;
|
||||
|
||||
/**
|
||||
* The map of tile
|
||||
*/
|
||||
private int[][] tiles;
|
||||
|
||||
/**
|
||||
* width, in tiles
|
||||
*/
|
||||
private int width;
|
||||
|
||||
/**
|
||||
* Height, in tiles
|
||||
*/
|
||||
private int height;
|
||||
|
||||
/**
|
||||
* Create a blank (All 0s) map
|
||||
*/
|
||||
public TileMap(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
tiles = new int[width][height];
|
||||
}
|
||||
|
||||
public TileMap(int[][] tiles) {
|
||||
this.width = World.WORLD_SIZE;
|
||||
this.height = World.WORLD_SIZE;
|
||||
|
||||
this.tiles = tiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the tile at a specified position
|
||||
* Sets the modified flag
|
||||
*
|
||||
* @param tileId id of the new Tile
|
||||
* @param x X coordinate of the tile to set
|
||||
* @param y Y coordinate of the tile to set
|
||||
*/
|
||||
public void setTileAt(int tileId, int x, int y) {
|
||||
|
||||
try {
|
||||
tiles[x][y] = tileId;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
//Shouldn't happen
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tile at a specific position
|
||||
*
|
||||
* @param x X coordinate of the tile to get
|
||||
* @param y Y coordinate of the tile to get
|
||||
* @return the tile at the specified position, -1 if out of bounds
|
||||
*/
|
||||
public int getTileAt(int x, int y) {
|
||||
try {
|
||||
return tiles[x][y];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int[][] getTiles() {
|
||||
return tiles;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
byte[] terrain = new byte[width * width];
|
||||
|
||||
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
||||
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
||||
terrain[x * width + y] = (byte) tiles[x][y];
|
||||
}
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION, true);
|
||||
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(stream, compressor);
|
||||
|
||||
deflaterOutputStream.write(terrain);
|
||||
|
||||
deflaterOutputStream.close();
|
||||
byte[] compressedBytes = stream.toByteArray();
|
||||
|
||||
json.put("z", new String(Base64.getEncoder().encode(compressedBytes)));
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("tiles", tiles);
|
||||
|
||||
return dbObject;
|
||||
|
||||
}
|
||||
|
||||
public static TileMap deserialize(DBObject object) {
|
||||
|
||||
BasicDBList terrain = (BasicDBList) object.get("tiles");
|
||||
|
||||
int[][] tiles = new int[World.WORLD_SIZE][World.WORLD_SIZE];
|
||||
|
||||
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
||||
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
||||
tiles[x][y] = (int) ((BasicDBList) terrain.get(x)).get(y);
|
||||
}
|
||||
}
|
||||
|
||||
return new TileMap(tiles);
|
||||
|
||||
}
|
||||
|
||||
public static TileMap deserialize(JSONObject object) {
|
||||
|
||||
TileMap tileMap = new TileMap(World.WORLD_SIZE, World.WORLD_SIZE);
|
||||
|
||||
byte[] compressedBytes = Base64.getDecoder().decode((String) object.get("z"));
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Inflater decompressor = new Inflater(true);
|
||||
InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(baos, decompressor);
|
||||
inflaterOutputStream.write(compressedBytes);
|
||||
inflaterOutputStream.close();
|
||||
|
||||
byte[] terrain = baos.toByteArray();
|
||||
|
||||
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
||||
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
||||
tileMap.tiles[x][y] = terrain[x * World.WORLD_SIZE + y];
|
||||
}
|
||||
}
|
||||
|
||||
return tileMap;
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Point getRandomPlainTile() {
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
int counter = 0;
|
||||
while (true) {
|
||||
counter++;
|
||||
|
||||
//Prevent infinite loop
|
||||
if (counter >= 2500) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int rx = random.nextInt(World.WORLD_SIZE);
|
||||
int ry = random.nextInt(World.WORLD_SIZE);
|
||||
|
||||
if (tiles[rx][ry] == TileMap.PLAIN_TILE) {
|
||||
return new Point(rx, ry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.assembly.CpuHardware;
|
||||
|
||||
public interface CpuHardwareDeserializer {
|
||||
|
||||
|
||||
CpuHardware deserializeHardware(DBObject hwJson);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Manages the database: this class manages the interactions with the database
|
||||
*/
|
||||
public abstract class DatabaseManager {
|
||||
|
||||
/**
|
||||
* SQL connection url
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* SQL username
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* SQL password
|
||||
*/
|
||||
private String password;
|
||||
|
||||
public DatabaseManager(ServerConfiguration config) {
|
||||
this.url = config.getString("mysql_url");
|
||||
this.username = config.getString("mysql_user");
|
||||
this.password = config.getString("mysql_pass");
|
||||
}
|
||||
|
||||
protected Connection getConnection() {
|
||||
try {
|
||||
return DriverManager.getConnection(url, this.username, password);
|
||||
} catch (SQLException e) {
|
||||
LogManager.LOGGER.severe("Couldn't connect to MySQL server state:" + e.getSQLState() + " error:" + e.getErrorCode());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
private static final String DATE_FORMAT = "yyyyMMddHHmmss";
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new stamp containing the current date and time
|
||||
*
|
||||
* @return date and time stamp
|
||||
*/
|
||||
private static String getDateTimeStamp() {
|
||||
Date millisToDate = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat f = new SimpleDateFormat(DATE_FORMAT);
|
||||
return f.format(millisToDate);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.game.GameObject;
|
||||
|
||||
public interface GameObjectDeserializer {
|
||||
|
||||
GameObject deserializeObject(DBObject object);
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface JSONSerialisable {
|
||||
|
||||
JSONObject serialise();
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package net.simon987.server.io;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
|
||||
public interface MongoSerialisable {
|
||||
|
||||
BasicDBObject mongoSerialise();
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package net.simon987.server.plugin;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class PluginManager {
|
||||
|
||||
private ArrayList<ServerPlugin> plugins;
|
||||
|
||||
public PluginManager() {
|
||||
this.plugins = new ArrayList<>(10);
|
||||
}
|
||||
|
||||
public void load(File pluginFile, ServerConfiguration config) {
|
||||
|
||||
LogManager.LOGGER.info("Loading plugin file " + pluginFile.getName());
|
||||
|
||||
try {
|
||||
//Get the plugin config file from the archive
|
||||
ZipFile zipFile = new ZipFile(pluginFile);
|
||||
|
||||
ZipEntry configEntry = zipFile.getEntry("plugin.properties");
|
||||
|
||||
if (configEntry != null) {
|
||||
|
||||
InputStream stream = zipFile.getInputStream(configEntry);
|
||||
Properties pluginConfig = new Properties();
|
||||
pluginConfig.load(stream);
|
||||
|
||||
//Load the plugin
|
||||
ClassLoader loader = URLClassLoader.newInstance(new URL[]{pluginFile.toURI().toURL()});
|
||||
Class<?> aClass = Class.forName(pluginConfig.getProperty("classpath"), true, loader);
|
||||
Class<? extends ServerPlugin> pluginClass = aClass.asSubclass(ServerPlugin.class);
|
||||
Constructor<? extends ServerPlugin> constructor = pluginClass.getConstructor();
|
||||
|
||||
ServerPlugin plugin = constructor.newInstance();
|
||||
plugin.setName(pluginConfig.getProperty("name"));
|
||||
plugin.setVersion(pluginConfig.getProperty("version"));
|
||||
|
||||
LogManager.LOGGER.info("Loaded " + plugin.name + " V" + plugin.version);
|
||||
|
||||
//Add it to the list
|
||||
plugins.add(plugin);
|
||||
|
||||
//Init the plugin
|
||||
plugin.init(config);
|
||||
|
||||
} else {
|
||||
LogManager.LOGGER.severe("Couldn't find plugin.properties in " + pluginFile.getName());
|
||||
}
|
||||
zipFile.close();
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<ServerPlugin> getPlugins() {
|
||||
return plugins;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package net.simon987.server.plugin;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.event.GameEventListener;
|
||||
import net.simon987.server.io.JSONSerialisable;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class ServerPlugin implements JSONSerialisable {
|
||||
|
||||
/**
|
||||
* Name of the plugin
|
||||
*/
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Version of the plugin
|
||||
*/
|
||||
protected String version;
|
||||
|
||||
/**
|
||||
* List of event listeners
|
||||
*/
|
||||
protected ArrayList<GameEventListener> listeners = new ArrayList<>(5);
|
||||
|
||||
/**
|
||||
* Called when the plugin is loaded
|
||||
*/
|
||||
public abstract void init(ServerConfiguration config);
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public ArrayList<GameEventListener> getListeners() {
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialise() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
json.put("name", name);
|
||||
json.put("version", version);
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package net.simon987.server.user;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.assembly.CPU;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.event.GameEvent;
|
||||
import net.simon987.server.event.UserCreationEvent;
|
||||
import net.simon987.server.game.ControllableUnit;
|
||||
import net.simon987.server.io.MongoSerialisable;
|
||||
|
||||
/**
|
||||
* Represents a User (or player) of the game
|
||||
*/
|
||||
public class User implements MongoSerialisable {
|
||||
|
||||
private String username;
|
||||
|
||||
private String userCode;
|
||||
|
||||
private CPU cpu;
|
||||
|
||||
private ControllableUnit controlledUnit;
|
||||
|
||||
private boolean guest;
|
||||
|
||||
public User() throws CancelledException {
|
||||
GameEvent event = new UserCreationEvent(this);
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
||||
if (event.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public User(ControllableUnit unit) {
|
||||
this.controlledUnit = unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicDBObject mongoSerialise() {
|
||||
|
||||
BasicDBObject dbObject = new BasicDBObject();
|
||||
|
||||
dbObject.put("_id", username); // a constant id ensures only one entry per user is kept and updated, instead of a new entry created every save for every user.
|
||||
dbObject.put("username", username);
|
||||
dbObject.put("code", userCode);
|
||||
dbObject.put("controlledUnit", controlledUnit.getObjectId());
|
||||
dbObject.put("cpu", cpu.mongoSerialise());
|
||||
|
||||
return dbObject;
|
||||
|
||||
}
|
||||
|
||||
public static User deserialize(DBObject obj) throws CancelledException {
|
||||
|
||||
User user = new User((ControllableUnit) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("controlledUnit")));
|
||||
user.username = (String) obj.get("username");
|
||||
user.userCode = (String) obj.get("code");
|
||||
|
||||
user.getControlledUnit().setParent(user);
|
||||
|
||||
user.cpu = CPU.deserialize((DBObject) obj.get("cpu"), user);
|
||||
|
||||
return user;
|
||||
}
|
||||
//----
|
||||
|
||||
public String getUserCode() {
|
||||
return userCode;
|
||||
}
|
||||
|
||||
public void setUserCode(String userCode) {
|
||||
this.userCode = userCode;
|
||||
}
|
||||
|
||||
public CPU getCpu() {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
public void setCpu(CPU cpu) {
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public ControllableUnit getControlledUnit() {
|
||||
return controlledUnit;
|
||||
}
|
||||
|
||||
public void setControlledUnit(ControllableUnit controlledUnit) {
|
||||
this.controlledUnit = controlledUnit;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public boolean isGuest() {
|
||||
return guest;
|
||||
}
|
||||
|
||||
public void setGuest(boolean guest) {
|
||||
this.guest = guest;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class FloppyHandler implements MessageHandler {
|
||||
|
||||
SocketServerDatabase db = new SocketServerDatabase(GameServer.INSTANCE.getConfig());
|
||||
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject json) {
|
||||
|
||||
if (json.get("t").equals("floppyDown")) {
|
||||
|
||||
LogManager.LOGGER.fine("(WS) Floppy download request from " + user.getUser().getUsername());
|
||||
|
||||
if (user.isGuest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.getUser().getControlledUnit().getFloppyData() != null) {
|
||||
byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes();
|
||||
user.getWebSocket().send(bytes);
|
||||
}
|
||||
|
||||
|
||||
} else if (json.get("t").equals("floppyUp")) {
|
||||
|
||||
LogManager.LOGGER.fine("(WS) Floppy upload request from " + user.getUser().getUsername());
|
||||
|
||||
//Check newly uploaded file on the database
|
||||
byte[] bytes = db.getFloppy(user.getUser().getUsername());
|
||||
|
||||
if (bytes != null) {
|
||||
user.getUser().getControlledUnit().getFloppyData().setBytes(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import org.java_websocket.exceptions.WebsocketNotConnectedException;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public interface MessageHandler {
|
||||
|
||||
void handle(OnlineUser user, JSONObject json) throws WebsocketNotConnectedException;
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class OnlineUserManager {
|
||||
|
||||
/**
|
||||
* List of online users.
|
||||
*/
|
||||
private ArrayList<OnlineUser> onlineUsers = new ArrayList<>(10);
|
||||
|
||||
|
||||
public OnlineUser getUser(WebSocket socket) {
|
||||
|
||||
ArrayList<OnlineUser> _onlineUsers = new ArrayList<>(onlineUsers);
|
||||
|
||||
for (OnlineUser user : _onlineUsers) {
|
||||
if (user.getWebSocket().equals(socket)) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an user to the list
|
||||
*
|
||||
* @param user user to add
|
||||
*/
|
||||
public void add(OnlineUser user) {
|
||||
onlineUsers.add(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an user to the list
|
||||
*
|
||||
* @param user user to remove
|
||||
*/
|
||||
public void remove(OnlineUser user) {
|
||||
onlineUsers.remove(user);
|
||||
}
|
||||
|
||||
public ArrayList<OnlineUser> getOnlineUsers() {
|
||||
return onlineUsers;
|
||||
}
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.game.ControllableUnit;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.server.user.User;
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.DefaultSSLWebSocketServerFactory;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.BindException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class SocketServer extends WebSocketServer {
|
||||
|
||||
private OnlineUserManager userManager = new OnlineUserManager();
|
||||
|
||||
private SocketServerDatabase database;
|
||||
|
||||
private MessageEventDispatcher messageEventDispatcher = new MessageEventDispatcher();
|
||||
|
||||
public SocketServer(InetSocketAddress address, ServerConfiguration config) {
|
||||
super(address);
|
||||
|
||||
if (config.getInt("use_secure_webSocket") != 0) {
|
||||
|
||||
SSLContext context = getContext(config.getString("cert_path"));
|
||||
if (context != null) {
|
||||
setWebSocketFactory(new DefaultSSLWebSocketServerFactory(context));
|
||||
|
||||
LogManager.LOGGER.info("(WS) Enabled secure webSocket");
|
||||
} else {
|
||||
LogManager.LOGGER.severe("(WS) Failed to create SSL context");
|
||||
}
|
||||
}
|
||||
|
||||
setConnectionLostTimeout(120);
|
||||
setReuseAddr(true); //To avoid BindException
|
||||
|
||||
database = new SocketServerDatabase(config);
|
||||
|
||||
messageEventDispatcher.addHandler(new UserInfoRequestHandler());
|
||||
messageEventDispatcher.addHandler(new TerrainRequestHandler());
|
||||
messageEventDispatcher.addHandler(new ObjectsRequestHandler());
|
||||
messageEventDispatcher.addHandler(new CodeUploadHandler());
|
||||
messageEventDispatcher.addHandler(new CodeRequestHandler());
|
||||
messageEventDispatcher.addHandler(new KeypressHandler());
|
||||
messageEventDispatcher.addHandler(new FloppyHandler());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket conn, ClientHandshake handshake) {
|
||||
LogManager.LOGGER.info("(WS) New Websocket connection " + conn.getRemoteSocketAddress());
|
||||
userManager.add(new OnlineUser(conn));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
|
||||
LogManager.LOGGER.info("(WS) Closed " + conn.getRemoteSocketAddress() + " with exit code " + code + " additional info: " + reason);
|
||||
userManager.remove(userManager.getUser(conn));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, String message) {
|
||||
OnlineUser onlineUser = userManager.getUser(conn);
|
||||
|
||||
if (onlineUser != null) {
|
||||
|
||||
if (onlineUser.isAuthenticated()) {
|
||||
|
||||
messageEventDispatcher.dispatch(onlineUser, message);
|
||||
|
||||
} else {
|
||||
LogManager.LOGGER.info("(WS) Received message from unauthenticated user " + conn.getRemoteSocketAddress());
|
||||
|
||||
//We expect a 128 characters long token
|
||||
if (message.length() == 128) {
|
||||
|
||||
String username = database.validateAuthToken(message);
|
||||
|
||||
if (username != null) {
|
||||
User user = GameServer.INSTANCE.getGameUniverse().getOrCreateUser(username, true);
|
||||
|
||||
LogManager.LOGGER.info("(WS) User was successfully authenticated: " + user.getUsername());
|
||||
|
||||
onlineUser.setUser(user);
|
||||
onlineUser.setAuthenticated(true);
|
||||
|
||||
conn.send("{\"t\":\"auth\", \"m\":\"ok\"}");
|
||||
|
||||
} else {
|
||||
|
||||
User user = GameServer.INSTANCE.getGameUniverse().getOrCreateUser(GameServer.INSTANCE.getGameUniverse().getGuestUsername(), false);
|
||||
onlineUser.setUser(user);
|
||||
onlineUser.setAuthenticated(true);
|
||||
onlineUser.setGuest(true);
|
||||
|
||||
LogManager.LOGGER.info("(WS) Created guest user " +
|
||||
onlineUser.getUser().getUsername() + conn.getRemoteSocketAddress());
|
||||
|
||||
conn.send("{\"t\":\"auth\", \"m\":\"ok\"}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
LogManager.LOGGER.severe("(WS) FIXME: SocketServer:onMessage");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, ByteBuffer message) {
|
||||
//System.out.println("received ByteBuffer from " + conn.getRemoteSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket conn, Exception ex) {
|
||||
|
||||
if (ex instanceof BindException) {
|
||||
|
||||
LogManager.LOGGER.severe("Address already in use");
|
||||
System.exit(-1);
|
||||
|
||||
} else {
|
||||
LogManager.LOGGER.severe("an error occurred on connection " + conn + ": " + ex);
|
||||
userManager.remove(userManager.getUser(conn));
|
||||
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
LogManager.LOGGER.info("(WS) Server started successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called every tick
|
||||
*/
|
||||
public void tick() {
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("t", "tick");
|
||||
|
||||
LogManager.LOGGER.info("Notified " + userManager.getOnlineUsers().size() + " users");
|
||||
|
||||
ArrayList<OnlineUser> onlineUsers = new ArrayList<>(userManager.getOnlineUsers()); //Avoid ConcurrentModificationException
|
||||
for (OnlineUser user : onlineUsers) {
|
||||
|
||||
if (user.getWebSocket().isOpen()) {
|
||||
|
||||
if (user.isGuest()) {
|
||||
|
||||
json.remove("c");
|
||||
user.getWebSocket().send(json.toJSONString());
|
||||
|
||||
} else {
|
||||
try {
|
||||
ControllableUnit unit = user.getUser().getControlledUnit();
|
||||
|
||||
//Send keyboard updated buffer
|
||||
ArrayList<Integer> kbBuffer = unit.getKeyboardBuffer();
|
||||
JSONArray keys = new JSONArray();
|
||||
keys.addAll(kbBuffer);
|
||||
json.put("keys", keys);
|
||||
|
||||
//Send console buffer
|
||||
if (unit.getConsoleMessagesBuffer().size() > 0) {
|
||||
|
||||
JSONArray buff = new JSONArray();
|
||||
|
||||
for (char[] message : unit.getConsoleMessagesBuffer()) {
|
||||
buff.add(new String(message));
|
||||
}
|
||||
|
||||
json.put("c", buff);
|
||||
} else {
|
||||
json.remove("c");
|
||||
}
|
||||
|
||||
json.put("cm", unit.getConsoleMode());
|
||||
|
||||
|
||||
//Send tick message
|
||||
user.getWebSocket().send(json.toJSONString());
|
||||
} catch (NullPointerException e) {
|
||||
//User is online but not completely initialised
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public OnlineUserManager getUserManager() {
|
||||
return userManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See https://github.com/TooTallNate/Java-WebSocket/blob/master/src/main/example/SSLServerLetsEncryptExample.java
|
||||
*/
|
||||
/*
|
||||
* * Copyright (c) 2010-2017 Nathan Rajlich
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*/
|
||||
private static SSLContext getContext(String pathTo) {
|
||||
SSLContext context;
|
||||
String password = "MAR";
|
||||
try {
|
||||
context = SSLContext.getInstance("TLS");
|
||||
|
||||
byte[] certBytes = parseDERFromPEM(getBytes(new File(pathTo + File.separator + "cert.pem")),
|
||||
"-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
|
||||
byte[] keyBytes = parseDERFromPEM(getBytes(new File(pathTo + File.separator + "privkey.pem")),
|
||||
"-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");
|
||||
|
||||
X509Certificate cert = generateCertificateFromDER(certBytes);
|
||||
RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);
|
||||
|
||||
KeyStore keystore = KeyStore.getInstance("JKS");
|
||||
keystore.load(null);
|
||||
keystore.setCertificateEntry("cert-alias", cert);
|
||||
keystore.setKeyEntry("key-alias", key, password.toCharArray(), new Certificate[]{cert});
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(keystore, password.toCharArray());
|
||||
|
||||
KeyManager[] km = kmf.getKeyManagers();
|
||||
|
||||
context.init(km, null, null);
|
||||
} catch (Exception e) {
|
||||
context = null;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private static byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
|
||||
String data = new String(pem);
|
||||
String[] tokens = data.split(beginDelimiter);
|
||||
tokens = tokens[1].split(endDelimiter);
|
||||
return DatatypeConverter.parseBase64Binary(tokens[0]);
|
||||
}
|
||||
|
||||
private static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
|
||||
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
|
||||
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
|
||||
return (RSAPrivateKey) factory.generatePrivate(spec);
|
||||
}
|
||||
|
||||
private static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
|
||||
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
|
||||
return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
|
||||
}
|
||||
|
||||
private static byte[] getBytes(File file) {
|
||||
byte[] bytesArray = new byte[(int) file.length()];
|
||||
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
fis.read(bytesArray); //read file into bytes[]
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bytesArray;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.io.DatabaseManager;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
class SocketServerDatabase extends DatabaseManager {
|
||||
|
||||
public SocketServerDatabase(ServerConfiguration config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
String validateAuthToken(String token) {
|
||||
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = getConnection();
|
||||
|
||||
PreparedStatement p = connection.prepareStatement("SELECT username FROM mar_user WHERE authToken=?");
|
||||
p.setString(1, token);
|
||||
|
||||
ResultSet rs = p.executeQuery();
|
||||
|
||||
if (rs.next()) {
|
||||
|
||||
return rs.getString("username");
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
LogManager.LOGGER.severe("MySQL Error " + e.getErrorCode() + ": " + e.getMessage());
|
||||
|
||||
} finally {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] getFloppy(String username) {
|
||||
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = getConnection();
|
||||
|
||||
PreparedStatement p = connection.prepareStatement("SELECT floppyData FROM mar_user WHERE username=?");
|
||||
p.setString(1, username);
|
||||
|
||||
ResultSet rs = p.executeQuery();
|
||||
|
||||
if (rs.next()) {
|
||||
Blob blob = rs.getBlob("floppyData");
|
||||
|
||||
if (blob != null) {
|
||||
return blob.getBytes(1, (int) blob.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
LogManager.LOGGER.severe("MySQL Error " + e.getErrorCode() + ": " + e.getMessage());
|
||||
|
||||
} finally {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package net.simon987.server.webserver;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.game.World;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class TerrainRequestHandler implements MessageHandler {
|
||||
|
||||
@Override
|
||||
public void handle(OnlineUser user, JSONObject json) {
|
||||
if (json.get("t").equals("terrain") && json.containsKey("x") && json.containsKey("y")) {
|
||||
|
||||
// LogManager.LOGGER.fine("Terrain request from " + user.getUser().getUsername());
|
||||
World world;
|
||||
try {
|
||||
world = GameServer.INSTANCE.getGameUniverse().getWorld(
|
||||
Long.valueOf((long) json.get("x")).intValue(),
|
||||
Long.valueOf((long) json.get("y")).intValue(), false);
|
||||
} catch (NullPointerException e) {
|
||||
LogManager.LOGGER.severe("FIXME: handle TerrainRequestHandler");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//todo It might be a good idea to cache this
|
||||
if (world != null) {
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
JSONArray terrain = new JSONArray();
|
||||
|
||||
int[][] tiles = world.getTileMap().getTiles();
|
||||
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
||||
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
||||
terrain.add(tiles[y][x]);
|
||||
}
|
||||
}
|
||||
|
||||
response.put("t", "terrain");
|
||||
response.put("ok", true);
|
||||
response.put("terrain", terrain);
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
} else {
|
||||
//Uncharted World
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("t", "terrain");
|
||||
response.put("ok", false);
|
||||
|
||||
user.getWebSocket().send(response.toJSONString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
# MySQL username
|
||||
mysql_user=mar
|
||||
# MySQL password/
|
||||
mysql_pass=mar
|
||||
# MySQL address
|
||||
mysql_url=jdbc:mysql://localhost:3306/mar?useSSL=false
|
||||
# File management
|
||||
save_interval=5
|
||||
log_limit=2000000
|
||||
log_count=10
|
||||
# Web server port
|
||||
webSocket_port=8887
|
||||
webSocket_host=0.0.0.0
|
||||
|
||||
use_secure_webSocket=0
|
||||
cert_path=certificates
|
||||
# ----------------------------------------------
|
||||
|
||||
# Length of a tick in ms
|
||||
tick_length=1000
|
||||
# Default offset of the origin (starting point of code execution) in words
|
||||
org_offset=512
|
||||
# Address of the stack bottom
|
||||
stack_bottom=65536
|
||||
# Size of the memory in words
|
||||
memory_size=65536
|
||||
# Initial location of new user's controlled unit
|
||||
new_user_worldX = 32767
|
||||
new_user_worldY = 32767
|
||||
# Default user code
|
||||
new_user_code=; Welcome to Much Assembly required!\n\
|
||||
; You will find useful information on the game here: https://github.com/simon987/Much-Assembly-Required/wiki\n\
|
||||
.text\n\
|
||||
\t; Write code here\n\
|
||||
\tbrk
|
||||
# Default held item
|
||||
new_user_item=0
|
||||
# ----------------------------------------------
|
||||
# Biomass units for each blob
|
||||
biomass_yield=2
|
||||
# Minimum biomass blob count for the WorldGenerator
|
||||
minBiomassCount=3
|
||||
minBiomassRespawnCount=2
|
||||
# Maximum biomass blob count for the WorldGenerator
|
||||
maxBiomassCount=10
|
||||
maxBiomassRespawnCount=6
|
||||
# Energy generated by consuming biomass
|
||||
biomassEnergyValue=4000
|
||||
# Maximum energy of the battery hardware in kJ
|
||||
battery_max_energy=60000
|
||||
# Time for biomass respawn in ticks
|
||||
biomassRespawnTime=64
|
||||
# Respawn timer will start when biomass count is below this number
|
||||
biomassRespawnThreshold=1
|
||||
# NPC lifetime in ticks
|
||||
npc_lifetime=1024
|
||||
# Maximum travel distance from the Factory in Worlds
|
||||
npc_max_factory_distance=3
|
||||
# Maximum NPC per Factory
|
||||
factory_max_npc_count=16
|
||||
# Harvester max hp
|
||||
harvester_hp_max=100
|
||||
# Harvester hp regeneration per tick
|
||||
harvester_regen=5
|
||||
# Number of biomass units dropped on death
|
||||
harvester_biomass_drop_count=8
|
||||
# ----------------------------------------------
|
||||
# Minimum center point count for the WorldGenerator
|
||||
wg_centerPointCountMin=5
|
||||
# Maximum center point count for the WorldGenerator
|
||||
wg_centerPointCountMax=15
|
||||
# Wall/Plain tile ratio for the WorldGenerator
|
||||
wg_wallPlainRatio=4
|
||||
# Minimum iron tile count for the WorldGenerator
|
||||
wg_minIronCount=0
|
||||
# Maximum iron tile count for the WorldGenerator
|
||||
wg_maxIronCount=2
|
||||
# Minimum copper tile count for the WorldGenerator
|
||||
wg_minCopperCount=0
|
||||
# Maximum copper tile count for the WorldGenerator
|
||||
wg_maxCopperCount=2
|
||||
|
||||
|
||||
# ----------------------------------------------
|
||||
# Maximum execution time of user code in ms
|
||||
user_timeout=100
|
||||
@@ -1,39 +0,0 @@
|
||||
package net.simon987.server.assembly;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.exception.CancelledException;
|
||||
import net.simon987.server.user.User;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class CPUTest {
|
||||
|
||||
@Test
|
||||
public void executeInstruction() throws CancelledException {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
User user = new User();
|
||||
CPU cpu = new CPU(config, user);
|
||||
|
||||
|
||||
for(int i = 0 ; i < 3 ; i++){
|
||||
//Execute every possible instruction with random values in memory
|
||||
cpu.reset();
|
||||
cpu.getMemory().clear();
|
||||
Random random = new Random();
|
||||
byte[] randomBytes = new byte[cpu.getMemory().getWords().length * 2];
|
||||
random.nextBytes(randomBytes);
|
||||
|
||||
for (int machineCode = Character.MIN_VALUE; machineCode < Character.MAX_VALUE; machineCode++) {
|
||||
Instruction instruction = cpu.getInstructionSet().get(machineCode & 0x03F); // 0000 0000 00XX XXXX
|
||||
|
||||
int source = (machineCode >> 11) & 0x001F; // XXXX X000 0000 0000
|
||||
int destination = (machineCode >> 6) & 0x001F; // 0000 0XXX XX00 0000
|
||||
|
||||
cpu.executeInstruction(instruction, source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package net.simon987.server.assembly.instruction;
|
||||
|
||||
import net.simon987.server.ServerConfiguration;
|
||||
import net.simon987.server.assembly.*;
|
||||
import net.simon987.server.user.User;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CallInstructionTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void execute() throws Exception {
|
||||
|
||||
ServerConfiguration config = new ServerConfiguration("config.properties");
|
||||
int memorySize = config.getInt("memory_size");
|
||||
|
||||
//Memory
|
||||
Memory memory = new Memory(memorySize);
|
||||
memory.clear();
|
||||
|
||||
//RegisterSet
|
||||
RegisterSet registerSet = new RegisterSet();
|
||||
registerSet.put(1, new Register("T1"));
|
||||
registerSet.put(2, new Register("T2"));
|
||||
registerSet.clear();
|
||||
|
||||
//Status
|
||||
Status status = new Status();
|
||||
status.clear();
|
||||
|
||||
CPU cpu = new CPU(config, new User());
|
||||
|
||||
CallInstruction callInstruction = new CallInstruction(cpu);
|
||||
|
||||
//We have to check if IP is 'pushed' correctly (try to pop it), the
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void execute1() throws Exception {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,19 +3,25 @@ services:
|
||||
server:
|
||||
build:
|
||||
context: .
|
||||
command: sh -c "sed -i -e 's#localhost#db#' config.properties && /usr/bin/java -jar /app/target/server-1.2a.jar"
|
||||
command: sh -c "/usr/bin/java -jar /app/target/server-1.4a.jar"
|
||||
depends_on:
|
||||
db:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "8887:8887"
|
||||
db:
|
||||
image: mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-umar", "-pmar"]
|
||||
environment:
|
||||
MYSQL_DATABASE: mar
|
||||
MYSQL_PASSWORD: mar
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
|
||||
MYSQL_ROOT_PASSWORD: something-secret
|
||||
MYSQL_USER: mar
|
||||
- 4567:4567
|
||||
mongodb:
|
||||
image: mongo:latest
|
||||
container_name: "mongodb"
|
||||
environment:
|
||||
- MONGO_DATA_DIR=/data/db
|
||||
- MONGO_LOG_DIR=/dev/null
|
||||
volumes:
|
||||
- ./data/db:/data/db
|
||||
ports:
|
||||
- 27017:27017
|
||||
command: mongod --smallfiles --logpath=/dev/null --port 27017
|
||||
healthcheck:
|
||||
test: echo 'db.stats().ok' | mongo localhost:27017/mar --quiet
|
||||
interval: 2s
|
||||
timeout: 2s
|
||||
retries: 2
|
||||
155
pom.xml
155
pom.xml
@@ -4,14 +4,30 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.simon987.server</groupId>
|
||||
<artifactId>server_root</artifactId>
|
||||
<version>1.2a</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<groupId>net.simon987.mar</groupId>
|
||||
<artifactId>muchassemblyrequired</artifactId>
|
||||
<version>1.6a</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<executable>tsc</executable>
|
||||
<workingDirectory>./src/main/typescript/</workingDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<version>3.6.2</version>
|
||||
@@ -22,33 +38,118 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<configuration>
|
||||
<outputDirectory>../target/plugins</outputDirectory>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>false</addClasspath>
|
||||
<mainClass>net.simon987.server.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-resources</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>./target/</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>./src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</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.mar.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>
|
||||
<forkMode>never</forkMode>
|
||||
<workingDirectory>./src/main/resources</workingDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<modules>
|
||||
<module>Server</module>
|
||||
<module>Plugin Plant</module>
|
||||
<module>Plugin NPC</module>
|
||||
<module>Plugin Misc HW</module>
|
||||
<module>Plugin Cubot</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</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.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-sync</artifactId>
|
||||
<version>3.9.1</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>5.1.11.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
<version>2.8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-template-velocity</artifactId>
|
||||
<version>2.7.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.7.25</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>
|
||||
94
src/main/java/net/simon987/mar/biomass/BiomassBlob.java
Normal file
94
src/main/java/net/simon987/mar/biomass/BiomassBlob.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package net.simon987.mar.biomass;
|
||||
|
||||
import net.simon987.mar.server.game.item.Item;
|
||||
import net.simon987.mar.server.game.objects.GameObject;
|
||||
import net.simon987.mar.server.game.objects.InventoryHolder;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class BiomassBlob extends GameObject implements InventoryHolder {
|
||||
|
||||
private static final char MAP_INFO = 0x0101;
|
||||
|
||||
/**
|
||||
* Yield of the blob, in biomass units
|
||||
*/
|
||||
private int biomassCount;
|
||||
|
||||
public BiomassBlob() {
|
||||
}
|
||||
|
||||
public BiomassBlob(Document document) {
|
||||
super(document);
|
||||
|
||||
biomassCount = document.getInteger("biomassCount");
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getMapInfo() {
|
||||
return MAP_INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject jsonSerialise() {
|
||||
|
||||
JSONObject json = super.jsonSerialise();
|
||||
|
||||
json.put("b", biomassCount);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
|
||||
Document dbObject = super.mongoSerialise();
|
||||
|
||||
dbObject.put("biomassCount", biomassCount);
|
||||
|
||||
return dbObject;
|
||||
|
||||
}
|
||||
|
||||
public int getBiomassCount() {
|
||||
return biomassCount;
|
||||
}
|
||||
|
||||
public void setBiomassCount(int biomassCount) {
|
||||
this.biomassCount = biomassCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an object attempts to place an item in this BiomassBlob
|
||||
*
|
||||
* @return Always returns false
|
||||
*/
|
||||
@Override
|
||||
public boolean placeItem(Item item) {
|
||||
//Why would you want to place an item in a blob?
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeItem(int itemId) {
|
||||
return itemId == ItemBiomass.ID && 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
|
||||
*/
|
||||
@Override
|
||||
public void takeItem(int itemId) {
|
||||
|
||||
if (itemId == ItemBiomass.ID) {
|
||||
if (biomassCount > 1) {
|
||||
biomassCount--;
|
||||
} else {
|
||||
//Delete plant
|
||||
setDead(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/main/java/net/simon987/mar/biomass/ItemBiomass.java
Normal file
36
src/main/java/net/simon987/mar/biomass/ItemBiomass.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package net.simon987.mar.biomass;
|
||||
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.game.item.Item;
|
||||
import net.simon987.mar.server.game.objects.ControllableUnit;
|
||||
import org.bson.Document;
|
||||
|
||||
public class ItemBiomass extends Item {
|
||||
|
||||
public static final int ID = 0x0001;
|
||||
|
||||
private static final int energy = GameServer.INSTANCE.getConfig().getInt("biomassEnergyValue");
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
public ItemBiomass() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public ItemBiomass(Document document) {
|
||||
super(document);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(ControllableUnit unit) {
|
||||
unit.storeEnergy(energy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char poll() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package net.simon987.biomassplugin;
|
||||
package net.simon987.mar.biomass;
|
||||
|
||||
import net.simon987.server.GameServer;
|
||||
import net.simon987.server.game.World;
|
||||
import net.simon987.server.logging.LogManager;
|
||||
import net.simon987.mar.server.game.world.TileMap;
|
||||
import net.simon987.mar.server.game.world.TilePlain;
|
||||
import net.simon987.mar.server.game.world.World;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
@@ -21,12 +22,12 @@ public class WorldUtils {
|
||||
|
||||
//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();
|
||||
TileMap m = world.getTileMap();
|
||||
int plainCount = 0;
|
||||
for (int y = 0; y < World.WORLD_SIZE; y++) {
|
||||
for (int x = 0; x < World.WORLD_SIZE; x++) {
|
||||
for (int y = 0; y < world.getWorldSize(); y++) {
|
||||
for (int x = 0; x < world.getWorldSize(); x++) {
|
||||
|
||||
if (tiles[x][y] == 0) {
|
||||
if (m.getTileIdAt(x, y) == TilePlain.ID) {
|
||||
plainCount++;
|
||||
}
|
||||
}
|
||||
@@ -39,14 +40,14 @@ public class WorldUtils {
|
||||
outerLoop:
|
||||
for (int i = 0; i < blobCount; i++) {
|
||||
|
||||
Point p = world.getTileMap().getRandomPlainTile();
|
||||
Point p = m.getRandomTile(TilePlain.ID);
|
||||
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 ||
|
||||
while (p.x == 0 || p.y == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 ||
|
||||
world.getGameObjectsAt(p.x, p.y).size() != 0) {
|
||||
p = world.getTileMap().getRandomPlainTile();
|
||||
p = m.getRandomTile(TilePlain.ID);
|
||||
counter++;
|
||||
|
||||
if (counter > 25) {
|
||||
@@ -62,8 +63,7 @@ public class WorldUtils {
|
||||
}
|
||||
|
||||
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.setObjectId(new ObjectId());
|
||||
biomassBlob.setBiomassCount(yield);
|
||||
biomassBlob.setX(p.x);
|
||||
biomassBlob.setY(p.y);
|
||||
@@ -73,9 +73,6 @@ public class WorldUtils {
|
||||
}
|
||||
}
|
||||
|
||||
LogManager.LOGGER.info("Generated " + biomassBlobs.size() + " biomassBlobs for World (" + world.getX() + ',' +
|
||||
world.getY() + ')');
|
||||
|
||||
return biomassBlobs;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,23 @@
|
||||
package net.simon987.biomassplugin.event;
|
||||
package net.simon987.mar.biomass.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;
|
||||
import net.simon987.mar.biomass.BiomassBlob;
|
||||
import net.simon987.mar.server.IServerConfiguration;
|
||||
import net.simon987.mar.server.event.GameEvent;
|
||||
import net.simon987.mar.server.event.GameEventListener;
|
||||
import net.simon987.mar.server.event.ObjectDeathEvent;
|
||||
import net.simon987.mar.server.game.objects.GameObject;
|
||||
import net.simon987.mar.server.game.world.World;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
/**
|
||||
* Handles ObjectDeathEvent events
|
||||
*/
|
||||
public class ObjectDeathListener implements GameEventListener {
|
||||
|
||||
private int biomassDropCount;
|
||||
private final int biomassDropCount;
|
||||
|
||||
public ObjectDeathListener(ServerConfiguration config) {
|
||||
public ObjectDeathListener(IServerConfiguration config) {
|
||||
biomassDropCount = config.getInt("harvester_biomass_drop_count");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -29,22 +27,19 @@ public class ObjectDeathListener implements GameEventListener {
|
||||
|
||||
@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();
|
||||
|
||||
if (event.getSource().getClass().getCanonicalName().equals("net.simon987.mar.npc.HarvesterNPC")) {
|
||||
//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) {
|
||||
if (dyingHarvesterNPC.getX() != 0 && dyingHarvesterNPC.getX() != dyingHarvesterNPC.getWorld().getWorldSize() - 1 &&
|
||||
dyingHarvesterNPC.getY() != 0 && dyingHarvesterNPC.getY() != dyingHarvesterNPC.getWorld().getWorldSize() - 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() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,8 +54,7 @@ public class ObjectDeathListener implements GameEventListener {
|
||||
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.setObjectId(new ObjectId());
|
||||
biomassBlob.setBiomassCount(biomassDropCount);
|
||||
biomassBlob.setX(x);
|
||||
biomassBlob.setY(y);
|
||||
@@ -1,11 +1,11 @@
|
||||
package net.simon987.biomassplugin.event;
|
||||
package net.simon987.mar.biomass.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 net.simon987.mar.biomass.BiomassBlob;
|
||||
import net.simon987.mar.biomass.WorldUtils;
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.event.GameEvent;
|
||||
import net.simon987.mar.server.event.GameEventListener;
|
||||
import net.simon987.mar.server.event.WorldGenerationEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package net.simon987.mar.biomass.event;
|
||||
|
||||
import net.simon987.mar.biomass.BiomassBlob;
|
||||
import net.simon987.mar.biomass.WorldUtils;
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.IServerConfiguration;
|
||||
import net.simon987.mar.server.event.GameEvent;
|
||||
import net.simon987.mar.server.event.GameEventListener;
|
||||
import net.simon987.mar.server.event.WorldUpdateEvent;
|
||||
import net.simon987.mar.server.game.world.World;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
public class WorldUpdateListener implements GameEventListener {
|
||||
|
||||
private final 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(IServerConfiguration 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 (world.getDimension().startsWith("w")) {
|
||||
//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.getUniverse().getTime() + waitTime);
|
||||
} else {
|
||||
|
||||
long waitUntil = worldWaitMap.get(world);
|
||||
|
||||
if (GameServer.INSTANCE.getUniverse().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);
|
||||
world.incUpdatable();
|
||||
}
|
||||
|
||||
//Set the 'waitUntil' time to 0 to indicate that we are not waiting
|
||||
worldWaitMap.replace(world, 0L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
111
src/main/java/net/simon987/mar/construction/BluePrint.java
Normal file
111
src/main/java/net/simon987/mar/construction/BluePrint.java
Normal file
@@ -0,0 +1,111 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import net.simon987.mar.server.game.item.Item;
|
||||
import net.simon987.mar.server.game.objects.GameObject;
|
||||
import net.simon987.mar.server.game.objects.InventoryHolder;
|
||||
import net.simon987.mar.server.io.JSONSerializable;
|
||||
import net.simon987.mar.server.io.MongoSerializable;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class BluePrint implements InventoryHolder, JSONSerializable, MongoSerializable {
|
||||
|
||||
/**
|
||||
* Map of items id and required amount
|
||||
* <br>The amount is decremented as the items are added
|
||||
*/
|
||||
protected Map<Integer, Integer> requiredItems;
|
||||
|
||||
/**
|
||||
* This object will be instantiated when completed
|
||||
*/
|
||||
protected Class<? extends GameObject> targetObject;
|
||||
|
||||
/**
|
||||
* Set to true when all the requirements are met
|
||||
*/
|
||||
private boolean completed;
|
||||
|
||||
public BluePrint() {
|
||||
requiredItems = new HashMap<>();
|
||||
}
|
||||
|
||||
public BluePrint(Document document) {
|
||||
requiredItems = (Map<Integer, Integer>) document.get("required_items");
|
||||
completed = document.getBoolean("completed");
|
||||
try {
|
||||
targetObject = Class.forName(document.getString("target")).asSubclass(GameObject.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCompleted() {
|
||||
|
||||
for (Integer remaining : requiredItems.values()) {
|
||||
if (remaining > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
completed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeItem(Item item) {
|
||||
|
||||
if (requiredItems.containsKey(item.getId()) && requiredItems.get(item.getId()) > 0) {
|
||||
requiredItems.put(item.getId(), requiredItems.get(item.getId()) - 1);
|
||||
checkCompleted();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeItem(int itemId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeItem(int itemId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCompleted() {
|
||||
return completed;
|
||||
}
|
||||
|
||||
public Class<? extends GameObject> getTargetObject() {
|
||||
return targetObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject debugJsonSerialise() {
|
||||
return jsonSerialise();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject jsonSerialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
json.put("target", targetObject);
|
||||
json.put("required_items", requiredItems);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
Document document = new Document();
|
||||
|
||||
document.put("completed", completed);
|
||||
document.put("target", targetObject);
|
||||
document.put("required_items", requiredItems);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import net.simon987.mar.server.logging.LogManager;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BluePrintRegistry {
|
||||
|
||||
public static final BluePrintRegistry INSTANCE = new BluePrintRegistry();
|
||||
|
||||
private final Map<String, Class<? extends BluePrint>> blueprints;
|
||||
private final Map<String, String> digitizedBlueprints;
|
||||
|
||||
private BluePrintRegistry() {
|
||||
blueprints = new HashMap<>();
|
||||
digitizedBlueprints = new HashMap<>();
|
||||
}
|
||||
|
||||
public void registerBluePrint(Class<? extends BluePrint> clazz) {
|
||||
blueprints.put(clazz.getCanonicalName(), clazz);
|
||||
String bpData = new String(BluePrintUtil.bluePrintData(clazz));
|
||||
digitizedBlueprints.put(bpData, clazz.getCanonicalName());
|
||||
}
|
||||
|
||||
public BluePrint deserializeBlueprint(Document document) {
|
||||
|
||||
String type = document.getString("type");
|
||||
|
||||
if (blueprints.containsKey(type)) {
|
||||
|
||||
try {
|
||||
return blueprints.get(type).getConstructor(Document.class).newInstance(document);
|
||||
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (InvocationTargetException e) {
|
||||
LogManager.LOGGER.severe("(Construction Plugin) Error while trying to deserialize object of type " + type + ": " + e.getTargetException().getMessage());
|
||||
LogManager.LOGGER.severe(document.toJson());
|
||||
e.getTargetException().printStackTrace();
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
LogManager.LOGGER.severe("(Construction Plugin) Trying to deserialize unknown BluePrint type: " + type);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public BluePrint deserializeBluePrint(char[] chars) {
|
||||
|
||||
String bpData = new String(chars);
|
||||
|
||||
if (digitizedBlueprints.containsKey(bpData)) {
|
||||
return deserializeBlueprint(new Document("type", digitizedBlueprints.get(bpData)));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
class BluePrintUtil {
|
||||
|
||||
private static byte[] secretKey;
|
||||
private static final String SHA512 = "SHA-512";
|
||||
|
||||
//We need 1024 chars = 2048 bytes = 32 values
|
||||
private static final char[] ARBITRARY_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456".toCharArray();
|
||||
|
||||
static void setSecretKey(String secretKey) {
|
||||
BluePrintUtil.secretKey = secretKey.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a message using SHA512 with the server secret key as the sal
|
||||
*
|
||||
* @return 128-bit char array
|
||||
*/
|
||||
private static char[] hashMessage(String message) {
|
||||
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance(SHA512);
|
||||
md.update(secretKey);
|
||||
md.update(message.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
byte[] digest = md.digest();
|
||||
char[] chars = new char[digest.length / 2];
|
||||
ByteBuffer.wrap(digest).order(ByteOrder.BIG_ENDIAN).asCharBuffer().get(chars);
|
||||
|
||||
return chars;
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a char array representation of a blueprint. It is obtained by hashing the blueprint
|
||||
* properties with the server secret key. Some arbitrary values are added to make a 1024-char
|
||||
* array. The same blueprint and secret key always gives the same result.
|
||||
*/
|
||||
static char[] bluePrintData(Class<? extends BluePrint> blueprint) {
|
||||
|
||||
char[] result = new char[ARBITRARY_STRING.length * 32];
|
||||
|
||||
for (int i = ARBITRARY_STRING.length - 1; i > 0; --i) {
|
||||
char[] hashedBlueprint = hashMessage(ARBITRARY_STRING[i] + blueprint.getName());
|
||||
if (hashedBlueprint != null) {
|
||||
System.arraycopy(hashedBlueprint, 0, result,
|
||||
i * hashedBlueprint.length, hashedBlueprint.length);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import net.simon987.mar.server.GameServer;
|
||||
|
||||
public class ConstructionPlugin {
|
||||
|
||||
public void init(GameServer gameServer) {
|
||||
// TODO
|
||||
BluePrintUtil.setSecretKey(gameServer.getSecretKey());
|
||||
BluePrintRegistry.INSTANCE.registerBluePrint(ObstacleBlueprint.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.game.item.Item;
|
||||
import net.simon987.mar.server.game.objects.InventoryHolder;
|
||||
import net.simon987.mar.server.game.objects.Structure;
|
||||
import net.simon987.mar.server.game.objects.Updatable;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class ConstructionSite extends Structure implements Updatable, InventoryHolder {
|
||||
|
||||
public static final int MAP_INFO = 0xFFFF; //TODO: determine
|
||||
public static final int LIFETIME = GameServer.INSTANCE.getConfig().getInt("construction_site_ttl");
|
||||
|
||||
private int age;
|
||||
private final BluePrint bluePrint;
|
||||
|
||||
public ConstructionSite(BluePrint bluePrint) {
|
||||
super(1, 1);
|
||||
|
||||
this.bluePrint = bluePrint;
|
||||
this.age = 0;
|
||||
}
|
||||
|
||||
public ConstructionSite(Document document) {
|
||||
super(document, 1, 1);
|
||||
|
||||
age = document.getInteger("age");
|
||||
bluePrint = BluePrintRegistry.INSTANCE.deserializeBlueprint((Document) document.get("blueprint"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getMapInfo() {
|
||||
return MAP_INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
|
||||
age += 1;
|
||||
|
||||
if (age > LIFETIME) {
|
||||
setDead(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeItem(Item item) {
|
||||
return bluePrint.placeItem(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void takeItem(int itemId) {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeItem(int itemId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject jsonSerialise() {
|
||||
JSONObject json = super.jsonSerialise();
|
||||
|
||||
json.put("blueprint", bluePrint.jsonSerialise());
|
||||
json.put("age", age);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
Document document = super.mongoSerialise();
|
||||
|
||||
document.put("blueprint", bluePrint.mongoSerialise());
|
||||
document.put("age", age);
|
||||
|
||||
return document;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import net.simon987.mar.server.assembly.Memory;
|
||||
import net.simon987.mar.server.game.item.Item;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class ItemBluePrint extends Item {
|
||||
|
||||
public static final int ID = 0x0005;
|
||||
private Class<? extends BluePrint> bluePrint;
|
||||
|
||||
public ItemBluePrint() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public ItemBluePrint(Document document) {
|
||||
super(document);
|
||||
try {
|
||||
bluePrint = Class.forName(document.getString("blueprint")).asSubclass(BluePrint.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void digitize(Memory memory, int offset) {
|
||||
char[] data = BluePrintUtil.bluePrintData(bluePrint);
|
||||
memory.write(offset, data, 0, data.length);
|
||||
|
||||
System.out.println("DEBUG: blueprint digitize " + data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char poll() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject debugJsonSerialise() {
|
||||
JSONObject json = super.debugJsonSerialise();
|
||||
json.put("blueprint", bluePrint.getCanonicalName());
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
Document document = super.mongoSerialise();
|
||||
|
||||
document.put("blueprint", bluePrint.getCanonicalName());
|
||||
return document;
|
||||
}
|
||||
}
|
||||
104
src/main/java/net/simon987/mar/construction/Obstacle.java
Normal file
104
src/main/java/net/simon987/mar/construction/Obstacle.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.game.objects.Attackable;
|
||||
import net.simon987.mar.server.game.objects.Structure;
|
||||
import net.simon987.mar.server.game.objects.Updatable;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class Obstacle extends Structure implements Attackable, Updatable {
|
||||
|
||||
public static final int MAP_INFO = 0x0601;
|
||||
private static final int HEAL_RATE = GameServer.INSTANCE.getConfig().getInt("obstacle_regen");
|
||||
private static final int MAX_HP = GameServer.INSTANCE.getConfig().getInt("obstacle_hp");
|
||||
|
||||
private int hp;
|
||||
private int color;
|
||||
|
||||
public Obstacle() {
|
||||
super(1, 1);
|
||||
}
|
||||
|
||||
public Obstacle(Document document) {
|
||||
super(document, 1, 1);
|
||||
|
||||
hp = document.getInteger(hp);
|
||||
color = document.getInteger(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
heal(HEAL_RATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHealRate(int hp) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHp(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHp() {
|
||||
return MAX_HP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxHp(int hp) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void heal(int amount) {
|
||||
hp = Math.min(getMaxHp(), hp + amount);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void damage(int amount) {
|
||||
hp -= amount;
|
||||
|
||||
if (hp < 0) {
|
||||
setDead(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getMapInfo() {
|
||||
return MAP_INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
Document document = super.mongoSerialise();
|
||||
|
||||
document.put("hp", hp);
|
||||
document.put("color", hp);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject debugJsonSerialise() {
|
||||
return jsonSerialise();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject jsonSerialise() {
|
||||
JSONObject json = super.jsonSerialise();
|
||||
|
||||
json.put("hp", hp);
|
||||
json.put("color", hp);
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.simon987.mar.construction;
|
||||
|
||||
import net.simon987.mar.server.game.item.ItemIron;
|
||||
import org.bson.Document;
|
||||
|
||||
public class ObstacleBlueprint extends BluePrint {
|
||||
|
||||
public ObstacleBlueprint() {
|
||||
super();
|
||||
|
||||
this.requiredItems.put(ItemIron.ID, 2); //TODO: load from config?
|
||||
this.targetObject = Obstacle.class;
|
||||
}
|
||||
|
||||
public ObstacleBlueprint(Document document) {
|
||||
this.requiredItems.put(ItemIron.ID, 2); //TODO: load from config?
|
||||
this.targetObject = Obstacle.class;
|
||||
}
|
||||
}
|
||||
52
src/main/java/net/simon987/mar/cubot/Clock.java
Normal file
52
src/main/java/net/simon987/mar/cubot/Clock.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package net.simon987.mar.cubot;
|
||||
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.assembly.HardwareModule;
|
||||
import net.simon987.mar.server.assembly.Status;
|
||||
import net.simon987.mar.server.assembly.Util;
|
||||
import net.simon987.mar.server.game.objects.ControllableUnit;
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
* Hardware to get game time
|
||||
*/
|
||||
public class Clock extends HardwareModule {
|
||||
|
||||
private static final char HWID = 0x0008;
|
||||
|
||||
public static final char DEFAULT_ADDRESS = 0x0008;
|
||||
|
||||
public Clock() {
|
||||
|
||||
}
|
||||
|
||||
public Clock(Document document, ControllableUnit unit) {
|
||||
super(document, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
int time = (int) GameServer.INSTANCE.getUniverse().getTime();
|
||||
|
||||
//Will need to be changed to quadword in about 136 years
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(Util.getHigherWord(time));
|
||||
getCpu().getRegisterSet().getRegister("C").setValue(Util.getLowerWord(time));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
|
||||
Document dbObject = new Document();
|
||||
dbObject.put("type", getClass().getCanonicalName());
|
||||
|
||||
return dbObject;
|
||||
}
|
||||
}
|
||||
610
src/main/java/net/simon987/mar/cubot/Cubot.java
Normal file
610
src/main/java/net/simon987/mar/cubot/Cubot.java
Normal file
@@ -0,0 +1,610 @@
|
||||
package net.simon987.mar.cubot;
|
||||
|
||||
import net.simon987.mar.cubot.event.CubotWalkEvent;
|
||||
import net.simon987.mar.cubot.event.DeathEvent;
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.IServerConfiguration;
|
||||
import net.simon987.mar.server.assembly.CPU;
|
||||
import net.simon987.mar.server.assembly.HardwareModule;
|
||||
import net.simon987.mar.server.assembly.Memory;
|
||||
import net.simon987.mar.server.assembly.Status;
|
||||
import net.simon987.mar.server.assembly.exception.CancelledException;
|
||||
import net.simon987.mar.server.event.GameEvent;
|
||||
import net.simon987.mar.server.game.item.Item;
|
||||
import net.simon987.mar.server.game.item.ItemVoid;
|
||||
import net.simon987.mar.server.game.objects.*;
|
||||
import net.simon987.mar.server.user.User;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class Cubot extends GameObject implements Updatable, ControllableUnit, MessageReceiver {
|
||||
|
||||
private static final char MAP_INFO = 0x0200;
|
||||
|
||||
/**
|
||||
* Hit points
|
||||
*/
|
||||
private int hp;
|
||||
/**
|
||||
* Maximum hit points
|
||||
*/
|
||||
private int maxHp;
|
||||
|
||||
/**
|
||||
* Shield points
|
||||
*/
|
||||
private int shield;
|
||||
|
||||
/**
|
||||
* Maximum shield points
|
||||
*/
|
||||
private int maxShield;
|
||||
|
||||
/**
|
||||
* Action that was set during the current tick. It is set to IDLE by default
|
||||
*/
|
||||
private Action currentAction = Action.IDLE;
|
||||
|
||||
/**
|
||||
* Action at the end of the last tick
|
||||
*/
|
||||
private Action lastAction = Action.IDLE;
|
||||
|
||||
/**
|
||||
* Status bit field that was set during the current tick. It is set to 0 by default
|
||||
* <br>See CubotStatus and addStatus() method
|
||||
*/
|
||||
private char currentStatus;
|
||||
|
||||
/**
|
||||
* Status bit field at the end of the last tick
|
||||
*/
|
||||
private char lastStatus;
|
||||
|
||||
/**
|
||||
* Buffer of keypress codes. It is not changed between ticks and it is reset when
|
||||
* the player uploads their code
|
||||
*/
|
||||
private ArrayList<Integer> keyboardBuffer = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Buffer of console messages (also called 'internal buffer') that was set during the current tick
|
||||
*/
|
||||
private final ArrayList<char[]> consoleMessagesBuffer = new ArrayList<>(CONSOLE_BUFFER_MAX_SIZE);
|
||||
/**
|
||||
* Buffer of console messages (also called 'internal buffer') at the end of the last tick
|
||||
*/
|
||||
private ArrayList<char[]> lastConsoleMessagesBuffer = new ArrayList<>(CONSOLE_BUFFER_MAX_SIZE);
|
||||
/**
|
||||
* Console mode that was set during the current tick. It is set to NORMAL by default
|
||||
*/
|
||||
private ConsoleMode consoleMode = ConsoleMode.NORMAL;
|
||||
/**
|
||||
* Console mode at the end of the last tick
|
||||
*/
|
||||
private ConsoleMode lastConsoleMode = ConsoleMode.NORMAL;
|
||||
|
||||
/**
|
||||
* User that controls this Cubot
|
||||
*/
|
||||
private User parent;
|
||||
|
||||
/**
|
||||
* Maximum size of the console buffer (also called 'internal buffer')
|
||||
*/
|
||||
public static final int CONSOLE_BUFFER_MAX_SIZE = 40;
|
||||
|
||||
/**
|
||||
* List of attached hardware, 'modules'
|
||||
*/
|
||||
private final Map<Integer, HardwareModule> hardwareAddresses = new HashMap<>();
|
||||
private final Map<Class<? extends HardwareModule>, Integer> hardwareModules = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Cubot's brain box
|
||||
*/
|
||||
private CPU cpu;
|
||||
|
||||
public enum ConsoleMode {
|
||||
/**
|
||||
* Used by the ComPort hardware - clears the console screen (client-side)
|
||||
*/
|
||||
CLEAR,
|
||||
/**
|
||||
* No specific client-side action
|
||||
*/
|
||||
NORMAL
|
||||
}
|
||||
|
||||
public Cubot() {
|
||||
|
||||
}
|
||||
|
||||
public Cubot(Document document) {
|
||||
super(document);
|
||||
|
||||
hp = document.getInteger("hp");
|
||||
shield = document.getInteger("shield");
|
||||
setDirection(Direction.getDirection(document.getInteger("direction")));
|
||||
|
||||
IServerConfiguration config = GameServer.INSTANCE.getConfig();
|
||||
maxHp = config.getInt("cubot_max_hp");
|
||||
maxShield = config.getInt("cubot_max_shield");
|
||||
|
||||
try {
|
||||
cpu = CPU.deserialize((Document) document.get("cpu"), this);
|
||||
|
||||
ArrayList hardwareList = (ArrayList) document.get("hardware");
|
||||
|
||||
for (Object serialisedHw : hardwareList) {
|
||||
HardwareModule hardware = GameServer.INSTANCE.getRegistry().deserializeHardware((Document) serialisedHw, this);
|
||||
hardware.setCpu(cpu);
|
||||
attachHardware(hardware, ((Document) serialisedHw).getInteger("address"));
|
||||
}
|
||||
} catch (CancelledException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getMapInfo() {
|
||||
return MAP_INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
|
||||
if (getCpu().isPaused() || getCpu().isExecuting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentAction == Action.WALKING) {
|
||||
if (spendEnergy(100)) {
|
||||
if (!incrementLocation()) {
|
||||
//Couldn't walk
|
||||
currentAction = Action.IDLE;
|
||||
}else{
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(new CubotWalkEvent(this));
|
||||
}
|
||||
} 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
|
||||
|
||||
//And the console
|
||||
lastConsoleMode = consoleMode;
|
||||
consoleMode = ConsoleMode.NORMAL;
|
||||
|
||||
lastConsoleMessagesBuffer = new ArrayList<>(consoleMessagesBuffer);
|
||||
consoleMessagesBuffer.clear();
|
||||
|
||||
//And the status..
|
||||
lastStatus = currentStatus;
|
||||
currentStatus = 0;
|
||||
|
||||
for (HardwareModule module : hardwareAddresses.values()) {
|
||||
module.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject jsonSerialise() {
|
||||
JSONObject json = super.jsonSerialise();
|
||||
json.put("direction", getDirection().ordinal());
|
||||
CubotInventory inv = (CubotInventory) getHardware(CubotInventory.class);
|
||||
int heldItem = inv.getInventory().getOrDefault(inv.getPosition(), new ItemVoid()).getId();
|
||||
json.put("heldItem", heldItem);
|
||||
json.put("hp", hp);
|
||||
json.put("shield", shield);
|
||||
json.put("action", lastAction.ordinal());
|
||||
|
||||
if (parent != null) {
|
||||
json.put("parent", parent.getUsername()); //Only used client-side for now
|
||||
}
|
||||
|
||||
for (HardwareModule module : hardwareAddresses.values()) {
|
||||
JSONObject hwJson = module.jsonSerialise();
|
||||
if (hwJson != null) {
|
||||
json.put(module.getClass().getName(), hwJson);
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
Document dbObject = super.mongoSerialise();
|
||||
|
||||
dbObject.put("direction", getDirection().ordinal());
|
||||
dbObject.put("hp", hp);
|
||||
dbObject.put("shield", shield);
|
||||
dbObject.put("action", lastAction.ordinal());
|
||||
|
||||
if (parent != null) {
|
||||
dbObject.put("parent", parent.getUsername()); //Only used client-side for now
|
||||
}
|
||||
|
||||
List<Document> hardwareList = new ArrayList<>();
|
||||
|
||||
for (Integer address : hardwareAddresses.keySet()) {
|
||||
|
||||
HardwareModule hardware = hardwareAddresses.get(address);
|
||||
|
||||
Document serialisedHw = hardware.mongoSerialise();
|
||||
serialisedHw.put("address", address);
|
||||
hardwareList.add(serialisedHw);
|
||||
}
|
||||
|
||||
dbObject.put("hardware", hardwareList);
|
||||
|
||||
dbObject.put("cpu", cpu.mongoSerialise());
|
||||
return dbObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to 'factory settings', as it were when it was first created
|
||||
*/
|
||||
private void reset() {
|
||||
setDead(false);
|
||||
setHp(maxHp);
|
||||
setShield(0);
|
||||
setEnergy(((CubotBattery) getHardware(CubotBattery.class)).getMaxEnergy());
|
||||
clearKeyboardBuffer();
|
||||
consoleMessagesBuffer.clear();
|
||||
lastConsoleMessagesBuffer.clear();
|
||||
currentStatus = 0;
|
||||
lastStatus = 0;
|
||||
addStatus(CubotStatus.FACTORY_NEW);
|
||||
|
||||
for (HardwareModule module : hardwareAddresses.values()) {
|
||||
module.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDeadCallback() {
|
||||
GameEvent event = new DeathEvent(this);
|
||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event);
|
||||
|
||||
reset();
|
||||
|
||||
//Teleport to spawn point
|
||||
this.getWorld().removeObject(this);
|
||||
this.getWorld().decUpdatable();
|
||||
|
||||
IServerConfiguration config = GameServer.INSTANCE.getConfig();
|
||||
Random random = new Random();
|
||||
|
||||
int spawnX = config.getInt("new_user_worldX") + random.nextInt(5);
|
||||
int spawnY = config.getInt("new_user_worldY") + random.nextInt(5);
|
||||
String dimension = config.getString("new_user_dimension");
|
||||
this.setWorld(GameServer.INSTANCE.getUniverse().getWorld(spawnX, spawnY, true, dimension));
|
||||
|
||||
Point point = this.getWorld().getRandomPassableTile();
|
||||
this.setX(point.x);
|
||||
this.setY(point.y);
|
||||
|
||||
this.getWorld().addObject(this);
|
||||
this.getWorld().incUpdatable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@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 void setParent(User parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Action getAction() {
|
||||
return lastAction;
|
||||
}
|
||||
|
||||
public Action getCurrentAction() {
|
||||
return currentAction;
|
||||
}
|
||||
|
||||
public int getEnergy() {
|
||||
CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class);
|
||||
return battery.getEnergy();
|
||||
}
|
||||
|
||||
public void setEnergy(int energy) {
|
||||
CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class);
|
||||
battery.setEnergy(energy);
|
||||
}
|
||||
|
||||
public boolean spendEnergy(int amount) {
|
||||
|
||||
CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class);
|
||||
|
||||
if (battery.getEnergy() - amount < 0) {
|
||||
return false;
|
||||
} else {
|
||||
battery.setEnergy(battery.getEnergy() - amount);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void storeEnergy(int amount) {
|
||||
|
||||
CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class);
|
||||
battery.setEnergy(Math.min(battery.getEnergy() + amount, battery.getMaxEnergy()));
|
||||
}
|
||||
|
||||
public void setMaxEnergy(int maxEnergy) {
|
||||
CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class);
|
||||
battery.setMaxEnergy(maxEnergy);
|
||||
}
|
||||
|
||||
public int getMaxEnergy() {
|
||||
CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class);
|
||||
return battery.getMaxEnergy();
|
||||
}
|
||||
|
||||
public int getShield() {
|
||||
return shield;
|
||||
}
|
||||
|
||||
public void setShield(int shield) {
|
||||
this.shield = shield;
|
||||
}
|
||||
|
||||
public boolean chargeShield(int amount) {
|
||||
amount = Math.min(amount, maxShield - shield);
|
||||
|
||||
int energySpent = amount * CubotShield.COST;
|
||||
if(spendEnergy(energySpent)) {
|
||||
shield += amount;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Damages shield by amount.
|
||||
*
|
||||
* Return damage that broke through the shield.
|
||||
*/
|
||||
public int damageShield(int amount) {
|
||||
int after = shield - amount;
|
||||
if(after < 0) {
|
||||
shield = 0;
|
||||
return -after;
|
||||
}
|
||||
shield = after;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Memory getFloppyData() {
|
||||
|
||||
CubotFloppyDrive drive = (CubotFloppyDrive) getHardware(CubotFloppyDrive.class);
|
||||
|
||||
if (drive.getFloppy() != null) {
|
||||
return drive.getFloppy().getMemory();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAt(int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@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 addStatus(CubotStatus status) {
|
||||
|
||||
currentStatus |= status.val;
|
||||
}
|
||||
|
||||
public void removeStatus(CubotStatus status) {
|
||||
|
||||
currentStatus &= (~status.val);
|
||||
}
|
||||
|
||||
public char getStatus() {
|
||||
return lastStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently has no effect
|
||||
*/
|
||||
@Override
|
||||
public void setHealRate(int hp) {
|
||||
//no op
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
public int getMaxShield() {
|
||||
return maxShield;
|
||||
}
|
||||
|
||||
public void setMaxShield(int maxShield) {
|
||||
this.maxShield = maxShield;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void heal(int amount) {
|
||||
hp += amount;
|
||||
|
||||
//Can't heal above max
|
||||
if (hp > maxHp) {
|
||||
hp = maxHp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int amount) {
|
||||
|
||||
//Damage shield first
|
||||
int hullDamage = damageShield(amount);
|
||||
|
||||
hp -= hullDamage;
|
||||
|
||||
if (hp <= 0) {
|
||||
setDead(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachHardware(HardwareModule hardware, int address) {
|
||||
hardwareAddresses.put(address, hardware);
|
||||
hardwareModules.put(hardware.getClass(), address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachHardware(int address) {
|
||||
hardwareAddresses.remove(address);
|
||||
|
||||
Class<? extends HardwareModule> toRemove = null;
|
||||
for (Class<? extends HardwareModule> clazz : hardwareModules.keySet()) {
|
||||
if (hardwareModules.get(clazz) == address) {
|
||||
toRemove = clazz;
|
||||
}
|
||||
}
|
||||
hardwareModules.remove(toRemove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hardwareInterrupt(int address, Status status) {
|
||||
HardwareModule hardware = hardwareAddresses.get(address);
|
||||
|
||||
if (hardware != null) {
|
||||
hardware.handleInterrupt(status);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hardwareQuery(int address) {
|
||||
HardwareModule hardware = hardwareAddresses.get(address);
|
||||
|
||||
if (hardware != null) {
|
||||
return hardware.getId();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public HardwareModule getHardware(Class<? extends HardwareModule> clazz) {
|
||||
return hardwareAddresses.get(hardwareModules.get(clazz));
|
||||
}
|
||||
|
||||
public HardwareModule getHardware(int address) {
|
||||
return hardwareAddresses.get(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU getCpu() {
|
||||
return cpu;
|
||||
}
|
||||
|
||||
public void setCpu(CPU cpu) {
|
||||
this.cpu = cpu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void giveItem(Item item) {
|
||||
//Overwrite item at current position
|
||||
((CubotInventory) getHardware(CubotInventory.class)).putItem(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder str = new StringBuilder(super.toString());
|
||||
|
||||
str.append("\nHardware: \n");
|
||||
for (Integer i : hardwareAddresses.keySet()) {
|
||||
str.append(String.format("%04X", i)).append(":").append(hardwareAddresses.get(i)).append("\n");
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
120
src/main/java/net/simon987/mar/cubot/CubotBattery.java
Normal file
120
src/main/java/net/simon987/mar/cubot/CubotBattery.java
Normal file
@@ -0,0 +1,120 @@
|
||||
package net.simon987.mar.cubot;
|
||||
|
||||
import net.simon987.mar.server.GameServer;
|
||||
import net.simon987.mar.server.assembly.HardwareModule;
|
||||
import net.simon987.mar.server.assembly.Status;
|
||||
import net.simon987.mar.server.game.objects.ControllableUnit;
|
||||
import org.bson.Document;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
public class CubotBattery extends HardwareModule {
|
||||
|
||||
public static final int DEFAULT_ADDRESS = 0x000A;
|
||||
|
||||
/**
|
||||
* Hardware ID (Should be unique)
|
||||
*/
|
||||
public static final char HWID = 0x000A;
|
||||
/**
|
||||
* Solar panel multiplier
|
||||
* <br>TODO: Set this constant in dimension
|
||||
*/
|
||||
private static final float SOLAR_PANEL_MULTIPLIER = 1;
|
||||
|
||||
/**
|
||||
* Energy units in kJ
|
||||
*/
|
||||
private int energy;
|
||||
|
||||
/**
|
||||
* Maximum energy units in kJ
|
||||
*/
|
||||
private int maxEnergy;
|
||||
|
||||
|
||||
private static final int BATTERY_POLL = 1;
|
||||
private static final int BATTERY_GET_MAX_CAPACITY = 2;
|
||||
|
||||
public CubotBattery(ControllableUnit unit) {
|
||||
super(null, unit);
|
||||
|
||||
energy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy");
|
||||
maxEnergy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy");
|
||||
}
|
||||
|
||||
public CubotBattery(Document document, ControllableUnit cubot) {
|
||||
super(document, cubot);
|
||||
|
||||
energy = document.getInteger("energy");
|
||||
maxEnergy = document.getInteger("max_energy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInterrupt(Status status) {
|
||||
|
||||
int a = getCpu().getRegisterSet().getRegister("A").getValue();
|
||||
|
||||
if (a == BATTERY_POLL) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(energy);
|
||||
|
||||
} else if (a == BATTERY_GET_MAX_CAPACITY) {
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(maxEnergy);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getId() {
|
||||
return HWID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject jsonSerialise() {
|
||||
JSONObject json = new JSONObject();
|
||||
|
||||
json.put("energy", energy);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject debugJsonSerialise() {
|
||||
JSONObject json = jsonSerialise();
|
||||
|
||||
json.put("max_energy", maxEnergy);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document mongoSerialise() {
|
||||
Document document = super.mongoSerialise();
|
||||
|
||||
document.put("energy", energy);
|
||||
document.put("max_energy", maxEnergy);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
public int getEnergy() {
|
||||
return energy;
|
||||
}
|
||||
|
||||
public void setEnergy(int energy) {
|
||||
this.energy = energy;
|
||||
}
|
||||
|
||||
public int getMaxEnergy() {
|
||||
return maxEnergy;
|
||||
}
|
||||
|
||||
public void setMaxEnergy(int maxEnergy) {
|
||||
this.maxEnergy = maxEnergy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
energy = Math.min(maxEnergy,
|
||||
energy + (int) (SOLAR_PANEL_MULTIPLIER * GameServer.INSTANCE.getDayNightCycle().getSunIntensity()));
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,32 @@
|
||||
package net.simon987.cubotplugin;
|
||||
package net.simon987.mar.cubot;
|
||||
|
||||
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 net.simon987.mar.server.assembly.HardwareModule;
|
||||
import net.simon987.mar.server.assembly.Status;
|
||||
import net.simon987.mar.server.game.objects.ControllableUnit;
|
||||
import net.simon987.mar.server.game.objects.GameObject;
|
||||
import net.simon987.mar.server.game.objects.MessageReceiver;
|
||||
import org.bson.Document;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CubotComPort extends CpuHardware {
|
||||
public class CubotComPort extends HardwareModule {
|
||||
|
||||
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;
|
||||
public CubotComPort(ControllableUnit unit) {
|
||||
super(null, unit);
|
||||
}
|
||||
|
||||
public CubotComPort(Document document, ControllableUnit cubot) {
|
||||
super(document, cubot);
|
||||
}
|
||||
|
||||
private static final int MESSAGE_LENGTH = 8;
|
||||
@@ -37,21 +38,23 @@ public class CubotComPort extends CpuHardware {
|
||||
|
||||
if (a == COMPORT_BUFFER_CLEAR) {
|
||||
|
||||
cubot.getConsoleMessagesBuffer().clear();
|
||||
unit.getConsoleMessagesBuffer().clear();
|
||||
|
||||
} else if (a == COMPORT_CONSOLE_CLEAR) {
|
||||
|
||||
cubot.setConsoleMode(Cubot.ConsoleMode.CLEAR);
|
||||
if (unit instanceof Cubot) {
|
||||
((Cubot) unit).setConsoleMode(Cubot.ConsoleMode.CLEAR);
|
||||
}
|
||||
|
||||
} else if (a == COMPORT_POLL) {
|
||||
|
||||
if (cubot.spendEnergy(4)) {
|
||||
if (unit.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()) {
|
||||
for (char[] message : unit.getConsoleMessagesBuffer()) {
|
||||
if (x + MESSAGE_LENGTH >= getCpu().getMemory().getWords().length) {
|
||||
//todo set interrupt ?
|
||||
getCpu().getStatus().setErrorFlag(true);
|
||||
@@ -61,19 +64,19 @@ public class CubotComPort extends CpuHardware {
|
||||
}
|
||||
|
||||
//Set B = number of messages
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(cubot.getConsoleMessagesBuffer().size());
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(unit.getConsoleMessagesBuffer().size());
|
||||
|
||||
}
|
||||
|
||||
} else if (a == COMPORT_FRONT_PORT_OUT) {
|
||||
|
||||
if (cubot.spendEnergy(20)) {
|
||||
if (unit.spendEnergy(5)) {
|
||||
//Get object directly in front of the Cubot
|
||||
Point frontTile = cubot.getFrontTile();
|
||||
Point frontTile = unit.getFrontTile();
|
||||
//Todo will have to add getGameObjectsBlockingAt to enable Factory
|
||||
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y);
|
||||
ArrayList<GameObject> objects = unit.getWorld().getGameObjectsAt(frontTile.x, frontTile.y);
|
||||
|
||||
if (objects.size() > 0 && objects.get(0) instanceof Programmable) {
|
||||
if (objects.size() > 0 && objects.get(0) instanceof MessageReceiver) {
|
||||
|
||||
int x = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
|
||||
@@ -86,9 +89,9 @@ public class CubotComPort extends CpuHardware {
|
||||
char[] message = new char[MESSAGE_LENGTH];
|
||||
System.arraycopy(getCpu().getMemory().getWords(), x, message, 0, MESSAGE_LENGTH);
|
||||
|
||||
//Send it to the Programmable object
|
||||
//Send it to the MessageReceiver object
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(
|
||||
((Programmable) objects.get(0)).sendMessage(message) ? 1 : 0);
|
||||
((MessageReceiver) objects.get(0)).sendMessage(message) ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +101,7 @@ public class CubotComPort extends CpuHardware {
|
||||
|
||||
} else if (a == COMPORT_SELF_OUT) {
|
||||
|
||||
if (cubot.spendEnergy(1)) {
|
||||
if (unit.spendEnergy(1)) {
|
||||
|
||||
int x = getCpu().getRegisterSet().getRegister("X").getValue();
|
||||
|
||||
@@ -111,34 +114,17 @@ public class CubotComPort extends CpuHardware {
|
||||
//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);
|
||||
getCpu().getRegisterSet().getRegister("B").setValue(unit.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")));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user