Merge pull request #153 from simon987/spark

Moved frontend to main server application
This commit is contained in:
Simon Fortier 2018-05-11 21:13:01 -04:00 committed by GitHub
commit c5cb5df335
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
202 changed files with 163352 additions and 1111 deletions

View File

@ -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.4a.jar"]

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
@ -13,11 +18,38 @@
<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: org.mongodb:mongo-java-driver:3.7.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-core:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.13" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-webapp:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-template-velocity:2.7.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.velocity:velocity:1.7" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.4" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.7.21" 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" />

View File

@ -1,13 +1,12 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.ServerConfiguration;
import net.simon987.server.assembly.Memory;
import net.simon987.server.game.*;
import net.simon987.server.logging.LogManager;
import net.simon987.server.user.User;
import org.bson.Document;
import org.json.simple.JSONObject;
import java.awt.*;
@ -19,42 +18,160 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
private static final char MAP_INFO = 0x0080;
public static final int ID = 1;
/**
* Hologram value that is displayed
* <br>TODO: Move to CubotHologram class
*/
private int hologram = 0;
/**
* Hologram string that is displayed
* <br>TODO: Move to CubotHologram class
*/
private String hologramString = "";
/**
* Hologram mode that was set during this tick
* <br>TODO: Move to CubotHologram class
*/
private HologramMode hologramMode = HologramMode.CLEARED;
/**
* Hologram mode at the end of the last tick
* <br>TODO: Move to CubotHologram class
*/
private HologramMode lastHologramMode = HologramMode.CLEARED;
/**
* Hologram color code. Format is handled by the client
* <br>TODO: Move to CubotHologram class
*/
private int hologramColor = 0;
/**
* Hit points
*/
private int hp;
/**
* Maximum hit points
*/
private int maxHp;
/**
* Shield points
*/
private int shield;
/**
* Maximum shield points
*/
private int maxShield;
/**
* Item ID of the current 'active' item
*/
private int heldItem;
/**
* 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 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;
/**
* Energy units in kJ
*/
private int energy;
/**
* Maximum energy units in kJ
*/
private int maxEnergy;
/**
* Solar panel multiplier
* <br>TODO: Set this constant in dimension
*/
private static final float SOLAR_PANEL_MULTIPLIER = 1;
/**
* Maximum size of the console buffer (also called 'internal buffer')
*/
private static final int CONSOLE_BUFFER_MAX_SIZE = 40;
/**
* Display mode of the hologram hardware
* <br>TODO: move this inside CubotHologram class
*/
public enum HologramMode {
/**
* Display nothing
*/
CLEARED,
/**
* Display value as hexadecimal in format 0x0000
*/
HEX,
/**
* Display string
*/
STRING,
/**
* Display value as decimal
*/
DEC
}
public enum ConsoleMode {
/**
* Used by the ComPort hardware - clears the console screen (client-side)
*/
CLEAR,
/**
* No specific client-side action
*/
NORMAL
}
public Cubot() {
}
@ -64,6 +181,9 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
return MAP_INFO;
}
/**
* Called every tick
*/
@Override
public void update() {
@ -130,8 +250,8 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("t", ID);
@ -155,7 +275,7 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
return dbObject;
}
public static Cubot deserialize(DBObject obj) {
public static Cubot deserialize(Document obj) {
Cubot cubot = new Cubot();
cubot.setObjectId((long) obj.get("i"));
@ -173,7 +293,52 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
cubot.maxShield = config.getInt("cubot_max_shield");
return cubot;
}
/**
* Reset to 'factory settings', as it were when it was first created
*/
private void reset() {
setDead(false);
setHp(maxHp);
setShield(0);
setHeldItem(0);
setEnergy(maxEnergy);
clearKeyboardBuffer();
consoleMessagesBuffer.clear();
lastConsoleMessagesBuffer.clear();
hologramColor = 0;
currentStatus = 0;
lastStatus = 0;
addStatus(CubotStatus.FACTORY_NEW);
}
@Override
public boolean onDeadCallback() {
LogManager.LOGGER.info(getParent().getUsername() + "'s Cubot died");
reset();
//Teleport to spawn point
this.getWorld().removeObject(this);
this.getWorld().decUpdatable();
ServerConfiguration 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.getGameUniverse().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;
}
public void setHeldItem(int heldItem) {
@ -314,18 +479,6 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
this.hologramMode = hologramMode;
}
public enum HologramMode {
CLEARED,
HEX,
STRING,
DEC
}
public enum ConsoleMode {
CLEAR,
NORMAL
}
@Override
public void setAction(Action action) {
currentAction = action;
@ -373,6 +526,9 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
return lastStatus;
}
/**
* Currently has no effect
*/
@Override
public void setHealRate(int hp) {
//no op
@ -398,6 +554,13 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
this.maxHp = hp;
}
public int getMaxShield() {
return maxShield;
}
public void setMaxShield(int maxShield) {
this.maxShield = maxShield;
}
@Override
public void heal(int amount) {
hp += amount;
@ -420,55 +583,4 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Pr
setDead(true);
}
}
public void reset() {
setDead(false);
setHp(maxHp);
setShield(0);
setHeldItem(0);
setEnergy(maxEnergy);
clearKeyboardBuffer();
consoleMessagesBuffer.clear();
lastConsoleMessagesBuffer.clear();
hologramColor = 0;
currentStatus = 0;
lastStatus = 0;
addStatus(CubotStatus.FACTORY_NEW);
}
@Override
public boolean onDeadCallback() {
LogManager.LOGGER.info(getParent().getUsername() + "'s Cubot died");
reset();
//Teleport to spawn point
this.getWorld().removeObject(this);
this.getWorld().decUpdatable();
ServerConfiguration 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.getGameUniverse().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;
}
public int getMaxShield() {
return maxShield;
}
public void setMaxShield(int maxShield) {
this.maxShield = maxShield;
}
}

View File

