Added basic Radio Tower functionality #32

Keypress buffer is cleared on code upload
This commit is contained in:
simon 2017-12-29 21:49:42 -05:00
parent 5afa767b4a
commit ef7f573256
15 changed files with 391 additions and 12 deletions

View File

@ -0,0 +1,84 @@
package net.simon987.cubotplugin;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import net.simon987.server.game.GameObject;
import net.simon987.server.game.Programmable;
import org.json.simple.JSONObject;
import java.awt.*;
import java.util.ArrayList;
public class ComPort extends CpuHardware {
public static final char HWID = 0xD;
public static final int DEFAULT_ADDRESS = 0xD;
private Cubot cubot;
private static final int POLL = 1;
private static final int OUT = 2;
public ComPort(Cubot cubot) {
this.cubot = cubot;
}
private static final int MESSAGE_LENGTH = 8;
@Override
public void handleInterrupt(Status status) {
int a = getCpu().getRegisterSet().getRegister("A").getValue();
if (a == POLL) {
/* No-op */
} else if (a == OUT) {
//Get object directly in front of the Cubot
Point frontTile = cubot.getFrontTile();
ArrayList<GameObject> objects = cubot.getWorld().getGameObjectsAt(frontTile.x, frontTile.y);
if (objects.size() > 0 && objects.get(0) instanceof Programmable) {
int x = getCpu().getRegisterSet().getRegister("X").getValue();
if (x + MESSAGE_LENGTH >= getCpu().getMemory().getWords().length) {
//todo set interrupt ?
getCpu().getStatus().setErrorFlag(true);
} else {
//Get MESSAGE_LENGTH-word message pointed by X
char[] message = new char[MESSAGE_LENGTH];
System.arraycopy(getCpu().getMemory().getWords(), x, message, 0, MESSAGE_LENGTH);
//Send it to the Programmable object
((Programmable) objects.get(0)).sendMessage(message);
}
}
}
}
@Override
public char getId() {
return HWID;
}
@Override
public JSONObject serialise() {
JSONObject json = new JSONObject();
json.put("hwid", (int) HWID);
json.put("cubot", cubot.getObjectId());
return json;
}
public static ComPort deserialize(JSONObject json) {
return new ComPort((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) json.get("cubot")));
}
}

View File

@ -225,4 +225,9 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
HEX, HEX,
STRING STRING
} }
@Override
public void setAction(Action action) {
currentAction = action;
}
} }

View File

@ -62,8 +62,6 @@ public class CubotLaser extends CpuHardware {
} }
} }
} }
} else {
System.out.println("\n\n\n\n\n It did it");
} }

View File

@ -58,6 +58,8 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
return CubotBattery.deserialize(hwJson); return CubotBattery.deserialize(hwJson);
case CubotFloppyDrive.HWID: case CubotFloppyDrive.HWID:
return CubotFloppyDrive.deserialize(hwJson); return CubotFloppyDrive.deserialize(hwJson);
case ComPort.HWID:
return ComPort.deserialize(hwJson);
} }
return null; return null;

View File

@ -5,7 +5,6 @@ import net.simon987.server.assembly.CPU;
import net.simon987.server.event.CpuInitialisationEvent; import net.simon987.server.event.CpuInitialisationEvent;
import net.simon987.server.event.GameEvent; import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventListener; import net.simon987.server.event.GameEventListener;
import net.simon987.server.logging.LogManager;
import net.simon987.server.user.User; import net.simon987.server.user.User;
public class CpuInitialisationListener implements GameEventListener { public class CpuInitialisationListener implements GameEventListener {
@ -16,7 +15,7 @@ public class CpuInitialisationListener implements GameEventListener {
@Override @Override
public void handle(GameEvent event) { public void handle(GameEvent event) {
LogManager.LOGGER.fine("(Plugin) Handled CPU Initialisation event (Cubot Plugin)"); //LogManager.LOGGER.fine("(Plugin) Handled CPU Initialisation event (Cubot Plugin)");
CPU cpu = (CPU) event.getSource(); CPU cpu = (CPU) event.getSource();
User user = ((CpuInitialisationEvent) event).getUser(); User user = ((CpuInitialisationEvent) event).getUser();
@ -39,6 +38,8 @@ public class CpuInitialisationListener implements GameEventListener {
batteryHw.setCpu(cpu); batteryHw.setCpu(cpu);
CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit()); CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit());
floppyHw.setCpu(cpu); floppyHw.setCpu(cpu);
ComPort comPortHw = new ComPort((Cubot) user.getControlledUnit());
comPortHw.setCpu(cpu);
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS); cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS); cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS);
@ -50,5 +51,6 @@ public class CpuInitialisationListener implements GameEventListener {
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS); cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS); cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS); cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS);
cpu.attachHardware(comPortHw, ComPort.DEFAULT_ADDRESS);
} }
} }

