package nl.tudelft.bw4t.server.eis; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.omg.CORBA.Environment; import eis.eis2java.annotation.AsAction; import eis.eis2java.annotation.AsPercept; import eis.eis2java.exception.TranslationException; import eis.eis2java.translation.Filter; import eis.eis2java.translation.Translator; import eis.exceptions.ActException; import eis.exceptions.PerceiveException; import eis.iilang.Action; import eis.iilang.Parameter; import nl.tudelft.bw4t.map.view.ViewEPartner; import nl.tudelft.bw4t.server.eis.translators.BlockWithColorTranslator; import nl.tudelft.bw4t.server.eis.translators.BoundedMovableObjectTranslator; import nl.tudelft.bw4t.server.eis.translators.ColorTranslator; import nl.tudelft.bw4t.server.eis.translators.ObjectInformationTranslator; import nl.tudelft.bw4t.server.eis.translators.PointTranslator; import nl.tudelft.bw4t.server.eis.translators.ZoneTranslator; import nl.tudelft.bw4t.server.environment.BW4TEnvironment; import nl.tudelft.bw4t.server.model.epartners.EPartner; import nl.tudelft.bw4t.server.model.robots.AbstractRobot; import nl.tudelft.bw4t.server.model.zone.Corridor; import nl.tudelft.bw4t.server.model.zone.Room; import nl.tudelft.bw4t.server.model.zone.Zone; import nl.tudelft.bw4t.server.util.RoomLocator; import nl.tudelft.bw4t.server.util.ZoneLocator; import repast.simphony.context.Context; /** * Interface to create an Entity that can be used for Robot or EPartner */ public class EPartnerEntity implements EntityInterface { static { // Register our translators. Translator translator = Translator.getInstance(); translator.registerJava2ParameterTranslator(new BlockWithColorTranslator()); translator.registerJava2ParameterTranslator(new BoundedMovableObjectTranslator()); translator.registerJava2ParameterTranslator(new ZoneTranslator()); translator.registerJava2ParameterTranslator(new PointTranslator()); translator.registerJava2ParameterTranslator(new ObjectInformationTranslator()); translator.registerJava2ParameterTranslator(new ColorTranslator()); } private final EPartner ourEPartner; private final Context<Object> context; /** * Here we store data that needs to be locked for a perception cycle. See {@link #initializePerceptionCycle()}. */ private Point2D ourEPartnerLocation; private Point2D spawnLocation; private Room ourEPartnerRoom; /** * each item in messages is a list with two items: the sender and the messagetext. */ private List<ArrayList<String>> messages; /** * Creates a new {@link RobotEntity} that can be launched by an EIS compatible {@link Environment}. * * @param eP * The {@link AbstractRobot} that this entity can put up for controlling in EIS. */ public EPartnerEntity(EPartner eP) { this.ourEPartner = eP; this.context = eP.getContext(); messages = new LinkedList<>(); } /** * Connect robot to repast (to be called when an agent is connected to this entity) */ @Override public void connect() { spawnLocation = new Point2D.Double(ourEPartner.getLocation().getX(), ourEPartner.getLocation().getY()); } /** * Disconnects the robot from repast. */ public void disconnect() { // Needs to be here or Repast will cry. } /** * This function should be called before perception cycle is started, so that we can lock the relevant data from the * environment. */ @Override public void initializePerceptionCycle() { ourEPartnerLocation = new Point2D.Double(ourEPartner.getLocation().getX(), ourEPartner.getLocation().getY()); ourEPartnerRoom = RoomLocator.getRoomAt(ourEPartnerLocation.getX(), ourEPartnerLocation.getY()); } /** * @return The functionalities of the e-Partner */ @AsPercept(name = "functionality", multiplePercepts = true, filter = Filter.Type.ONCE) public List<String> getFunctionalities() { return ourEPartner.getTypeList(); } /** * Percept if the e-Partner was dropped. * * @return id of holder * @throws PerceiveException */ @AsPercept(name = "heldBy", multiplePercepts = false, filter = Filter.Type.ON_CHANGE_NEG) public long heldBy() throws PerceiveException { if (ourEPartner.getTypeList().contains(ViewEPartner.FORGET_ME_NOT) && ourEPartner.getHolder() != null) { return ourEPartner.getHolder().getId(); } return -1; } /** * Percept if the epartner is taken, so other bots won't pick it up if a bot has forgot it. * * @return The epartner id. * @throws PerceiveException */ @AsPercept(name = "isTaken", multiplePercepts = false, filter = Filter.Type.ON_CHANGE_NEG) public long isTaken() throws PerceiveException { if (ourEPartner.getTypeList().contains(ViewEPartner.FORGET_ME_NOT) && ourEPartner.getHolder() != null) { return ourEPartner.getId(); } return -1; } /** * Percept if the epartner is left behind, so the epartner knows when to message the holder. * * @return 1 if it was left behind, 0 if it's still held. * @throws PerceiveException */ @AsPercept(name = "leftBehind", multiplePercepts = false, filter = Filter.Type.ON_CHANGE) public int leftBehind() throws PerceiveException { if (ourEPartner.getTypeList().contains(ViewEPartner.FORGET_ME_NOT) && ourEPartner.getHolder() == null) { return 1; } return 0; } /** * Percept for navpoints the robot is at. Send on change. If robot is in a {@link Zone}, that zone name is returned. * If not, the nearest {@link Corridor} name is returned. * * @return a list of blockID * @throws PerceiveException */ @AsPercept(name = "at", multiplePercepts = false, filter = Filter.Type.ON_CHANGE) public String getAt() throws PerceiveException { if (ourEPartner.getTypeList().contains(ViewEPartner.GPS)) { Zone navpt = ZoneLocator.getNearestZone(ourEPartner.getLocation()); if (navpt == null) { throw new PerceiveException( "perceiving 'at' percept failed, because map has no suitable navpoint for position " + ourEPartnerLocation); } return navpt.getName(); } return ""; } /** * Percept for the location of this robot Send on change * * @return location of epartner */ @AsPercept(name = "location", multiplePercepts = false, filter = Filter.Type.ON_CHANGE) public Point2D getLocation() { return new Point2D.Double(spawnLocation.getX(), spawnLocation.getY()); } /** * Percept for the room that the player is in, null if not in a room. Send on change * * @return room name */ @AsPercept(name = "in", multiplePercepts = false, filter = Filter.Type.ON_CHANGE_NEG) public String getRoom() { if (ourEPartnerRoom == null) { return null; } return ourEPartnerRoom.getName(); } /** * Percept for the places in the world. Send at the beginning * * @return Rooms of the epartner * @throws PerceiveException */ @AsPercept(name = "place", multiplePercepts = true, filter = Filter.Type.ONCE) public List<String> getRooms() throws PerceiveException { List<String> places = new LinkedList<>(); if (ourEPartner.getTypeList().contains(ViewEPartner.GPS)) { for (Object o : context.getObjects(Zone.class)) { Zone zone = (Zone) o; places.add(zone.getName()); } } return places; } /** * Returns all messages received by the player, Send on change * * @return the messages that were received */ @AsPercept(name = "message", multiplePercepts = true, filter = Filter.Type.ALWAYS) public List<ArrayList<String>> getMessages() { List<ArrayList<String>> msg = messages; messages = new LinkedList<>(); return msg; } /** * Instructs the robot to send a message * * @param message * , the message that should be sent * @param receiver * , the receiver of the message (can be all or the id of another robot * @throws ActException * if the action fails */ @AsAction(name = "sendMessage") public void sendMessage(String receiver, String message) throws ActException { // Translate the message into parameters Parameter[] parameters = new Parameter[2]; try { parameters[0] = Translator.getInstance().translate2Parameter(ourEPartner.getName())[0]; parameters[1] = Translator.getInstance().translate2Parameter(message)[0]; } catch (TranslationException e) { throw new ActException("translating of message failed:" + message, e); } // Send to all other entities (except self) if ("all".equals(receiver)) { for (String entity : BW4TEnvironment.getInstance().getEntities()) { BW4TEnvironment.getInstance().performClientAction(entity, new Action("receiveMessage", parameters)); } // Send to a single entity } else { BW4TEnvironment.getInstance().performClientAction(receiver, new Action("receiveMessage", parameters)); } } /** * Instructs the robot to receive a certain message, should only be used internally in the server environment * * @param message * , the message to be received * @param sender * , the sender of the message */ @AsAction(name = "receiveMessage") public void receiveMessage(String sender, String message) { // Add message to messageArray ArrayList<String> messageArray = new ArrayList<>(2); messageArray.add(sender); messageArray.add(message); messages.add(messageArray); } }