@ -1,10 +1,9 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
public class CubotBattery extends CpuHardware {
@ -45,9 +44,9 @@ public class CubotBattery extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -56,7 +55,7 @@ public class CubotBattery extends CpuHardware {
}
public static CubotBattery deserialize(DBObject obj) {
public static CubotBattery deserialize(Document obj) {
return new CubotBattery((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}

View File

@ -1,12 +1,11 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import net.simon987.server.game.GameObject;
import net.simon987.server.game.Programmable;
import org.bson.Document;
import java.awt.*;
import java.util.ArrayList;
@ -128,9 +127,9 @@ public class CubotComPort extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -138,7 +137,7 @@ public class CubotComPort extends CpuHardware {
return dbObject;
}
public static CubotComPort deserialize(DBObject obj) {
public static CubotComPort deserialize(Document obj) {
return new CubotComPort((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,10 +1,9 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
public class CubotCore extends CpuHardware {
@ -42,9 +41,9 @@ public class CubotCore extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -53,7 +52,7 @@ public class CubotCore extends CpuHardware {
}
public static CubotCore deserialize(DBObject obj) {
public static CubotCore deserialize(Document obj) {
return new CubotCore((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,12 +1,11 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import net.simon987.server.game.Action;
import net.simon987.server.game.TileMap;
import org.bson.Document;
public class CubotDrill extends CpuHardware {
@ -62,9 +61,9 @@ public class CubotDrill extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -72,7 +71,7 @@ public class CubotDrill extends CpuHardware {
return dbObject;
}
public static CubotDrill deserialize(DBObject obj) {
public static CubotDrill deserialize(Document obj) {
return new CubotDrill((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,10 +1,9 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
public class CubotFloppyDrive extends CpuHardware {
@ -79,9 +78,9 @@ public class CubotFloppyDrive extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -93,12 +92,12 @@ public class CubotFloppyDrive extends CpuHardware {
return dbObject;
}
public static CubotFloppyDrive deserialize(DBObject obj) {
public static CubotFloppyDrive deserialize(Document obj) {
CubotFloppyDrive drive = new CubotFloppyDrive((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
if (obj.containsField("floppy")) {
drive.floppyDisk = FloppyDisk.deserialise((DBObject) obj.get("floppy"));
if (obj.containsKey("floppy")) {
drive.floppyDisk = FloppyDisk.deserialise((Document) obj.get("floppy"));
}
return drive;

View File

@ -1,10 +1,9 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
public class CubotHologram extends CpuHardware {
@ -83,14 +82,14 @@ public class CubotHologram extends CpuHardware {
return HWID;
}
public static CubotHologram deserialize(DBObject obj) {
public static CubotHologram deserialize(Document obj) {
return new CubotHologram((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());

View File

@ -1,10 +1,9 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
public class CubotInventory extends CpuHardware {
@ -52,9 +51,9 @@ public class CubotInventory extends CpuHardware {
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -62,7 +61,7 @@ public class CubotInventory extends CpuHardware {
return dbObject;
}
public static CubotInventory deserialize(DBObject obj) {
public static CubotInventory deserialize(Document obj) {
return new CubotInventory((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,10 +1,9 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
public class CubotKeyboard extends CpuHardware {
@ -53,9 +52,9 @@ public class CubotKeyboard extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -63,7 +62,7 @@ public class CubotKeyboard extends CpuHardware {
return dbObject;
}
public static CubotKeyboard deserialize(DBObject obj) {
public static CubotKeyboard deserialize(Document obj) {
return new CubotKeyboard((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,7 +1,5 @@
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;
@ -9,6 +7,7 @@ import net.simon987.server.game.Action;
import net.simon987.server.game.Attackable;
import net.simon987.server.game.GameObject;
import net.simon987.server.game.InventoryHolder;
import org.bson.Document;
import java.awt.*;
import java.util.ArrayList;
@ -93,9 +92,9 @@ public class CubotLaser extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -103,7 +102,7 @@ public class CubotLaser extends CpuHardware {
return dbObject;
}
public static CubotLaser deserialize(DBObject obj) {
public static CubotLaser deserialize(Document obj) {
return new CubotLaser((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,13 +1,12 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import net.simon987.server.game.Action;
import net.simon987.server.game.Direction;
import net.simon987.server.io.JSONSerialisable;
import org.bson.Document;
import org.json.simple.JSONObject;
public class CubotLeg extends CpuHardware implements JSONSerialisable {
@ -86,9 +85,9 @@ public class CubotLeg extends CpuHardware implements JSONSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -96,7 +95,7 @@ public class CubotLeg extends CpuHardware implements JSONSerialisable {
return dbObject;
}
public static CubotLeg deserialize(DBObject obj) {
public static CubotLeg deserialize(Document obj) {
return new CubotLeg((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}

View File

@ -1,7 +1,5 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Memory;
@ -10,6 +8,7 @@ import net.simon987.server.game.pathfinding.Node;
import net.simon987.server.game.pathfinding.Pathfinder;
import net.simon987.server.io.JSONSerialisable;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import org.json.simple.JSONObject;
import java.util.ArrayList;
@ -150,9 +149,9 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -160,7 +159,7 @@ public class CubotLidar extends CpuHardware implements JSONSerialisable {
return dbObject;
}
public static CubotLidar deserialize(DBObject obj) {
public static CubotLidar deserialize(Document obj) {
return new CubotLidar((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,6 +1,5 @@
package net.simon987.cubotplugin;
import com.mongodb.DBObject;
import net.simon987.cubotplugin.event.ChargeShieldCommandListener;
import net.simon987.cubotplugin.event.CpuInitialisationListener;
import net.simon987.cubotplugin.event.UserCreationListener;
@ -11,6 +10,7 @@ import net.simon987.server.io.CpuHardwareDeserializer;
import net.simon987.server.io.GameObjectDeserializer;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.ServerPlugin;
import org.bson.Document;
public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer, CpuHardwareDeserializer {
@ -25,7 +25,7 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
}
@Override
public GameObject deserializeObject(DBObject object) {
public GameObject deserializeObject(Document object) {
int objType = (int) object.get("t");
@ -38,7 +38,7 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
}
@Override
public CpuHardware deserializeHardware(DBObject obj) {
public CpuHardware deserializeHardware(Document obj) {
int hwid = (int) obj.get("hwid");
switch (hwid) {

View File

@ -1,10 +1,9 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
public class CubotShield extends CpuHardware {
@ -28,8 +27,8 @@ public class CubotShield extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -49,8 +48,8 @@ public class CubotShield extends CpuHardware {
getCpu().getRegisterSet().getRegister("B").setValue(shield);
}
}
public static CubotShield deserialize(DBObject obj) {
public static CubotShield deserialize(Document obj) {
return new CubotShield((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,17 +1,16 @@
package net.simon987.cubotplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.assembly.Memory;
import net.simon987.server.io.MongoSerialisable;
import net.simon987.server.io.MongoSerializable;
import org.bson.Document;
/**
* Represents a floppy disk that is inside a floppy drive.
* Floppies contains 80 tracks with 18 sectors per track.
* That's 1440 sectors of 512 words. (total 1,474,560 bytes / 737,280 words / 1.44Mb)
*/
public class FloppyDisk implements MongoSerialisable {
public class FloppyDisk implements MongoSerializable {
/**
* Contents of the disk
@ -84,8 +83,8 @@ public class FloppyDisk implements MongoSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("rwHeadTrack", rwHeadTrack);
dbObject.put("memory", memory.mongoSerialise());
@ -93,12 +92,12 @@ public class FloppyDisk implements MongoSerialisable {
return dbObject;
}
public static FloppyDisk deserialise(DBObject obj) {
public static FloppyDisk deserialise(Document obj) {
FloppyDisk floppyDisk = new FloppyDisk();
floppyDisk.rwHeadTrack = (int) obj.get("rwHeadTrack");
floppyDisk.memory = Memory.deserialize((DBObject) obj.get("memory"));
floppyDisk.memory = Memory.deserialize((Document) obj.get("memory"));
return floppyDisk;
}

View File

@ -7,6 +7,9 @@ import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventListener;
import net.simon987.server.game.GameObject;
/**
* Debug command to add shield points to a Cubot
*/
public class ChargeShieldCommandListener implements GameEventListener {
@Override
public Class getListenedEventType() {

View File

@ -15,7 +15,6 @@ public class CpuInitialisationListener implements GameEventListener {
@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();

View File

@ -57,7 +57,5 @@ public class UserCreationListener implements GameEventListener {
user.setControlledUnit(cubot);
LogManager.LOGGER.fine("(Plugin) Handled User creation event (Cubot Plugin)");
}
}

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
@ -12,11 +17,38 @@
<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: org.mongodb:mongo-java-driver:3.7.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-core:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.13" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-webapp:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-template-velocity:2.7.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.velocity:velocity:1.7" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.4" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.7.21" 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" />

View File

@ -1,11 +1,14 @@
package net.simon987.mischwplugin;
import com.mongodb.BasicDBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Util;
import org.bson.Document;
/**
* Hardware to get game time
*/
public class Clock extends CpuHardware {
public static final char HWID = 0x0008;
@ -34,9 +37,9 @@ public class Clock extends CpuHardware {
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);

View File

@ -1,13 +1,16 @@
package net.simon987.mischwplugin;
import com.mongodb.DBObject;
import net.simon987.mischwplugin.event.CpuInitialisationListener;
import net.simon987.server.ServerConfiguration;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.io.CpuHardwareDeserializer;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.ServerPlugin;
import org.bson.Document;
/**
* Plugin that adds miscellaneous hardware to the game
*/
public class MiscHWPlugin extends ServerPlugin implements CpuHardwareDeserializer {
@ -19,7 +22,7 @@ public class MiscHWPlugin extends ServerPlugin implements CpuHardwareDeserialize
}
@Override
public CpuHardware deserializeHardware(DBObject hwJson) {
public CpuHardware deserializeHardware(Document hwJson) {
int hwid = (int) hwJson.get("hwid");
switch (hwid) {

View File

@ -1,11 +1,14 @@
package net.simon987.mischwplugin;
import com.mongodb.BasicDBObject;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.bson.Document;
import java.util.Random;
/**
* Hardware to generate random numbers
*/
public class RandomNumberGenerator extends CpuHardware {
public static final char HWID = 0x0007;
@ -31,9 +34,9 @@ public class RandomNumberGenerator extends CpuHardware {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
@ -15,10 +20,37 @@
<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" />
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:3.7.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-core:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.13" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-webapp:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-template-velocity:2.7.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.velocity:velocity:1.7" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.4" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.7.21" level="project" />
</component>
</module>

View File

@ -1,7 +1,5 @@
package net.simon987.npcplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.Util;
import net.simon987.server.game.Attackable;
@ -9,28 +7,48 @@ import net.simon987.server.game.GameObject;
import net.simon987.server.game.Rechargeable;
import net.simon987.server.game.Updatable;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import org.json.simple.JSONObject;
import java.util.ArrayList;
/**
* Game object that deals damage to nearby objects and gives them energy
*/
public class ElectricBox extends GameObject implements Updatable, Attackable {
public static final int ID = 7;
/**
* Hit points
*/
private int hp;
/**
* Maximum hit points
*/
private static final int maxHp = GameServer.INSTANCE.getConfig().getInt("electric_box_hp");
/**
* Number of hit points dealt to nearby objects each tick
*/
private static final int damageDealt = GameServer.INSTANCE.getConfig().getInt("electric_box_damage");
/**
* Number of energy points given to nearby objects each tick
*/
private static final int energyGiven = GameServer.INSTANCE.getConfig().getInt("electric_box_energy_given");
private int hp;
/**
* List of nearby objects. Is updated every tick
*/
private ArrayList<Attackable> nearObjects = new ArrayList<>();
public ElectricBox() {
this.hp = maxHp;
}
/**
* Currently has no effect
*/
@Override
public void setHealRate(int hp) {
//no op
@ -51,11 +69,17 @@ public class ElectricBox extends GameObject implements Updatable, Attackable {
return hp;
}
/**
* Currently has no effect
*/
@Override
public void setMaxHp(int hp) {
//No op
}
/**
* Currently has no effect
*/
@Override
public void heal(int amount) {
//No op
@ -77,6 +101,10 @@ public class ElectricBox extends GameObject implements Updatable, Attackable {
return Obstacle.MAP_INFO;
}
/**
* Updates the current list nearby objects
* <br>An object is considered 'nearby' if its Manhattan distance is {@literal <= @} 1 and is Attackable
*/
private void updateNearObjects() {
nearObjects.clear();
@ -89,6 +117,9 @@ public class ElectricBox extends GameObject implements Updatable, Attackable {
}
}
/**
* Called every tick
*/
@Override
public void update() {
@ -118,8 +149,8 @@ public class ElectricBox extends GameObject implements Updatable, Attackable {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("x", getX());
@ -130,7 +161,7 @@ public class ElectricBox extends GameObject implements Updatable, Attackable {
return dbObject;
}
public static ElectricBox deserialize(DBObject obj) {
public static ElectricBox deserialize(Document obj) {
ElectricBox electricBox = new ElectricBox();
electricBox.setHp((int) obj.get("hp"));

View File

@ -1,25 +1,36 @@
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.bson.Document;
import org.json.simple.JSONObject;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Game objects that regularly creates NonPlayerCharacters
*/
public class Factory extends GameObject implements Updatable {
private static final int MAP_INFO = 0x0200;
static final int ID = 3;
/**
* Maximum number of NonPlayerCharacters assigned to this Factory
*/
private static final int MAX_NPC_COUNT = GameServer.INSTANCE.getConfig().getInt("factory_max_npc_count");
/**
* Number of ticks to wait after creating a NonPlayerCharacter
*/
private static final int NPC_CREATION_COOLDOWN = NonPlayerCharacter.LIFETIME / MAX_NPC_COUNT;
/**
* List of associated NonPlayerCharacters
*/
private ArrayList<NonPlayerCharacter> npcs = new ArrayList<>();
/**
@ -43,6 +54,10 @@ public class Factory extends GameObject implements Updatable {
return MAP_INFO;
}
/**
* Called every tick
* <br>The fist time this is called, NPCs retrieved from the database are linked to the Factory
*/
@Override
public void update() {
@ -61,6 +76,8 @@ public class Factory extends GameObject implements Updatable {
}
tmpNpcArray = null;
} else {
if (cooldown == 0) {
@ -115,15 +132,15 @@ public class Factory extends GameObject implements Updatable {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("x", getX());
dbObject.put("y", getY());
dbObject.put("t", ID);
BasicDBList tmpNpcArray = new BasicDBList();
List<Long> tmpNpcArray = new ArrayList<>(npcs.size());
for (NonPlayerCharacter npc : npcs) {
tmpNpcArray.add(npc.getObjectId());
@ -134,14 +151,14 @@ public class Factory extends GameObject implements Updatable {
return dbObject;
}
public static Factory deserialise(DBObject obj) {
public static Factory deserialise(Document 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();
factory.tmpNpcArray = ((ArrayList) obj.get("tmpNpcArray")).toArray();
return factory;
}

View File

@ -10,19 +10,31 @@ import net.simon987.server.logging.LogManager;
import java.util.ArrayList;
import java.util.Random;
/**
* Find Biomass, move towards it, collect it, repeat
*/
public class HarvestTask extends NPCTask {
private Random random;
/**
* Number of ticks to wait before continuing
*/
private int pause;
/**
* Direction of the next world to visit (randomly chosen)
*/
private Direction nextWorldDirection = null;
public HarvestTask() {
random = new Random();
pause = 0;
}
private Direction nextWorldDirection = null;
/**
* This task never finishes
*/
@Override
public boolean checkCompleted() {
return false;

View File

@ -1,10 +1,9 @@
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.bson.Document;
import org.json.simple.JSONObject;
@ -12,6 +11,9 @@ 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");
@ -77,22 +79,21 @@ public class HarvesterNPC extends NonPlayerCharacter {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
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) {
public static HarvesterNPC deserialize(Document obj) {
HarvesterNPC npc = new HarvesterNPC();
npc.setObjectId((long) obj.get("i"));
@ -100,8 +101,6 @@ public class HarvesterNPC extends NonPlayerCharacter {
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;

View File

@ -9,27 +9,40 @@ import net.simon987.server.logging.LogManager;
import java.util.ArrayList;
/**
* Game object that actively interacts with the game world by doing tasks
*/
public abstract class NonPlayerCharacter extends GameObject implements Updatable, Attackable {
private static final int MAP_INFO = 0x0040;
/**
* Maximum distance to travel from its factory, in Worlds
*/
private static final int MAX_FACTORY_DISTANCE = GameServer.INSTANCE.getConfig().getInt("npc_max_factory_distance");
/**
* Number of ticks to live
*/
public static final int LIFETIME = GameServer.INSTANCE.getConfig().getInt("npc_lifetime");
// Set these just in case they aren't overridden in the subclass
public static final int HP_MAX_DEFAULT = 100;
public static final int HP_REGEN_RATE_DEFAULT = 0;
//Unused
/**
* Currently unused
*/
int energy;
int maxEnergy;
/**
* Current task
*/
private NPCTask task;
/**
* Action at the end of the last tick
*/
private Action lastAction = Action.IDLE;
/**

View File

@ -1,10 +1,8 @@
package net.simon987.npcplugin;
import com.mongodb.DBObject;
import net.simon987.npcplugin.event.CpuInitialisationListener;
import net.simon987.npcplugin.event.VaultWorldUpdateListener;
import net.simon987.npcplugin.event.WorldCreationListener;
import net.simon987.npcplugin.io.StatsDatabaseManager;
import net.simon987.server.ServerConfiguration;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.game.GameObject;
@ -12,6 +10,7 @@ import net.simon987.server.io.CpuHardwareDeserializer;
import net.simon987.server.io.GameObjectDeserializer;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.ServerPlugin;
import org.bson.Document;
import java.util.ArrayList;
@ -22,8 +21,6 @@ public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer, C
*/
private static ArrayList<RadioTower> radioTowers;
private static StatsDatabaseManager statsDbManager;
@Override
public void init(ServerConfiguration configuration) {
@ -33,13 +30,11 @@ public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer, C
radioTowers = new ArrayList<>(32);
statsDbManager = new StatsDatabaseManager(configuration);
LogManager.LOGGER.info("Initialised NPC plugin");
}
@Override
public GameObject deserializeObject(DBObject obj) {
public GameObject deserializeObject(Document obj) {
int objType = (int) obj.get("t");
@ -65,7 +60,7 @@ public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer, C
}
@Override
public CpuHardware deserializeHardware(DBObject obj) {
public CpuHardware deserializeHardware(Document obj) {
int hwid = (int) obj.get("hwid");
switch (hwid) {
@ -80,7 +75,4 @@ public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer, C
return radioTowers;
}
public static StatsDatabaseManager getStatsDbManager() {
return statsDbManager;
}
}

View File

@ -1,14 +1,12 @@
package net.simon987.npcplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.game.Attackable;
import net.simon987.server.game.GameObject;
import org.bson.Document;
import org.json.simple.JSONObject;
/**
* Generic game object that blocks the path.
* Some types of obstacles might have some more interesting features (see ElectricBox)
*/
public class Obstacle extends GameObject implements Attackable {
@ -90,8 +88,8 @@ public class Obstacle extends GameObject implements Attackable {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("x", getX());
@ -117,7 +115,7 @@ public class Obstacle extends GameObject implements Attackable {
return json;
}
public static Obstacle deserialize(DBObject obj) {
public static Obstacle deserialize(Document obj) {
Obstacle obstacle = new Obstacle((int) obj.get("hp"));
obstacle.setObjectId((long) obj.get("i"));

View File

@ -1,23 +1,31 @@
package net.simon987.npcplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.game.*;
import org.bson.Document;
import org.json.simple.JSONObject;
public class Portal extends GameObject implements Enterable {
private Location dst;
/**
* Destination location
*/
private Location destination;
public static final int MAP_INFO = 0x0020;
public static final int ID = 8;
/**
* Called when an object attempts to walk directly into a Enterable object
*
* @param object The game object that attempted to enter
* @return true if successful, false to block the object
*/
@Override
public boolean enter(GameObject object) {
World world = GameServer.INSTANCE.getGameUniverse().getWorld(dst.worldX, dst.worldY, false, dst.dimension);
World world = GameServer.INSTANCE.getGameUniverse().getWorld(destination.worldX, destination.worldY, false, destination.dimension);
if (object instanceof Updatable) {
object.getWorld().decUpdatable();
@ -27,8 +35,8 @@ public class Portal extends GameObject implements Enterable {
object.setWorld(world);
world.addObject(object);
object.setX(dst.x);
object.setY(dst.y);
object.setX(destination.x);
object.setY(destination.y);
return true;
}
@ -39,27 +47,27 @@ public class Portal extends GameObject implements Enterable {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("x", getX());
dbObject.put("y", getY());
dbObject.put("t", ID);
dbObject.put("dstWorldX", dst.worldX);
dbObject.put("dstWorldY", dst.worldY);
dbObject.put("dstX", dst.x);
dbObject.put("dstY", dst.y);
dbObject.put("dstDimension", dst.dimension);
dbObject.put("dstWorldX", destination.worldX);
dbObject.put("dstWorldY", destination.worldY);
dbObject.put("dstX", destination.x);
dbObject.put("dstY", destination.y);
dbObject.put("dstDimension", destination.dimension);
return dbObject;
}
public static Portal deserialize(DBObject obj) {
public static Portal deserialize(Document obj) {
Portal portal = new Portal();
portal.dst = new Location(
portal.destination = new Location(
(int) obj.get("dstWorldX"),
(int) obj.get("dstWorldY"),
(String) obj.get("dstDimension"),
@ -83,11 +91,11 @@ public class Portal extends GameObject implements Enterable {
return json;
}
public Location getDst() {
return dst;
public Location getDestination() {
return destination;
}
public void setDst(Location dst) {
this.dst = dst;
public void setDestination(Location destination) {
this.destination = destination;
}
}

View File

@ -1,13 +1,12 @@
package net.simon987.npcplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Util;
import net.simon987.server.game.Action;
import net.simon987.server.game.ControllableUnit;
import org.bson.Document;
import java.util.ArrayList;
@ -67,9 +66,9 @@ public class RadioReceiverHardware extends CpuHardware {
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("hwid", (int) HWID);
dbObject.put("cubot", cubot.getObjectId());
@ -77,7 +76,7 @@ public class RadioReceiverHardware extends CpuHardware {
return dbObject;
}
public static RadioReceiverHardware deserialize(DBObject obj) {
public static RadioReceiverHardware deserialize(Document obj) {
return new RadioReceiverHardware((ControllableUnit) GameServer.INSTANCE.getGameUniverse().getObject((long) obj.get("cubot")));
}
}

View File

@ -1,10 +1,9 @@
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.bson.Document;
import org.json.simple.JSONObject;
import java.util.ArrayList;
@ -24,7 +23,6 @@ public class RadioTower extends GameObject implements Programmable, Updatable {
return MAP_INFO;
}
/**
* Messages from the current tick
*/
@ -67,8 +65,8 @@ public class RadioTower extends GameObject implements Programmable, Updatable {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("x", getX());
@ -78,7 +76,7 @@ public class RadioTower extends GameObject implements Programmable, Updatable {
return dbObject;
}
public static RadioTower deserialize(DBObject obj) {
public static RadioTower deserialize(Document obj) {
RadioTower tower = new RadioTower();
tower.setObjectId((long) obj.get("i"));

View File

@ -141,7 +141,7 @@ public class VaultDimension {
if (exitPortalPt != null) {
VaultExitPortal exitPortal = new VaultExitPortal();
exitPortal.setDst(exitLocation);
exitPortal.setDestination(exitLocation);
exitPortal.setX(exitPortalPt.x);
exitPortal.setY(exitPortalPt.y);
exitPortal.setWorld(objectiveWorld);
@ -158,7 +158,7 @@ public class VaultDimension {
if (homePortalPt != null) {
Portal homePortal = new Portal();
homePortal.setDst(exitLocation);
homePortal.setDestination(exitLocation);
homePortal.setX(homePortalPt.x);
homePortal.setY(homePortalPt.y);
homePortal.setWorld(homeWorld);

View File

@ -1,11 +1,10 @@
package net.simon987.npcplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.crypto.RandomStringGenerator;
import net.simon987.server.game.*;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import org.json.simple.JSONObject;
import java.util.Arrays;
@ -124,8 +123,8 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("x", getX());
@ -152,7 +151,7 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up
return json;
}
public static VaultDoor deserialize(DBObject obj) {
public static VaultDoor deserialize(Document obj) {
VaultDoor vaultDoor = new VaultDoor(0); //cypherId ?
vaultDoor.setX((int) obj.get("x"));
@ -160,7 +159,7 @@ public class VaultDoor extends GameObject implements Programmable, Enterable, Up
vaultDoor.setObjectId((long) obj.get("i"));
if (obj.containsField("homeX") && obj.containsField("homeY")) {
if (obj.containsKey("homeX") && obj.containsKey("homeY")) {
vaultDoor.setHomeX((int) obj.get("homeX"));
vaultDoor.setHomeY((int) obj.get("homeY"));
}

View File

@ -1,11 +1,10 @@
package net.simon987.npcplugin;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.game.ControllableUnit;
import net.simon987.server.game.GameObject;
import net.simon987.server.game.Location;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
/**
* Final exit portal located in the 'last' World of a Vault dimension
@ -15,18 +14,18 @@ public class VaultExitPortal extends Portal {
public static final int ID = 9;
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("i", getObjectId());
dbObject.put("x", getX());
dbObject.put("y", getY());
dbObject.put("t", ID);
dbObject.put("dstWorldX", getDst().worldX);
dbObject.put("dstWorldY", getDst().worldY);
dbObject.put("dstX", getDst().x);
dbObject.put("dstY", getDst().y);
dbObject.put("dstDimension", getDst().dimension);
dbObject.put("dstWorldX", getDestination().worldX);
dbObject.put("dstWorldY", getDestination().worldY);
dbObject.put("dstX", getDestination().x);
dbObject.put("dstY", getDestination().y);
dbObject.put("dstDimension", getDestination().dimension);
return dbObject;
}
@ -34,20 +33,21 @@ public class VaultExitPortal extends Portal {
@Override
public boolean enter(GameObject object) {
LogManager.LOGGER.info(((ControllableUnit) object).getParent().getUsername() + " Completed vault " +
object.getWorld().getDimension());
NpcPlugin.getStatsDbManager().saveVaultCompletion((ControllableUnit) object, object.getWorld().getDimension());
if (object instanceof ControllableUnit) {
LogManager.LOGGER.info(((ControllableUnit) object).getParent().getUsername() + " Completed vault " +
object.getWorld().getDimension());
((ControllableUnit) object).getParent().getStats().addToStringSet("completedVaults", getWorld().getDimension());
}
return super.enter(object);
}
public static Portal deserialize(DBObject obj) {
public static Portal deserialize(Document obj) {
VaultExitPortal portal = new VaultExitPortal();
portal.setDst(new Location(
portal.setDestination(new Location(
(int) obj.get("dstWorldX"),
(int) obj.get("dstWorldY"),
(String) obj.get("dstDimension"),

View File

@ -14,11 +14,26 @@ import java.util.HashMap;
public class VaultWorldUpdateListener implements GameEventListener {
/**
* Map of worlds and their time to wait until next respawn event
*/
private HashMap<World, Long> worldWaitMap = new HashMap<>(200);
/**
* Lower bound of ElectricBox to be created on a respawn event
*/
private static int minElectricBoxCount;
/**
* Upper bound of ElectricBox to be created on a respawn event
*/
private static int maxElectricBoxCount;
/**
* Number of game ticks to wait after the threshold has been met
*/
private static int waitTime;
/**
* Threshold before starting the
*/
private static int electricBoxThreshold;
public VaultWorldUpdateListener(ServerConfiguration config) {
@ -37,6 +52,7 @@ public class VaultWorldUpdateListener implements GameEventListener {
@Override
public void handle(GameEvent event) {
//TODO: Move this and the Biomass UpdateListener to a 'RespawnManager' kind of deal
World world = ((WorldUpdateEvent) event).getWorld();
if (world.getDimension().startsWith("v")) {
@ -66,6 +82,5 @@ public class VaultWorldUpdateListener implements GameEventListener {
}
}
}
}
}

View File

@ -18,6 +18,7 @@ public class WorldCreationListener implements GameEventListener {
/**
* Spawn rate. Higher = rarer: A factory will be spawn about every FACTORY_SPAWN_RATE generated Worlds
* <br>TODO: Get from config.properties
*/
private static final int FACTORY_SPAWN_RATE = 35;

View File

@ -1,49 +0,0 @@
package net.simon987.npcplugin.io;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
import net.simon987.server.ServerConfiguration;
import net.simon987.server.game.ControllableUnit;
import net.simon987.server.io.DatabaseManager;
import net.simon987.server.logging.LogManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class StatsDatabaseManager extends DatabaseManager {
public StatsDatabaseManager(ServerConfiguration config) {
super(config);
}
public void saveVaultCompletion(ControllableUnit unit, String dimension) {
Connection connection = getConnection();
try {
PreparedStatement p = connection.prepareStatement("INSERT INTO mar_vault_clear " +
"(username, clear_time, vault_id) VALUES (?,?,?)");
p.setString(1, unit.getParent().getUsername());
p.setInt(2, 0);
p.setString(3, dimension);
int result = p.executeUpdate();
LogManager.LOGGER.fine("Saved vault clear (" + result + " rows changed)");
} catch (MySQLIntegrityConstraintViolationException e) {
LogManager.LOGGER.fine("This vault was already cleared by " + unit.getParent().getUsername());
} catch (SQLException e) {
LogManager.LOGGER.severe(e.getMessage());
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
@ -15,10 +20,37 @@
<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" />
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:3.7.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-core:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.13" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-webapp:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-template-velocity:2.7.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.velocity:velocity:1.7" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.4" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.7.21" level="project" />
</component>
</module>

View File

@ -1,9 +1,8 @@
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.bson.Document;
import org.json.simple.JSONObject;
public class BiomassBlob extends GameObject implements InventoryHolder {
@ -43,9 +42,9 @@ public class BiomassBlob extends GameObject implements InventoryHolder {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("t", ID);
dbObject.put("i", getObjectId());
@ -65,15 +64,8 @@ public class BiomassBlob extends GameObject implements InventoryHolder {
this.biomassCount = biomassCount;
}
// public int getStyle() {
// return style;
// }
//
// public void setStyle(int style) {
// this.style = style;
// }
public static BiomassBlob deserialize(DBObject obj) {
public static BiomassBlob deserialize(Document obj) {
BiomassBlob biomassBlob = new BiomassBlob();

View File

@ -1,6 +1,5 @@
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;
@ -9,6 +8,8 @@ import net.simon987.server.game.GameObject;
import net.simon987.server.io.GameObjectDeserializer;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.ServerPlugin;
import org.bson.Document;
public class BiomassPlugin extends ServerPlugin implements GameObjectDeserializer {
@ -23,7 +24,7 @@ public class BiomassPlugin extends ServerPlugin implements GameObjectDeserialize
}
@Override
public GameObject deserializeObject(DBObject object) {
public GameObject deserializeObject(Document object) {
int objType = (int) object.get("t");

View File

@ -1,11 +1,11 @@
package net.simon987.pluginradioactivecloud;
import com.mongodb.DBObject;
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;
import org.bson.Document;
public class RadioactiveCloudPlugin extends ServerPlugin implements GameObjectDeserializer {
@ -16,7 +16,7 @@ public class RadioactiveCloudPlugin extends ServerPlugin implements GameObjectDe
}
@Override
public GameObject deserializeObject(DBObject object) {
public GameObject deserializeObject(Document object) {
return null;
}

View File

@ -1,25 +1,18 @@
# [Live demo](https://muchassemblyrequired.com)
### [Official website](https://muchassemblyrequired.com)
Program the 8086-like microprocessor of a robot in a grid-based multiplayer world. The game is web based so no installation is required.
In its current state, players can walk around the game universe and collect Biomass blobs & Iron/copper ore using the online code editor.
![screenshot from 2017-11-12 13-01-43](https://user-images.githubusercontent.com/7120851/32701793-e5d07e98-c7a9-11e7-9931-f8db7b287994.png)
Wiki: [GitHub](https://github.com/simon987/Much-Assembly-Required/wiki)
Wiki: [GitHub](https://github.com/simon987/Much-Assembly-Required/wiki)
Chat: [Slack](https://join.slack.com/t/muchassemblyrequired/shared_invite/enQtMjY3Mjc1OTUwNjEwLTkyOTIwOTA5OGY4MDVlMGI4NzM5YzlhMWJiMGY1OWE2NjUxODQ1NWQ1YTcxMTA1NGZkYzNjYzMyM2E1ODdmNzg)
## 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
# Deploying the server
Note: You can find the frontend [here](https://github.com/simon987/Much-Assembly-Required-Frontend)
## Linux (Ubuntu 16.04)
```bash
# Install tools
sudo apt install git maven openjdk-8-jdk
sudo apt install git maven openjdk-8-jdk mongodb
# Obtain source files
git clone https://github.com/simon987/Much-Assembly-Required.git
@ -30,7 +23,7 @@ mvn package
# Run
cd target
java -jar server-1.2a.jar
java -jar server-1.4a.jar
```
## Windows (tested on Windows 10)
@ -61,10 +54,8 @@ mongod
```batch
:: Runs the MAR server
cd Much-Assembly-Required\target
java -jar server-1.2a.jar
java -jar server-1.4a.jar
```
3. Run the frontend, following the instructions that you can find [here](https://github.com/simon987/Much-Assembly-Required-Frontend).
## Docker
### Requirements
@ -79,8 +70,12 @@ 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

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
@ -11,13 +16,40 @@
</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" />
<orderEntry type="library" name="Maven: org.mongodb:mongo-java-driver:3.7.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.0.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.0.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-core:2.7.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.13" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-webapp:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-server:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-servlet:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.8.v20171121" level="project" />
<orderEntry type="library" name="Maven: com.sparkjava:spark-template-velocity:2.7.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.velocity:velocity:1.7" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.4" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.7.21" level="project" />
</component>
</module>

View File

@ -24,10 +24,6 @@
<resources>
<resource>
<directory>../Server/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>config.properties</include>
</includes>
</resource>
</resources>
</configuration>
@ -92,22 +88,12 @@
<version>1.4a</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>
@ -121,7 +107,27 @@
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>2.10.1</version>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.7.2</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.21</version>
</dependency>
</dependencies>

View File

@ -1,8 +1,11 @@
package net.simon987.server;
import com.mongodb.*;
import net.simon987.server.assembly.exception.CancelledException;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.UpdateOptions;
import net.simon987.server.crypto.CryptoProvider;
import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventDispatcher;
@ -14,10 +17,13 @@ import net.simon987.server.game.debug.*;
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 net.simon987.server.user.UserManager;
import net.simon987.server.user.UserStatsHelper;
import net.simon987.server.websocket.SocketServer;
import org.bson.Document;
import java.io.File;
import java.net.UnknownHostException;
import java.util.ArrayList;
public class GameServer implements Runnable {
@ -39,15 +45,21 @@ public class GameServer implements Runnable {
private MongoClient mongo = null;
private UserManager userManager;
private UserStatsHelper userStatsHelper;
public GameServer() {
this.config = new ServerConfiguration("config.properties");
try{
mongo = new MongoClient("localhost", 27017);
} catch (UnknownHostException e) {
e.printStackTrace();
}
mongo = new MongoClient(config.getString("mongo_address"), config.getInt("mongo_port"));
MongoDatabase db = mongo.getDatabase(config.getString("mongo_dbname"));
MongoCollection<Document> userCollection = db.getCollection("user");
userManager = new UserManager(userCollection);
userStatsHelper = new UserStatsHelper(userCollection);
gameUniverse = new GameUniverse(config);
gameUniverse.setMongo(mongo);
@ -69,7 +81,6 @@ public class GameServer implements Runnable {
if (pluginFile.getName().endsWith(".jar")) {
pluginManager.load(pluginFile, config);
}
}
} else {
if (!pluginDir.mkdir()) {
@ -93,7 +104,7 @@ public class GameServer implements Runnable {
eventDispatcher.getListeners().add(new HealObjCommandListener());
eventDispatcher.getListeners().add(new DamageObjCommandListener());
eventDispatcher.getListeners().add(new SetEnergyCommandListener());
eventDispatcher.getListeners().add(new SaveGameCommandListener());
}
public GameUniverse getGameUniverse() {
@ -127,7 +138,7 @@ public class GameServer implements Runnable {
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");
// LogManager.LOGGER.info("Wait time : " + waitTime + "ms | Update time: " + uTime + "ms | " + (int) (((double) uTime / waitTime) * 100) + "% load");
try {
if (waitTime >= 0) {
@ -136,10 +147,7 @@ public class GameServer implements Runnable {
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void tick() {
@ -149,7 +157,6 @@ public class GameServer implements Runnable {
GameEvent event = new TickEvent(gameUniverse.getTime());
eventDispatcher.dispatch(event); //Ignore cancellation
//Process user code
for (User user : gameUniverse.getUsers()) {
@ -186,25 +193,22 @@ public class GameServer implements Runnable {
socketServer.tick();
LogManager.LOGGER.info("Processed " + gameUniverse.getWorldCount() + " worlds (" + updatedWorlds +
" updated)");
// LogManager.LOGGER.info("Processed " + gameUniverse.getWorldCount() + " worlds (" + updatedWorlds +
// " updated)");
}
void load() {
LogManager.LOGGER.info("Loading all data from MongoDB");
DB db = mongo.getDB("mar");
MongoDatabase db = mongo.getDatabase(config.getString("mongo_dbname"));
DBCollection worlds = db.getCollection("world");
DBCollection users = db.getCollection("user");
DBCollection server = db.getCollection("server");
MongoCollection<Document> worlds = db.getCollection("world");
MongoCollection<Document> server = db.getCollection("server");
BasicDBObject whereQuery = new BasicDBObject();
Document whereQuery = new Document();
whereQuery.put("shouldUpdate", true);
DBCursor cursor = worlds.find(whereQuery);
MongoCursor<Document> cursor = worlds.find(whereQuery).iterator();
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
while (cursor.hasNext()) {
World w = World.deserialize(cursor.next());
@ -212,19 +216,15 @@ public class GameServer implements Runnable {
}
//Load users
cursor = users.find();
while (cursor.hasNext()) {
try {
universe.addUser(User.deserialize(cursor.next()));
} catch (CancelledException e) {
e.printStackTrace();
}
ArrayList<User> userList = userManager.getUsers();
for (User user : userList) {
universe.addUser(user);
}
//Load misc server info
cursor = server.find();
cursor = server.find().iterator();
if (cursor.hasNext()) {
DBObject serverObj = cursor.next();
Document serverObj = cursor.next();
gameUniverse.setTime((long) serverObj.get("time"));
gameUniverse.setNextObjectId((long) serverObj.get("nextObjectId"));
}
@ -233,49 +233,47 @@ public class GameServer implements Runnable {
" | U:" + GameServer.INSTANCE.getGameUniverse().getUserCount());
}
private void save() {
public void save() {
LogManager.LOGGER.info("Saving to MongoDB | W:" + gameUniverse.getWorldCount() + " | U:" + gameUniverse.getUserCount());
try{
DB db = mongo.getDB("mar");
MongoDatabase db = mongo.getDatabase(config.getString("mongo_dbname"));
UpdateOptions updateOptions = new UpdateOptions();
updateOptions.upsert(true);
int unloaded_worlds = 0;
DBCollection worlds = db.getCollection("world");
DBCollection users = db.getCollection("user");
DBCollection server = db.getCollection("server");
MongoCollection<Document> worlds = db.getCollection("world");
MongoCollection<Document> users = db.getCollection("user");
MongoCollection<Document> 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());
worlds.replaceOne(new Document("_id", w.getId()), w.mongoSerialise(), updateOptions);
// If the world should unload, it is removed from the Universe after having been saved.
//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());
users.replaceOne(new Document("_id", u.getUsername()), u.mongoSerialise(), updateOptions);
}
}
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.
Document serverObj = new Document();
serverObj.put("time", gameUniverse.getTime());
serverObj.put("nextObjectId", gameUniverse.getNextObjectId());
server.save(serverObj);
//A constant id ensures only one entry is kept and updated, instead of a new entry created every save.
server.replaceOne(new Document("_id", "serverinfo"), serverObj, updateOptions);
LogManager.LOGGER.info(""+insertedWorlds+" worlds saved, "+unloaded_worlds+" unloaded");
LogManager.LOGGER.info("Done!");
LogManager.LOGGER.info("" + insertedWorlds + " worlds saved, " + unloaded_worlds + " unloaded");
} catch (Exception e) {
LogManager.LOGGER.severe("Problem happened during save function");
e.printStackTrace();
@ -297,4 +295,12 @@ public class GameServer implements Runnable {
public DayNightCycle getDayNightCycle() {
return dayNightCycle;
}
public UserManager getUserManager() {
return userManager;
}
public UserStatsHelper getUserStatsHelper() {
return userStatsHelper;
}
}

View File

@ -1,9 +1,8 @@
package net.simon987.server;
import net.simon987.server.logging.LogManager;
import net.simon987.server.webserver.SocketServer;
import java.net.InetSocketAddress;
import net.simon987.server.web.WebServer;
import spark.Spark;
public class Main {
@ -12,15 +11,14 @@ public class Main {
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);
//Web server
WebServer webServer = new WebServer(GameServer.INSTANCE.getConfig());
GameServer.INSTANCE.setSocketServer(socketServer);
Spark.awaitInitialization();
GameServer.INSTANCE.setSocketServer(webServer.getSocketServer());
(new Thread(socketServer)).start();
(new Thread(GameServer.INSTANCE)).start();
}
}

View File

@ -3,7 +3,6 @@ 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;

View File

@ -61,7 +61,7 @@ public class Assembler {
/**
* Check for and save the origin
*
* @param line Current line. Assuming that the comments & labels are removed
* @param line Current line. Assuming that the comments and labels are removed
* @param result Current line number
*/
private static void checkForORGInstruction(String line, AssemblyResult result, int currentLine)
@ -121,7 +121,7 @@ public class Assembler {
/**
* Parse the DW instruction (Define word). Handles DUP operator
*
* @param line Current line. assuming that comments & labels are removed
* @param line Current line. assuming that comments and labels are removed
* @param currentLine Current line number
* @param labels Map of labels
* @return Encoded instruction, null if the line is not a DW instruction
@ -258,7 +258,7 @@ public class Assembler {
/**
* Parse the DW instruction (Define word). Handles DUP operator
*
* @param line Current line. assuming that comments & labels are removed
* @param line Current line. assuming that comments and labels are removed
* @param currentLine Current line number
* @return Encoded instruction, null if the line is not a DW instruction
*/
@ -267,7 +267,7 @@ public class Assembler {
}
/**
* Check for and handle section declarations (.text & .data)
* Check for and handle section declarations (.text and .data)
*
* @param line Current line
*/

View File

@ -1,26 +1,26 @@
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.io.MongoSerializable;
import net.simon987.server.logging.LogManager;
import net.simon987.server.user.User;
import org.bson.Document;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 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 and execute them. A CPU object holds registers objects and
* a Memory object.
*/
public class CPU implements MongoSerialisable {
public class CPU implements MongoSerializable {
/**
*
@ -160,7 +160,7 @@ public class CPU implements MongoSerialisable {
}
int elapsed = (int) (System.currentTimeMillis() - startTime);
LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
// LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
//Write execution cost and instruction count to memory
@ -173,7 +173,6 @@ public class CPU implements MongoSerialisable {
public void executeInstruction(Instruction instruction, int source, int destination) {
//Execute the instruction
if (source == 0) {
//No operand (assuming that destination is also null)
@ -348,21 +347,21 @@ public class CPU implements MongoSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
public Document mongoSerialise() {
Document dbObject = new Document();
dbObject.put("memory", memory.mongoSerialise());
dbObject.put("registerSet", registerSet.mongoSerialise());
dbObject.put("codeSegmentOffset", codeSectionOffset);
BasicDBList hardwareList = new BasicDBList();
List<Document> hardwareList = new ArrayList<>();
for (Integer address : attachedHardware.keySet()) {
CpuHardware hardware = attachedHardware.get(address);
BasicDBObject serialisedHw = hardware.mongoSerialise();
Document serialisedHw = hardware.mongoSerialise();
serialisedHw.put("address", address);
hardwareList.add(serialisedHw);
}
@ -373,22 +372,22 @@ public class CPU implements MongoSerialisable {
}
public static CPU deserialize(DBObject obj, User user) throws CancelledException {
public static CPU deserialize(Document 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");
ArrayList hardwareList = (ArrayList) obj.get("hardware");
for (Object serialisedHw : hardwareList) {
CpuHardware hardware = CpuHardware.deserialize((DBObject) serialisedHw);
CpuHardware hardware = CpuHardware.deserialize((Document) serialisedHw);
hardware.setCpu(cpu);
cpu.attachHardware(hardware, (int) ((BasicDBObject) serialisedHw).get("address"));
cpu.attachHardware(hardware, (int) ((Document) serialisedHw).get("address"));
}
cpu.memory = Memory.deserialize((DBObject) obj.get("memory"));
cpu.registerSet = RegisterSet.deserialize((DBObject) obj.get("registerSet"));
cpu.memory = Memory.deserialize((Document) obj.get("memory"));
cpu.registerSet = RegisterSet.deserialize((Document) obj.get("registerSet"));
return cpu;

View File

@ -1,13 +1,13 @@
package net.simon987.server.assembly;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.io.CpuHardwareDeserializer;
import net.simon987.server.io.MongoSerialisable;
import net.simon987.server.io.MongoSerializable;
import net.simon987.server.plugin.ServerPlugin;
import org.bson.Document;
public abstract class CpuHardware implements MongoSerialisable {
public abstract class CpuHardware implements MongoSerializable {
CPU cpu;
@ -26,7 +26,7 @@ public abstract class CpuHardware implements MongoSerialisable {
public abstract char getId();
public static CpuHardware deserialize(DBObject obj) {
public static CpuHardware deserialize(Document obj) {
for (ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()) {

View File

@ -1,11 +1,10 @@
package net.simon987.server.assembly;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.io.MongoSerialisable;
import net.simon987.server.io.MongoSerializable;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -22,7 +21,7 @@ import java.util.zip.InflaterOutputStream;
/**
* Represents the available memory for a CPU in the game universe
*/
public class Memory implements Target, MongoSerialisable {
public class Memory implements Target, MongoSerializable {
/**
@ -133,9 +132,9 @@ public class Memory implements Target, MongoSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
@ -154,7 +153,7 @@ public class Memory implements Target, MongoSerialisable {
return dbObject;
}
public static Memory deserialize(DBObject obj) {
public static Memory deserialize(Document obj) {
Memory memory = new Memory(0);

View File

@ -1,21 +1,20 @@
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.io.MongoSerializable;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* A set of registers for a CPU
*/
public class RegisterSet implements Target, MongoSerialisable {
public class RegisterSet implements Target, MongoSerializable {
/**
* List of registers
@ -145,10 +144,10 @@ public class RegisterSet implements Target, MongoSerialisable {
@Override
public BasicDBObject mongoSerialise() {
BasicDBList registers = new BasicDBList();
public Document mongoSerialise() {
List<Document> registers = new ArrayList<>();
for (Integer index : this.registers.keySet()) {
JSONObject register = new JSONObject();
Document register = new Document();
register.put("index", index);
register.put("name", getRegister(index).getName());
@ -157,24 +156,24 @@ public class RegisterSet implements Target, MongoSerialisable {
registers.add(register);
}
BasicDBObject obj = new BasicDBObject();
Document obj = new Document();
obj.put("registers", registers);
return obj;
}
public static RegisterSet deserialize(DBObject obj) {
public static RegisterSet deserialize(Document obj) {
RegisterSet registerSet = new RegisterSet();
BasicDBList registers = (BasicDBList) obj.get("registers");
List registers = (ArrayList) obj.get("registers");
for (Object sRegister : registers) {
Register register = new Register((String) ((DBObject) sRegister).get("name"));
register.setValue((int) ((DBObject) sRegister).get("value"));
Register register = new Register((String) ((Document) sRegister).get("name"));
register.setValue((int) ((Document) sRegister).get("value"));
registerSet.registers.put((int) ((DBObject) sRegister).get("index"), register);
registerSet.registers.put((int) ((Document) sRegister).get("index"), register);
}

View File

@ -7,10 +7,11 @@ import net.simon987.server.assembly.Util;
/**
* AND two numbers together, the result is stored in the destination operand
* <p>
* <br>
* AND A, B
* A = A & B
* </p>
* <br>
* {@literal A = A & B @}
* <br>
* FLAGS: OF=0 S=* Z=* X=0
*/
public class AndInstruction extends Instruction {

View File

@ -6,9 +6,9 @@ import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Target;
/**
* Send hardware interupt
* Used to interact with the World using hardware
* </p>
* Send hardware interrupt
* <br>Used to interact with the World using hardware
*
*/
public class HwiInstruction extends Instruction {

View File

@ -6,9 +6,9 @@ import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Target;
/**
* +---------------------+
* | |
* CF < 0<0<0<0<0<0<0<0 <-+
*<br> +---------------------+
*<br> | |
*<br> {@literal CF < 0<0<0<0<0<0<0<0 <-+ @}
*/
public class RclInstruction extends Instruction {

View File

@ -5,9 +5,9 @@ import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Target;
/**
* +---------------------+
* | |
* CF < 0<0<0<0<0<0<0<0 <-+
* <br> +---------------------+
* <br> | |
* <br> {@literal CF < 0<0<0<0<0<0<0<0 <-+ @}
*/
public class RcrInstruction extends Instruction {

View File

@ -5,9 +5,9 @@ import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Target;
/**
* +-----------------+
* | |
* CF < 0<0<0<0<0<0<0<0 <-+
* <br> +-----------------+
* <br> | |
* <br> {@literal CF < 0<0<0<0<0<0<0<0 <-+ @}
*/
public class RolInstruction extends Instruction {

View File

@ -5,9 +5,9 @@ import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Target;
/**
* +-----------------+
* | |
* +-> 0>0>0>0>0>0>0>0 > CF
* <br> +-----------------+
* <br> | |
* <br> {@literal +-> 0>0>0>0>0>0>0>0 > CF @}
*/
public class RorInstruction extends Instruction {

View File

@ -23,10 +23,10 @@ public class RandomStringGenerator {
return new String(buf);
}
public static final String UPPER_ALPHA_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String LOWER_ALPHA_CHARSET = UPPER_ALPHA_CHARSET.toLowerCase(Locale.ROOT);
public static final String NUMERIC_CHARSET = "0123456789";
public static final String ALPHANUMERIC_CHARSET = UPPER_ALPHA_CHARSET + LOWER_ALPHA_CHARSET + NUMERIC_CHARSET;
static final String UPPER_ALPHA_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static final String LOWER_ALPHA_CHARSET = UPPER_ALPHA_CHARSET.toLowerCase(Locale.ROOT);
static final String NUMERIC_CHARSET = "0123456789";
static final String ALPHANUMERIC_CHARSET = UPPER_ALPHA_CHARSET + LOWER_ALPHA_CHARSET + NUMERIC_CHARSET;
private final Random random;

View File

@ -1,8 +1,10 @@
package net.simon987.server.event;
import net.simon987.server.webserver.OnlineUser;
import net.simon987.server.websocket.OnlineUser;
import org.json.simple.JSONObject;
import java.io.IOException;
public class DebugCommandEvent extends GameEvent {
private JSONObject command;
@ -37,7 +39,11 @@ public class DebugCommandEvent extends GameEvent {
response.put("t", "debug");
response.put("message", message);
((OnlineUser) getSource()).getWebSocket().send(response.toJSONString());
try {
((OnlineUser) getSource()).getWebSocket().getRemote().sendString(response.toJSONString());
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -6,7 +6,7 @@ public interface Enterable {
* Called when an object attempts to walk directly into a Enterable object
*
* @param object The game object that attempted to enter
* @return true if successful,
* @return true if successful, false to block the object
*/
boolean enter(GameObject object);

View File

@ -1,11 +1,11 @@
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.io.MongoSerializable;
import net.simon987.server.plugin.ServerPlugin;
import org.bson.Document;
import org.json.simple.JSONObject;
import java.awt.*;
@ -15,7 +15,7 @@ import java.util.ArrayList;
* An INSTANCE of an object (e.g. a Tree, a character ...) inside the
* game universe
*/
public abstract class GameObject implements JSONSerialisable, MongoSerialisable {
public abstract class GameObject implements JSONSerialisable, MongoSerializable {
private boolean dead;
/**
@ -223,8 +223,8 @@ public abstract class GameObject implements JSONSerialisable, MongoSerialisable
return new JSONObject();
}
public static GameObject deserialize(DBObject obj) {
//
public static GameObject deserialize(Document obj) {
for (ServerPlugin plugin : GameServer.INSTANCE.getPluginManager().getPlugins()) {
if (plugin instanceof GameObjectDeserializer) {

View File

@ -1,6 +1,9 @@
package net.simon987.server.game;
import com.mongodb.*;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import net.simon987.server.GameServer;
import net.simon987.server.ServerConfiguration;
import net.simon987.server.assembly.Assembler;
@ -9,6 +12,7 @@ import net.simon987.server.assembly.CPU;
import net.simon987.server.assembly.exception.CancelledException;
import net.simon987.server.logging.LogManager;
import net.simon987.server.user.User;
import org.bson.Document;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
@ -55,13 +59,13 @@ public class GameUniverse {
* @return World, null if not found
*/
private World loadWorld(int x, int y, String dimension) {
DB db = mongo.getDB("mar");
DBCollection worlds = db.getCollection("world");
BasicDBObject whereQuery = new BasicDBObject();
MongoDatabase db = mongo.getDatabase(GameServer.INSTANCE.getConfig().getString("mongo_dbname"));
MongoCollection<Document> worlds = db.getCollection("world");
Document whereQuery = new Document();
whereQuery.put("_id", World.idFromCoordinates(x, y, dimension));
DBCursor cursor = worlds.find(whereQuery);
MongoCursor<Document> cursor = worlds.find(whereQuery).iterator();
if (cursor.hasNext()) {
return World.deserialize(cursor.next());
}

View File

@ -0,0 +1,10 @@
package net.simon987.server.game;
//Alpha: ±5cm
//Beta: 10-20 feet
//Gamma: 100+ feet
public interface Radioactive {
}

View File

@ -1,16 +1,15 @@
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 net.simon987.server.io.MongoSerializable;
import org.bson.Document;
import org.json.simple.JSONObject;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Random;
import java.util.zip.Deflater;
@ -19,7 +18,7 @@ import java.util.zip.DeflaterOutputStream;
/**
* A 2D map of Tile objects of size width*height
*/
public class TileMap implements JSONSerialisable, MongoSerialisable {
public class TileMap implements JSONSerialisable, MongoSerializable {
public static final int VOID = -1;
public static final int PLAIN_TILE = 0;
@ -141,25 +140,34 @@ public class TileMap implements JSONSerialisable, MongoSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
dbObject.put("tiles", tiles);
//Flatten multi-dimensional array
ArrayList<Integer> bsonTiles = new ArrayList<>();
for (int x = 0; x < this.width; x++) {
for (int y = 0; y < this.height; y++) {
bsonTiles.add(tiles[x][y]);
}
}
dbObject.put("tiles", bsonTiles);
return dbObject;
}
public static TileMap deserialize(DBObject object, int size) {
public static TileMap deserialize(Document object, int size) {
BasicDBList terrain = (BasicDBList) object.get("tiles");
ArrayList<Integer> terrain = (ArrayList<Integer>) object.get("tiles");
int[][] tiles = new int[size][size];
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
tiles[x][y] = (int) ((BasicDBList) terrain.get(x)).get(y);
tiles[x][y] = terrain.get(x * size + y);
}
}

View File

@ -1,21 +1,20 @@
package net.simon987.server.game;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import net.simon987.server.GameServer;
import net.simon987.server.event.GameEvent;
import net.simon987.server.event.WorldUpdateEvent;
import net.simon987.server.game.pathfinding.Pathfinder;
import net.simon987.server.io.MongoSerialisable;
import net.simon987.server.io.MongoSerializable;
import org.bson.Document;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
public class World implements MongoSerialisable {
public class World implements MongoSerializable {
/**
* Size of the side of this world
@ -171,17 +170,15 @@ public class World implements MongoSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
BasicDBList objects = new BasicDBList();
List<Document> objects = new ArrayList<>();
for (GameObject obj : gameObjects.values()) {
objects.add(obj.mongoSerialise());
}
dbObject.put("_id", getId());
dbObject.put("dimension", getDimension());
dbObject.put("objects", objects);
@ -214,7 +211,7 @@ public class World implements MongoSerialisable {
}
public static World deserialize(DBObject dbObject) {
public static World deserialize(Document dbObject) {
World world = new World((int) dbObject.get("size"));
world.x = (int) dbObject.get("x");
@ -222,13 +219,13 @@ public class World implements MongoSerialisable {
world.dimension = (String) dbObject.get("dimension");
world.updatable = (int) dbObject.get("updatable");
world.tileMap = TileMap.deserialize((BasicDBObject) dbObject.get("terrain"), world.getWorldSize());
world.tileMap = TileMap.deserialize((Document) dbObject.get("terrain"), world.getWorldSize());
BasicDBList objects = (BasicDBList) dbObject.get("objects");
ArrayList<Document> objects = (ArrayList<Document>) dbObject.get("objects");
for (Object obj : objects) {
GameObject object = GameObject.deserialize((DBObject) obj);
GameObject object = GameObject.deserialize((Document) obj);
object.setWorld(world);
world.addObject(object);

View File

@ -42,5 +42,4 @@ public class HealObjCommandListener implements GameEventListener {
}
}
}
}

View File

@ -0,0 +1,27 @@
package net.simon987.server.game.debug;
import net.simon987.server.GameServer;
import net.simon987.server.event.DebugCommandEvent;
import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventListener;
public class SaveGameCommandListener implements GameEventListener {
@Override
public Class getListenedEventType() {
return DebugCommandEvent.class;
}
@Override
public void handle(GameEvent event) {
DebugCommandEvent e = (DebugCommandEvent) event;
if (e.getName().equals("saveGame")) {
GameServer.INSTANCE.save();
e.reply("Saved the game");
}
}
}

View File

@ -1,13 +1,12 @@
package net.simon987.server.game.debug;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
import net.simon987.server.GameServer;
import net.simon987.server.event.DebugCommandEvent;
import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventListener;
import net.simon987.server.game.GameObject;
import net.simon987.server.game.World;
import org.bson.Document;
import java.util.Arrays;
@ -28,7 +27,7 @@ public class SpawnObjCommandListener implements GameEventListener {
World world = GameServer.INSTANCE.getGameUniverse().getWorld(e.getInt("worldX"), e.getInt("worldY"),
false, e.getString("dimension"));
DBObject dbObj = (DBObject) JSON.parse(e.getString("data"));
Document dbObj = Document.parse(e.getString("data"));
dbObj.put("i", GameServer.INSTANCE.getGameUniverse().getNextObjectId());
GameObject object = GameObject.deserialize(dbObj);

View File

@ -1,10 +1,10 @@
package net.simon987.server.io;
import com.mongodb.DBObject;
import net.simon987.server.assembly.CpuHardware;
import org.bson.Document;
public interface CpuHardwareDeserializer {
CpuHardware deserializeHardware(DBObject hwJson);
CpuHardware deserializeHardware(Document hwJson);
}

View File

@ -1,10 +1,10 @@
package net.simon987.server.io;
import com.mongodb.DBObject;
import net.simon987.server.game.GameObject;
import org.bson.Document;
public interface GameObjectDeserializer {
GameObject deserializeObject(DBObject object);
GameObject deserializeObject(Document object);
}

View File

@ -1,9 +0,0 @@
package net.simon987.server.io;
import com.mongodb.BasicDBObject;
public interface MongoSerialisable {
BasicDBObject mongoSerialise();
}

View File

@ -0,0 +1,9 @@
package net.simon987.server.io;
import org.bson.Document;
public interface MongoSerializable {
Document mongoSerialise();
}

View File

@ -0,0 +1,9 @@
package net.simon987.server.user;
public class RegistrationException extends Exception {
public RegistrationException(String message) {
super(message);
}
}

View File

@ -1,29 +1,33 @@
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;
import net.simon987.server.io.MongoSerializable;
import org.bson.Document;
/**
* Represents a User (or player) of the game
*/
public class User implements MongoSerialisable {
public class User implements MongoSerializable {
private String username;
private String userCode;
private String password;
private String accessToken;
private CPU cpu;
private ControllableUnit controlledUnit;
private boolean guest;
private boolean guest = false;
private boolean moderator = false;
private UserStats stats;
public User() throws CancelledException {
GameEvent event = new UserCreationEvent(this);
@ -32,7 +36,7 @@ public class User implements MongoSerialisable {
throw new CancelledException();
}
this.stats = new UserStats();
}
public User(ControllableUnit unit) {
@ -40,33 +44,38 @@ public class User implements MongoSerialisable {
}
@Override
public BasicDBObject mongoSerialise() {
public Document mongoSerialise() {
BasicDBObject dbObject = new BasicDBObject();
Document dbObject = new Document();
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());
dbObject.put("password", password);
dbObject.put("moderator", moderator);
dbObject.put("stats", stats.mongoSerialise());
return dbObject;
}
public static User deserialize(DBObject obj) throws CancelledException {
public static User deserialize(Document 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.password = (String) obj.get("password");
user.moderator = (boolean) obj.get("moderator");
user.stats = new UserStats((Document) obj.get("stats"));
user.getControlledUnit().setParent(user);
user.cpu = CPU.deserialize((DBObject) obj.get("cpu"), user);
user.cpu = CPU.deserialize((Document) obj.get("cpu"), user);
return user;
}
//----
public String getUserCode() {
return userCode;
@ -107,4 +116,28 @@ public class User implements MongoSerialisable {
public void setGuest(boolean guest) {
this.guest = guest;
}
public void setPassword(String password) {
this.password = password;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public boolean isModerator() {
return moderator;
}
public void setModerator(boolean moderator) {
this.moderator = moderator;
}
public UserStats getStats() {
return stats;
}
}

View File

@ -0,0 +1,161 @@
package net.simon987.server.user;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.exception.CancelledException;
import net.simon987.server.crypto.RandomStringGenerator;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import org.springframework.security.crypto.bcrypt.BCrypt;
import java.util.ArrayList;
public class UserManager {
private MongoCollection<Document> userCollection;
public UserManager(MongoCollection<Document> userCollection) {
this.userCollection = userCollection;
}
/**
* Get and deserialise all users from mongo
*
* @return list of de-serialized users
*/
public ArrayList<User> getUsers() {
ArrayList<User> userList = new ArrayList<>();
MongoCursor<Document> cursor = userCollection.find().iterator();
while (cursor.hasNext()) {
try {
userList.add(User.deserialize(cursor.next()));
} catch (CancelledException e) {
e.printStackTrace();
}
}
return userList;
}
/**
* Register an user and initialises its controlled unit
* @param username username
* @param password plain password
* @throws RegistrationException is username/password length is invalid
*/
public void registerUser(String username, String password) throws RegistrationException {
if (username.length() < 5 || username.length() > 20) {
throw new RegistrationException("Username must be 5-20 characters");
}
if (password.length() < 8 || password.length() > 96) {
throw new RegistrationException("Password must be 8-96 characters");
}
//Check if exists
Document where = new Document();
where.put("_id", username);
if (userCollection.find(where).first() != null) {
throw new RegistrationException("Username is already in use");
}
try {
User user = GameServer.INSTANCE.getGameUniverse().getOrCreateUser(username, true);
user.setUsername(username);
String salt = BCrypt.gensalt();
String hashedPassword = BCrypt.hashpw(password, salt);
user.setPassword(hashedPassword);
Document dbUser = user.mongoSerialise();
userCollection.insertOne(dbUser);
} catch (Exception e) {
throw new RegistrationException("An exception occurred while trying to create user: " + e.getMessage());
}
}
/**
* Validate a username/password combo
* @param username username
* @param password plain password
* @return true if combo is valid
*/
public boolean validateUser(String username, String password) {
Document where = new Document();
where.put("_id", username);
Document user = userCollection.find(where).first();
return user != null && BCrypt.checkpw(password, (String) user.get("password"));
}
/**
* Change the password of an user and immediately save it
* @param username Username
* @param newPassword New plain password
* @throws RegistrationException When password length is invalid
*/
public void changePassword(String username, String newPassword) throws RegistrationException {
if (newPassword.length() < 8 || newPassword.length() > 96) {
throw new RegistrationException("Password must be 8-96 characters");
}
User user = GameServer.INSTANCE.getGameUniverse().getUser(username);
String salt = BCrypt.gensalt();
String hashedPassword = BCrypt.hashpw(newPassword, salt);
user.setPassword(hashedPassword);
userCollection.replaceOne(new Document("_id", username), user.mongoSerialise()); //Save new password immediately
}
/**
* Generate and save a access token for websocket auth
*
* @param username Username
* @return The generated token
*/
public String generateAndGetToken(String username) {
User user = GameServer.INSTANCE.getGameUniverse().getUser(username);
if (user == null) {
return null;
}
RandomStringGenerator generator = new RandomStringGenerator(128);
String token = generator.nextString();
user.setAccessToken(token); //Token is not saved in DB, and is erased when used
LogManager.LOGGER.fine("(Web) Generated access token for " + username);
return token;
}
/**
* Validate an access token sent by the client
* @param token 128-char accesss token
* @return username of the corresponding user, null if not found
*/
public User validateAuthToken(String token) {
for (User user : GameServer.INSTANCE.getGameUniverse().getUsers()) {
if (user.getAccessToken() != null && user.getAccessToken().equals(token)) {
user.setAccessToken(""); //Token is erased when used
return user;
}
}
return null;
}
}

View File

@ -0,0 +1,102 @@
package net.simon987.server.user;
import net.simon987.server.io.MongoSerializable;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import java.util.ArrayList;
public class UserStats implements MongoSerializable {
private Document stats;
UserStats() {
this.stats = new Document();
}
UserStats(Document stats) {
if (stats != null) {
this.stats = stats;
} else {
this.stats = new Document();
}
}
@Override
public Document mongoSerialise() {
return stats;
}
/**
* Increment a stat n times
*
* @param name Name of the stat to increment
* @param count Number of time to increment
*/
public void incrementStat(String name, int count) {
stats.putIfAbsent(name, 0);
stats.put(name, stats.getInteger(name) + count);
}
/**
* Set the value of a stat
*
* @param name Name of the stat
* @param value new value
*/
public void setInt(String name, int value) {
stats.put(name, value);
}
/**
* Get the value of at stat
*
* @param name Name of the value
* @return The value of the stat. Returns 0 if not found
*/
public int getInt(String name) {
return stats.getInteger(name, 0);
}
/**
* Add an string item to a set
*
* @param name Name of the stat
* @param value Value to add to the set
*/
public void addToStringSet(String name, String value) {
stats.putIfAbsent(name, new ArrayList<>());
try {
((ArrayList<String>) stats.get(name)).add(value);
} catch (ClassCastException e) {
LogManager.LOGGER.severe("UserStats: cannot add to list because stat already exists and is not a list");
}
}
/**
* Remove an item from a set
*
* @param name Name of the stat
* @param value Value to remove from the set
* @return true if the list contained the item
*/
public boolean removeFromSet(String name, String value) {
if (stats.putIfAbsent(name, new ArrayList()) != null) {
return ((ArrayList) stats.get(name)).remove(value);
}
return false;
}
public ArrayList getSet(String name) {
stats.putIfAbsent(name, new ArrayList());
return (ArrayList) stats.get(name);
}
}

View File

@ -0,0 +1,83 @@
package net.simon987.server.user;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import net.simon987.server.GameServer;
import org.bson.Document;
import java.util.*;
/**
* Retrieve user stats in a structured fashion
*/
public class UserStatsHelper {
/**
* Database collection of users
*/
private MongoCollection<Document> users;
/**
* @param users Database collection of users
*/
public UserStatsHelper(MongoCollection<Document> users) {
this.users = users;
}
/**
* Get top n players along with their stat value, in descending order
*
* @param statName Name of the stat
* @param n Maximum number of players
* @return Top n players, in User,value format, in descending order
*/
public ArrayList<Map.Entry<User, Integer>> getTopN(String statName, int n) {
ArrayList<Map.Entry<User, Integer>> rows = new ArrayList<>();
Document orderBy = new Document("$stats." + statName, -1);
MongoCursor<Document> cursor = users.find().sort(orderBy).limit(n).iterator();
while (cursor.hasNext()) {
Document dbUser = cursor.next();
User user = GameServer.INSTANCE.getGameUniverse().getUser((String) dbUser.get("username"));
rows.add(new AbstractMap.SimpleEntry<>(user, user.getStats().getInt(statName)));
}
return rows;
}
/**
* Get top n players along with the stat set, in descending order
*
* @param statName Name of the stat
* @param n Maximum number of players
* @return Top n players, in User,set format, in descending order
*/
public ArrayList<Map.Entry<User, ArrayList>> getTopNSetLength(String statName, int n) {
ArrayList<Map.Entry<User, ArrayList>> rows = new ArrayList<>();
List<Object> ifNullList = new ArrayList<>(2);
ifNullList.add("$stats." + statName);
ifNullList.add(new ArrayList());
Document project = new Document();
project.put("setLength", new Document("$size", new Document("$ifNull", ifNullList)));
project.put("username", 1);
Iterator<Document> results = users.aggregate(Arrays.asList(
new Document("$project", project),
new Document("$sort", new Document("setLength", -1)),
new Document("$limit", n))
).iterator();
while (results.hasNext()) {
User user = GameServer.INSTANCE.getGameUniverse().getUser((String) results.next().get("username"));
rows.add(new AbstractMap.SimpleEntry<>(user, user.getStats().getSet(statName)));
}
return rows;
}
}

View File

@ -0,0 +1,25 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.TemplateViewRoute;
import java.util.HashMap;
import java.util.Map;
public class AccountPage implements TemplateViewRoute {
@Override
public ModelAndView handle(Request request, Response response) {
Map<String, Object> model = new HashMap<>();
model.put("session", request.session());
if (request.session().attribute("username") != null) {
model.put("user", GameServer.INSTANCE.getGameUniverse().getUser(request.session().attribute("username")));
}
return new ModelAndView(model, "account.vm");
}
}

View File

@ -0,0 +1,20 @@
package net.simon987.server.web;
public class AlertMessage {
private String message;
private AlertType type;
public AlertMessage(String message, AlertType type) {
this.message = message;
this.type = type;
}
public String getMessage() {
return message;
}
public AlertType getType() {
return type;
}
}

View File

@ -0,0 +1,23 @@
package net.simon987.server.web;
public enum AlertType {
SUCCESS("alert-success"),
INFO("alert-info"),
WARNING("alert-info"),
DANGER("alert-danger"),
PRIMARY("alert-primary"),
SECONDARY("alert-secondary"),
DARK("alert-dark");
public String name;
AlertType(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}

View File

@ -0,0 +1,44 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import net.simon987.server.user.RegistrationException;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.Route;
public class ChangePasswordRoute implements Route {
@Override
public ModelAndView handle(Request request, Response response) {
String username = request.session().attribute("username");
String currentPassword = request.queryParams("password");
String newPassword = request.queryParams("new_password");
String newPasswordRepeat = request.queryParams("new_password_repeat");
if (newPassword.equals(newPasswordRepeat)) {
if (username != null && GameServer.INSTANCE.getUserManager().validateUser(username, currentPassword)) {
try {
GameServer.INSTANCE.getUserManager().changePassword(username, newPassword);
AlertMessage[] messages = {new AlertMessage("Changed password", AlertType.SUCCESS)};
request.session().attribute("messages", messages);
} catch (RegistrationException e) {
AlertMessage[] messages = {new AlertMessage(e.getMessage(), AlertType.DANGER)};
request.session().attribute("messages", messages);
}
} else {
AlertMessage[] messages = {new AlertMessage("Invalid password", AlertType.DANGER)};
request.session().attribute("messages", messages);
}
} else {
AlertMessage[] messages = {new AlertMessage("Passwords did not match", AlertType.DANGER)};
request.session().attribute("messages", messages);
}
response.redirect("/account");
return null;
}
}

View File

@ -0,0 +1,36 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import net.simon987.server.logging.LogManager;
import spark.Request;
import spark.Response;
import spark.Route;
public class FloppyDownloadRoute implements Route {
@Override
public Object handle(Request request, Response response) {
String username = request.session().attribute("username");
if (username != null) {
response.header("Content-Type", "application/octet-stream");
response.header("Content-Disposition", "filename=\"floppy.bin\"");
try {
return GameServer.INSTANCE.getGameUniverse().getUser(username).getControlledUnit().getFloppyData().getBytes();
} catch (Exception e) {
String message = "Encountered exception while reading floppy data: " + e.getMessage();
LogManager.LOGGER.severe(message);
return message;
}
} else {
response.status(403);
return "Not logged in";
}
}
}

View File

@ -0,0 +1,67 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import net.simon987.server.logging.LogManager;
import spark.Request;
import spark.Response;
import spark.Route;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.InputStream;
public class FloppyUploadRoute implements Route {
@Override
public Object handle(Request request, Response response) {
String username = request.session().attribute("username");
if (username != null) {
try {
request.attribute("org.eclipse.jetty.multipartConfig",
new MultipartConfigElement("/tmp_floppy", 1474560L, -1L, 0));
try (InputStream is = request.raw().getPart("floppyData").getInputStream()) {
if (is.available() == 1474560) {
byte[] bytes = new byte[1474560];
int bytesRead = is.read(bytes);
if (bytesRead == 1474560) {
try {
GameServer.INSTANCE.getGameUniverse().getUser(username).getControlledUnit().getFloppyData().setBytes(bytes);
return "ok";
} catch (Exception e) {
String message = "Encountered exception while writing floppy data: " + e.getMessage();
LogManager.LOGGER.severe(message);
return message;
}
} else {
return "Couldn't read floppy file";
}
} else {
return "File size must be 1474560 bytes";
}
} catch (IOException | ServletException e) {
e.printStackTrace();
return "Error reading floppy file: " + e.getMessage();
}
} catch (IllegalStateException e) {
return "File exceeds maximum size";
}
} else {
response.status(403);
return "Not logged in";
}
}
}

View File

@ -0,0 +1,21 @@
package net.simon987.server.web;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.TemplateViewRoute;
import java.util.HashMap;
import java.util.Map;
public class HomePage implements TemplateViewRoute {
@Override
public ModelAndView handle(Request request, Response response) throws Exception {
Map<String, Object> model = new HashMap<>(1);
model.put("session", request.session());
return new ModelAndView(model, "home.vm");
}
}

View File

@ -0,0 +1,21 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.TemplateViewRoute;
import java.util.HashMap;
import java.util.Map;
public class LeaderBoardPage implements TemplateViewRoute {
@Override
public ModelAndView handle(Request request, Response response) {
Map<String, Object> model = new HashMap<>(2);
model.put("session", request.session());
model.put("stats", GameServer.INSTANCE.getUserStatsHelper().getTopNSetLength("completedVaults", 25));
return new ModelAndView(model, "leaderboard.vm");
}
}

View File

@ -0,0 +1,32 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import net.simon987.server.logging.LogManager;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.Route;
public class LoginRoute implements Route {
@Override
public ModelAndView handle(Request request, Response response) {
String username = request.queryParams("username");
String password = request.queryParams("password");
if (username != null && password != null) {
if (GameServer.INSTANCE.getUserManager().validateUser(username, password)) {
AlertMessage[] messages = {new AlertMessage("Logged in as " + username, AlertType.SUCCESS)};
request.session().attribute("messages", messages);
request.session().attribute("username", username);
LogManager.LOGGER.fine("(Web) " + username + " logged in");
} else {
AlertMessage[] messages = {new AlertMessage("Invalid username or password", AlertType.DANGER)};
request.session().attribute("messages", messages);
}
}
response.redirect("/account");
return null;
}
}

View File

@ -0,0 +1,18 @@
package net.simon987.server.web;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.Route;
public class LogoutRoute implements Route {
@Override
public ModelAndView handle(Request request, Response response) {
AlertMessage[] messages = {new AlertMessage("Logged out", AlertType.INFO)};
request.session().attribute("messages", messages);
request.session().removeAttribute("username");
response.redirect("/account");
return null;
}
}

View File

@ -0,0 +1,20 @@
package net.simon987.server.web;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.TemplateViewRoute;
import java.util.HashMap;
import java.util.Map;
public class PlayPage implements TemplateViewRoute {
@Override
public ModelAndView handle(Request request, Response response) {
Map<String, Object> model = new HashMap<>(1);
model.put("session", request.session());
return new ModelAndView(model, "play.vm");
}
}

View File

@ -0,0 +1,36 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import net.simon987.server.logging.LogManager;
import net.simon987.server.user.RegistrationException;
import spark.ModelAndView;
import spark.Request;
import spark.Response;
import spark.Route;
public class RegisterRoute implements Route {
@Override
public ModelAndView handle(Request request, Response response) {
String username = request.queryParams("username");
String password = request.queryParams("password");
if (username != null && password != null) {
try {
GameServer.INSTANCE.getUserManager().registerUser(username, password);
AlertMessage[] messages = {new AlertMessage("Successfully registered", AlertType.SUCCESS)};
request.session().attribute("messages", messages);
request.session().attribute("username", username);
LogManager.LOGGER.fine("(Web) " + username + " registered " + request.ip());
} catch (RegistrationException e) {
AlertMessage[] messages = {new AlertMessage(e.getMessage(), AlertType.DANGER)};
request.session().attribute("messages", messages);
}
}
response.redirect("/account");
return null;
}
}

View File

@ -0,0 +1,64 @@
package net.simon987.server.web;
import net.simon987.server.GameServer;
import org.json.simple.JSONObject;
import spark.Request;
import spark.Response;
import spark.Route;
public class ServerInfoRoute implements Route {
private String address;
private String serverName;
private int tickLength;
public ServerInfoRoute() {
//Info variables that don't change
if (GameServer.INSTANCE.getConfig().getInt("use_ssl") == 0) {
address = "ws://" +
GameServer.INSTANCE.getConfig().getString("mar_address") + ":" +
GameServer.INSTANCE.getConfig().getString("mar_port") + "/socket";
} else {
address = "wss://" +
GameServer.INSTANCE.getConfig().getString("mar_address") + ":" +
GameServer.INSTANCE.getConfig().getString("mar_port") + "/socket";
}
serverName = GameServer.INSTANCE.getConfig().getString("server_name");
tickLength = GameServer.INSTANCE.getConfig().getInt("tick_length");
}
@Override
public Object handle(Request request, Response response) {
JSONObject json = new JSONObject();
String username = request.session().attribute("username");
if (username != null) {
String token = GameServer.INSTANCE.getUserManager().generateAndGetToken(username);
json.put("token", token);
json.put("username", username);
} else {
json.put("token",
"00000000000000000000000000000000" +
"00000000000000000000000000000000" +
"00000000000000000000000000000000" +
"00000000000000000000000000000000");
json.put("username", "guest");
}
json.put("address", address);
json.put("serverName", serverName);
json.put("tickLength", tickLength);
response.header("Content-Type", "application/json");
return json.toJSONString();
}
}

View File

@ -0,0 +1,63 @@
package net.simon987.server.web;
import net.simon987.server.ServerConfiguration;
import net.simon987.server.logging.LogManager;
import net.simon987.server.websocket.SocketServer;
import org.apache.velocity.app.VelocityEngine;
import spark.Spark;
import spark.template.velocity.VelocityTemplateEngine;
import java.util.Properties;
public class WebServer {
private SocketServer socketServer;
public WebServer(ServerConfiguration config) {
//Velocity config
Properties properties = new Properties();
properties.setProperty("file.resource.loader.path", "templates/");
VelocityTemplateEngine templateEngine = new VelocityTemplateEngine(new VelocityEngine(properties));
Spark.staticFiles.externalLocation("static");
//Spark config
if (config.getInt("use_ssl") != 0) {
/*
* Generate keystore from Let's Encrypt with command:
* openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.jks -name muchassemblyrequired -CAfile chain.pem -caname root -password file:password.txt
*
* Certificates generated from Let's Encrypt are usually in /etc/letsencrypt/live/www.site.com
*/
Spark.secure(
config.getString("keyStore_path"),
config.getString("keyStore_password"), null, null);
LogManager.LOGGER.info("(Web) Enabled ssl");
}
socketServer = new SocketServer();
Spark.webSocket("/socket", socketServer);
Spark.get("/", new HomePage(), templateEngine);
Spark.get("/leaderboard", new LeaderBoardPage(), templateEngine);
Spark.get("/play", new PlayPage(), templateEngine);
Spark.get("/account", new AccountPage(), templateEngine);
Spark.post("/register", new RegisterRoute());
Spark.post("/login", new LoginRoute());
Spark.get("/logout", new LogoutRoute());
Spark.post("/change_password", new ChangePasswordRoute());
Spark.get("/server_info", new ServerInfoRoute());
Spark.post("/floppy_upload", new FloppyUploadRoute());
Spark.get("/floppy_download", new FloppyDownloadRoute());
Spark.after((request, response) -> response.header("Content-Encoding", "gzip"));
}
public SocketServer getSocketServer() {
return socketServer;
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}

View File

@ -1,323 +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 MessageDispatcher messageDispatcher = new MessageDispatcher();
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);
messageDispatcher.addHandler(new UserInfoRequestHandler());
messageDispatcher.addHandler(new TerrainRequestHandler());
messageDispatcher.addHandler(new ObjectsRequestHandler());
messageDispatcher.addHandler(new CodeUploadHandler());
messageDispatcher.addHandler(new CodeRequestHandler());
messageDispatcher.addHandler(new KeypressHandler());
messageDispatcher.addHandler(new FloppyHandler());
messageDispatcher.addHandler(new DebugCommandHandler());
}
@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()) {
messageDispatcher.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);
onlineUser.setModerator(database.isModerator(username));
LogManager.LOGGER.info("(WS) User was successfully authenticated: " + user.getUsername() +
" moderator: " + onlineUser.isModerator());
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;
}
}

View File

@ -1,24 +1,26 @@
package net.simon987.server.webserver;
package net.simon987.server.websocket;
import net.simon987.server.logging.LogManager;
import org.json.simple.JSONObject;
import java.io.IOException;
public class CodeRequestHandler implements MessageHandler {
@Override
public void handle(OnlineUser user, JSONObject json) {
public void handle(OnlineUser user, JSONObject json) throws IOException {
if (json.get("t").equals("codeRequest")) {
LogManager.LOGGER.fine("(WS) Code request from " + user.getUser().getUsername());
if (user.isGuest()) {
if (user.getUser().isGuest()) {
JSONObject response = new JSONObject();
response.put("t", "code");
response.put("code", "; Create a free account to control your own Cubot with assembly language!"); //todo load from config
user.getWebSocket().send(response.toJSONString());
user.getWebSocket().getRemote().sendString(response.toJSONString());
} else {
@ -27,7 +29,7 @@ public class CodeRequestHandler implements MessageHandler {
response.put("t", "code");
response.put("code", user.getUser().getUserCode());
user.getWebSocket().send(response.toJSONString());
user.getWebSocket().getRemote().sendString(response.toJSONString());
}

Some files were not shown because too many files have changed in this diff Show More