View File

@ -124,7 +124,7 @@ public class Factory extends GameObject implements Updatable {
factory.setX((int) (long) json.get("x")); factory.setX((int) (long) json.get("x"));
factory.setY((int) (long) json.get("y")); factory.setY((int) (long) json.get("y"));
factory.tmpNpcArray = (Object[]) ((JSONArray) json.get("n")).toArray(); factory.tmpNpcArray = ((JSONArray) json.get("n")).toArray();
return factory; return factory;
} }

View File

@ -1,35 +1,65 @@
package net.simon987.npcplugin; package net.simon987.npcplugin;
import net.simon987.npcplugin.event.CpuInitialisationListener;
import net.simon987.npcplugin.event.WorldCreationListener; import net.simon987.npcplugin.event.WorldCreationListener;
import net.simon987.server.ServerConfiguration; import net.simon987.server.ServerConfiguration;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.game.GameObject; import net.simon987.server.game.GameObject;
import net.simon987.server.io.CpuHardwareDeserializer;
import net.simon987.server.io.GameObjectDeserializer; import net.simon987.server.io.GameObjectDeserializer;
import net.simon987.server.logging.LogManager; import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.ServerPlugin; import net.simon987.server.plugin.ServerPlugin;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer { import java.util.ArrayList;
public class NpcPlugin extends ServerPlugin implements GameObjectDeserializer, CpuHardwareDeserializer {
/**
* Radio tower cache
*/
private static ArrayList<RadioTower> radioTowers;
@Override @Override
public void init(ServerConfiguration configuration) { public void init(ServerConfiguration configuration) {
listeners.add(new WorldCreationListener()); listeners.add(new WorldCreationListener());
listeners.add(new CpuInitialisationListener());
radioTowers = new ArrayList<>(32);
LogManager.LOGGER.info("Initialised NPC plugin"); LogManager.LOGGER.info("Initialised NPC plugin");
} }
@Override @Override
public GameObject deserializeObject(JSONObject object) { public GameObject deserializeObject(JSONObject json) {
int objType = (int) (long) object.get("t"); int objType = (int) (long) json.get("t");
if (objType == HarvesterNPC.ID) { if (objType == HarvesterNPC.ID) {
return HarvesterNPC.deserialize(object); return HarvesterNPC.deserialize(json);
} else if (objType == Factory.ID) { } else if (objType == Factory.ID) {
return Factory.deserialise(object); return Factory.deserialise(json);
} else if (objType == RadioTower.ID) {
return RadioTower.deserialize(json);
} }
return null; return null;
} }
@Override
public CpuHardware deserializeHardware(JSONObject hwJson) {
int hwid = (int) (long) hwJson.get("hwid");
switch (hwid) {
case RadioReceiverHardware.HWID:
return RadioReceiverHardware.deserialize(hwJson);
}
return null;
}
public static ArrayList<RadioTower> getRadioTowers() {
return radioTowers;
}
} }

View File

