Small improvements to usability, auto disconnect when server closes connection

This commit is contained in:
lieght
2025-12-14 01:13:42 +01:00
parent 8cb0a86d4e
commit b94d1b6c9d
17 changed files with 87 additions and 43 deletions

View File

@@ -159,7 +159,8 @@ public final class Server {
.listen(NetworkEvents.GameMatchResponse.class, this::handleMatchResponse, false, "match-response") .listen(NetworkEvents.GameMatchResponse.class, this::handleMatchResponse, false, "match-response")
.listen(NetworkEvents.GameResultResponse.class, this::handleGameResult, false, "game-result") .listen(NetworkEvents.GameResultResponse.class, this::handleGameResult, false, "game-result")
.listen(NetworkEvents.GameMoveResponse.class, this::handleReceivedMove, false, "game-move") .listen(NetworkEvents.GameMoveResponse.class, this::handleReceivedMove, false, "game-move")
.listen(NetworkEvents.YourTurnResponse.class, this::handleYourTurn, false, "your-turn"); .listen(NetworkEvents.YourTurnResponse.class, this::handleYourTurn, false, "your-turn")
.listen(NetworkEvents.ClosedConnection.class, this::closedConnection, false, "closed-connection");
connectFlow = a; connectFlow = a;
} }
@@ -233,7 +234,8 @@ public final class Server {
} }
if (gameController != null){ if (gameController != null) {
primary.reEnableButton();
gameController.start(); gameController.start();
} }
} }
@@ -293,6 +295,20 @@ public final class Server {
WidgetContainer.getCurrentView().transitionPrevious(); WidgetContainer.getCurrentView().transitionPrevious();
} }
private void closedConnection(NetworkEvents.ClosedConnection e) {
new EventFlow().addPostEvent(new NetworkEvents.CloseClient(clientId)).postEvent();
isPolling = false;
stopScheduler();
connectFlow.unsubscribeAll();
if (nettyGatewayServer != null) {
nettyGatewayServer.stop();
}
WidgetContainer.getCurrentView().transitionPrevious();
WidgetContainer.add(Pos.CENTER, new ErrorPopup("Server closed connection."));
}
private void forfeitGame() { private void forfeitGame() {
new EventFlow().addPostEvent(new NetworkEvents.SendForfeit(clientId)).postEvent(); new EventFlow().addPostEvent(new NetworkEvents.SendForfeit(clientId)).postEvent();
} }
@@ -339,7 +355,9 @@ public final class Server {
private void gamesListFromServerHandler(NetworkEvents.GamelistResponse event) { private void gamesListFromServerHandler(NetworkEvents.GamelistResponse event) {
gameList.clear(); gameList.clear();
gameList.addAll(List.of(event.gamelist())); var gl = List.of(event.gamelist());
gameList.addAll(gl);
primary.updateGameList(gl);
} }
public void populateGameList() { public void populateGameList() {

View File

@@ -64,7 +64,7 @@ public final class Primitive {
return imageView; return imageView;
} }
public static Button button(String key, Runnable onAction, boolean localize) { public static Button button(String key, Runnable onAction, boolean localize, boolean disableOnClick) {
var button = new Button(); var button = new Button();
button.getStyleClass().add("button"); button.getStyleClass().add("button");
@@ -75,6 +75,7 @@ public final class Primitive {
if (onAction != null) { if (onAction != null) {
button.setOnAction(_ -> { button.setOnAction(_ -> {
if (disableOnClick) button.setDisable(true);
onAction.run(); onAction.run();
playButtonSound(); playButtonSound();
}); });
@@ -83,8 +84,8 @@ public final class Primitive {
return button; return button;
} }
public static Button button(String key, Runnable onAction) { public static Button button(String key, Runnable onAction, boolean disableOnClick) {
return button(key, onAction, true); return button(key, onAction, true, disableOnClick);
} }
public static TextField input(String promptKey, String text, Consumer<String> onValueChanged, boolean localize) { public static TextField input(String promptKey, String text, Consumer<String> onValueChanged, boolean localize) {

View File

@@ -26,7 +26,7 @@ public class ConfirmWidget implements Widget {
public void addButton(String key, Runnable onClick) { public void addButton(String key, Runnable onClick) {
Platform.runLater(() -> { Platform.runLater(() -> {
var button = Primitive.button(key, onClick); var button = Primitive.button(key, onClick, false);
buttonsContainer.getChildren().add(button); buttonsContainer.getChildren().add(button);
}); });
} }

View File

@@ -91,7 +91,7 @@ public class PlayerInfoWidget {
information.computerDifficulty = depth; information.computerDifficulty = depth;
information.computerThinkTime = thinktime; information.computerThinkTime = thinktime;
this.playerName.setText(getName(name)); this.playerName.setText(getName(name));
}); }, false);
} }
private String getName(String name) { private String getName(String name) {

View File

@@ -32,7 +32,7 @@ public abstract class ViewWidget extends StackWidget {
var backButton = Primitive.button("back", () -> { var backButton = Primitive.button("back", () -> {
view.transitionPrevious(); view.transitionPrevious();
}); }, false);
view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton)); view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton));
} }
@@ -45,7 +45,7 @@ public abstract class ViewWidget extends StackWidget {
var customButton = Primitive.button(key, () -> { var customButton = Primitive.button(key, () -> {
runnable.run(); runnable.run();
view.transitionPrevious(); view.transitionPrevious();
}); }, false);
view.add(Pos.BOTTOM_LEFT, Primitive.vbox(customButton)); view.add(Pos.BOTTOM_LEFT, Primitive.vbox(customButton));
} }
@@ -97,7 +97,7 @@ public abstract class ViewWidget extends StackWidget {
var backButton = Primitive.button("back", () -> { var backButton = Primitive.button("back", () -> {
view.transitionPrevious(); view.transitionPrevious();
}); }, false);
view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton)); view.add(Pos.BOTTOM_LEFT, Primitive.vbox(backButton));
} }

