Merge pull request #47 from rubenpirreram/Server-Launcher
Server-Launcher
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
package it.polimi.ingsw.gc14.Network;
|
package it.polimi.ingsw.gc14.Network;
|
||||||
|
|
||||||
import it.polimi.ingsw.gc14.Controller.GameController;
|
import it.polimi.ingsw.gc14.Controller.GameController;
|
||||||
import javafx.event.Event;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
@@ -12,9 +11,23 @@ public abstract class NetworkEvent implements Serializable {
|
|||||||
}
|
}
|
||||||
protected EventType eventType;
|
protected EventType eventType;
|
||||||
public EventType getEventType() {return eventType;}
|
public EventType getEventType() {return eventType;}
|
||||||
protected NetworkEvent(String username, EventType eventType) {
|
protected boolean isError;
|
||||||
|
public boolean getIsError() {return isError;}
|
||||||
|
public void setIsError(boolean isError) {this.isError = isError;}
|
||||||
|
|
||||||
|
protected NetworkEvent(String username, EventType eventType, boolean isError) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.eventType = eventType;
|
this.eventType = eventType;
|
||||||
|
this.isError = isError;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if(isError) {
|
||||||
|
return ("ERROR: action " + eventType.toString());
|
||||||
|
} else {
|
||||||
|
return ("ACTION: action " + eventType.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean apply(GameController gameController);
|
public abstract boolean apply(GameController gameController);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class AddPlayer extends NetworkEvent implements Serializable {
|
|||||||
return proposedNPlayer;
|
return proposedNPlayer;
|
||||||
}
|
}
|
||||||
public AddPlayer(String username, int proposedNPlayer) {
|
public AddPlayer(String username, int proposedNPlayer) {
|
||||||
super(username, EventType.ADD_PLAYER);
|
super(username, EventType.ADD_PLAYER, false);
|
||||||
this.proposedNPlayer = proposedNPlayer;
|
this.proposedNPlayer = proposedNPlayer;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class DrawLowerBuildingCard extends NetworkEvent implements Serializable
|
|||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
public DrawLowerBuildingCard(String username, int pos){
|
public DrawLowerBuildingCard(String username, int pos){
|
||||||
super(username, EventType.DRAW_LOWER_BUILD);
|
super(username, EventType.DRAW_LOWER_BUILD, false);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class DrawLowerTribeCard extends NetworkEvent implements Serializable{
|
|||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
public DrawLowerTribeCard(String username, int pos){
|
public DrawLowerTribeCard(String username, int pos){
|
||||||
super(username, EventType.DRAW_LOWER_TRIBE);
|
super(username, EventType.DRAW_LOWER_TRIBE, false);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class DrawUpperBuildingCard extends NetworkEvent implements Serializable
|
|||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
public DrawUpperBuildingCard(String username, int pos){
|
public DrawUpperBuildingCard(String username, int pos){
|
||||||
super(username, EventType.DRAW_UPPER_BUILD);
|
super(username, EventType.DRAW_UPPER_BUILD, false);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class DrawUpperTribeCard extends NetworkEvent implements Serializable{
|
|||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
public DrawUpperTribeCard(String username, int pos){
|
public DrawUpperTribeCard(String username, int pos){
|
||||||
super(username, EventType.DRAW_UPPER_TRIBE);
|
super(username, EventType.DRAW_UPPER_TRIBE, false);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ public class PickOptionalBuildingCard extends NetworkEvent implements Serializa
|
|||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
public PickOptionalBuildingCard(String username, int pos){
|
public PickOptionalBuildingCard(String username, int pos){
|
||||||
super(username, EventType.PICK_OPTIONAL_BUILD);
|
super(username, EventType.PICK_OPTIONAL_BUILD, false);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class PickOptionalTribeCard extends NetworkEvent implements Serializable
|
|||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
public PickOptionalTribeCard(String username, int pos){
|
public PickOptionalTribeCard(String username, int pos){
|
||||||
super(username, EventType.PICK_OPTIONAL_TRIBE);
|
super(username, EventType.PICK_OPTIONAL_TRIBE, false);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class SlotChoice extends NetworkEvent implements Serializable {
|
|||||||
private int pos;
|
private int pos;
|
||||||
|
|
||||||
public SlotChoice(String username, int pos) {
|
public SlotChoice(String username, int pos) {
|
||||||
super(username, EventType.SLOT_CHOICE);
|
super(username, EventType.SLOT_CHOICE, false);
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,13 +23,11 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAction(NetworkEvent event) throws RemoteException {
|
public void onAction(NetworkEvent event) throws RemoteException {
|
||||||
event.apply(clientController.localController); // delega tutto al controller
|
if(event.getIsError()) {
|
||||||
//clientController.view.update(); TODO
|
System.out.println(event.toString());
|
||||||
|
} else {
|
||||||
|
event.apply(clientController.localController); // delega tutto al controller
|
||||||
|
//clientController.view.update(); TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(String message) throws RemoteException {
|
|
||||||
clientController.onError(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,4 @@ import java.rmi.*;
|
|||||||
public interface IClientCallback extends Remote {
|
public interface IClientCallback extends Remote {
|
||||||
void onGameInit(Game model) throws RemoteException;
|
void onGameInit(Game model) throws RemoteException;
|
||||||
void onAction(NetworkEvent action) throws RemoteException;
|
void onAction(NetworkEvent action) throws RemoteException;
|
||||||
void onError(String message) throws RemoteException;
|
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ public class RMIServer implements IGameServer {
|
|||||||
if (controller.addPlayer(username)) {
|
if (controller.addPlayer(username)) {
|
||||||
if(playerList.size()==0)
|
if(playerList.size()==0)
|
||||||
{
|
{
|
||||||
Game game= new Game(preferredInt);
|
Game game = new Game(preferredInt);
|
||||||
controller.setModel(game);
|
controller.setModel(game);
|
||||||
playerList.setLimit(preferredInt);
|
playerList.setLimit(preferredInt);
|
||||||
}
|
}
|
||||||
@@ -83,10 +83,6 @@ public class RMIServer implements IGameServer {
|
|||||||
cb.onGameInit(model);
|
cb.onGameInit(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void notifyError(String username, String message) throws RemoteException {
|
|
||||||
IClientCallback cb = clients.get(username);
|
|
||||||
if (cb != null) cb.onError(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package it.polimi.ingsw.gc14.Network.TCP.Client;
|
package it.polimi.ingsw.gc14.Network.TCP.Client;
|
||||||
|
|
||||||
import it.polimi.ingsw.gc14.Controller.GameController;
|
import it.polimi.ingsw.gc14.Controller.GameController;
|
||||||
|
import it.polimi.ingsw.gc14.Model.Game;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
import it.polimi.ingsw.gc14.Network.NetworkEvent;
|
||||||
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
|
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
|
||||||
|
|
||||||
@@ -46,7 +47,21 @@ public class TCPClient implements Serializable{
|
|||||||
private void ReceiveMessage(){
|
private void ReceiveMessage(){
|
||||||
while(true){
|
while(true){
|
||||||
try{
|
try{
|
||||||
((NetworkEvent)(socketReceive.readObject())).apply(controller);
|
Object read = socketReceive.readObject();
|
||||||
|
|
||||||
|
if (read instanceof NetworkEvent) { //TODO non fare con instanceof
|
||||||
|
NetworkEvent event = (NetworkEvent) read;
|
||||||
|
if(event.getIsError()) {
|
||||||
|
System.out.println(event.toString());
|
||||||
|
} else {
|
||||||
|
event.apply(controller);
|
||||||
|
//clientController.view.update(); TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (read instanceof Game) {
|
||||||
|
controller.setModel((Game) read);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(IOException e){
|
catch(IOException e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ public class ClientHandler implements Runnable {
|
|||||||
while(true){
|
while(true){
|
||||||
try{
|
try{
|
||||||
input = (NetworkEvent) (in.readObject());
|
input = (NetworkEvent) (in.readObject());
|
||||||
if(actionQueue.add(input)){
|
if(!actionQueue.add(input)){
|
||||||
server.broadcastUpdate(input);
|
System.out.println("An error occurred in inserting an action into queue");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(java.io.IOException e){
|
catch(java.io.IOException e){
|
||||||
@@ -53,8 +53,6 @@ public class ClientHandler implements Runnable {
|
|||||||
catch (ClassNotFoundException e){
|
catch (ClassNotFoundException e){
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
|
|||||||
@@ -118,11 +118,11 @@ public class TCPServer {
|
|||||||
this.playerList = players;
|
this.playerList = players;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void broadcastUpdate(NetworkEvent event){
|
public void notifyAll(NetworkEvent event){
|
||||||
clientHandlers.forEach((x) -> x.notifyEvent(event));
|
clientHandlers.forEach((x) -> x.notifyEvent(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void broadcastModel(Game model){
|
public void notifyAll(Game model){
|
||||||
clientHandlers.forEach((x) -> x.notifyModel(model));
|
clientHandlers.forEach((x) -> x.notifyModel(model));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,16 +12,58 @@ import java.rmi.RemoteException;
|
|||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main server launcher that handles both TCP and RMI connections.
|
||||||
|
* The workflow is divided into two parts: game creation and game execution.
|
||||||
|
*
|
||||||
|
* The process flow for game creation is as follows:
|
||||||
|
* - The first client (TCP/RMI) requests to join the game by providing a username and the desired number of players
|
||||||
|
* - The TCP/RMI server checks {@link #playerList} and, if it is empty, sets the number of players according to the first user's request using {@link LimitedList#setLimit(int)}
|
||||||
|
* - The TCP/RMI server creates the {@link Game} with the requested number of players and adds the player to {@link #playerList}
|
||||||
|
* - Other players request to join the game (their requested number of players is ignored)
|
||||||
|
* - When the number of players in {@link #playerList} reaches the {@link LimitedList}'s limit, the list calls {@link #run()}
|
||||||
|
* - All players are notified of the {@link Game}
|
||||||
|
*
|
||||||
|
* The process flow for game execution is as follows:
|
||||||
|
* - The TCP/RMI server receives a {@link NetworkEvent} from a client and adds it to the {@link #actionQueue}
|
||||||
|
* - The {@link #run()} method repeatedly calls {@link #doFirstEvent()}, which takes the first event in the {@link #actionQueue} and tries to apply it
|
||||||
|
* - If the event cannot be successfully applied to the model, its {@code isError} flag is set to {@code true}
|
||||||
|
* - All players are notified of the event
|
||||||
|
*/
|
||||||
public class ServerLauncher {
|
public class ServerLauncher {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue containing the events to be applied to the game model.
|
||||||
|
* Thread safe by design.
|
||||||
|
*/
|
||||||
BlockingQueue<NetworkEvent> actionQueue;
|
BlockingQueue<NetworkEvent> actionQueue;
|
||||||
|
|
||||||
|
/** Game controller. Used to apply events */
|
||||||
GameController gameController;
|
GameController gameController;
|
||||||
|
|
||||||
|
/** Server RMI. Handles RMI clients */
|
||||||
RMIServer serverRMI;
|
RMIServer serverRMI;
|
||||||
|
|
||||||
|
/** Server TCP. Handles TCP clients */
|
||||||
TCPServer serverTCP;
|
TCPServer serverTCP;
|
||||||
static LimitedList<String> players;
|
|
||||||
|
/**
|
||||||
|
* List containing the usernames of joined players.
|
||||||
|
* {@link LimitedList}'s limit defines at which size the list calls its action
|
||||||
|
* Both the limit and the action can be set using {@link LimitedList#setLimit(int)} and {@link LimitedList#setAction(Runnable)}
|
||||||
|
* The limit is set by the first player joining the game. The action consists in calling {@link #run()}
|
||||||
|
*/
|
||||||
|
static LimitedList<String> playerList;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor that initializes the attributes.
|
||||||
|
* @param actionQueue The queue containing the events
|
||||||
|
* @param gameController The game controller
|
||||||
|
* @param serverRMI The server RMI
|
||||||
|
* @param serverTCP The server TCP
|
||||||
|
*/
|
||||||
public ServerLauncher(BlockingQueue<NetworkEvent> actionQueue, GameController gameController, RMIServer serverRMI, TCPServer serverTCP) {
|
public ServerLauncher(BlockingQueue<NetworkEvent> actionQueue, GameController gameController, RMIServer serverRMI, TCPServer serverTCP) {
|
||||||
this.actionQueue = actionQueue;
|
this.actionQueue = actionQueue;
|
||||||
this.serverRMI = serverRMI;
|
this.serverRMI = serverRMI;
|
||||||
@@ -29,34 +71,44 @@ public class ServerLauncher {
|
|||||||
this.serverTCP = serverTCP;
|
this.serverTCP = serverTCP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean doFirstEven() throws InterruptedException, RemoteException {
|
|
||||||
|
/**
|
||||||
|
* Takes the first event in the actionQueue and attempts to apply it to the game controller.
|
||||||
|
* If the event cannot be applied, its isError flag is set to true; otherwise, it is set to false.
|
||||||
|
* All clients (both TCP and RMI) are notified of the event
|
||||||
|
* @return the outcome of applying the event to the controller
|
||||||
|
* @throws InterruptedException if an error occurs while accessing the actionQueue
|
||||||
|
* @throws RemoteException if an RMI error occurs
|
||||||
|
*/
|
||||||
|
public boolean doFirstEvent() throws InterruptedException, RemoteException {
|
||||||
NetworkEvent event = actionQueue.take();
|
NetworkEvent event = actionQueue.take();
|
||||||
if(event.apply(gameController)) {
|
event.setIsError(!event.apply(gameController));
|
||||||
serverRMI.notifyAll(event);
|
|
||||||
serverTCP.broadcastUpdate(event);
|
serverRMI.notifyAll(event);
|
||||||
return true;
|
serverTCP.notifyAll(event);
|
||||||
} else {
|
|
||||||
serverRMI.notifyError(event.getUsername(), "Mossa non valida"); // TODO Converrebbe mettere in network event un booleano che dice se è stato accettato e fare una notifyAll anche per errori
|
return !event.getIsError();
|
||||||
//serverTCP // TODO non esiste un notify error (guarda sopra)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main() throws RemoteException, InterruptedException {
|
/**
|
||||||
// TODO
|
* The first method executed when the server program is launched.
|
||||||
// Deve avere una coda con gli eventi.
|
* It creates all the objects needed: playerList, actionQueue, gameController, serverRMI, serverTCP, launcher.
|
||||||
// Il server RMI e il server TCP quando ricevono un doEvent devono aggiungere l'evento alla coda condivisa
|
* Then sets the playerList's action to execute launcher.run() and starts the TCP/RMI servers.
|
||||||
// Questa classe esegue gli eventi nella coda e chiama il notify all e notify error sia RMI che TCP
|
* Note: the model is initialized and set in the controller in TCP/RMI servers when the first user decides the number of players.
|
||||||
|
*
|
||||||
players = new LimitedList<>(5, ()->{});
|
* @throws InterruptedException if this exception is issued by run method
|
||||||
|
* @throws RemoteException if this exception is issued by run method
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws InterruptedException, RemoteException {
|
||||||
|
playerList = new LimitedList<>(5, ()->{});
|
||||||
BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>();
|
BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>();
|
||||||
GameController gameController = new GameController();
|
GameController gameController = new GameController();
|
||||||
RMIServer serverRMI = new RMIServer(gameController, 1099, actionQueue, players);
|
RMIServer serverRMI = new RMIServer(gameController, 1099, actionQueue, playerList);
|
||||||
TCPServer serverTCP = new TCPServer(gameController, 8080, actionQueue, players);
|
TCPServer serverTCP = new TCPServer(gameController, 8080, actionQueue, playerList);
|
||||||
ServerLauncher launcher = new ServerLauncher(actionQueue, gameController, serverRMI, serverTCP);
|
ServerLauncher launcher = new ServerLauncher(actionQueue, gameController, serverRMI, serverTCP);
|
||||||
|
|
||||||
players.setAction(()->{
|
playerList.setAction(()->{
|
||||||
try {
|
try {
|
||||||
launcher.run();
|
launcher.run();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -70,15 +122,23 @@ public class ServerLauncher {
|
|||||||
new Thread(()->{serverTCP.start();}).start();
|
new Thread(()->{serverTCP.start();}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and executes the game.
|
||||||
|
* Game creation: TCP/RMI servers send the game model to all players.
|
||||||
|
* Game execution: repeatedly calls doFirstEvent() to process the events in the actionQueue.
|
||||||
|
* @throws InterruptedException if the TCP server thread is interrupted
|
||||||
|
* @throws RemoteException if an RMI error occurs
|
||||||
|
*/
|
||||||
public void run() throws InterruptedException, RemoteException {
|
public void run() throws InterruptedException, RemoteException {
|
||||||
|
// Game creation
|
||||||
serverRMI.notifyAll(gameController.getModel());
|
serverRMI.notifyAll(gameController.getModel());
|
||||||
serverTCP.broadcastModel(gameController.getModel());
|
serverTCP.notifyAll(gameController.getModel());
|
||||||
|
|
||||||
|
|
||||||
|
// Game execution
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
this.doFirstEven();
|
this.doFirstEvent();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user