package iamrescue.agent;
import iamrescue.agent.firebrigade.FastFirePredictor;
import iamrescue.agent.search.ClashRandomisedClosestSearchBehaviour;
import iamrescue.agent.search.ISearchBehaviour;
import iamrescue.belief.IAMWorldModel;
import iamrescue.belief.commupdates.IMessageHandler;
import iamrescue.belief.commupdates.IWorldModelUpdatePropagator;
import iamrescue.belief.commupdates.WorldModelCommsUpdater;
import iamrescue.belief.commupdates.WorldModelUpdatePropagator;
import iamrescue.belief.entities.BlockInfoRoadEntityFactory;
import iamrescue.belief.entities.BlockedEdgesPropertyFactory;
import iamrescue.belief.entities.KnownToBePassablePropertyFactory;
import iamrescue.belief.entities.RoutingInfoBlockade;
import iamrescue.belief.entities.RoutingInfoBlockadeEntityFactory;
import iamrescue.belief.gui.IAMWorldModelViewerComponent;
import iamrescue.belief.inference.BlockDetectingRoutingModule;
import iamrescue.belief.inference.BlockForgettingModule;
import iamrescue.belief.inference.INegativeSenseUpdater;
import iamrescue.belief.inference.NegativeSenseUpdater;
import iamrescue.belief.inference.PassableRoadsDetector;
import iamrescue.belief.inference.RoutingInfoUpdater;
import iamrescue.belief.provenance.LatestProperty;
import iamrescue.communication.ISimulationCommunicationConfiguration;
import iamrescue.communication.SimulationCommunicationConfigurationAdapter;
import iamrescue.communication.messages.Message;
import iamrescue.communication.messages.PingMessage;
import iamrescue.communication.messages.codec.CommunicationBeliefBaseAdapter;
import iamrescue.communication.messages.codec.ICommunicationBeliefBaseAdapter;
import iamrescue.communication.scenario.IAMCommunicationModule;
import iamrescue.execution.IExecutionService;
import iamrescue.execution.RC2ExecutionService;
import iamrescue.execution.command.IPath;
import iamrescue.routing.IRoutingModule;
import iamrescue.routing.costs.SimpleDistanceRoutingCostFunction;
import iamrescue.routing.dijkstra.BidirectionalDijkstrasRoutingModule;
import iamrescue.routing.dijkstra.SimpleDijkstrasRoutingModule;
import iamrescue.routing.util.ISpeedInfo;
import iamrescue.routing.util.SpeedLearningModule;
import iamrescue.util.IntervalTimer;
import java.awt.BorderLayout;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javolution.util.FastList;
import javolution.util.FastSet;
import org.apache.log4j.Logger;
import rescuecore2.components.AbstractAgent;
import rescuecore2.messages.Command;
import rescuecore2.messages.control.KASense;
import rescuecore2.registry.Registry;
import rescuecore2.standard.entities.Human;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.standard.entities.StandardPropertyURN;
import rescuecore2.worldmodel.ChangeSet;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.Property;
public abstract class AbstractIAMAgent<E extends StandardEntity> extends
AbstractAgent<IAMWorldModel, E> {
private static final boolean NAME_THREADS = true;
private static final boolean USE_BLOCK_DETECTION = true;
private static final boolean USE_FALLBACK_BEHAVIOUR = false;
private static final int FORGET_BLOCKADES_AFTER = 50;
private static final String IGNORE_KEY = "kernel.agents.ignoreuntil";
private final Object SYNC_BLOCK = new Object();
private IAMCommunicationModule communicationModule;
private IRoutingModule routing;
private IRoutingModule reusableRouting = null;
private IExecutionService executionService;
private SimulationTimer timer = new SimulationTimer();
private WorldModelCommsUpdater worldModelCommsUpdater;
private IWorldModelUpdatePropagator propagator;
// private ISpatialIndex spatialIndex = null;
private INegativeSenseUpdater negativeUpdater;
private PassableRoadsDetector passableRoadsDetector;
private ISearchBehaviour searchBehaviour;
private IntervalTimer intervalTimer = new IntervalTimer();
private static final Logger LOGGER = Logger
.getLogger(AbstractIAMAgent.class);
private IAMWorldModelViewerComponent viewer = null;
private RoutingInfoUpdater blockUpdater;
private SpeedLearningModule speedInfo;
private SimpleDistanceRoutingCostFunction routingCostFunction;
private ExecutorService ThinkExecution;
private int thinkRuntime = 0;
private int ignoreUntil;
private boolean iAmCentre = false;
private ShoutGenerator shoutGenerator;
private BlockForgettingModule blockForgetter = null;
private int fallbackRuntime;
private boolean myTypeIsCentre;
/**
* Shows a GUI containing the agent's local world model. This brings up a
* JFrame that remains visible throughout the simuation.
*
*/
protected void showWorldModelViewer() {
synchronized (SYNC_BLOCK) {
if (viewer == null) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("World Model view of "
+ me());
viewer = new IAMWorldModelViewerComponent();
JPanel main = new JPanel(new BorderLayout());
main.add(viewer.getGUIComponent(),
BorderLayout.CENTER);
frame.add(main);
frame.pack();
frame.setVisible(true);
viewer.simulationStarted(config, getWorldModel(),
getRoutingModule());
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
protected void showRoutingViewer() {
showWorldModelViewer();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
synchronized (SYNC_BLOCK) {
viewer.showRoutingLayer();
}
}
});
}
protected void showFireImportanceModel(FastFirePredictor firePredictor) {
showWorldModelViewer();
final FastFirePredictor predictor = firePredictor;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
synchronized (SYNC_BLOCK) {
viewer.showFireLayer(predictor);
}
}
});
}
protected void showSearchViewer() {
showWorldModelViewer();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
synchronized (SYNC_BLOCK) {
viewer.showSearchLayer();
}
}
});
}
// Override this to set the time before properties are updated.
@Override
protected final void processSense(KASense sense) {
int time = sense.getTime();
timer.setTime(time);
if (NAME_THREADS) {
Thread.currentThread().setName(me().toString() + " " + time);
} else {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(me().toString() + " is starting time step " + time);
}
}
super.processSense(sense);
}
@Override
protected final void think(int time, ChangeSet changed,
Collection<Command> heard) {
intervalTimer.start();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Starting think method with changeset :" + changed
+ " at time " + timer.getTime());
}
try {
handleWorldUpdates(changed, heard);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("EXCEPTION OCCURED");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Handling world updates took " + intervalTimer.lap()
+ "ns");
}
// Now signal start of turn
timer.fireTimeStepStarted();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Timer listeners took " + intervalTimer.lap() + "ns");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Calling abstract think method");
}
// initialse search;
// System.out
// .println(me()
// + " knows about "
// + getWorldModel().getEntitiesOfType(
// StandardEntityURN.BLOCKADE));
// Do shouting behaviour
if (!myTypeIsCentre) {
shoutGenerator.generateShouts();
}
if (USE_FALLBACK_BEHAVIOUR) {
runThinkWithFallBack(time, changed);
} else {
try {
think(time, changed);
} catch (Exception e) {
LOGGER.error("An exception occurred: " + e);
e.printStackTrace();
doDefaultSearch();
}
}
// Main think method
// think(time, changed);
// at this point, the execution module has unprocessed commands and the
// communication module has unsent messages
// Only send messages at time step 3 and later
if (timer.getTime() >= ignoreUntil) {
communicationModule.flushOutbox();
}
executionService.flushCommands();
long delay = intervalTimer.getTime();
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Think method done after " + delay / 1000000.0 + "ms");
}
if (delay > 300000000) {
LOGGER.warn("Think method took " + delay / 1000000.0 + "ms!");
}
if (viewer != null) {
viewer.timestepCompleted(getWorldModel());
}
}
private void runThinkWithFallBack(int time, ChangeSet changed) {
// Execution service for fallback behaviour
Future thinkFuture = null;
Future fallbackFuture = null;
try {
thinkFuture = ThinkExecution.submit(new ThinkRunner(time, changed));
thinkFuture.get(thinkRuntime, TimeUnit.MILLISECONDS);
thinkFuture.cancel(true);
} catch (InterruptedException e) {
LOGGER.error(" - INTERRUPTED EXCEPTION!");
e.printStackTrace();
try {
thinkFuture.cancel(true);
if (executionService.NotSubmittedCommand()) {
fallbackFuture = ThinkExecution.submit(new FallbackRunner(
time, changed));
fallbackFuture.get(fallbackRuntime, TimeUnit.MILLISECONDS);
fallbackFuture.cancel(true);
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (TimeoutException e3) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ExecutionException e) {
LOGGER.error(" - EXECUTION EXCEPTION!");
LOGGER.error(e.toString());
e.printStackTrace();
try {
thinkFuture.cancel(true);
if (executionService.NotSubmittedCommand()) {
fallbackFuture = ThinkExecution.submit(new FallbackRunner(
time, changed));
fallbackFuture.get(fallbackRuntime, TimeUnit.MILLISECONDS);
fallbackFuture.cancel(true);
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (TimeoutException e3) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (TimeoutException e) {
LOGGER.error(" - TIMEOUT EXCEPTION!");
e.printStackTrace();
try {
thinkFuture.cancel(true);
if (executionService.NotSubmittedCommand()) {
fallbackFuture = ThinkExecution.submit(new FallbackRunner(
time, changed));
fallbackFuture.get(fallbackRuntime, TimeUnit.MILLISECONDS);
fallbackFuture.cancel(true);
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ExecutionException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (TimeoutException e3) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* @param changed
* @param changed
* @param heard
*
*/
private void handleWorldUpdates(ChangeSet changed, Collection<Command> heard) {
IntervalTimer updateTimer = new IntervalTimer();
updateTimer.start();
// Get only the real differences between the changed ChangeSet and what
// was in the world model at the beginning of the time step.
ChangeSet sensedChanges = getWorldModel().getLastSensedChanges();
// sensedChanges = changed;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Newly sensed: " + sensedChanges);
}
// Now do negative updates
try {
ChangeSet negativeUpdates = negativeUpdater
.removeUnseenEntities(changed);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Negative updates took " + updateTimer.lap()
+ "ns");
LOGGER.debug("Negative updates: " + negativeUpdates);
}
// Add these to the sensed changes
mergeChangeSets(sensedChanges, negativeUpdates);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("EXCETION OCCURED");
}
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("Merging change sets took " + updateTimer.lap()
+ "ns");
}
// Now infer passable roads
try {
ChangeSet passableUpdates = passableRoadsDetector
.inferPassableRoads();
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("Passable update took " + updateTimer.lap()
+ "ns");
LOGGER.debug("Passable updates: " + passableUpdates);
}
mergeChangeSets(sensedChanges, passableUpdates);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("EXCEPTION OCCURED");
}
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("Merging change sets took " + updateTimer.lap()
+ "ns");
}
try {
// Now infer blockage routing updates
ChangeSet blockedUpdates = blockUpdater.inferUpdatedBlockades();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Routing block update took " + updateTimer.lap()
+ "ns");
LOGGER.debug("Routing block updates: " + blockedUpdates);
}
mergeChangeSets(sensedChanges, blockedUpdates);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("EXCEPTION OCCURED");
}
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("Merging change sets took " + updateTimer.lap()
+ "ns");
}
LOGGER.debug("Heard " + heard.size() + " messages.");
// process all incoming messages
// heard = filterOldMessages(heard);
/*
* if (LOGGER.isDebugEnabled()) {
* LOGGER.debug("Filtering messages took " + updateTimer.lap() + "ns");
* }
*/
if (LOGGER.isTraceEnabled()) {
for (Command c : heard) {
LOGGER.trace("Heard: " + c.toString());
}
}
communicationModule.hear(heard);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Decoding messages took " + updateTimer.lap() + "ns");
}
// Now check if I am a centre
boolean amICentre = false;
try {
amICentre = communicationModule.amICentre();
} catch (Exception e) {
LOGGER.warn("Caught exception. This means I am not a centre.");
e.printStackTrace();
}
if (amICentre != iAmCentre) {
iAmCentre = amICentre;
if (iAmCentre) {
LOGGER.info("Detected centre role");
worldModelCommsUpdater.setCentreRole(communicationModule
.getChannelsToOwnTeam());
} else {
LOGGER.info("Detected no longer centre role");
worldModelCommsUpdater.unsetCentreRole();
}
}
// Update world model based on communicated messages
List<Message> updates = worldModelCommsUpdater.update();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Merging update messages with world model took "
+ updateTimer.lap() + "ns");
}
// Now forward messages if necessary
if (iAmCentre) {
for (Message message : updates) {
communicationModule.enqueueRadioMessageToOwnTeam(message);
}
if (updates.size() == 0) {
// Make sure to send a ping every time step if nothing else is
// sent
communicationModule
.enqueueRadioMessageToOwnTeam(new PingMessage());
}
}
// Make sure all position information is consistent (always includes x,y
// and position updates if any change)
ensurePositionConsistency(sensedChanges);
// Remove updates that would be propagated by others
filterOutRedundantUpdates(sensedChanges, changed);
// Send sensed entities to other agents (using only changed properties)
propagator.sendUpdates(sensedChanges, me().getID());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending update messages took " + updateTimer.lap()
+ "ns");
}
// Finally remove old blocks
if (blockForgetter != null && FORGET_BLOCKADES_AFTER > 0) {
blockForgetter.forgetOldBlockades();
}
// ensureBlockadeConsistency();
}
// private void ensureBlockadeConsistency() {
// }
/**
* @param sensedChanges
* @param changed
*/
private void filterOutRedundantUpdates(ChangeSet sensedChanges,
ChangeSet changed) {
Set<EntityID> changedEntities = changed.getChangedEntities();
Set<StandardEntity> otherAgents = new FastSet<StandardEntity>();
for (EntityID id : changedEntities) {
StandardEntity entity = getWorldModel().getEntity(id);
// if (entity instanceof Human && !(entity instanceof Civilian) &&
// entity) {
// }
}
}
/**
* @param sensedChanges
*/
private void ensurePositionConsistency(ChangeSet sensedChanges) {
Set<EntityID> changedEntities = sensedChanges.getChangedEntities();
for (EntityID changed : changedEntities) {
StandardEntity entity = getWorldModel().getEntity(changed);
if (entity instanceof Human) {
Set<Property> changedProperties = sensedChanges
.getChangedProperties(entity.getID());
Set<String> included = new FastSet<String>();
for (Property p : changedProperties) {
if (p.getURN().equals(StandardPropertyURN.X.toString())
|| p.getURN().equals(
StandardPropertyURN.Y.toString())
|| p.getURN().equals(
StandardPropertyURN.POSITION.toString())) {
included.add(p.getURN());
}
}
if (included.size() > 0 && included.size() < 3) {
// Not all were included.
if (!included.contains(StandardPropertyURN.X.toString())) {
sensedChanges.addChange(entity, entity
.getProperty(StandardPropertyURN.X.toString()));
}
if (!included.contains(StandardPropertyURN.Y.toString())) {
sensedChanges.addChange(entity, entity
.getProperty(StandardPropertyURN.Y.toString()));
}
if (!included.contains(StandardPropertyURN.POSITION
.toString())) {
sensedChanges.addChange(entity, entity
.getProperty(StandardPropertyURN.POSITION
.toString()));
}
}
}
}
}
/**
*
* @return The simulation timer.
*/
protected ISimulationTimer getTimer() {
return timer;
}
/**
* This removes out-of-date messages. Used as a workaround for current bug
* with server that sends old messages.
*/
private Collection<Command> filterOldMessages(Collection<Command> heard) {
Collection<Command> newHeard = new FastList<Command>();
for (Command command : heard) {
if (command.getTime() >= timer.getTime() - 6) {
newHeard.add(command);
} else {
LOGGER.trace("Ignoring old command: " + command);
}
}
return newHeard;
}
/**
* Merges negative updates into sensed changes. At the end of the method,
* sensedChanges will contain all changes.
*
* @param sensedChanges
* The original changes
* @param negativeUpdates
* The negative updates to merge into the original changes.
*/
private void mergeChangeSets(ChangeSet sensedChanges,
ChangeSet negativeUpdates) {
Set<EntityID> changedEntities = negativeUpdates.getChangedEntities();
for (EntityID entityID : changedEntities) {
String entityURN = negativeUpdates.getEntityURN(entityID);
Set<Property> changedProperties = negativeUpdates
.getChangedProperties(entityID);
for (Property property : changedProperties) {
sensedChanges.addChange(entityID, entityURN, property);
}
}
}
/**
* Main fallback method that is called every time step if the think fails.
* Logic for the agent goes here.
*
* @param time
* The current time step.
* @param changed
* Everything that has been observed this time step.
*/
protected abstract void fallback(int time, ChangeSet changed);
/**
* Main think method that is called every time step. Logic for the agent
* goes here.
*
* @param time
* The current time step.
* @param changed
* Everything that has been observed this time step.
*/
protected abstract void think(int time, ChangeSet changed);
@Override
protected void postConnect() {
Thread.currentThread().setName(me().toString());
LOGGER.info("Starting postconnect");
/*
* Registry.getCurrentRegistry().registerEntityFactory(
* StandardEntityURN.BLOCKADE.toString(), new
* RoutingInfoBlockadeEntityFactory());
*
* Registry.getCurrentRegistry().registerPropertyFactory(
* RoutingInfoBlockade.BLOCK_INFO_URN, new
* BlockedEdgesPropertyFactory());
*/
try {
super.postConnect();
getWorldModel().buildShortIndex();
// Only create speed info object if I am human
if (getWorldModel().getEntity(getID()) instanceof Human) {
speedInfo = new SpeedLearningModule(getWorldModel(), getID(),
getTimer());
}
executionService = new RC2ExecutionService(getID(), connection,
config, timer, getWorldModel(), speedInfo);
routingCostFunction = new SimpleDistanceRoutingCostFunction(
getWorldModel(), false);
routingCostFunction.setBurningPenalty(5000000);
if (USE_BLOCK_DETECTION) {
routing = getReusableRouting();// new
// BlockDetectingRoutingModule(getWorldModel(),
// routingCostFunction, timer, executionService, getID(),
// speedInfo, true);
} else {
routing = new BidirectionalDijkstrasRoutingModule(
getWorldModel(), routingCostFunction, timer);
}
ICommunicationBeliefBaseAdapter communicationBeliefBaseAdapter = new CommunicationBeliefBaseAdapter(
getWorldModel(), config, routing.getConverter());
getWorldModel().setDefaultConverter(routing.getConverter());
ISimulationCommunicationConfiguration configuration = new SimulationCommunicationConfigurationAdapter(
config, getID(), getWorldModel().getEntity(getID())
.getStandardURN(), getWorldModel());
communicationModule = new IAMCommunicationModule(getID(), timer,
communicationBeliefBaseAdapter, configuration, connection);
worldModelCommsUpdater = new WorldModelCommsUpdater(
getWorldModel(), communicationModule, timer, config,
getID());
if (!getWorldModel().getEntitiesOfType(
StandardEntityURN.AMBULANCE_CENTRE,
StandardEntityURN.FIRE_STATION,
StandardEntityURN.POLICE_OFFICE).contains(me())) {
myTypeIsCentre = false;
this.shoutGenerator = new ShoutGenerator(getWorldModel(),
getCommunicationModule());
} else {
myTypeIsCentre = true;
}
/*
* executionService = new RC2ExecutionService(getID(), connection,
* config, timer, getWorldModel());
*/
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Starting to build routing.");
}
propagator = new WorldModelUpdatePropagator(getWorldModel(),
communicationModule, timer, getRoutingModule()
.getConverter());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Starting to build spatial index.");
}
// spatialIndex = new SpatialIndex(getWorldModel());
negativeUpdater = new NegativeSenseUpdater(config, getWorldModel(),
getID(), timer, new LatestProperty());
passableRoadsDetector = new PassableRoadsDetector(getWorldModel(),
getID());
if ((me().getURN().equals(
StandardEntityURN.AMBULANCE_TEAM.toString()) || me()
.getURN().equals(StandardEntityURN.FIRE_BRIGADE.toString()))
&& FORGET_BLOCKADES_AFTER > 0) {
this.blockForgetter = new BlockForgettingModule(
getWorldModel(), new LatestProperty(), timer,
FORGET_BLOCKADES_AFTER);
}
getWorldModel().postConnect();
searchBehaviour = new ClashRandomisedClosestSearchBehaviour(
getWorldModel(), getID(), executionService,
getRoutingModule(), config, getCommunicationModule());
blockUpdater = new RoutingInfoUpdater(getWorldModel(),
getRoutingModule().getConverter(), getTimer(),
new LatestProperty());
// make execution service
ThinkExecution = Executors.newFixedThreadPool(1);
double temp = config.getFloatValue("kernel.agents.think-time") * 0.8;
thinkRuntime = (int) temp;
temp = config.getFloatValue("kernel.agents.think-time") * 0.2;
fallbackRuntime = (int) temp;
this.ignoreUntil = config.getIntValue(IGNORE_KEY, 3);
getWorldModel().getStuckMemory().enableAutoUpdate(getWorldModel());
if (!getWorldModel().initialisedSearch()) {
getWorldModel().initialiseSearch(getID());
}
LOGGER.info("Finished postconnect");
} catch (Exception e) {
LOGGER.error("Exception during postconnect! " + e);
e.printStackTrace();
}
}
public static void stopIfInterrupted() {
if (Thread.currentThread().isInterrupted()) {
throw new RuntimeException();
}
}
/**
* Causes the agent to follow the default search behaviour. This will
* automatically submit a command, so the think method can return after
* calling this.
*/
public void doDefaultSearch() {
searchBehaviour.doDefaultSearch();
}
/**
* Returns the agent's default routing module.
*
* @return The agent's routing module.
*/
public IRoutingModule getRoutingModule() {
return getReusableRouting();
// return routing;
}
/**
* Returns the communication module. Use this to send messages.
*
* @return The communication module.
*/
public IAMCommunicationModule getCommunicationModule() {
return communicationModule;
}
/**
* Returns execution service. Use this to submit commands to the server.
*
* @return The execution service.
*/
public IExecutionService getExecutionService() {
return executionService;
}
@Override
protected final IAMWorldModel createWorldModel() {
IAMWorldModel wm = new IAMWorldModel(timer, config);
return wm;
}
/*
* (non-Javadoc)
*
* @see
* rescuecore2.components.AbstractComponent#getPreferredRegistry(rescuecore2
* .registry.Registry)
*/
@Override
public Registry getPreferredRegistry(Registry parent) {
Registry registry = new Registry(parent);
registry.registerEntityFactory(StandardEntityURN.BLOCKADE.toString(),
RoutingInfoBlockadeEntityFactory.INSTANCE);
registry.registerPropertyFactory(RoutingInfoBlockade.BLOCK_INFO_URN,
BlockedEdgesPropertyFactory.INSTANCE);
registry.registerEntityFactory(StandardEntityURN.ROAD.toString(),
BlockInfoRoadEntityFactory.INSTANCE);
registry
.registerPropertyFactory(KnownToBePassablePropertyFactory.INSTANCE);
return registry;
}
/**
* Returns the agent's world model.
*
* @return THe world model
*/
protected IAMWorldModel getWorldModel() {
return model;
}
public ISpeedInfo getSpeedInfo() {
return speedInfo;
}
@Override
public final String[] getRequestedEntityURNs() {
List<StandardEntityURN> agentTypes = getAgentTypes();
String[] result = new String[agentTypes.size()];
for (int i = 0; i < result.length; i++) {
result[i] = agentTypes.get(i).toString();
}
return result;
}
/**
* Returns the spatial index used by this agent (creates one if necessary).
*
* @return The spatial index.
*/
/*
* public ISpatialIndex getSpatialIndex() { if (spatialIndex == null) {
* spatialIndex = new SpatialIndex(getWorldModel()); } return spatialIndex;
* }
*/
/**
* Subclasses need to define which agents they want to control
*
* @return
*/
protected abstract List<StandardEntityURN> getAgentTypes();
protected void addUpdateHandler(IMessageHandler handler) {
worldModelCommsUpdater.addUpdateHandler(handler);
}
/**
* Plans a path from the agent's current position to another entity
* (building, road, agent...).
*
* @param id
* The target ID.
* @return The shortest path or an invalid path if none could be found
* (e.g., if blocked).
*/
protected IPath planPath(EntityID id) {
return getRoutingModule().findShortestPath(getID(), id);
}
/**
* Plans a path from the agent's current position to the closest of a set of
* other entities (buildings, roads, agents...).
*
* @param ids
* The target IDs.
* @return The shortest path to the closest entity or an invalid path if
* none could be found (e.g., if all are blocked).
*/
protected IPath planPath(Collection<EntityID> ids) {
return getRoutingModule().findShortestPath(getID(), ids);
}
/**
* @return the reusableRouting
*/
public IRoutingModule getReusableRouting() {
if (reusableRouting == null) {
if (USE_BLOCK_DETECTION) {
reusableRouting = new BlockDetectingRoutingModule(
getWorldModel(), routingCostFunction, timer,
executionService, getID(), speedInfo, false);
} else {
reusableRouting = new SimpleDijkstrasRoutingModule(
getWorldModel(), routingCostFunction, timer);
}
}
return reusableRouting;
}
private class ThinkRunner implements Runnable {
private ChangeSet changeSet;
private int time;
public ThinkRunner(int time2, ChangeSet changed) {
time = time2;
changeSet = changed;
}
@Override
public void run() {
Thread.currentThread().setName(me().toString() + " " + time);
think(time, changeSet);
}
}
private class FallbackRunner implements Runnable {
private ChangeSet changeSet;
private int time;
public FallbackRunner(int time2, ChangeSet changed) {
time = time2;
changeSet = changed;
}
@Override
public void run() {
Thread.currentThread().setName(me().toString() + " " + time);
fallback(time, changeSet);
}
}
}