@ -0,0 +1,78 @@
package net.simon987.npcplugin;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import net.simon987.server.assembly.Util;
import net.simon987.server.game.Action;
import net.simon987.server.game.ControllableUnit;
import org.json.simple.JSONObject;
import java.util.ArrayList;
public class RadioReceiverHardware extends CpuHardware {
public static final char HWID = 0xC; //12
private static final int LISTEN = 1;
public static final int DEFAULT_ADDRESS = 0xC;
private ControllableUnit cubot;
public RadioReceiverHardware(ControllableUnit cubot) {
this.cubot = cubot;
}
@Override
public void handleInterrupt(Status status) {
int x = getCpu().getRegisterSet().getRegister("X").getValue();
int a = getCpu().getRegisterSet().getRegister("A").getValue();
if (a == LISTEN) {
//Find the nearest Radio Tower and query it
cubot.setAction(Action.LISTENING);
ArrayList<char[]> messages = new ArrayList<>(6);
ArrayList<RadioTower> towers = new ArrayList<>(NpcPlugin.getRadioTowers()); //Avoid ConcurrentModificationException
for (RadioTower tower : towers) {
if (Util.manhattanDist(tower.getX(), tower.getY(), cubot.getX(), cubot.getY()) <= RadioTower.MAX_RANGE) {
//Tower is in range
messages.addAll(tower.getMessages());
}
}
//Write messages to memory
int offset = 0;
for (char[] message : messages) {
getCpu().getMemory().write(x + offset, message, 0, message.length);
offset += message.length;
}
//Write the amount of messages received to B
getCpu().getRegisterSet().getRegister("B").setValue(messages.size());
}
}
@Override
public char getId() {
return HWID;
}
@Override
public JSONObject serialise() {
JSONObject json = new JSONObject();
json.put("hwid", (int) HWID);
json.put("cubot", cubot.getObjectId());
return json;
}
public static RadioReceiverHardware deserialize(JSONObject json) {
return new RadioReceiverHardware((ControllableUnit) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) json.get("cubot")));
}
}

View File

@ -1,4 +1,103 @@
package net.simon987.npcplugin; package net.simon987.npcplugin;
public class RadioTower { import net.simon987.server.game.GameObject;
import net.simon987.server.game.Programmable;
import net.simon987.server.game.Updatable;
import org.json.simple.JSONObject;
import java.awt.*;
import java.util.ArrayList;
public class RadioTower extends GameObject implements Programmable, Updatable {
private static final int MAP_INFO = 0x1000;
public static final int ID = 4;
public static final int MAX_RANGE = 3; //todo load from config
private static final int MAX_MESSAGES = 16;
@Override
public char getMapInfo() {
return MAP_INFO;
}
/**
* Messages from the current tick
*/
private ArrayList<char[]> messages = new ArrayList<>(4);
/**
* Messages from the last tick
*/
private ArrayList<char[]> lastMessages = new ArrayList<>(4);
@Override
public void update() {
lastMessages = new ArrayList<>(messages);
messages.clear();
}
@Override
public void sendMessage(char[] message) {
if (message.length < MAX_MESSAGES) {
messages.add(message);
}
}
@Override
public JSONObject serialise() {
JSONObject json = new JSONObject();
json.put("i", getObjectId());
json.put("x", getX());
json.put("y", getY());
json.put("t", ID);
return json;
}
public static RadioTower deserialize(JSONObject json) {
RadioTower tower = new RadioTower();
tower.setObjectId((long) json.get("i"));
tower.setX((int) (long) json.get("x"));
tower.setY((int) (long) json.get("y"));
NpcPlugin.getRadioTowers().add(tower);
return tower;
}
public ArrayList<char[]> getMessages() {
return lastMessages;
}
/**
* Get the first directly adjacent tile (starting east, going clockwise)
*/
public Point getAdjacentTile() {
if (!getWorld().isTileBlocked(getX() + 1, getY())) {
return new Point(getX() + 1, getY());
} else if (!getWorld().isTileBlocked(getX(), getY() + 1)) {
return new Point(getX(), getY() + 1);
} else if (!getWorld().isTileBlocked(getX() - 1, getY())) {
return new Point(getX() - 1, getY());
} else if (!getWorld().isTileBlocked(getX(), getY() - 1)) {
return new Point(getX(), getY() - 1);
} else {
return null;
}
}
} }

View File

