in Minecraft/src/main/java/com/microsoft/Malmo/Client/ClientStateMachine.java [431:662]
protected void initialiseComms() throws UnknownHostException
{
// Start polling for missions:
if (this.missionPoller != null)
{
this.missionPoller.stopServer();
}
this.missionPoller = new TCPInputPoller(AddressHelper.getMissionControlPortOverride(), AddressHelper.MIN_MISSION_CONTROL_PORT, AddressHelper.MAX_FREE_PORT, true, "mcp")
{
@Override
public void onError(String error, DataOutputStream dos)
{
System.out.println("SENDING ERROR: " + error);
try
{
dos.writeInt(error.length());
dos.writeBytes(error);
dos.flush();
}
catch (IOException e)
{
}
}
private void reply(String reply, DataOutputStream dos)
{
System.out.println("REPLYING WITH: " + reply);
try
{
dos.writeInt(reply.length());
dos.writeBytes(reply);
dos.flush();
}
catch (IOException e)
{
System.out.println("Failed to reply to message!");
}
}
@Override
public boolean onCommand(String command, String ipFrom, DataOutputStream dos)
{
System.out.println("Received from " + ipFrom + ":" +
command.substring(0, Math.min(command.length(), 1024)));
boolean keepProcessing = false;
// Possible commands:
// 1: MALMO_REQUEST_CLIENT:<malmo version>:<reservation_length(ms)><experiment_id>
// 2: MALMO_CANCEL_REQUEST
// 3: MALMO_FIND_SERVER<experiment_id>
// 4: MALMO_KILL_CLIENT
// 5: MissionInit
String reservePrefixGeneral = "MALMO_REQUEST_CLIENT:";
String reservePrefix = reservePrefixGeneral + Loader.instance().activeModContainer().getVersion() + ":";
String findServerPrefix = "MALMO_FIND_SERVER";
String cancelRequestCommand = "MALMO_CANCEL_REQUEST";
String killClientCommand = "MALMO_KILL_CLIENT";
if (command.startsWith(reservePrefix))
{
// Reservation request.
// We either reply with MALMOOK, if we are free, or MALMOBUSY if not.
IState currentState = getStableState();
if (currentState != null && currentState.equals(ClientState.DORMANT) && !isReserved())
{
reserveClient(command.substring(reservePrefix.length()));
reply("MALMOOK", dos);
}
else
{
// We're busy - we can't be reserved.
reply("MALMOBUSY", dos);
}
}
else if (command.startsWith(reservePrefixGeneral))
{
// Reservation request, but it didn't match the request we expect, above.
// This happens if the agent sending the request is running a different version of Malmo -
// a version mismatch error.
reply("MALMOERRORVERSIONMISMATCH in reservation string (Got " + command + ", expected " + reservePrefix + " - check your path for old versions of MalmoPython/MalmoJava/Malmo.lib etc)", dos);
}
else if (command.equals(cancelRequestCommand))
{
// If we've been reserved, cancel the reservation.
if (isReserved())
{
cancelReservation();
reply("MALMOOK", dos);
}
else
{
// We weren't reserved in the first place - something is odd.
reply("MALMOERRORAttempt to cancel a reservation that was never made.", dos);
}
}
else if (command.startsWith(findServerPrefix))
{
// Request to find the server for the given experiment ID.
String expID = command.substring(findServerPrefix.length());
if (currentMissionInit() != null && currentMissionInit().getExperimentUID().equals(expID))
{
// Our Experiment IDs match, so we are running the same experiment.
// Return the port and server IP address to the caller:
MinecraftServerConnection msc = currentMissionInit().getMinecraftServerConnection();
if (msc == null)
reply("MALMONOSERVERYET", dos); // Mission might be starting up.
else
reply("MALMOS" + msc.getAddress().trim() + ":" + msc.getPort(), dos);
}
else
{
// We don't have a MissionInit ourselves, or we're running a different experiment,
// so we can't help.
reply("MALMONOSERVER", dos);
}
}
else if (command.equals(killClientCommand))
{
// Kill switch provided in case AI takes over the world...
// Or, more likely, in case this Minecraft instance has become unreliable (eg if it's been running for several days)
// and needs to be replaced with a fresh instance.
// If we are currently running a mission, we gracefully decline, to prevent users from wiping out
// other users' experiments.
// We also decline unless we were launched in "replaceable" mode - a command-line switch that indicates we were
// launched by a script which is still running, and can therefore replace us when we terminate.
IState currentState = getStableState();
if (currentState != null && currentState.equals(ClientState.DORMANT) && !isReserved())
{
Configuration config = MalmoMod.instance.getModSessionConfigFile();
if (config.getBoolean("replaceable", "runtype", false, "Will be replaced if killed"))
{
reply("MALMOOK", dos);
missionPoller.stopServer();
exitJava();
}
else
{
reply("MALMOERRORNOTKILLABLE", dos);
}
}
else
{
// We're too busy and important to be killed.
reply("MALMOBUSY", dos);
}
}
else
{
// See if we've been sent a MissionInit message:
MissionInitResult missionInitResult = decodeMissionInit(command);
if (missionInitResult.wasMissionInit && missionInitResult.missionInit == null)
{
// Got sent a duff MissionInit xml - pass back the JAXB/SAXB errors.
reply("MALMOERROR" + missionInitResult.error, dos);
}
else if (missionInitResult.wasMissionInit && missionInitResult.missionInit != null)
{
MissionInit missionInit = missionInitResult.missionInit;
// We've been sent a MissionInit message.
// First, check the version number:
String platformVersion = missionInit.getPlatformVersion();
String ourVersion = Loader.instance().activeModContainer().getVersion();
if (platformVersion == null || !platformVersion.equals(ourVersion))
{
reply("MALMOERRORVERSIONMISMATCH (Got " + platformVersion + ", expected " + ourVersion + " - check your path for old versions of MalmoPython/MalmoJava/Malmo.lib etc)", dos);
}
else
{
// MissionInit passed to us - this is a request to launch this mission. Can we?
IState currentState = getStableState();
if (currentState != null && currentState.equals(ClientState.DORMANT) && isAvailable(missionInit.getExperimentUID()))
{
reply("MALMOOK", dos);
keepProcessing = true; // State machine will now process this MissionInit and start the mission.
}
else
{
// We're busy - we can't run this mission.
reply("MALMOBUSY", dos);
}
}
}
}
return keepProcessing;
}
};
int mcPort = 0;
if (MalmoEnvServer.isEnv()) {
// Start up new "Env" service instead of Malmo AgentHost api.
System.out.println("***** Start MalmoEnvServer on port " + AddressHelper.getMissionControlPortOverride());
this.envServer = new MalmoEnvServer(Loader.instance().activeModContainer().getVersion(), AddressHelper.getMissionControlPortOverride(), this.missionPoller);
Thread thread = new Thread("MalmoEnvServer") {
public void run() {
try {
envServer.serve();
} catch (IOException ioe) {
System.out.println("MalmoEnvServer exist on " + ioe);
}
}
};
thread.start();
} else {
// "Legacy" AgentHost api.
this.missionPoller.start();
mcPort = ClientStateMachine.this.missionPoller.getPortBlocking();
}
// Tell the address helper what the actual port is:
AddressHelper.setMissionControlPort(mcPort);
if (AddressHelper.getMissionControlPort() == -1)
{
// Failed to create a mission control port - nothing will work!
System.out.println("**** NO MISSION CONTROL SOCKET CREATED - WAS THE PORT IN USE? (Check Mod GUI options) ****");
ClientStateMachine.this.getScreenHelper().addFragment("ERROR: Could not open a Mission Control Port - check the Mod GUI options.", TextCategory.TXT_CLIENT_WARNING, MISSING_MCP_PORT_ERROR);
}
else
{
// Clear the error string, if there was one:
ClientStateMachine.this.getScreenHelper().clearFragment(MISSING_MCP_PORT_ERROR);
}
// Display the port number:
ClientStateMachine.this.getScreenHelper().clearFragment(INFO_MCP_PORT);
if (AddressHelper.getMissionControlPort() != -1)
ClientStateMachine.this.getScreenHelper().addFragment("MCP: " + AddressHelper.getMissionControlPort(), TextCategory.TXT_INFO, INFO_MCP_PORT);
}