diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index 00f91cc..206496d 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -1,18 +1,23 @@ package org.toop.app; +import javafx.application.Platform; +import javafx.geometry.Pos; import org.toop.app.game.Connect4Game; import org.toop.app.game.ReversiGame; import org.toop.app.game.TicTacToeGame; import org.toop.app.widget.WidgetContainer; +import org.toop.app.widget.complex.LoadingWidget; import org.toop.app.widget.popup.ChallengePopup; import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.popup.SendChallengePopup; import org.toop.app.widget.view.ServerView; import org.toop.framework.eventbus.EventFlow; +import org.toop.framework.eventbus.ListenerHandler; import org.toop.framework.networking.clients.TournamentNetworkingClient; import org.toop.framework.networking.events.NetworkEvents; import org.toop.framework.networking.types.NetworkingConnector; import org.toop.local.AppContext; +import java.util.function.Consumer; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -69,24 +74,35 @@ public final class Server { return; } - new EventFlow() + final int reconnectAttempts = 10; + + LoadingWidget loading = new LoadingWidget(0, reconnectAttempts); + loading.show(Pos.CENTER); + + var a = new EventFlow() .addPostEvent(NetworkEvents.StartClient.class, new TournamentNetworkingClient(), - new NetworkingConnector(ip, parsedPort, 10, 1, TimeUnit.SECONDS) - ) - .onResponse(NetworkEvents.StartClientResponse.class, e -> { - this.user = user; - clientId = e.clientId(); + new NetworkingConnector(ip, parsedPort, reconnectAttempts, 1, TimeUnit.SECONDS) + ); - new EventFlow().addPostEvent(new NetworkEvents.SendLogin(clientId, user)).postEvent(); + a.onResponse(NetworkEvents.StartClientResponse.class, e -> { - primary = new ServerView(user, this::sendChallenge, this::disconnect); - WidgetContainer.getCurrentView().transitionNext(primary); + a.unsubscribe("startclient"); - startPopulateScheduler(); - populateGameList(); + loading.hide(); + this.user = user; + clientId = e.clientId(); - }).postEvent(); + new EventFlow().addPostEvent(new NetworkEvents.SendLogin(clientId, user)).postEvent(); + + primary = new ServerView(user, this::sendChallenge, this::disconnect); + WidgetContainer.getCurrentView().transitionNext(primary); + + startPopulateScheduler(); + populateGameList(); + }, false, "startclient").listen(NetworkEvents.ConnectTry.class, e -> { + Platform.runLater(() -> loading.setAmount(e.amount())); + }).postEvent(); new EventFlow().listen(this::handleReceivedChallenge) .listen(this::handleMatchResponse); diff --git a/app/src/main/java/org/toop/app/widget/complex/LoadingWidget.java b/app/src/main/java/org/toop/app/widget/complex/LoadingWidget.java new file mode 100644 index 0000000..461110f --- /dev/null +++ b/app/src/main/java/org/toop/app/widget/complex/LoadingWidget.java @@ -0,0 +1,75 @@ +package org.toop.app.widget.complex; + +import javafx.geometry.Pos; +import javafx.scene.control.ProgressBar; +import javafx.scene.layout.HBox; + +public class LoadingWidget extends ViewWidget implements Update { // TODO make of widget type + private final ProgressBar progressBar; + + private Runnable success = () -> {}; + private Runnable failure = () -> {}; + private int maxAmount; + private int amount; + private float percentage = 0.0f; + + + public LoadingWidget(int startAmount, int maxAmount) { + + amount = startAmount; + this.maxAmount = maxAmount; + + progressBar = new ProgressBar(); + + HBox box = new HBox(10, progressBar); + add(Pos.CENTER, box); + } + + public void setMaxAmount(int maxAmount) { + this.maxAmount = maxAmount; + } + + public void setAmount(int amount) { + this.amount = amount; + update(); + } + + public void setAmount() { + setAmount(this.amount+1); + } + + public void setOnSuccess(Runnable onSuccess) { + success = onSuccess; + } + + public void setOnFailure(Runnable onFailure) { + failure = onFailure; + } + + public void triggerSuccess() { + success.run(); + } + + public void triggerFailure() { + failure.run(); + } + + @Override + public void update() { + if (amount >= maxAmount) { + triggerSuccess(); + System.out.println("triggered"); + this.hide(); + return; + } else if (amount < 0) { + triggerFailure(); + System.out.println("triggerFailure"); + this.hide(); + return; + } + + percentage = (float) amount / maxAmount; + progressBar.setProgress(percentage); + + } +} diff --git a/app/src/main/java/org/toop/app/widget/complex/Update.java b/app/src/main/java/org/toop/app/widget/complex/Update.java new file mode 100644 index 0000000..c44fe00 --- /dev/null +++ b/app/src/main/java/org/toop/app/widget/complex/Update.java @@ -0,0 +1,5 @@ +package org.toop.app.widget.complex; + +public interface Update { + void update(); +} diff --git a/app/src/main/java/org/toop/app/widget/display/SongDisplay.java b/app/src/main/java/org/toop/app/widget/display/SongDisplay.java index c75ce8f..e8c48b1 100644 --- a/app/src/main/java/org/toop/app/widget/display/SongDisplay.java +++ b/app/src/main/java/org/toop/app/widget/display/SongDisplay.java @@ -22,7 +22,7 @@ public class SongDisplay extends VBox implements Widget { public SongDisplay() { new EventFlow() - .listen(this::updateTheSong); + .listen(AudioEvents.PlayingMusic.class, this::updateTheSong, false); setAlignment(Pos.CENTER); setMaxHeight(Region.USE_PREF_SIZE); diff --git a/framework/src/main/java/org/toop/framework/networking/NetworkingClientManager.java b/framework/src/main/java/org/toop/framework/networking/NetworkingClientManager.java index 02434fc..8357980 100644 --- a/framework/src/main/java/org/toop/framework/networking/NetworkingClientManager.java +++ b/framework/src/main/java/org/toop/framework/networking/NetworkingClientManager.java @@ -8,6 +8,8 @@ import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.toop.framework.eventbus.GlobalEventBus; +import org.toop.framework.networking.events.NetworkEvents; import org.toop.framework.networking.exceptions.ClientNotFoundException; import org.toop.framework.networking.exceptions.CouldNotConnectException; import org.toop.framework.networking.interfaces.NetworkingClient; @@ -44,6 +46,7 @@ public class NetworkingClientManager implements org.toop.framework.networking.in nClient.connect(id, nConnector.host(), nConnector.port()); networkClients.put(id, nClient); logger.info("New client started successfully for {}:{}", nConnector.host(), nConnector.port()); + GlobalEventBus.post(new NetworkEvents.ConnectTry(id, attempts, nConnector.reconnectAttempts(), true)); onSuccess.run(); scheduler.shutdown(); } catch (CouldNotConnectException e) { @@ -51,14 +54,17 @@ public class NetworkingClientManager implements org.toop.framework.networking.in if (attempts < nConnector.reconnectAttempts()) { logger.warn("Could not connect to {}:{}. Retrying in {} {}", nConnector.host(), nConnector.port(), nConnector.timeout(), nConnector.timeUnit()); + GlobalEventBus.post(new NetworkEvents.ConnectTry(id, attempts, nConnector.reconnectAttempts(), false)); scheduler.schedule(this, nConnector.timeout(), nConnector.timeUnit()); } else { logger.error("Failed to start client for {}:{} after {} attempts", nConnector.host(), nConnector.port(), attempts); + GlobalEventBus.post(new NetworkEvents.ConnectTry(id, -1, nConnector.reconnectAttempts(), false)); onFailure.run(); scheduler.shutdown(); } } catch (Exception e) { logger.error("Unexpected exception during startClient", e); + GlobalEventBus.post(new NetworkEvents.ConnectTry(id, -1, nConnector.reconnectAttempts(), false)); onFailure.run(); scheduler.shutdown(); } diff --git a/framework/src/main/java/org/toop/framework/networking/events/NetworkEvents.java b/framework/src/main/java/org/toop/framework/networking/events/NetworkEvents.java index ac3de68..f199634 100644 --- a/framework/src/main/java/org/toop/framework/networking/events/NetworkEvents.java +++ b/framework/src/main/java/org/toop/framework/networking/events/NetworkEvents.java @@ -181,6 +181,8 @@ public class NetworkEvents extends EventsBase { public record StartClientResponse(long clientId, boolean successful, long identifier) implements ResponseToUniqueEvent {} + public record ConnectTry(long clientId, int amount, int maxAmount, boolean success) implements GenericEvent {} + /** * Requests reconnection of an existing client using its previous configuration. *