Merge branch 'main' into javadoc-fixes

This commit is contained in:
rubenpirreram
2026-05-06 17:36:37 +02:00
committed by GitHub
191 changed files with 2398 additions and 367 deletions
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
</profile>
</component>
@@ -0,0 +1,61 @@
package it.polimi.ingsw.gc14;
import it.polimi.ingsw.gc14.Controller.ClientController;
import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient;
import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient;
import it.polimi.ingsw.gc14.View.GUI.GUI;
import it.polimi.ingsw.gc14.View.GUI.LoginView;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
public class ClientLauncherGUI extends Application {
@Override
public void start(Stage stage) {
LoginView loginView = new LoginView();
GUI view = new GUI(stage);
ClientController controller = new ClientController(view);
loginView.getBtnAccedi().setOnAction(e -> {
String nome = loginView.getNome();
int numPlayer = loginView.getNumPlayers();
int networkType = loginView.getNetworkType();
String ip = loginView.getIP();
if (nome.isEmpty() || ip.isEmpty()) {
loginView.setErrore("Compila tutti i campi.");
return;
}
// Connessione in un thread separato — non bloccare il JavaFX thread!
new Thread(() -> {
if (networkType == 0) {
RMIClient client = new RMIClient(controller, ip, 1099);
if (client.connect(nome, numPlayer)) {
controller.setClient(client);
// Da qui in poi il server chiamerà onGameInit → render()
} else {
Platform.runLater(() -> loginView.setErrore("Connessione RMI fallita."));
}
} else {
TCPClient client = new TCPClient(controller, ip, 8080);
if (client.connect(nome, numPlayer)) {
controller.setClient(client);
} else {
Platform.runLater(() -> loginView.setErrore("Connessione TCP fallita."));
}
}
}).start();
});
stage.setTitle("Mesos");
stage.setScene(loginView.getScene());
stage.show();
}
public static void main(String[] args) {
launch();
}
}
@@ -4,6 +4,13 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient;
import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient;
import it.polimi.ingsw.gc14.View.TUI.TUI;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Scanner;
/**
@@ -14,6 +21,8 @@ import java.util.Scanner;
*/
public class ClientLauncherTUI {
List<String> admissibleChar=new ArrayList<>();
/**
* The TUI view associated with this client.
*/
@@ -29,19 +38,44 @@ public class ClientLauncherTUI {
*/
public void main() throws InterruptedException {
view = new TUI(null);
admissibleChar.add("0");
admissibleChar.add("1");
admissibleChar.add("2");
admissibleChar.add("3");
admissibleChar.add("4");
admissibleChar.add("5");
admissibleChar.add("6");
admissibleChar.add("7");
admissibleChar.add("8");
admissibleChar.add("9");
admissibleChar.add("A");
admissibleChar.add("B");
admissibleChar.add("C");
admissibleChar.add("a");
admissibleChar.add("b");
admissibleChar.add("c");
ClientController controller = new ClientController(view);
Scanner scanner = new Scanner(System.in);
System.out.println("Selezionare nome utente: ");
System.out.println("Insert username: ");
String username = scanner.next();
view.setUsername(username);
System.out.println("Selezionare numero di giocatori desiderato: ");
System.out.println("Insert preferred number of players: ");
int proposedNumPlayers = scanner.nextInt();
System.out.println("Selezionare RMI[0] o TCP[1]: ");
System.out.println("Select RMI[0] o TCP[1]: ");
int networkType = scanner.nextInt();
System.out.println("Insert server IP: ");
String IP = scanner.next();
// RMI
if (networkType == 0) {
// Connect
RMIClient client = new RMIClient(controller, "localhost", 1099);
String myIP;
try {
myIP = chooseNetworkInterface(scanner);
} catch (Exception e) {
throw new RuntimeException(e);
}
RMIClient client = new RMIClient(controller, IP, 1099, myIP);
if (client.connect(username, proposedNumPlayers)) {
System.out.println("Succesfully connected to RMI server\n\n");
} else {
@@ -55,7 +89,7 @@ public class ClientLauncherTUI {
// TCP
} else if (networkType == 1) {
// Connect
TCPClient client = new TCPClient(controller, "localhost", 8080);
TCPClient client = new TCPClient(controller, IP, 8080);
if (client.connect(username, proposedNumPlayers)) {
System.out.println("Succesfully connected to TCP server\n\n");
} else {
@@ -101,29 +135,71 @@ public class ClientLauncherTUI {
private void getInput(Scanner scanner, ClientController controller, String username) {
String action = scanner.next();
int pos = -1;
if (!action.equals("7") && !action.equals("8") && !action.equals("9") && !action.equals("A") && !action.equals("B") && !action.equals("C")) {
if(admissibleChar.contains(action))
{
if (!action.equals("7") && !action.equals("8") && !action.equals("9") && !action.equals("A") && !action.equals("B") && !action.equals("C")&&!action.equals("a") && !action.equals("b") && !action.equals("c")) {
try {
System.out.println("Insert the required position:");
pos = scanner.nextInt();
} catch (Exception e) {
System.out.println("ERROR: Invalid input(expected number)");
view.showError("ERROR: Invalid input(expected number)");
return;
}
}
switch (action) {
case "0" -> controller.slotChoice(username, pos);
case "1" -> controller.drawUpperBuildingCard(username, pos);
case "2" -> controller.drawUpperTribeCard(username, pos);
case "3" -> controller.drawLowerBuildingCard(username, pos);
case "4" -> controller.drawLowerTribeCard(username, pos);
case "1" -> controller.drawUpperTribeCard(username, pos);
case "2" -> controller.drawUpperBuildingCard(username, pos);
case "3" -> controller.drawLowerTribeCard(username, pos);
case "4" -> controller.drawLowerBuildingCard(username, pos);
case "5" -> controller.pickOptionalTribeCard(username, pos);
case "6" -> controller.pickOptionalBuildingCard(username, pos);
case "7" -> controller.noOptionalCard(username);
case "8" -> controller.skipUpper(username);
case "9" -> controller.skipLower(username);
case "A" -> view.fullRender();
case "B" -> view.renderBoard();
case "C" -> view.renderPlayer();
case "A", "a" -> view.fullRender();
case "B", "b" -> view.renderBoard();
case "C", "c" -> view.renderPlayer();
default -> {}
}
}
else
{
view.showError("ERROR: Invalid input(action not valid)");
}
}
public static String chooseNetworkInterface(Scanner scanner) throws Exception {
List<String> ips = new ArrayList<>();
// Lista tutte le interfacce attive con IP reale
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
// Salta loopback, interfacce spente o virtuali
if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) continue;
Enumeration<InetAddress> addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
// Solo IPv4
if (addr instanceof Inet4Address) {
System.out.println("[" + ips.size() + "] " + ni.getDisplayName() + " -> " + addr.getHostAddress());
ips.add(addr.getHostAddress());
}
}
}
if (ips.isEmpty()) throw new Exception("Nessuna interfaccia disponibile");
if (ips.size() == 1) {
System.out.println("Una sola interfaccia trovata, uso: " + ips.get(0));
return ips.get(0);
}
System.out.print("Scegli interfaccia: ");
int choice = scanner.nextInt();
return ips.get(choice);
}
}
@@ -1,12 +1,13 @@
package it.polimi.ingsw.gc14.Controller;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Model.Player;
import it.polimi.ingsw.gc14.Network.IClient;
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
import it.polimi.ingsw.gc14.Network.Observer;
import it.polimi.ingsw.gc14.View.IView;
import java.rmi.RemoteException;
import java.util.Objects;
/**
* Controller class that holds all the components of the client, such as view, network client and Game Controller.
* It provides methods to set the client components and to execute requested actions.
@@ -50,7 +51,7 @@ public class ClientController {
*/
public void setModel(Game model) {
localController.setModel(model);
view.update(localController.getModel());
view.setModel(localController.getModel());
}
@@ -70,7 +71,19 @@ public class ClientController {
* @param pos the index of the card to draw
*/
public void drawUpperTribeCard(String playerUsername, int pos) {
client.doEvent(new DrawUpperTribeCard(playerUsername,pos));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
{
view.showError("It's not your turn!");
}
else
{
try {
client.drawUpperTribeCard(playerUsername, pos);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
@@ -81,7 +94,14 @@ public class ClientController {
* @param pos the index of the card to draw
*/
public void drawLowerTribeCard(String playerUsername,int pos) {
client.doEvent(new DrawLowerTribeCard(playerUsername,pos));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else
try {
client.drawLowerTribeCard(playerUsername, pos);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
@@ -92,7 +112,16 @@ public class ClientController {
* @param pos the index of the card to draw
*/
public void drawUpperBuildingCard(String playerUsername,int pos) {
client.doEvent(new DrawUpperBuildingCard(playerUsername,pos));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.drawUpperBuildingCard(playerUsername,pos);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
@@ -103,7 +132,15 @@ public class ClientController {
* @param pos the index of the card to draw
*/
public void drawLowerBuildingCard(String playerUsername,int pos) {
client.doEvent(new DrawLowerBuildingCard(playerUsername,pos));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.drawLowerBuildingCard(playerUsername,pos);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
@@ -113,7 +150,15 @@ public class ClientController {
* @param playerUsername the name of the player performing the action
*/
public void skipUpper(String playerUsername) {
client.doEvent(new SkipUpper(playerUsername));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.skipUpper(playerUsername);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
@@ -122,7 +167,17 @@ public class ClientController {
* This action is available only when the lower list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipLower(String playerUsername) { client.doEvent(new SkipLower(playerUsername));}
public void skipLower(String playerUsername) {
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.skipLower(playerUsername);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
/**
@@ -132,7 +187,15 @@ public class ClientController {
* @param pos the index of the card to draw
*/
public void pickOptionalTribeCard(String playerUsername,int pos) {
client.doEvent(new PickOptionalTribeCard(playerUsername,pos));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.pickOptionalTribeCard(playerUsername,pos);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
@@ -143,7 +206,15 @@ public class ClientController {
* @param pos the index of the card to draw
*/
public void pickOptionalBuildingCard(String playerUsername,int pos) {
client.doEvent(new PickOptionalBuildingCard(playerUsername,pos));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.pickOptionalBuildingCard(playerUsername,pos);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
@@ -153,7 +224,15 @@ public class ClientController {
* @param playerUsername the name of the player performing the action
*/
public void noOptionalCard(String playerUsername) {
client.doEvent(new NoOptionalCard(playerUsername));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.noOptionalCard(playerUsername);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
@@ -163,7 +242,15 @@ public class ClientController {
* @param pos the index of the selected slot
*/
public void slotChoice(String playerUsername,int pos) {
client.doEvent(new SlotChoice(playerUsername,pos));
if(!Objects.equals(playerUsername, localController.getModel().getCurrentState().getCurrentPlayer().getUserName()))
view.showError("It's not your turn!");
else {
try {
client.slotChoice(playerUsername,pos);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -42,7 +42,7 @@ public class Building8 extends BuildingCard {
if(!player.buildingCards.contains(this))
throw new IllegalArgumentException();
for (Builder builder : player.builders) {
player.addPrestige(builder.getPrestigeValue() * 2);
player.addPrestige(builder.getPrestigeValue());
}
}
@@ -167,8 +167,16 @@ public class BuildingCard extends PlayableCard implements Cloneable , BuildingEf
* @return {@code true} if the building card is successfully bought,
* {@code false} otherwise.
*/
// sum reduction value builder=> sconto
public boolean buy(Player player) {
if( bought || !player.removeFood(getPrice()))
int discount = 0;
discount = player.builders.stream().mapToInt(x -> x.getReductionValue()).sum();
if(discount > this.price){
discount = this.price;
}
if(bought || !player.removeFood(this.price - discount))
return false;
player.buildingCards.add(this);
bought=true;
@@ -91,7 +91,6 @@ public class CavePaintings extends EventCard {
return new CavePaintings(getEra(), NLower, NPrestigeRem, NPrestigeMul) ;
}
/**
* Prints a string representation of this {@code TribeCard}. This specific variation is used in the {@code Game}'s
* toString to print a more detailed version.
@@ -111,6 +110,6 @@ public class CavePaintings extends EventCard {
*/
@Override
public String toStringBoard() {
return super.toString()+" 0-"+(NLower-1)+":"+NPrestigeRem+" "+NLower+"+:"+NPrestigeMul;
return super.toStringBoard()+" 0-"+(NLower-1)+":"+NPrestigeRem+" "+NLower+"+:"+NPrestigeMul;
}
}
@@ -84,7 +84,7 @@ public class Hunt extends EventCard {
*/
@Override
public String toStringBoard() {
return super.toString()+" 1F+"+prestigeMultiplier+"PP"+" X N Hunter";
return super.toStringBoard()+" 1F+"+prestigeMultiplier+"PP"+" X N Hunter";
}
}
@@ -111,7 +111,7 @@ public class ShamanicRitual extends EventCard {
*/
@Override
public String toStringBoard() {
return super.toString()+" *>:"+prestigeToAdd+" *<:"+prestigeToRemove;
return super.toStringBoard()+" *>:"+prestigeToAdd+" *<:"+prestigeToRemove;
}
}
@@ -48,7 +48,7 @@ public class Sustenance extends EventCard {
* If the resulting Food debt is positive, the player must pay it with available Food.
* If the player does not have enough Food, all remaining Food is removed and the player
* loses Prestige equal to the unpaid Food debt multiplied by {@code PrestigeDebt}.
* This event is intended to be executed last among event effects.
* <b>This event is intended to be executed last among event effects.</b>
*
* @param playerList the list of players affected by the event.
* @throws NullPointerException if {@code playerList} or one of its required elements is {@code null}.
@@ -108,6 +108,6 @@ public class Sustenance extends EventCard {
*/
@Override
public String toStringBoard() {
return super.toString()+" -1F/-"+PrestigeDebt+"PP";
return super.toStringBoard()+" -1F/-"+PrestigeDebt+"PP";
}
}
@@ -4,6 +4,9 @@ import it.polimi.ingsw.gc14.Model.Cards.Building.EffectType;
import it.polimi.ingsw.gc14.Model.Cards.BuildingCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.CharacterType;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Builder;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Inventor;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.EventCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.EventType;
import it.polimi.ingsw.gc14.Model.GamePackage.Board;
@@ -17,7 +20,8 @@ import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import it.polimi.ingsw.gc14.Network.Observer;
import java.util.stream.Stream;
import it.polimi.ingsw.gc14.View.TUI.AsciiTable;
import it.polimi.ingsw.gc14.View.TUI.BorderStyle;
@@ -28,26 +32,6 @@ import it.polimi.ingsw.gc14.View.TUI.BorderStyle;
*/
public class Game implements Serializable {
/**
* List of observers registered to receive updates when the game state changes.
*
* <p>The list is marked as {@code transient} because observers should not be
* serialized with the game model.
*/
private transient List<Observer> observers = new ArrayList<>(); // transient! non serializzare
public void addObserver(Observer observer) {
observers.add(observer);
}
private void notifyObservers() {
for (Observer o : observers) {
o.update(this);
}
}
/**
* Returns the list of players participating in the game.
*
@@ -250,6 +234,16 @@ public class Game implements Serializable {
orderLogicCard=new Order5(playersList);
break;
}
for(Player player : playersList)
{
switch(orderLogicCard.getPosition(player.getUserName()))
{
case 0: player.addFood(2); break;
case 1,2: player.addFood(3); break;
case 3,4: player.addFood(4); break;
}
}
currentState.PlayerUpdate(orderLogicCard.pull(),null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
}
@@ -282,6 +276,10 @@ public class Game implements Serializable {
{
return false;
}
if(slotPlayerEntry.getKey().getSlotId()=='A')
{
player.addFood(3);
}
slotMap.put(slotPlayerEntry.getKey(),player);
nextPlayerSetup();
return true;
@@ -306,7 +304,7 @@ public class Game implements Serializable {
public boolean DrawUpperTribeCardByIndex(Player player,int cardIndex) {
if( cardIndex<0 || cardIndex >=board.upperListTribe.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -342,7 +340,7 @@ public class Game implements Serializable {
* @return {@code true} if the skip succeeds, {@code false} otherwise.
*/
public boolean SkipUpperDrawing(Player player) {
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -373,7 +371,7 @@ public class Game implements Serializable {
* @return {@code true} if the skip succeeds, {@code false} otherwise.
*/
public boolean SkipLowerDrawing(Player player) {
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -407,7 +405,7 @@ public class Game implements Serializable {
public boolean DrawLowerTribeCardByIndex(Player player, int cardIndex) {
if( cardIndex<0 || cardIndex >=board.lowerListTribe.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -448,7 +446,7 @@ public class Game implements Serializable {
public boolean DrawUpperBuildingCardByIndex(Player player,int cardIndex) {
if( cardIndex<0 || cardIndex >=board.upperListBuilding.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -487,7 +485,7 @@ public class Game implements Serializable {
public boolean DrawLowerBuildingCardByIndex(Player player,int cardIndex) {
if( cardIndex<0 || cardIndex >=board.lowerListBuilding.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -532,7 +530,7 @@ public class Game implements Serializable {
* @return {@code true} if the operation succeeds, {@code false} otherwise.
*/
public boolean PickOptionalTribeCardByIndex(Player player,int cardIndex) {
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
if(currentState.getGameStage() != GameStages.OPT_CARD_E){
return false;
}
if(!player.equals(currentState.getCurrentPlayer())){
@@ -567,7 +565,7 @@ public class Game implements Serializable {
* @return {@code true} if the operation succeeds, {@code false} otherwise.
*/
public boolean PickOptionalBuildingCard(Player player, int cardIndex) {
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
if(currentState.getGameStage() != GameStages.OPT_CARD_E){
return false;
}
if(!player.equals(currentState.getCurrentPlayer())){
@@ -599,7 +597,7 @@ public class Game implements Serializable {
* @return {@code true} if the operation succeeds, {@code false} otherwise.
*/
public boolean NoOptionalCard(Player player) {
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
if(currentState.getGameStage() != GameStages.OPT_CARD_E){
return false;
}
if(!player.equals(currentState.getCurrentPlayer())){
@@ -638,7 +636,7 @@ public class Game implements Serializable {
currentState.PlayerUpdate(tempPlayer, null);
return;
}
currentState.GameStageUpdate(GameStages.RESOLVING_ACTIONS);
currentState.GameStageUpdate(GameStages.RES_ACTIONS);
for (Slot s : slotMap.keySet()) {
if (slotMap.get(s) != null) {
currentState.PlayerUpdate(slotMap.get(s), s);
@@ -654,7 +652,7 @@ public class Game implements Serializable {
return;
}
if(GameStages.RESOLVING_ACTIONS==currentState.getGameStage()) {
if(GameStages.RES_ACTIONS ==currentState.getGameStage()) {
orderLogicCard.push(currentState.getCurrentPlayer());
slotMap.put(currentState.getSlot(), null);
for (Slot s : slotMap.keySet()) {
@@ -673,9 +671,9 @@ public class Game implements Serializable {
}
if(slotMap.values().stream().allMatch(v -> v == null))
{
currentState.GameStageUpdate(GameStages.OPTIONAL_CARD_EFFECT);
currentState.GameStageUpdate(GameStages.OPT_CARD_E);
HashMap<Player,Integer> optional=new LinkedHashMap<>();
for (Player p : playersList) {
for (Player p : orderLogicCard.players) {
int tempCount=(int)p.buildingCards.stream().filter(x->x.getEffectId()==12).count();
if(tempCount>0)
{
@@ -694,14 +692,13 @@ public class Game implements Serializable {
return;
}
currentState.GameStageUpdate(GameStages.RESOLVING_EVENT);
currentState.GameStageUpdate(GameStages.RES_EVENT);
if (currentState.getRound() < 10) {
nextRound();
currentState.PlayerUpdate(orderLogicCard.pull(), null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
} else {
EventResolution();
currentState.GameStageUpdate(GameStages.ENDING);
endGame();
}
@@ -710,7 +707,7 @@ public class Game implements Serializable {
}
}
if (GameStages.OPTIONAL_CARD_EFFECT == currentState.getGameStage()) {
if (GameStages.OPT_CARD_E == currentState.getGameStage()) {
Player optionalPlayer = OptionalCardQueue.poll();
if (optionalPlayer != null) {
@@ -718,14 +715,13 @@ public class Game implements Serializable {
return;
}
currentState.GameStageUpdate(GameStages.RESOLVING_EVENT);
currentState.GameStageUpdate(GameStages.RES_EVENT);
if (currentState.getRound() < 10) {
nextRound();
currentState.PlayerUpdate(orderLogicCard.pull(), null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
} else {
EventResolution();
currentState.GameStageUpdate(GameStages.ENDING);
endGame();
}
@@ -768,7 +764,7 @@ public class Game implements Serializable {
*/
private void EventResolution() {
if(currentState.getGameStage()!= GameStages.RESOLVING_EVENT)
if(currentState.getGameStage()!= GameStages.RES_EVENT)
{
return;
}
@@ -818,6 +814,28 @@ public class Game implements Serializable {
* and updating the game stage to {@code ENDED}.
*/
private void endGame() {
Queue<EventCard> events;
events=Stream.concat(board.lowerListTribe.stream().filter(TribeCard::IsEventCard),board.upperListTribe.stream().filter(TribeCard::IsEventCard)).map(x->((EventCard)x)).collect(Collectors.toCollection(LinkedList::new));
ArrayList<EventCard>sustenance=events.stream().filter(x->x.getType().equals(EventType.SUSTENANCE)).collect(Collectors.toCollection(ArrayList::new));
events.removeAll(sustenance);
events.forEach(event->event.activateEvent(playersList));
sustenance.forEach(event->event.activateEvent(playersList));
playersList.forEach(p->{
int temp= p.builders.stream().mapToInt(Builder::getPrestigeValue).sum();
p.addPrestige(temp);
});
playersList.forEach(p->{
int temp=(int) p.inventors.stream().mapToInt(Inventor::Icon).distinct().count();
p.addPrestige(temp*p.getNType(CharacterType.INVENTOR));
});
playersList.forEach(p->{
p.addPrestige(10 * (p.getNType(CharacterType.ARTIST)/2));
});
playersList.forEach(p->{
int temp= p.buildingCards.stream().mapToInt(BuildingCard::getPrestigeValue).sum();
p.addPrestige(temp);
});
playersList.forEach(
p -> p.buildingCards.stream().filter(x -> x.getEffectType() == EffectType.FINAL).
forEach(x -> x.applyEffect(p))
@@ -41,6 +41,8 @@ public class Board implements Serializable {
/** Contains all the building cards of the upper list. When a new era starts, the old era's buildings are moved from the upper to the lower list */
public List<BuildingCard> lowerListBuilding;
private final ArrayList<List<BuildingCard>> buildingCardsAllEras;
/** Number of players */
private int nTotem;
@@ -88,6 +90,7 @@ public class Board implements Serializable {
tribeDeck=generateTribeDeck(nTotem);
era=1;
for(int i=0;i<nTotem+1;i++)
{
TribeCard tempCard = tribeDeck.remove();
@@ -110,12 +113,46 @@ public class Board implements Serializable {
ArrayList<BuildingCard> buildingDeck = new ArrayList<>(DecksCreator.loadBuildingDeckByEra(1));
Collections.shuffle(buildingDeck);
buildingCardsAllEras= new ArrayList<>();
buildingCardsAllEras.add(new ArrayList<>());
buildingCardsAllEras.add(new ArrayList<>());
buildingCardsAllEras.add(new ArrayList<>());
if(nTotem==2)
{
buildingCardsAllEras.set(0, new ArrayList<>(buildingDeck.subList(0, 1)));
upperListBuilding = new ArrayList<>(buildingDeck.subList(0,1));
}
else
{
buildingCardsAllEras.set(0, new ArrayList<>(buildingDeck.subList(0, 2)));
upperListBuilding = new ArrayList<>(buildingDeck.subList(0,2));
}
buildingDeck=new ArrayList<>(DecksCreator.loadBuildingDeckByEra(2));
Collections.shuffle(buildingDeck);
if(nTotem<=3)
{
buildingCardsAllEras.set(1, new ArrayList<BuildingCard>(buildingDeck.subList(0, 2)));
}
else
{
buildingCardsAllEras.set(1, new ArrayList<BuildingCard>(buildingDeck.subList(0, 3)));
}
buildingDeck=new ArrayList<>(DecksCreator.loadBuildingDeckByEra(3));
Collections.shuffle(buildingDeck);
if(nTotem==2)
{
buildingCardsAllEras.set(2, new ArrayList<BuildingCard>(buildingDeck.subList(0, 3)));
}else if(nTotem==5)
{
buildingCardsAllEras.set(2, new ArrayList<BuildingCard>(buildingDeck.subList(0, 5)));
}
else {
buildingCardsAllEras.set(2, new ArrayList<BuildingCard>(buildingDeck.subList(0, 4)));
}
}
/**
* Creates the tribeDeck. Loads the cards from each era, shuffle them, and then combine them in the final deck.
* In the end, two special events (Sustenance and ShamanicRitual) are added.
@@ -231,27 +268,11 @@ public class Board implements Serializable {
Collections.shuffle(buildingCards);
if(era==2)
{
if(nTotem<=3)
{
upperListBuilding.addAll(buildingCards.subList(0,2));
upperListBuilding.addAll(buildingCardsAllEras.get(1));
}
else
{
upperListBuilding.addAll( buildingCards.subList(0,3));
}
}
else // Era 3
{
if(nTotem==2)
{
upperListBuilding.addAll( buildingCards.subList(0,3));
}else if(nTotem==5)
{
upperListBuilding.addAll( buildingCards.subList(0,5));
}
else {
upperListBuilding.addAll(buildingCards.subList(0,4));
}
upperListBuilding.addAll(buildingCardsAllEras.get(2));
}
}
}
@@ -6,5 +6,5 @@ package it.polimi.ingsw.gc14.Model.GamePackage;
* Represents the possible stages of a game.
*/
public enum GameStages {
WAITING, SLOT_CHOICE, RESOLVING_ACTIONS, OPTIONAL_CARD_EFFECT, RESOLVING_EVENT, ENDING, ENDED
WAITING, SLOT_CHOICE, RES_ACTIONS, OPT_CARD_E, RES_EVENT, ENDING, ENDED
}
@@ -1,8 +1,33 @@
package it.polimi.ingsw.gc14.Network;
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
import java.rmi.RemoteException;
import java.util.Objects;
public interface IClient {
public boolean connect(String username,int preferredInt);
public void doEvent(NetworkEvent event) ;
public void drawUpperTribeCard(String playerUsername, int pos) throws RemoteException;
public void drawLowerTribeCard(String playerUsername,int pos) throws RemoteException;
public void drawUpperBuildingCard(String playerUsername,int pos) throws RemoteException;
public void drawLowerBuildingCard(String playerUsername,int pos) throws RemoteException;
public void skipUpper(String playerUsername) throws RemoteException;
public void skipLower(String playerUsername) throws RemoteException;
public void pickOptionalTribeCard(String playerUsername,int pos) throws RemoteException;
public void pickOptionalBuildingCard(String playerUsername,int pos) throws RemoteException;
public void noOptionalCard(String playerUsername) throws RemoteException;
public void slotChoice(String playerUsername,int pos) throws RemoteException;
}
@@ -1,7 +0,0 @@
package it.polimi.ingsw.gc14.Network;
import it.polimi.ingsw.gc14.Model.Game;
public interface Observer {
public void update(Game model);
}
@@ -53,7 +53,7 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa
@Override
public void onAction(NetworkEvent event) throws RemoteException {
if(event.getIsError()) {
System.out.println(event.toString());
clientController.view.showError(event.toString());
} else {
event.apply(clientController.localController);
clientController.view.render();
@@ -1,11 +1,14 @@
package it.polimi.ingsw.gc14.Network.RMI.Client;
import java.net.InetAddress;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Objects;
import it.polimi.ingsw.gc14.Controller.ClientController;
import it.polimi.ingsw.gc14.Network.IClient;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
import it.polimi.ingsw.gc14.Network.RMI.Common.IGameServer;
import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer;
@@ -27,6 +30,7 @@ public class RMIClient implements IClient {
/** Client game's controller */
ClientController controller;
private String myIP;
/**
* Class constructor.
@@ -34,10 +38,11 @@ public class RMIClient implements IClient {
* @param host the host address of the RMI server
* @param port the port of the RMI server
*/
public RMIClient(ClientController controller, String host, int port) {
public RMIClient(ClientController controller, String host, int port, String myIP) {
this.controller=controller;
this.host = host;
this.port = port;
this.myIP = myIP;
}
@@ -51,6 +56,7 @@ public class RMIClient implements IClient {
*/
public boolean connect(String username,int preferredInt) {
try {
System.setProperty("java.rmi.server.hostname", this.myIP);
Registry registry = LocateRegistry.getRegistry(host, port);
this.stub = (IGameServer) registry.lookup("RMIGameServer");
ClientCallbackImpl callback = new ClientCallbackImpl(controller);
@@ -64,17 +70,111 @@ public class RMIClient implements IClient {
}
/**
* Sends a {@link NetworkEvent} to the server.
* @param event the event to send
* @throws RemoteException if any RMI error occurs
* Requests to draw a tribe card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void doEvent(NetworkEvent event) {
try {
stub.doEvent(event);
}catch (Exception e) {
}
public void drawUpperTribeCard(String playerUsername, int pos) throws RemoteException {
stub.drawUpperTribeCard(playerUsername,pos);
}
/**
* Requests to draw a tribe card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerTribeCard(String playerUsername,int pos) throws RemoteException {
stub.drawLowerTribeCard(playerUsername,pos);
}
/**
* Requests to draw a building card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawUpperBuildingCard(String playerUsername,int pos) throws RemoteException {
stub.drawUpperBuildingCard(playerUsername,pos);
}
/**
* Requests to draw a building card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerBuildingCard(String playerUsername,int pos) throws RemoteException {
stub.drawLowerBuildingCard(playerUsername,pos);
}
/**
* Requests to skip drawing from the upper list.
* This action is available only when the upper list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipUpper(String playerUsername) throws RemoteException {
stub.skipUpper(playerUsername);
}
/**
* Requests to skip drawing from the lower list.
* This action is available only when the lower list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipLower(String playerUsername) throws RemoteException {
stub.skipLower(playerUsername);
}
/**
* Used to draw a tribe card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalTribeCard(String playerUsername,int pos) throws RemoteException {
stub.pickOptionalTribeCard(playerUsername,pos);
}
/**
* Used to draw a building card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalBuildingCard(String playerUsername,int pos) throws RemoteException {
stub.pickOptionalBuildingCard(playerUsername,pos);
}
/**
* Used to skip the action of drawing a card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
*/
public void noOptionalCard(String playerUsername) throws RemoteException {
stub.noOptionalCard(playerUsername);
}
/**
* Used to perform the slot choice action for the specified player at the specified position.
* @param playerUsername the name of the player performing the action
* @param pos the index of the selected slot
*/
public void slotChoice(String playerUsername,int pos) throws RemoteException {
stub.slotChoice(playerUsername,pos);
}
}
@@ -30,5 +30,27 @@ public interface IGameServer extends Remote {
* @throws RemoteException if an RMI communication error occurs.
*/
boolean doEvent(NetworkEvent event) throws RemoteException;
void drawUpperTribeCard(String playerUsername, int pos) throws RemoteException;
void drawLowerTribeCard(String playerUsername,int pos) throws RemoteException;
void drawUpperBuildingCard(String playerUsername,int pos) throws RemoteException;
void drawLowerBuildingCard(String playerUsername,int pos) throws RemoteException;
void skipUpper(String playerUsername) throws RemoteException;
void skipLower(String playerUsername) throws RemoteException;
void pickOptionalTribeCard(String playerUsername,int pos) throws RemoteException;
void pickOptionalBuildingCard(String playerUsername,int pos) throws RemoteException;
void noOptionalCard(String playerUsername) throws RemoteException;
void slotChoice(String playerUsername,int pos) throws RemoteException;
}
@@ -4,14 +4,18 @@ import it.polimi.ingsw.gc14.Controller.GameController;
import it.polimi.ingsw.gc14.LimitedList;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
import it.polimi.ingsw.gc14.Network.RMI.Common.IGameServer;
import java.net.InetAddress;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
@@ -22,7 +26,7 @@ import java.rmi.*;
* Server RMI. Exposes a method to join the game and one to execute an event.
*/
public class RMIServer extends UnicastRemoteObject implements IGameServer {
private String host;
/** Server game's controller */
private GameController controller;
@@ -56,11 +60,12 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
* @param playerList The player's usernames list
* @throws RemoteException if an RMI error occurs
*/
public RMIServer(GameController controller, int nPort, BlockingQueue<NetworkEvent> actionQueue,LimitedList<String> playerList) throws RemoteException {
public RMIServer(GameController controller, int nPort, BlockingQueue<NetworkEvent> actionQueue,LimitedList<String> playerList,String host) throws RemoteException {
this.controller = controller;
this.nPort = nPort;
this.actionQueue = actionQueue;
this.playerList = playerList;
this.host = host;
}
@@ -76,7 +81,6 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
* @param callback The client's callback interface
* @return true if the player successfully joined the game, false otherwise
*/
@Override
public boolean joinGame(String username, int preferredInt, IClientCallback callback) {
if (preferredInt<2 || preferredInt>5) {
return false;
@@ -90,6 +94,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
if (controller.addPlayer(username)) {
clients.put(username, callback);
playerList.add(username);
System.out.println("Accepted player: " + username);
return true;
}
return false;
@@ -103,11 +108,114 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
* @param action The desired actio
* @return true if the action was successfully added, false otherwise
*/
@Override
public boolean doEvent(NetworkEvent action) {
return actionQueue.offer(action);
}
/**
* Requests to draw a tribe card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawUpperTribeCard(String playerUsername, int pos) {
actionQueue.offer(new DrawUpperTribeCard(playerUsername,pos));
}
/**
* Requests to draw a tribe card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerTribeCard(String playerUsername,int pos) {
actionQueue.offer(new DrawLowerTribeCard(playerUsername,pos));
}
/**
* Requests to draw a building card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawUpperBuildingCard(String playerUsername,int pos) {
actionQueue.offer(new DrawUpperBuildingCard(playerUsername,pos));
}
/**
* Requests to draw a building card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerBuildingCard(String playerUsername,int pos) {
actionQueue.offer(new DrawLowerBuildingCard(playerUsername,pos));
}
/**
* Requests to skip drawing from the upper list.
* This action is available only when the upper list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipUpper(String playerUsername) {
actionQueue.offer(new SkipUpper(playerUsername));
}
/**
* Requests to skip drawing from the lower list.
* This action is available only when the lower list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipLower(String playerUsername) {
actionQueue.offer(new SkipLower(playerUsername));
}
/**
* Used to draw a tribe card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalTribeCard(String playerUsername,int pos) {
actionQueue.offer(new PickOptionalTribeCard(playerUsername,pos));
}
/**
* Used to draw a building card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalBuildingCard(String playerUsername,int pos) {
actionQueue.offer(new PickOptionalBuildingCard(playerUsername,pos));
}
/**
* Used to skip the action of drawing a card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
*/
public void noOptionalCard(String playerUsername) {
actionQueue.offer(new NoOptionalCard(playerUsername));
}
/**
* Used to perform the slot choice action for the specified player at the specified position.
* @param playerUsername the name of the player performing the action
* @param pos the index of the selected slot
*/
public void slotChoice(String playerUsername,int pos) {
actionQueue.offer(new SlotChoice(playerUsername,pos));
}
// RMI's internal methods
@@ -116,8 +224,9 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
* @param action The desired action
*/
public void notifyAll(NetworkEvent action) throws RemoteException {
for (IClientCallback cb : clients.values()) {
cb.onAction(action);
for (Map.Entry<String,IClientCallback> entry : clients.entrySet()) {
if(!action.getIsError() ||(action.getIsError()&& action.getUsername().equals(entry.getKey())))
entry.getValue().onAction(action);
}
}
@@ -141,6 +250,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
*/
public boolean start() {
try {
System.setProperty("java.rmi.server.hostname", host); // o il tuo IP/hostname
registry = LocateRegistry.createRegistry(nPort);
registry.rebind("RMIGameServer", this);
System.out.println("RMI Server started on port: "+nPort);
@@ -4,7 +4,7 @@ import it.polimi.ingsw.gc14.Controller.ClientController;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Network.IClient;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
import java.io.*;
import java.net.*;
@@ -87,10 +87,17 @@ public class TCPClient implements IClient {
private void receiveMessage() {
while (true) {
try {
Object read = socketReceive.readObject();
Object read;
try {
read = socketReceive.readObject();
} catch (IOException e) {
e.printStackTrace();
break;
}
if (read instanceof NetworkEvent event) { //TODO: avoid instanceof
if (event.getIsError()) {
System.out.println(event);
controller.view.showError(event.toString());
} else {
event.apply(controller.localController);
controller.view.render();
@@ -99,20 +106,124 @@ public class TCPClient implements IClient {
controller.setModel(model);
controller.view.render();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
e.printStackTrace();
break;
}
}
}
/**
* Requests to draw a tribe card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawUpperTribeCard(String playerUsername, int pos) {
doEvent(new DrawUpperTribeCard(playerUsername,pos));
}
/**
* Requests to draw a tribe card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerTribeCard(String playerUsername,int pos) {
doEvent(new DrawLowerTribeCard(playerUsername,pos));
}
/**
* Requests to draw a building card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawUpperBuildingCard(String playerUsername,int pos) {
doEvent(new DrawUpperBuildingCard(playerUsername,pos));
}
/**
* Requests to draw a building card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerBuildingCard(String playerUsername,int pos) {
doEvent(new DrawLowerBuildingCard(playerUsername,pos));
}
/**
* Requests to skip drawing from the upper list.
* This action is available only when the upper list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipUpper(String playerUsername) {
doEvent(new SkipUpper(playerUsername));
}
/**
* Requests to skip drawing from the lower list.
* This action is available only when the lower list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipLower(String playerUsername) {
doEvent(new SkipLower(playerUsername));
}
/**
* Used to draw a tribe card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalTribeCard(String playerUsername,int pos) {
doEvent(new PickOptionalTribeCard(playerUsername,pos));
}
/**
* Used to draw a building card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalBuildingCard(String playerUsername,int pos) {
doEvent(new PickOptionalBuildingCard(playerUsername,pos));
}
/**
* Used to skip the action of drawing a card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
*/
public void noOptionalCard(String playerUsername) {
doEvent(new NoOptionalCard(playerUsername));
}
/**
* Used to perform the slot choice action for the specified player at the specified position.
* @param playerUsername the name of the player performing the action
* @param pos the index of the selected slot
*/
public void slotChoice(String playerUsername,int pos) {
doEvent(new SlotChoice(playerUsername,pos));
}
/**
* Sends a {@link NetworkEvent} to the server.
* @param event The NetworkEvent to send.
*/
public void doEvent(NetworkEvent event) {
private void doEvent(NetworkEvent event) {
try {
socketSend.writeObject(event);
} catch (IOException e) {
@@ -15,7 +15,13 @@ import java.util.concurrent.BlockingQueue;
* It is also responsible to send events and game model updates back to the client.
*/
public class ClientHandler implements Runnable {
/**
* The username of the connected client on this handler
*/
private final String username;
public String getUsername() {
return username;
}
/** The TCP socket */
private Socket clientSocket;
@@ -44,7 +50,8 @@ public class ClientHandler implements Runnable {
* @param clientHandlers the shared list of all active client handlers.
* @param actionQueue the queue containing incoming events.
*/
public ClientHandler(Socket clientSocket, ObjectOutputStream out, ObjectInputStream in, List<ClientHandler> clientHandlers, BlockingQueue<NetworkEvent> actionQueue) {
public ClientHandler(String username, Socket clientSocket, ObjectOutputStream out, ObjectInputStream in, List<ClientHandler> clientHandlers, BlockingQueue<NetworkEvent> actionQueue) {
this.username=username;
this.clientSocket = clientSocket;
this.in = in;
this.out = out;
@@ -115,7 +115,7 @@ public class TCPServer {
clientSocket.getOutputStream().write((int) (1));
System.out.println("Accepted player: " + eventAddPlayer.getUsername());
ClientHandler clientHandler = new ClientHandler(clientSocket, clientSend, clientReceive, clientHandlers, actionQueue);
ClientHandler clientHandler = new ClientHandler(eventAddPlayer.getUsername(),clientSocket, clientSend, clientReceive, clientHandlers, actionQueue);
clientHandlers.add(clientHandler);
ConnectedPlayers++;
@@ -145,7 +145,10 @@ public class TCPServer {
* @param event the network event to send to all connected TCP clients.
*/
public void notifyAll(NetworkEvent event){
clientHandlers.forEach((x) -> x.notifyEvent(event));
clientHandlers.forEach((x) -> {
if(!event.getIsError()||(event.getIsError()&& event.getUsername().equals(x.getUsername())))
x.notifyEvent(event);
});
}
@@ -7,10 +7,13 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer;
import it.polimi.ingsw.gc14.Network.TCP.Server.TCPServer;
import it.polimi.ingsw.gc14.View.TUI.TUI;
import java.rmi.RemoteException;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.net.*;
/**
@@ -56,6 +59,8 @@ public class ServerLauncher {
*/
static LimitedList<String> playerList;
TUI view;
/**
* Class constructor that initializes the attributes.
@@ -104,7 +109,14 @@ public class ServerLauncher {
playerList = new LimitedList<>(5, ()->{});
BlockingQueue<NetworkEvent> actionQueue = new LinkedBlockingQueue<>();
GameController gameController = new GameController();
RMIServer serverRMI = new RMIServer(gameController, 1099, actionQueue, playerList);
String IP;
try {
IP=chooseNetworkInterface(new Scanner(System.in));
} catch (Exception e) {
throw new RuntimeException(e);
}
RMIServer serverRMI = new RMIServer(gameController, 1099, actionQueue, playerList,IP);
TCPServer serverTCP = new TCPServer(gameController, 8080, actionQueue, playerList);
ServerLauncher launcher = new ServerLauncher(actionQueue, gameController, serverRMI, serverTCP);
@@ -137,11 +149,14 @@ public class ServerLauncher {
System.out.println("\n\nNotifying model");
serverRMI.notifyAll(gameController.getModel());
serverTCP.notifyAll(gameController.getModel());
this.view = new TUI(gameController.getModel());
this.view.fullRender();
// Game execution
while (true) {
try {
this.doFirstEvent();
this.view.fullRender();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
@@ -150,4 +165,36 @@ public class ServerLauncher {
}
}
}
public static String chooseNetworkInterface(Scanner scanner) throws Exception {
List<String> ips = new ArrayList<>();
// Lista tutte le interfacce attive con IP reale
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
// Salta loopback, interfacce spente o virtuali
if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) continue;
Enumeration<InetAddress> addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
// Solo IPv4
if (addr instanceof Inet4Address) {
System.out.println("[" + ips.size() + "] " + ni.getDisplayName() + " -> " + addr.getHostAddress());
ips.add(addr.getHostAddress());
}
}
}
if (ips.isEmpty()) throw new Exception("Nessuna interfaccia disponibile");
if (ips.size() == 1) {
System.out.println("Una sola interfaccia trovata, uso: " + ips.get(0));
return ips.get(0);
}
System.out.print("Scegli interfaccia: ");
int choice = Integer.parseInt(scanner.nextLine().trim());
return ips.get(choice);
}
}
@@ -0,0 +1,55 @@
package it.polimi.ingsw.gc14.View.GUI;
import it.polimi.ingsw.gc14.Controller.ClientController;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.View.GUI.MainView;
import it.polimi.ingsw.gc14.View.IView;
import javafx.application.Platform;
import javafx.stage.Stage;
public class GUI implements IView { // stessa interfaccia che implementa TUI
private final Stage stage;
private final MainView mainView = new MainView();
private Game model;
private String username;
public GUI(Stage stage) {
this.stage = stage;
}
@Override
public void setModel(Game model) {
this.model = model;
mainView.setModel(model);
}
/**
* Chiamato da onGameInit e onAction sempre da thread RMI/TCP.
* Platform.runLater garantisce che la UI venga aggiornata sul JavaFX thread.
*/
@Override
public void render() {
Platform.runLater(() -> {
mainView.render();
stage.setScene(mainView.getScene());
});
}
@Override
public void showMessage(String message) {
}
@Override
public void showError(String message) {
}
public void setUsername(String username) {
this.username=username;
}
// Getter per il launcher
public Stage getStage() { return stage; }
}
@@ -0,0 +1,44 @@
package it.polimi.ingsw.gc14.View.GUI;
import javafx.fxml.FXML;
import javafx.scene.control.*;
public class LoginFXMLController {
@FXML private TextField campoNome;
@FXML private TextField campoNumPlayers;
@FXML private TextField campoIP;
@FXML private RadioButton btnRMI;
@FXML private RadioButton btnTCP;
@FXML private Button btnAccedi;
@FXML private Label labelErrore;
@FXML
public void initialize() {
// I RadioButton vanno collegati a un ToggleGroup a mano
// perché FXML non lo fa automaticamente
ToggleGroup group = new ToggleGroup();
btnRMI.setToggleGroup(group);
btnTCP.setToggleGroup(group);
}
// --- Getter esposti a LoginView ---
public Button getBtnAccedi() { return btnAccedi; }
public String getNome() { return campoNome.getText().trim(); }
public int getNumPlayers() {
try {
return Integer.parseInt(campoNumPlayers.getText().trim());
} catch (NumberFormatException e) {
return -1;
}
}
public int getNetworkType() { return btnRMI.isSelected() ? 0 : 1; }
public String getIP() { return campoIP.getText().trim(); }
public void setErrore(String messaggio) { labelErrore.setText(messaggio); }
}
@@ -0,0 +1,35 @@
package it.polimi.ingsw.gc14.View.GUI;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import java.io.IOException;
public class LoginView {
private final Scene scene;
private final LoginFXMLController fxmlController;
public LoginView() {
try {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/GUIScene/login.fxml")
);
scene = new Scene(loader.load(), 350, 380);
fxmlController = loader.getController();
} catch (IOException e) {
throw new RuntimeException("Impossibile caricare login.fxml", e);
}
}
// --- Delega tutto al controller FXML ---
public Scene getScene() { return scene; }
public Button getBtnAccedi() { return fxmlController.getBtnAccedi(); }
public String getNome() { return fxmlController.getNome(); }
public int getNumPlayers() { return fxmlController.getNumPlayers(); }
public int getNetworkType() { return fxmlController.getNetworkType(); }
public String getIP() { return fxmlController.getIP(); }
public void setErrore(String messaggio) { fxmlController.setErrore(messaggio); }
}
@@ -0,0 +1,43 @@
package it.polimi.ingsw.gc14.View.GUI;
import it.polimi.ingsw.gc14.Model.Cards.TribeCard;
import it.polimi.ingsw.gc14.Model.Game;
import javafx.fxml.FXML;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.shape.*;
import java.util.List;
public class MainFXMLController {
@FXML private HBox board;
@FXML private HBox upperList;
@FXML private HBox lowerList;
@FXML private HBox myHand;
@FXML private VBox playersHand;
private Game model;
public void setModel(Game model) {
this.model = model;
}
public void render() {
Image placeholder = new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-001.png"));
for (TribeCard card : model.getUpperListTribeCards()) {
ImageView view = new ImageView(placeholder);
view.setFitHeight(250);
view.setPreserveRatio(true);
upperList.getChildren().add(view);
}
for (TribeCard card : model.getLowerListTribeCards()) {
ImageView view = new ImageView(placeholder);
view.setFitHeight(250);
view.setPreserveRatio(true);
lowerList.getChildren().add(view);
}
}
}
@@ -0,0 +1,39 @@
package it.polimi.ingsw.gc14.View.GUI;
import it.polimi.ingsw.gc14.Model.Game;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import java.io.IOException;
public class MainView {
private final Scene scene;
private final MainFXMLController fxmlController;
private Game model;
public MainView() {
try {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/GUIScene/main.fxml")
);
scene = new Scene(loader.load(), 1920, 1080);
fxmlController = loader.getController();
} catch (IOException e) {
throw new RuntimeException("Impossibile caricare login.fxml", e);
}
}
public Scene getScene() { return scene; }
public void setModel(Game model) {
this.model = model;
fxmlController.setModel(model);
}
public void render() {
fxmlController.render();
}
}
@@ -4,7 +4,7 @@ import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
public interface IView {
public void update(Game game);
public void setModel(Game game);
public void render();
public void showMessage(String message);
public void showError(String message);
@@ -77,7 +77,7 @@ public class TUI implements IView {
* @param model the new {@link Game} model; must not be {@code null}
*/
@Override
public void update(Game model) {
public void setModel(Game model) {
this.model = model;
}
+4
View File
@@ -18,4 +18,8 @@ module it.polimi.ingsw.gc14 {
exports it.polimi.ingsw.gc14.Network.RMI.Client to java.rmi;
exports it.polimi.ingsw.gc14.Network to java.rmi;
exports it.polimi.ingsw.gc14.Model to java.rmi, com.google.gson;
// GUI
opens it.polimi.ingsw.gc14.View.GUI to javafx.fxml;
exports it.polimi.ingsw.gc14.View.GUI;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 832 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 KiB

Some files were not shown because too many files have changed in this diff Show More