Merge branch 'develop' into Story64_SailsAnimations

# Conflicts:
#	src/main/java/seng302/visualiser/GameClient.java
This commit is contained in:
Alistair McIntyre
2017-08-14 14:04:53 +12:00
24 changed files with 381 additions and 334 deletions
@@ -4,9 +4,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import seng302.gameServer.server.messages.BoatAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import seng302.gameServer.server.messages.BoatActionType;
import seng302.model.Player;
import seng302.model.Yacht;
import seng302.model.mark.MarkOrder;
@@ -56,7 +56,6 @@ public class GameState implements Runnable {
players = new ArrayList<>();
currentStage = GameStages.LOBBYING;
isRaceStarted = false;
yachts = new HashMap<>();
//set this when game stage changes to prerace
previousUpdateTime = System.currentTimeMillis();
yachts = new HashMap<>();
@@ -75,7 +74,8 @@ public class GameState implements Runnable {
public static void addPlayer(Player player) {
players.add(player);
String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName() + " " + player.getYacht().getCountry();
String playerText = player.getYacht().getSourceId() + " " + player.getYacht().getBoatName()
+ " " + player.getYacht().getCountry();
playerStringMap.put(player, playerText);
}
@@ -132,7 +132,7 @@ public class GameState implements Runnable {
return yachts;
}
public static void updateBoat(Integer sourceId, BoatActionType actionType) {
public static void updateBoat(Integer sourceId, BoatAction actionType) {
Yacht playerYacht = yachts.get(sourceId);
// System.out.println("-----------------------");
switch (actionType) {
@@ -42,7 +42,6 @@ public class HeartbeatThread extends Thread{
*/
private void sendHeartbeatToAllPlayers(){
Message heartbeat = new Heartbeat(seqNum);
for (Player player : GameState.getPlayers()){
if (!player.getSocket().isConnected()) {
playerLostConnection(player);
@@ -54,7 +53,6 @@ public class HeartbeatThread extends Thread{
playerLostConnection(player);
}
}
updateDelegate();
seqNum++;
}
@@ -71,7 +69,6 @@ public class HeartbeatThread extends Thread{
public void run(){
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
@@ -8,6 +8,7 @@ import java.util.Observable;
import java.util.Timer;
import java.util.TimerTask;
import seng302.model.Player;
import seng302.model.PolarTable;
/**
* A class describing the overall server, which creates and collects server threads for each client
@@ -32,7 +33,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
} catch (IOException e) {
serverLog("IO error in server thread handler upon trying to make new server socket", 0);
}
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
terminated = false;
thread = new Thread(this);
thread.start();
@@ -44,6 +45,7 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
HeartbeatThread heartbeatThread;
serverListenThread = new ServerListenThread(serverSocket, this);
heartbeatThread = new HeartbeatThread(this);
heartbeatThread.start();
@@ -102,9 +104,11 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
public void clientConnected(ServerToClientThread serverToClientThread) {
serverLog("Player Connected From " + serverToClientThread.getThread().getName(), 0);
serverToClientThreads.add(serverToClientThread);
this.addObserver(serverToClientThread);
setChanged();
notifyObservers();
serverToClientThread.addConnectionListener(() -> {
for (ServerToClientThread thread : serverToClientThreads) {
thread.sendSetupMessages();
}
});
}
/**
@@ -121,11 +125,15 @@ public class MainServerThread extends Observable implements Runnable, ClientConn
serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
GameState.removeYacht(player.getYacht().getSourceId());
GameState.removePlayer(player);
ServerToClientThread closedConnection = null;
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
if (serverToClientThread.getSocket() == player.getSocket()) {
this.deleteObserver(serverToClientThread);
closedConnection = serverToClientThread;
} else {
serverToClientThread.sendSetupMessages();
}
}
serverToClientThreads.remove(closedConnection);
setChanged();
notifyObservers();
}
@@ -5,16 +5,16 @@ import java.util.Arrays;
import seng302.gameServer.server.messages.ClientType;
import seng302.gameServer.server.messages.Message;
import seng302.model.stream.packets.StreamPacket;
import seng302.gameServer.server.messages.BoatActionType;
import seng302.gameServer.server.messages.BoatAction;
public class ServerPacketParser {
public static BoatActionType extractBoatAction(StreamPacket packet) {
public static BoatAction extractBoatAction(StreamPacket packet) {
byte[] payload = packet.getPayload();
int messageVersionNo = payload[0];
long actionTypeValue = Message.bytesToLong(Arrays.copyOfRange(payload, 0, 1));
return BoatActionType.getType((int) actionTypeValue);
return BoatAction.getType((int) actionTypeValue);
}
public static ClientType extractClientType(StreamPacket packet){
@@ -1,7 +1,34 @@
package seng302.gameServer;
import seng302.gameServer.server.messages.*;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
import seng302.gameServer.server.messages.BoatAction;
import seng302.gameServer.server.messages.BoatLocationMessage;
import seng302.gameServer.server.messages.BoatStatus;
import seng302.gameServer.server.messages.BoatSubMessage;
import seng302.gameServer.server.messages.ClientType;
import seng302.gameServer.server.messages.Message;
import seng302.gameServer.server.messages.RaceStatus;
import seng302.gameServer.server.messages.RaceStatusMessage;
import seng302.gameServer.server.messages.RaceType;
import seng302.gameServer.server.messages.RegistrationResponseMessage;
import seng302.gameServer.server.messages.RegistrationResponseStatus;
import seng302.gameServer.server.messages.XMLMessage;
import seng302.gameServer.server.messages.XMLMessageSubType;
import seng302.model.Player;
import seng302.model.Yacht;
import seng302.model.stream.packets.PacketType;
@@ -10,25 +37,20 @@ import seng302.model.stream.xml.generator.Race;
import seng302.model.stream.xml.generator.Regatta;
import seng302.utilities.XMLGenerator;
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
/**
* A class describing a single connection to a Client for the purposes of sending and receiving on
* its own thread. All server threads created and owned by the server thread handler which can
* trigger client updates on its threads Created by wmu16 on 13/07/17.
*/
public class ServerToClientThread implements Runnable, Observer {
public class ServerToClientThread implements Runnable {
/**
* Called to notify listeners when this thread receives a connection correctly.
*/
@FunctionalInterface
interface ConnectionListener {
void notifyConnection ();
}
private static final Integer LOG_LEVEL = 1;
private static final Integer MAX_ID_ATTEMPTS = 10;
@@ -41,9 +63,6 @@ public class ServerToClientThread implements Runnable, Observer {
private ByteArrayOutputStream crcBuffer;
private Boolean userIdentified = false;
private Boolean connected = true;
private Boolean updateClient = true;
// private Boolean initialisedRace = true;
private Integer seqNo;
@@ -54,6 +73,8 @@ public class ServerToClientThread implements Runnable, Observer {
private XMLGenerator xml;
private List<ConnectionListener> connectionListeners = new ArrayList<>();
public ServerToClientThread(Socket socket) {
this.socket = socket;
seqNo = 0;
@@ -69,7 +90,7 @@ public class ServerToClientThread implements Runnable, Observer {
thread.start();
}
private void setUpYacht(){
private void setUpPlayer(){
BufferedReader fn;
String fName = "";
BufferedReader ln;
@@ -98,7 +119,6 @@ public class ServerToClientThread implements Runnable, Observer {
Yacht yacht = new Yacht(
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
);
GameState.addYacht(sourceId, yacht);
GameState.addPlayer(new Player(socket, yacht));
}
@@ -110,11 +130,6 @@ public class ServerToClientThread implements Runnable, Observer {
}
}
@Override
public void update(Observable o, Object arg) {
sendSetupMessages();
}
private void completeRegistration(ClientType clientType) throws IOException {
// Fail if not a player
if (!clientType.equals(ClientType.PLAYER)){
@@ -134,12 +149,14 @@ public class ServerToClientThread implements Runnable, Observer {
this.clientType = clientType;
this.sourceId = sourceId;
setUpYacht();
isRegistered = true;
os.write(responseMessage.getBuffer());
sendSetupMessages();
setUpPlayer();
for (ConnectionListener listener : connectionListeners) {
listener.notifyConnection();
}
}
public void run() {
@@ -151,20 +168,6 @@ public class ServerToClientThread implements Runnable, Observer {
while (socket.isConnected()) {
try {
//Perform a write if it is time to as delegated by the MainServerThread
if (updateClient) {
// TODO: 13/07/17 wmu16 - Write out game state - some function that would write all appropriate messages to this output stream
// ChatterMessage chatterMessage = new ChatterMessage(4, 14, "Hello, it's me");
// sendMessage(chatterMessage);
// try {
// GameState.outputState(os);
// } catch (IOException e) {
// System.out.println("IO error in server thread upon writing to output stream");
// }
// sendBoatLocationPackets();
updateClient = false;
}
crcBuffer = new ByteArrayOutputStream();
sync1 = readByte();
sync2 = readByte();
@@ -184,7 +187,7 @@ public class ServerToClientThread implements Runnable, Observer {
//System.out.println("RECEIVED A PACKET");
switch (PacketType.assignPacketType(type, payload)) {
case BOAT_ACTION:
BoatActionType actionType = ServerPacketParser
BoatAction actionType = ServerPacketParser
.extractBoatAction(
new StreamPacket(type, payloadLength, timeStamp, payload));
GameState.updateBoat(sourceId, actionType);
@@ -210,7 +213,7 @@ public class ServerToClientThread implements Runnable, Observer {
}
}
private void sendSetupMessages() {
public void sendSetupMessages() {
xml = new XMLGenerator();
Race race = new Race();
@@ -238,23 +241,6 @@ public class ServerToClientThread implements Runnable, Observer {
public void updateClient() {
sendBoatLocationPackets();
updateClient = true;
}
/**
* Tries to confirm the connection just accepted.
* Sends ID, expects that ID echoed for confirmation,
* if so, sends a confirmation packet back to that connection
* Creates a player instance with that ID and this thread and adds it to the GameState
* If not, close the socket and end the threads execution
*
* @param id the id to try and assign to the connection
* @return A boolean indicating if it was a successful handshake
*/
private Boolean threeWayHandshake(Integer id) {
return true;
}
private void closeSocket() {
@@ -265,7 +251,6 @@ public class ServerToClientThread implements Runnable, Observer {
}
}
private int readByte() throws Exception {
int currentByte = -1;
try {
@@ -316,7 +301,6 @@ public class ServerToClientThread implements Runnable, Observer {
private void sendBoatLocationPackets() {
ArrayList<Yacht> yachts = new ArrayList<>(GameState.getYachts().values());
for (Yacht yacht : yachts) {
// System.out.println("[SERVER] Lat: " + yacht.getLocation().getLat() + " Lon: " + yacht.getLocation().getLng());
BoatLocationMessage boatLocationMessage =
new BoatLocationMessage(
yacht.getSourceId(),
@@ -337,7 +321,6 @@ public class ServerToClientThread implements Runnable, Observer {
public void sendRaceStatusMessage() {
// variables taken from GameServerThread
List<BoatSubMessage> boatSubMessages = new ArrayList<>();
BoatStatus boatStatus;
RaceStatus raceStatus;
@@ -372,4 +355,12 @@ public class ServerToClientThread implements Runnable, Observer {
public Socket getSocket() {
return socket;
}
public void addConnectionListener(ConnectionListener listener) {
connectionListeners.add(listener);
}
public void removeConnectionListener(ConnectionListener listener) {
connectionListeners.remove(listener);
}
}
@@ -6,29 +6,30 @@ import java.util.Map;
/**
* Created by kre39 on 12/07/17.
*/
public enum BoatActionType {
public enum BoatAction {
VMG(1),
SAILS_IN(2),
SAILS_OUT(3),
TACK_GYBE(4),
UPWIND(5),
DOWNWIND(6);
DOWNWIND(6),
MAINTAIN_HEADING(7);
private final int type;
private static final Map<Integer, BoatActionType> intToTypeMap = new HashMap<>();
private static final Map<Integer, BoatAction> intToTypeMap = new HashMap<>();
static {
for (BoatActionType type : BoatActionType.values()) {
for (BoatAction type : BoatAction.values()) {
intToTypeMap.put(type.getValue(), type);
}
}
BoatActionType(int type){
BoatAction(int type){
this.type = type;
}
public static BoatActionType getType(int value) {
public static BoatAction getType(int value) {
return intToTypeMap.get(value);
}
@@ -6,9 +6,9 @@ package seng302.gameServer.server.messages;
public class BoatActionMessage extends Message{
private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION;
private final int MESSAGE_SIZE = 1;
private BoatActionType actionType;
private BoatAction actionType;
public BoatActionMessage(BoatActionType actionType) {
public BoatActionMessage(BoatAction actionType) {
this.actionType = actionType;
setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id
allocateBuffer();