mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Merge branch 'develop' into story61_player_perspective
# Conflicts: # src/main/java/seng302/App.java # src/main/java/seng302/client/ClientPacketParser.java # src/main/java/seng302/client/ClientState.java # src/main/java/seng302/client/ClientStateQueryingRunnable.java # src/main/java/seng302/controllers/Controller.java # src/main/java/seng302/controllers/LobbyController.java # src/main/java/seng302/controllers/RaceViewController.java # src/main/java/seng302/controllers/StartScreenController.java # src/main/java/seng302/fxObjects/BoatAnnotations.java # src/main/java/seng302/gameServer/GameState.java # src/main/java/seng302/gameServer/MainServerThread.java # src/main/java/seng302/model/Yacht.java # src/main/java/seng302/model/stream/StreamReceiver.java # src/main/java/seng302/visualiser/ClientToServerThread.java # src/main/java/seng302/visualiser/GameView.java # src/main/java/seng302/visualiser/fxObjects/BoatObject.java # src/test/java/seng302/model/stream/StreamReceiverTest.java
This commit is contained in:
@@ -13,7 +13,9 @@ import seng302.server.messages.BoatActionType;
|
||||
* A Static class to hold information about the current state of the game (model)
|
||||
* Created by wmu16 on 10/07/17.
|
||||
*/
|
||||
public class GameState {
|
||||
public class GameState implements Runnable {
|
||||
|
||||
private static Integer STATE_UPDATES_PER_SECOND = 60;
|
||||
|
||||
private static Long previousUpdateTime;
|
||||
public static Double windDirection;
|
||||
@@ -40,8 +42,9 @@ public class GameState {
|
||||
*/
|
||||
|
||||
public GameState(String hostIpAddress) {
|
||||
windDirection = 170d;
|
||||
windDirection = 180d;
|
||||
windSpeed = 10000d;
|
||||
this.hostIpAddress = hostIpAddress;
|
||||
yachts = new HashMap<>();
|
||||
players = new ArrayList<>();
|
||||
GameState.hostIpAddress = hostIpAddress;
|
||||
@@ -52,6 +55,9 @@ public class GameState {
|
||||
//set this when game stage changes to prerace
|
||||
previousUpdateTime = System.currentTimeMillis();
|
||||
yachts = new HashMap<>();
|
||||
|
||||
new Thread(this).start();
|
||||
|
||||
}
|
||||
|
||||
public static String getHostIpAddress() {
|
||||
@@ -96,9 +102,17 @@ public class GameState {
|
||||
}
|
||||
|
||||
public static void setCurrentStage(GameStages currentStage) {
|
||||
if (currentStage == GameStages.RACING){
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
GameState.currentStage = currentStage;
|
||||
}
|
||||
|
||||
public static long getStartTime(){
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public static Double getWindDirection() {
|
||||
return windDirection;
|
||||
}
|
||||
@@ -122,7 +136,6 @@ public class GameState {
|
||||
case VMG:
|
||||
playerYacht.turnToVMG();
|
||||
// System.out.println("Snapping to VMG");
|
||||
// TODO: 22/07/17 wmu16 - Add in the vmg calculation code here
|
||||
break;
|
||||
case SAILS_IN:
|
||||
playerYacht.toggleSailIn();
|
||||
@@ -146,17 +159,10 @@ public class GameState {
|
||||
break;
|
||||
}
|
||||
|
||||
System.out.println("-----------------------");
|
||||
System.out.println("Sails are in: " + playerYacht.getSailIn());
|
||||
System.out.println("Heading: " + playerYacht.getHeading());
|
||||
System.out.println("Velocity: " + playerYacht.getVelocityMMS() / 1000);
|
||||
System.out.println("Lat: " + playerYacht.getLocation().getLat());
|
||||
System.out.println("Lng: " + playerYacht.getLocation().getLng());
|
||||
System.out.println("-----------------------\n");
|
||||
// printBoatStatus(playerYacht);
|
||||
}
|
||||
|
||||
public static void update() {
|
||||
|
||||
Long timeInterval = System.currentTimeMillis() - previousUpdateTime;
|
||||
previousUpdateTime = System.currentTimeMillis();
|
||||
for (Yacht yacht : yachts.values()) {
|
||||
@@ -173,4 +179,38 @@ public class GameState {
|
||||
// TODO: 22/07/17 wmu16 - This may not be robust enough and may have to be improved on.
|
||||
return yachts.size() + 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A thread to have the game state update itself at certain intervals
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
while(true) {
|
||||
try {
|
||||
Thread.sleep(1000 / STATE_UPDATES_PER_SECOND);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("[GameState] interrupted exception");
|
||||
}
|
||||
if (currentStage == GameStages.PRE_RACE) {
|
||||
update();
|
||||
}
|
||||
|
||||
//RACING
|
||||
if (currentStage == GameStages.RACING) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void printBoatStatus(Yacht playerYacht) {
|
||||
System.out.println("-----------------------");
|
||||
System.out.println("Sails are in: " + playerYacht.getSailIn());
|
||||
System.out.println("Heading: " + playerYacht.getHeading());
|
||||
System.out.println("Velocity: " + playerYacht.getVelocityMMS() / 1000);
|
||||
System.out.println("Lat: " + playerYacht.getLocation().getLat());
|
||||
System.out.println("Lng: " + playerYacht.getLocation().getLng());
|
||||
System.out.println("-----------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,35 +2,36 @@ package seng302.gameServer;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Observable;
|
||||
import seng302.client.ClientPacketParser;
|
||||
import seng302.models.Player;
|
||||
import seng302.models.stream.PacketBufferDelegate;
|
||||
import seng302.models.stream.packets.StreamPacket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
import seng302.model.Player;
|
||||
import seng302.model.stream.PacketBufferDelegate;
|
||||
import seng302.model.stream.packets.StreamPacket;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A class describing the overall server, which creates and collects server threads for each client
|
||||
* Created by wmu16 on 13/07/17.
|
||||
*/
|
||||
public class MainServerThread extends Observable implements Runnable, PacketBufferDelegate, ClientConnectionDelegate{
|
||||
public class MainServerThread extends Observable implements Runnable, ClientConnectionDelegate{
|
||||
|
||||
private static final int PORT = 4942;
|
||||
private static final Integer MAX_NUM_PLAYERS = 3;
|
||||
private static final Integer UPDATES_PER_SECOND = 2;
|
||||
private static final Integer CLIENT_UPDATES_PER_SECOND = 10;
|
||||
private static final int LOG_LEVEL = 1;
|
||||
private boolean terminated;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
private ServerSocket serverSocket = null;
|
||||
private Socket socket;
|
||||
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
|
||||
|
||||
private PriorityBlockingQueue<StreamPacket> packetBuffer;
|
||||
|
||||
|
||||
public MainServerThread() {
|
||||
try {
|
||||
serverSocket = new ServerSocket(PORT);
|
||||
@@ -38,8 +39,7 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
|
||||
serverLog("IO error in server thread handler upon trying to make new server socket", 0);
|
||||
}
|
||||
|
||||
packetBuffer = new PriorityBlockingQueue<>();
|
||||
|
||||
terminated = false;
|
||||
thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
@@ -55,22 +55,20 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
|
||||
heartbeatThread.start();
|
||||
serverListenThread.start();
|
||||
|
||||
|
||||
//You should handle interrupts in some way, so that the thread won't keep on forever if you exit the app.
|
||||
while (!thread.isInterrupted()) {
|
||||
while (!terminated) {
|
||||
try {
|
||||
Thread.sleep(1000 / UPDATES_PER_SECOND);
|
||||
Thread.sleep(1000 / CLIENT_UPDATES_PER_SECOND);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
serverLog("Interrupted exception in Main Server Thread thread sleep", 1);
|
||||
}
|
||||
|
||||
if (GameState.getCurrentStage() == GameStages.PRE_RACE) {
|
||||
GameState.update();
|
||||
updateClients();
|
||||
}
|
||||
|
||||
//RACING
|
||||
if (GameState.getCurrentStage() == GameStages.RACING) {
|
||||
GameState.update();
|
||||
updateClients();
|
||||
}
|
||||
|
||||
@@ -78,15 +76,6 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
|
||||
else if (GameState.getCurrentStage() == GameStages.FINISHED) {
|
||||
|
||||
}
|
||||
|
||||
while (!packetBuffer.isEmpty()){
|
||||
try {
|
||||
StreamPacket packet = packetBuffer.take();
|
||||
// ClientPacketParser.parsePacket(packet);
|
||||
} catch (InterruptedException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
|
||||
@@ -111,11 +100,6 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addToBuffer(StreamPacket streamPacket) {
|
||||
return packetBuffer.add(streamPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* A client has tried to connect to the server
|
||||
* @param serverToClientThread The player that connected
|
||||
@@ -153,20 +137,20 @@ public class MainServerThread extends Observable implements Runnable, PacketBuff
|
||||
}
|
||||
|
||||
public void startGame() {
|
||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||
serverToClientThread.sendRaceStatusMessage();
|
||||
}
|
||||
Timer t = new Timer();
|
||||
|
||||
t.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||
serverToClientThread.sendRaceStatusMessage();
|
||||
}
|
||||
}
|
||||
}, 0, 500);
|
||||
}
|
||||
|
||||
public void shutDown() {
|
||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||
try {
|
||||
serverToClientThread.getSocket().close();
|
||||
} catch (IOException ioe) {
|
||||
serverLog("Failed to close socket " + serverToClientThread.getSocket().toString(), 0);
|
||||
}
|
||||
}
|
||||
serverToClientThreads = null;
|
||||
thread = null;
|
||||
public void terminate() {
|
||||
terminated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@ public class ServerListenThread extends Thread{
|
||||
private void acceptConnection() {
|
||||
try {
|
||||
Socket thisClient = serverSocket.accept();
|
||||
if (thisClient != null){
|
||||
if (thisClient != null && GameState.getCurrentStage().equals(GameStages.LOBBYING)) {
|
||||
ServerToClientThread thisConnection = new ServerToClientThread(thisClient);
|
||||
delegate.clientConnected(thisConnection);
|
||||
} else {
|
||||
thisClient.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.getMessage();
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package seng302.gameServer;
|
||||
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
@@ -12,6 +15,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.Checksum;
|
||||
import seng302.model.Player;
|
||||
@@ -63,17 +69,41 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
|
||||
public ServerToClientThread(Socket socket) {
|
||||
this.socket = socket;
|
||||
BufferedReader fn;
|
||||
String fName = "";
|
||||
BufferedReader ln;
|
||||
String lName = "";
|
||||
try {
|
||||
is = socket.getInputStream();
|
||||
os = socket.getOutputStream();
|
||||
fn = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
ServerToClientThread.class.getResourceAsStream(
|
||||
"/server_config/CSV_Database_of_First_Names.csv"
|
||||
)
|
||||
)
|
||||
);
|
||||
List<String> all = fn.lines().collect(Collectors.toList());
|
||||
fName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
||||
ln = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
ServerToClientThread.class.getResourceAsStream(
|
||||
"/server_config/CSV_Database_of_Last_Names.csv"
|
||||
)
|
||||
)
|
||||
);
|
||||
all = ln.lines().collect(Collectors.toList());
|
||||
lName = all.get(ThreadLocalRandom.current().nextInt(0, all.size()));
|
||||
} catch (IOException e) {
|
||||
System.out.println("IO error in server thread upon grabbing streams");
|
||||
serverLog("IO error in server thread upon grabbing streams", 1);
|
||||
}
|
||||
//Attempt threeway handshake with connection
|
||||
sourceId = GameState.getUniquePlayerID();
|
||||
if (threeWayHandshake(sourceId)) {
|
||||
serverLog("Successful handshake. Client allocated id: " + sourceId, 1);
|
||||
Yacht yacht = new Yacht("Yacht", sourceId, sourceId.toString(), "Kapa", "Kappa", "NZ");
|
||||
serverLog("Successful handshake. Client allocated id: " + sourceId, 0);
|
||||
Yacht yacht = new Yacht(
|
||||
"Yacht", sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
|
||||
);
|
||||
// Yacht yacht = new Yacht("Kappa", "Kap", new GeoPoint(57.6708220, 11.8321340), 90.0);
|
||||
GameState.addYacht(sourceId, yacht);
|
||||
GameState.addPlayer(new Player(socket, yacht));
|
||||
@@ -108,11 +138,6 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
while (socket.isConnected()) {
|
||||
|
||||
try {
|
||||
// if (initialisedRace) {
|
||||
// sendSetupMessages();
|
||||
// initialisedRace = false;
|
||||
// }
|
||||
|
||||
//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
|
||||
@@ -159,12 +184,10 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
} catch (Exception e) {
|
||||
// TODO: 24/07/17 zyt10 - fix a logic here when a client disconnected
|
||||
// serverLog("ERROR OCCURRED, CLOSING SERVER CONNECTION: " + socket.getRemoteSocketAddress().toString(), 1);
|
||||
// e.printStackTrace();
|
||||
closeSocket();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendSetupMessages() {
|
||||
@@ -179,18 +202,18 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
xml.setRegatta(new Regatta("RaceVision Test Game", 57.6679590, 11.8503233));
|
||||
xml.setRace(race);
|
||||
|
||||
XMLMessage xmlMessage = new XMLMessage(xml.getRegattaAsXml(), XMLMessageSubType.REGATTA,
|
||||
xml.getRegattaAsXml().length());
|
||||
XMLMessage xmlMessage;
|
||||
xmlMessage = new XMLMessage(xml.getRegattaAsXml(), XMLMessageSubType.REGATTA,
|
||||
xml.getRegattaAsXml().length());
|
||||
sendMessage(xmlMessage);
|
||||
|
||||
xmlMessage = new XMLMessage(xml.getBoatsAsXml(), XMLMessageSubType.BOAT,
|
||||
xml.getBoatsAsXml().length());
|
||||
xml.getBoatsAsXml().length());
|
||||
sendMessage(xmlMessage);
|
||||
|
||||
xmlMessage = new XMLMessage(xml.getRaceAsXml(), XMLMessageSubType.RACE,
|
||||
xml.getRaceAsXml().length());
|
||||
xml.getRaceAsXml().length());
|
||||
sendMessage(xmlMessage);
|
||||
// System.out.println("Sent xml messages for " + thread.getName());
|
||||
}
|
||||
|
||||
public void updateClient() {
|
||||
@@ -217,7 +240,7 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
os.write(id); //Send out new ID looking for echo
|
||||
confirmationID = is.read();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
serverLog("Three way handshake failed", 1);
|
||||
}
|
||||
|
||||
if (id.equals(confirmationID)) { //ID is echoed back. Connection is a client
|
||||
@@ -247,7 +270,7 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
currentByte = is.read();
|
||||
crcBuffer.write(currentByte);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
serverLog("Socket read failed", 1);
|
||||
}
|
||||
if (currentByte == -1) {
|
||||
throw new Exception();
|
||||
@@ -273,10 +296,10 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
try {
|
||||
os.write(message.getBuffer());
|
||||
} catch (SocketException e) {
|
||||
//serverLog("Player " + sourceId + " side socket disconnected", 0);
|
||||
//serverLog("Player " + sourceId + " side socket disconnected", 1);
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
serverLog("Message send failed", 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,8 +332,7 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
|
||||
public void sendRaceStatusMessage() {
|
||||
// variables taken from GameServerThread
|
||||
int TIME_TILL_RACE_START = 20 * 1000;
|
||||
long startTime = System.currentTimeMillis() + TIME_TILL_RACE_START;
|
||||
|
||||
|
||||
List<BoatSubMessage> boatSubMessages = new ArrayList<>();
|
||||
BoatStatus boatStatus;
|
||||
@@ -338,7 +360,7 @@ public class ServerToClientThread implements Runnable, Observer {
|
||||
raceStatus = RaceStatus.WARNING;
|
||||
}
|
||||
|
||||
sendMessage(new RaceStatusMessage(1, raceStatus, startTime, GameState.getWindDirection(),
|
||||
sendMessage(new RaceStatusMessage(1, raceStatus, GameState.getStartTime(), GameState.getWindDirection(),
|
||||
GameState.getWindSpeedMMS().longValue(), GameState.getPlayers().size(),
|
||||
RaceType.MATCH_RACE, 1, boatSubMessages));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user