Fixed some debug commands. Added blueprint item deserialization, Added inventory SCAN and SEEK actions

This commit is contained in:
Simon
2018-12-06 11:13:06 -05:00
parent 71e88afdc9
commit 5de909cd9c
28 changed files with 798 additions and 253 deletions

View File

@@ -0,0 +1,111 @@
package net.simon987.constructionplugin;
import net.simon987.server.game.item.Item;
import net.simon987.server.game.objects.GameObject;
import net.simon987.server.game.objects.InventoryHolder;
import net.simon987.server.io.JSONSerializable;
import net.simon987.server.io.MongoSerializable;
import org.bson.Document;
import org.json.simple.JSONObject;
import java.util.HashMap;
import java.util.Map;
public abstract class BluePrint implements InventoryHolder, JSONSerializable, MongoSerializable {
/**
* Map of items id and required amount
* <br>The amount is decremented as the items are added
*/
protected Map<Integer, Integer> requiredItems;
/**
* This object will be instantiated when completed
*/
protected Class<? extends GameObject> targetObject;
/**
* Set to true when all the requirements are met
*/
private boolean completed;
public BluePrint() {
requiredItems = new HashMap<>();
}
public BluePrint(Document document) {
requiredItems = (Map<Integer, Integer>) document.get("required_items");
completed = document.getBoolean("completed");
try {
targetObject = Class.forName(document.getString("target")).asSubclass(GameObject.class);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void checkCompleted() {
for (Integer remaining : requiredItems.values()) {
if (remaining > 0) {
return;
}
}
completed = true;
}
@Override
public boolean placeItem(Item item) {
if (requiredItems.containsKey(item.getId()) && requiredItems.get(item.getId()) > 0) {
requiredItems.put(item.getId(), requiredItems.get(item.getId()) - 1);
checkCompleted();
return true;
}
return false;
}
@Override
public void takeItem(int itemId) {
}
@Override
public boolean canTakeItem(int itemId) {
return false;
}
public boolean isCompleted() {
return completed;
}
public Class<? extends GameObject> getTargetObject() {
return targetObject;
}
@Override
public JSONObject debugJsonSerialise() {
return jsonSerialise();
}
@Override
public JSONObject jsonSerialise() {
JSONObject json = new JSONObject();
json.put("target", targetObject);
json.put("required_items", requiredItems);
return json;
}
@Override
public Document mongoSerialise() {
Document document = new Document();
document.put("completed", completed);
document.put("target", targetObject);
document.put("required_items", requiredItems);
return document;
}
}

View File

@@ -0,0 +1,61 @@
package net.simon987.constructionplugin;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class BluePrintRegistry {
public static final BluePrintRegistry INSTANCE = new BluePrintRegistry();
private Map<String, Class<? extends BluePrint>> blueprints;
private Map<String, String> digitizedBlueprints;
private BluePrintRegistry() {
blueprints = new HashMap<>();
digitizedBlueprints = new HashMap<>();
}
public void registerBluePrint(Class<? extends BluePrint> clazz) {
blueprints.put(clazz.getCanonicalName(), clazz);
String bpData = new String(BluePrintUtil.bluePrintData(clazz));
digitizedBlueprints.put(bpData, clazz.getCanonicalName());
}
public BluePrint deserializeBlueprint(Document document) {
String type = document.getString("type");
if (blueprints.containsKey(type)) {
try {
return blueprints.get(type).getConstructor(Document.class).newInstance(document);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
LogManager.LOGGER.severe("(Construction Plugin) Error while trying to deserialize object of type " + type + ": " + e.getTargetException().getMessage());
LogManager.LOGGER.severe(document.toJson());
e.getTargetException().printStackTrace();
return null;
}
} else {
LogManager.LOGGER.severe("(Construction Plugin) Trying to deserialize unknown BluePrint type: " + type);
return null;
}
}
public BluePrint deserializeBluePrint(char[] chars) {
String bpData = new String(chars);
if (digitizedBlueprints.containsKey(bpData)) {
return deserializeBlueprint(new Document("type", digitizedBlueprints.get(bpData)));
}
return null;
}
}

View File

@@ -0,0 +1,66 @@
package net.simon987.constructionplugin;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
class BluePrintUtil {
private static byte[] secretKey;
private static final String SHA512 = "SHA-512";
//We need 1024 chars = 2048 bytes = 32 values
private static final char[] ARBITRARY_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456".toCharArray();
static void setSecretKey(String secretKey) {
BluePrintUtil.secretKey = secretKey.getBytes(StandardCharsets.UTF_8);
}
/**
* Hash a message using SHA512 with the server secret key as the sal
*
* @return 128-bit char array
*/
private static char[] hashMessage(String message) {
try {
MessageDigest md = MessageDigest.getInstance(SHA512);
md.update(secretKey);
md.update(message.getBytes(StandardCharsets.UTF_8));
byte[] digest = md.digest();
char[] chars = new char[digest.length / 2];
ByteBuffer.wrap(digest).order(ByteOrder.BIG_ENDIAN).asCharBuffer().get(chars);
return chars;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* Returns a char array representation of a blueprint. It is obtained by hashing the blueprint
* properties with the server secret key. Some arbitrary values are added to make a 1024-char
* array. The same blueprint and secret key always gives the same result.
*/
static char[] bluePrintData(Class<? extends BluePrint> blueprint) {
char[] result = new char[ARBITRARY_STRING.length * 32];
for (int i = ARBITRARY_STRING.length - 1; i > 0; --i) {
char[] hashedBlueprint = hashMessage(ARBITRARY_STRING[i] + blueprint.getName());
if (hashedBlueprint != null) {
System.arraycopy(hashedBlueprint, 0, result,
i * hashedBlueprint.length, hashedBlueprint.length);
}
}
return result;
}
}

View File

@@ -1,12 +1,24 @@
package net.simon987.constructionplugin;
import net.simon987.server.ServerConfiguration;
import net.simon987.server.GameServer;
import net.simon987.server.game.objects.GameRegistry;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.ServerPlugin;
public class ConstructionPlugin extends ServerPlugin {
@Override
public void init(ServerConfiguration config, GameRegistry gameRegistry) {
@Override
public void init(GameServer gameServer) {
BluePrintUtil.setSecretKey(gameServer.getSecretKey());
GameRegistry gameRegistry = gameServer.getRegistry();
gameRegistry.registerItem(ItemBluePrint.ID, ItemBluePrint.class);
gameRegistry.registerGameObject(Obstacle.class);
gameRegistry.registerGameObject(ConstructionSite.class);
BluePrintRegistry.INSTANCE.registerBluePrint(ObstacleBlueprint.class);
LogManager.LOGGER.info("(Construction Plugin) Initialized construction plugin");
}
}

View File

@@ -2,16 +2,33 @@ package net.simon987.constructionplugin;
import net.simon987.server.GameServer;
import net.simon987.server.game.item.Item;
import net.simon987.server.game.objects.GameObject;
import net.simon987.server.game.objects.InventoryHolder;
import net.simon987.server.game.objects.Structure;
import net.simon987.server.game.objects.Updatable;
import org.bson.Document;
import org.json.simple.JSONObject;
public class ConstructionSite extends GameObject implements Updatable, InventoryHolder {
public class ConstructionSite extends Structure implements Updatable, InventoryHolder {
public static final int MAP_INFO = 0xFFFF; //TODO: determine
public static final int LIFETIME = GameServer.INSTANCE.getConfig().getInt("construction_site_ttl");
private int age;
private BluePrint bluePrint;
public ConstructionSite(BluePrint bluePrint) {
super(1, 1);
this.bluePrint = bluePrint;
this.age = 0;
}
public ConstructionSite(Document document) {
super(document, 1, 1);
age = document.getInteger("age");
bluePrint = BluePrintRegistry.INSTANCE.deserializeBlueprint((Document) document.get("blueprint"));
}
@Override
public char getMapInfo() {
@@ -30,11 +47,7 @@ public class ConstructionSite extends GameObject implements Updatable, Inventory
@Override
public boolean placeItem(Item item) {
//todo: add mats here
//todo: inv digitize
return false;
return bluePrint.placeItem(item);
}
@Override
@@ -46,4 +59,24 @@ public class ConstructionSite extends GameObject implements Updatable, Inventory
public boolean canTakeItem(int itemId) {
return false;
}
@Override
public JSONObject jsonSerialise() {
JSONObject json = super.jsonSerialise();
json.put("blueprint", bluePrint.jsonSerialise());
json.put("age", age);
return json;
}
@Override
public Document mongoSerialise() {
Document document = super.mongoSerialise();
document.put("blueprint", bluePrint.mongoSerialise());
document.put("age", age);
return document;
}
}

View File

@@ -0,0 +1,58 @@
package net.simon987.constructionplugin;
import net.simon987.server.assembly.Memory;
import net.simon987.server.game.item.Item;
import org.bson.Document;
import org.json.simple.JSONObject;
public class ItemBluePrint extends Item {
public static final int ID = 0x0005;
private Class<? extends BluePrint> bluePrint;
public ItemBluePrint() {
super(null);
}
public ItemBluePrint(Document document) {
super(document);
try {
bluePrint = Class.forName(document.getString("blueprint")).asSubclass(BluePrint.class);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void digitize(Memory memory, int offset) {
char[] data = BluePrintUtil.bluePrintData(bluePrint);
memory.write(offset, data, 0, data.length);
System.out.println("DEBUG: blueprint digitize " + data.length);
}
@Override
public char poll() {
return ID;
}
@Override
public int getId() {
return ID;
}
@Override
public JSONObject debugJsonSerialise() {
JSONObject json = super.debugJsonSerialise();
json.put("blueprint", bluePrint.getCanonicalName());
return json;
}
@Override
public Document mongoSerialise() {
Document document = super.mongoSerialise();
document.put("blueprint", bluePrint.getCanonicalName());
return document;
}
}

View File

@@ -0,0 +1,104 @@
package net.simon987.constructionplugin;
import net.simon987.server.GameServer;
import net.simon987.server.game.objects.Attackable;
import net.simon987.server.game.objects.Structure;
import net.simon987.server.game.objects.Updatable;
import org.bson.Document;
import org.json.simple.JSONObject;
public class Obstacle extends Structure implements Attackable, Updatable {
public static final int MAP_INFO = 0x0601;
private static final int HEAL_RATE = GameServer.INSTANCE.getConfig().getInt("obstacle_regen");
private static final int MAX_HP = GameServer.INSTANCE.getConfig().getInt("obstacle_hp");
private int hp;
private int color;
public Obstacle() {
super(1, 1);
}
public Obstacle(Document document) {
super(document, 1, 1);
hp = document.getInteger(hp);
color = document.getInteger(color);
}
@Override
public void update() {
heal(HEAL_RATE);
}
@Override
public void setHealRate(int hp) {
}
@Override
public int getHp() {
return hp;
}
@Override
public void setHp(int hp) {
this.hp = hp;
}
@Override
public int getMaxHp() {
return MAX_HP;
}
@Override
public void setMaxHp(int hp) {
}
@Override
public void heal(int amount) {
hp = Math.min(getMaxHp(), hp + amount);
}
@Override
public void damage(int amount) {
hp -= amount;
if (hp < 0) {
setDead(true);
}
}
@Override
public char getMapInfo() {
return MAP_INFO;
}
@Override
public Document mongoSerialise() {
Document document = super.mongoSerialise();
document.put("hp", hp);
document.put("color", hp);
return document;
}
@Override
public JSONObject debugJsonSerialise() {
return jsonSerialise();
}
@Override
public JSONObject jsonSerialise() {
JSONObject json = super.jsonSerialise();
json.put("hp", hp);
json.put("color", hp);
return json;
}
}

View File

@@ -0,0 +1,19 @@
package net.simon987.constructionplugin;
import net.simon987.server.game.item.ItemIron;
import org.bson.Document;
public class ObstacleBlueprint extends BluePrint {
public ObstacleBlueprint() {
super();
this.requiredItems.put(ItemIron.ID, 2); //TODO: load from config?
this.targetObject = Obstacle.class;
}
public ObstacleBlueprint(Document document) {
this.requiredItems.put(ItemIron.ID, 2); //TODO: load from config?
this.targetObject = Obstacle.class;
}
}