View File

@@ -37,8 +37,8 @@ public final class ChallengePopup extends PopupWidget {
var acceptButton = Primitive.button("accept", () -> { var acceptButton = Primitive.button("accept", () -> {
onAccept.accept(playerInformation); onAccept.accept(playerInformation);
this.hide(); this.hide();
}); }, false);
var denyButton = Primitive.button("deny", () -> hide()); var denyButton = Primitive.button("deny", () -> hide(), false);
var leftSection = Primitive.vbox( var leftSection = Primitive.vbox(
challengeText, challengeText,

View File

@@ -24,7 +24,7 @@ public class EscapePopup extends PopupWidget {
var opt = Primitive.button("options", () -> { var opt = Primitive.button("options", () -> {
hide(); hide();
WidgetContainer.getCurrentView().transitionNext(new OptionsView()); WidgetContainer.getCurrentView().transitionNext(new OptionsView());
}); }, false);
nodes.add(opt); nodes.add(opt);
} }
@@ -33,14 +33,14 @@ public class EscapePopup extends PopupWidget {
if (tut != null) { if (tut != null) {
nodes.add(Primitive.button("tutorialstring", () -> { nodes.add(Primitive.button("tutorialstring", () -> {
WidgetContainer.getCurrentView().add(Pos.CENTER, tut); WidgetContainer.getCurrentView().add(Pos.CENTER, tut);
})); }, false));
} }
} }
nodes.add(Primitive.button("quit", () -> { nodes.add(Primitive.button("quit", () -> {
hide(); hide();
WidgetContainer.add(Pos.CENTER, new QuitPopup()); WidgetContainer.add(Pos.CENTER, new QuitPopup());
})); }, false));
add(Pos.CENTER, Primitive.vbox(nodes.toArray(new Node[0]))); add(Pos.CENTER, Primitive.vbox(nodes.toArray(new Node[0])));

View File

@@ -62,9 +62,9 @@ public final class SendChallengePopup extends PopupWidget {
var sendButton = Primitive.button( var sendButton = Primitive.button(
"send", "send",
() -> { onSend.accept(playerInformation, gameChoice.getValue()); this.hide(); } () -> { onSend.accept(playerInformation, gameChoice.getValue()); this.hide(); }
); , false);
var cancelButton = Primitive.button("cancel", () -> hide()); var cancelButton = Primitive.button("cancel", () -> hide(), false);
var leftSection = Primitive.vbox( var leftSection = Primitive.vbox(
challengeText, challengeText,

View File

@@ -47,8 +47,8 @@ public class BaseTutorialWidget extends PopupWidget implements Updatable {
this.pages = pages; this.pages = pages;
this.nextScreen = nextScreen; this.nextScreen = nextScreen;
previousButton = Primitive.button("goback", () -> { update(false); this.hide(); }); previousButton = Primitive.button("goback", () -> { update(false); this.hide(); }, false);
nextButton = Primitive.button(">", () -> update(true)); nextButton = Primitive.button(">", () -> update(true), false);
var w = Primitive.hbox( var w = Primitive.hbox(
previousButton, previousButton,

View File

@@ -10,9 +10,9 @@ public class ShowEnableTutorialWidget extends PopupWidget {
public ShowEnableTutorialWidget(Runnable tutorial, Runnable nextScreen, Runnable appSettingsSetter) { public ShowEnableTutorialWidget(Runnable tutorial, Runnable nextScreen, Runnable appSettingsSetter) {
var a = Primitive.hbox( var a = Primitive.hbox(
Primitive.button("ok", () -> { appSettingsSetter.run(); tutorial.run(); this.hide(); }), Primitive.button("ok", () -> { appSettingsSetter.run(); tutorial.run(); this.hide(); }, false),
Primitive.button("no", () -> { appSettingsSetter.run(); nextScreen.run(); this.hide(); }), Primitive.button("no", () -> { appSettingsSetter.run(); nextScreen.run(); this.hide(); }, false),
Primitive.button("never", () -> { AppSettings.getSettings().setTutorialFlag(false); nextScreen.run(); this.hide(); }) Primitive.button("never", () -> { AppSettings.getSettings().setTutorialFlag(false); nextScreen.run(); this.hide(); }, false)
); );
var txt = Primitive.text("tutorial"); var txt = Primitive.text("tutorial");

View File

@@ -40,7 +40,7 @@ public final class GameView extends ViewWidget {
player2Icon = new Circle(); player2Icon = new Circle();
if (onForfeit != null) { if (onForfeit != null) {
forfeitButton = Primitive.button("forfeit", () -> onForfeit.run()); forfeitButton = Primitive.button("forfeit", () -> onForfeit.run(), false);
} else { } else {
forfeitButton = null; forfeitButton = null;
} }
@@ -48,7 +48,7 @@ public final class GameView extends ViewWidget {
exitButton = Primitive.button("exit", () -> { exitButton = Primitive.button("exit", () -> {
onExit.run(); onExit.run();
transitionPrevious(); transitionPrevious();
}); }, false);
if (onMessage != null) { if (onMessage != null) {
chatInput = Primitive.input("enter-your-message", "", null); chatInput = Primitive.input("enter-your-message", "", null);

View File

@@ -107,7 +107,7 @@ public class LocalMultiplayerView extends ViewWidget {
} }
break; break;
} }
}); }, false);
var playerSection = setupPlayerSections(); var playerSection = setupPlayerSections();

View File

@@ -10,11 +10,11 @@ public class LocalView extends ViewWidget {
public LocalView() { public LocalView() {
var ticTacToeButton = Primitive.button("tic-tac-toe", () -> { var ticTacToeButton = Primitive.button("tic-tac-toe", () -> {
transitionNext(new LocalMultiplayerView(GameInformation.Type.TICTACTOE)); transitionNext(new LocalMultiplayerView(GameInformation.Type.TICTACTOE));
}); }, false);
var reversiButton = Primitive.button("reversi", () -> { var reversiButton = Primitive.button("reversi", () -> {
transitionNext(new LocalMultiplayerView(GameInformation.Type.REVERSI)); transitionNext(new LocalMultiplayerView(GameInformation.Type.REVERSI));
}); }, false);
add(Pos.CENTER, Primitive.vbox( add(Pos.CENTER, Primitive.vbox(
ticTacToeButton, ticTacToeButton,

View File

@@ -9,24 +9,24 @@ public class MainView extends ViewWidget {
public MainView() { public MainView() {
var localButton = Primitive.button("local", () -> { var localButton = Primitive.button("local", () -> {
transitionNext(new LocalView()); transitionNext(new LocalView());
}); }, false);
var onlineButton = Primitive.button("online", () -> { var onlineButton = Primitive.button("online", () -> {
transitionNext(new OnlineView()); transitionNext(new OnlineView());
}); }, false);
var creditsButton = Primitive.button("credits", () -> { var creditsButton = Primitive.button("credits", () -> {
transitionNext(new CreditsView()); transitionNext(new CreditsView());
}); }, false);
var optionsButton = Primitive.button("options", () -> { var optionsButton = Primitive.button("options", () -> {
transitionNext(new OptionsView()); transitionNext(new OptionsView());
}); }, false);
var quitButton = Primitive.button("quit", () -> { var quitButton = Primitive.button("quit", () -> {
var a = new QuitPopup(); var a = new QuitPopup();
a.show(Pos.CENTER); a.show(Pos.CENTER);
}); }, false);
add(Pos.CENTER, Primitive.vbox( add(Pos.CENTER, Primitive.vbox(
localButton, localButton,

View File

@@ -29,7 +29,7 @@ public class OnlineView extends ViewWidget {
serverPortInput.getValue(), serverPortInput.getValue(),
playerNameInput.getValue() playerNameInput.getValue()
); );
}); }, false);
var localHostButton = Primitive.button("host!", () -> { var localHostButton = Primitive.button("host!", () -> {
@@ -53,7 +53,7 @@ public class OnlineView extends ViewWidget {
"host", "host",
a a
); );
}, false); }, false, false);
add(Pos.CENTER, Primitive.vbox( add(Pos.CENTER, Primitive.vbox(
serverInformationHeader, serverInformationHeader,

View File

@@ -1,9 +1,13 @@
package org.toop.app.widget.view; package org.toop.app.widget.view;
import javafx.collections.FXCollections;
import javafx.css.converter.StringConverter;
import javafx.scene.control.ComboBox;
import org.toop.app.widget.Primitive; import org.toop.app.widget.Primitive;
import org.toop.app.widget.complex.ViewWidget; import org.toop.app.widget.complex.ViewWidget;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.function.Consumer; import java.util.function.Consumer;
import javafx.application.Platform; import javafx.application.Platform;
@@ -18,13 +22,16 @@ public final class ServerView extends ViewWidget {
private final Consumer<String> onPlayerClicked; private final Consumer<String> onPlayerClicked;
private final long clientId; private final long clientId;
private final ComboBox<String> gameList;
private final ListView<Button> listView; private final ListView<Button> listView;
private Button subscribeButton;
public ServerView(String user, Consumer<String> onPlayerClicked, long clientId) { public ServerView(String user, Consumer<String> onPlayerClicked, long clientId) {
this.user = user; this.user = user;
this.onPlayerClicked = onPlayerClicked; this.onPlayerClicked = onPlayerClicked;
this.clientId = clientId; this.clientId = clientId;
this.gameList = new ComboBox<>();
this.listView = new ListView<>(); this.listView = new ListView<>();
setupLayout(); setupLayout();
@@ -33,24 +40,26 @@ public final class ServerView extends ViewWidget {
private void setupLayout() { private void setupLayout() {
var playerHeader = Primitive.header(user, false); var playerHeader = Primitive.header(user, false);
Button subscribeButton = Primitive.button( subscribeButton = Primitive.button(
"subscribe", "subscribe",
() -> new EventFlow().addPostEvent(new NetworkEvents.SendSubscribe(clientId, "reversi")).postEvent(), () -> new EventFlow().addPostEvent(new NetworkEvents.SendSubscribe(clientId, gameList.getValue())).postEvent(),
false false,
true
); // TODO localize ); // TODO localize
var subscribe = Primitive.hbox(gameList, subscribeButton);
var playerListSection = Primitive.vbox( var playerListSection = Primitive.vbox(
playerHeader, playerHeader,
Primitive.separator(), Primitive.separator(),
subscribeButton, subscribe,
listView listView
); );
add(Pos.CENTER, playerListSection); add(Pos.CENTER, playerListSection);
var disconnectButton = Primitive.button("disconnect", () -> { var disconnectButton = Primitive.button(
transitionPrevious(); "disconnect", () -> transitionPrevious(), false);
});
add(Pos.BOTTOM_LEFT, Primitive.vbox(disconnectButton)); add(Pos.BOTTOM_LEFT, Primitive.vbox(disconnectButton));
} }
@@ -60,9 +69,21 @@ public final class ServerView extends ViewWidget {
listView.getItems().clear(); listView.getItems().clear();
for (String player : players) { for (String player : players) {
var playerButton = Primitive.button(player, () -> onPlayerClicked.accept(player), false); var playerButton = Primitive.button(player, () -> onPlayerClicked.accept(player), false, false);
listView.getItems().add(playerButton); listView.getItems().add(playerButton);
} }
}); });
} }
public void updateGameList(List<String> games) {
Platform.runLater(() -> {
gameList.getItems().clear();
gameList.setItems(FXCollections.observableArrayList(games));
gameList.getSelectionModel().select(0);
});
}
public void reEnableButton() {
subscribeButton.setDisable(false);
}
} }

View File

@@ -12,6 +12,7 @@ import io.netty.util.CharsetUtil;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.toop.framework.eventbus.bus.EventBus; import org.toop.framework.eventbus.bus.EventBus;
import org.toop.framework.networking.connection.events.NetworkEvents;
import org.toop.framework.networking.connection.exceptions.CouldNotConnectException; import org.toop.framework.networking.connection.exceptions.CouldNotConnectException;
import org.toop.framework.networking.connection.handlers.NetworkingGameClientHandler; import org.toop.framework.networking.connection.handlers.NetworkingGameClientHandler;
import org.toop.framework.networking.connection.interfaces.NetworkingClient; import org.toop.framework.networking.connection.interfaces.NetworkingClient;
@@ -23,6 +24,7 @@ public class TournamentNetworkingClient implements NetworkingClient {
private final EventBus eventBus; private final EventBus eventBus;
private Channel channel; private Channel channel;
private long clientId;
public TournamentNetworkingClient(EventBus eventBus) { public TournamentNetworkingClient(EventBus eventBus) {
this.eventBus = eventBus; this.eventBus = eventBus;
@@ -35,6 +37,7 @@ public class TournamentNetworkingClient implements NetworkingClient {
@Override @Override
public void connect(long clientId, String host, int port) throws CouldNotConnectException { public void connect(long clientId, String host, int port) throws CouldNotConnectException {
this.clientId = clientId;
try { try {
Bootstrap bootstrap = new Bootstrap(); Bootstrap bootstrap = new Bootstrap();
EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()); EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
@@ -75,6 +78,7 @@ public class TournamentNetworkingClient implements NetworkingClient {
logger.info("Connection {} sent message: '{}' ", this.channel.remoteAddress(), literalMsg); logger.info("Connection {} sent message: '{}' ", this.channel.remoteAddress(), literalMsg);
} else { } else {
logger.warn("Cannot send message: '{}', connection inactive. ", literalMsg); logger.warn("Cannot send message: '{}', connection inactive. ", literalMsg);
eventBus.post(new NetworkEvents.ClosedConnection(clientId));
} }
} }