@ -0,0 +1,27 @@
package net.simon987.npcplugin.event;
import net.simon987.npcplugin.RadioReceiverHardware;
import net.simon987.server.assembly.CPU;
import net.simon987.server.event.CpuInitialisationEvent;
import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventListener;
import net.simon987.server.user.User;
public class CpuInitialisationListener implements GameEventListener {
@Override
public Class getListenedEventType() {
return CpuInitialisationEvent.class;
}
@Override
public void handle(GameEvent event) {
CPU cpu = (CPU) event.getSource();
User user = ((CpuInitialisationEvent) event).getUser();
RadioReceiverHardware radioHw = new RadioReceiverHardware(user.getControlledUnit());
radioHw.setCpu(cpu);
cpu.attachHardware(radioHw, RadioReceiverHardware.DEFAULT_ADDRESS);
}
}

View File

@ -1,6 +1,8 @@
package net.simon987.npcplugin.event; package net.simon987.npcplugin.event;
import net.simon987.npcplugin.Factory; import net.simon987.npcplugin.Factory;
import net.simon987.npcplugin.NpcPlugin;
import net.simon987.npcplugin.RadioTower;
import net.simon987.server.GameServer; import net.simon987.server.GameServer;
import net.simon987.server.event.GameEvent; import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventListener; import net.simon987.server.event.GameEventListener;
@ -8,6 +10,7 @@ import net.simon987.server.event.WorldGenerationEvent;
import net.simon987.server.game.World; import net.simon987.server.game.World;
import net.simon987.server.logging.LogManager; import net.simon987.server.logging.LogManager;
import java.awt.*;
import java.util.Random; import java.util.Random;
public class WorldCreationListener implements GameEventListener { public class WorldCreationListener implements GameEventListener {
@ -31,6 +34,7 @@ public class WorldCreationListener implements GameEventListener {
World world = ((WorldGenerationEvent) event).getWorld(); World world = ((WorldGenerationEvent) event).getWorld();
outerLoopFactory:
for (int x = 2; x < 12; x++) { for (int x = 2; x < 12; x++) {
for (int y = 2; y < 12; y++) { for (int y = 2; y < 12; y++) {
@ -54,10 +58,40 @@ public class WorldCreationListener implements GameEventListener {
LogManager.LOGGER.info("Spawned Factory at (" + world.getX() + ", " + world.getY() + LogManager.LOGGER.info("Spawned Factory at (" + world.getX() + ", " + world.getY() +
") (" + x + ", " + y + ")"); ") (" + x + ", " + y + ")");
break outerLoopFactory;
}
}
}
//Also spawn a radio tower in the same World
Point p = world.getRandomPassableTile();
if (p != null) {
while (p.x == 0 || p.x == World.WORLD_SIZE - 1 || p.y == World.WORLD_SIZE - 1 || p.y == 0) {
p = world.getRandomPassableTile();
if (p == null) {
//World is full
return; return;
} }
} }
RadioTower radioTower = new RadioTower();
radioTower.setWorld(world);
radioTower.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
radioTower.setX(p.x);
radioTower.setY(p.y);
if (radioTower.getAdjacentTile() != null) {
//Radio Tower has adjacent tiles
world.getGameObjects().add(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 + ")");
}
} }
} }
} }

View File

@ -5,6 +5,7 @@ public enum Action {
DIGGING, DIGGING,
WALKING, WALKING,
WITHDRAWING, WITHDRAWING,
DEPOSITING DEPOSITING,
LISTENING
} }

View File

@ -21,4 +21,9 @@ public interface ControllableUnit {
int getEnergy(); int getEnergy();
int getX();
int getY();
void setAction(Action listening);
} }

View File

@ -0,0 +1,7 @@
package net.simon987.server.game;
public interface Programmable {
void sendMessage(char[] message);
}

View File

@ -33,6 +33,13 @@ public class CodeUploadHandler implements MessageHandler {
user.getUser().getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length); user.getUser().getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
user.getUser().getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset()); user.getUser().getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset());
//Clear keyboard buffer
if (user.getUser().getControlledUnit() != null &&
user.getUser().getControlledUnit().getKeyboardBuffer() != null) {
user.getUser().getControlledUnit().getKeyboardBuffer().clear();
}
JSONObject response = new JSONObject(); JSONObject response = new JSONObject();
response.put("t", "codeResponse"); response.put("t", "codeResponse");
response.put("bytes", ar.bytes.length); response.put("bytes", ar.bytes.length);