Unverified Commit 342fea6f authored by Juon Kawakami's avatar Juon Kawakami 🥗
Browse files

init

parent 54f6cedf
/*
* Last change: $Date: 2004/05/04 03:09:38 $
* $Revision: 1.2 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
/**
An exception to be thrown whenever a mobile RescueObject cannot be located
*/
public class CannotFindLocationException extends Exception {
public CannotFindLocationException() {super();}
/**
Construct a new exception with a given error message
@param s The error message
*/
public CannotFindLocationException(String s) {super(s);}
}
/*
* Last change: $Date: 2004/05/04 03:09:38 $
* $Revision: 1.3 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import rescuecore.objects.*;
/**
An abstract superclass for center agents (i.e fire station, police office, ambulance center).
*/
public abstract class CenterAgent extends Agent {
protected CenterAgent(int... types) {
super(types);
}
private Building me() {
return (Building)memory.lookup(id);
}
}
/*
* Last change: $Date: 2004/05/04 03:09:38 $
* $Revision: 1.3 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
public class CommunicationException extends Exception {
public CommunicationException() {super();}
public CommunicationException(String s) {super(s);}
public CommunicationException(java.net.InetAddress host, int port, String s) {super("Error talking to "+host+":"+port+": "+s);}
public CommunicationException(java.net.InetAddress host, int port, Throwable t) {super("Error talking to "+host+":"+port,t);}
}
/*
* Last change: $Date: 2005/06/14 21:55:50 $
* $Revision: 1.1 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.io.IOException;
/**
The Connection interface encapsulates the sending and receiving of messages to and from the kernel.
*/
public interface Connection {
/**
Close the connection
*/
public abstract void close();
/**
Send a message
@param msg The message to send
@throws IOException if something goes wrong during sending
*/
public abstract void send(byte[] data) throws IOException;
/**
Receive a message. If there is nothing to receive then this method will wait for the specified timeout (in ms, -1 to wait forever, 0 to not wait).
@param timeout The maximum time to wait, in ms. If this is negative then this method will wait forever (or until interrupted), if it is zero then this method will not block.
@return The next message to be received, or null if nothing is available
@throws IOException if there is an error during receiving
*/
public abstract byte[] receive(int timeout) throws IOException, InterruptedException;
}
/*
* Last change: $Date: 2004/07/11 22:26:27 $
* $Revision: 1.5 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
public class DummyAgent extends Agent {
public DummyAgent() {
super(RescueConstants.TYPE_FIRE_BRIGADE, RescueConstants.TYPE_AMBULANCE_TEAM, RescueConstants.TYPE_POLICE_FORCE, RescueConstants.TYPE_FIRE_STATION, RescueConstants.TYPE_AMBULANCE_CENTER, RescueConstants.TYPE_POLICE_OFFICE);
}
protected void sense() {}
}
/*
* Last change: $Date: 2005/03/15 00:46:38 $
* $Revision: 1.10 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.util.*;
import java.io.UnsupportedEncodingException;
import rescuecore.commands.*;
/**
A collection of useful methods
*/
public class Handy {
private final static String[] HEX_DIGITS = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
private final static String CHARACTER_ENCODING = "US-ASCII";
private final static Object PRINT_LOCK = new Object();
private Handy() {}
/**
Print an array of bytes to System.out in a nice way
@param data The bytes to print out
*/
public static void printBytes(byte[] data) {
printBytes(null,data);
}
/**
Print an array of bytes to System.out in a nice way
@param header A string to print out as a title
@param data The bytes to print out
*/
public static void printBytes(String header, byte[] data) {
synchronized(PRINT_LOCK) {
if (header!=null) System.out.println(header);
System.out.println("OFFSET\tBYTES");
for (int i=0;i<data.length;i+=4) {
printBytes(i,data,"");
}
}
}
public static void printBytes(InputBuffer in) {
printBytes(null,in);
}
public static void printBytes(String header, InputBuffer in) {
int position = in.getPosition();
byte[] temp = new byte[in.available()];
in.readBytes(temp);
printBytes(header,temp);
in.setPosition(position);
}
/**
Print four bytes to System.out in a nice way
@param startIndex The index of the first byte
@param data The buffer containing the bytes to print out
@param description A description of what these four bytes actually mean
*/
public static void printBytes(int startIndex, byte[] data, String description) {
StringBuffer buffer = new StringBuffer();
synchronized(PRINT_LOCK) {
buffer.append(startIndex);
buffer.append("\t");
for (int j=0;j<4;++j) {
if (data.length>startIndex+j) {
buffer.append(hex(data[startIndex+j]));
if (j!=3) buffer.append(" ");
}
}
buffer.append("\t");
char charValue = (char)decodeInt(data,startIndex);
if (Character.isLetterOrDigit(charValue)) buffer.append(charValue);
buffer.append("\t");
buffer.append(decodeInt(data,startIndex));
buffer.append("\t");
buffer.append(description);
System.out.println(buffer.toString());
}
}
/**
Turn a byte into a hexadecimal String
@param b The byte to convert
@return The byte in hexadecimal, as a String
*/
public static String hex(byte b) {
byte left = (byte)((b >> 4) & 0xF);
byte right = (byte)(b & 0xF);
return HEX_DIGITS[left]+HEX_DIGITS[right];
}
/**
Decode a byte from a buffer
@param buffer The buffer we are looking at
@param off The offset into the buffer to start decoding from
@return The next byte in the buffer
*/
/*
public static byte decodeByte(byte[] buffer, int off) {
return buffer[off];
}
*/
/**
Decode a byte array from a buffer
@param buffer The buffer we are looking at
@param off The offset into the buffer to start decoding from
@param length The number of bytes to read
@return The next byte array in the buffer
*/
/*
public static byte[] decodeBytes(byte[] buffer, int off, int length) {
byte[] result = new byte[length];
System.arraycopy(buffer,off,result,0,length);
return result;
}
*/
/**
Decode a short from a buffer
@param buffer The buffer we are looking at
@param off The offset into the buffer to start decoding from
@return The next short in the buffer
*/
/*
public static short decodeShort(byte[] buffer, int off) {
int result = ((buffer[off] << 8) & 0x0000FF00) | (buffer[off+1] & 0x000000FF);
return (short)result;
}
*/
/**
Decode an int from a buffer
@param buffer The buffer we are looking at
@param off The offset into the buffer to start decoding from
@return The next int in the buffer
*/
private static int decodeInt(byte[] buffer, int off) {
int result = ((buffer[off] << 24) & 0xFF000000) | ((buffer[off+1] << 16) & 0x00FF0000) | ((buffer[off+2] << 8) & 0x0000FF00) | (buffer[off+3] & 0x000000FF);
return result;
}
/**
Decode a String from a buffer
@param buffer The buffer we are looking at
@param off The offset into the buffer to start decoding from
@param length The number of characters in the String
@return The next String in the buffer
*/
/*
public static String decodeString(byte[] buffer, int off, int length) {
int realLength = Math.min(length,buffer.length-off);
byte[] data = new byte[realLength];
System.arraycopy(buffer,off,data,0,realLength);
try {
return new String(data,CHARACTER_ENCODING);
}
catch (UnsupportedEncodingException e) {
return new String(data);
}
}
*/
/**
Encode a byte into a byte array
@param value The byte to encode
@return A byte array representation of the input value
*/
/*
public static byte[] encodeByte(int value) {
return new byte[] {(byte)(value & 0xFF)};
}
*/
/**
Encode a byte into a buffer
@param value The byte to encode
@param buf The buffer to write the result into
@param off The offset to start writing at
*/
/*
public static void encodeByte(int value, byte[] buf, int off) {
buf[off] = (byte)(value&0xFF);
}
*/
/**
Encode a byte arrray into a buffer
@param bytes The byte array to encode
@param buf The buffer to write the result into
@param off The offset to start writing at
*/
/*
public static void encodeBytes(byte[] bytes, byte[] buf, int off) {
System.arraycopy(bytes,0,buf,off,bytes.length);
}
*/
/**
Encode part of a byte array into a buffer
@param bytes The byte arrray to encode
@param bytesOffset The offset into bytes to start writing from
@param bytesLength The number of bytes to write
@param buf The buffer to write the result into
@param off The offset to start writing at
*/
/*
public static void encodeBytes(byte[] bytes, int bytesOffset, int bytesLength, byte[] buf, int off) {
System.arraycopy(bytes,bytesOffset,buf,off,bytesLength);
}
*/
/**
Encode a short into a byte array
@param value The short to encode
@return A byte array representation of the input value
*/
/*
public static byte[] encodeShort(int value) {
byte[] result = new byte[2];
result[0] = (byte)(value >> 8 & 0xFF);
result[1] = (byte)(value & 0xFF);
return result;
}
*/
/**
Encode a short into a buffer
@param value The short to encode
@param buf The buffer to write the result into
@param off The offset to start writing at
*/
/*
public static void encodeShort(int value, byte[] buf, int off) {
buf[off] = (byte)(value >> 8 & 0xFF);
buf[off+1] = (byte)(value & 0xFF);
}
*/
/**
Encode an int into a byte array
@param value The int to encode
@return A byte array representation of the input value
*/
/*
public static byte[] encodeInt(int value) {
byte[] result = new byte[4];
result[0] = (byte)(value >> 24 & 0xFF);
result[1] = (byte)(value >> 16 & 0xFF);
result[2] = (byte)(value >> 8 & 0xFF);
result[3] = (byte)(value & 0xFF);
return result;
}
*/
/**
Encode an int into a buffer
@param value The int to encode
@param buf The buffer to write the result into
@param off The offset to start writing at
*/
/*
public static void encodeInt(int value, byte[] buf, int off) {
buf[off] = (byte)(value >> 24 & 0xFF);
buf[off+1] = (byte)(value >> 16 & 0xFF);
buf[off+2] = (byte)(value >> 8 & 0xFF);
buf[off+3] = (byte)(value & 0xFF);
}
*/
/**
Encode a String into a byte array
@param value The String to encode
@param length The maximum number of bytes to use
@return A byte array representation of the input byte
*/
/*
public static byte[] encodeString(String value, int length) {
byte[] result = new byte[length];
byte[] data;
try {
data = value.getBytes(CHARACTER_ENCODING);
}
catch (UnsupportedEncodingException e) {
data = value.getBytes();
}
System.arraycopy(data,0,result,0,Math.min(data.length,length));
return result;
}
*/
/**
Encode a String into a buffer
@param value The String to encode
@param length The maximum number of bytes to write
@param buf The buffer to write the result into
@param off The offset to start writing at
*/
/*
public static void encodeString(String value, int length, byte[] buf, int off) {
byte[] data;
try {
data = value.getBytes(CHARACTER_ENCODING);
}
catch (UnsupportedEncodingException e) {
data = value.getBytes();
}
System.arraycopy(data,0,buf,off,Math.min(data.length,length));
}
*/
/**
Find out if two int arrays are different. The two arrays are not different if and only if they are the same size and contain the same elements (possibly out of order).
@param a The first array
@param b The second array
@return true if and only if the two arrays are different
*/
/*
public static boolean isDifferent(int[] a, int[] b) {
if (a==null && b==null) return false;
if (a==null || b==null) return true;
if (a.length!=b.length) return true;
int[] aSorted = new int[a.length];
int[] bSorted = new int[b.length];
System.arraycopy(a,0,aSorted,0,a.length);
System.arraycopy(b,0,bSorted,0,b.length);
Arrays.sort(aSorted);
Arrays.sort(bSorted);
for (int i=0;i<a.length;++i) if (aSorted[i]!=bSorted[i]) return true;
return false;
}
*/
/**
Translate a type name into a human-readable string
@param type The type we want to convert
@return A human-readable String showing the type given
@see RescueConstants#TYPE_CIVILIAN
@see RescueConstants#TYPE_FIRE_BRIGADE
@see RescueConstants#TYPE_AMBULANCE_TEAM
@see RescueConstants#TYPE_POLICE_FORCE
@see RescueConstants#TYPE_ROAD
@see RescueConstants#TYPE_NODE
@see RescueConstants#TYPE_RIVER
@see RescueConstants#TYPE_RIVER_NODE
@see RescueConstants#TYPE_BUILDING
@see RescueConstants#TYPE_REFUGE
@see RescueConstants#TYPE_FIRE_STATION
@see RescueConstants#TYPE_AMBULANCE_CENTER
@see RescueConstants#TYPE_POLICE_OFFICE
@see RescueConstants#TYPE_WORLD
@see RescueConstants#TYPE_CAR
*/
public static String getTypeName(int type) {
switch(type) {
case RescueConstants.TYPE_NULL:
return "TYPE_NULL";
case RescueConstants.TYPE_CIVILIAN:
return "TYPE_CIVILIAN";
case RescueConstants.TYPE_FIRE_BRIGADE:
return "TYPE_FIRE_BRIGADE";
case RescueConstants.TYPE_AMBULANCE_TEAM:
return "TYPE_AMBULANCE_TEAM";
case RescueConstants.TYPE_POLICE_FORCE:
return "TYPE_POLICE_FORCE";
case RescueConstants.TYPE_ROAD:
return "TYPE_ROAD";
case RescueConstants.TYPE_NODE:
return "TYPE_NODE";
case RescueConstants.TYPE_RIVER:
return "TYPE_RIVER";
case RescueConstants.TYPE_RIVER_NODE:
return "TYPE_RIVER_NODE";
case RescueConstants.TYPE_BUILDING:
return "TYPE_BUILDING";
case RescueConstants.TYPE_REFUGE:
return "TYPE_REFUGE";
case RescueConstants.TYPE_FIRE_STATION:
return "TYPE_FIRE_STATION";
case RescueConstants.TYPE_AMBULANCE_CENTER:
return "TYPE_AMBULANCE_CENTER";
case RescueConstants.TYPE_POLICE_OFFICE:
return "TYPE_POLICE_OFFICE";
case RescueConstants.TYPE_WORLD:
return "TYPE_WORLD";
case RescueConstants.TYPE_CAR:
return "TYPE_CAR";
default:
return "Unknown type: "+type;
}
}
/**
Translate a property name into a human-readable string
@param type The property we want to convert
@return A human-readable String showing the property given
@see RescueConstants#PROPERTY_NULL
@see RescueConstants#PROPERTY_START_TIME
@see RescueConstants#PROPERTY_LONGITUDE
@see RescueConstants#PROPERTY_LATITUDE
@see RescueConstants#PROPERTY_WIND_FORCE
@see RescueConstants#PROPERTY_WIND_DIRECTION
@see RescueConstants#PROPERTY_X
@see RescueConstants#PROPERTY_Y
@see RescueConstants#PROPERTY_DIRECTION
@see RescueConstants#PROPERTY_POSITION
@see RescueConstants#PROPERTY_POSITION_HISTORY
@see RescueConstants#PROPERTY_POSITION_EXTRA
@see RescueConstants#PROPERTY_STAMINA
@see RescueConstants#PROPERTY_HP
@see RescueConstants#PROPERTY_DAMAGE
@see RescueConstants#PROPERTY_BURIEDNESS
@see RescueConstants#PROPERTY_FLOORS
@see RescueConstants#PROPERTY_BUILDING_ATTRIBUTES
@see RescueConstants#PROPERTY_IGNITION
@see RescueConstants#PROPERTY_BROKENNESS
@see RescueConstants#PROPERTY_FIERYNESS
@see RescueConstants#PROPERTY_ENTRANCES
@see RescueConstants#PROPERTY_BUILDING_SHAPE_ID
@see RescueConstants#PROPERTY_BUILDING_CODE
@see RescueConstants#PROPERTY_BUILDING_AREA_GROUND
@see RescueConstants#PROPERTY_BUILDING_AREA_TOTAL
@see RescueConstants#PROPERTY_BUILDING_APEXES
@see RescueConstants#PROPERTY_WATER_QUANTITY
@see RescueConstants#PROPERTY_STRETCHED_LENGTH
@see RescueConstants#PROPERTY_HEAD
@see RescueConstants#PROPERTY_TAIL
@see RescueConstants#PROPERTY_LENGTH
@see RescueConstants#PROPERTY_ROAD_KIND
@see RescueConstants#PROPERTY_CARS_PASS_TO_HEAD
@see RescueConstants#PROPERTY_CARS_PASS_TO_TAIL
@see RescueConstants#PROPERTY_HUMANS_PASS_TO_HEAD
@see RescueConstants#PROPERTY_HUMANS_PASS_TO_TAIL
@see RescueConstants#PROPERTY_WIDTH
@see RescueConstants#PROPERTY_BLOCK
@see RescueConstants#PROPERTY_REPAIR_COST
@see RescueConstants#PROPERTY_MEDIAN_STRIP
@see RescueConstants#PROPERTY_LINES_TO_HEAD
@see RescueConstants#PROPERTY_LINES_TO_TAIL
@see RescueConstants#PROPERTY_WIDTH_FOR_WALKERS
@see RescueConstants#PROPERTY_EDGES
@see RescueConstants#PROPERTY_SIGNAL
@see RescueConstants#PROPERTY_SIGNAL_TIMING
@see RescueConstants#PROPERTY_SHORTCUT_TO_TURN
@see RescueConstants#PROPERTY_POCKET_TO_TURN_ACROSS
*/
public static String getPropertyName(int type) {
switch (type) {
case RescueConstants.PROPERTY_NULL:
return "PROPERTY_NULL";
case RescueConstants.PROPERTY_START_TIME:
return "PROPERTY_START_TIME";
case RescueConstants.PROPERTY_LONGITUDE:
return "PROPERTY_LONGITUDE";
case RescueConstants.PROPERTY_LATITUDE:
return "PROPERTY_LATITUDE";
case RescueConstants.PROPERTY_WIND_FORCE:
return "PROPERTY_WIND_FORCE";
case RescueConstants.PROPERTY_WIND_DIRECTION:
return "PROPERTY_WIND_DIRECTION";
case RescueConstants.PROPERTY_X:
return "PROPERTY_X";
case RescueConstants.PROPERTY_Y:
return "PROPERTY_Y";
case RescueConstants.PROPERTY_DIRECTION:
return "PROPERTY_DIRECTION";
case RescueConstants.PROPERTY_POSITION:
return "PROPERTY_POSITION";
case RescueConstants.PROPERTY_POSITION_HISTORY:
return "PROPERTY_POSITION_HISTORY";
case RescueConstants.PROPERTY_POSITION_EXTRA:
return "PROPERTY_POSITION_EXTRA";
case RescueConstants.PROPERTY_STAMINA:
return "PROPERTY_STAMINA";
case RescueConstants.PROPERTY_HP:
return "PROPERTY_HP";
case RescueConstants.PROPERTY_DAMAGE:
return "PROPERTY_DAMAGE";
case RescueConstants.PROPERTY_BURIEDNESS:
return "PROPERTY_BURIEDNESS";
case RescueConstants.PROPERTY_FLOORS:
return "PROPERTY_FLOORS";
case RescueConstants.PROPERTY_BUILDING_ATTRIBUTES:
return "PROPERTY_BUILDING_ATTRIBUTES";
case RescueConstants.PROPERTY_IGNITION:
return "PROPERTY_IGNITION";
case RescueConstants.PROPERTY_BROKENNESS:
return "PROPERTY_BROKENNESS";
case RescueConstants.PROPERTY_FIERYNESS:
return "PROPERTY_FIERYNESS";
case RescueConstants.PROPERTY_ENTRANCES:
return "PROPERTY_ENTRANCES";
// case RescueConstants.PROPERTY_BUILDING_SHAPE_ID:
// return "PROPERTY_BUILDING_SHAPE_ID";
case RescueConstants.PROPERTY_BUILDING_CODE:
return "PROPERTY_BUILDING_CODE";
case RescueConstants.PROPERTY_BUILDING_AREA_GROUND:
return "PROPERTY_BUILDING_AREA_GROUND";
case RescueConstants.PROPERTY_BUILDING_AREA_TOTAL:
return "PROPERTY_BUILDING_AREA_TOTAL";
case RescueConstants.PROPERTY_BUILDING_APEXES:
return "PROPERTY_BUILDING_APEXES";
case RescueConstants.PROPERTY_WATER_QUANTITY:
return "PROPERTY_WATER_QUANTITY";
// case RescueConstants.PROPERTY_STRETCHED_LENGTH:
// return "PROPERTY_STRETCHED_LENGTH";
case RescueConstants.PROPERTY_HEAD:
return "PROPERTY_HEAD";
case RescueConstants.PROPERTY_TAIL:
return "PROPERTY_TAIL";
case RescueConstants.PROPERTY_LENGTH:
return "PROPERTY_LENGTH";
case RescueConstants.PROPERTY_ROAD_KIND:
return "PROPERTY_ROAD_KIND";
case RescueConstants.PROPERTY_CARS_PASS_TO_HEAD:
return "PROPERTY_CARS_PASS_TO_HEAD";
case RescueConstants.PROPERTY_CARS_PASS_TO_TAIL:
return "PROPERTY_CARS_PASS_TO_TAIL";
case RescueConstants.PROPERTY_HUMANS_PASS_TO_HEAD:
return "PROPERTY_HUMANS_PASS_TO_HEAD";
case RescueConstants.PROPERTY_HUMANS_PASS_TO_TAIL:
return "PROPERTY_HUMANS_PASS_TO_TAIL";
case RescueConstants.PROPERTY_WIDTH:
return "PROPERTY_WIDTH";
case RescueConstants.PROPERTY_BLOCK:
return "PROPERTY_BLOCK";
case RescueConstants.PROPERTY_REPAIR_COST:
return "PROPERTY_REPAIR_COST";
case RescueConstants.PROPERTY_MEDIAN_STRIP:
return "PROPERTY_MEDIAN_STRIP";
case RescueConstants.PROPERTY_LINES_TO_HEAD:
return "PROPERTY_LINES_TO_HEAD";
case RescueConstants.PROPERTY_LINES_TO_TAIL:
return "PROPERTY_LINES_TO_TAIL";
case RescueConstants.PROPERTY_WIDTH_FOR_WALKERS:
return "PROPERTY_WIDTH_FOR_WALKERS";
case RescueConstants.PROPERTY_EDGES:
return "PROPERTY_EDGES";
case RescueConstants.PROPERTY_SIGNAL:
return "PROPERTY_SIGNAL";
case RescueConstants.PROPERTY_SIGNAL_TIMING:
return "PROPERTY_SIGNAL_TIMING";
case RescueConstants.PROPERTY_SHORTCUT_TO_TURN:
return "PROPERTY_SHORTCUT_TO_TURN";
case RescueConstants.PROPERTY_POCKET_TO_TURN_ACROSS:
return "PROPERTY_POCKET_TO_TURN_ACROSS";
case RescueConstants.PROPERTY_BUILDING_IMPORTANCE:
return "PROPERTY_BUILDING_IMPORTANCE";
case RescueConstants.PROPERTY_BUILDING_TEMPERATURE:
return "PROPERTY_BUILDING_TEMPERATURE";
default:
return "Unknown property: "+type;
}
}
/**
Translate a command type into a human-readable string
@param header The type we want to convert
@return A human-readable String showing the type given
@see RescueConstants#HEADER_NULL
@see RescueConstants#AK_CONNECT
@see RescueConstants#AK_ACKNOWLEDGE
@see RescueConstants#AK_REST
@see RescueConstants#AK_MOVE
@see RescueConstants#AK_EXTINGUISH
@see RescueConstants#AK_RESCUE
@see RescueConstants#AK_CLEAR
@see RescueConstants#AK_LOAD
@see RescueConstants#AK_UNLOAD
@see RescueConstants#KA_CONNECT_OK
@see RescueConstants#KA_CONNECT_ERROR
@see RescueConstants#KA_SENSE
@see RescueConstants#KA_HEAR
@see RescueConstants#SK_CONNECT
@see RescueConstants#SK_ACKNOWLEDGE
@see RescueConstants#SK_UPDATE
@see RescueConstants#KS_CONNECT_OK
@see RescueConstants#KS_CONNECT_ERROR
@see RescueConstants#KS_COMMANDS
@see RescueConstants#KG_CONNECT
@see RescueConstants#KG_ACKNOWLEDGE
@see RescueConstants#KG_UPDATE
@see RescueConstants#GK_CONNECT_OK
@see RescueConstants#GK_CONNECT_ERROR
*/
public static String getCommandTypeName(int header) {
switch (header) {
case RescueConstants.HEADER_NULL:
return "HEADER_NULL";
case RescueConstants.GK_CONNECT_OK:
return "GK_CONNECT_OK";
case RescueConstants.GK_CONNECT_ERROR:
return "GK_CONNECT_ERROR";
case RescueConstants.KG_CONNECT:
return "KG_CONNECT";
case RescueConstants.KG_ACKNOWLEDGE:
return "KG_ACKNOWLEDGE";
case RescueConstants.SK_CONNECT:
return "SK_CONNECT";
case RescueConstants.SK_ACKNOWLEDGE:
return "SK_ACKNOWLEDGE";
case RescueConstants.SK_UPDATE:
return "SK_UPDATE";
case RescueConstants.KS_CONNECT_OK:
return "KS_CONNECT_OK";
case RescueConstants.KS_CONNECT_ERROR:
return "KS_CONNECT_ERROR";
case RescueConstants.COMMANDS:
return "COMMANDS";
case RescueConstants.UPDATE:
return "UPDATE";
case RescueConstants.VK_CONNECT:
return "VK_CONNECT";
case RescueConstants.VK_ACKNOWLEDGE:
return "VK_ACKNOWLEDGE";
case RescueConstants.KV_CONNECT_OK:
return "KV_CONNECT_OK";
case RescueConstants.KV_CONNECT_ERROR:
return "KV_CONNECT_ERROR";
// case RescueConstants.KV_UPDATE:
// return "KV_UPDATE";
case RescueConstants.AK_CONNECT:
return "AK_CONNECT";
case RescueConstants.AK_ACKNOWLEDGE:
return "AK_ACKNOWLEDGE";
case RescueConstants.AK_REST:
return "AK_REST";
case RescueConstants.AK_MOVE:
return "AK_MOVE";
case RescueConstants.AK_EXTINGUISH:
return "AK_EXTINGUISH";
case RescueConstants.AK_CLEAR:
return "AK_CLEAR";
case RescueConstants.AK_RESCUE:
return "AK_RESCUE";
case RescueConstants.AK_LOAD:
return "AK_LOAD";
case RescueConstants.AK_UNLOAD:
return "AK_UNLOAD";
case RescueConstants.AK_CHANNEL:
return "AK_CHANNEL";
case RescueConstants.AK_REPAIR:
return "AK_REPAIR";
case RescueConstants.KA_CONNECT_OK:
return "KA_CONNECT_OK";
case RescueConstants.KA_CONNECT_ERROR:
return "KA_CONNECT_ERROR";
case RescueConstants.KA_SENSE:
return "KA_SENSE";
case RescueConstants.KA_HEAR:
return "KA_HEAR";
// case RescueConstants.KA_HEAR_SAY:
// return "KA_HEAR_SAY";
// case RescueConstants.KA_HEAR_TELL:
// return "KA_HEAR_TELL";
default:
return "Unknown header: "+header;
}
}
/**
Turn an agent type into a human-readable String
@param type The agent type to convert
@return A human-readable version of the type given
*/
public static String getAgentTypeName(int type) {
StringBuffer result = new StringBuffer();
if ((type & RescueConstants.AGENT_TYPE_CIVILIAN)==RescueConstants.AGENT_TYPE_CIVILIAN) result.append("Civilian, ");
if ((type & RescueConstants.AGENT_TYPE_FIRE_BRIGADE)==RescueConstants.AGENT_TYPE_FIRE_BRIGADE) result.append("Fire Brigade, ");
if ((type & RescueConstants.AGENT_TYPE_FIRE_STATION)==RescueConstants.AGENT_TYPE_FIRE_STATION) result.append("Fire Station, ");
if ((type & RescueConstants.AGENT_TYPE_AMBULANCE_TEAM)==RescueConstants.AGENT_TYPE_AMBULANCE_TEAM) result.append("Ambulance Team, ");
if ((type & RescueConstants.AGENT_TYPE_AMBULANCE_CENTER)==RescueConstants.AGENT_TYPE_AMBULANCE_CENTER) result.append("Ambulance Center, ");
if ((type & RescueConstants.AGENT_TYPE_POLICE_FORCE)==RescueConstants.AGENT_TYPE_POLICE_FORCE) result.append("Police Force, ");
if ((type & RescueConstants.AGENT_TYPE_POLICE_OFFICE)==RescueConstants.AGENT_TYPE_POLICE_OFFICE) result.append("Police Office, ");
String s = result.toString();
if (s.length()>0) return s.substring(0,s.length()-2);
return "Unknown";
}
/**
Turn an array of integers into a String containing a comma-seperated list of numbers
@param array The array to convert
@return A human-readable String containing a comma-seperated list of numbers
*/
public static String arrayAsString(int[] array) {
if (array==null) return "null";
StringBuffer result = new StringBuffer();
for (int i=0;i<array.length;++i) {
result.append(array[i]);
if (i<array.length-1) result.append(", ");
}
return result.toString();
}
public static String arrayAsString(Object[] array) {
if (array==null) return "null";
StringBuffer result = new StringBuffer();
for (int i=0;i<array.length;++i) {
result.append(array[i]==null?"null":array[i].toString());
if (i<array.length-1) result.append(", ");
}
return result.toString();
}
public static String collectionAsString(Collection c) {
if (c==null) return "null";
StringBuffer result = new StringBuffer();
for (Iterator it = c.iterator();it.hasNext();) {
Object next = it.next();
result.append(next==null?"null":next.toString());
if (it.hasNext()) result.append(", ");
}
return result.toString();
}
public static RescueObject[] merge(RescueObject[] o1, RescueObject[] o2) {
RescueObject[] result = new RescueObject[o1.length+o2.length];
System.arraycopy(o1,0,result,0,o1.length);
System.arraycopy(o2,0,result,o1.length,o2.length);
return result;
}
}
/*
* Last change: $Date: 2004/05/04 03:09:38 $
* $Revision: 1.7 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
/**
* This is an implementation of Memory that stores the data in a hashtable
*/
public class HashMemory extends Memory {
protected Map data;
/**
* Construct a new empty memory
*/
public HashMemory() {
data = new HashMap();
}
public Memory copy() {
HashMemory m = new HashMemory();
Iterator it = data.values().iterator();
while (it.hasNext()) {
RescueObject o = (RescueObject) it.next();
m.add(o.copy(), 0, RescueConstants.SOURCE_UNKNOWN);
}
return m;
}
public RescueObject lookup(int id) {
return (RescueObject) data.get(Integer.valueOf(id));
}
public Collection<RescueObject> getAllObjects() {
return new HashSet<RescueObject>(data.values());
}
public void getObjectsOfType(Collection<RescueObject> result, int... types) {
for (Iterator it = data.values().iterator(); it.hasNext();) {
RescueObject next = (RescueObject) it.next();
int type = next.getType();
for (int nextType : types) {
if (type == nextType) {
result.add(next);
break;
}
}
}
}
/*
* public RescueObject[] getObjectsOfInternalType(int type) { List result = new
* ArrayList(); for (Iterator it = data.values().iterator();it.hasNext();) {
* RescueObject next = (RescueObject)it.next(); if (next!=null &&
* (next.getInternalType() & type)!=0) result.add(next); } return
* (RescueObject[])result.toArray(new RescueObject[0]); }
*/
public void add(RescueObject o, int timestamp, Object source) {
data.put(Integer.valueOf(o.getID()), o);
super.add(o, timestamp, source);
}
public void remove(RescueObject o) {
data.remove(Integer.valueOf(o.getID()));
super.remove(o);
}
}
\ No newline at end of file
/*
* Last change: $Date: 2005/02/20 01:29:55 $
* $Revision: 1.15 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import rescuecore.commands.*;
import rescuecore.objects.*;
import java.util.*;
public class InputBuffer {
private byte[] data;
private int index;
public InputBuffer(byte[] b) {
data = new byte[b.length];
System.arraycopy(b,0,data,0,b.length);
}
public int getSize() {
return data.length;
}
public int available() {
return data.length-index;
}
public byte readByte() {
return data[index++];
}
public void readBytes(byte[] result) {
System.arraycopy(data,index,result,0,result.length);
index += result.length;
}
public short readShort() {
int result = ((data[index++] << 8) & 0xFF00) | (data[index++] & 0x00FF);
return (short)result;
}
public int readInt() {
int result = ((data[index++] << 24) & 0xFF000000) | ((data[index++] << 16) & 0x00FF0000) | ((data[index++] << 8) & 0x0000FF00) | (data[index++] & 0x000000FF);
return result;
}
public String readString() {
byte[] result = new byte[readInt()];
readBytes(result);
return new String(result);
}
public void reset() {
index = 0;
}
public void skip(int size) {
index += size;
}
public int getPosition() {
return index;
}
public void setPosition(int i) {
index = i;
}
/**
Decode a new RescueObject from the buffer
@param timestamp The current simulation timestamp
@param source The source of the new object
@return The next RescueObject in the buffer. Returns null if the next object is TYPE_NULL.
@see RescueConstants#TYPE_NULL
*/
public RescueObject readObject(int timestamp, Object source) {
int type = readInt();
if (type==RescueConstants.TYPE_NULL) return null;
int id = readInt();
int size = readInt();
RescueObject result = RescueObject.newObject(type);
if (result==null) skip(size);
else if (size>0) {
result.read(this,timestamp,source);
}
result.setID(id);
return result;
}
/**
Decode a set of objects from the buffer.
@param timestamp The current simulation timestamp
@param source The source of the new objects
@return The next RescueObject array in the buffer
*/
public RescueObject[] readObjects(int timestamp, Object source) {
List<RescueObject> result = new ArrayList<RescueObject>();
int count = readInt();
for (int i = 0; i < count; ++i) {
RescueObject next = readObject(timestamp, source);
result.add(next);
};
return (RescueObject[])result.toArray(new RescueObject[0]);
}
public Command readCommand() {
int type = readInt();
if (type==RescueConstants.HEADER_NULL) return null;
int size = readInt();
return readCommand(type,size);
}
public Command readCommand(int type, int size) {
Command c = null;
switch (type) {
case RescueConstants.AK_EXTINGUISH:
c = new AKExtinguish(this);
break;
case RescueConstants.AK_MOVE:
c = new AKMove(this);
break;
case RescueConstants.AK_CLEAR:
c = new AKClear(this);
break;
case RescueConstants.AK_LOAD:
c = new AKLoad(this);
break;
case RescueConstants.AK_UNLOAD:
c = new AKUnload(this);
break;
case RescueConstants.AK_RESCUE:
c = new AKRescue(this);
break;
case RescueConstants.AK_SAY:
c = new AKSay(this);
break;
case RescueConstants.AK_TELL:
c = new AKTell(this);
break;
case RescueConstants.AK_REST:
c = new AKRest(this);
break;
case RescueConstants.AK_CONNECT:
c = new AKConnect(this);
break;
case RescueConstants.AK_ACKNOWLEDGE:
c = new AKAcknowledge(this);
break;
case RescueConstants.KA_CONNECT_OK:
c = new KAConnectOK(this);
break;
case RescueConstants.KA_CONNECT_ERROR:
c = new KAConnectError(this);
break;
case RescueConstants.KA_SENSE:
c = new KASense(this);
break;
case RescueConstants.KA_HEAR:
case RescueConstants.KA_HEAR_SAY:
case RescueConstants.KA_HEAR_TELL:
c = new KAHear(this);
break;
/*
case RescueConstants.KA_HEAR_SAY:
c = KAHear.KA_HEAR_SAY(this);
break;
case RescueConstants.KA_HEAR_TELL:
c = KAHear.KA_HEAR_TELL(this);
break;
*/
case RescueConstants.SK_CONNECT:
c = new SKConnect(this);
break;
case RescueConstants.SK_ACKNOWLEDGE:
c = new SKAcknowledge(this);
break;
case RescueConstants.SK_UPDATE:
c = new SKUpdate(this);
break;
case RescueConstants.KS_CONNECT_OK:
c = new KSConnectOK(this);
break;
case RescueConstants.KS_CONNECT_ERROR:
c = new KSConnectError(this);
break;
case RescueConstants.COMMANDS:
c = new Commands(this);
break;
case RescueConstants.UPDATE:
c = new Update(this);
break;
case RescueConstants.VK_CONNECT:
c = new VKConnect(this);
break;
case RescueConstants.VK_ACKNOWLEDGE:
c = new VKAcknowledge(this);
break;
case RescueConstants.KV_CONNECT_OK:
c = new KVConnectOK(this);
break;
case RescueConstants.KV_CONNECT_ERROR:
c = new KVConnectError(this);
break;
// case RescueConstants.KV_UPDATE:
// c = new KVUpdate(this);
// break;
default:
System.err.println("Don't know how to decode commands of type "+Handy.getCommandTypeName(type));
skip(size);
break;
}
return c;
}
/**
Decode a set of commands from the buffer.
@return The next Command array in the buffer
*/
public Command[] readCommands() {
List<Command> result = new ArrayList<Command>();
Command next = null;
do {
next = readCommand();
if (next!=null) {
result.add(next);
}
} while (next!=null);
return (Command[])result.toArray(new Command[0]);
}
}
/*
* Last change: $Date: 2005/02/20 01:29:55 $
* $Revision: 1.15 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.util.*;
import java.io.*;
/**
This class encapsulates information about an individual property within a RescueObject
*/
public class IntProperty extends Property {
private int value;
public IntProperty(int type) {
super(type);
}
public IntProperty(int type, boolean value) {
this(type,value?1:0);
}
public IntProperty(int type, int value) {
super(type);
this.value = value;
lastUpdate = 0;
}
/*
public Property copy() {
return new IntProperty(type,value);
}
*/
/**
Get the value of this property.
@return The integer value of this property
*/
public int getValue() {
return value;
}
/**
Get the value of this property as a string
@return A nice string representation of the value of this property
*/
public String getStringValue() {
StringBuffer result = new StringBuffer();
result.append(value);
return result.toString();
}
/**
Set the value of this property. The timestamp will also be updated. Note that this method does not check that the update is newer than the current value - it is up to the application to test for this.
@param newValue The new value
@param timestamp The timestamp of this update
@param source The source of this update
@return true if and only if the value was actually changed, i.e the new value is different from the old value
@see #isOlderThan(int)
*/
public boolean setValue(int newValue, int timestamp, Object source) {
lastUpdate = timestamp;
lastUpdateSource = source;
if (value==newValue) return false;
value = newValue;
return true;
}
/**
Update the value of this property. The timestamp will also be updated.
@param newValue The new value
@param timestamp The timestamp of this update
@param source The source of this update
@return true if and only if the value was actually changed, i.e the new value is different from the old value, and the new timestamp is greater than the old timestamp
@see #isOlderThan(int)
*/
public boolean updateValue(int newValue, int timestamp, Object source) {
if (timestamp <= lastUpdate) return false;
if (lastUpdate>=0 && newValue==value) return false;
lastUpdate = timestamp;
lastUpdateSource = source;
value = newValue;
return true;
}
/**
Merge this Property with a different one
@param p The Property to merge from
@return true if and only if the value of this property was actually changed
*/
public boolean merge(Property p) {
if (p instanceof IntProperty) {
return updateValue(((IntProperty)p).value,p.lastUpdate,p.lastUpdateSource);
}
return false;
/*
if (p.lastUpdate <= this.lastUpdate) return false;
if (p instanceof IntProperty) {
IntProperty i = (IntProperty)p;
lastUpdate = i.lastUpdate;
lastUpdateSource = i.lastUpdateSource;
if (value==i.value) return false;
value = i.value;
return true;
}
return false;
*/
}
/**
Write this property to an OutputBuffer
@param out The OutputBuffer to write this property to
*/
public void write(OutputBuffer out) {
out.writeInt(value);
}
/**
Decode property data from an InputBuffer.
@param in An InputBuffer to read data from
@param timestamp The timestamp of this update
@param source The source of this update
@return true if and only if a change was made
*/
public boolean read(InputBuffer in, int timestamp, Object source) {
// System.out.println("Timestep "+timestamp+": updating "+this+" from buffer");
int newValue = in.readInt();
return updateValue(newValue,timestamp,source);
/*
if (lastUpdate < timestamp) {
changed = (newValue != value);
if (changed) {
value = newValue;
lastUpdate = timestamp;
lastUpdateSource = source;
}
}
return changed;
*/
}
}
/*
* Last change: $Date: 2005/06/14 21:55:50 $
* $Revision: 1.9 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import rescuecore.commands.Command;
/**
* The Launch class is responsible for starting rescue components.
*/
public class Launch {
private static Collection components;
private final static int TIMEOUT = 60000;
private final static String UDP_FLAG = "-u";
private final static String UDP_LONG_FLAG = "--udp";
/**
* Launch some rescue components
*/
public static void main(String[] args) {
boolean tcp = true;
components = new ArrayList();
InetAddress kernel = null;
int kernelPort = -1;
if (args.length < 3) {
printUsage();
return;
}
try {
kernel = InetAddress.getByName(args[0]);
kernelPort = Integer.parseInt(args[1]);
} catch (UnknownHostException e) {
System.out.println("Bad host name: " + args[0]);
printUsage();
return;
} catch (NumberFormatException e) {
System.out.println("Bad host port: " + args[1]);
printUsage();
return;
}
Collection launch = new ArrayList();
for (int i = 2; i < args.length; ++i) {
// Process the next argument
if (args[i].startsWith("-")) {
// It is a switch
if (args[i].equalsIgnoreCase(UDP_FLAG) || args[i].equalsIgnoreCase(UDP_LONG_FLAG))
tcp = false;
else {
System.out.println("Unrecognised option: " + args[i]);
printUsage();
}
} else {
// Is it a file?
File file = new File(args[i]);
if (file.exists()) {
System.out.println("I don't handle files yet. Try again later.");
} else {
// It's a command line component
try {
Info info = new Info(args[i]);
launch.add(info);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
}
// Launch the components
long start = System.currentTimeMillis();
for (Iterator it = launch.iterator(); it.hasNext();) {
// Open the connection and input thread
Info next = (Info) it.next();
try {
System.out.println("Launching " + (next.number == 0 ? "lots of" : "" + next.number) + " components of class "
+ next.clazz.getName());
int max = next.number;
if (max < 1)
max = Integer.MAX_VALUE;
for (int j = 0; j < max; ++j) {
RescueComponent component = instantiate(next);
Connection connection;
if (tcp)
connection = new TCPConnection(kernel, kernelPort);
else
connection = new LongUDPConnection(kernel, kernelPort);
component.setConnection(connection);
if (launch(component, connection)) {
InputThread input = new InputThread(connection, component);
input.start();
components.add(new ComponentInfo(component, input, connection));
} else {
connection.close();
break;
}
}
System.out.println("Finished launching components of class " + next.clazz.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
System.out.println("Launched all components in " + ((end - start) / 1000.0) + " s");
// Wait for one of them to terminate
boolean running = true;
while (running) {
// Sleep for a bit
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
for (Iterator it = components.iterator(); it.hasNext();) {
RescueComponent c = ((ComponentInfo) it.next()).component;
if (!c.isRunning())
running = false;
}
}
shutdown();
}
private static void printUsage() {
System.out.println("Usage: Launch hostname portnumber components [options]");
System.out.println("hostname:\tThe name of the machine running the simulation kernel");
System.out.println("portnumber:\tThe port number that the kernel is listening on");
System.out.println(
"components:\tA set of components that should be launched. These are all of the form \"[number] classname arguments\". This will launch <number> (default 1) objects of type <classname>, passing <arguments> to each component.");
System.out.println("Options");
System.out.println("=======");
System.out.println(UDP_FLAG + "\t" + UDP_LONG_FLAG + "\tUse UDP instead of TCP");
}
private static RescueComponent instantiate(Info info) throws InstantiationException, IllegalAccessException,
ClassNotFoundException, InvocationTargetException, NoSuchMethodException {
RescueComponent result;
// System.out.print("Instantiating "+info+": ");
if (info.args.length != 0) {
// Try to find a constructor
Constructor c;
try {
c = info.clazz.getDeclaredConstructor(new Class[] { String[].class });
result = (RescueComponent) c.newInstance(new Object[] { info.args });
} catch (NoSuchMethodException e) {
try {
Class[] classes = new Class[info.args.length];
for (int j = 0; j < classes.length; ++j)
classes[j] = String.class;
c = info.clazz.getDeclaredConstructor(classes);
result = (RescueComponent) c.newInstance((Object[]) info.args);
} catch (NoSuchMethodException ex) {
result = (RescueComponent) info.clazz.getDeclaredConstructor().newInstance();
}
}
} else {
result = (RescueComponent) info.clazz.getDeclaredConstructor().newInstance();
}
// System.out.println(result);
return result;
}
private static boolean launch(RescueComponent c, Connection connection) throws IOException {
System.out.println("Launching " + c);
RescueMessage msg = new RescueMessage();
msg.append(c.generateConnectCommand());
int okReply = -1;
int errorReply = -1;
switch (c.getComponentType()) {
case RescueConstants.COMPONENT_TYPE_AGENT:
okReply = RescueConstants.KA_CONNECT_OK;
errorReply = RescueConstants.KA_CONNECT_ERROR;
break;
case RescueConstants.COMPONENT_TYPE_SIMULATOR:
okReply = RescueConstants.KS_CONNECT_OK;
errorReply = RescueConstants.KS_CONNECT_ERROR;
break;
case RescueConstants.COMPONENT_TYPE_VIEWER:
okReply = RescueConstants.KV_CONNECT_OK;
errorReply = RescueConstants.KV_CONNECT_ERROR;
break;
default:
throw new RuntimeException("Unknown component type");
}
connection.send(msg.toByteArray());
// Wait for reply
long timeout = System.currentTimeMillis() + 60000;
boolean success = false;
do {
// System.out.println("Waiting for reply...");
try {
byte[] reply = connection.receive(TIMEOUT);
if (reply != null) {
InputBuffer in = new InputBuffer(reply);
Command[] messages = in.readCommands();
// System.out.println("Received "+messages.length+" messages");
for (int i = 0; i < messages.length; ++i) {
if (success)
c.handleMessage(messages[i]);
else {
if (messages[i].getType() == okReply)
success = c.handleConnectOK(messages[i]);
if (messages[i].getType() == errorReply) {
String reason = c.handleConnectError(messages[i]);
if (reason != null) {
System.out.println("Error connecting " + c + ": " + reason);
return false;
}
}
}
}
}
} catch (InterruptedException e) {
return false;
}
} while (!success && System.currentTimeMillis() < timeout);
if (!success)
System.out.println("Timeout trying to connect " + c);
return success;
}
private static void shutdown() {
// Terminate all components
for (Iterator it = components.iterator(); it.hasNext();) {
ComponentInfo next = (ComponentInfo) it.next();
// Shut down the component
next.component.shutdown();
// Kill the input thread
next.input.kill();
}
// Wait for components to finish terminating
for (Iterator it = components.iterator(); it.hasNext();) {
ComponentInfo next = (ComponentInfo) it.next();
next.input.killAndWait();
}
// Exit the VM
System.exit(0);
}
private static class InputThread extends Thread {
private volatile boolean running, alive;
private final Object aliveLock = new Object();
private RescueComponent target;
private Connection connection;
InputThread(Connection connection, RescueComponent target) {
this.connection = connection;
this.target = target;
running = alive = true;
}
public void kill() {
running = false;
interrupt();
}
public void killAndWait() {
kill();
synchronized (aliveLock) {
while (alive)
try {
aliveLock.wait(1000);
} catch (InterruptedException e) {
}
}
connection.close();
}
public void run() {
while (running) {
try {
// System.out.println(target+" waiting for input");
byte[] msg = connection.receive(1000);
if (msg != null) {
// Handy.printBytes("RECEIVED",msg.getData());
// long start = System.currentTimeMillis();
Command[] messages = new InputBuffer(msg).readCommands();
for (int i = 0; i < messages.length; ++i) {
// System.out.println(target+" received "+messages[i]);
target.handleMessage(messages[i]);
}
// long end = System.currentTimeMillis();
// System.out.println(target+" took "+(end-start)+"ms to process a message");
}
} catch (InterruptedException e) {
} catch (IOException e) {
e.printStackTrace();
running = false;
}
}
synchronized (aliveLock) {
alive = false;
aliveLock.notifyAll();
}
}
}
private static class ComponentInfo {
RescueComponent component;
InputThread input;
Connection connection;
public ComponentInfo(RescueComponent c, InputThread i, Connection connection) {
component = c;
input = i;
this.connection = connection;
}
}
private static class Info {
Class clazz;
int number;
String[] args;
Info(String line) throws ClassNotFoundException, NoSuchElementException {
StringTokenizer tokens = new StringTokenizer(line);
// Try to parse the first token as an integer
String first = tokens.nextToken();
String second;
number = 1;
try {
number = Integer.parseInt(first);
second = tokens.nextToken();
} catch (NumberFormatException e) {
// Couldn't parse it, we'll assume no number was given
second = first;
}
clazz = Class.forName(second);
args = new String[tokens.countTokens()];
for (int i = 0; i < args.length; ++i)
args[i] = tokens.nextToken();
}
public String toString() {
StringBuffer result = new StringBuffer();
result.append(clazz.getName());
result.append("(");
for (int i = 0; i < args.length; ++i) {
result.append("\"");
result.append(args[i]);
result.append("\"");
if (i < args.length - 1)
result.append(",");
}
result.append(")");
return result.toString();
}
}
}
\ No newline at end of file
/*
* Last change: $Date: 2005/06/14 21:55:50 $
* $Revision: 1.1 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.net.*;
import java.util.*;
import java.io.*;
/**
The LongUDPConnection class encapsulates the sending and receiving of LongUDPMessages to and from the kernel. Messages are received asynchronously and stored in a queue.
*/
public class LongUDPConnection implements Connection {
private short nextID;
private DatagramSocket socket;
private List q;
private ReadThread read;
private IOException toThrow;
private InetAddress destination;
private int port;
private final static long WAIT = 10000;
/**
Generate a new LongUDPConnection
@throws SocketException if something goes wrong
*/
public LongUDPConnection() throws SocketException {
this(null,-1);
}
/**
Generate a new LongUDPConnection with a given destination
@param destination The target machine
@param port The target port
@throws SocketException if something goes wrong
*/
public LongUDPConnection(InetAddress destination, int port) throws SocketException {
nextID = 0;
socket = new DatagramSocket();
socket.setSoTimeout(1000);
// socket.setReceiveBufferSize(1000000);
q = new LinkedList();
toThrow = null;
read = new ReadThread();
read.start();
this.destination = destination;
this.port = port;
// System.err.println("Socket opened listening on port "+socket.getLocalPort());
}
public int getLocalPort() {
return socket.getLocalPort();
}
/**
Close the socket
*/
public void close() {
read.kill();
socket.close();
}
public void send(byte[] bytes) throws IOException {
if (destination==null || port < 0) throw new IOException("No destination given");
send(new LongUDPMessage(bytes),destination,port);
}
/**
Send a message
@param msg The LongUDPMessage to send
@param destination The destination address
@param port The destination port
@throws IOException if something goes wrong during sending
*/
public void send(LongUDPMessage msg, InetAddress destination, int port) throws IOException {
LongUDPFragment[] fragments = msg.fragment(nextID++);
// System.out.println("Sending message to "+destination+":"+port);
for (int i=0;i<fragments.length;++i) {
// System.out.print("Sending fragment "+(i+1)+" of "+fragments.length+"...");
byte[] buffer = fragments[i].toByteArray();
// Handy.printBytes(buffer);
DatagramPacket packet = new DatagramPacket(buffer,buffer.length,destination,port);
packet.setLength(buffer.length);
try {
socket.send(packet);
// System.out.println("sent");
}
catch (InterruptedIOException e) {
System.out.println("send interrupted");
--i;
}
}
}
public byte[] receive(int timeout) throws IOException, InterruptedException {
synchronized(q) {
if (toThrow!=null) throw toThrow;
if (q.size()==0) {
if (timeout<1) q.wait();
else q.wait(timeout);
}
if (toThrow!=null) throw toThrow;
if (q.size()==0) return null;
return ((LongUDPMessage)q.remove(0)).getData();
}
}
private class ReadThread extends Thread {
private boolean running;
private boolean alive;
private final Object aliveLock = new Object();
private Set partial;
private long lastCheck;
ReadThread() {
running = true;
alive = true;
partial = new HashSet();
}
public void kill() {
running = false;
synchronized(aliveLock) {
while (alive) try {aliveLock.wait(1000);} catch (InterruptedException e) {}
}
}
public void run() {
byte[] input = new byte[65536];
lastCheck = System.currentTimeMillis();
DatagramPacket packet = new DatagramPacket(input,input.length);
while (running) {
try {
socket.receive(packet);
// System.out.println("Received packet of length "+packet.getLength());
byte[] packetData = packet.getData();
byte[] result = new byte[packet.getLength()];
System.arraycopy(packetData,0,result,0,result.length);
LongUDPFragment fragment = new LongUDPFragment(result);
// System.out.println("Received "+fragment);
addFragment(fragment);
}
catch (InterruptedIOException e) {}
catch (IOException e) {
e.printStackTrace();
synchronized(q) {
toThrow = e;
}
}
if (System.currentTimeMillis()>lastCheck+WAIT) checkForTimeouts();
}
synchronized(aliveLock) {
alive = false;
aliveLock.notifyAll();
}
}
private void addFragment(LongUDPFragment fragment) {
boolean found = false;
for (Iterator it = partial.iterator();it.hasNext()&&!found;) {
PartialMessage next = (PartialMessage)it.next();
if (next.id==fragment.getID()) {
found = true;
if (next.addFragment(fragment)) {
finishedMessage(next.fragments);
it.remove();
}
// System.out.println("New fragment for message "+next.id+". Fragment size: "+fragment.getData().length+" - now have "+next.received+" of "+next.total+" fragments with a total size of "+next.size);
if (next.total > 10) System.out.println(next.received+"/"+next.total);
}
}
if (!found) {
PartialMessage pm = new PartialMessage(fragment.getID(),fragment.getTotal());
// System.out.println("Started receiving message "+pm.id);
if (pm.addFragment(fragment)) {
finishedMessage(pm.fragments);
}
else {
partial.add(pm);
}
}
}
private void finishedMessage(LongUDPFragment[] fragments) {
// System.out.println("Finished receiving message "+fragments[0].getID());
synchronized(q) {
q.add(LongUDPMessage.defragment(fragments));
q.notifyAll();
// System.err.println("Listening on port "+socket.getLocalPort()+" receive queue size: "+q.size());
}
}
private void checkForTimeouts() {
// System.out.println("Checking for timeouts");
for (Iterator it = partial.iterator();it.hasNext();) {
PartialMessage next = (PartialMessage)it.next();
// System.out.println("Checking "+next+" for timeout at time "+System.currentTimeMillis());
if (System.currentTimeMillis() > next.last+WAIT) {
System.out.println("Message "+next.id+" timed out - we received "+next.received+" of "+next.total+" packets");
it.remove();
}
}
lastCheck = System.currentTimeMillis();
}
private class PartialMessage {
int id;
int total;
int received;
long last;
int size;
LongUDPFragment[] fragments;
PartialMessage(int id, int total) {
this.id = id;
this.total = total;
this.received = 0;
this.last = System.currentTimeMillis();
fragments = new LongUDPFragment[total];
size = 0;
}
public String toString() {
return "Partial message "+id+": received "+received+" of "+total+", last fragment at time "+last;
}
/**
Returns true iff this message is now complete
*/
public boolean addFragment(LongUDPFragment fragment) {
if (fragment.getID()==id) {
if (fragments[fragment.getNumber()]==null) {
fragments[fragment.getNumber()] = fragment;
++received;
last = System.currentTimeMillis();
size += fragment.getData().length;
if (received == total) return true;
}
}
return false;
}
}
}
}
/*
* Last change: $Date: 2005/02/18 03:34:33 $
* $Revision: 1.3 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
/**
This is a piece of a LongUDPMessage
*/
public class LongUDPFragment implements Comparable {
private final static int MAGIC = 0x0008;
private int id;
private int number;
private int total;
private byte[] data;
/**
Generate a new LongUDPFragment ready for sending
@param id The id of the LongUDPMessage we are sending
@param number The number of this fragment
@param total The total number of fragments we are sending
@param data The body of this fragment
*/
public LongUDPFragment(int id, int number, int total, byte[] data) {
this.id = id;
this.number = number;
this.total = total;
this.data = new byte[data.length];
System.arraycopy(data,0,this.data,0,data.length);
}
/**
Generate a new LongUDPFragment from some data sent by the kernal
@param input The raw data from the kernal. It should consist of four 16-bit numbers (magic number, id, fragment number, total number of fragments) followed by some data.
*/
public LongUDPFragment(byte[] input) {
int magic = input[0]<<8 | input[1];
if (magic!=MAGIC) System.err.println("Oh oh - we got a LongUDPFragment with a bad magic number ("+magic+" instead of "+MAGIC+")");
id = input[2]<<8 | input[3];
number = input[4]<<8 | input[5];
total = input[6]<<8 | input[7];
data = new byte[input.length-8];
System.arraycopy(input,8,data,0,data.length);
// System.out.println((number+1)+" of "+total);
}
public String toString() {
return "LongUDPFragment: "+id+" ("+(number+1)+" of "+total+")";
}
public int compareTo(Object o) {
LongUDPFragment l = (LongUDPFragment)o;
return this.number-l.number;
}
/**
Turn this fragment into a byte array suitable for transmission to the kernal
@return A byte array containing the raw data of this fragment
*/
public byte[] toByteArray() {
byte[] result = new byte[data.length+8];
write(result,0,MAGIC);
write(result,2,id);
write(result,4,number);
write(result,6,total);
System.arraycopy(data,0,result,8,data.length);
return result;
}
/**
Get the body of this fragment
@return A byte array containing the body of this fragment
*/
public byte[] getData() {
return data;
}
/**
Get the message id of this fragment
@return This fragment's message id
*/
public int getID() {
return id;
}
/**
Get the sequence number of this fragment
@return This fragment's sequence number
*/
public int getNumber() {
return number;
}
/**
Get the total number of fragments in this fragment's message
@return The total number of fragments in this fragment's message
*/
public int getTotal() {
return total;
}
private void write(byte[] buffer, int off, int value) {
buffer[off] = (byte)((value>>8)&0xFF);
buffer[off+1] = (byte)(value&0xFF);
}
}
/*
* Last change: $Date: 2004/05/04 03:09:38 $
* $Revision: 1.3 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
/**
This class encapsulates a long UDP message, as defined by the robocup rescue manual version 0.4
*/
public class LongUDPMessage {
public final static int CHUNK_SIZE = 1024;
private byte[] data;
/**
Construct a new LongUDPMessage containing the given data
@param data The body of the message
*/
public LongUDPMessage(byte[] data) {
this.data = data;
}
/**
Break up this message into fragments ready for sending
@param id The id number assigned to each fragment
@return An array of LongUDPFragments that can be sent to the kernal
*/
public LongUDPFragment[] fragment(short id) {
short count = 0;
int done = 0;
short fragments = (short)(data.length/CHUNK_SIZE);
if (data.length%CHUNK_SIZE!=0) ++fragments;
LongUDPFragment[] result = new LongUDPFragment[fragments];
while (done < data.length) {
byte[] someData = new byte[Math.min(CHUNK_SIZE,data.length-done)];
System.arraycopy(data,done,someData,0,someData.length);
result[count] = new LongUDPFragment(id,count,fragments,someData);
++count;
done += someData.length;
}
return result;
}
/**
Get the body of this message
@return The message body
*/
public byte[] getData() {
return data;
}
/**
Defragment a set of LongUDPFragments into one LongUDPMessage
@param fragments The fragmented message to reassemble
@return A new LongUDPMessage that has been assembled from the given fragments. If there is a problem, then null is returned.
*/
public static LongUDPMessage defragment(LongUDPFragment[] fragments) {
// System.out.println("Defragmenting message");
java.util.Arrays.sort(fragments);
// Check that all the fragments are correct
if (!checkFragments(fragments)) return null;
int totalSize = 0;
for (int i=0;i<fragments.length;++i) {
totalSize += fragments[i].getData().length;
}
// System.out.println("Total size: "+totalSize);
byte[] data = new byte[totalSize];
int offset = 0;
for (int i=0;i<fragments.length;++i) {
byte[] next = fragments[i].getData();
// System.out.println("Fragment "+(i+1)+" gets appended at position "+offset);
System.arraycopy(next,0,data,offset,next.length);
offset += next.length;
}
// Handy.printBytes("Fragment 1",fragments[0].getData());
// Handy.printBytes("Fragment 2",fragments[1].getData());
// Handy.printBytes("Message received",data);
return new LongUDPMessage(data);
}
private static boolean checkFragments(LongUDPFragment[] fragments) {
// System.out.println("Checking fragments");
int id = fragments[0].getID();
int total = fragments[0].getTotal();
for (int i=0;i<fragments.length;++i) {
if (fragments[i].getID()!=id) {
System.out.println("Fragment "+(i+1)+" has id "+fragments[i].getID()+" - it should be "+id);
return false;
}
if (fragments[i].getTotal()!=total) {
System.out.println("Fragment "+(i+1)+" thinks there should be "+fragments[i].getTotal()+" fragments in total - it should be "+total);
return false;
}
}
// Make sure they're in order
for (int i=0;i<fragments.length;++i) {
if (fragments[i].getNumber()!=i) {
System.out.println("Fragment "+(i+1)+" thinks it should be number "+(fragments[i].getNumber()+1));
return false;
}
}
return true;
}
}
/*
* Last change: $Date: 2005/03/17 06:07:08 $
* $Revision: 1.14 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import rescuecore.commands.KASense;
import rescuecore.commands.Update;
import rescuecore.event.MemoryListener;
import rescuecore.event.ObjectAddedEvent;
import rescuecore.event.ObjectChangedEvent;
import rescuecore.event.PropertyChangedEvent;
import rescuecore.event.PropertyListener;
import rescuecore.objects.Building;
import rescuecore.objects.Edge;
import rescuecore.objects.Humanoid;
import rescuecore.objects.MotionlessObject;
import rescuecore.objects.MovingObject;
import rescuecore.objects.Node;
import rescuecore.objects.River;
import rescuecore.objects.RiverNode;
import rescuecore.objects.Road;
import rescuecore.objects.Vertex;
/**
* This class holds an agents view of the world
*/
public abstract class Memory implements java.io.Serializable {
private int minX, maxX, width, minY, maxY, height;
private transient Collection<MemoryListener> listeners;
private final Object LOCK = Integer.valueOf(0);
private class InternalPropertyListener implements PropertyListener, java.io.Serializable {
public void propertyChanged(PropertyChangedEvent event) {
fireObjectChanged(event.getObject(), event.getProperty(), event.getTimestamp(), event.getSource());
}
}
private final PropertyListener PROPERTY_LISTENER = new InternalPropertyListener();
/**
* Construct a new empty memory
*/
protected Memory() {
listeners = new HashSet<MemoryListener>();
width = -1;
}
public abstract Memory copy();
/**
* Get the minimum x value of the world
*
* @return The minimum x value of the world
*/
public int getMinX() {
if (width == -1)
calculateDimensions();
return minX;
}
/**
* Get the maximum x value of the world
*
* @return The maximum x value of the world
*/
public int getMaxX() {
if (width == -1)
calculateDimensions();
return maxX;
}
/**
* Get the minimum y value of the world
*
* @return The minimum y value of the world
*/
public int getMinY() {
if (width == -1)
calculateDimensions();
return minY;
}
/**
* Get the maximum y value of the world
*
* @return The maximum y value of the world
*/
public int getMaxY() {
if (width == -1)
calculateDimensions();
return maxY;
}
/**
* Get the width of the world
*
* @return The width of the world
*/
public int getWidth() {
if (width == -1)
calculateDimensions();
return width;
}
/**
* Get the height of the world
*
* @return The height of the world
*/
public int getHeight() {
if (width == -1)
calculateDimensions();
return height;
}
private void calculateDimensions() {
Collection<RescueObject> allNodes = getObjectsOfType(RescueConstants.TYPE_NODE);
if (allNodes.size() == 0) {
minX = 0;
maxX = 1;
minY = 0;
maxY = 1;
} else {
Iterator it = allNodes.iterator();
Node n = (Node) it.next();
minX = n.getX();
minY = n.getY();
maxX = minX;
maxY = minY;
while (it.hasNext()) {
n = (Node) it.next();
int x = n.getX();
minX = Math.min(minX, x);
maxX = Math.max(maxX, x);
int y = n.getY();
minY = Math.min(minY, y);
maxY = Math.max(maxY, y);
}
}
width = maxX - minX;
height = maxY - minY;
}
/**
* Add a MemoryListener that will be informed of adds and updates
*
* @param l The MemoryListener to add
*/
public void addMemoryListener(MemoryListener l) {
synchronized (LOCK) {
if (listeners == null)
listeners = new HashSet<MemoryListener>();
listeners.add(l);
}
}
/**
* Remove a MemoryListener
*
* @param l The MemoryListener to remove
*/
public void removeMemoryListener(MemoryListener l) {
synchronized (LOCK) {
if (listeners == null)
listeners = new HashSet<MemoryListener>();
listeners.remove(l);
}
}
/**
* Look up a RescueObject by id
*
* @param id The id of the object we want
* @return The object with the given id, or null if there are no objects with
* that id
*/
public abstract RescueObject lookup(int id);
/**
* Get all objects in memory
*
* @return An array of all objects in memory
*/
// public abstract RescueObject[] getAllObjects();
/**
* Get all objects in memory as a Collection
*
* @return A Collection of all objects in memory
*/
public abstract Collection<RescueObject> getAllObjects();
/**
* Get all objects of particular types
*
* @param result The Collection we want to fill with RescueObjects. Implementers
* should not remove any items from this Collection.
* @param type The types we want
* @see RescueConstants#TYPE_CIVILIAN
* @see RescueConstants#TYPE_FIRE_BRIGADE
* @see RescueConstants#TYPE_AMBULANCE_TEAM
* @see RescueConstants#TYPE_POLICE_FORCE
* @see RescueConstants#TYPE_ROAD
* @see RescueConstants#TYPE_NODE
* @see RescueConstants#TYPE_RIVER
* @see RescueConstants#TYPE_RIVER_NODE
* @see RescueConstants#TYPE_BUILDING
* @see RescueConstants#TYPE_REFUGE
* @see RescueConstants#TYPE_FIRE_STATION
* @see RescueConstants#TYPE_AMBULANCE_CENTER
* @see RescueConstants#TYPE_POLICE_OFFICE
* @see RescueConstants#TYPE_WORLD
* @see RescueConstants#TYPE_CAR
*/
public abstract void getObjectsOfType(Collection<RescueObject> result, int... types);
public Collection<RescueObject> getObjectsOfType(int... types) {
Collection<RescueObject> result = new HashSet<RescueObject>();
getObjectsOfType(result, types);
return result;
}
/**
* Get all objects of a particular internal type
*
* @param type The type we want
* @return An array of all objects of the given internal type
* @see RescueConstants#INTERNAL_TYPE_CIVILIAN
* @see RescueConstants#INTERNAL_TYPE_FIRE_BRIGADE
* @see RescueConstants#INTERNAL_TYPE_AMBULANCE_TEAM
* @see RescueConstants#INTERNAL_TYPE_POLICE_FORCE
* @see RescueConstants#INTERNAL_TYPE_CAR
* @see RescueConstants#INTERNAL_TYPE_BUILDING
* @see RescueConstants#INTERNAL_TYPE_REFUGE
* @see RescueConstants#INTERNAL_TYPE_FIRE_STATION
* @see RescueConstants#INTERNAL_TYPE_POLICE_OFFICE
* @see RescueConstants#INTERNAL_TYPE_AMBULANCE_CENTER
* @see RescueConstants#INTERNAL_TYPE_ROAD
* @see RescueConstants#INTERNAL_TYPE_NODE
* @see RescueConstants#INTERNAL_TYPE_RIVER
* @see RescueConstants#INTERNAL_TYPE_RIVER_NODE
* @see RescueConstants#INTERNAL_TYPE_WORLD
* @see RescueConstants#INTERNAL_TYPE_ANY_BUILDING
* @see RescueConstants#INTERNAL_TYPE_ANY_HUMANOID
*/
// public abstract RescueObject[] getObjectsOfInternalType(int type);
/**
* Add a new object with a null source
*
* @param o The new object
* @param timestamp The time that this object is added
*/
public void add(RescueObject o, int timestamp) {
add(o, timestamp, null);
}
/**
* Add a new object
*
* @param o The new object
* @param timestamp The time that this object is added
* @param source The source of the change
*/
public void add(RescueObject o, int timestamp, Object source) {
fireObjectAdded(o, timestamp, source);
o.addPropertyListener(PROPERTY_LISTENER);
}
/**
* Remove an object from the memory
*
* @param o The object to be removed
*/
public void remove(RescueObject o) {
o.removePropertyListener(PROPERTY_LISTENER);
}
/**
* Update our memory from a KASense object
*
* @param sense The KASense object to update from
*/
public void update(KASense sense) {
update(sense.getUpdatedObjects(), sense.getTime(), RescueConstants.SOURCE_SENSE);
}
/**
* Update our memory from an Update object
*
* @param sense The Update object to update from
*/
public void update(Update update) {
update(update.getUpdatedObjects(), update.getTime(), RescueConstants.SOURCE_UPDATE);
}
public void update(RescueObject[] changed, int time, Object source) {
for (int i = 0; i < changed.length; ++i) {
RescueObject current = lookup(changed[i].getID());
if (current == null) {
RescueObject copy = changed[i].copy();
add(copy, time, source);
} else {
current.merge(changed[i]);
}
}
}
/**
* Notify listeners that an object has been added
*
* @param o The added object
* @param source The source of the change
*/
private void fireObjectAdded(RescueObject o, int timestep, Object source) {
ObjectAddedEvent event = new ObjectAddedEvent(o, timestep, source);
synchronized (LOCK) {
if (listeners == null)
listeners = new HashSet<MemoryListener>();
for (Iterator it = listeners.iterator(); it.hasNext();) {
((MemoryListener) it.next()).objectAdded(event);
}
}
}
/**
* Notify listeners that an object has been changed
*
* @param o The changed object
* @param source The source of the change
*/
private void fireObjectChanged(RescueObject o, int property, int timestep, Object source) {
ObjectChangedEvent event = new ObjectChangedEvent(o, property, timestep, source);
synchronized (LOCK) {
if (listeners == null)
listeners = new HashSet<MemoryListener>();
for (Iterator it = listeners.iterator(); it.hasNext();) {
((MemoryListener) it.next()).objectChanged(event);
}
}
}
/**
* Get the Euclidean distance between two objects
*
* @param o1 The first object
* @param o2 The second object
* @return The distance between the two objects
*/
public double getDistance(RescueObject o1, RescueObject o2) throws CannotFindLocationException {
int x1, x2, y1, y2;
int[] xy = getXY(o1);
x1 = xy[0];
y1 = xy[1];
xy = getXY(o2);
x2 = xy[0];
y2 = xy[1];
double x = x2 - x1;
x = x * x;
double y = y2 - y1;
y = y * y;
return Math.sqrt(x + y);
}
/**
* Get the angle in arc-seconds from one object to another
*
* @param from The first object
* @param to The second object
* @return The angle from 'from' to 'to', in arc-seconds
*/
public int getAngle(RescueObject from, RescueObject to) throws CannotFindLocationException {
int x1, x2, y1, y2;
int[] xy = getXY(from);
x1 = xy[0];
y1 = xy[1];
xy = getXY(to);
x2 = xy[0];
y2 = xy[1];
int dx = x2 - x1;
int dy = y2 - y1;
double theta = Math.atan2(-dx, dy);
if (theta < 0)
theta += 2 * Math.PI;
return (int) (theta * 360 * 60 * 60 / (2.0 * Math.PI));
}
/**
* Get the X and Y coordinates of an object
*
* @param o The object of interest
* @return An array of two ints. The first element is the X coordinate, the
* second is Y. The return value may be null if the location of the
* object is unknown
*/
public int[] getXY(RescueObject o) throws CannotFindLocationException {
int x = 0, y = 0;
switch (o.getType()) {
case RescueConstants.TYPE_CIVILIAN:
case RescueConstants.TYPE_FIRE_BRIGADE:
case RescueConstants.TYPE_AMBULANCE_TEAM:
case RescueConstants.TYPE_POLICE_FORCE:
case RescueConstants.TYPE_CAR:
RescueObject location = lookup(((Humanoid) o).getPosition());
if (location == null) {
throw new CannotFindLocationException();
}
switch (location.getType()) {
case RescueConstants.TYPE_BUILDING:
case RescueConstants.TYPE_POLICE_OFFICE:
case RescueConstants.TYPE_FIRE_STATION:
case RescueConstants.TYPE_AMBULANCE_CENTER:
case RescueConstants.TYPE_REFUGE:
x = ((Building) location).getX();
y = ((Building) location).getY();
break;
case RescueConstants.TYPE_NODE:
x = ((Node) location).getX();
y = ((Node) location).getY();
break;
case RescueConstants.TYPE_RIVER_NODE:
x = ((RiverNode) location).getX();
y = ((RiverNode) location).getY();
break;
case RescueConstants.TYPE_ROAD:
Node roadHead = (Node) lookup(((Road) location).getHead());
Node roadTail = (Node) lookup(((Road) location).getTail());
int roadLength = ((Road) location).getLength();
double d = ((double) ((Humanoid) o).getPositionExtra()) / ((double) roadLength);
int xDelta = roadTail.getX() - roadHead.getX();
int yDelta = roadTail.getY() - roadHead.getY();
x = (int) (roadHead.getX() + d * xDelta);
y = (int) (roadHead.getY() + d * yDelta);
break;
case RescueConstants.TYPE_AMBULANCE_TEAM:
return getXY(location);
default:
System.err
.println("Can't find location for a humanoid that lives in " + Handy.getTypeName(location.getType()));
throw new CannotFindLocationException(
o + " is located at " + location + " but I don't know how to handle that");
}
break;
case RescueConstants.TYPE_NODE:
x = ((Node) o).getX();
y = ((Node) o).getY();
break;
case RescueConstants.TYPE_RIVER_NODE:
x = ((RiverNode) o).getX();
y = ((RiverNode) o).getY();
break;
case RescueConstants.TYPE_ROAD:
// Halfway between head and tail?
Node head = (Node) lookup(((Road) o).getHead());
Node tail = (Node) lookup(((Road) o).getTail());
if (head == null) {
System.err.println("Can't find head of this road: " + o.toLongString());
}
if (tail == null) {
System.err.println("Can't find tail of this road: " + o.toLongString());
}
x = (head.getX() + tail.getX()) / 2;
y = (head.getY() + tail.getY()) / 2;
break;
case RescueConstants.TYPE_RIVER:
RiverNode head_ = (RiverNode) lookup(((River) o).getHead());
RiverNode tail_ = (RiverNode) lookup(((River) o).getTail());
x = (head_.getX() + tail_.getX()) / 2;
y = (head_.getY() + tail_.getY()) / 2;
break;
case RescueConstants.TYPE_BUILDING:
case RescueConstants.TYPE_REFUGE:
case RescueConstants.TYPE_FIRE_STATION:
case RescueConstants.TYPE_AMBULANCE_CENTER:
case RescueConstants.TYPE_POLICE_OFFICE:
x = ((Building) o).getX();
y = ((Building) o).getY();
break;
case RescueConstants.TYPE_WORLD:
throw new CannotFindLocationException("Tried to find the position of a TYPE_WORLD object");
}
return new int[] { x, y };
}
/**
* Get the RescueObject the represents the position of a MovingObject. This
* might be another MovingObject, for example the position of a civilian in an
* ambulance will be the ambulance
*
* @param object The object in question
* @return The position of the object, or null if the position cannot be found
*/
public RescueObject getPosition(MovingObject o) {
RescueObject result = lookup(o.getPosition());
return result;
}
/**
* Get the MotionlessObject that represents a given object's position in the
* world
*
* @param o The object in question
* @return The MotionlessObject that represents a given object's position in the
* world, or null if the position cannot be found
*/
public MotionlessObject getMotionlessPosition(RescueObject o) {
switch (o.getType()) {
case RescueConstants.TYPE_CIVILIAN:
case RescueConstants.TYPE_FIRE_BRIGADE:
case RescueConstants.TYPE_POLICE_FORCE:
case RescueConstants.TYPE_AMBULANCE_TEAM:
case RescueConstants.TYPE_CAR:
RescueObject position = lookup(((Humanoid) o).getPosition());
if (position == null)
return null;
return getMotionlessPosition(position);
case RescueConstants.TYPE_BUILDING:
case RescueConstants.TYPE_REFUGE:
case RescueConstants.TYPE_FIRE_STATION:
case RescueConstants.TYPE_POLICE_OFFICE:
case RescueConstants.TYPE_AMBULANCE_CENTER:
case RescueConstants.TYPE_ROAD:
case RescueConstants.TYPE_NODE:
case RescueConstants.TYPE_RIVER_NODE:
case RescueConstants.TYPE_RIVER:
return (MotionlessObject) o;
default:
return null;
}
}
/**
* Find the closest Node to a RescueObject. If the given object is a Node then
* it is returned. If it is a road, then the head node is returned. If it is a
* building, then the entrance node closest to the center of the building is
* returned. If it is a mobile agent (civilian, fire brigade etc) then the
* closest node to it's location is returned
*
* @param o The object we want the closest node to
* @return The Node object that is closest to the given RescueObject
*/
public Node getClosestNode(RescueObject o) {
switch (o.getType()) {
case RescueConstants.TYPE_NODE:
return (Node) o;
case RescueConstants.TYPE_ROAD:
return (Node) lookup(((Road) o).getHead());
case RescueConstants.TYPE_BUILDING:
case RescueConstants.TYPE_REFUGE:
case RescueConstants.TYPE_FIRE_STATION:
case RescueConstants.TYPE_AMBULANCE_CENTER:
case RescueConstants.TYPE_POLICE_OFFICE:
int[] entrances = ((Building) o).getEntrances();
int best = -1;
double bestDistance = Double.MAX_VALUE;
for (int i = 0; i < entrances.length; ++i) {
try {
double d = getDistance(o, lookup(entrances[i]));
if (d < bestDistance) {
best = i;
bestDistance = d;
}
} catch (CannotFindLocationException e) {
}
}
if (best == -1)
return null;
return (Node) lookup(entrances[best]);
case RescueConstants.TYPE_CIVILIAN:
case RescueConstants.TYPE_FIRE_BRIGADE:
case RescueConstants.TYPE_AMBULANCE_TEAM:
case RescueConstants.TYPE_POLICE_FORCE:
case RescueConstants.TYPE_CAR:
RescueObject location = lookup(((Humanoid) o).getPosition());
if (location == null)
return null;
switch (location.getType()) {
case RescueConstants.TYPE_NODE:
return (Node) location;
case RescueConstants.TYPE_ROAD:
int length = ((Road) location).getLength();
int pos = ((Humanoid) o).getPositionExtra();
if (pos < length / 2)
return (Node) lookup(((Road) location).getHead());
else
return (Node) lookup(((Road) location).getTail());
default:
return getClosestNode(location);
}
}
return null;
}
/**
* Get the node id (either head or tail of the given road) that is closest to
* the position given
*
* @param road The road that we want the head or tail of
* @param positionExtra The agent's position along the road
* @return Either the head or tail node of the given road, whichever is closest
*/
public Node getClosestNode(Road road, int positionExtra) {
if (positionExtra < (road.getLength() / 2))
return (Node) lookup(road.getHead());
return (Node) lookup(road.getTail());
}
/**
* Find the neighbours of a RescueObject. This method delegates to @{link
* #findNodeNeighbours(Node)}, @{link #findRoadNeighbours(Road)} or @{link
* #findBuildingNeighbours(Building)} for Nodes, Roads and Buildings
* respectively
*
* @param o The RescueObject we want the neighbours for
* @return An array of all neighbours of the given object
*/
public RescueObject[] findNeighbours(RescueObject o) {
switch (o.getType()) {
case RescueConstants.TYPE_NODE:
return findNodeNeighbours((Node) o);
case RescueConstants.TYPE_ROAD:
return findRoadNeighbours((Road) o);
case RescueConstants.TYPE_BUILDING:
case RescueConstants.TYPE_REFUGE:
case RescueConstants.TYPE_FIRE_STATION:
case RescueConstants.TYPE_POLICE_OFFICE:
case RescueConstants.TYPE_AMBULANCE_CENTER:
return findBuildingNeighbours((Building) o);
default:
System.out.println("Cannot find neighbours of a " + Handy.getTypeName(o.getType()));
return null;
}
}
/**
* Find the neighbours of a Node. This method returns all RescueObjects
* identified by this Nodes 'edges' property
*
* @param node The Node we want the neighbours for
* @return An array of all neighbours of the given Node
*/
public RescueObject[] findNodeNeighbours(Node node) {
int[] edges = node.getEdges();
RescueObject[] all = new RescueObject[edges.length];
int count = 0;
for (int i = 0; i < edges.length; ++i) {
all[i] = lookup(edges[i]);
}
return all;
}
/**
* Find the neighbours of a Road. This method returns the head and tail nodes
* connected to this Road
*
* @param road The Road we want the neighbours for
* @return An array containing the head and tail nodes, in that order
*/
public RescueObject[] findRoadNeighbours(Road road) {
RescueObject head = lookup(road.getHead());
RescueObject tail = lookup(road.getTail());
return new RescueObject[] { head, tail };
}
public Node getHead(Road r) {
return (Node) lookup(r.getHead());
}
public Node getTail(Road r) {
return (Node) lookup(r.getTail());
}
public Road getRoadBetween(Node n1, Node n2) {
RescueObject[] neighbours = findNodeNeighbours(n1);
for (int i = 0; i < neighbours.length; ++i) {
if (neighbours[i] instanceof Road) {
Road r = (Road) neighbours[i];
if ((r.getHead() == n1.getID() && r.getTail() == n2.getID())
|| (r.getHead() == n2.getID() && r.getTail() == n1.getID()))
return r;
}
}
return null;
}
public boolean neighbours(RescueObject o1, RescueObject o2) {
int id = o2.getID();
if (o1 instanceof Building) {
int[] entrances = ((Building) o1).getEntrances();
for (int i = 0; i < entrances.length; ++i)
if (entrances[i] == id)
return true;
}
if (o1 instanceof Edge) {
Edge e = (Edge) o1;
if (e.getHead() == id || e.getTail() == id)
return true;
}
if (o1 instanceof Vertex) {
return isEdge(id, (Vertex) o1);
}
return false;
}
public boolean isEdge(int id, Vertex v) {
int[] edges = v.getEdges();
for (int i = 0; i < edges.length; ++i)
if (edges[i] == id)
return true;
return false;
}
public boolean isEdge(RescueObject o, Node node) {
return isEdge(o.getID(), node);
}
public boolean isEntrance(int id, Building b) {
int[] entrances = b.getEntrances();
for (int i = 0; i < entrances.length; ++i)
if (entrances[i] == id)
return true;
return false;
}
public boolean isEntrance(RescueObject o, Building b) {
return isEntrance(o.getID(), b);
}
/**
* Find the neighbours of a Building. This method returns all Nodes identified
* by this Buildings 'entrances' property
*
* @param b The Building we want the neighbours for
* @return An array of all Nodes identified by the 'entrances' property
*/
public RescueObject[] findBuildingNeighbours(Building b) {
int[] entrances = b.getEntrances();
RescueObject[] all = new RescueObject[entrances.length];
for (int i = 0; i < entrances.length; ++i) {
all[i] = lookup(entrances[i]);
}
return all;
}
}
\ No newline at end of file
/*
* Last change: $Date: 2005/02/20 01:29:55 $
* $Revision: 1.15 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import java.io.UnsupportedEncodingException;
import rescuecore.commands.Command;
public class OutputBuffer {
private byte[] data;
private int index;
public OutputBuffer() {
this(256);
}
public OutputBuffer(int capacity) {
data = new byte[capacity];
}
public void writeByte(byte b) {
expand(RescueConstants.BYTE_SIZE);
data[index++] = b;
}
public void writeBytes(byte[] b) {
expand(b.length*RescueConstants.BYTE_SIZE);
for (int i=0;i<b.length;++i) data[index++] = b[i];
}
public void writeShort(int s) {
expand(RescueConstants.SHORT_SIZE);
data[index++] = (byte)(s>>8 & 0xFF);
data[index++] = (byte)(s & 0xFF);
}
public void writeInt(int i) {
expand(RescueConstants.INT_SIZE);
data[index++] = (byte)(i >> 24 & 0xFF);
data[index++] = (byte)(i >> 16 & 0xFF);
data[index++] = (byte)(i >> 8 & 0xFF);
data[index++] = (byte)(i & 0xFF);
}
public void writeString(String s) {
try {
byte[] bytes = s.getBytes("UTF-8");
writeInt(bytes.length);
writeBytes(bytes);
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 encoding not found!", e);
}
}
public void writeObject(RescueObject o) {
writeInt(o.getType());
writeInt(o.getID());
int base = markBlock();
o.write(this);
writeBlockSize(base);
}
public void writeObjects(RescueObject[] objects) {
writeInt(objects.length);
for (int i=0;i<objects.length;++i) writeObject(objects[i]);
}
public void writeCommand(Command c) {
writeInt(c.getType());
int base = markBlock();
c.write(this);
writeBlockSize(base);
}
public void writeCommands(Command[] c) {
writeInt(c.length);
for (int i=0;i<c.length;++i) writeCommand(c[i]);
}
public int markBlock() {
writeInt(0);
return index;
}
public void writeBlockSize(int mark) {
int size = index-mark;
writeInt(size,mark-RescueConstants.INT_SIZE);
}
public void clear() {
index = 0;
}
public int getSize() {
return index;
}
public byte[] getBytes() {
byte[] result = new byte[index];
System.arraycopy(data,0,result,0,index);
return result;
}
public void ensureCapacity(int capacity) {
expand(capacity);
}
public void trim(int size) {
index = Math.min(index,size);
}
private void writeInt(int i, int position) {
int old = index;
index = position;
writeInt(i);
if (index < old) index = old; // If we went past the old position then just leave things as they are
}
private void expand(int needed) {
if (index+needed < data.length) return;
byte[] newData = new byte[Math.max(index+needed,data.length*2)];
System.arraycopy(data,0,newData,0,data.length);
data = newData;
}
}
/*
* Last change: $Date: 2004/05/20 23:41:59 $
* $Revision: 1.6 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import rescuecore.objects.*;
import rescuecore.commands.Command;
/**
An abstract superclass for platoon agents (i.e fire brigade, police force, ambulance team).
*/
public abstract class PlatoonAgent extends Agent {
protected PlatoonAgent(int... types) {
super(types);
}
private Humanoid me() {
return (Humanoid)memory.lookup(id);
}
/**
Get this agent's current position as a RescueObject
@return The RescueObject representing this agent's current position
*/
protected RescueObject getLocation() {
return memory.lookup(me().getPosition());
}
/**
Get this agent's current position
@return This agent's current position
*/
protected int getPosition() {
return me().getPosition();
}
/**
Get this agent's current position
@return This agent's current position
*/
protected int getPositionExtra() {
return me().getPositionExtra();
}
/**
Append a move command
@param ids The list of road/node/building ids that we want to move through
*/
protected void move(int[] ids) {
if (ids==null || ids.length==0) return;
appendCommand(Command.MOVE(id,timeStep,ids));
}
/**
Append an extinguish command
@param target The building to extinguish
*/
protected void extinguish(Building target) {
try {
int[] xy = memory.getXY(me());
appendCommand(Command.EXTINGUISH(id,timeStep,target.getID()));
}
catch (CannotFindLocationException e) {
System.err.println(e);
}
}
/**
Append an extinguish command
@param target The building to extinguish
@param power The amount of water to use
*/
protected void extinguish(Building target, int power) {
try {
int[] xy = memory.getXY(me());
appendCommand(Command.EXTINGUISH(id,timeStep,target.getID(),memory.getAngle(me(),target),xy[0],xy[1],power));
}
catch (CannotFindLocationException e) {
System.err.println(e);
}
}
/**
Append a clear command
@param target The road to clear
*/
protected void clear(Road target) {
appendCommand(Command.CLEAR(id,timeStep,target.getID()));
}
/**
Append a rescue command
@param target The humanoid to rescue
*/
protected void rescue(Humanoid target) {
appendCommand(Command.RESCUE(id,timeStep,target.getID()));
}
/**
Append a load command
@param target The humanoid to load
*/
protected void load(Humanoid target) {
appendCommand(Command.LOAD(id,timeStep,target.getID()));
}
/**
Append an unload command
*/
protected void unload() {
appendCommand(Command.UNLOAD(id,timeStep));
}
}
/*
* Last change: $Date: 2005/02/20 01:29:55 $
* $Revision: 1.15 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
/**
This class encapsulates information about an individual property within a RescueObject
*/
public abstract class Property implements java.io.Serializable {
private int type;
protected int lastUpdate;
protected Object lastUpdateSource;
protected Property(int type) {
this.type = type;
lastUpdate = RescueConstants.VALUE_UNKNOWN;
lastUpdateSource = null;
}
/**
Get the type of this property
@return The type of this property
*/
public int getType() {
return type;
}
public abstract boolean read(InputBuffer in, int timestamp, Object source);
public abstract void write(OutputBuffer out);
/**
Get the last time this property was updated
@return The last time this property was updated
*/
public int getLastUpdate() {
return lastUpdate;
}
/**
Get the source of the last update
@return The source of the last update
*/
public Object getLastUpdateSource() {
return lastUpdateSource;
}
/**
Find out whether this property was last updated before a certain time
@param time The time to check against
@return true if and only if this property was last updated before the given time
*/
public boolean isOlderThan(int time) {
return lastUpdate < time;
}
/**
Find out whether the value of this property is known or not
@return true if and only if the value of this property is known
*/
public boolean isValueKnown() {
return lastUpdate >= 0;
}
/**
Find out whether the value of this property is assumed or not
@return true if and only if the value of this property is assumed
*/
public boolean isValueAssumed() {
return lastUpdate == RescueConstants.VALUE_ASSUMED;
}
public String toString() {
return Handy.getPropertyName(type)+": "+getStringValue()+" (last update: "+lastUpdate+")";
}
/**
Get the value of this property as a string
@return A nice string representation of the value of this property
*/
public abstract String getStringValue();
/**
Update this Property from a different one
@param p The Property to update from
@return true if and only if the value of this property was actually changed
*/
public abstract boolean merge(Property p);
}
/*
* Last change: $Date: 2005/06/14 21:55:50 $
* $Revision: 1.7 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import rescuecore.commands.*;
import java.io.*;
public abstract class RescueComponent {
private RescueMessage currentMessage;
private Connection connection;
/** Handle an incoming message
@param msg The incoming message
*/
public abstract void handleMessage(Command msg);
/**
Get the type of this component, either COMPONENT_TYPE_AGENT, COMPONENT_TYPE_SIMULATOR or COMPONENT_TYPE_VIEWER.
@return The type of this component
@see RescueConstants#COMPONENT_TYPE_AGENT
@see RescueConstants#COMPONENT_TYPE_SIMULATOR
@see RescueConstants#COMPONENT_TYPE_VIEWER
*/
public abstract int getComponentType();
/**
Generate a Command that can be used to connect this component to the kernel
@return A Command that will connect this component to the kernel
*/
public abstract Command generateConnectCommand();
/**
Handle a message that looks like a successful connection to the kernel
@param c The message from the kernel
@return If this really was a successful connection
*/
public abstract boolean handleConnectOK(Command c);
/**
Handle a message that looks like an unsuccessful connection to the kernel
@param c The message from the kernel
@return A string describing the error, or null if this message does not indicate a failed connection
*/
public abstract String handleConnectError(Command c);
/**
Find out whether this component is still running
@return true iff this component is still running
*/
public abstract boolean isRunning();
/**
Shut the component down
*/
public abstract void shutdown();
/**
Set the Connection that should be used for talking to the kernel. Subclasses should NOT attempt to read input from this connection.
@param connection The Connection to use when talking to the kernel.
*/
public void setConnection(Connection connection) {
this.connection = connection;
}
/**
Send a message to the kernel
@param message The message to send
*/
public void sendMessage(RescueMessage message) {
if (connection==null) {
System.out.println(this+" tried to send to a null socket");
return;
}
try {
connection.send(message.toByteArray());
}
catch (IOException e) {
System.err.println("Error while sending message: "+e);
e.printStackTrace();
}
}
/**
Add a Command to our current set of Commands to be sent to the kernel. Commands will be buffered until @{link #flushCommands()} is called.
@param c The next Command to send.
*/
protected void appendCommand(Command c) {
if (currentMessage==null) currentMessage = new RescueMessage();
currentMessage.append(c);
}
/**
Send all our buffered commands to the kernel
*/
protected void flushCommands() {
if (currentMessage!=null) {
sendMessage(currentMessage);
}
currentMessage = null;
}
}
/*
* Last change: $Date: 2004/05/20 23:41:59 $
* $Revision: 1.9 $
*
* Copyright (c) 2004, The Black Sheep, Department of Computer Science, The University of Auckland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of The Black Sheep, The Department of Computer Science or The University of Auckland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
/**
A whole pile of useful constants
*/
public final class RescueConstants {
private RescueConstants() {}
public final static int MAX_EXTINGUISH_DISTANCE = 30000;
public final static int MAX_EXTINGUISH_POWER = 1000;
public final static int MAX_WATER = 15000;
public final static int MAX_RESCUE_DISTANCE = 30000;
public final static int MAX_HP = 10000;
public final static int MAX_VISION = 10000;
public final static int SAY_LENGTH = 256;
public final static int TELL_LENGTH = 256;
public final static int MAX_PLATOON_MESSAGES = 4;
public final static int MAX_CENTER_MESSAGES = 2;
public final static int COMPONENT_TYPE_AGENT = 1;
public final static int COMPONENT_TYPE_SIMULATOR = 2;
public final static int COMPONENT_TYPE_VIEWER = 3;
public final static int BYTE_SIZE = 1;
public final static int SHORT_SIZE = 2;
public final static int INT_SIZE = 4;
public final static int FIERYNESS_NOT_BURNT = 0;
public final static int FIERYNESS_HEATING = 1;
public final static int FIERYNESS_BURNING = 2;
public final static int FIERYNESS_INFERNO = 3;
public final static int FIERYNESS_WATER_DAMAGE = 4;
public final static int FIERYNESS_SLIGHTLY_BURNT = 5;
public final static int FIERYNESS_MODERATELY_BURNT = 6;
public final static int FIERYNESS_VERY_BURNT = 7;
public final static int FIERYNESS_BURNT_OUT = 8;
public final static int NUM_FIERYNESS_LEVELS = 9;
public final static int TYPE_NULL = 0;
public final static int TYPE_WORLD = 0x01;
public final static int TYPE_ROAD = 0x02;
public final static int TYPE_RIVER = 0x03;
public final static int TYPE_NODE = 0x04;
public final static int TYPE_RIVER_NODE = 0x05;
public final static int TYPE_BUILDING = 0x20;
public final static int TYPE_REFUGE = 0x21;
public final static int TYPE_FIRE_STATION = 0x22;
public final static int TYPE_AMBULANCE_CENTER = 0x23;
public final static int TYPE_POLICE_OFFICE = 0x24;
public final static int TYPE_CIVILIAN = 0x40;
public final static int TYPE_CAR = 0x41;
public final static int TYPE_FIRE_BRIGADE = 0x42;
public final static int TYPE_AMBULANCE_TEAM = 0x43;
public final static int TYPE_POLICE_FORCE = 0x44;
public final static int AGENT_TYPE_CIVILIAN = 0x01;
public final static int AGENT_TYPE_FIRE_BRIGADE = 0x02;
public final static int AGENT_TYPE_FIRE_STATION = 0x04;
public final static int AGENT_TYPE_AMBULANCE_TEAM = 0x08;
public final static int AGENT_TYPE_AMBULANCE_CENTER = 0x10;
public final static int AGENT_TYPE_POLICE_FORCE = 0x20;
public final static int AGENT_TYPE_POLICE_OFFICE = 0x40;
public final static int AGENT_TYPE_ANY_MOBILE = AGENT_TYPE_FIRE_BRIGADE | AGENT_TYPE_AMBULANCE_TEAM | AGENT_TYPE_POLICE_FORCE;
public final static int AGENT_TYPE_ANY_BUILDING = AGENT_TYPE_FIRE_STATION | AGENT_TYPE_AMBULANCE_CENTER | AGENT_TYPE_POLICE_OFFICE;
public final static int AGENT_TYPE_ANY_AGENT = AGENT_TYPE_ANY_MOBILE | AGENT_TYPE_ANY_BUILDING;
public final static int AGENT_TYPE_ANY = AGENT_TYPE_ANY_MOBILE | AGENT_TYPE_ANY_BUILDING | AGENT_TYPE_CIVILIAN;
public final static int PROPERTY_NULL = 0;
public final static int PROPERTY_MIN = 1;
public final static int PROPERTY_START_TIME = 1;
public final static int PROPERTY_LONGITUDE = 2;
public final static int PROPERTY_LATITUDE = 3;
public final static int PROPERTY_WIND_FORCE = 4;
public final static int PROPERTY_WIND_DIRECTION = 5;
public final static int PROPERTY_HEAD = 6;
public final static int PROPERTY_TAIL = 7;
public final static int PROPERTY_LENGTH = 8;
public final static int PROPERTY_ROAD_KIND = 9;
public final static int PROPERTY_CARS_PASS_TO_HEAD = 10;
public final static int PROPERTY_CARS_PASS_TO_TAIL = 11;
public final static int PROPERTY_HUMANS_PASS_TO_HEAD = 12;
public final static int PROPERTY_HUMANS_PASS_TO_TAIL = 13;
public final static int PROPERTY_WIDTH = 14;
public final static int PROPERTY_BLOCK = 15;
public final static int PROPERTY_REPAIR_COST = 16;
public final static int PROPERTY_MEDIAN_STRIP = 17;
public final static int PROPERTY_LINES_TO_HEAD = 18;
public final static int PROPERTY_LINES_TO_TAIL = 19;
public final static int PROPERTY_WIDTH_FOR_WALKERS = 20;
public final static int PROPERTY_SIGNAL = 21;
public final static int PROPERTY_SHORTCUT_TO_TURN = 22;
public final static int PROPERTY_POCKET_TO_TURN_ACROSS = 23;
public final static int PROPERTY_SIGNAL_TIMING = 24;
public final static int PROPERTY_X = 25;
public final static int PROPERTY_Y = 26;
public final static int PROPERTY_EDGES = 27;
public final static int PROPERTY_FLOORS = 28;
public final static int PROPERTY_BUILDING_ATTRIBUTES = 29;
public final static int PROPERTY_IGNITION = 30;
public final static int PROPERTY_FIERYNESS = 31;
public final static int PROPERTY_BROKENNESS = 32;
public final static int PROPERTY_ENTRANCES = 33;
public final static int PROPERTY_BUILDING_CODE = 34;
public final static int PROPERTY_BUILDING_AREA_GROUND = 35;
public final static int PROPERTY_BUILDING_AREA_TOTAL = 36;
public final static int PROPERTY_BUILDING_APEXES = 37;
public final static int PROPERTY_POSITION = 38;
public final static int PROPERTY_POSITION_EXTRA = 39;
public final static int PROPERTY_DIRECTION = 40;
public final static int PROPERTY_POSITION_HISTORY = 41;
public final static int PROPERTY_STAMINA = 42;
public final static int PROPERTY_HP = 43;
public final static int PROPERTY_DAMAGE = 44;
public final static int PROPERTY_BURIEDNESS = 45;
public final static int PROPERTY_WATER_QUANTITY = 46;
public final static int PROPERTY_BUILDING_TEMPERATURE = 47;
public final static int PROPERTY_BUILDING_IMPORTANCE = 48;
public final static int PROPERTY_MAX = 48;
public final static int HEADER_NULL = 0;
public final static int KG_CONNECT = 0x10;
public final static int KG_ACKNOWLEDGE = 0x11;
public final static int GK_CONNECT_OK = 0x12;
public final static int GK_CONNECT_ERROR = 0x13;
public final static int SK_CONNECT = 0x20;
public final static int SK_ACKNOWLEDGE = 0x21;
public final static int SK_UPDATE = 0x22;
public final static int KS_CONNECT_OK = 0x23;
public final static int KS_CONNECT_ERROR = 0x24;
public final static int VK_CONNECT = 0x30;
public final static int VK_ACKNOWLEDGE = 0x31;
public final static int KV_CONNECT_OK = 0x32;
public final static int KV_CONNECT_ERROR = 0x33;
public final static int AK_CONNECT = 0x40;
public final static int AK_ACKNOWLEDGE = 0x41;
public final static int KA_CONNECT_OK = 0x42;
public final static int KA_CONNECT_ERROR = 0x43;
public final static int KA_SENSE = 0x44;
public final static int KA_HEAR = 0x45;
public final static int KA_HEAR_SAY = 0x46;
public final static int KA_HEAR_TELL = 0x47;
public final static int UPDATE = 0x50;
public final static int COMMANDS = 0x51;
public final static int AK_REST = 0x80;
public final static int AK_MOVE = 0x81;
public final static int AK_LOAD = 0x82;
public final static int AK_UNLOAD = 0x83;
public final static int AK_SAY = 0x84;
public final static int AK_TELL = 0x85;
public final static int AK_EXTINGUISH = 0x86;
// public final static int AK_STRETCH = 0x87;
public final static int AK_RESCUE = 0x88;
public final static int AK_CLEAR = 0x89;
public final static int AK_CHANNEL = 0x90;
public final static int AK_REPAIR = 0x91; //changed from 90
public final static Object SOURCE_SENSE = "KA_SENSE";
public final static Object SOURCE_INITIAL = "KA_CONNECT_OK";
public final static Object SOURCE_UNKNOWN = "Unknown";
public final static Object SOURCE_NONE = "None";
public final static Object SOURCE_ASSUMED = "Assumed";
public final static Object SOURCE_UPDATE = "Update";
public final static int VALUE_UNKNOWN = -2;
public final static int VALUE_ASSUMED = -1;
}
/*
* Last change: $Date: 2004/05/20 23:41:59 $ $Revision: 1.5 $ Copyright (c)
* 2004, The Black Sheep, Department of Computer Science, The University of
* Auckland All rights reserved. Redistribution and use in source and binary
* forms, with or without modification, are permitted provided that the
* following conditions are met: Redistributions of source code must retain the
* above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. Neither the name of
* The Black Sheep, The Department of Computer Science or The University of
* Auckland nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package rescuecore;
import rescuecore.commands.*;
import java.util.*;
/**
* A RescueMessage is a package of Commands to be sent to the kernal
*/
public class RescueMessage {
private List parts;
public RescueMessage() {
parts = new ArrayList();
}
/**
* Append a new Command to the end of this message
*
* @param command
* The Command to append
*/
public void append( Command command ) {
parts.add( command );
}
/**
* Go through all parts of this message and make sure we don't have too many
* of any kind of Command
*
* @param type
* The bitwise or of the types of Command that are being culled
* @param max
* The maximum number of Commands of the given type that we are
* allowed
* @return The number of matching Commands left in this message once we're
* finished
*/
@Deprecated
public int cull( int type, int max ) {
int count = 0;
for ( Iterator it = parts.iterator(); it.hasNext(); ) {
Command next = (Command) it.next();
if ( ( next.getType() & type ) != 0 ) {
++count;
if ( count > max ) it.remove();
}
}
return count;
}
/**
* Go through all parts of this message and count how many of each type of
* Commannd we have
*
* @param type
* The bitwise or of the types of Command that are being counted
* @return The number of matching Commands
*/
@Deprecated
public int count( int type ) {
int count = 0;
for ( Iterator it = parts.iterator(); it.hasNext(); ) {
Command next = (Command) it.next();
if ( ( next.getType() & type ) != 0 ) {
++count;
}
}
return count;
}
/**
* Turn this RescueMessage into a raw byte array ready for wrapping in a
* LongUDPMessage
*
* @return A byte array ready for wrapping
* @see LongUDPMessage
*/
public byte[] toByteArray() {
OutputBuffer out = new OutputBuffer();
Command[] all = new Command[parts.size()];
parts.toArray( all );
out.writeCommands( all );
return out.getBytes();
}
public String toString() {
StringBuffer result = new StringBuffer();
result.append( "RescueMessage with " );
result.append( parts.size() );
result.append( parts.size() == 1 ? " part" : " parts" );
result.append( ": " );
for ( Iterator it = parts.iterator(); it.hasNext(); ) {
result.append(
Handy.getCommandTypeName( ( (Command) it.next() ).getType() ) );
if ( it.hasNext() ) result.append( ", " );
}
return result.toString();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment