package com.cardshifter.client; import java.net.URL; import java.util.*; import java.util.Map.Entry; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.prefs.Preferences; import com.cardshifter.api.LogInterface; import com.cardshifter.api.config.PlayerConfig; import com.cardshifter.core.Log4jAdapter; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ChoiceBox; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.HBox; import javafx.stage.Stage; import com.cardshifter.api.config.DeckConfig; import com.cardshifter.ai.FakeAIClientTCG; import com.cardshifter.api.ClientIO; import com.cardshifter.api.ClientServerInterface; import com.cardshifter.api.both.PlayerConfigMessage; import com.cardshifter.api.incoming.RequestTargetsMessage; import com.cardshifter.api.incoming.UseAbilityMessage; import com.cardshifter.api.messages.Message; import com.cardshifter.api.outgoing.NewGameMessage; import com.cardshifter.client.buttons.AIChoiceButton; import com.cardshifter.core.game.FakeClient; import com.cardshifter.core.game.ModCollection; import com.cardshifter.core.game.TCGGame; import com.cardshifter.modapi.ai.AIComponent; import com.cardshifter.modapi.base.ECSMod; import com.cardshifter.modapi.base.Entity; import com.cardshifter.modapi.base.PlayerComponent; public final class GameClientLauncherController implements Initializable { @FXML private TextField ipAddressBox; @FXML private TextField portBox; @FXML private TextField userNameBox; @FXML private Button connectButton; @FXML private Label errorMessage; @FXML private AnchorPane anchorPane; @FXML private Button localGameButton; @FXML private HBox aiChoiceBox; @FXML private ChoiceBox<String> modChoice; private final Map<String, AIComponent> aiChoices = new HashMap<>(); private AIComponent aiChoice; private final Preferences settings = Preferences.userNodeForPackage(GameClientLauncherController.class); private ClientIO human; private final ModCollection mods = ModCollection.defaultMods(); private static final String CONF_NAME = "name"; private String getCharactersFromTextField(TextField textField) { return textField.getCharacters().toString(); } private void buttonClick(ActionEvent event) { String ipAddressValue = this.getCharactersFromTextField(this.ipAddressBox); int portValue = Integer.parseInt(this.getCharactersFromTextField(this.portBox)); String userNameValue = this.getCharactersFromTextField(this.userNameBox); settings.put(CONF_NAME, userNameValue); //this.switchToMainGameWindow(ipAddressValue, portValue); this.switchToLobbyWindow(ipAddressValue, portValue, userNameValue); } private void closeWithSuccess() { Node source = anchorPane; Stage stage = (Stage)source.getScene().getWindow(); stage.close(); } private void switchToLobbyWindow(String ipAddress, int port, String userName) { try { FXMLLoader loader = new FXMLLoader(getClass().getResource("LobbyDocument.fxml")); Parent root = (Parent)loader.load(); GameClientLobby controller = loader.<GameClientLobby>getController(); controller.acceptConnectionSettings(ipAddress, port, userName); if (controller.connectToLobby()) { errorMessage.setText("Success!"); this.closeWithSuccess(); Scene scene = new Scene(root); Stage lobbyStage = new Stage(); lobbyStage.setScene(scene); lobbyStage.setOnCloseRequest(windowEvent -> controller.closeLobby()); lobbyStage.show(); } else { errorMessage.setText("Connection Failed!"); } } catch (Exception e) { throw new RuntimeException(e); } } private void createAIChoices() { mods.getAIs().forEach((name, ai) -> aiChoices.put(name, new AIComponent(ai))); modChoice.getItems().addAll(mods.getAvailableMods()); modChoice.getSelectionModel().select(0); localGameButton.setOnAction(this::localGameStart); this.createAIButtons(); } private void createAIButtons() { double buttonWidth = this.aiChoiceBox.getPrefWidth() / this.aiChoices.size(); double buttonHeight = this.aiChoiceBox.getPrefHeight() - this.aiChoiceBox.getPrefHeight()/4; for (String string : this.aiChoices.keySet()) { AIChoiceButton button = new AIChoiceButton(buttonWidth, buttonHeight, string, this); this.aiChoiceBox.getChildren().add(button); } } public void clearAIButtons() { for (Object button : this.aiChoiceBox.getChildren()) { ((AIChoiceButton)button).unHighlightButton(); } } public void setAI(String aiName) { this.aiChoice = this.aiChoices.get(aiName); this.checkLocalGameButtonEnable(); } private void checkLocalGameButtonEnable() { boolean aiSelected = this.aiChoice != null; boolean modChosen = this.modChoice.getSelectionModel().getSelectedItem() != null; this.localGameButton.setDisable(!aiSelected || !modChosen); } private void localGameStart(ActionEvent event) { String modName = modChoice.getValue(); ECSMod mod = mods.getModFor(modName); ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); TCGGame game = new TCGGame(() -> executor, modName, 1, mod); ClientServerInterface singlePlayerHandler = new ClientServerInterface() { @Override public void performIncoming(Message message, ClientIO clientIO) { if (message instanceof UseAbilityMessage) { UseAbilityMessage msg = (UseAbilityMessage) message; game.handleMove(msg, clientIO); } if (message instanceof RequestTargetsMessage) { RequestTargetsMessage msg = (RequestTargetsMessage) message; game.informAboutTargets(msg, clientIO); } if (message instanceof PlayerConfigMessage) { PlayerConfigMessage msg = (PlayerConfigMessage) message; game.incomingPlayerConfig(msg, clientIO); } } @Override public void onDisconnected(ClientIO clientIO) { } @Override public int newClientId() { return 0; } @Override public void handleMessage(ClientIO clientIO, String message) { throw new UnsupportedOperationException(); } @Override public LogInterface getLogger() { return new Log4jAdapter(); } }; try { FXMLLoader loader = new FXMLLoader(getClass().getResource("ClientDocument.fxml")); Parent root = (Parent)loader.load(); GameClientController controller = loader.<GameClientController>getController(); human = new FakeClient(singlePlayerHandler, msg -> handleMessage(msg, controller)); ClientIO ai = new FakeAIClientTCG(singlePlayerHandler, this.aiChoice.getAI()); game.start(Arrays.asList(human, ai)); Entity humanPlayer = game.playerFor(human); PlayerComponent playerInfo = humanPlayer.getComponent(PlayerComponent.class); controller.acceptConnectionSettings(new NewGameMessage(0, playerInfo.getIndex()), e -> human.sentToServer(e)); Scene scene = new Scene(root); Stage gameStage = new Stage(); gameStage.setScene(scene); gameStage.setOnCloseRequest(windowEvent -> {}); gameStage.show(); } catch (Exception e) { throw new RuntimeException(e); } } private void handleMessage(Message msg, GameClientController controller) { if (msg instanceof PlayerConfigMessage) { PlayerConfigMessage configMessage = (PlayerConfigMessage) msg; Map<String, PlayerConfig> configs = configMessage.getConfigs(); for (Entry<String, PlayerConfig> entry : configs.entrySet()) { Object value = entry.getValue(); if (value instanceof DeckConfig) { DeckConfig deckConfig = (DeckConfig) value; this.showDeckBuilderWindow(configMessage, deckConfig, true); } } return; } Platform.runLater(() -> controller.processMessageFromServer(msg)); } private void showDeckBuilderWindow(PlayerConfigMessage conf, DeckConfig deckConfig, boolean startingGame) { try { FXMLLoader loader = new FXMLLoader(getClass().getResource("DeckBuilderDocument.fxml")); Parent root = (Parent)loader.load(); DeckBuilderWindow controller = loader.<DeckBuilderWindow>getController(); controller.acceptDeckConfig(deckConfig, conf.getModName(), cnf -> human.sentToServer(incorporateConfig(conf, deckConfig, cnf))); controller.configureWindow(); if (!startingGame) { controller.disableGameStart(); } Scene scene = new Scene(root); Stage stage = new Stage(); stage.setScene(scene); // stage.setOnCloseRequest(windowEvent -> this.closeDeckBuilderWindow()); stage.show(); } catch (Exception e) { throw new RuntimeException(e); } } private Message incorporateConfig(PlayerConfigMessage conf, DeckConfig oldConfig, DeckConfig newConfig) { Map<String, PlayerConfig> configs = conf.getConfigs(); for (Entry<String, PlayerConfig> entry : configs.entrySet()) { Object value = entry.getValue(); if (value instanceof DeckConfig) { DeckConfig config = (DeckConfig) value; newConfig.getChosen().forEach((id, count) -> config.setChosen(id, count)); } } return new PlayerConfigMessage(conf.getGameId(), conf.getModName(), configs); } @Override public void initialize(URL url, ResourceBundle rb) { this.connectButton.setOnAction(this::buttonClick); this.ipAddressBox.setText("127.0.0.1"); this.portBox.setText("4242"); this.userNameBox.setText(settings.get(CONF_NAME, "Enter Name")); this.localGameButton.setDisable(true); this.createAIChoices(); } }