From 94b8ef53958559a8a725f297cffae53446a9e093 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 21 Dec 2018 14:00:18 -0500 Subject: [PATCH 1/6] NPC Plugin rewrite. Plugin-level data can be stored in DB --- .../simon987/cubotplugin/CubotComPort.java | 2 +- .../java/net/simon987/npcplugin/Factory.java | 87 ++----- .../net/simon987/npcplugin/HarvesterNPC.java | 6 +- .../npcplugin/NonPlayerCharacter.java | 32 ++- .../net/simon987/npcplugin/NpcPlugin.java | 37 ++- .../npcplugin/RadioReceiverHardware.java | 13 +- .../net/simon987/npcplugin/RadioTower.java | 1 - .../net/simon987/npcplugin/Settlement.java | 219 ++++++++++++++++++ .../simon987/npcplugin/VaultDimension.java | 2 +- .../event/WorldCreationListener.java | 113 +-------- .../simon987/biomassplugin/WorldUtils.java | 3 - .../event/ObjectDeathListener.java | 3 - .../java/net/simon987/server/GameServer.java | 17 +- .../simon987/server/game/GameUniverse.java | 8 + .../server/game/objects/GameObject.java | 16 +- .../simon987/server/game/world/TileMap.java | 13 +- .../net/simon987/server/game/world/World.java | 18 +- .../game/world/WorldGenerationException.java | 7 + .../server/game/world/WorldGenerator.java | 10 +- .../simon987/server/plugin/PluginManager.java | 4 + .../simon987/server/plugin/ServerPlugin.java | 23 +- Server/src/main/resources/config.properties | 2 +- 22 files changed, 391 insertions(+), 245 deletions(-) create mode 100644 Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java create mode 100644 Server/src/main/java/net/simon987/server/game/world/WorldGenerationException.java diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java index a281dd7..c0eb4e6 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java @@ -67,7 +67,7 @@ public class CubotComPort extends CubotHardwareModule { } else if (a == COMPORT_FRONT_PORT_OUT) { - if (cubot.spendEnergy(20)) { + if (cubot.spendEnergy(5)) { //Get object directly in front of the Cubot Point frontTile = cubot.getFrontTile(); //Todo will have to add getGameObjectsBlockingAt to enable Factory diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java index 5827ccc..0d82c14 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java @@ -7,8 +7,6 @@ import org.bson.Document; import org.bson.types.ObjectId; import java.awt.*; -import java.util.ArrayList; -import java.util.List; /** * Game objects that regularly creates NonPlayerCharacters @@ -27,35 +25,17 @@ public class Factory extends Structure implements Updatable { */ private static final int NPC_CREATION_COOLDOWN = NonPlayerCharacter.LIFETIME / MAX_NPC_COUNT; - /** - * List of associated NonPlayerCharacters - */ - private ArrayList npcs = new ArrayList<>(); - /** * Number of ticks to wait until the Factory can spawn a new NPC */ private int cooldown = 0; - /** - * Temporary NPC objectId array. The Factory links the NPCs to itself when initialised, - * at the first call of update(). - */ - private Object[] tmpNpcArray = new Object[0]; - - /** - * Factory are uninitialised until the first update() call - */ - private boolean initialised = false; - public Factory() { super(2, 2); } public Factory(Document document) { super(document, 2, 2); - - tmpNpcArray = ((ArrayList) document.get("npcs")).toArray(); } @Override @@ -70,66 +50,29 @@ public class Factory extends Structure implements Updatable { @Override public void update() { - if (!initialised) { + Settlement settlement = NpcPlugin.settlementMap.get(getWorld().getId()); - initialised = true; + if (cooldown == 0) { + if (settlement.getNpcs().size() < MAX_NPC_COUNT) { + Point p = getAdjacentTile(); - for (Object id : tmpNpcArray) { + if (p != null) { + NonPlayerCharacter npc = new HarvesterNPC(); + npc.setWorld(getWorld()); + npc.setObjectId(new ObjectId()); + npc.setX(p.x); + npc.setY(p.y); + getWorld().addObject(npc); + getWorld().incUpdatable(); - NonPlayerCharacter npc = (NonPlayerCharacter) GameServer.INSTANCE.getGameUniverse().getObject((ObjectId) id); - - if (npc != null) { - npc.setFactory(this); - npcs.add(npc); + settlement.addNpc(npc); } } - tmpNpcArray = null; + cooldown += NPC_CREATION_COOLDOWN; } else { - - if (cooldown == 0) { - if (npcs.size() < MAX_NPC_COUNT) { - Point p = getAdjacentTile(); - - if (p != null) { - NonPlayerCharacter npc = new HarvesterNPC(); - npc.setWorld(getWorld()); - npc.setObjectId(new ObjectId()); - npc.setX(p.x); - npc.setY(p.y); - getWorld().addObject(npc); - getWorld().incUpdatable(); - npc.setFactory(this); - - npcs.add(npc); - } - } - - cooldown += NPC_CREATION_COOLDOWN; - - } else { - cooldown--; - } + cooldown--; } } - - @Override - public Document mongoSerialise() { - Document dbObject = super.mongoSerialise(); - - List tmpNpcArray = new ArrayList<>(npcs.size()); - - for (NonPlayerCharacter npc : npcs) { - tmpNpcArray.add(npc.getObjectId()); - } - - dbObject.put("npcs", tmpNpcArray); - - return dbObject; - } - - ArrayList getNpcs() { - return npcs; - } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java index f15219f..d204f76 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java @@ -33,7 +33,7 @@ public class HarvesterNPC extends NonPlayerCharacter { super.update(); - if (getFactory() != null) { + if (getSettlement() != null) { if (getTask().checkCompleted()) { setTask(new HarvestTask()); @@ -54,8 +54,8 @@ public class HarvesterNPC extends NonPlayerCharacter { getWorld().decUpdatable(); - if (getFactory() != null && getFactory().getNpcs() != null) { - getFactory().getNpcs().remove(this); + if (getSettlement() != null && getSettlement().getNpcs() != null) { + getSettlement().getNpcs().remove(this); } GameServer.INSTANCE.getEventDispatcher().dispatch(new ObjectDeathEvent(this)); diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java index a11c7d6..8ad7c65 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java @@ -41,10 +41,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable */ private Action lastAction = Action.IDLE; - /** - * Factory that created this NPC - */ - private Factory factory; + private Settlement settlement; /** * If set to true, the NPC will be destroyed next tick if it is @@ -93,8 +90,8 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable age++; - //Destroy NPCs that are not linked with a Factory - if (factory == null) { + //Destroy NPCs that are not linked with a Settlement + if (settlement == null) { if (selfDestroyNextTick) { setDead(true); } @@ -147,7 +144,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable if (direction == Direction.NORTH) { - if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(), + if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(), getWorld().getX(), getWorld().getY() - 1) <= MAX_FACTORY_DISTANCE) { if (!moveTo(8, 0, 0)) { setDirection(Direction.NORTH); @@ -159,7 +156,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable } } else if (direction == Direction.EAST) { - if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(), + if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(), getWorld().getX() + 1, getWorld().getY()) <= MAX_FACTORY_DISTANCE) { if (!moveTo(15, 7, 0)) { setDirection(Direction.EAST); @@ -170,7 +167,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable return false; } } else if (direction == Direction.SOUTH) { - if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(), + if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(), getWorld().getX(), getWorld().getY() + 1) <= MAX_FACTORY_DISTANCE) { if (!moveTo(8, 15, 0)) { setDirection(Direction.SOUTH); @@ -181,7 +178,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable return false; } } else if (direction == Direction.WEST) { - if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(), + if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(), getWorld().getX() - 1, getWorld().getY()) <= MAX_FACTORY_DISTANCE) { if (!moveTo(0, 7, 0)) { setDirection(Direction.WEST); @@ -254,16 +251,15 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable return lastAction; } - public Factory getFactory() { - return factory; - } - - public void setFactory(Factory factory) { - this.factory = factory; - } - public int getAge() { return age; } + public Settlement getSettlement() { + return settlement; + } + + public void setSettlement(Settlement settlement) { + this.settlement = settlement; + } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java index c884d2d..8d6f3ad 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java @@ -11,15 +11,14 @@ import net.simon987.server.ServerConfiguration; import net.simon987.server.game.objects.GameRegistry; import net.simon987.server.logging.LogManager; import net.simon987.server.plugin.ServerPlugin; +import org.bson.Document; -import java.util.ArrayList; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class NpcPlugin extends ServerPlugin { - /** - * Radio tower cache - */ - private static ArrayList radioTowers; + public static Map settlementMap; @Override public void init(GameServer gameServer) { @@ -46,13 +45,35 @@ public class NpcPlugin extends ServerPlugin { registry.registerTile(TileVaultFloor.ID, TileVaultFloor.class); registry.registerTile(TileVaultWall.ID, TileVaultWall.class); - radioTowers = new ArrayList<>(32); + settlementMap = new ConcurrentHashMap<>(); LogManager.LOGGER.info("(NPC Plugin) Initialised NPC plugin"); } - public static ArrayList getRadioTowers() { - return radioTowers; + @Override + public Document mongoSerialise() { + Document document = super.mongoSerialise(); + + Document settlements = new Document(); + for (String world : settlementMap.keySet()) { + settlements.put(world, settlementMap.get(world).mongoSerialise()); + } + + document.put("settlement_map", settlements); + + return document; } + @Override + public void load(Document document) { + super.load(document); + + Document settlements = (Document) document.get("settlement_map"); + + for (String world : settlements.keySet()) { + settlementMap.put(world, new Settlement((Document) settlements.get(world))); + } + + LogManager.LOGGER.fine(String.format("(%s) Loaded %d settlements", name, settlementMap.size())); + } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioReceiverHardware.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioReceiverHardware.java index cb0ab04..415d248 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioReceiverHardware.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioReceiverHardware.java @@ -8,6 +8,7 @@ import net.simon987.server.game.objects.ControllableUnit; import org.bson.Document; import java.util.ArrayList; +import java.util.List; public class RadioReceiverHardware extends HardwareModule { @@ -39,12 +40,14 @@ public class RadioReceiverHardware extends HardwareModule { //Find the nearest Radio Tower and query it cubot.setAction(Action.LISTENING); - ArrayList messages = new ArrayList<>(6); + List messages = new ArrayList<>(6); - ArrayList towers = new ArrayList<>(NpcPlugin.getRadioTowers()); //Avoid ConcurrentModificationException - for (RadioTower tower : towers) { - if (Util.manhattanDist(tower.getWorld().getX(), tower.getWorld().getY(), cubot.getWorld().getX(), - cubot.getWorld().getY()) <= RadioTower.MAX_RANGE) { + for (String world : NpcPlugin.settlementMap.keySet()) { + RadioTower tower = NpcPlugin.settlementMap.get(world).getRadioTower(); + + if (tower != null && Util.manhattanDist( + tower.getWorld().getX(), tower.getWorld().getY(), + cubot.getWorld().getX(), cubot.getWorld().getY()) <= RadioTower.MAX_RANGE) { //Tower is in range messages.addAll(tower.getMessages()); } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioTower.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioTower.java index e867774..0a66b7a 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioTower.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/RadioTower.java @@ -24,7 +24,6 @@ public class RadioTower extends Structure implements MessageReceiver, Updatable public RadioTower(Document document) { super(document, 1, 1); - NpcPlugin.getRadioTowers().add(this); } @Override diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java new file mode 100644 index 0000000..eb9ea9f --- /dev/null +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java @@ -0,0 +1,219 @@ +package net.simon987.npcplugin; + +import net.simon987.server.GameServer; +import net.simon987.server.game.world.TilePlain; +import net.simon987.server.game.world.World; +import net.simon987.server.game.world.WorldGenerationException; +import net.simon987.server.io.MongoSerializable; +import org.bson.Document; +import org.bson.types.ObjectId; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class Settlement implements MongoSerializable { + + private Factory factory = null; + private RadioTower radioTower = null; + private VaultDoor vaultDoor = null; + private World world; + private DifficultyLevel difficultyLevel; + + private List npcs = new ArrayList<>(); + + private char[] password; + + public Settlement(Document document) { + + world = GameServer.INSTANCE.getGameUniverse().getWorld(document.getString("world"), false); + ObjectId radioTowerId = document.getObjectId("radio_tower"); + if (radioTowerId != null) { + radioTower = (RadioTower) GameServer.INSTANCE.getGameUniverse().getObject(radioTowerId); + } + ObjectId vaultDoorId = document.getObjectId("vault_door"); + if (vaultDoorId != null) { + vaultDoor = (VaultDoor) GameServer.INSTANCE.getGameUniverse().getObject(vaultDoorId); + } + ObjectId factoryId = document.getObjectId("factory"); + factory = (Factory) GameServer.INSTANCE.getGameUniverse().getObject(factoryId); + + difficultyLevel = DifficultyLevel.values()[document.getInteger("difficulty_level")]; + + Object[] npcArray = ((ArrayList) document.get("npcs")).toArray(); + for (Object id : npcArray) { + + NonPlayerCharacter npc = (NonPlayerCharacter) GameServer.INSTANCE.getGameUniverse().getObject((ObjectId) id); + + if (npc != null) { + addNpc(npc); + } + } + + password = document.getString("password").toCharArray(); + } + + public Settlement(World world) throws WorldGenerationException { + + System.out.println("SETTLING"); + + this.world = world; + this.difficultyLevel = DifficultyLevel.NORMAL; //TODO randomize ? + + outerLoopFactory: + for (int x = 2; x < 12; x++) { + for (int y = 2; y < 12; y++) { + + if ((!world.isTileBlocked(x, y) && !world.isTileBlocked(x + 1, y) && + !world.isTileBlocked(x, y + 1) && !world.isTileBlocked(x + 1, y + 1))) { + + Factory factory = new Factory(); + + factory.setWorld(world); + factory.setObjectId(new ObjectId()); + factory.setX(x); + factory.setY(y); + + if (factory.getAdjacentTile() == null) { + //Factory has no non-blocked adjacent tiles + continue; + } + + world.addObject(factory); + world.incUpdatable(); + this.factory = factory; + + break outerLoopFactory; + } + } + } + if (factory == null) { + throw new WorldGenerationException("Could not place Factory"); + } + + //Also spawn a radio tower in the same World + Point p = world.getRandomTileWithAdjacent(8, TilePlain.ID); + if (p != null) { + while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0) { + p = world.getRandomPassableTile(); + + if (p == null) { + //World is full + return; + } + } + + RadioTower radioTower = new RadioTower(); + + radioTower.setWorld(world); + radioTower.setObjectId(new ObjectId()); + radioTower.setX(p.x); + radioTower.setY(p.y); + + if (radioTower.getAdjacentTile() != null) { + //Radio Tower has adjacent tiles + world.addObject(radioTower); + world.incUpdatable(); //In case the Factory couldn't be spawned. + + this.radioTower = radioTower; + } + } + + //Also spawn a Vault in the same World + p = world.getRandomPassableTile(); + if (p != null) { + + VaultDoor vaultDoor = new VaultDoor(0); //todo cypherId ? + vaultDoor.setWorld(world); + + int counter = 700; + while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0 + || vaultDoor.getAdjacentTileCount(true) < 8) { + p = world.getRandomPassableTile(); + + if (p == null) { + //World is full + return; + } + + vaultDoor.setX(p.x); + vaultDoor.setY(p.y); + + counter--; + + if (counter <= 0) { + //Reached maximum amount of retries + return; + } + } + + vaultDoor.setObjectId(new ObjectId()); + world.addObject(vaultDoor); + world.incUpdatable(); //In case the Factory & Radio Tower couldn't be spawned. + vaultDoor.setWorld(world); + + vaultDoor.initialize(); + this.vaultDoor = vaultDoor; + } + } + + public void addNpc(NonPlayerCharacter npc) { + npcs.add(npc); + npc.setSettlement(this); + } + + @Override + public Document mongoSerialise() { + Document document = new Document(); + + document.put("world", world.getId()); + if (radioTower != null) { + document.put("radio_tower", radioTower.getObjectId()); + } + if (vaultDoor != null) { + document.put("vault_door", vaultDoor.getObjectId()); + } + document.put("factory", factory.getObjectId()); + document.put("difficulty_level", difficultyLevel.ordinal()); + document.put("password", "1234567"); //todo + + + List npcArray = new ArrayList<>(npcs.size()); + for (NonPlayerCharacter npc : npcs) { + npcArray.add(npc.getObjectId()); + } + document.put("npcs", npcArray); + + return document; + } + + public enum DifficultyLevel { + NORMAL(0); + + public int cypherId; + + DifficultyLevel(int cypherId) { + this.cypherId = cypherId; + } + } + + public Factory getFactory() { + return factory; + } + + public RadioTower getRadioTower() { + return radioTower; + } + + public VaultDoor getVaultDoor() { + return vaultDoor; + } + + public World getWorld() { + return world; + } + + public List getNpcs() { + return npcs; + } +} diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java index a4c1f48..87a3cc1 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDimension.java @@ -29,7 +29,7 @@ public class VaultDimension { public VaultDimension(VaultDoor vaultDoor) { - name = "v" + vaultDoor.getObjectId() + "-"; + name = "v" + vaultDoor.getObjectId(); /* * Creates a group of vault worlds and pieces them together with openings. diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java index 8821bd4..609e727 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java @@ -1,17 +1,14 @@ package net.simon987.npcplugin.event; -import net.simon987.npcplugin.Factory; import net.simon987.npcplugin.NpcPlugin; -import net.simon987.npcplugin.RadioTower; -import net.simon987.npcplugin.VaultDoor; +import net.simon987.npcplugin.Settlement; import net.simon987.server.event.GameEvent; import net.simon987.server.event.GameEventListener; import net.simon987.server.event.WorldGenerationEvent; -import net.simon987.server.game.world.TilePlain; import net.simon987.server.game.world.World; -import org.bson.types.ObjectId; +import net.simon987.server.game.world.WorldGenerationException; +import net.simon987.server.logging.LogManager; -import java.awt.*; import java.util.Random; public class WorldCreationListener implements GameEventListener { @@ -37,105 +34,13 @@ public class WorldCreationListener implements GameEventListener { if (random.nextInt(FACTORY_SPAWN_RATE) == 0) { - World world = ((WorldGenerationEvent) event).getWorld(); + World world = (World) event.getSource(); - outerLoopFactory: - for (int x = 2; x < 12; x++) { - for (int y = 2; y < 12; y++) { - - if ((!world.isTileBlocked(x, y) && !world.isTileBlocked(x + 1, y) && - !world.isTileBlocked(x, y + 1) && !world.isTileBlocked(x + 1, y + 1))) { - - Factory factory = new Factory(); - - factory.setWorld(world); - factory.setObjectId(new ObjectId()); - factory.setX(x); - factory.setY(y); - - if (factory.getAdjacentTile() == null) { - //Factory has no non-blocked adjacent tiles - continue; - } - - world.addObject(factory); - world.incUpdatable(); - -// LogManager.LOGGER.info("Spawned Factory at (" + world.getX() + ", " + world.getY() + -// ") (" + x + ", " + y + ")"); - break outerLoopFactory; - } - } - } - - //Also spawn a radio tower in the same World - Point p = world.getRandomTileWithAdjacent(8, TilePlain.ID); - if (p != null) { - while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0) { - p = world.getRandomPassableTile(); - - if (p == null) { - //World is full - return; - } - } - - RadioTower radioTower = new RadioTower(); - - radioTower.setWorld(world); - radioTower.setObjectId(new ObjectId()); - radioTower.setX(p.x); - radioTower.setY(p.y); - - if (radioTower.getAdjacentTile() != null) { - //Radio Tower has adjacent tiles - world.addObject(radioTower); - world.incUpdatable(); //In case the Factory couldn't be spawned. - - NpcPlugin.getRadioTowers().add(radioTower); - -// LogManager.LOGGER.info("Spawned RadioTower at (" + world.getX() + ", " + world.getY() + -// ") (" + p.x + ", " + p.y + ")"); - } - } - - //Also spawn a Vault in the same World - p = world.getRandomPassableTile(); - if (p != null) { - - VaultDoor vaultDoor = new VaultDoor(0); //todo cypherId ? - vaultDoor.setWorld(world); - - int counter = 700; - while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0 - || vaultDoor.getAdjacentTileCount(true) < 8) { - p = world.getRandomPassableTile(); - - if (p == null) { - //World is full - return; - } - - vaultDoor.setX(p.x); - vaultDoor.setY(p.y); - - counter--; - - if (counter <= 0) { - //Reached maximum amount of retries - return; - } - } - - vaultDoor.setObjectId(new ObjectId()); - world.addObject(vaultDoor); - world.incUpdatable(); //In case the Factory & Radio Tower couldn't be spawned. - vaultDoor.setWorld(world); - - vaultDoor.initialize(); - -// LogManager.LOGGER.info("Spawned Vault Door at (" + world.getX() + ", " + world.getY() + -// ") (" + p.x + ", " + p.y + ")"); + try { + NpcPlugin.settlementMap.put(world.getId(), new Settlement(world)); + } catch (WorldGenerationException e) { + LogManager.LOGGER.fine(String.format("Exception during settlement generation: %s.", + e.getMessage())); } } } diff --git a/Plugin Plant/src/main/java/net/simon987/biomassplugin/WorldUtils.java b/Plugin Plant/src/main/java/net/simon987/biomassplugin/WorldUtils.java index 8d05d74..61dda4b 100644 --- a/Plugin Plant/src/main/java/net/simon987/biomassplugin/WorldUtils.java +++ b/Plugin Plant/src/main/java/net/simon987/biomassplugin/WorldUtils.java @@ -73,9 +73,6 @@ public class WorldUtils { } } -// LogManager.LOGGER.info("Generated " + biomassBlobs.size() + " biomassBlobs for World (" + world.getX() + ',' + -// world.getY() + ')'); - return biomassBlobs; } } diff --git a/Plugin Plant/src/main/java/net/simon987/biomassplugin/event/ObjectDeathListener.java b/Plugin Plant/src/main/java/net/simon987/biomassplugin/event/ObjectDeathListener.java index 3a5deed..023c66f 100644 --- a/Plugin Plant/src/main/java/net/simon987/biomassplugin/event/ObjectDeathListener.java +++ b/Plugin Plant/src/main/java/net/simon987/biomassplugin/event/ObjectDeathListener.java @@ -7,7 +7,6 @@ import net.simon987.server.event.GameEventListener; import net.simon987.server.event.ObjectDeathEvent; import net.simon987.server.game.objects.GameObject; import net.simon987.server.game.world.World; -import net.simon987.server.logging.LogManager; import org.bson.types.ObjectId; /** @@ -41,8 +40,6 @@ public class ObjectDeathListener implements GameEventListener { dyingHarvesterNPC.getX(), dyingHarvesterNPC.getY(), dyingHarvesterNPC.getWorld()); //Add it to the world game objects dyingHarvesterNPC.getWorld().addObject(newBiomassBlob); - LogManager.LOGGER.fine("Spawned biomass at (" + newBiomassBlob.getX() + - ", " + newBiomassBlob.getY() + ")"); } } } diff --git a/Server/src/main/java/net/simon987/server/GameServer.java b/Server/src/main/java/net/simon987/server/GameServer.java index 0996dde..4777c42 100644 --- a/Server/src/main/java/net/simon987/server/GameServer.java +++ b/Server/src/main/java/net/simon987/server/GameServer.java @@ -18,6 +18,7 @@ import net.simon987.server.game.objects.GameRegistry; import net.simon987.server.game.world.*; import net.simon987.server.logging.LogManager; import net.simon987.server.plugin.PluginManager; +import net.simon987.server.plugin.ServerPlugin; import net.simon987.server.user.User; import net.simon987.server.user.UserManager; import net.simon987.server.user.UserStatsHelper; @@ -221,11 +222,18 @@ public class GameServer implements Runnable { universe.addUser(user); } - //Load misc server info + //Load server & plugin data cursor = server.find().iterator(); if (cursor.hasNext()) { Document serverObj = cursor.next(); gameUniverse.setTime((long) serverObj.get("time")); + + Document plugins = (Document) serverObj.get("plugins"); + + for (String pluginName : plugins.keySet()) { + ServerPlugin plugin = pluginManager.getPluginByName(pluginName); + plugin.load((Document) plugins.get(pluginName)); + } } LogManager.LOGGER.info("Done loading! W:" + GameServer.INSTANCE.getGameUniverse().getWorldCount() + @@ -267,6 +275,13 @@ public class GameServer implements Runnable { Document serverObj = new Document(); serverObj.put("time", gameUniverse.getTime()); + + Document plugins = new Document(); + for (ServerPlugin plugin : pluginManager.getPlugins()) { + plugins.put(plugin.getName(), plugin.mongoSerialise()); + } + serverObj.put("plugins", plugins); + //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); diff --git a/Server/src/main/java/net/simon987/server/game/GameUniverse.java b/Server/src/main/java/net/simon987/server/game/GameUniverse.java index 9248736..d3415a6 100644 --- a/Server/src/main/java/net/simon987/server/game/GameUniverse.java +++ b/Server/src/main/java/net/simon987/server/game/GameUniverse.java @@ -115,6 +115,14 @@ public class GameUniverse { } } + public World getWorld(String id, boolean createNew) { + + String[] tokens = id.split("-"); + + return getWorld(Integer.decode(tokens[1]), Integer.decode(tokens[2]), + createNew, tokens[0]); + } + public World getLoadedWorld(int x, int y, String dimension) { // Wrapping coordinates around cyclically x %= maxWidth; diff --git a/Server/src/main/java/net/simon987/server/game/objects/GameObject.java b/Server/src/main/java/net/simon987/server/game/objects/GameObject.java index 251e441..b463fa4 100755 --- a/Server/src/main/java/net/simon987/server/game/objects/GameObject.java +++ b/Server/src/main/java/net/simon987/server/game/objects/GameObject.java @@ -159,30 +159,30 @@ public abstract class GameObject implements JSONSerializable, MongoSerializable int count = 0; - if (!getWorld().isTileBlocked(getX() + 1, getY())) { + if (getWorld().getTileMap().isInBounds(x + 1, y) && !getWorld().isTileBlocked(x + 1, y)) { count++; } - if (!getWorld().isTileBlocked(getX(), getY() + 1)) { + if (getWorld().getTileMap().isInBounds(x, y + 1) && !getWorld().isTileBlocked(x, y + 1)) { count++; } - if (!getWorld().isTileBlocked(getX() - 1, getY())) { + if (getWorld().getTileMap().isInBounds(x - 1, y) && !getWorld().isTileBlocked(x - 1, y)) { count++; } - if (!getWorld().isTileBlocked(getX(), getY() - 1)) { + if (getWorld().getTileMap().isInBounds(x, y - 1) && !getWorld().isTileBlocked(x, y - 1)) { count++; } if (diagonals) { - if (!getWorld().isTileBlocked(getX() + 1, getY() + 1)) { + if (getWorld().getTileMap().isInBounds(x + 1, y + 1) && !getWorld().isTileBlocked(x + 1, y + 1)) { count++; } - if (!getWorld().isTileBlocked(getX() - 1, getY() + 1)) { + if (getWorld().getTileMap().isInBounds(x - 1, y + 1) && !getWorld().isTileBlocked(x - 1, y + 1)) { count++; } - if (!getWorld().isTileBlocked(getX() + 1, getY() - 1)) { + if (getWorld().getTileMap().isInBounds(x + 1, y - 1) && !getWorld().isTileBlocked(x + 1, y - 1)) { count++; } - if (!getWorld().isTileBlocked(getX() - 1, getY() - 1)) { + if (getWorld().getTileMap().isInBounds(x - 1, y - 1) && !getWorld().isTileBlocked(x - 1, y - 1)) { count++; } } diff --git a/Server/src/main/java/net/simon987/server/game/world/TileMap.java b/Server/src/main/java/net/simon987/server/game/world/TileMap.java index d64ba6f..5d91007 100755 --- a/Server/src/main/java/net/simon987/server/game/world/TileMap.java +++ b/Server/src/main/java/net/simon987/server/game/world/TileMap.java @@ -5,6 +5,7 @@ import net.simon987.server.GameServer; import net.simon987.server.game.objects.GameRegistry; import net.simon987.server.io.JSONSerializable; 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; @@ -87,7 +88,8 @@ public class TileMap implements JSONSerializable, MongoSerializable { */ public int getTileIdAt(int x, int y) { try { - return tiles[x][y].getId(); + Tile tile = tiles[x][y]; + return tile == null ? -1 : tile.getId(); } catch (ArrayIndexOutOfBoundsException e) { return -1; } @@ -101,13 +103,18 @@ public class TileMap implements JSONSerializable, MongoSerializable { * @return the tile id at the specified position, null if out of bounds */ public Tile getTileAt(int x, int y) { - try { + if (isInBounds(x, y)) { return tiles[x][y]; - } catch (ArrayIndexOutOfBoundsException e) { + } else { + LogManager.LOGGER.warning(String.format("ArrayIndexOutOfBoundsException in TileMap::getTileAt(%d, %d)", x, y)); + Thread.dumpStack(); return null; } } + public boolean isInBounds(int x, int y) { + return x >= 0 && x < width && y >= 0 && y < width; + } public int getWidth() { diff --git a/Server/src/main/java/net/simon987/server/game/world/World.java b/Server/src/main/java/net/simon987/server/game/world/World.java index 3d74162..c3890da 100644 --- a/Server/src/main/java/net/simon987/server/game/world/World.java +++ b/Server/src/main/java/net/simon987/server/game/world/World.java @@ -76,7 +76,7 @@ public class World implements MongoSerializable { * @return long */ public static String idFromCoordinates(int x, int y, String dimension) { - return dimension + "0x" + Integer.toHexString(x) + "-" + "0x" + Integer.toHexString(y); + return dimension + "-0x" + Integer.toHexString(x) + "-" + "0x" + Integer.toHexString(y); } /** @@ -425,28 +425,28 @@ public class World implements MongoSerializable { if (rTile != null) { int adjacentTiles = 0; - if (!isTileBlocked(rTile.x, rTile.y - 1)) { + if (tileMap.isInBounds(rTile.x, rTile.y - 1) && !isTileBlocked(rTile.x, rTile.y - 1)) { adjacentTiles++; } - if (!isTileBlocked(rTile.x + 1, rTile.y)) { + if (tileMap.isInBounds(rTile.x + 1, rTile.y) && !isTileBlocked(rTile.x + 1, rTile.y)) { adjacentTiles++; } - if (!isTileBlocked(rTile.x, rTile.y + 1)) { + if (tileMap.isInBounds(rTile.x, rTile.y + 1) && !isTileBlocked(rTile.x, rTile.y + 1)) { adjacentTiles++; } - if (!isTileBlocked(rTile.x - 1, rTile.y)) { + if (tileMap.isInBounds(rTile.x - 1, rTile.y) && !isTileBlocked(rTile.x - 1, rTile.y)) { adjacentTiles++; } - if (!isTileBlocked(rTile.x + 1, rTile.y + 1)) { + if (tileMap.isInBounds(rTile.x + 1, rTile.y + 1) && !isTileBlocked(rTile.x + 1, rTile.y + 1)) { adjacentTiles++; } - if (!isTileBlocked(rTile.x - 1, rTile.y + 1)) { + if (tileMap.isInBounds(rTile.x - 1, rTile.y + 1) && !isTileBlocked(rTile.x - 1, rTile.y + 1)) { adjacentTiles++; } - if (!isTileBlocked(rTile.x + 1, rTile.y - 1)) { + if (tileMap.isInBounds(rTile.x + 1, rTile.y - 1) && !isTileBlocked(rTile.x + 1, rTile.y - 1)) { adjacentTiles++; } - if (!isTileBlocked(rTile.x - 1, rTile.y - 1)) { + if (tileMap.isInBounds(rTile.x - 1, rTile.y - 1) && !isTileBlocked(rTile.x - 1, rTile.y - 1)) { adjacentTiles++; } diff --git a/Server/src/main/java/net/simon987/server/game/world/WorldGenerationException.java b/Server/src/main/java/net/simon987/server/game/world/WorldGenerationException.java new file mode 100644 index 0000000..bac7ee8 --- /dev/null +++ b/Server/src/main/java/net/simon987/server/game/world/WorldGenerationException.java @@ -0,0 +1,7 @@ +package net.simon987.server.game.world; + +public class WorldGenerationException extends Exception { + public WorldGenerationException(String message) { + super(message); + } +} diff --git a/Server/src/main/java/net/simon987/server/game/world/WorldGenerator.java b/Server/src/main/java/net/simon987/server/game/world/WorldGenerator.java index dd51e53..1550e43 100755 --- a/Server/src/main/java/net/simon987/server/game/world/WorldGenerator.java +++ b/Server/src/main/java/net/simon987/server/game/world/WorldGenerator.java @@ -38,6 +38,8 @@ public class WorldGenerator { private int minCopperCount; private int maxCopperCount; + private String dimension; + private static final int DEFAULT_WORLD_SIZE = 16; /** @@ -48,6 +50,8 @@ public class WorldGenerator { public WorldGenerator(ServerConfiguration config) { + dimension = config.getString("new_user_dimension"); + centerPointCountMin = config.getInt("wg_centerPointCountMin"); centerPointCountMax = config.getInt("wg_centerPointCountMax"); wallPlainRatio = config.getInt("wg_wallPlainRatio"); @@ -88,9 +92,9 @@ public class WorldGenerator { /** * Generates an empty World */ - private static World generateEmptyWorld(int locX, int locY) { + private static World generateEmptyWorld(int locX, int locY, String dimension) { - return new World(locX, locY, new TileMap(DEFAULT_WORLD_SIZE, DEFAULT_WORLD_SIZE), "w-"); + return new World(locX, locY, new TileMap(DEFAULT_WORLD_SIZE, DEFAULT_WORLD_SIZE), dimension); } /** @@ -99,7 +103,7 @@ public class WorldGenerator { public World generateWorld(int locX, int locY) throws CancelledException { Random random = new Random(); - World world = generateEmptyWorld(locX, locY); + World world = generateEmptyWorld(locX, locY, dimension); centerPointsMap = new HashMap<>(16); diff --git a/Server/src/main/java/net/simon987/server/plugin/PluginManager.java b/Server/src/main/java/net/simon987/server/plugin/PluginManager.java index 2d51f8f..7a12e87 100644 --- a/Server/src/main/java/net/simon987/server/plugin/PluginManager.java +++ b/Server/src/main/java/net/simon987/server/plugin/PluginManager.java @@ -152,6 +152,10 @@ public class PluginManager { return null; } + public ServerPlugin getPluginByName(String name) { + return PluginManager.getPluginByName(name, loadedPlugins); + } + private boolean isLoaded(String name) { return getPluginByName(name, loadedPlugins) != null; } diff --git a/Server/src/main/java/net/simon987/server/plugin/ServerPlugin.java b/Server/src/main/java/net/simon987/server/plugin/ServerPlugin.java index 5b6af10..c6a2d8d 100644 --- a/Server/src/main/java/net/simon987/server/plugin/ServerPlugin.java +++ b/Server/src/main/java/net/simon987/server/plugin/ServerPlugin.java @@ -2,11 +2,14 @@ package net.simon987.server.plugin; import net.simon987.server.GameServer; import net.simon987.server.event.GameEventListener; +import net.simon987.server.io.MongoSerializable; +import net.simon987.server.logging.LogManager; +import org.bson.Document; import java.util.ArrayList; import java.util.List; -public abstract class ServerPlugin { +public abstract class ServerPlugin implements MongoSerializable { /** * Name of the plugin @@ -49,4 +52,22 @@ public abstract class ServerPlugin { public List getListeners() { return listeners; } + + @Override + public Document mongoSerialise() { + Document document = new Document(); + + document.put("version", version); + + return document; + } + + public void load(Document document) { + + LogManager.LOGGER.fine(String.format("(%s) Loading from database", name)); + if (!version.equals(document.getString("version"))) { + LogManager.LOGGER.warning(String.format("(%s) Version mismatch with database!" + + " This could cause problems. %s!=%s", name, version, document.getString("version"))); + } + } } diff --git a/Server/src/main/resources/config.properties b/Server/src/main/resources/config.properties index 5dd914a..1b44a00 100644 --- a/Server/src/main/resources/config.properties +++ b/Server/src/main/resources/config.properties @@ -48,7 +48,7 @@ user_timeout=100 #User creation new_user_worldX=32767 new_user_worldY=32767 -new_user_dimension=w- +new_user_dimension=w # Default user code new_user_code=; Welcome to Much Assembly required!\n\ ; You will find useful information on the game here: https://github.com/simon987/Much-Assembly-Required/wiki\n\ From 201d83f8d8b10b1f3d5098d35a4df8768e972be6 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 21 Dec 2018 14:00:47 -0500 Subject: [PATCH 2/6] Bump version --- Plugin NPC/src/main/resources/plugin.properties | 2 +- Server/src/main/resources/config.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugin NPC/src/main/resources/plugin.properties b/Plugin NPC/src/main/resources/plugin.properties index d2e105b..91f14e5 100644 --- a/Plugin NPC/src/main/resources/plugin.properties +++ b/Plugin NPC/src/main/resources/plugin.properties @@ -1,3 +1,3 @@ classpath=net.simon987.npcplugin.NpcPlugin name=NPC Plugin -version=1.0 \ No newline at end of file +version=1.1 \ No newline at end of file diff --git a/Server/src/main/resources/config.properties b/Server/src/main/resources/config.properties index 1b44a00..dc7fd82 100644 --- a/Server/src/main/resources/config.properties +++ b/Server/src/main/resources/config.properties @@ -66,7 +66,7 @@ shield_energy_cost=50 npc_lifetime=1024 npc_max_factory_distance=3 factory_max_npc_count=16 -factory_spawn_rate=35 +factory_spawn_rate=5 harvester_hp_max=100 harvester_regen=5 harvester_biomass_drop_count=8 From 955d61ce99ffdd08d01cf3f499b6080622d1ffee Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 21 Dec 2018 14:04:42 -0500 Subject: [PATCH 3/6] Password moved from vault door to settlement --- .../net/simon987/npcplugin/Settlement.java | 6 +++- .../net/simon987/npcplugin/VaultDoor.java | 31 +++++-------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java index eb9ea9f..667329c 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java @@ -123,7 +123,7 @@ public class Settlement implements MongoSerializable { p = world.getRandomPassableTile(); if (p != null) { - VaultDoor vaultDoor = new VaultDoor(0); //todo cypherId ? + VaultDoor vaultDoor = new VaultDoor(); vaultDoor.setWorld(world); int counter = 700; @@ -216,4 +216,8 @@ public class Settlement implements MongoSerializable { public List getNpcs() { return npcs; } + + public char[] getPassword() { + return password; + } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java index 3408b4d..ad58009 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultDoor.java @@ -1,7 +1,6 @@ package net.simon987.npcplugin; import net.simon987.server.GameServer; -import net.simon987.server.crypto.RandomStringGenerator; import net.simon987.server.game.objects.*; import net.simon987.server.game.world.World; import net.simon987.server.logging.LogManager; @@ -14,13 +13,6 @@ public class VaultDoor extends Structure implements MessageReceiver, Enterable, private static final int MAP_INFO = 0x0B00; - /** - * Password to open the vault door - */ - private char[] password; - - private RandomStringGenerator randomStringGenerator; - /** * Whether or not the vault door is opened */ @@ -37,16 +29,9 @@ public class VaultDoor extends Structure implements MessageReceiver, Enterable, private int OPEN_TIME = GameServer.INSTANCE.getConfig().getInt("vault_door_open_time"); private int openedTimer = 0; - private int cypherId; - public VaultDoor(int cypherId) { + public VaultDoor() { super(1, 1); - - this.cypherId = cypherId; - - this.randomStringGenerator = new RandomStringGenerator(); - - this.password = "12345678".toCharArray(); } public VaultDoor(Document document) { @@ -60,8 +45,6 @@ public class VaultDoor extends Structure implements MessageReceiver, Enterable, homeX = document.getInteger("homeX"); homeY = document.getInteger("homeY"); } - - password = document.getString("password").toCharArray(); } @@ -69,8 +52,7 @@ public class VaultDoor extends Structure implements MessageReceiver, Enterable, public void update() { if (open){ if (openedTimer <= 0) { - //Door was open for OPEN_TIME, close it and regen password - //password = GameServer.INSTANCE.getConfig().getRandomPassword(); + //Door was open for OPEN_TIME, close it open = false; openedTimer = 0; LogManager.LOGGER.fine("Closed Vault door ID: " + getObjectId()); @@ -84,10 +66,12 @@ public class VaultDoor extends Structure implements MessageReceiver, Enterable, @Override public boolean sendMessage(char[] message) { - System.out.println("message: " + new String(message)); - System.out.println("password: " + new String(password)); + Settlement settlement = NpcPlugin.settlementMap.get(getWorld().getId()); - if (Arrays.equals(message, password)) { + System.out.println("message: " + new String(message)); + System.out.println("password: " + new String(settlement.getPassword())); + + if (Arrays.equals(message, settlement.getPassword())) { if (!open) { openVault(); } else { @@ -144,7 +128,6 @@ public class VaultDoor extends Structure implements MessageReceiver, Enterable, dbObject.put("homeX", getHomeX()); dbObject.put("homeY", getHomeY()); - dbObject.put("password", new String(password)); return dbObject; } From e4a06e79d43259ccad9182d17c8305820b47bb44 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 22 Dec 2018 11:26:34 -0500 Subject: [PATCH 4/6] Hacked NPC minimum viable --- .../java/net/simon987/cubotplugin/Cubot.java | 54 ++- .../simon987/cubotplugin/CubotBattery.java | 88 ++++- .../simon987/cubotplugin/CubotComPort.java | 31 +- .../net/simon987/cubotplugin/CubotCore.java | 17 +- .../net/simon987/cubotplugin/CubotDrill.java | 17 +- .../cubotplugin/CubotHardwareModule.java | 7 - .../simon987/cubotplugin/CubotHologram.java | 9 +- .../simon987/cubotplugin/CubotInventory.java | 17 +- .../net/simon987/cubotplugin/CubotLaser.java | 29 +- .../net/simon987/cubotplugin/CubotLeg.java | 23 +- .../net/simon987/cubotplugin/CubotLidar.java | 35 +- .../event/UserCreationListener.java | 11 +- .../java/net/simon987/npcplugin/Factory.java | 83 ++++- .../net/simon987/npcplugin/HackedNPC.java | 314 ++++++++++++++++++ .../net/simon987/npcplugin/NpcBattery.java | 109 ++++++ .../net/simon987/npcplugin/NpcInventory.java | 109 ++++++ .../net/simon987/npcplugin/NpcPlugin.java | 12 + .../net/simon987/npcplugin/Settlement.java | 3 +- .../resources/defaultHackedCubotHardware.json | 62 ++++ .../src/main/resources/plugin.properties | 3 +- .../net/simon987/server/assembly/CPU.java | 44 ++- .../server/assembly/HardwareModule.java | 11 +- .../server/game/objects/ControllableUnit.java | 14 +- Server/src/main/resources/config.properties | 1 + Server/src/main/resources/static/js/mar.js | 40 ++- Server/src/main/typescript/GameObject.ts | 48 ++- 26 files changed, 1030 insertions(+), 161 deletions(-) create mode 100644 Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java create mode 100644 Plugin NPC/src/main/java/net/simon987/npcplugin/NpcBattery.java create mode 100644 Plugin NPC/src/main/java/net/simon987/npcplugin/NpcInventory.java create mode 100644 Plugin NPC/src/main/resources/defaultHackedCubotHardware.json diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java index 1bdf597..f7693d3 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java @@ -91,25 +91,10 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me */ private User parent; - /** - * Energy units in kJ - */ - private int energy; - - /** - * Maximum energy units in kJ - */ - private int maxEnergy; - - /** - * Solar panel multiplier - *
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; + public static final int CONSOLE_BUFFER_MAX_SIZE = 40; /** * List of attached hardware, 'modules' @@ -143,10 +128,8 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me hp = document.getInteger("hp"); shield = document.getInteger("shield"); setDirection(Direction.getDirection(document.getInteger("direction"))); - energy = document.getInteger("energy"); ServerConfiguration config = GameServer.INSTANCE.getConfig(); - maxEnergy = config.getInt("battery_max_energy"); maxHp = config.getInt("cubot_max_hp"); maxShield = config.getInt("cubot_max_shield"); @@ -176,8 +159,6 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me @Override public void update() { - storeEnergy((int) (SOLAR_PANEL_MULTIPLIER * GameServer.INSTANCE.getDayNightCycle().getSunIntensity())); - if (currentAction == Action.WALKING) { if (spendEnergy(100)) { if (!incrementLocation()) { @@ -225,7 +206,6 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me json.put("hp", hp); json.put("shield", shield); json.put("action", lastAction.ordinal()); - json.put("energy", energy); if (parent != null) { json.put("parent", parent.getUsername()); //Only used client-side for now @@ -249,7 +229,6 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me dbObject.put("hp", hp); dbObject.put("shield", shield); dbObject.put("action", lastAction.ordinal()); - dbObject.put("energy", energy); if (parent != null) { dbObject.put("parent", parent.getUsername()); //Only used client-side for now @@ -279,7 +258,7 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me setDead(false); setHp(maxHp); setShield(0); - setEnergy(maxEnergy); + setEnergy(((CubotBattery) getHardware(CubotBattery.class)).getMaxEnergy()); clearKeyboardBuffer(); consoleMessagesBuffer.clear(); lastConsoleMessagesBuffer.clear(); @@ -354,34 +333,41 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me } public int getEnergy() { - return energy; + CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class); + return battery.getEnergy(); } public void setEnergy(int energy) { - this.energy = energy; + CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class); + battery.setEnergy(energy); } public boolean spendEnergy(int amount) { - if (energy - amount < 0) { + CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class); + + if (battery.getEnergy() - amount < 0) { return false; } else { - energy -= amount; + battery.setEnergy(battery.getEnergy() - amount); return true; } } public void storeEnergy(int amount) { - energy = Math.min(energy + amount, maxEnergy); + CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class); + battery.setEnergy(Math.min(battery.getEnergy() + amount, battery.getMaxEnergy())); } public void setMaxEnergy(int maxEnergy) { - this.maxEnergy = maxEnergy; + CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class); + battery.setMaxEnergy(maxEnergy); } public int getMaxEnergy() { - return maxEnergy; + CubotBattery battery = (CubotBattery) getHardware(CubotBattery.class); + return battery.getMaxEnergy(); } public int getShield() { @@ -422,8 +408,7 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me @Override public Memory getFloppyData() { - //TODO change DEFAULT_ADDRESS to getHW(class) to allow mutable addresses - CubotFloppyDrive drive = ((CubotFloppyDrive) getHardware(CubotFloppyDrive.DEFAULT_ADDRESS)); + CubotFloppyDrive drive = (CubotFloppyDrive) getHardware(CubotFloppyDrive.class); if (drive.getFloppy() != null) { return drive.getFloppy().getMemory(); @@ -515,6 +500,7 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me public void setMaxShield(int maxShield) { this.maxShield = maxShield; } + @Override public void heal(int amount) { hp += amount; @@ -538,11 +524,13 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me } } + @Override public void attachHardware(HardwareModule hardware, int address) { hardwareAddresses.put(address, hardware); hardwareModules.put(hardware.getClass(), address); } + @Override public void detachHardware(int address) { hardwareAddresses.remove(address); @@ -555,6 +543,7 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me hardwareModules.remove(toRemove); } + @Override public boolean hardwareInterrupt(int address, Status status) { HardwareModule hardware = hardwareAddresses.get(address); @@ -566,6 +555,7 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit, Me } } + @Override public int hardwareQuery(int address) { HardwareModule hardware = hardwareAddresses.get(address); diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotBattery.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotBattery.java index d345501..4c8b80a 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotBattery.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotBattery.java @@ -1,10 +1,13 @@ package net.simon987.cubotplugin; +import net.simon987.server.GameServer; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.objects.ControllableUnit; import org.bson.Document; +import org.json.simple.JSONObject; -public class CubotBattery extends CubotHardwareModule { +public class CubotBattery extends HardwareModule { public static final int DEFAULT_ADDRESS = 0x000A; @@ -12,16 +15,38 @@ public class CubotBattery extends CubotHardwareModule { * Hardware ID (Should be unique) */ public static final char HWID = 0x000A; + /** + * Solar panel multiplier + *
TODO: Set this constant in dimension + */ + private static final float SOLAR_PANEL_MULTIPLIER = 1; + + /** + * Energy units in kJ + */ + private int energy; + + /** + * Maximum energy units in kJ + */ + private int maxEnergy; + private static final int BATTERY_POLL = 1; private static final int BATTERY_GET_MAX_CAPACITY = 2; - public CubotBattery(Cubot cubot) { - super(cubot); + public CubotBattery(ControllableUnit unit) { + super(null, unit); + + energy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy"); + maxEnergy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy"); } public CubotBattery(Document document, ControllableUnit cubot) { super(document, cubot); + + energy = document.getInteger("energy"); + maxEnergy = document.getInteger("max_energy"); } @Override @@ -30,16 +55,12 @@ public class CubotBattery extends CubotHardwareModule { int a = getCpu().getRegisterSet().getRegister("A").getValue(); if (a == BATTERY_POLL) { - getCpu().getRegisterSet().getRegister("B").setValue(cubot.getEnergy()); + getCpu().getRegisterSet().getRegister("B").setValue(energy); } else if (a == BATTERY_GET_MAX_CAPACITY) { - getCpu().getRegisterSet().getRegister("B").setValue(cubot.getMaxEnergy()); + getCpu().getRegisterSet().getRegister("B").setValue(maxEnergy); - //TODO: Remove debug action - } else if (a == 0xFFFF) { - cubot.setEnergy(cubot.getMaxEnergy()); } - } @Override @@ -47,4 +68,53 @@ public class CubotBattery extends CubotHardwareModule { return HWID; } + @Override + public JSONObject jsonSerialise() { + JSONObject json = new JSONObject(); + + json.put("energy", energy); + + return json; + } + + @Override + public JSONObject debugJsonSerialise() { + JSONObject json = jsonSerialise(); + + json.put("max_energy", maxEnergy); + + return json; + } + + @Override + public Document mongoSerialise() { + Document document = super.mongoSerialise(); + + document.put("energy", energy); + document.put("max_energy", maxEnergy); + + return document; + } + + public int getEnergy() { + return energy; + } + + public void setEnergy(int energy) { + this.energy = energy; + } + + public int getMaxEnergy() { + return maxEnergy; + } + + public void setMaxEnergy(int maxEnergy) { + this.maxEnergy = maxEnergy; + } + + @Override + public void update() { + energy = Math.min(maxEnergy, + energy + (int) (SOLAR_PANEL_MULTIPLIER * GameServer.INSTANCE.getDayNightCycle().getSunIntensity())); + } } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java index c0eb4e6..65efed4 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotComPort.java @@ -1,5 +1,6 @@ package net.simon987.cubotplugin; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.objects.ControllableUnit; import net.simon987.server.game.objects.GameObject; @@ -9,7 +10,7 @@ import org.bson.Document; import java.awt.*; import java.util.ArrayList; -public class CubotComPort extends CubotHardwareModule { +public class CubotComPort extends HardwareModule { public static final char HWID = 0xD; public static final int DEFAULT_ADDRESS = 0xD; @@ -20,8 +21,8 @@ public class CubotComPort extends CubotHardwareModule { private static final int COMPORT_SELF_OUT = 3; private static final int COMPORT_CONSOLE_CLEAR = 4; - public CubotComPort(Cubot cubot) { - super(cubot); + public CubotComPort(ControllableUnit unit) { + super(null, unit); } public CubotComPort(Document document, ControllableUnit cubot) { @@ -37,21 +38,23 @@ public class CubotComPort extends CubotHardwareModule { if (a == COMPORT_BUFFER_CLEAR) { - cubot.getConsoleMessagesBuffer().clear(); + unit.getConsoleMessagesBuffer().clear(); } else if (a == COMPORT_CONSOLE_CLEAR) { - - cubot.setConsoleMode(Cubot.ConsoleMode.CLEAR); + + if (unit instanceof Cubot) { + ((Cubot) unit).setConsoleMode(Cubot.ConsoleMode.CLEAR); + } } else if (a == COMPORT_POLL) { - if (cubot.spendEnergy(4)) { + if (unit.spendEnergy(4)) { int x = getCpu().getRegisterSet().getRegister("X").getValue(); //Read all messages in the console buffer to memory at X - for (char[] message : cubot.getConsoleMessagesBuffer()) { + for (char[] message : unit.getConsoleMessagesBuffer()) { if (x + MESSAGE_LENGTH >= getCpu().getMemory().getWords().length) { //todo set interrupt ? getCpu().getStatus().setErrorFlag(true); @@ -61,17 +64,17 @@ public class CubotComPort extends CubotHardwareModule { } //Set B = number of messages - getCpu().getRegisterSet().getRegister("B").setValue(cubot.getConsoleMessagesBuffer().size()); + getCpu().getRegisterSet().getRegister("B").setValue(unit.getConsoleMessagesBuffer().size()); } } else if (a == COMPORT_FRONT_PORT_OUT) { - if (cubot.spendEnergy(5)) { + if (unit.spendEnergy(5)) { //Get object directly in front of the Cubot - Point frontTile = cubot.getFrontTile(); + Point frontTile = unit.getFrontTile(); //Todo will have to add getGameObjectsBlockingAt to enable Factory - ArrayList objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y); + ArrayList objects = unit.getWorld().getGameObjectsAt(frontTile.x, frontTile.y); if (objects.size() > 0 && objects.get(0) instanceof MessageReceiver) { @@ -98,7 +101,7 @@ public class CubotComPort extends CubotHardwareModule { } else if (a == COMPORT_SELF_OUT) { - if (cubot.spendEnergy(1)) { + if (unit.spendEnergy(1)) { int x = getCpu().getRegisterSet().getRegister("X").getValue(); @@ -111,7 +114,7 @@ public class CubotComPort extends CubotHardwareModule { //Get MESSAGE_LENGTH-word message pointed by X char[] message = new char[MESSAGE_LENGTH]; System.arraycopy(getCpu().getMemory().getWords(), x, message, 0, MESSAGE_LENGTH); - getCpu().getRegisterSet().getRegister("B").setValue(cubot.sendMessage(message) ? 1 : 0); + getCpu().getRegisterSet().getRegister("B").setValue(unit.sendMessage(message) ? 1 : 0); return; } } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotCore.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotCore.java index 74a303f..6a8996a 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotCore.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotCore.java @@ -1,10 +1,11 @@ package net.simon987.cubotplugin; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.objects.ControllableUnit; import org.bson.Document; -public class CubotCore extends CubotHardwareModule { +public class CubotCore extends HardwareModule { public static final int DEFAULT_ADDRESS = 0x000E; @@ -16,12 +17,12 @@ public class CubotCore extends CubotHardwareModule { private static final int CORE_STATUS_POLL = 1; private static final int CORE_HULL_POLL = 2; - public CubotCore(Cubot cubot) { - super(cubot); + public CubotCore(ControllableUnit unit) { + super(null, unit); } - public CubotCore(Document document, ControllableUnit cubot) { - super(document, cubot); + public CubotCore(Document document, ControllableUnit unit) { + super(document, unit); } @Override @@ -30,9 +31,11 @@ public class CubotCore extends CubotHardwareModule { int a = getCpu().getRegisterSet().getRegister("A").getValue(); if (a == CORE_STATUS_POLL) { - getCpu().getRegisterSet().getRegister("B").setValue(cubot.getStatus()); + if (unit instanceof Cubot) { + getCpu().getRegisterSet().getRegister("B").setValue(((Cubot) unit).getStatus()); + } } else if (a == CORE_HULL_POLL) { - getCpu().getRegisterSet().getRegister("B").setValue(cubot.getHp()); + getCpu().getRegisterSet().getRegister("B").setValue(unit.getHp()); } } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotDrill.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotDrill.java index 884fe90..88dc0b9 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotDrill.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotDrill.java @@ -1,5 +1,6 @@ package net.simon987.cubotplugin; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.item.Item; import net.simon987.server.game.objects.Action; @@ -7,7 +8,7 @@ import net.simon987.server.game.objects.ControllableUnit; import net.simon987.server.game.world.Tile; import org.bson.Document; -public class CubotDrill extends CubotHardwareModule { +public class CubotDrill extends HardwareModule { /** * Hardware ID (Should be unique) @@ -19,8 +20,8 @@ public class CubotDrill extends CubotHardwareModule { private static final int DRILL_POLL = 1; private static final int DRILL_GATHER = 2; // simplified gather - public CubotDrill(Cubot cubot) { - super(cubot); + public CubotDrill(ControllableUnit unit) { + super(null, unit); } public CubotDrill(Document document, ControllableUnit cubot) { @@ -42,15 +43,15 @@ public class CubotDrill extends CubotHardwareModule { } else if (a == DRILL_GATHER) { - if (cubot.spendEnergy(1400)) { - if (cubot.getCurrentAction() == Action.IDLE) { + if (unit.spendEnergy(1400)) { + if (unit.getCurrentAction() == Action.IDLE) { - Tile tile = cubot.getWorld().getTileMap().getTileAt(cubot.getX(), cubot.getY()); + Tile tile = unit.getWorld().getTileMap().getTileAt(unit.getX(), unit.getY()); Item newItem = tile.drill(); if (newItem != null) { - cubot.setCurrentAction(Action.DIGGING); - cubot.giveItem(newItem); + unit.setCurrentAction(Action.DIGGING); + unit.giveItem(newItem); } } } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHardwareModule.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHardwareModule.java index 4f9a5f5..0df894b 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHardwareModule.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHardwareModule.java @@ -16,11 +16,4 @@ public abstract class CubotHardwareModule extends HardwareModule { this.cubot = cubot; } - @Override - public Document mongoSerialise() { - Document document = new Document(); - - document.put("type", getClass().getCanonicalName()); - return document; - } } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHologram.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHologram.java index 9e291c2..f19e88c 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHologram.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotHologram.java @@ -1,11 +1,12 @@ package net.simon987.cubotplugin; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.objects.ControllableUnit; import org.bson.Document; import org.json.simple.JSONObject; -public class CubotHologram extends CubotHardwareModule { +public class CubotHologram extends HardwareModule { /** * Hardware ID (Should be unique) @@ -31,8 +32,8 @@ public class CubotHologram extends CubotHardwareModule { */ private int displayColor = 0; - public CubotHologram(Cubot cubot) { - super(cubot); + public CubotHologram(ControllableUnit unit) { + super(null, unit); } public CubotHologram(Document document, ControllableUnit cubot) { @@ -80,7 +81,7 @@ public class CubotHologram extends CubotHardwareModule { } else if (a == HOLO_DISPLAY_COLOR) { - if (cubot.spendEnergy(4)) { + if (unit.spendEnergy(4)) { int b = getCpu().getRegisterSet().getRegister("B").getValue(); int c = getCpu().getRegisterSet().getRegister("C").getValue(); diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotInventory.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotInventory.java index 263b9b4..0a344a4 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotInventory.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotInventory.java @@ -1,16 +1,16 @@ package net.simon987.cubotplugin; import net.simon987.server.GameServer; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.item.Item; -import net.simon987.server.game.item.ItemCopper; import net.simon987.server.game.objects.ControllableUnit; import org.bson.Document; import java.util.HashMap; import java.util.Map; -public class CubotInventory extends CubotHardwareModule { +public class CubotInventory extends HardwareModule { /** * Hardware ID (Should be unique) @@ -29,11 +29,10 @@ public class CubotInventory extends CubotHardwareModule { private int position = 0; - public CubotInventory(Cubot cubot) { - super(cubot); + public CubotInventory(ControllableUnit unit) { + super(null, unit); inventory = new HashMap<>(); - inventory.put(2, new ItemCopper(new Document())); // TODO: Remove debug value } public CubotInventory(Document document, ControllableUnit cubot) { @@ -56,12 +55,12 @@ public class CubotInventory extends CubotHardwareModule { private void scanItem() { int x = getCpu().getRegisterSet().getRegister("X").getValue(); Item item = inventory.get(position); - item.digitize(cubot.getCpu().getMemory(), x); + item.digitize(unit.getCpu().getMemory(), x); } public Item clearItem() { Item item = inventory.get(position); - item.clear(cubot); + item.clear(unit); inventory.remove(position); return item; @@ -100,13 +99,13 @@ public class CubotInventory extends CubotHardwareModule { getCpu().getRegisterSet().getRegister("B").setValue(result); } else if (a == INV_CLEAR) { - if (cubot.spendEnergy(100)) { + if (unit.spendEnergy(100)) { clearItem(); } } else if (a == INV_SEEK) { setPosition(getCpu().getRegisterSet().getRegister("X").getValue()); } else if (a == INV_SCAN) { - if (cubot.spendEnergy(200)) { + if (unit.spendEnergy(200)) { scanItem(); clearItem(); } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLaser.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLaser.java index 186f2e6..040c3ad 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLaser.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLaser.java @@ -1,6 +1,7 @@ package net.simon987.cubotplugin; import net.simon987.server.GameServer; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.objects.*; import org.bson.Document; @@ -8,7 +9,7 @@ import org.bson.Document; import java.awt.*; import java.util.ArrayList; -public class CubotLaser extends CubotHardwareModule { +public class CubotLaser extends HardwareModule { /** * Hardware ID (Should be unique) @@ -23,8 +24,8 @@ public class CubotLaser extends CubotHardwareModule { private static final int LASER_DAMAGE = 25; - public CubotLaser(Cubot cubot) { - super(cubot); + public CubotLaser(ControllableUnit unit) { + super(null, unit); } public CubotLaser(Document document, ControllableUnit cubot) { @@ -46,19 +47,19 @@ public class CubotLaser extends CubotHardwareModule { if (a == LASER_WITHDRAW) { - Point frontTile = cubot.getFrontTile(); - ArrayList objects = cubot.getWorld().getGameObjectsBlockingAt(frontTile.x, frontTile.y); + Point frontTile = unit.getFrontTile(); + ArrayList objects = unit.getWorld().getGameObjectsBlockingAt(frontTile.x, frontTile.y); - if (cubot.getCurrentAction() == Action.IDLE && objects.size() > 0) { + if (unit.getCurrentAction() == Action.IDLE && objects.size() > 0) { //FIXME: Problem here if more than 1 object if (objects.get(0) instanceof InventoryHolder) { if (((InventoryHolder) objects.get(0)).canTakeItem(b)) { - if (cubot.spendEnergy(30)) { + if (unit.spendEnergy(30)) { //Take the item ((InventoryHolder) objects.get(0)).takeItem(b); - cubot.giveItem(GameServer.INSTANCE.getRegistry().makeItem(b)); - cubot.setCurrentAction(Action.WITHDRAWING); + unit.giveItem(GameServer.INSTANCE.getRegistry().makeItem(b)); + unit.setCurrentAction(Action.WITHDRAWING); } } } @@ -69,12 +70,12 @@ public class CubotLaser extends CubotHardwareModule { // TODO } else if (a == LASER_ATTACK) { - if (cubot.getCurrentAction() == Action.IDLE) { - if (cubot.spendEnergy(70)) { + if (unit.getCurrentAction() == Action.IDLE) { + if (unit.spendEnergy(70)) { //Get object directly in front of the Cubot - Point frontTile = cubot.getFrontTile(); - ArrayList objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y); + Point frontTile = unit.getFrontTile(); + ArrayList objects = unit.getWorld().getGameObjectsAt(frontTile.x, frontTile.y); //todo: Add option in config to allow PvP if (objects.size() > 0 && objects.get(0) instanceof Attackable && !(objects.get(0) instanceof Cubot)) { @@ -83,7 +84,7 @@ public class CubotLaser extends CubotHardwareModule { } - cubot.setCurrentAction(Action.ATTACKING); + unit.setCurrentAction(Action.ATTACKING); } } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLeg.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLeg.java index 99710e1..f91c329 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLeg.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLeg.java @@ -1,12 +1,13 @@ package net.simon987.cubotplugin; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Status; import net.simon987.server.game.objects.Action; import net.simon987.server.game.objects.ControllableUnit; import net.simon987.server.game.objects.Direction; import org.bson.Document; -public class CubotLeg extends CubotHardwareModule { +public class CubotLeg extends HardwareModule { public static final int DEFAULT_ADDRESS = 1; @@ -18,12 +19,12 @@ public class CubotLeg extends CubotHardwareModule { */ static final char HWID = 0x0001; - public CubotLeg(Cubot cubot) { - super(cubot); + public CubotLeg(ControllableUnit unit) { + super(null, unit); } - public CubotLeg(Document document, ControllableUnit cubot) { - super(document, cubot); + public CubotLeg(Document document, ControllableUnit unit) { + super(document, unit); } @Override @@ -34,7 +35,7 @@ public class CubotLeg extends CubotHardwareModule { @Override public void handleInterrupt(Status status) { - if (cubot.getCurrentAction() == Action.IDLE) { + if (unit.getCurrentAction() == Action.IDLE) { int a = getCpu().getRegisterSet().getRegister("A").getValue(); int b = getCpu().getRegisterSet().getRegister("B").getValue(); @@ -44,8 +45,8 @@ public class CubotLeg extends CubotHardwareModule { Direction dir = Direction.getDirection(b); if (dir != null) { - if (cubot.spendEnergy(20)) { - cubot.setDirection(Direction.getDirection(b)); + if (unit.spendEnergy(20)) { + unit.setDirection(Direction.getDirection(b)); status.setErrorFlag(false); } } else { @@ -55,17 +56,17 @@ public class CubotLeg extends CubotHardwareModule { } else if (a == LEGS_SET_DIR_AND_WALK) { - if (cubot.getMaxEnergy() >= 100) { + if (unit.getMaxEnergy() >= 100) { Direction dir = Direction.getDirection(b); if (dir != null) { - cubot.setDirection(Direction.getDirection(b)); + unit.setDirection(Direction.getDirection(b)); status.setErrorFlag(false); } else { status.setErrorFlag(true); } - cubot.setCurrentAction(Action.WALKING); + unit.setCurrentAction(Action.WALKING); } } } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLidar.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLidar.java index 04da704..dd5eb0b 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLidar.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/CubotLidar.java @@ -1,5 +1,6 @@ package net.simon987.cubotplugin; +import net.simon987.server.assembly.HardwareModule; import net.simon987.server.assembly.Memory; import net.simon987.server.assembly.Status; import net.simon987.server.game.objects.ControllableUnit; @@ -9,7 +10,7 @@ import org.bson.Document; import java.util.ArrayList; -public class CubotLidar extends CubotHardwareModule { +public class CubotLidar extends HardwareModule { /** * Hardware ID (Should be unique) @@ -24,12 +25,12 @@ public class CubotLidar extends CubotHardwareModule { private static final int LIDAR_GET_WORLD_POS = 4; private static final int LIDAR_GET_WORLD_SIZE = 5; - public CubotLidar(Cubot cubot) { - super(cubot); + public CubotLidar(ControllableUnit unit) { + super(null, unit); } - public CubotLidar(Document document, ControllableUnit cubot) { - super(document, cubot); + public CubotLidar(Document document, ControllableUnit unit) { + super(document, unit); } @Override @@ -44,18 +45,18 @@ public class CubotLidar extends CubotHardwareModule { switch (a) { case LIDAR_GET_POS: - getCpu().getRegisterSet().getRegister("X").setValue(cubot.getX()); - getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getY()); + getCpu().getRegisterSet().getRegister("X").setValue(unit.getX()); + getCpu().getRegisterSet().getRegister("Y").setValue(unit.getY()); break; case LIDAR_GET_PATH: - if (cubot.spendEnergy(50)) { + if (unit.spendEnergy(50)) { int c = getCpu().getRegisterSet().getRegister("C").getValue(); int b = getCpu().getRegisterSet().getRegister("B").getValue(); int destX = getCpu().getRegisterSet().getRegister("X").getValue(); int destY = getCpu().getRegisterSet().getRegister("Y").getValue(); //Get path - ArrayList nodes = Pathfinder.findPath(cubot.getWorld(), cubot.getX(), cubot.getY(), + ArrayList nodes = Pathfinder.findPath(unit.getWorld(), unit.getX(), unit.getY(), destX, destY, b); //Write to memory @@ -102,13 +103,13 @@ public class CubotLidar extends CubotHardwareModule { break; case LIDAR_GET_MAP: - if (cubot.spendEnergy(10)) { - char[][] mapInfo = cubot.getWorld().getMapInfo(); + if (unit.spendEnergy(10)) { + char[][] mapInfo = unit.getWorld().getMapInfo(); //Write map data to the location specified by register X int i = getCpu().getRegisterSet().getRegister("X").getValue(); - for (int x = 0; x < cubot.getWorld().getWorldSize(); x++) { - for (int y = 0; y < cubot.getWorld().getWorldSize(); y++) { + for (int x = 0; x < unit.getWorld().getWorldSize(); x++) { + for (int y = 0; y < unit.getWorld().getWorldSize(); y++) { getCpu().getMemory().set(i++, mapInfo[x][y]); } } @@ -116,13 +117,13 @@ public class CubotLidar extends CubotHardwareModule { break; case LIDAR_GET_WORLD_SIZE: - getCpu().getRegisterSet().getRegister("X").setValue(cubot.getWorld().getWorldSize()); - getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getWorld().getWorldSize()); + getCpu().getRegisterSet().getRegister("X").setValue(unit.getWorld().getWorldSize()); + getCpu().getRegisterSet().getRegister("Y").setValue(unit.getWorld().getWorldSize()); break; case LIDAR_GET_WORLD_POS: - getCpu().getRegisterSet().getRegister("X").setValue(cubot.getWorld().getX()); - getCpu().getRegisterSet().getRegister("Y").setValue(cubot.getWorld().getY()); + getCpu().getRegisterSet().getRegister("X").setValue(unit.getWorld().getX()); + getCpu().getRegisterSet().getRegister("Y").setValue(unit.getWorld().getY()); break; } diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/event/UserCreationListener.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/event/UserCreationListener.java index 08d78e0..c34c085 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/event/UserCreationListener.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/event/UserCreationListener.java @@ -50,13 +50,6 @@ public class UserCreationListener implements GameEventListener { cubot.getWorld().addObject(cubot); cubot.getWorld().incUpdatable(); - cubot.setEnergy(config.getInt("battery_max_energy")); - cubot.setMaxEnergy(config.getInt("battery_max_energy")); - - cubot.setHp(config.getInt("cubot_max_hp")); - cubot.setMaxHp(config.getInt("cubot_max_hp")); - cubot.setMaxShield(config.getInt("cubot_max_shield")); - cubot.setParent(user); user.setControlledUnit(cubot); @@ -81,6 +74,10 @@ public class UserCreationListener implements GameEventListener { e.printStackTrace(); } + cubot.setHp(config.getInt("cubot_max_hp")); + cubot.setMaxHp(config.getInt("cubot_max_hp")); + cubot.setMaxShield(config.getInt("cubot_max_shield")); + LogManager.LOGGER.fine("(Plugin) Handled User creation event (Cubot Plugin)"); } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java index 0d82c14..175f372 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java @@ -1,17 +1,19 @@ package net.simon987.npcplugin; import net.simon987.server.GameServer; +import net.simon987.server.game.objects.MessageReceiver; import net.simon987.server.game.objects.Structure; import net.simon987.server.game.objects.Updatable; import org.bson.Document; import org.bson.types.ObjectId; import java.awt.*; +import java.util.Arrays; /** * Game objects that regularly creates NonPlayerCharacters */ -public class Factory extends Structure implements Updatable { +public class Factory extends Structure implements Updatable, MessageReceiver { private static final int MAP_INFO = 0x0401; @@ -30,6 +32,15 @@ public class Factory extends Structure implements Updatable { */ private int cooldown = 0; + private boolean locked = true; + + /** + * If non-null, the next spawned NPC will be a HackedNPC and the program will be + * injected in its memory + */ + private char[] program; + private int programIndex = 0; + public Factory() { super(2, 2); } @@ -57,14 +68,7 @@ public class Factory extends Structure implements Updatable { Point p = getAdjacentTile(); if (p != null) { - NonPlayerCharacter npc = new HarvesterNPC(); - npc.setWorld(getWorld()); - npc.setObjectId(new ObjectId()); - npc.setX(p.x); - npc.setY(p.y); - getWorld().addObject(npc); - getWorld().incUpdatable(); - + NonPlayerCharacter npc = spawnNPC(p); settlement.addNpc(npc); } } @@ -75,4 +79,65 @@ public class Factory extends Structure implements Updatable { cooldown--; } } + + private NonPlayerCharacter spawnNPC(Point p) { + + NonPlayerCharacter npc; + if (programIndex == 0) { + npc = new HarvesterNPC(); + npc.setWorld(getWorld()); + npc.setObjectId(new ObjectId()); + npc.setX(p.x); + npc.setY(p.y); + getWorld().addObject(npc); + getWorld().incUpdatable(); + } else { + + npc = new HackedNPC(program); + npc.setWorld(getWorld()); + npc.setObjectId(new ObjectId()); + npc.setX(p.x); + npc.setY(p.y); + getWorld().addObject(npc); + getWorld().incUpdatable(); + + System.out.println("NEW HACKED NPC"); + this.locked = true; + } + + return npc; + } + + @Override + public boolean sendMessage(char[] message) { + + String strMessage = String.valueOf(message); + + System.out.println("Received message " + strMessage); + if (locked) { + Settlement settlement = NpcPlugin.settlementMap.get(getWorld().getId()); + + if (Arrays.equals(settlement.getPassword(), message)) { + System.out.println("Factory unlock"); + this.locked = false; + + return true; + } + System.out.println("Wrong password, " + strMessage + "!=" + String.valueOf(settlement.getPassword())); + } else if (programIndex <= 2048) { //todo config + + if (programIndex == 0) { + program = new char[2048]; + } + + System.arraycopy(message, 0, program, programIndex, message.length); + System.out.println("Factory append code: " + strMessage); + System.out.println("Wrote " + message.length + " chars"); + programIndex += message.length; + + return true; + } + + return false; + } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java new file mode 100644 index 0000000..ea85a61 --- /dev/null +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java @@ -0,0 +1,314 @@ +package net.simon987.npcplugin; + +import net.simon987.server.GameServer; +import net.simon987.server.assembly.*; +import net.simon987.server.game.item.Item; +import net.simon987.server.game.item.ItemVoid; +import net.simon987.server.game.objects.Action; +import net.simon987.server.game.objects.ControllableUnit; +import net.simon987.server.game.objects.Direction; +import net.simon987.server.game.objects.HardwareHost; +import net.simon987.server.user.User; +import org.bson.Document; +import org.json.simple.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, HardwareHost { + + private static final int MEM_SIZE = GameServer.INSTANCE.getConfig().getInt("hacked_npc_mem_size"); + + private CPU cpu; + /** + * List of attached hardware, 'modules' + */ + private Map hardwareAddresses = new HashMap<>(); + private Map, Integer> hardwareModules = new HashMap<>(); + + private Action currentAction = Action.IDLE; + private Action lastAction = Action.IDLE; + private ArrayList consoleMessagesBuffer = new ArrayList<>(30); //todo load from conf + private ArrayList lastConsoleMessagesBuffer = new ArrayList<>(30); + + HackedNPC(char[] program) { + + cpu = new CPU(); + + cpu.setMemory(new Memory(MEM_SIZE)); + cpu.setHardwareHost(this); + //Write program + boolean write = cpu.getMemory().write(0, program, 0, program.length); + System.out.println("Write " + write); + + for (Object serialisedHw : (List) NpcPlugin.DEFAULT_HACKED_NPC.get("hardware")) { + HardwareModule hardware = GameServer.INSTANCE.getRegistry().deserializeHardware((Document) serialisedHw, this); + hardware.setCpu(cpu); + attachHardware(hardware, ((Document) serialisedHw).getInteger("address")); + } + } + + public HackedNPC(Document document) { + super(document); + + setHp(document.getInteger("hp")); + setDirection(Direction.getDirection(document.getInteger("direction"))); + + cpu = new CPU(); + cpu.setHardwareHost(this); + cpu.setMemory(new Memory((Document) document.get("memory"))); + cpu.setRegisterSet(RegisterSet.deserialize((Document) document.get("registerSet"))); + + ArrayList hardwareList = (ArrayList) document.get("hardware"); + + for (Object serialisedHw : hardwareList) { + HardwareModule hardware = GameServer.INSTANCE.getRegistry().deserializeHardware((Document) serialisedHw, this); + hardware.setCpu(cpu); + attachHardware(hardware, ((Document) serialisedHw).getInteger("address")); + } + } + + @Override + public void update() { + + + System.out.println(Util.toHex(cpu.getMemory().getBytes())); + + //Execute code + System.out.println("HACKED NPC " + this.getObjectId()); + int timeout = Math.min(getEnergy(), 30); //todo get from config + cpu.reset(); + int cost = cpu.execute(timeout); + spendEnergy(cost); + + if (currentAction == Action.WALKING) { + if (spendEnergy(100)) { + if (!incrementLocation()) { + //Couldn't walk + currentAction = Action.IDLE; + } + } else { + currentAction = Action.IDLE; + } + } + + /* + * CurrentAction is set during the code execution and this function is called right after + * If no action as been set, the action sent to the client is the action in currentAction that + * was set last tick (IDLE) + */ + lastAction = currentAction; + currentAction = Action.IDLE; + + lastConsoleMessagesBuffer = new ArrayList<>(consoleMessagesBuffer); + consoleMessagesBuffer.clear(); + + for (HardwareModule module : hardwareAddresses.values()) { + module.update(); + } + } + + @Override + public void setKeyboardBuffer(ArrayList kbBuffer) { + } + + @Override + public void setParent(User user) { + } + + @Override + public User getParent() { + return null; + } + + @Override + public ArrayList getKeyboardBuffer() { + return null; + } + + @Override + public Memory getFloppyData() { + return null; + } + + + @Override + public void setAction(Action action) { + currentAction = action; + } + + @Override + public ArrayList getConsoleMessagesBuffer() { + return null; + } + + @Override + public int getConsoleMode() { + return 0; + } + + @Override + public CPU getCpu() { + return cpu; + } + + @Override + public void giveItem(Item item) { + //Overwrite item at current position + ((NpcInventory) getHardware(NpcInventory.class)).putItem(item); + } + + @Override + public void attachHardware(HardwareModule hardware, int address) { + hardwareAddresses.put(address, hardware); + hardwareModules.put(hardware.getClass(), address); + } + + @Override + public void detachHardware(int address) { + hardwareAddresses.remove(address); + + Class toRemove = null; + for (Class clazz : hardwareModules.keySet()) { + if (hardwareModules.get(clazz) == address) { + toRemove = clazz; + } + } + hardwareModules.remove(toRemove); + } + + @Override + public boolean hardwareInterrupt(int address, Status status) { + HardwareModule hardware = hardwareAddresses.get(address); + + if (hardware != null) { + hardware.handleInterrupt(status); + return true; + } else { + return false; + } + } + + @Override + public int hardwareQuery(int address) { + HardwareModule hardware = hardwareAddresses.get(address); + + if (hardware != null) { + return hardware.getId(); + } else { + return 0; + } + } + + public int getEnergy() { + NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); + return battery.getEnergy(); + } + + public void setEnergy(int energy) { + NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); + battery.setEnergy(energy); + } + + public boolean spendEnergy(int amount) { + + NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); + + if (battery.getEnergy() - amount < 0) { + return false; + } else { + battery.setEnergy(battery.getEnergy() - amount); + return true; + } + } + + @Override + public Document mongoSerialise() { + Document dbObject = super.mongoSerialise(); + + dbObject.put("direction", getDirection().ordinal()); + dbObject.put("hp", getHp()); + dbObject.put("action", lastAction.ordinal()); + + List hardwareList = new ArrayList<>(); + + for (Integer address : hardwareAddresses.keySet()) { + + HardwareModule hardware = hardwareAddresses.get(address); + + Document serialisedHw = hardware.mongoSerialise(); + serialisedHw.put("address", address); + hardwareList.add(serialisedHw); + } + + dbObject.put("hardware", hardwareList); + + dbObject.put("memory", cpu.getMemory().mongoSerialise()); + + dbObject.put("registerSet", cpu.getRegisterSet().mongoSerialise()); + return dbObject; + } + + public void storeEnergy(int amount) { + + NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); + battery.setEnergy(Math.min(battery.getEnergy() + amount, battery.getMaxEnergy())); + } + + private HardwareModule getHardware(Class clazz) { + return hardwareAddresses.get(hardwareModules.get(clazz)); + } + + public void setMaxEnergy(int maxEnergy) { + NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); + battery.setMaxEnergy(maxEnergy); + } + + public int getMaxEnergy() { + NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); + return battery.getMaxEnergy(); + } + + @Override + public boolean sendMessage(char[] message) { + return false; + } + + @Override + public void setCurrentAction(Action action) { + currentAction = action; + } + + @Override + public Action getCurrentAction() { + return currentAction; + } + + @Override + public JSONObject jsonSerialise() { + JSONObject json = super.jsonSerialise(); + + for (HardwareModule module : hardwareAddresses.values()) { + JSONObject hwJson = module.jsonSerialise(); + if (hwJson != null) { + json.put(module.getClass().getName(), hwJson); + } + } + + json.put("direction", getDirection().ordinal()); + NpcInventory inv = (NpcInventory) getHardware(NpcInventory.class); + Item item = inv.getItem(); + json.put("heldItem", item == null ? new ItemVoid().getId() : item.getId()); + json.put("hp", getHp()); + json.put("action", lastAction.ordinal()); + + return json; + } + + @Override + public JSONObject debugJsonSerialise() { + return jsonSerialise(); + } +} diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcBattery.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcBattery.java new file mode 100644 index 0000000..d5eb401 --- /dev/null +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcBattery.java @@ -0,0 +1,109 @@ +package net.simon987.npcplugin; + +import net.simon987.server.GameServer; +import net.simon987.server.assembly.HardwareModule; +import net.simon987.server.assembly.Status; +import net.simon987.server.game.objects.ControllableUnit; +import org.bson.Document; +import org.json.simple.JSONObject; + +public class NpcBattery extends HardwareModule { + + public static final int DEFAULT_ADDRESS = 0x010A; + + /** + * Hardware ID (Should be unique) + */ + public static final char HWID = 0x010A; + + /** + * Energy units in kJ + */ + private int energy; + + /** + * Maximum energy units in kJ + */ + private int maxEnergy; + + + private static final int BATTERY_POLL = 1; + private static final int BATTERY_GET_MAX_CAPACITY = 2; + + public NpcBattery(ControllableUnit unit) { + super(null, unit); + + energy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy"); + maxEnergy = GameServer.INSTANCE.getConfig().getInt("battery_max_energy"); + } + + public NpcBattery(Document document, ControllableUnit cubot) { + super(document, cubot); + + energy = document.getInteger("energy"); + maxEnergy = document.getInteger("max_energy"); + } + + @Override + public void handleInterrupt(Status status) { + + int a = getCpu().getRegisterSet().getRegister("A").getValue(); + + if (a == BATTERY_POLL) { + getCpu().getRegisterSet().getRegister("B").setValue(unit.getEnergy()); + + } else if (a == BATTERY_GET_MAX_CAPACITY) { + getCpu().getRegisterSet().getRegister("B").setValue(unit.getMaxEnergy()); + + } + } + + @Override + public char getId() { + return HWID; + } + + @Override + public JSONObject jsonSerialise() { + JSONObject json = new JSONObject(); + + json.put("energy", energy); + + return json; + } + + @Override + public JSONObject debugJsonSerialise() { + JSONObject json = jsonSerialise(); + + json.put("max_energy", maxEnergy); + + return json; + } + + @Override + public Document mongoSerialise() { + Document document = super.mongoSerialise(); + + document.put("energy", energy); + document.put("max_energy", maxEnergy); + + return document; + } + + public int getEnergy() { + return energy; + } + + public void setEnergy(int energy) { + this.energy = energy; + } + + public int getMaxEnergy() { + return maxEnergy; + } + + public void setMaxEnergy(int maxEnergy) { + this.maxEnergy = maxEnergy; + } +} diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcInventory.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcInventory.java new file mode 100644 index 0000000..43477eb --- /dev/null +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcInventory.java @@ -0,0 +1,109 @@ +package net.simon987.npcplugin; + +import net.simon987.server.GameServer; +import net.simon987.server.assembly.HardwareModule; +import net.simon987.server.assembly.Status; +import net.simon987.server.game.item.Item; +import net.simon987.server.game.objects.ControllableUnit; +import org.bson.Document; + + +public class NpcInventory extends HardwareModule { + + /** + * Hardware ID (Should be unique) + */ + static final char HWID = 0x0106; + + public static final int DEFAULT_ADDRESS = 0x0106; + + private static final int INV_CLEAR = 0; + private static final int INV_POLL = 1; + private static final int INV_SCAN = 3; + + private Item item; + + public NpcInventory(ControllableUnit unit) { + super(null, unit); + } + + public NpcInventory(Document document, ControllableUnit cubot) { + super(document, cubot); + + Document itemDoc = (Document) document.get("item"); + if (itemDoc != null) { + item = GameServer.INSTANCE.getRegistry().deserializeItem(itemDoc); + } + } + + public void putItem(Item item) { + this.item = item; + } + + private void scanItem() { + int x = getCpu().getRegisterSet().getRegister("X").getValue(); + item.digitize(unit.getCpu().getMemory(), x); + } + + public Item clearItem() { + + Item oldItem = item; + item.clear(unit); + item = null; + + return oldItem; + } + + @Override + public char getId() { + return HWID; + } + + public Item getItem() { + return item; + } + + @Override + public void handleInterrupt(Status status) { + + int a = getCpu().getRegisterSet().getRegister("A").getValue(); + + if (a == INV_POLL) { + char result; + if (item == null) { + result = 0; + } else { + result = item.poll(); + } + getCpu().getRegisterSet().getRegister("B").setValue(result); + + } else if (a == INV_CLEAR) { + if (unit.spendEnergy(100)) { + clearItem(); + } + } else if (a == INV_SCAN) { + if (unit.spendEnergy(200)) { + scanItem(); + clearItem(); + } + } + } + + @Override + public Document mongoSerialise() { + Document document = super.mongoSerialise(); + + if (item != null) { + document.put("item", item.mongoSerialise()); + } else { + document.put("item", null); + } + + return document; + } + + @Override + public String toString() { + return String.format("{NpcInventory [%s]}", item); + } +} \ No newline at end of file diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java index 8d6f3ad..e6b790d 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java @@ -13,13 +13,17 @@ import net.simon987.server.logging.LogManager; import net.simon987.server.plugin.ServerPlugin; import org.bson.Document; +import java.io.InputStream; import java.util.Map; +import java.util.Scanner; import java.util.concurrent.ConcurrentHashMap; public class NpcPlugin extends ServerPlugin { public static Map settlementMap; + public static Document DEFAULT_HACKED_NPC; + @Override public void init(GameServer gameServer) { @@ -39,14 +43,22 @@ public class NpcPlugin extends ServerPlugin { registry.registerGameObject(ElectricBox.class); registry.registerGameObject(Portal.class); registry.registerGameObject(VaultExitPortal.class); + registry.registerGameObject(HackedNPC.class); registry.registerHardware(RadioReceiverHardware.class); + registry.registerHardware(NpcBattery.class); + registry.registerHardware(NpcInventory.class); registry.registerTile(TileVaultFloor.ID, TileVaultFloor.class); registry.registerTile(TileVaultWall.ID, TileVaultWall.class); settlementMap = new ConcurrentHashMap<>(); + InputStream is = getClass().getClassLoader().getResourceAsStream("defaultHackedCubotHardware.json"); + Scanner scanner = new Scanner(is).useDelimiter("\\A"); + String json = scanner.next(); + DEFAULT_HACKED_NPC = Document.parse(json); + LogManager.LOGGER.info("(NPC Plugin) Initialised NPC plugin"); } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java index 667329c..0afc06c 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java @@ -59,6 +59,7 @@ public class Settlement implements MongoSerializable { this.world = world; this.difficultyLevel = DifficultyLevel.NORMAL; //TODO randomize ? + this.password = "12345678".toCharArray(); outerLoopFactory: for (int x = 2; x < 12; x++) { @@ -175,7 +176,7 @@ public class Settlement implements MongoSerializable { } document.put("factory", factory.getObjectId()); document.put("difficulty_level", difficultyLevel.ordinal()); - document.put("password", "1234567"); //todo + document.put("password", String.valueOf(password)); List npcArray = new ArrayList<>(npcs.size()); diff --git a/Plugin NPC/src/main/resources/defaultHackedCubotHardware.json b/Plugin NPC/src/main/resources/defaultHackedCubotHardware.json new file mode 100644 index 0000000..1784c2e --- /dev/null +++ b/Plugin NPC/src/main/resources/defaultHackedCubotHardware.json @@ -0,0 +1,62 @@ +{ + "hardware": [ + { + "type": "net.simon987.cubotplugin.CubotLeg", + "address": 1 + }, + { + "type": "net.simon987.cubotplugin.CubotLaser", + "address": 2 + }, + { + "type": "net.simon987.cubotplugin.CubotLidar", + "address": 3 + }, + { + "type": "net.simon987.cubotplugin.CubotDrill", + "address": 5 + }, + { + "type": "net.simon987.npcplugin.NpcInventory", + "item": null, + "address": 6 + }, + { + "type": "net.simon987.mischwplugin.RandomNumberGenerator", + "address": 7 + }, + { + "type": "net.simon987.mischwplugin.Clock", + "address": 8 + }, + { + "type": "net.simon987.cubotplugin.CubotHologram", + "color": 0, + "value": 0, + "string": "", + "mode": 0, + "address": 9 + }, + { + "type": "net.simon987.npcplugin.NpcBattery", + "energy": 60000, + "max_energy": 60000, + "address": 262 + }, + { + "type": "net.simon987.npcplugin.RadioReceiverHardware", + "cubot": { + "$oid": "5c1d43e40d3d2530aba636df" + }, + "address": 12 + }, + { + "type": "net.simon987.cubotplugin.CubotComPort", + "address": 13 + }, + { + "type": "net.simon987.cubotplugin.CubotCore", + "address": 14 + } + ] +} \ No newline at end of file diff --git a/Plugin NPC/src/main/resources/plugin.properties b/Plugin NPC/src/main/resources/plugin.properties index 91f14e5..bfd7fd6 100644 --- a/Plugin NPC/src/main/resources/plugin.properties +++ b/Plugin NPC/src/main/resources/plugin.properties @@ -1,3 +1,4 @@ classpath=net.simon987.npcplugin.NpcPlugin name=NPC Plugin -version=1.1 \ No newline at end of file +version=1.1 +depend=Cubot Plugin \ No newline at end of file diff --git a/Server/src/main/java/net/simon987/server/assembly/CPU.java b/Server/src/main/java/net/simon987/server/assembly/CPU.java index 38898bc..c25fc3f 100755 --- a/Server/src/main/java/net/simon987/server/assembly/CPU.java +++ b/Server/src/main/java/net/simon987/server/assembly/CPU.java @@ -60,6 +60,41 @@ public class CPU implements MongoSerializable { private static final char EXECUTION_COST_ADDR = 0x0050; private static final char EXECUTED_INS_ADDR = 0x0051; + public CPU() { + instructionSet = new DefaultInstructionSet(); + registerSet = new DefaultRegisterSet(); + codeSectionOffset = 0; + + instructionSet.add(new JmpInstruction(this)); + instructionSet.add(new JnzInstruction(this)); + instructionSet.add(new JzInstruction(this)); + instructionSet.add(new JgInstruction(this)); + instructionSet.add(new JgeInstruction(this)); + instructionSet.add(new JleInstruction(this)); + instructionSet.add(new JlInstruction(this)); + instructionSet.add(new PushInstruction(this)); + instructionSet.add(new PopInstruction(this)); + instructionSet.add(new CallInstruction(this)); + instructionSet.add(new RetInstruction(this)); + instructionSet.add(new MulInstruction(this)); + instructionSet.add(new DivInstruction(this)); + instructionSet.add(new JnsInstruction(this)); + instructionSet.add(new JsInstruction(this)); + instructionSet.add(new HwiInstruction(this)); + instructionSet.add(new HwqInstruction(this)); + instructionSet.add(new XchgInstruction(this)); + instructionSet.add(new JcInstruction(this)); + instructionSet.add(new JncInstruction(this)); + instructionSet.add(new JnoInstruction(this)); + instructionSet.add(new JoInstruction(this)); + instructionSet.add(new PushfInstruction(this)); + instructionSet.add(new PopfInstruction(this)); + instructionSet.add(new JnaInstruction(this)); + instructionSet.add(new JaInstruction(this)); + + status = new Status(); + } + /** * Creates a new CPU */ @@ -359,7 +394,6 @@ public class CPU implements MongoSerializable { cpu.codeSectionOffset = obj.getInteger("codeSegmentOffset"); - cpu.memory = new Memory((Document) obj.get("memory")); cpu.registerSet = RegisterSet.deserialize((Document) obj.get("registerSet")); @@ -379,6 +413,14 @@ public class CPU implements MongoSerializable { return memory; } + public void setMemory(Memory memory) { + this.memory = memory; + } + + public void setRegisterSet(RegisterSet registerSet) { + this.registerSet = registerSet; + } + public Status getStatus() { return status; } diff --git a/Server/src/main/java/net/simon987/server/assembly/HardwareModule.java b/Server/src/main/java/net/simon987/server/assembly/HardwareModule.java index 290365e..b352e6d 100644 --- a/Server/src/main/java/net/simon987/server/assembly/HardwareModule.java +++ b/Server/src/main/java/net/simon987/server/assembly/HardwareModule.java @@ -11,13 +11,14 @@ import org.json.simple.JSONObject; public abstract class HardwareModule implements MongoSerializable, JSONSerializable { private CPU cpu; + protected ControllableUnit unit; public HardwareModule() { } public HardwareModule(Document document, ControllableUnit unit) { - + this.unit = unit; } /** @@ -58,4 +59,12 @@ public abstract class HardwareModule implements MongoSerializable, JSONSerializa public JSONObject debugJsonSerialise() { return null; } + + @Override + public Document mongoSerialise() { + Document document = new Document(); + + document.put("type", getClass().getCanonicalName()); + return document; + } } diff --git a/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java b/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java index d326da3..989c1f0 100644 --- a/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java +++ b/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java @@ -7,9 +7,10 @@ import net.simon987.server.game.world.World; import net.simon987.server.user.User; import org.bson.types.ObjectId; +import java.awt.*; import java.util.ArrayList; -public interface ControllableUnit { +public interface ControllableUnit extends MessageReceiver, Rechargeable, Attackable { ObjectId getObjectId(); @@ -31,7 +32,11 @@ public interface ControllableUnit { int getY(); - void setAction(Action listening); + void setAction(Action action); + + void setCurrentAction(Action action); + + Action getCurrentAction(); World getWorld(); @@ -42,4 +47,9 @@ public interface ControllableUnit { CPU getCpu(); void giveItem(Item item); + + Point getFrontTile(); + + void setDirection(Direction direction); } + diff --git a/Server/src/main/resources/config.properties b/Server/src/main/resources/config.properties index dc7fd82..40806f5 100644 --- a/Server/src/main/resources/config.properties +++ b/Server/src/main/resources/config.properties @@ -71,6 +71,7 @@ harvester_hp_max=100 harvester_regen=5 harvester_biomass_drop_count=8 radio_tower_range=3 +hacked_npc_mem_size=5120 #Vaults vault_door_open_time=4 min_electric_box_count=1 diff --git a/Server/src/main/resources/static/js/mar.js b/Server/src/main/resources/static/js/mar.js index 1c7ae54..610f2fb 100644 --- a/Server/src/main/resources/static/js/mar.js +++ b/Server/src/main/resources/static/js/mar.js @@ -830,6 +830,7 @@ var ObjectType; ObjectType["OBSTACLE"] = "net.simon987.npcplugin.Obstacle"; ObjectType["ELECTRIC_BOX"] = "net.simon987.npcplugin.ElectricBox"; ObjectType["PORTAL"] = "net.simon987.npcplugin.Portal"; + ObjectType["HACKED_NPC"] = "net.simon987.npcplugin.HackedNPC"; })(ObjectType || (ObjectType = {})); var ItemType; (function (ItemType) { @@ -873,6 +874,8 @@ var GameObject = (function (_super) { return new ElectricBox(json); case ObjectType.PORTAL: return new Portal(json); + case ObjectType.HACKED_NPC: + return new HackedNPC(json); default: return null; } @@ -917,7 +920,7 @@ var Cubot = (function (_super) { _this.heldItem = json.heldItem; _this.direction = json.direction; _this.action = json.action; - _this.energy = json.energy; + _this.energy = _this.getEnergy(json); _this.cubotSprite = mar.game.make.sprite(0, 0, "sheet", null); _this.cubotSprite.anchor.set(0.5, 0); _this.addChild(_this.cubotSprite); @@ -949,6 +952,10 @@ var Cubot = (function (_super) { _this.setShield(false); return _this; } + + Cubot.prototype.getEnergy = function (json) { + return json["net.simon987.cubotplugin.CubotBattery"].energy; + }; Cubot.prototype.setShield = function (shield) { this.shieldBackSprite.visible = shield; this.shieldFrontSprite.visible = shield; @@ -1012,7 +1019,7 @@ var Cubot = (function (_super) { console.log("Updating Cubot object"); } this.action = json.action; - this.energy = json.energy; + this.energy = this.getEnergy(json); this.direction = json.direction; this.shield = json.shield; this.createInventory([json.heldItem]); @@ -1207,6 +1214,13 @@ var HarvesterNPC = (function (_super) { break; } }; + HarvesterNPC.prototype.getEnergy = function (json) { + if (json.hasOwnProperty("net.simon987.npcplugin.NpcBattery")) { + return json["net.simon987.npcplugin.NpcBattery"].energy; + } else { + return 0; + } + }; HarvesterNPC.prototype.updateObject = function (json) { if (DEBUG) { console.log("Updating Harvester NPC object"); @@ -1226,6 +1240,28 @@ var HarvesterNPC = (function (_super) { }; return HarvesterNPC; }(Cubot)); +var HackedNPC = (function (_super) { + __extends(HackedNPC, _super); + + function HackedNPC(json) { + var _this = _super.call(this, json) || this; + _this.updateDirection(); + _this.setText("Hacked NPC"); + _this.text.visible = false; + _this.tint = 0xE040FB; + return _this; + } + + HackedNPC.prototype.updateObject = function (json) { + _super.prototype.updateObject.call(this, json); + var holoHw = json["net.simon987.cubotplugin.CubotHologram"]; + this.updateHologram(holoHw.mode, holoHw.color, holoHw.value, holoHw.string); + }; + HackedNPC.prototype.getEnergy = function (json) { + return json["net.simon987.npcplugin.NpcBattery"].energy; + }; + return HackedNPC; +}(HarvesterNPC)); var BiomassBlob = (function (_super) { __extends(BiomassBlob, _super); function BiomassBlob(json) { diff --git a/Server/src/main/typescript/GameObject.ts b/Server/src/main/typescript/GameObject.ts index f649d9a..ff106c1 100644 --- a/Server/src/main/typescript/GameObject.ts +++ b/Server/src/main/typescript/GameObject.ts @@ -7,7 +7,8 @@ enum ObjectType { VAULT_DOOR = "net.simon987.npcplugin.VaultDoor", OBSTACLE = "net.simon987.npcplugin.Obstacle", ELECTRIC_BOX = "net.simon987.npcplugin.ElectricBox", - PORTAL = "net.simon987.npcplugin.Portal" + PORTAL = "net.simon987.npcplugin.Portal", + HACKED_NPC = "net.simon987.npcplugin.HackedNPC" } enum ItemType { @@ -59,7 +60,6 @@ abstract class GameObject extends Phaser.Plugin.Isometric.IsoSprite { switch (json.t) { case ObjectType.CUBOT: return new Cubot(json); - case ObjectType.BIOMASS: return new BiomassBlob(json); case ObjectType.HARVESTER_NPC: @@ -76,6 +76,8 @@ abstract class GameObject extends Phaser.Plugin.Isometric.IsoSprite { return new ElectricBox(json); case ObjectType.PORTAL: return new Portal(json); + case ObjectType.HACKED_NPC: + return new HackedNPC(json); default: return null; @@ -155,7 +157,7 @@ class Cubot extends GameObject { this.heldItem = json.heldItem; this.direction = json.direction; this.action = json.action; - this.energy = json.energy; + this.energy = this.getEnergy(json); this.cubotSprite = mar.game.make.sprite(0, 0, "sheet", null); this.cubotSprite.anchor.set(0.5, 0); @@ -197,6 +199,10 @@ class Cubot extends GameObject { this.setShield(false); } + protected getEnergy(json): number { + return json["net.simon987.cubotplugin.CubotBattery"].energy + } + public setShield(shield: boolean) { this.shieldBackSprite.visible = shield; this.shieldFrontSprite.visible = shield; @@ -277,7 +283,7 @@ class Cubot extends GameObject { } this.action = json.action; - this.energy = json.energy; + this.energy = this.getEnergy(json); this.direction = json.direction; this.shield = json.shield; @@ -333,7 +339,7 @@ class Cubot extends GameObject { this.setShield(this.shield > 0) } - private updateHologram(holoMode: HologramMode, holoColor: number, holoValue: number, holoStr: string): void { + protected updateHologram(holoMode: HologramMode, holoColor: number, holoValue: number, holoStr: string): void { let fillColor: string = (holoColor & 0xFFFFFF).toString(16); fillColor = "#" + ("000000".substr(fillColor.length) + fillColor); @@ -548,6 +554,14 @@ class HarvesterNPC extends Cubot { } } + protected getEnergy(json): number { + if (json.hasOwnProperty("net.simon987.npcplugin.NpcBattery")) { + return json["net.simon987.npcplugin.NpcBattery"].energy; + } else { + return 0; + } + } + updateObject(json) { if (DEBUG) { console.log("Updating Harvester NPC object") @@ -578,6 +592,30 @@ class HarvesterNPC extends Cubot { } +class HackedNPC extends HarvesterNPC { + + constructor(json) { + super(json); + + this.updateDirection(); + this.setText("Hacked NPC"); + this.text.visible = false; + this.tint = 0xE040FB; + } + + updateObject(json) { + super.updateObject(json); + + let holoHw = json["net.simon987.cubotplugin.CubotHologram"]; + this.updateHologram(holoHw.mode, holoHw.color, holoHw.value, holoHw.string); + } + + protected getEnergy(json): number { + return json["net.simon987.npcplugin.NpcBattery"].energy + } + +} + class BiomassBlob extends GameObject { From b361f87154fa5c5582616f68466acd7bf96b942c Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 22 Dec 2018 15:29:58 -0500 Subject: [PATCH 5/6] NPC Plugin refactoring --- .../java/net/simon987/cubotplugin/Cubot.java | 3 +- .../simon987/npcplugin/ExecuteCpuTask.java | 38 ++++++++++ .../java/net/simon987/npcplugin/Factory.java | 58 ++++++++------- .../net/simon987/npcplugin/HackedNPC.java | 71 ++++++++++--------- .../net/simon987/npcplugin/HarvesterNPC.java | 1 - .../net/simon987/npcplugin/NpcPlugin.java | 4 +- .../net/simon987/npcplugin/Settlement.java | 2 - .../server/game/objects/ControllableUnit.java | 2 +- .../server/websocket/SocketServer.java | 4 +- Server/src/main/resources/config.properties | 5 +- Server/src/main/resources/static/js/mar.js | 26 +++---- Server/src/main/typescript/GameClient.ts | 6 +- Server/src/main/typescript/GameObject.ts | 24 ++----- Server/src/main/typescript/mar.ts | 3 + 14 files changed, 146 insertions(+), 101 deletions(-) create mode 100644 Plugin NPC/src/main/java/net/simon987/npcplugin/ExecuteCpuTask.java diff --git a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java index f7693d3..600fdb6 100644 --- a/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java +++ b/Plugin Cubot/src/main/java/net/simon987/cubotplugin/Cubot.java @@ -18,8 +18,7 @@ import java.awt.*; import java.util.List; import java.util.*; -public class Cubot extends GameObject implements Updatable, ControllableUnit, MessageReceiver, - Attackable, Rechargeable, HardwareHost { +public class Cubot extends GameObject implements Updatable, ControllableUnit, MessageReceiver { private static final char MAP_INFO = 0x0200; diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/ExecuteCpuTask.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/ExecuteCpuTask.java new file mode 100644 index 0000000..3cde56d --- /dev/null +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/ExecuteCpuTask.java @@ -0,0 +1,38 @@ +package net.simon987.npcplugin; + +import net.simon987.server.GameServer; +import net.simon987.server.game.objects.Action; + +public class ExecuteCpuTask extends NPCTask { + + private static final int MAX_EXEC_TIME = GameServer.INSTANCE.getConfig().getInt("npc_exec_time"); + + @Override + public boolean checkCompleted() { + return false; + } + + @Override + public void tick(NonPlayerCharacter npc) { + + HackedNPC hNpc = (HackedNPC) npc; + + //Execute code + int timeout = Math.min(hNpc.getEnergy(), MAX_EXEC_TIME); + hNpc.getCpu().reset(); + int cost = hNpc.getCpu().execute(timeout); + hNpc.spendEnergy(cost); + + if (hNpc.getCurrentAction() == Action.WALKING) { + if (hNpc.spendEnergy(100)) { + if (hNpc.incrementLocation()) { + //Couldn't walk + hNpc.setCurrentAction(Action.IDLE); + } + } else { + hNpc.setCurrentAction(Action.IDLE); + } + } + + } +} diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java index 175f372..a7ce582 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java @@ -41,6 +41,8 @@ public class Factory extends Structure implements Updatable, MessageReceiver { private char[] program; private int programIndex = 0; + private static final int PROGRAM_SIZE = GameServer.INSTANCE.getConfig().getInt("factory_program_size"); + public Factory() { super(2, 2); } @@ -83,47 +85,57 @@ public class Factory extends Structure implements Updatable, MessageReceiver { private NonPlayerCharacter spawnNPC(Point p) { NonPlayerCharacter npc; + if (programIndex == 0) { - npc = new HarvesterNPC(); - npc.setWorld(getWorld()); - npc.setObjectId(new ObjectId()); - npc.setX(p.x); - npc.setY(p.y); - getWorld().addObject(npc); - getWorld().incUpdatable(); + npc = spawnRandomNpc(p); } else { - - npc = new HackedNPC(program); - npc.setWorld(getWorld()); - npc.setObjectId(new ObjectId()); - npc.setX(p.x); - npc.setY(p.y); - getWorld().addObject(npc); - getWorld().incUpdatable(); - - System.out.println("NEW HACKED NPC"); - this.locked = true; + npc = spawnHackedNpc(p); } return npc; } + private NonPlayerCharacter spawnRandomNpc(Point p) { + NonPlayerCharacter npc; + npc = new HarvesterNPC(); + npc.setWorld(getWorld()); + npc.setObjectId(new ObjectId()); + npc.setX(p.x); + npc.setY(p.y); + getWorld().addObject(npc); + getWorld().incUpdatable(); + return npc; + } + + private NonPlayerCharacter spawnHackedNpc(Point p) { + NonPlayerCharacter npc; + npc = new HackedNPC(program); + npc.setWorld(getWorld()); + npc.setObjectId(new ObjectId()); + npc.setX(p.x); + npc.setY(p.y); + getWorld().addObject(npc); + getWorld().incUpdatable(); + + this.locked = true; + this.programIndex = 0; + + return npc; + } + @Override public boolean sendMessage(char[] message) { String strMessage = String.valueOf(message); - System.out.println("Received message " + strMessage); if (locked) { Settlement settlement = NpcPlugin.settlementMap.get(getWorld().getId()); if (Arrays.equals(settlement.getPassword(), message)) { - System.out.println("Factory unlock"); this.locked = false; return true; } - System.out.println("Wrong password, " + strMessage + "!=" + String.valueOf(settlement.getPassword())); } else if (programIndex <= 2048) { //todo config if (programIndex == 0) { @@ -131,13 +143,11 @@ public class Factory extends Structure implements Updatable, MessageReceiver { } System.arraycopy(message, 0, program, programIndex, message.length); - System.out.println("Factory append code: " + strMessage); - System.out.println("Wrote " + message.length + " chars"); programIndex += message.length; return true; } - return false; + return true; } } diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java index ea85a61..904a54a 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java @@ -7,7 +7,7 @@ import net.simon987.server.game.item.ItemVoid; import net.simon987.server.game.objects.Action; import net.simon987.server.game.objects.ControllableUnit; import net.simon987.server.game.objects.Direction; -import net.simon987.server.game.objects.HardwareHost; +import net.simon987.server.logging.LogManager; import net.simon987.server.user.User; import org.bson.Document; import org.json.simple.JSONObject; @@ -17,9 +17,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, HardwareHost { +public class HackedNPC extends NonPlayerCharacter implements ControllableUnit { private static final int MEM_SIZE = GameServer.INSTANCE.getConfig().getInt("hacked_npc_mem_size"); + private static final boolean DIE_ON_NO_ENERGY = GameServer.INSTANCE.getConfig().getInt("hacked_npc_die_on_no_energy") != 0; private CPU cpu; /** @@ -39,15 +40,15 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, H cpu.setMemory(new Memory(MEM_SIZE)); cpu.setHardwareHost(this); - //Write program - boolean write = cpu.getMemory().write(0, program, 0, program.length); - System.out.println("Write " + write); + cpu.getMemory().write(0, program, 0, program.length); for (Object serialisedHw : (List) NpcPlugin.DEFAULT_HACKED_NPC.get("hardware")) { HardwareModule hardware = GameServer.INSTANCE.getRegistry().deserializeHardware((Document) serialisedHw, this); hardware.setCpu(cpu); attachHardware(hardware, ((Document) serialisedHw).getInteger("address")); } + + setTask(new ExecuteCpuTask()); } public HackedNPC(Document document) { @@ -68,37 +69,14 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, H hardware.setCpu(cpu); attachHardware(hardware, ((Document) serialisedHw).getInteger("address")); } + + setTask(new ExecuteCpuTask()); } @Override public void update() { + super.update(); - - System.out.println(Util.toHex(cpu.getMemory().getBytes())); - - //Execute code - System.out.println("HACKED NPC " + this.getObjectId()); - int timeout = Math.min(getEnergy(), 30); //todo get from config - cpu.reset(); - int cost = cpu.execute(timeout); - spendEnergy(cost); - - if (currentAction == Action.WALKING) { - if (spendEnergy(100)) { - if (!incrementLocation()) { - //Couldn't walk - currentAction = Action.IDLE; - } - } else { - currentAction = Action.IDLE; - } - } - - /* - * CurrentAction is set during the code execution and this function is called right after - * If no action as been set, the action sent to the client is the action in currentAction that - * was set last tick (IDLE) - */ lastAction = currentAction; currentAction = Action.IDLE; @@ -108,32 +86,49 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, H for (HardwareModule module : hardwareAddresses.values()) { module.update(); } + + //Don't bother calling checkCompleted() + getTask().tick(this); } @Override public void setKeyboardBuffer(ArrayList kbBuffer) { + LogManager.LOGGER.warning("Something went wrong here: Hacked NPC has no keyboard module" + + "@HackedNPC::setKeyBoardBuffer()"); + Thread.dumpStack(); } @Override public void setParent(User user) { + LogManager.LOGGER.warning("Something went wrong here: Hacked NPC has no parent" + + "@HackedNPC::setParent()"); + Thread.dumpStack(); } @Override public User getParent() { + LogManager.LOGGER.warning("Something went wrong here: Hacked NPC has no parent" + + "@HackedNPC::getParent()"); + Thread.dumpStack(); return null; } @Override public ArrayList getKeyboardBuffer() { + LogManager.LOGGER.warning("Something went wrong here: Hacked NPC has no keyboard module" + + "@HackedNPC::getKeyBoardBuffer()"); + Thread.dumpStack(); return null; } @Override public Memory getFloppyData() { + LogManager.LOGGER.warning("Something went wrong here: Hacked NPC has floppy data." + + "@HackedNPC::getFloppyData()"); + Thread.dumpStack(); return null; } - @Override public void setAction(Action action) { currentAction = action; @@ -141,11 +136,14 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, H @Override public ArrayList getConsoleMessagesBuffer() { - return null; + return lastConsoleMessagesBuffer; } @Override public int getConsoleMode() { + LogManager.LOGGER.warning("Something went wrong here: Hacked NPC has no console UI." + + "@HackedNPC::getConsoleMode()"); + Thread.dumpStack(); return 0; } @@ -210,6 +208,10 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, H public void setEnergy(int energy) { NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); battery.setEnergy(energy); + + if (energy == 0 && DIE_ON_NO_ENERGY) { + setDead(true); + } } public boolean spendEnergy(int amount) { @@ -217,6 +219,9 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit, H NpcBattery battery = (NpcBattery) getHardware(NpcBattery.class); if (battery.getEnergy() - amount < 0) { + if (DIE_ON_NO_ENERGY) { + setDead(true); + } return false; } else { battery.setEnergy(battery.getEnergy() - amount); diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java index d204f76..b78673e 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/HarvesterNPC.java @@ -30,7 +30,6 @@ public class HarvesterNPC extends NonPlayerCharacter { @Override public void update() { - super.update(); if (getSettlement() != null) { diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java index e6b790d..79251d3 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NpcPlugin.java @@ -30,7 +30,7 @@ public class NpcPlugin extends ServerPlugin { ServerConfiguration configuration = gameServer.getConfig(); GameRegistry registry = gameServer.getRegistry(); - listeners.add(new WorldCreationListener(configuration.getInt("factory_spawn_rate"))); + listeners.add(new WorldCreationListener(configuration.getInt("settlement_spawn_rate"))); listeners.add(new CpuInitialisationListener()); listeners.add(new VaultWorldUpdateListener(configuration)); listeners.add(new VaultCompleteListener()); @@ -54,6 +54,8 @@ public class NpcPlugin extends ServerPlugin { settlementMap = new ConcurrentHashMap<>(); + LogManager.LOGGER.fine("(NPC Plugin) Loading default HackedNPC settings from" + + " defaultHackedCubotHardware.json"); InputStream is = getClass().getClassLoader().getResourceAsStream("defaultHackedCubotHardware.json"); Scanner scanner = new Scanner(is).useDelimiter("\\A"); String json = scanner.next(); diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java index 0afc06c..4f7a1ba 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Settlement.java @@ -55,8 +55,6 @@ public class Settlement implements MongoSerializable { public Settlement(World world) throws WorldGenerationException { - System.out.println("SETTLING"); - this.world = world; this.difficultyLevel = DifficultyLevel.NORMAL; //TODO randomize ? this.password = "12345678".toCharArray(); diff --git a/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java b/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java index 989c1f0..3e6504a 100644 --- a/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java +++ b/Server/src/main/java/net/simon987/server/game/objects/ControllableUnit.java @@ -10,7 +10,7 @@ import org.bson.types.ObjectId; import java.awt.*; import java.util.ArrayList; -public interface ControllableUnit extends MessageReceiver, Rechargeable, Attackable { +public interface ControllableUnit extends MessageReceiver, Rechargeable, Attackable, HardwareHost { ObjectId getObjectId(); diff --git a/Server/src/main/java/net/simon987/server/websocket/SocketServer.java b/Server/src/main/java/net/simon987/server/websocket/SocketServer.java index 9030bc9..bec46e4 100644 --- a/Server/src/main/java/net/simon987/server/websocket/SocketServer.java +++ b/Server/src/main/java/net/simon987/server/websocket/SocketServer.java @@ -138,9 +138,9 @@ public class SocketServer { } else { ControllableUnit unit = user.getUser().getControlledUnit(); - json.put("c", charArraysToJSON(unit.getConsoleMessagesBuffer())); + json.put("console_message_buffer", charArraysToJSON(unit.getConsoleMessagesBuffer())); json.put("keys", intListToJSON(unit.getKeyboardBuffer())); - json.put("cm", unit.getConsoleMode()); + json.put("console_mode", unit.getConsoleMode()); sendJSONObject(user, json); } diff --git a/Server/src/main/resources/config.properties b/Server/src/main/resources/config.properties index 40806f5..8162a50 100644 --- a/Server/src/main/resources/config.properties +++ b/Server/src/main/resources/config.properties @@ -66,12 +66,15 @@ shield_energy_cost=50 npc_lifetime=1024 npc_max_factory_distance=3 factory_max_npc_count=16 -factory_spawn_rate=5 +factory_program_size=1024 +settlement_spawn_rate=5 harvester_hp_max=100 harvester_regen=5 harvester_biomass_drop_count=8 radio_tower_range=3 hacked_npc_mem_size=5120 +npc_exec_time=5 +hacked_npc_die_on_no_energy=1 #Vaults vault_door_open_time=4 min_electric_box_count=1 diff --git a/Server/src/main/resources/static/js/mar.js b/Server/src/main/resources/static/js/mar.js index 610f2fb..b34b8c1 100644 --- a/Server/src/main/resources/static/js/mar.js +++ b/Server/src/main/resources/static/js/mar.js @@ -276,6 +276,9 @@ var config = { lowEnergy: 100, otherCubotAlpha: 0.6, }, + hackedNpc: { + tint: 0xE040FB, + }, biomass: { tint: 0x63B85F, tintHover: 0x00FF00, @@ -537,9 +540,9 @@ var TickListener = (function () { mar.client.keyboardBuffer.keys = message.keys; } if (message.c != undefined) { - mar.client.consoleScreen.handleConsoleBufferUpdate(message.c, message.cm); + mar.client.consoleScreen.handleConsoleBufferUpdate(message.console_message_buffer, message.console_mode); if (DEBUG) { - console.log("[MAR] Received " + message.c.length + " console message(s)"); + console.log("[MAR] Received " + message.console_message_buffer.length + " console message(s)"); } } }; @@ -921,6 +924,7 @@ var Cubot = (function (_super) { _this.direction = json.direction; _this.action = json.action; _this.energy = _this.getEnergy(json); + _this.baseTint = config.cubot.tint; _this.cubotSprite = mar.game.make.sprite(0, 0, "sheet", null); _this.cubotSprite.anchor.set(0.5, 0); _this.addChild(_this.cubotSprite); @@ -952,7 +956,6 @@ var Cubot = (function (_super) { _this.setShield(false); return _this; } - Cubot.prototype.getEnergy = function (json) { return json["net.simon987.cubotplugin.CubotBattery"].energy; }; @@ -963,11 +966,11 @@ var Cubot = (function (_super) { Cubot.prototype.onTileHover = function () { mar.game.add.tween(this).to({ isoZ: 45 }, 200, Phaser.Easing.Quadratic.InOut, true); mar.game.add.tween(this.scale).to({ x: 1.2, y: 1.2 }, 200, Phaser.Easing.Linear.None, true); - this.cubotSprite.tint = config.cubot.hoverTint; if (this.text !== undefined) { this.text.visible = true; } this.hovered = true; + this.cubotSprite.tint = this.getTint(); }; Cubot.prototype.onTileExit = function () { mar.game.add.tween(this).to({ isoZ: 15 }, 400, Phaser.Easing.Bounce.Out, true); @@ -1007,7 +1010,7 @@ var Cubot = (function (_super) { return config.cubot.lowEnergyTint; } else { - return config.cubot.tint; + return this.baseTint; } } else { @@ -1195,9 +1198,6 @@ var HarvesterNPC = (function (_super) { _this.text.visible = false; return _this; } - HarvesterNPC.prototype.getTint = function () { - return config.cubot.tint; - }; HarvesterNPC.prototype.updateDirection = function () { switch (this.direction) { case Direction.NORTH: @@ -1218,7 +1218,7 @@ var HarvesterNPC = (function (_super) { if (json.hasOwnProperty("net.simon987.npcplugin.NpcBattery")) { return json["net.simon987.npcplugin.NpcBattery"].energy; } else { - return 0; + return 1000; } }; HarvesterNPC.prototype.updateObject = function (json) { @@ -1242,24 +1242,20 @@ var HarvesterNPC = (function (_super) { }(Cubot)); var HackedNPC = (function (_super) { __extends(HackedNPC, _super); - function HackedNPC(json) { var _this = _super.call(this, json) || this; _this.updateDirection(); _this.setText("Hacked NPC"); _this.text.visible = false; - _this.tint = 0xE040FB; + _this.baseTint = config.hackedNpc.tint; + _this.cubotSprite.tint = _this.baseTint; return _this; } - HackedNPC.prototype.updateObject = function (json) { _super.prototype.updateObject.call(this, json); var holoHw = json["net.simon987.cubotplugin.CubotHologram"]; this.updateHologram(holoHw.mode, holoHw.color, holoHw.value, holoHw.string); }; - HackedNPC.prototype.getEnergy = function (json) { - return json["net.simon987.npcplugin.NpcBattery"].energy; - }; return HackedNPC; }(HarvesterNPC)); var BiomassBlob = (function (_super) { diff --git a/Server/src/main/typescript/GameClient.ts b/Server/src/main/typescript/GameClient.ts index 5e5ee96..8758637 100644 --- a/Server/src/main/typescript/GameClient.ts +++ b/Server/src/main/typescript/GameClient.ts @@ -85,10 +85,12 @@ class TickListener implements MessageListener { //Update console screen if (message.c != undefined) { - mar.client.consoleScreen.handleConsoleBufferUpdate(message.c, message.cm as ConsoleMode); + mar.client.consoleScreen.handleConsoleBufferUpdate( + message.console_message_buffer, + message.console_mode as ConsoleMode); if (DEBUG) { - console.log("[MAR] Received " + message.c.length + " console message(s)") + console.log("[MAR] Received " + message.console_message_buffer.length + " console message(s)") } } } diff --git a/Server/src/main/typescript/GameObject.ts b/Server/src/main/typescript/GameObject.ts index ff106c1..316eca5 100644 --- a/Server/src/main/typescript/GameObject.ts +++ b/Server/src/main/typescript/GameObject.ts @@ -138,6 +138,7 @@ class Cubot extends GameObject { protected cubotSprite: Phaser.Sprite; private shieldBackSprite: Phaser.Sprite; private shieldFrontSprite: Phaser.Sprite; + protected baseTint: number; constructor(json) { //workaround for topological sort, needs sprite dimensions @@ -158,6 +159,7 @@ class Cubot extends GameObject { this.direction = json.direction; this.action = json.action; this.energy = this.getEnergy(json); + this.baseTint = config.cubot.tint; this.cubotSprite = mar.game.make.sprite(0, 0, "sheet", null); this.cubotSprite.anchor.set(0.5, 0); @@ -213,13 +215,12 @@ class Cubot extends GameObject { mar.game.add.tween(this).to({isoZ: 45}, 200, Phaser.Easing.Quadratic.InOut, true); mar.game.add.tween(this.scale).to({x: 1.2, y: 1.2}, 200, Phaser.Easing.Linear.None, true); - this.cubotSprite.tint = config.cubot.hoverTint; - if (this.text !== undefined) { this.text.visible = true; } this.hovered = true; + this.cubotSprite.tint = this.getTint(); } @@ -269,7 +270,7 @@ class Cubot extends GameObject { if (this.energy <= config.cubot.lowEnergy) { return config.cubot.lowEnergyTint; } else { - return config.cubot.tint; + return this.baseTint; } } else { return config.cubot.hoverTint; @@ -530,13 +531,6 @@ class HarvesterNPC extends Cubot { this.text.visible = false; } - /** - * Needs to be overridden because Cubot() calls getTint() when initialised - */ - public getTint() { - return config.cubot.tint; - } - public updateDirection() { switch (this.direction) { case Direction.NORTH: @@ -558,7 +552,7 @@ class HarvesterNPC extends Cubot { if (json.hasOwnProperty("net.simon987.npcplugin.NpcBattery")) { return json["net.simon987.npcplugin.NpcBattery"].energy; } else { - return 0; + return 1000; //arbitrary number so that the lowEnergy color thresh doesn't trigger } } @@ -600,7 +594,8 @@ class HackedNPC extends HarvesterNPC { this.updateDirection(); this.setText("Hacked NPC"); this.text.visible = false; - this.tint = 0xE040FB; + this.baseTint = config.hackedNpc.tint; + this.cubotSprite.tint = this.baseTint; } updateObject(json) { @@ -609,11 +604,6 @@ class HackedNPC extends HarvesterNPC { let holoHw = json["net.simon987.cubotplugin.CubotHologram"]; this.updateHologram(holoHw.mode, holoHw.color, holoHw.value, holoHw.string); } - - protected getEnergy(json): number { - return json["net.simon987.npcplugin.NpcBattery"].energy - } - } diff --git a/Server/src/main/typescript/mar.ts b/Server/src/main/typescript/mar.ts index 4c3167d..a7b6388 100644 --- a/Server/src/main/typescript/mar.ts +++ b/Server/src/main/typescript/mar.ts @@ -18,6 +18,9 @@ let config = { lowEnergy: 100, //Low energy threshold to change color otherCubotAlpha: 0.6, }, + hackedNpc: { + tint: 0xE040FB, + }, biomass: { tint: 0x63B85F, tintHover: 0x00FF00, From 5f95c17aed15a624ea4e067f7669cca5e5d60788 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 22 Dec 2018 17:48:29 -0500 Subject: [PATCH 6/6] More refactoring, updated mongodb driver + transactions on supported clusters --- Plugin Cubot/Plugin Cubot.iml | 4 ++- Plugin Misc HW/Plugin Misc HW.iml | 4 ++- Plugin NPC/Plugin NPC.iml | 4 ++- .../java/net/simon987/npcplugin/Factory.java | 20 ++++++++------ .../net/simon987/npcplugin/HackedNPC.java | 20 ++++++++++++++ .../npcplugin/NonPlayerCharacter.java | 12 +-------- .../event/WorldCreationListener.java | 3 ++- Plugin Plant/Plugin Plant.iml | 4 ++- Server/Server.iml | 4 ++- Server/pom.xml | 4 +-- .../java/net/simon987/server/GameServer.java | 26 +++++++++++++++---- .../main/java/net/simon987/server/Main.java | 1 + .../simon987/server/game/GameUniverse.java | 4 +-- Server/src/main/resources/config.properties | 4 +-- Server/src/main/resources/static/css/mar.css | 1 - Server/src/main/resources/static/js/mar.js | 4 +-- Server/src/main/resources/templates/play.vm | 9 +------ Server/src/main/typescript/GameObject.ts | 4 +-- 18 files changed, 83 insertions(+), 49 deletions(-) diff --git a/Plugin Cubot/Plugin Cubot.iml b/Plugin Cubot/Plugin Cubot.iml index 6182e32..f96bbb7 100644 --- a/Plugin Cubot/Plugin Cubot.iml +++ b/Plugin Cubot/Plugin Cubot.iml @@ -20,7 +20,9 @@ - + + + diff --git a/Plugin Misc HW/Plugin Misc HW.iml b/Plugin Misc HW/Plugin Misc HW.iml index e8b738c..7e03db0 100644 --- a/Plugin Misc HW/Plugin Misc HW.iml +++ b/Plugin Misc HW/Plugin Misc HW.iml @@ -19,7 +19,9 @@ - + + + diff --git a/Plugin NPC/Plugin NPC.iml b/Plugin NPC/Plugin NPC.iml index df01d12..b9c98db 100644 --- a/Plugin NPC/Plugin NPC.iml +++ b/Plugin NPC/Plugin NPC.iml @@ -22,7 +22,9 @@ - + + + diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java index a7ce582..b1ae4cb 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/Factory.java @@ -65,6 +65,13 @@ public class Factory extends Structure implements Updatable, MessageReceiver { Settlement settlement = NpcPlugin.settlementMap.get(getWorld().getId()); + if (settlement == null) { + //Only happens when server is killed during save function + getWorld().decUpdatable(); + setDead(true); + return; + } + if (cooldown == 0) { if (settlement.getNpcs().size() < MAX_NPC_COUNT) { Point p = getAdjacentTile(); @@ -72,6 +79,9 @@ public class Factory extends Structure implements Updatable, MessageReceiver { if (p != null) { NonPlayerCharacter npc = spawnNPC(p); settlement.addNpc(npc); + + getWorld().addObject(npc); + getWorld().incUpdatable(); } } @@ -102,8 +112,6 @@ public class Factory extends Structure implements Updatable, MessageReceiver { npc.setObjectId(new ObjectId()); npc.setX(p.x); npc.setY(p.y); - getWorld().addObject(npc); - getWorld().incUpdatable(); return npc; } @@ -114,8 +122,6 @@ public class Factory extends Structure implements Updatable, MessageReceiver { npc.setObjectId(new ObjectId()); npc.setX(p.x); npc.setY(p.y); - getWorld().addObject(npc); - getWorld().incUpdatable(); this.locked = true; this.programIndex = 0; @@ -126,8 +132,6 @@ public class Factory extends Structure implements Updatable, MessageReceiver { @Override public boolean sendMessage(char[] message) { - String strMessage = String.valueOf(message); - if (locked) { Settlement settlement = NpcPlugin.settlementMap.get(getWorld().getId()); @@ -136,10 +140,10 @@ public class Factory extends Structure implements Updatable, MessageReceiver { return true; } - } else if (programIndex <= 2048) { //todo config + } else if (programIndex <= PROGRAM_SIZE) { if (programIndex == 0) { - program = new char[2048]; + program = new char[PROGRAM_SIZE]; } System.arraycopy(message, 0, program, programIndex, message.length); diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java index 904a54a..fb3fcb0 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/HackedNPC.java @@ -2,6 +2,7 @@ package net.simon987.npcplugin; import net.simon987.server.GameServer; import net.simon987.server.assembly.*; +import net.simon987.server.event.ObjectDeathEvent; import net.simon987.server.game.item.Item; import net.simon987.server.game.item.ItemVoid; import net.simon987.server.game.objects.Action; @@ -87,6 +88,11 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit { module.update(); } + //Self-destroy when age limit is reached + if (getAge() >= NonPlayerCharacter.LIFETIME) { + setDead(true); + } + //Don't bother calling checkCompleted() getTask().tick(this); } @@ -312,6 +318,20 @@ public class HackedNPC extends NonPlayerCharacter implements ControllableUnit { return json; } + @Override + public boolean onDeadCallback() { + + getWorld().decUpdatable(); + + if (getSettlement() != null && getSettlement().getNpcs() != null) { + getSettlement().getNpcs().remove(this); + } + + GameServer.INSTANCE.getEventDispatcher().dispatch(new ObjectDeathEvent(this)); + + return false; + } + @Override public JSONObject debugJsonSerialise() { return jsonSerialise(); diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java index 8ad7c65..ddabc73 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/NonPlayerCharacter.java @@ -43,12 +43,6 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable private Settlement settlement; - /** - * If set to true, the NPC will be destroyed next tick if it is - * not linked to a Factory - */ - private boolean selfDestroyNextTick = false; - /** * Age of the npc, in ticks */ @@ -92,11 +86,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable //Destroy NPCs that are not linked with a Settlement if (settlement == null) { - if (selfDestroyNextTick) { - setDead(true); - } - - selfDestroyNextTick = true; + setDead(true); } //Heal the NPC diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java index 609e727..aae031c 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/event/WorldCreationListener.java @@ -37,7 +37,8 @@ public class WorldCreationListener implements GameEventListener { World world = (World) event.getSource(); try { - NpcPlugin.settlementMap.put(world.getId(), new Settlement(world)); + Settlement settlement = new Settlement(world); + NpcPlugin.settlementMap.put(world.getId(), settlement); } catch (WorldGenerationException e) { LogManager.LOGGER.fine(String.format("Exception during settlement generation: %s.", e.getMessage())); diff --git a/Plugin Plant/Plugin Plant.iml b/Plugin Plant/Plugin Plant.iml index df01d12..b9c98db 100644 --- a/Plugin Plant/Plugin Plant.iml +++ b/Plugin Plant/Plugin Plant.iml @@ -22,7 +22,9 @@ - + + + diff --git a/Server/Server.iml b/Server/Server.iml index badff86..fbb67a2 100644 --- a/Server/Server.iml +++ b/Server/Server.iml @@ -21,7 +21,9 @@ - + + + diff --git a/Server/pom.xml b/Server/pom.xml index 88c0c53..07c5697 100644 --- a/Server/pom.xml +++ b/Server/pom.xml @@ -106,8 +106,8 @@ org.mongodb - mongo-java-driver - 3.7.0 + mongodb-driver-sync + 3.9.1 org.springframework.security diff --git a/Server/src/main/java/net/simon987/server/GameServer.java b/Server/src/main/java/net/simon987/server/GameServer.java index 4777c42..8b542a5 100644 --- a/Server/src/main/java/net/simon987/server/GameServer.java +++ b/Server/src/main/java/net/simon987/server/GameServer.java @@ -1,9 +1,7 @@ package net.simon987.server; -import com.mongodb.MongoClient; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoCursor; -import com.mongodb.client.MongoDatabase; +import com.mongodb.MongoClientException; +import com.mongodb.client.*; import com.mongodb.client.model.ReplaceOptions; import net.simon987.server.crypto.CryptoProvider; import net.simon987.server.crypto.SecretKeyGenerator; @@ -58,7 +56,9 @@ public class GameServer implements Runnable { public GameServer() { this.config = new ServerConfiguration("config.properties"); - mongo = new MongoClient(config.getString("mongo_address"), config.getInt("mongo_port")); + String connString = String.format("mongodb://%s:%d", + config.getString("mongo_address"), config.getInt("mongo_port")); + mongo = MongoClients.create(connString); MongoDatabase db = mongo.getDatabase(config.getString("mongo_dbname")); MongoCollection userCollection = db.getCollection("user"); @@ -243,7 +243,16 @@ public class GameServer implements Runnable { public void save() { LogManager.LOGGER.info("Saving to MongoDB | W:" + gameUniverse.getWorldCount() + " | U:" + gameUniverse.getUserCount()); + + ClientSession session = null; try { + try { + session = mongo.startSession(); + session.startTransaction(); + } catch (MongoClientException e) { + LogManager.LOGGER.fine("Could not create mongoDB session, will not start a transaction."); + } + MongoDatabase db = mongo.getDatabase(config.getString("mongo_dbname")); ReplaceOptions updateOptions = new ReplaceOptions(); updateOptions.upsert(true); @@ -284,11 +293,18 @@ public class GameServer implements Runnable { //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); + if (session != null) { + session.commitTransaction(); + } LogManager.LOGGER.info("" + insertedWorlds + " worlds saved, " + unloaded_worlds + " unloaded"); } catch (Exception e) { LogManager.LOGGER.severe("Problem happened during save function"); e.printStackTrace(); + + if (session != null) { + session.commitTransaction(); + } } } diff --git a/Server/src/main/java/net/simon987/server/Main.java b/Server/src/main/java/net/simon987/server/Main.java index a81a075..ca351a4 100644 --- a/Server/src/main/java/net/simon987/server/Main.java +++ b/Server/src/main/java/net/simon987/server/Main.java @@ -8,6 +8,7 @@ import spark.Spark; public class Main { public static void main(String[] args) { + ServerConfiguration config = new ServerConfiguration("config.properties"); LogManager.initialize(config); diff --git a/Server/src/main/java/net/simon987/server/game/GameUniverse.java b/Server/src/main/java/net/simon987/server/game/GameUniverse.java index d3415a6..85c3f20 100644 --- a/Server/src/main/java/net/simon987/server/game/GameUniverse.java +++ b/Server/src/main/java/net/simon987/server/game/GameUniverse.java @@ -1,6 +1,6 @@ package net.simon987.server.game; -import com.mongodb.MongoClient; +import com.mongodb.client.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import com.mongodb.client.MongoDatabase; @@ -20,7 +20,6 @@ import java.util.concurrent.ConcurrentHashMap; public class GameUniverse { - //private ArrayList worlds; private ConcurrentHashMap worlds; //username:user private ConcurrentHashMap users; @@ -233,6 +232,7 @@ public class GameUniverse { } LogManager.LOGGER.severe("Couldn't find object: " + id); + Thread.dumpStack(); return null; } diff --git a/Server/src/main/resources/config.properties b/Server/src/main/resources/config.properties index 8162a50..391d76a 100644 --- a/Server/src/main/resources/config.properties +++ b/Server/src/main/resources/config.properties @@ -40,7 +40,7 @@ wg_maxCopperCount=2 wg_fluidCenterPointMin=0 wg_fluidCenterPointMax=2 #CPU -tick_length=1000 +tick_length=50 org_offset=512 stack_bottom=65536 memory_size=65536 @@ -67,7 +67,7 @@ npc_lifetime=1024 npc_max_factory_distance=3 factory_max_npc_count=16 factory_program_size=1024 -settlement_spawn_rate=5 +settlement_spawn_rate=35 harvester_hp_max=100 harvester_regen=5 harvester_biomass_drop_count=8 diff --git a/Server/src/main/resources/static/css/mar.css b/Server/src/main/resources/static/css/mar.css index 0d10035..74042f6 100644 --- a/Server/src/main/resources/static/css/mar.css +++ b/Server/src/main/resources/static/css/mar.css @@ -115,7 +115,6 @@ .bottom-panel { min-height: 18px; max-height: 100%; - height: 235px; width: 100%; position: fixed; bottom: 0; diff --git a/Server/src/main/resources/static/js/mar.js b/Server/src/main/resources/static/js/mar.js index b34b8c1..6ea23c9 100644 --- a/Server/src/main/resources/static/js/mar.js +++ b/Server/src/main/resources/static/js/mar.js @@ -1368,7 +1368,7 @@ var VaultDoor = (function (_super) { _this.anchor.set(0.55, 0.55); _this.inputEnabled = true; _this.events.onInputDown.add(function (self) { - Debug.goToHex("7FFF", "7FFF", "v" + self.id + "-"); + Debug.goToHex("7FFF", "7FFF", "v" + self.id); document.body.style.cursor = 'default'; document.body.setAttribute("title", ""); }, _this); @@ -1449,7 +1449,7 @@ var ElectricBox = (function (_super) { var Portal = (function (_super) { __extends(Portal, _super); function Portal(json) { - var _this = _super.call(this, Util.getIsoX(json.x), Util.getIsoY(json.y), 15, "sheet", "objects/Portal") || this; + var _this = _super.call(this, Util.getIsoX(json.x), Util.getIsoY(json.y), 15, "sheet", "objects/portal") || this; _this.anchor.set(0.5, 0.3); _this.tint = config.portal.tint; _this.setText("Portal"); diff --git a/Server/src/main/resources/templates/play.vm b/Server/src/main/resources/templates/play.vm index 678ff99..9761245 100644 --- a/Server/src/main/resources/templates/play.vm +++ b/Server/src/main/resources/templates/play.vm @@ -118,11 +118,7 @@ #parse("footer.vm") -##Console - - -
+
@@ -151,7 +147,6 @@
-

- -