diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java
index 05a34a4..8456819 100644
--- a/app/src/main/java/org/toop/Main.java
+++ b/app/src/main/java/org/toop/Main.java
@@ -8,14 +8,14 @@ import org.toop.framework.networking.NetworkingClientManager;
import org.toop.framework.networking.NetworkingInitializationException;
public final class Main {
- public static void main(String[] args) {
- initSystems();
- App.run(args);
- }
+ public static void main(String[] args) {
+ initSystems();
+ App.run(args);
+ }
- private static void initSystems() throws NetworkingInitializationException {
- ResourceManager.loadAssets(new ResourceLoader("app/src/main/resources/assets"));
- new Thread(NetworkingClientManager::new).start();
- new Thread(SoundManager::new).start();
- }
-}
\ No newline at end of file
+ private static void initSystems() throws NetworkingInitializationException {
+ ResourceManager.loadAssets(new ResourceLoader("app/src/main/resources/assets"));
+ new Thread(NetworkingClientManager::new).start();
+ new Thread(SoundManager::new).start();
+ }
+}
diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java
index 38a4873..c4c9251 100644
--- a/app/src/main/java/org/toop/app/App.java
+++ b/app/src/main/java/org/toop/app/App.java
@@ -1,6 +1,11 @@
package org.toop.app;
+import java.util.Stack;
+import javafx.application.Application;
import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.layout.StackPane;
+import javafx.stage.Stage;
import org.toop.app.layer.Layer;
import org.toop.app.layer.layers.MainLayer;
import org.toop.app.layer.layers.QuitPopup;
@@ -9,155 +14,154 @@ import org.toop.framework.asset.resources.CssAsset;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
import org.toop.local.AppContext;
-
-import javafx.application.Application;
-import javafx.scene.Scene;
-import javafx.scene.layout.StackPane;
-import javafx.stage.Stage;
import org.toop.local.AppSettings;
-import java.util.Stack;
-
public final class App extends Application {
- private static Stage stage;
- private static Scene scene;
- private static StackPane root;
+ private static Stage stage;
+ private static Scene scene;
+ private static StackPane root;
- private static Stack stack;
+ private static Stack stack;
private static int height;
private static int width;
- private static boolean isQuitting;
+ private static boolean isQuitting;
- public static void run(String[] args) {
- launch(args);
- }
+ public static void run(String[] args) {
+ launch(args);
+ }
- @Override
- public void start(Stage stage) throws Exception {
+ @Override
+ public void start(Stage stage) throws Exception {
final StackPane root = new StackPane();
- final Scene scene = new Scene(root);
+ final Scene scene = new Scene(root);
- stage.setTitle(AppContext.getString("appTitle"));
- stage.setWidth(1080);
- stage.setHeight(720);
+ stage.setTitle(AppContext.getString("appTitle"));
+ stage.setWidth(1080);
+ stage.setHeight(720);
- stage.setOnCloseRequest(event -> {
- event.consume();
+ stage.setOnCloseRequest(
+ event -> {
+ event.consume();
- if (!isQuitting) {
- quitPopup();
- }
- });
+ if (!isQuitting) {
+ quitPopup();
+ }
+ });
- stage.setScene(scene);
- stage.setResizable(false);
+ stage.setScene(scene);
+ stage.setResizable(false);
- stage.show();
+ stage.show();
- App.stage = stage;
- App.scene = scene;
- App.root = root;
+ App.stage = stage;
+ App.scene = scene;
+ App.root = root;
- App.stack = new Stack<>();
+ App.stack = new Stack<>();
- App.width = (int) stage.getWidth();
- App.height = (int) stage.getHeight();
+ App.width = (int) stage.getWidth();
+ App.height = (int) stage.getHeight();
- App.isQuitting = false;
+ App.isQuitting = false;
- final AppSettings settings = new AppSettings();
- settings.applySettings();
+ final AppSettings settings = new AppSettings();
+ settings.applySettings();
- new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
- activate(new MainLayer());
- }
+ new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
+ activate(new MainLayer());
+ }
- public static void activate(Layer layer) {
- Platform.runLater(() -> {
- popAll();
- push(layer);
- });
- }
+ public static void activate(Layer layer) {
+ Platform.runLater(
+ () -> {
+ popAll();
+ push(layer);
+ });
+ }
- public static void push(Layer layer) {
- Platform.runLater(() -> {
- root.getChildren().addLast(layer.getLayer());
- stack.push(layer);
- });
- }
+ public static void push(Layer layer) {
+ Platform.runLater(
+ () -> {
+ root.getChildren().addLast(layer.getLayer());
+ stack.push(layer);
+ });
+ }
- public static void pop() {
- Platform.runLater(() -> {
- root.getChildren().removeLast();
- stack.pop();
+ public static void pop() {
+ Platform.runLater(
+ () -> {
+ root.getChildren().removeLast();
+ stack.pop();
- isQuitting = false;
- });
- }
+ isQuitting = false;
+ });
+ }
- public static void popAll() {
- Platform.runLater(() -> {
- final int childrenCount = root.getChildren().size();
+ public static void popAll() {
+ Platform.runLater(
+ () -> {
+ final int childrenCount = root.getChildren().size();
- for (int i = 0; i < childrenCount; i++) {
- try {
- root.getChildren().removeLast();
- } catch (Exception e) {
- IO.println(e);
- }
- }
+ for (int i = 0; i < childrenCount; i++) {
+ try {
+ root.getChildren().removeLast();
+ } catch (Exception e) {
+ IO.println(e);
+ }
+ }
- stack.removeAllElements();
- });
- }
+ stack.removeAllElements();
+ });
+ }
- public static void quitPopup() {
- Platform.runLater(() -> {
- push(new QuitPopup());
- isQuitting = true;
- });
- }
+ public static void quitPopup() {
+ Platform.runLater(
+ () -> {
+ push(new QuitPopup());
+ isQuitting = true;
+ });
+ }
- public static void quit() {
- stage.close();
- }
+ public static void quit() {
+ stage.close();
+ }
- public static void reloadAll() {
- stage.setTitle(AppContext.getString("appTitle"));
+ public static void reloadAll() {
+ stage.setTitle(AppContext.getString("appTitle"));
- for (final Layer layer : stack) {
- layer.reload();
- }
- }
+ for (final Layer layer : stack) {
+ layer.reload();
+ }
+ }
- public static void setFullscreen(boolean fullscreen) {
- stage.setFullScreen(fullscreen);
+ public static void setFullscreen(boolean fullscreen) {
+ stage.setFullScreen(fullscreen);
- width = (int) stage.getWidth();
- height = (int) stage.getHeight();
+ width = (int) stage.getWidth();
+ height = (int) stage.getHeight();
- reloadAll();
- }
+ reloadAll();
+ }
- public static void setStyle(String theme, String layoutSize) {
- final int stylesCount = scene.getStylesheets().size();
+ public static void setStyle(String theme, String layoutSize) {
+ final int stylesCount = scene.getStylesheets().size();
- for (int i = 0; i < stylesCount; i++) {
- scene.getStylesheets().removeLast();
- }
+ for (int i = 0; i < stylesCount; i++) {
+ scene.getStylesheets().removeLast();
+ }
- scene.getStylesheets().add(ResourceManager.get(theme + ".css").getUrl());
- scene.getStylesheets().add(ResourceManager.get(layoutSize + ".css").getUrl());
+ scene.getStylesheets().add(ResourceManager.get(theme + ".css").getUrl());
+ scene.getStylesheets().add(ResourceManager.get(layoutSize + ".css").getUrl());
- reloadAll();
- }
+ reloadAll();
+ }
- public static int getWidth() {
- return width;
- }
+ public static int getWidth() {
+ return width;
+ }
- public static int getHeight() {
- return height;
- }
-}
\ No newline at end of file
+ public static int getHeight() {
+ return height;
+ }
+}
diff --git a/app/src/main/java/org/toop/app/GameInformation.java b/app/src/main/java/org/toop/app/GameInformation.java
index fd7c56e..2a3e56f 100644
--- a/app/src/main/java/org/toop/app/GameInformation.java
+++ b/app/src/main/java/org/toop/app/GameInformation.java
@@ -1,6 +1,10 @@
package org.toop.app;
-public record GameInformation(String[] playerName, boolean[] isPlayerHuman,
- int[] computerDifficulty, int[] computerThinkTime,
- boolean isConnectionLocal, String serverIP, String serverPort) {
-}
+public record GameInformation(
+ String[] playerName,
+ boolean[] isPlayerHuman,
+ int[] computerDifficulty,
+ int[] computerThinkTime,
+ boolean isConnectionLocal,
+ String serverIP,
+ String serverPort) {}
diff --git a/app/src/main/java/org/toop/app/canvas/GameCanvas.java b/app/src/main/java/org/toop/app/canvas/GameCanvas.java
index 5d4b56d..5ed5775 100644
--- a/app/src/main/java/org/toop/app/canvas/GameCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/GameCanvas.java
@@ -1,123 +1,130 @@
package org.toop.app.canvas;
+import java.util.function.Consumer;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseButton;
import javafx.scene.paint.Color;
-import java.util.function.Consumer;
-
public abstract class GameCanvas {
- protected record Cell(float x, float y, float width, float height) {
- }
+ protected record Cell(float x, float y, float width, float height) {}
- protected final Canvas canvas;
- protected final GraphicsContext graphics;
+ protected final Canvas canvas;
+ protected final GraphicsContext graphics;
- protected final Color color;
+ protected final Color color;
- protected int width;
- protected int height;
+ protected int width;
+ protected int height;
- protected final int rows;
- protected final int columns;
+ protected final int rows;
+ protected final int columns;
- protected final int gapSize;
- protected final boolean edges;
+ protected final int gapSize;
+ protected final boolean edges;
- protected final Cell[] cells;
+ protected final Cell[] cells;
- protected GameCanvas(Color color, int width, int height, int rows, int columns, int gapSize, boolean edges, Consumer onCellClicked) {
- canvas = new Canvas(width, height);
- graphics = canvas.getGraphicsContext2D();
+ protected GameCanvas(
+ Color color,
+ int width,
+ int height,
+ int rows,
+ int columns,
+ int gapSize,
+ boolean edges,
+ Consumer onCellClicked) {
+ canvas = new Canvas(width, height);
+ graphics = canvas.getGraphicsContext2D();
- this.color = color;
+ this.color = color;
- this.width = width;
- this.height = height;
+ this.width = width;
+ this.height = height;
- this.rows = rows;
- this.columns = columns;
+ this.rows = rows;
+ this.columns = columns;
- this.gapSize = gapSize;
- this.edges = edges;
+ this.gapSize = gapSize;
+ this.edges = edges;
- cells = new Cell[rows * columns];
+ cells = new Cell[rows * columns];
- final float cellWidth = ((float) width - (rows - 1) * gapSize) / rows;
- final float cellHeight = ((float) height - (columns - 1) * gapSize) / columns;
+ final float cellWidth = ((float) width - (rows - 1) * gapSize) / rows;
+ final float cellHeight = ((float) height - (columns - 1) * gapSize) / columns;
- for (int y = 0; y < columns; y++) {
- final float startY = y * cellHeight + y * gapSize;
+ for (int y = 0; y < columns; y++) {
+ final float startY = y * cellHeight + y * gapSize;
- for (int x = 0; x < rows; x++) {
- final float startX = x * cellWidth + x * gapSize;
- cells[y * rows + x] = new Cell(startX, startY, cellWidth, cellHeight);
- }
- }
+ for (int x = 0; x < rows; x++) {
+ final float startX = x * cellWidth + x * gapSize;
+ cells[y * rows + x] = new Cell(startX, startY, cellWidth, cellHeight);
+ }
+ }
- canvas.setOnMouseClicked(event -> {
- if (event.getButton() != MouseButton.PRIMARY) {
- return;
- }
+ canvas.setOnMouseClicked(
+ event -> {
+ if (event.getButton() != MouseButton.PRIMARY) {
+ return;
+ }
- final int column = (int) ((event.getX() / width) * rows);
- final int row = (int) ((event.getY() / height) * columns);
+ final int column = (int) ((event.getX() / width) * rows);
+ final int row = (int) ((event.getY() / height) * columns);
- event.consume();
- onCellClicked.accept(row * rows + column);
- });
+ event.consume();
+ onCellClicked.accept(row * rows + column);
+ });
- render();
- }
+ render();
+ }
- public void clear() {
- graphics.clearRect(0, 0, width, height);
- }
+ public void clear() {
+ graphics.clearRect(0, 0, width, height);
+ }
- public void render() {
- graphics.setFill(color);
+ public void render() {
+ graphics.setFill(color);
- for (int x = 1; x < rows; x++) {
- graphics.fillRect(cells[x].x() - gapSize, 0, gapSize, height);
- }
+ for (int x = 1; x < rows; x++) {
+ graphics.fillRect(cells[x].x() - gapSize, 0, gapSize, height);
+ }
- for (int y = 1; y < columns; y++) {
- graphics.fillRect(0, cells[y * rows].y() - gapSize, width, gapSize);
- }
+ for (int y = 1; y < columns; y++) {
+ graphics.fillRect(0, cells[y * rows].y() - gapSize, width, gapSize);
+ }
- if (edges) {
- graphics.fillRect(-gapSize, 0, gapSize, height);
- graphics.fillRect(0, -gapSize, width, gapSize);
+ if (edges) {
+ graphics.fillRect(-gapSize, 0, gapSize, height);
+ graphics.fillRect(0, -gapSize, width, gapSize);
- graphics.fillRect(width - gapSize, 0, gapSize, height);
- graphics.fillRect(0, height - gapSize, width, gapSize);
- }
- }
+ graphics.fillRect(width - gapSize, 0, gapSize, height);
+ graphics.fillRect(0, height - gapSize, width, gapSize);
+ }
+ }
- public void draw(Color color, int cell) {
- final float x = cells[cell].x() + gapSize;
- final float y = cells[cell].y() + gapSize;
+ public void draw(Color color, int cell) {
+ final float x = cells[cell].x() + gapSize;
+ final float y = cells[cell].y() + gapSize;
- final float width = cells[cell].width() - gapSize * 2;
- final float height = cells[cell].height() - gapSize * 2;
+ final float width = cells[cell].width() - gapSize * 2;
+ final float height = cells[cell].height() - gapSize * 2;
- graphics.setFill(color);
- graphics.fillRect(x, y, width, height);
- }
+ graphics.setFill(color);
+ graphics.fillRect(x, y, width, height);
+ }
- public void resize(int width, int height) {
- canvas.setWidth(width);
- canvas.setHeight(height);
+ public void resize(int width, int height) {
+ canvas.setWidth(width);
+ canvas.setHeight(height);
- this.width = width;
- this.height = height;
+ this.width = width;
+ this.height = height;
- clear();
- render();
- }
+ clear();
+ render();
+ }
- public Canvas getCanvas() {
- return canvas;
- }
-}
\ No newline at end of file
+ public Canvas getCanvas() {
+ return canvas;
+ }
+}
diff --git a/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java b/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java
index 0f7cbb9..1838335 100644
--- a/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java
@@ -1,38 +1,37 @@
package org.toop.app.canvas;
+import java.util.function.Consumer;
import javafx.scene.paint.Color;
-import java.util.function.Consumer;
-
public class TicTacToeCanvas extends GameCanvas {
- public TicTacToeCanvas(Color color, int width, int height, Consumer onCellClicked) {
- super(color, width, height, 3, 3, 10, false, onCellClicked);
- }
+ public TicTacToeCanvas(Color color, int width, int height, Consumer onCellClicked) {
+ super(color, width, height, 3, 3, 10, false, onCellClicked);
+ }
- public void drawX(Color color, int cell) {
- graphics.setStroke(color);
- graphics.setLineWidth(gapSize);
+ public void drawX(Color color, int cell) {
+ graphics.setStroke(color);
+ graphics.setLineWidth(gapSize);
- final float x = cells[cell].x() + gapSize;
- final float y = cells[cell].y() + gapSize;
+ final float x = cells[cell].x() + gapSize;
+ final float y = cells[cell].y() + gapSize;
- final float width = cells[cell].width() - gapSize * 2;
- final float height = cells[cell].height() - gapSize * 2;
+ final float width = cells[cell].width() - gapSize * 2;
+ final float height = cells[cell].height() - gapSize * 2;
- graphics.strokeLine(x, y, x + width, y + height);
- graphics.strokeLine(x + width, y, x, y + height);
- }
+ graphics.strokeLine(x, y, x + width, y + height);
+ graphics.strokeLine(x + width, y, x, y + height);
+ }
- public void drawO(Color color, int cell) {
- graphics.setStroke(color);
- graphics.setLineWidth(gapSize);
+ public void drawO(Color color, int cell) {
+ graphics.setStroke(color);
+ graphics.setLineWidth(gapSize);
- final float x = cells[cell].x() + gapSize;
- final float y = cells[cell].y() + gapSize;
+ final float x = cells[cell].x() + gapSize;
+ final float y = cells[cell].y() + gapSize;
- final float width = cells[cell].width() - gapSize * 2;
- final float height = cells[cell].height() - gapSize * 2;
+ final float width = cells[cell].width() - gapSize * 2;
+ final float height = cells[cell].height() - gapSize * 2;
- graphics.strokeOval(x, y, width, height);
- }
-}
\ No newline at end of file
+ graphics.strokeOval(x, y, width, height);
+ }
+}
diff --git a/app/src/main/java/org/toop/app/layer/Container.java b/app/src/main/java/org/toop/app/layer/Container.java
index 409c0eb..89e6436 100644
--- a/app/src/main/java/org/toop/app/layer/Container.java
+++ b/app/src/main/java/org/toop/app/layer/Container.java
@@ -4,8 +4,9 @@ import javafx.scene.Node;
import javafx.scene.layout.Region;
public abstract class Container {
- public abstract Region getContainer();
+ public abstract Region getContainer();
- public abstract void addNodes(Node... nodes);
- public abstract void addContainer(Container container, boolean fill);
-}
\ No newline at end of file
+ public abstract void addNodes(Node... nodes);
+
+ public abstract void addContainer(Container container, boolean fill);
+}
diff --git a/app/src/main/java/org/toop/app/layer/Layer.java b/app/src/main/java/org/toop/app/layer/Layer.java
index 35034c9..d357200 100644
--- a/app/src/main/java/org/toop/app/layer/Layer.java
+++ b/app/src/main/java/org/toop/app/layer/Layer.java
@@ -1,81 +1,86 @@
package org.toop.app.layer;
-import org.toop.app.App;
-import org.toop.app.canvas.GameCanvas;
-
import javafx.geometry.Pos;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
+import org.toop.app.App;
+import org.toop.app.canvas.GameCanvas;
public abstract class Layer {
- protected StackPane layer;
- protected Region background;
+ protected StackPane layer;
+ protected Region background;
- protected Layer(String... backgroundStyles) {
- layer = new StackPane();
+ protected Layer(String... backgroundStyles) {
+ layer = new StackPane();
- background = new Region();
- background.getStyleClass().addAll(backgroundStyles);
- background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
+ background = new Region();
+ background.getStyleClass().addAll(backgroundStyles);
+ background.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
- layer.getChildren().addLast(background);
- }
+ layer.getChildren().addLast(background);
+ }
- protected void addContainer(Container container, Pos position, int xOffset, int yOffset, int widthPercent, int heightPercent) {
- StackPane.setAlignment(container.getContainer(), position);
+ protected void addContainer(
+ Container container,
+ Pos position,
+ int xOffset,
+ int yOffset,
+ int widthPercent,
+ int heightPercent) {
+ StackPane.setAlignment(container.getContainer(), position);
- final double widthUnit = App.getWidth() / 100.0;
- final double heightUnit = App.getHeight() / 100.0;
+ final double widthUnit = App.getWidth() / 100.0;
+ final double heightUnit = App.getHeight() / 100.0;
- if (widthPercent > 0) {
- container.getContainer().setMaxWidth(widthPercent * widthUnit);
- } else {
- container.getContainer().setMaxWidth(Region.USE_PREF_SIZE);
- }
+ if (widthPercent > 0) {
+ container.getContainer().setMaxWidth(widthPercent * widthUnit);
+ } else {
+ container.getContainer().setMaxWidth(Region.USE_PREF_SIZE);
+ }
- if (heightPercent > 0) {
- container.getContainer().setMaxHeight(heightPercent * heightUnit);
- } else {
- container.getContainer().setMaxHeight(Region.USE_PREF_SIZE);
- }
+ if (heightPercent > 0) {
+ container.getContainer().setMaxHeight(heightPercent * heightUnit);
+ } else {
+ container.getContainer().setMaxHeight(Region.USE_PREF_SIZE);
+ }
- container.getContainer().setTranslateX(xOffset * widthUnit);
- container.getContainer().setTranslateY(yOffset * heightUnit);
+ container.getContainer().setTranslateX(xOffset * widthUnit);
+ container.getContainer().setTranslateY(yOffset * heightUnit);
- layer.getChildren().addLast(container.getContainer());
- }
+ layer.getChildren().addLast(container.getContainer());
+ }
- protected void addGameCanvas(GameCanvas canvas, Pos position, int xOffset, int yOffset) {
- StackPane.setAlignment(canvas.getCanvas(), position);
+ protected void addGameCanvas(GameCanvas canvas, Pos position, int xOffset, int yOffset) {
+ StackPane.setAlignment(canvas.getCanvas(), position);
- final double widthUnit = App.getWidth() / 100.0;
- final double heightUnit = App.getHeight() / 100.0;
+ final double widthUnit = App.getWidth() / 100.0;
+ final double heightUnit = App.getHeight() / 100.0;
- canvas.getCanvas().setTranslateX(xOffset * widthUnit);
- canvas.getCanvas().setTranslateY(yOffset * heightUnit);
+ canvas.getCanvas().setTranslateX(xOffset * widthUnit);
+ canvas.getCanvas().setTranslateY(yOffset * heightUnit);
- layer.getChildren().addLast(canvas.getCanvas());
- }
+ layer.getChildren().addLast(canvas.getCanvas());
+ }
- protected void pop() {
- if (layer.getChildren().size() <= 1) {
- return;
- }
+ protected void pop() {
+ if (layer.getChildren().size() <= 1) {
+ return;
+ }
- layer.getChildren().removeLast();
- }
+ layer.getChildren().removeLast();
+ }
- protected void popAll() {
- final int containers = layer.getChildren().size();
+ protected void popAll() {
+ final int containers = layer.getChildren().size();
- for (int i = 1; i < containers; i++) {
- layer.getChildren().removeLast();
- }
- }
+ for (int i = 1; i < containers; i++) {
+ layer.getChildren().removeLast();
+ }
+ }
- public StackPane getLayer() {
- return layer;
- }
+ public StackPane getLayer() {
+ return layer;
+ }
- public abstract void reload();
-}
\ No newline at end of file
+ public abstract void reload();
+}
diff --git a/app/src/main/java/org/toop/app/layer/NodeBuilder.java b/app/src/main/java/org/toop/app/layer/NodeBuilder.java
index a0f2996..b55a70d 100644
--- a/app/src/main/java/org/toop/app/layer/NodeBuilder.java
+++ b/app/src/main/java/org/toop/app/layer/NodeBuilder.java
@@ -1,131 +1,140 @@
package org.toop.app.layer;
-import org.toop.framework.audio.events.AudioEvents;
-import org.toop.framework.eventbus.EventFlow;
-
+import java.util.function.Consumer;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.text.Text;
-
-import java.util.function.Consumer;
+import org.toop.framework.audio.events.AudioEvents;
+import org.toop.framework.eventbus.EventFlow;
public final class NodeBuilder {
- public static void addCss(Node node, String... cssClasses) {
- node.getStyleClass().addAll(cssClasses);
- }
+ public static void addCss(Node node, String... cssClasses) {
+ node.getStyleClass().addAll(cssClasses);
+ }
- public static void setCss(Node node, String... cssClasses) {
- node.getStyleClass().removeAll();
- node.getStyleClass().addAll(cssClasses);
- }
+ public static void setCss(Node node, String... cssClasses) {
+ node.getStyleClass().removeAll();
+ node.getStyleClass().addAll(cssClasses);
+ }
- public static Text header(String x) {
- final Text element = new Text(x);
- setCss(element, "text-primary", "text-header");
+ public static Text header(String x) {
+ final Text element = new Text(x);
+ setCss(element, "text-primary", "text-header");
- return element;
- }
+ return element;
+ }
- public static Text text(String x) {
- final Text element = new Text(x);
- setCss(element, "text-secondary", "text-normal");
+ public static Text text(String x) {
+ final Text element = new Text(x);
+ setCss(element, "text-secondary", "text-normal");
- return element;
- }
+ return element;
+ }
- public static Label button(String x, Runnable runnable) {
- final Label element = new Label(x);
- setCss(element, "button", "text-normal");
+ public static Label button(String x, Runnable runnable) {
+ final Label element = new Label(x);
+ setCss(element, "button", "text-normal");
- element.setOnMouseClicked(_ -> {
- new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
- runnable.run();
- });
+ element.setOnMouseClicked(
+ _ -> {
+ new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
+ runnable.run();
+ });
- return element;
- }
+ return element;
+ }
- public static Label toggle(String x1, String x2, boolean toggled, Consumer consumer) {
- final Label element = new Label(toggled ? x2 : x1);
- setCss(element, "toggle", "text-normal");
+ public static Label toggle(String x1, String x2, boolean toggled, Consumer consumer) {
+ final Label element = new Label(toggled ? x2 : x1);
+ setCss(element, "toggle", "text-normal");
- final BooleanProperty checked = new SimpleBooleanProperty(toggled);
+ final BooleanProperty checked = new SimpleBooleanProperty(toggled);
- element.setOnMouseClicked(_ -> {
- new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
- checked.set(!checked.get());
+ element.setOnMouseClicked(
+ _ -> {
+ new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
+ checked.set(!checked.get());
- if (checked.get()) {
- element.setText(x1);
- } else {
- element.setText(x2);
- }
+ if (checked.get()) {
+ element.setText(x1);
+ } else {
+ element.setText(x2);
+ }
- consumer.accept(checked.get());
- });
+ consumer.accept(checked.get());
+ });
- return element;
- }
+ return element;
+ }
- public static Slider slider(int max, int initial, Consumer consumer) {
- final Slider element = new Slider(0, max, initial);
- setCss(element, "bg-slider-track");
+ public static Slider slider(int max, int initial, Consumer consumer) {
+ final Slider element = new Slider(0, max, initial);
+ setCss(element, "bg-slider-track");
- element.setMinorTickCount(0);
- element.setMajorTickUnit(1);
- element.setBlockIncrement(1);
+ element.setMinorTickCount(0);
+ element.setMajorTickUnit(1);
+ element.setBlockIncrement(1);
- element.setSnapToTicks(true);
- element.setShowTickLabels(true);
+ element.setSnapToTicks(true);
+ element.setShowTickLabels(true);
- element.setOnMouseClicked(_ -> {
- new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
- });
+ element.setOnMouseClicked(
+ _ -> {
+ new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
+ });
- element.valueProperty().addListener((_, _, newValue) -> {
- consumer.accept(newValue.intValue());
- });
+ element.valueProperty()
+ .addListener(
+ (_, _, newValue) -> {
+ consumer.accept(newValue.intValue());
+ });
- return element;
- }
+ return element;
+ }
- public static TextField input(String x, Consumer consumer) {
- final TextField element = new TextField(x);
- setCss(element, "input", "text-normal");
+ public static TextField input(String x, Consumer consumer) {
+ final TextField element = new TextField(x);
+ setCss(element, "input", "text-normal");
- element.setOnMouseClicked(_ -> {
- new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
- });
+ element.setOnMouseClicked(
+ _ -> {
+ new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
+ });
- element.textProperty().addListener((_, _, newValue) -> {
- consumer.accept(newValue);
- });
+ element.textProperty()
+ .addListener(
+ (_, _, newValue) -> {
+ consumer.accept(newValue);
+ });
- return element;
- }
+ return element;
+ }
- public static ChoiceBox choiceBox(Consumer consumer) {
- final ChoiceBox element = new ChoiceBox<>();
- setCss(element, "choice-box", "text-normal");
+ public static ChoiceBox choiceBox(Consumer consumer) {
+ final ChoiceBox element = new ChoiceBox<>();
+ setCss(element, "choice-box", "text-normal");
- element.setOnMouseClicked(_ -> {
- new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
- });
+ element.setOnMouseClicked(
+ _ -> {
+ new EventFlow().addPostEvent(new AudioEvents.ClickButton()).asyncPostEvent();
+ });
- element.valueProperty().addListener((_, _, newValue) -> {
- consumer.accept(newValue);
- });
+ element.valueProperty()
+ .addListener(
+ (_, _, newValue) -> {
+ consumer.accept(newValue);
+ });
- return element;
- }
+ return element;
+ }
- public static Separator separator() {
- final Separator element = new Separator(Orientation.HORIZONTAL);
- setCss(element, "separator");
+ public static Separator separator() {
+ final Separator element = new Separator(Orientation.HORIZONTAL);
+ setCss(element, "separator");
- return element;
- }
-}
\ No newline at end of file
+ return element;
+ }
+}
diff --git a/app/src/main/java/org/toop/app/layer/Popup.java b/app/src/main/java/org/toop/app/layer/Popup.java
index 6a54bec..7e498df 100644
--- a/app/src/main/java/org/toop/app/layer/Popup.java
+++ b/app/src/main/java/org/toop/app/layer/Popup.java
@@ -3,17 +3,18 @@ package org.toop.app.layer;
import org.toop.app.App;
public abstract class Popup extends Layer {
- protected Popup(boolean popOnBackground, String... backgroundStyles) {
- super(backgroundStyles);
+ protected Popup(boolean popOnBackground, String... backgroundStyles) {
+ super(backgroundStyles);
- if (popOnBackground) {
- background.setOnMouseClicked(_ -> {
- App.pop();
- });
- }
- }
+ if (popOnBackground) {
+ background.setOnMouseClicked(
+ _ -> {
+ App.pop();
+ });
+ }
+ }
- protected Popup(boolean popOnBackground) {
- this(popOnBackground, "bg-popup");
- }
-}
\ No newline at end of file
+ protected Popup(boolean popOnBackground) {
+ this(popOnBackground, "bg-popup");
+ }
+}
diff --git a/app/src/main/java/org/toop/app/layer/containers/HorizontalContainer.java b/app/src/main/java/org/toop/app/layer/containers/HorizontalContainer.java
index b3f00a5..2350216 100644
--- a/app/src/main/java/org/toop/app/layer/containers/HorizontalContainer.java
+++ b/app/src/main/java/org/toop/app/layer/containers/HorizontalContainer.java
@@ -1,60 +1,59 @@
package org.toop.app.layer.containers;
-import org.toop.app.layer.Container;
-
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
+import org.toop.app.layer.Container;
public final class HorizontalContainer extends Container {
- private final HBox container;
+ private final HBox container;
- public HorizontalContainer(int spacing, String... cssClasses) {
- container = new HBox(spacing);
- container.getStyleClass().addAll(cssClasses);
- }
+ public HorizontalContainer(int spacing, String... cssClasses) {
+ container = new HBox(spacing);
+ container.getStyleClass().addAll(cssClasses);
+ }
- public HorizontalContainer(int spacing) {
- this(spacing, "container");
- }
+ public HorizontalContainer(int spacing) {
+ this(spacing, "container");
+ }
- @Override
- public Region getContainer() {
- return container;
- }
+ @Override
+ public Region getContainer() {
+ return container;
+ }
- @Override
- public void addNodes(Node... nodes) {
- container.getChildren().addAll(nodes);
- }
+ @Override
+ public void addNodes(Node... nodes) {
+ container.getChildren().addAll(nodes);
+ }
- @Override
- public void addContainer(Container container, boolean fill) {
- if (fill) {
- container.getContainer().setMinSize(0, 0);
- container.getContainer().setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
- HBox.setHgrow(container.getContainer(), Priority.ALWAYS);
- } else {
- container.getContainer().setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
- }
+ @Override
+ public void addContainer(Container container, boolean fill) {
+ if (fill) {
+ container.getContainer().setMinSize(0, 0);
+ container.getContainer().setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
+ HBox.setHgrow(container.getContainer(), Priority.ALWAYS);
+ } else {
+ container.getContainer().setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
+ }
- this.container.getChildren().add(container.getContainer());
+ this.container.getChildren().add(container.getContainer());
- if (fill) {
- balanceChildWidths();
- }
- }
+ if (fill) {
+ balanceChildWidths();
+ }
+ }
- private void balanceChildWidths() {
- final ObservableList children = container.getChildren();
- final double widthPerChild = container.getWidth() / children.size();
+ private void balanceChildWidths() {
+ final ObservableList children = container.getChildren();
+ final double widthPerChild = container.getWidth() / children.size();
- for (final Node child : children) {
- if (child instanceof Region) {
- ((Region) child).setPrefWidth(widthPerChild);
- }
- }
- }
-}
\ No newline at end of file
+ for (final Node child : children) {
+ if (child instanceof Region) {
+ ((Region) child).setPrefWidth(widthPerChild);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/toop/app/layer/containers/VerticalContainer.java b/app/src/main/java/org/toop/app/layer/containers/VerticalContainer.java
index a8fb74d..56d610c 100644
--- a/app/src/main/java/org/toop/app/layer/containers/VerticalContainer.java
+++ b/app/src/main/java/org/toop/app/layer/containers/VerticalContainer.java
@@ -1,60 +1,59 @@
package org.toop.app.layer.containers;
-import org.toop.app.layer.Container;
-
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
+import org.toop.app.layer.Container;
public final class VerticalContainer extends Container {
- private final VBox container;
+ private final VBox container;
- public VerticalContainer(int spacing, String... cssClasses) {
- container = new VBox(spacing);
- container.getStyleClass().addAll(cssClasses);
- }
+ public VerticalContainer(int spacing, String... cssClasses) {
+ container = new VBox(spacing);
+ container.getStyleClass().addAll(cssClasses);
+ }
- public VerticalContainer(int spacing) {
- this(spacing, "container");
- }
+ public VerticalContainer(int spacing) {
+ this(spacing, "container");
+ }
- @Override
- public Region getContainer() {
- return container;
- }
+ @Override
+ public Region getContainer() {
+ return container;
+ }
- @Override
- public void addNodes(Node... nodes) {
- container.getChildren().addAll(nodes);
- }
+ @Override
+ public void addNodes(Node... nodes) {
+ container.getChildren().addAll(nodes);
+ }
- @Override
- public void addContainer(Container container, boolean fill) {
- if (fill) {
- container.getContainer().setMinSize(0, 0);
- container.getContainer().setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
- VBox.setVgrow(container.getContainer(), Priority.ALWAYS);
- } else {
- container.getContainer().setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
- }
+ @Override
+ public void addContainer(Container container, boolean fill) {
+ if (fill) {
+ container.getContainer().setMinSize(0, 0);
+ container.getContainer().setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
+ VBox.setVgrow(container.getContainer(), Priority.ALWAYS);
+ } else {
+ container.getContainer().setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
+ }
- this.container.getChildren().add(container.getContainer());
+ this.container.getChildren().add(container.getContainer());
- if (fill) {
- balanceChildHeights();
- }
- }
+ if (fill) {
+ balanceChildHeights();
+ }
+ }
- private void balanceChildHeights() {
- final ObservableList children = container.getChildren();
- final double heightPerChild = container.getHeight() / children.size();
+ private void balanceChildHeights() {
+ final ObservableList children = container.getChildren();
+ final double heightPerChild = container.getHeight() / children.size();
- for (final Node child : children) {
- if (child instanceof Region) {
- ((Region) child).setPrefHeight(heightPerChild);
- }
- }
- }
-}
\ No newline at end of file
+ for (final Node child : children) {
+ if (child instanceof Region) {
+ ((Region) child).setPrefHeight(heightPerChild);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/toop/app/layer/layers/ConnectedLayer.java b/app/src/main/java/org/toop/app/layer/layers/ConnectedLayer.java
index ff9e7ce..b255c3d 100644
--- a/app/src/main/java/org/toop/app/layer/layers/ConnectedLayer.java
+++ b/app/src/main/java/org/toop/app/layer/layers/ConnectedLayer.java
@@ -1,6 +1,14 @@
package org.toop.app.layer.layers;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Platform;
+import javafx.geometry.Pos;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListView;
import org.toop.app.App;
import org.toop.app.GameInformation;
import org.toop.app.layer.Container;
@@ -14,169 +22,214 @@ import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.networking.events.NetworkEvents;
import org.toop.local.AppContext;
-import javafx.geometry.Pos;
-import javafx.scene.control.Label;
-import javafx.scene.control.ListView;
-
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-
public final class ConnectedLayer extends Layer {
- private static Timer pollTimer = new Timer();
+ private static Timer pollTimer = new Timer();
- private static class ChallengePopup extends Popup {
- private final GameInformation information;
+ private static class ChallengePopup extends Popup {
+ private final GameInformation information;
- private final String challenger;
- private final String game;
+ private final String challenger;
+ private final String game;
- private final long clientID;
- private final int challengeID;
+ private final long clientID;
+ private final int challengeID;
- public ChallengePopup(GameInformation information, String challenger, String game, long clientID, String challengeID) {
- super(false, "bg-popup");
+ public ChallengePopup(
+ GameInformation information,
+ String challenger,
+ String game,
+ long clientID,
+ String challengeID) {
+ super(false, "bg-popup");
- this.information = information;
+ this.information = information;
- this.challenger = challenger;
- this.game = game;
+ this.challenger = challenger;
+ this.game = game;
- this.clientID = clientID;
- this.challengeID = Integer.parseInt(challengeID.substring(18, challengeID.length() - 2));
+ this.clientID = clientID;
+ this.challengeID =
+ Integer.parseInt(challengeID.substring(18, challengeID.length() - 2));
- reload();
- }
+ reload();
+ }
- @Override
- public void reload() {
- popAll();
+ @Override
+ public void reload() {
+ popAll();
- final var challengeText = NodeBuilder.header(AppContext.getString("challengeText"));
- final var challengerNameText = NodeBuilder.header(challenger);
+ final var challengeText = NodeBuilder.header(AppContext.getString("challengeText"));
+ final var challengerNameText = NodeBuilder.header(challenger);
- final var gameText = NodeBuilder.text(AppContext.getString("gameIsText"));
- final var gameNameText = NodeBuilder.text(game);
+ final var gameText = NodeBuilder.text(AppContext.getString("gameIsText"));
+ final var gameNameText = NodeBuilder.text(game);
- final var acceptButton = NodeBuilder.button(AppContext.getString("accept"), () -> {
- pollTimer.cancel();
+ final var acceptButton =
+ NodeBuilder.button(
+ AppContext.getString("accept"),
+ () -> {
+ pollTimer.cancel();
- new EventFlow().addPostEvent(new NetworkEvents.SendAcceptChallenge(clientID, challengeID)).postEvent();
- App.activate(new TicTacToeLayer(information, clientID));
- });
+ new EventFlow()
+ .addPostEvent(
+ new NetworkEvents.SendAcceptChallenge(
+ clientID, challengeID))
+ .postEvent();
+ App.activate(new TicTacToeLayer(information, clientID));
+ });
- final var denyButton = NodeBuilder.button(AppContext.getString("deny"), () -> {
- App.pop();
- });
+ final var denyButton =
+ NodeBuilder.button(
+ AppContext.getString("deny"),
+ () -> {
+ App.pop();
+ });
- final Container controlContainer = new HorizontalContainer(30);
- controlContainer.addNodes(acceptButton, denyButton);
+ final Container controlContainer = new HorizontalContainer(30);
+ controlContainer.addNodes(acceptButton, denyButton);
- final Container mainContainer = new VerticalContainer(30);
- mainContainer.addNodes(challengeText, challengerNameText);
- mainContainer.addNodes(gameText, gameNameText);
+ final Container mainContainer = new VerticalContainer(30);
+ mainContainer.addNodes(challengeText, challengerNameText);
+ mainContainer.addNodes(gameText, gameNameText);
- mainContainer.addContainer(controlContainer, false);
+ mainContainer.addContainer(controlContainer, false);
- addContainer(mainContainer, Pos.CENTER, 0, 0, 30, 30);
- }
- }
+ addContainer(mainContainer, Pos.CENTER, 0, 0, 30, 30);
+ }
+ }
- GameInformation information;
- long clientId;
- String user;
- List onlinePlayers = new CopyOnWriteArrayList<>();
+ GameInformation information;
+ long clientId;
+ String user;
+ List onlinePlayers = new CopyOnWriteArrayList<>();
- public ConnectedLayer(GameInformation information) {
- super("bg-primary");
+ public ConnectedLayer(GameInformation information) {
+ super("bg-primary");
- this.information = information;
+ this.information = information;
- new EventFlow()
- .addPostEvent(NetworkEvents.StartClient.class, information.serverIP(), Integer.parseInt(information.serverPort()))
- .onResponse(NetworkEvents.StartClientResponse.class, e -> {
- clientId = e.clientId();
- user = information.playerName()[0].replaceAll("\\s+", "");
+ new EventFlow()
+ .addPostEvent(
+ NetworkEvents.StartClient.class,
+ information.serverIP(),
+ Integer.parseInt(information.serverPort()))
+ .onResponse(
+ NetworkEvents.StartClientResponse.class,
+ e -> {
+ clientId = e.clientId();
+ user = information.playerName()[0].replaceAll("\\s+", "");
- new EventFlow().addPostEvent(new NetworkEvents.SendLogin(this.clientId, this.user)).postEvent();
+ new EventFlow()
+ .addPostEvent(
+ new NetworkEvents.SendLogin(this.clientId, this.user))
+ .postEvent();
- Thread popThread = new Thread(this::populatePlayerList);
- popThread.setDaemon(false);
- popThread.start();
- }).postEvent();
+ Thread popThread = new Thread(this::populatePlayerList);
+ popThread.setDaemon(false);
+ popThread.start();
+ })
+ .postEvent();
- new EventFlow().listen(this::handleReceivedChallenge);
+ new EventFlow().listen(this::handleReceivedChallenge);
reload();
- }
+ }
- private void populatePlayerList() {
- EventFlow sendGetPlayerList = new EventFlow().addPostEvent(new NetworkEvents.SendGetPlayerlist(this.clientId));
- new EventFlow().listen(NetworkEvents.PlayerlistResponse.class, e -> {
- if (e.clientId() == this.clientId) {
- List playerList = new java.util.ArrayList<>(List.of(e.playerlist())); // TODO: Garbage, but works
- playerList.removeIf(name -> name.equalsIgnoreCase(user));
- if (this.onlinePlayers != playerList) {
- this.onlinePlayers.clear();
- this.onlinePlayers.addAll(playerList);
- }
- }
- });
+ private void populatePlayerList() {
+ EventFlow sendGetPlayerList =
+ new EventFlow().addPostEvent(new NetworkEvents.SendGetPlayerlist(this.clientId));
+ new EventFlow()
+ .listen(
+ NetworkEvents.PlayerlistResponse.class,
+ e -> {
+ if (e.clientId() == this.clientId) {
+ List playerList =
+ new java.util.ArrayList<>(
+ List.of(e.playerlist())); // TODO: Garbage,
+ // but works
+ playerList.removeIf(name -> name.equalsIgnoreCase(user));
+ if (this.onlinePlayers != playerList) {
+ this.onlinePlayers.clear();
+ this.onlinePlayers.addAll(playerList);
+ }
+ }
+ });
- TimerTask task = new TimerTask() {
- public void run() {
- sendGetPlayerList.postEvent();
- Platform.runLater(() -> reload());
- }
- };
+ TimerTask task =
+ new TimerTask() {
+ public void run() {
+ sendGetPlayerList.postEvent();
+ Platform.runLater(() -> reload());
+ }
+ };
- pollTimer.schedule(task, 0L, 5000L); // TODO: Block app exit, fix later
- }
+ pollTimer.schedule(task, 0L, 5000L); // TODO: Block app exit, fix later
+ }
- private void sendChallenge(String oppUsername, String gameType) {
- final AtomicInteger challengeId = new AtomicInteger(-1);
+ private void sendChallenge(String oppUsername, String gameType) {
+ final AtomicInteger challengeId = new AtomicInteger(-1);
- if (onlinePlayers.contains(oppUsername)) {
- new EventFlow().addPostEvent(new NetworkEvents.SendChallenge(this.clientId, oppUsername, gameType))
- .listen(NetworkEvents.ChallengeResponse.class, e -> {
- challengeId.set(Integer.parseInt(e.challengeId().substring(18, e.challengeId().length() - 2)));
- })
- .listen(NetworkEvents.GameMatchResponse.class, e -> {
- if (e.clientId() == this.clientId) {
- pollTimer.cancel();
- App.activate(new TicTacToeLayer(information, this.clientId));
- }
- }, false).postEvent();
- // ^
- // |
- // |
- // |
- }
- }
+ if (onlinePlayers.contains(oppUsername)) {
+ new EventFlow()
+ .addPostEvent(
+ new NetworkEvents.SendChallenge(this.clientId, oppUsername, gameType))
+ .listen(
+ NetworkEvents.ChallengeResponse.class,
+ e -> {
+ challengeId.set(
+ Integer.parseInt(
+ e.challengeId()
+ .substring(
+ 18, e.challengeId().length() - 2)));
+ })
+ .listen(
+ NetworkEvents.GameMatchResponse.class,
+ e -> {
+ if (e.clientId() == this.clientId) {
+ pollTimer.cancel();
+ App.activate(new TicTacToeLayer(information, this.clientId));
+ }
+ },
+ false)
+ .postEvent();
+ // ^
+ // |
+ // |
+ // |
+ }
+ }
- private void handleReceivedChallenge(NetworkEvents.ChallengeResponse response) {
- App.push(new ChallengePopup(information, response.challengerName(), response.gameType(), clientId, response.challengeId()));
- }
+ private void handleReceivedChallenge(NetworkEvents.ChallengeResponse response) {
+ App.push(
+ new ChallengePopup(
+ information,
+ response.challengerName(),
+ response.gameType(),
+ clientId,
+ response.challengeId()));
+ }
- @Override
- public void reload() {
- popAll();
+ @Override
+ public void reload() {
+ popAll();
- ListView
*
*
This implementation ensures:
+ *
*
- *
IDs are unique per machine.
- *
Monotonicity within the same machine.
- *
Safe concurrent generation via synchronized {@link #nextId()}.
+ *
IDs are unique per machine.
+ *
Monotonicity within the same machine.
+ *
Safe concurrent generation via synchronized {@link #nextId()}.
*
- *
*
- *
Custom epoch is set to {@code 2025-01-01T00:00:00Z}.
+ *
Custom epoch is set to {@code 2025-01-01T00:00:00Z}.
+ *
+ *
Usage example:
*
- *
Usage example:
*
{@code
* SnowflakeGenerator generator = new SnowflakeGenerator();
* long id = generator.nextId();
@@ -34,9 +35,7 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public class SnowflakeGenerator {
- /**
- * Custom epoch in milliseconds (2025-01-01T00:00:00Z).
- */
+ /** Custom epoch in milliseconds (2025-01-01T00:00:00Z). */
private static final long EPOCH = Instant.parse("2025-01-01T00:00:00Z").toEpochMilli();
// Bit allocations
@@ -53,17 +52,15 @@ public class SnowflakeGenerator {
private static final long MACHINE_SHIFT = SEQUENCE_BITS;
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_BITS;
- /**
- * Unique machine identifier derived from network interfaces (10 bits).
- */
+ /** Unique machine identifier derived from network interfaces (10 bits). */
private static final long machineId = SnowflakeGenerator.genMachineId();
private final AtomicLong lastTimestamp = new AtomicLong(-1L);
private long sequence = 0L;
/**
- * Generates a 10-bit machine identifier based on MAC addresses of network interfaces.
- * Falls back to a random value if MAC cannot be determined.
+ * Generates a 10-bit machine identifier based on MAC addresses of network interfaces. Falls
+ * back to a random value if MAC cannot be determined.
*/
private static long genMachineId() {
try {
@@ -82,6 +79,7 @@ public class SnowflakeGenerator {
/**
* For testing: manually set the last generated timestamp.
+ *
* @param l timestamp in milliseconds
*/
void setTime(long l) {
@@ -89,8 +87,8 @@ public class SnowflakeGenerator {
}
/**
- * Constructs a SnowflakeGenerator.
- * Validates that the machine ID is within allowed range.
+ * Constructs a SnowflakeGenerator. Validates that the machine ID is within allowed range.
+ *
* @throws IllegalArgumentException if machine ID is invalid
*/
public SnowflakeGenerator() {
@@ -102,10 +100,9 @@ public class SnowflakeGenerator {
/**
* Generates the next unique ID.
- *
- * If multiple IDs are generated in the same millisecond, a sequence number
- * is incremented. If the sequence overflows, waits until the next millisecond.
- *
+ *
+ *
If multiple IDs are generated in the same millisecond, a sequence number is incremented.
+ * If the sequence overflows, waits until the next millisecond.
*
* @return a unique 64-bit ID
* @throws IllegalStateException if clock moves backwards or timestamp exceeds 41-bit limit
@@ -139,6 +136,7 @@ public class SnowflakeGenerator {
/**
* Waits until the next millisecond if sequence overflows.
+ *
* @param lastTimestamp previous timestamp
* @return new timestamp
*/
@@ -150,9 +148,7 @@ public class SnowflakeGenerator {
return ts;
}
- /**
- * Returns current system timestamp in milliseconds.
- */
+ /** Returns current system timestamp in milliseconds. */
private long timestamp() {
return System.currentTimeMillis();
}
diff --git a/framework/src/main/java/org/toop/framework/asset/ResourceLoader.java b/framework/src/main/java/org/toop/framework/asset/ResourceLoader.java
index 4e69a50..829b982 100644
--- a/framework/src/main/java/org/toop/framework/asset/ResourceLoader.java
+++ b/framework/src/main/java/org/toop/framework/asset/ResourceLoader.java
@@ -1,45 +1,44 @@
package org.toop.framework.asset;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.toop.framework.asset.events.AssetLoaderEvents;
-import org.toop.framework.asset.resources.*;
-import org.toop.framework.asset.types.BundledResource;
-import org.toop.framework.asset.types.FileExtension;
-import org.toop.framework.asset.types.PreloadResource;
-import org.toop.framework.eventbus.EventFlow;
-import org.reflections.Reflections;
-
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.reflections.Reflections;
+import org.toop.framework.asset.events.AssetLoaderEvents;
+import org.toop.framework.asset.resources.*;
+import org.toop.framework.asset.types.BundledResource;
+import org.toop.framework.asset.types.FileExtension;
+import org.toop.framework.asset.types.PreloadResource;
+import org.toop.framework.eventbus.EventFlow;
/**
* Responsible for loading assets from a file system directory into memory.
- *
- * The {@code ResourceLoader} scans a root folder recursively, identifies files,
- * and maps them to registered resource types based on file extensions and
- * {@link FileExtension} annotations.
- * It supports multiple resource types including {@link PreloadResource} (automatically loaded)
- * and {@link BundledResource} (merged across multiple files).
- *
*
- *
Assets are stored in a static, thread-safe list and can be retrieved
- * through {@link ResourceManager}.
+ *
The {@code ResourceLoader} scans a root folder recursively, identifies files, and maps them to
+ * registered resource types based on file extensions and {@link FileExtension} annotations. It
+ * supports multiple resource types including {@link PreloadResource} (automatically loaded) and
+ * {@link BundledResource} (merged across multiple files).
+ *
+ *
Assets are stored in a static, thread-safe list and can be retrieved through {@link
+ * ResourceManager}.
+ *
+ *
Features:
*
- *
Features:
*
- *
Recursive directory scanning for assets.
- *
Automatic registration of resource classes via reflection.
- *
Bundled resource support: multiple files merged into a single resource instance.
Progress tracking via {@link AssetLoaderEvents.LoadingProgressUpdate} events.
*
*
- *
Usage example:
+ *
Usage example:
+ *
*
{@code
* ResourceLoader loader = new ResourceLoader("assets");
* double progress = loader.getProgress();
@@ -48,14 +47,17 @@ import java.util.function.Function;
*/
public class ResourceLoader {
private static final Logger logger = LogManager.getLogger(ResourceLoader.class);
- private static final List> assets = new CopyOnWriteArrayList<>();
- private final Map> registry = new ConcurrentHashMap<>();
+ private static final List> assets =
+ new CopyOnWriteArrayList<>();
+ private final Map> registry =
+ new ConcurrentHashMap<>();
private final AtomicInteger loadedCount = new AtomicInteger(0);
private int totalCount = 0;
/**
* Constructs an ResourceLoader and loads assets from the given root folder.
+ *
* @param rootFolder the folder containing asset files
*/
public ResourceLoader(File rootFolder) {
@@ -84,6 +86,7 @@ public class ResourceLoader {
/**
* Constructs an ResourceLoader from a folder path.
+ *
* @param rootFolder the folder path containing assets
*/
public ResourceLoader(String rootFolder) {
@@ -92,6 +95,7 @@ public class ResourceLoader {
/**
* Returns the current progress of loading assets (0.0 to 1.0).
+ *
* @return progress as a double
*/
public double getProgress() {
@@ -100,6 +104,7 @@ public class ResourceLoader {
/**
* Returns the number of assets loaded so far.
+ *
* @return loaded count
*/
public int getLoadedCount() {
@@ -108,6 +113,7 @@ public class ResourceLoader {
/**
* Returns the total number of files found to load.
+ *
* @return total asset count
*/
public int getTotalCount() {
@@ -116,6 +122,7 @@ public class ResourceLoader {
/**
* Returns a snapshot list of all assets loaded by this loader.
+ *
* @return list of loaded assets
*/
public List> getAssets() {
@@ -124,6 +131,7 @@ public class ResourceLoader {
/**
* Registers a factory for a specific file extension.
+ *
* @param extension the file extension (without dot)
* @param factory a function mapping a File to a resource instance
* @param the type of resource
@@ -132,9 +140,7 @@ public class ResourceLoader {
this.registry.put(extension, factory);
}
- /**
- * Maps a file to a resource instance based on its extension and registered factories.
- */
+ /** Maps a file to a resource instance based on its extension and registered factories. */
private T resourceMapper(File file, Class type) {
String ext = getExtension(file.getName());
Function factory = registry.get(ext);
@@ -144,16 +150,13 @@ public class ResourceLoader {
if (!type.isInstance(resource)) {
throw new IllegalArgumentException(
- "File " + file.getName() + " is not of type " + type.getSimpleName()
- );
+ "File " + file.getName() + " is not of type " + type.getSimpleName());
}
return type.cast(resource);
}
- /**
- * Loads the given list of files into assets, handling bundled and preload resources.
- */
+ /** Loads the given list of files into assets, handling bundled and preload resources. */
private void loader(List files) {
Map bundledResources = new HashMap<>();
@@ -166,35 +169,38 @@ public class ResourceLoader {
}
case BundledResource br -> {
String key = resource.getClass().getName() + ":" + br.getBaseName();
- if (!bundledResources.containsKey(key)) {bundledResources.put(key, br);}
+ if (!bundledResources.containsKey(key)) {
+ bundledResources.put(key, br);
+ }
bundledResources.get(key).loadFile(file);
resource = (BaseResource) bundledResources.get(key);
assets.add(new ResourceMeta<>(br.getBaseName(), resource));
skipAdd = true;
}
case PreloadResource pr -> pr.load();
- default -> {
- }
+ default -> {}
}
BaseResource finalResource = resource;
- boolean alreadyAdded = assets.stream()
- .anyMatch(a -> a.getResource() == finalResource);
+ boolean alreadyAdded = assets.stream().anyMatch(a -> a.getResource() == finalResource);
if (!alreadyAdded && !skipAdd) {
assets.add(new ResourceMeta<>(file.getName(), resource));
}
- logger.info("Loaded {} from {}", resource.getClass().getSimpleName(), file.getAbsolutePath());
+ logger.info(
+ "Loaded {} from {}",
+ resource.getClass().getSimpleName(),
+ file.getAbsolutePath());
loadedCount.incrementAndGet();
new EventFlow()
- .addPostEvent(new AssetLoaderEvents.LoadingProgressUpdate(loadedCount.get(), totalCount))
+ .addPostEvent(
+ new AssetLoaderEvents.LoadingProgressUpdate(
+ loadedCount.get(), totalCount))
.postEvent();
}
}
- /**
- * Recursively searches a folder and adds all files to the foundFiles list.
- */
+ /** Recursively searches a folder and adds all files to the foundFiles list. */
private void fileSearcher(final File folder, List foundFiles) {
for (File fileEntry : Objects.requireNonNull(folder.listFiles())) {
if (fileEntry.isDirectory()) {
@@ -206,8 +212,8 @@ public class ResourceLoader {
}
/**
- * Uses reflection to automatically register all {@link BaseResource} subclasses
- * annotated with {@link FileExtension}.
+ * Uses reflection to automatically register all {@link BaseResource} subclasses annotated with
+ * {@link FileExtension}.
*/
private void autoRegisterResources() {
Reflections reflections = new Reflections("org.toop.framework.asset.resources");
@@ -217,20 +223,20 @@ public class ResourceLoader {
if (!cls.isAnnotationPresent(FileExtension.class)) continue;
FileExtension annotation = cls.getAnnotation(FileExtension.class);
for (String ext : annotation.value()) {
- registry.put(ext, file -> {
- try {
- return cls.getConstructor(File.class).newInstance(file);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ registry.put(
+ ext,
+ file -> {
+ try {
+ return cls.getConstructor(File.class).newInstance(file);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
}
}
}
- /**
- * Extracts the base name from a file name, used for bundling multiple files.
- */
+ /** Extracts the base name from a file name, used for bundling multiple files. */
private static String getBaseName(String fileName) {
int underscoreIndex = fileName.indexOf('_');
int dotIndex = fileName.lastIndexOf('.');
@@ -238,9 +244,7 @@ public class ResourceLoader {
return fileName.substring(0, dotIndex);
}
- /**
- * Returns the file extension of a given file name (without dot).
- */
+ /** Returns the file extension of a given file name (without dot). */
public static String getExtension(String name) {
int i = name.lastIndexOf('.');
return (i > 0) ? name.substring(i + 1) : "";
diff --git a/framework/src/main/java/org/toop/framework/asset/ResourceManager.java b/framework/src/main/java/org/toop/framework/asset/ResourceManager.java
index 983dc02..7878a7e 100644
--- a/framework/src/main/java/org/toop/framework/asset/ResourceManager.java
+++ b/framework/src/main/java/org/toop/framework/asset/ResourceManager.java
@@ -1,30 +1,29 @@
package org.toop.framework.asset;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.asset.resources.*;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-
/**
* Centralized manager for all loaded assets in the application.
- *
- * {@code ResourceManager} maintains a thread-safe registry of {@link Asset} objects
- * and provides utility methods to retrieve assets by name, ID, or type.
- * It works together with {@link ResourceLoader} to register assets automatically
- * when they are loaded from the file system.
- *
*
- *
Key responsibilities:
+ *
{@code ResourceManager} maintains a thread-safe registry of {@link Asset} objects and provides
+ * utility methods to retrieve assets by name, ID, or type. It works together with {@link
+ * ResourceLoader} to register assets automatically when they are loaded from the file system.
+ *
+ *
Key responsibilities:
+ *
*
- *
Storing all loaded assets in a concurrent map.
- *
Providing typed access to asset resources.
- *
Allowing lookup by asset name or ID.
- *
Supporting retrieval of all assets of a specific {@link BaseResource} subclass.
+ *
Storing all loaded assets in a concurrent map.
+ *
Providing typed access to asset resources.
+ *
Allowing lookup by asset name or ID.
+ *
Supporting retrieval of all assets of a specific {@link BaseResource} subclass.
*
*
- *
Example usage:
+ *
Example usage:
+ *
*
{@code
* // Load assets from a loader
* ResourceLoader loader = new ResourceLoader(new File("RootFolder"));
@@ -40,17 +39,20 @@ import java.util.concurrent.ConcurrentHashMap;
* Optional> maybeAsset = ResourceManager.findByName("menu.css");
* }
*
- *
Notes:
+ *
Notes:
+ *
*
- *
All retrieval methods are static and thread-safe.
- *
The {@link #get(String)} method may require casting if the asset type is not known at compile time.
- *
Assets should be loaded via {@link ResourceLoader} before retrieval.
+ *
All retrieval methods are static and thread-safe.
+ *
The {@link #get(String)} method may require casting if the asset type is not known at
+ * compile time.
+ *
Assets should be loaded via {@link ResourceLoader} before retrieval.
*
*/
public class ResourceManager {
private static final Logger logger = LogManager.getLogger(ResourceManager.class);
private static final ResourceManager INSTANCE = new ResourceManager();
- private static final Map> assets = new ConcurrentHashMap<>();
+ private static final Map> assets =
+ new ConcurrentHashMap<>();
private ResourceManager() {}
@@ -68,7 +70,7 @@ public class ResourceManager {
*
* @param loader the loader that has already loaded assets
*/
- public synchronized static void loadAssets(ResourceLoader loader) {
+ public static synchronized void loadAssets(ResourceLoader loader) {
for (var asset : loader.getAssets()) {
assets.put(asset.getName(), asset);
}
@@ -85,15 +87,20 @@ public class ResourceManager {
public static T get(String name) {
ResourceMeta asset = (ResourceMeta) assets.get(name);
if (asset == null) {
- throw new TypeNotPresentException(name, new RuntimeException(String.format("Type %s not present", name))); // TODO: Create own exception, BAM
+ throw new TypeNotPresentException(
+ name,
+ new RuntimeException(
+ String.format(
+ "Type %s not present",
+ name))); // TODO: Create own exception, BAM
}
return asset.getResource();
}
-// @SuppressWarnings("unchecked")
-// public static ArrayList> getAllOfType() {
-// return (ArrayList>) (ArrayList>) new ArrayList<>(assets.values());
-// }
+ // @SuppressWarnings("unchecked")
+ // public static ArrayList> getAllOfType() {
+ // return (ArrayList>) (ArrayList>) new ArrayList<>(assets.values());
+ // }
/**
* Retrieve all assets of a specific resource type.
diff --git a/framework/src/main/java/org/toop/framework/asset/ResourceMeta.java b/framework/src/main/java/org/toop/framework/asset/ResourceMeta.java
index 972b635..4632624 100644
--- a/framework/src/main/java/org/toop/framework/asset/ResourceMeta.java
+++ b/framework/src/main/java/org/toop/framework/asset/ResourceMeta.java
@@ -25,5 +25,4 @@ public class ResourceMeta {
public T getResource() {
return this.resource;
}
-
}
diff --git a/framework/src/main/java/org/toop/framework/asset/events/AssetLoaderEvents.java b/framework/src/main/java/org/toop/framework/asset/events/AssetLoaderEvents.java
index 91a296e..b19709c 100644
--- a/framework/src/main/java/org/toop/framework/asset/events/AssetLoaderEvents.java
+++ b/framework/src/main/java/org/toop/framework/asset/events/AssetLoaderEvents.java
@@ -3,5 +3,6 @@ package org.toop.framework.asset.events;
import org.toop.framework.eventbus.events.EventWithoutSnowflake;
public class AssetLoaderEvents {
- public record LoadingProgressUpdate(int hasLoadedAmount, int isLoadingAmount) implements EventWithoutSnowflake {}
+ public record LoadingProgressUpdate(int hasLoadedAmount, int isLoadingAmount)
+ implements EventWithoutSnowflake {}
}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/BaseResource.java b/framework/src/main/java/org/toop/framework/asset/resources/BaseResource.java
index c1aa040..e913026 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/BaseResource.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/BaseResource.java
@@ -14,5 +14,4 @@ public abstract class BaseResource {
public File getFile() {
return this.file;
}
-
}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/CssAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/CssAsset.java
index 6f8cd19..f0e6977 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/CssAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/CssAsset.java
@@ -1,8 +1,7 @@
package org.toop.framework.asset.resources;
-import org.toop.framework.asset.types.FileExtension;
-
import java.io.File;
+import org.toop.framework.asset.types.FileExtension;
@FileExtension({"css"})
public class CssAsset extends BaseResource {
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/FontAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/FontAsset.java
index 1054d03..e804ab0 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/FontAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/FontAsset.java
@@ -1,12 +1,11 @@
package org.toop.framework.asset.resources;
-import javafx.scene.text.Font;
-import org.toop.framework.asset.types.FileExtension;
-import org.toop.framework.asset.types.PreloadResource;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import javafx.scene.text.Font;
+import org.toop.framework.asset.types.FileExtension;
+import org.toop.framework.asset.types.PreloadResource;
@FileExtension({"ttf", "otf"})
public class FontAsset extends BaseResource implements PreloadResource {
@@ -60,4 +59,4 @@ public class FontAsset extends BaseResource implements PreloadResource {
}
return this.family;
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/ImageAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/ImageAsset.java
index ed2c87e..27d6ef3 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/ImageAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/ImageAsset.java
@@ -1,11 +1,10 @@
package org.toop.framework.asset.resources;
-import javafx.scene.image.Image;
-import org.toop.framework.asset.types.FileExtension;
-import org.toop.framework.asset.types.LoadableResource;
-
import java.io.File;
import java.io.FileInputStream;
+import javafx.scene.image.Image;
+import org.toop.framework.asset.types.FileExtension;
+import org.toop.framework.asset.types.LoadableResource;
@FileExtension({"png", "jpg", "jpeg"})
public class ImageAsset extends BaseResource implements LoadableResource {
@@ -45,4 +44,4 @@ public class ImageAsset extends BaseResource implements LoadableResource {
}
return null;
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/JsonAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/JsonAsset.java
index 5f9e1ba..d5beda4 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/JsonAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/JsonAsset.java
@@ -1,12 +1,13 @@
package org.toop.framework.asset.resources;
+
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import org.toop.framework.asset.types.FileExtension;
-import org.toop.framework.asset.types.LoadableResource;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import org.toop.framework.asset.types.FileExtension;
+import org.toop.framework.asset.types.LoadableResource;
@FileExtension({"json"})
public class JsonAsset extends BaseResource implements LoadableResource {
@@ -25,7 +26,8 @@ public class JsonAsset extends BaseResource implements LoadableResource {
File file = getFile();
if (!file.exists()) {
try {
- // make a new file with the declared constructor (example: settings) if it doesn't exist
+ // make a new file with the declared constructor (example: settings) if it doesn't
+ // exist
content = type.getDeclaredConstructor().newInstance();
save();
} catch (Exception e) {
@@ -36,7 +38,7 @@ public class JsonAsset extends BaseResource implements LoadableResource {
try (FileReader reader = new FileReader(file)) {
content = gson.fromJson(reader, type);
this.isLoaded = true;
- } catch(Exception e) {
+ } catch (Exception e) {
throw new RuntimeException("Failed to load JSON asset" + getFile(), e);
}
}
@@ -62,7 +64,7 @@ public class JsonAsset extends BaseResource implements LoadableResource {
parent.mkdirs();
}
try (FileWriter writer = new FileWriter(file)) {
- gson.toJson(content, writer);
+ gson.toJson(content, writer);
} catch (IOException e) {
throw new RuntimeException("Failed to save JSON asset" + getFile(), e);
}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/LocalizationAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/LocalizationAsset.java
index cf18f14..763f332 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/LocalizationAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/LocalizationAsset.java
@@ -1,34 +1,29 @@
package org.toop.framework.asset.resources;
-import org.toop.framework.asset.types.BundledResource;
-import org.toop.framework.asset.types.FileExtension;
-import org.toop.framework.asset.types.LoadableResource;
-
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
+import org.toop.framework.asset.types.BundledResource;
+import org.toop.framework.asset.types.FileExtension;
+import org.toop.framework.asset.types.LoadableResource;
/**
- * Represents a localization resource asset that loads and manages property files
- * containing key-value pairs for different locales.
- *
- * This class implements {@link LoadableResource} to support loading/unloading
- * and {@link BundledResource} to represent resources that can contain multiple
- * localized bundles.
- *
- *
- * Files handled by this class must have the {@code .properties} extension,
- * optionally with a locale suffix, e.g., {@code messages_en_US.properties}.
- *
+ * Represents a localization resource asset that loads and manages property files containing
+ * key-value pairs for different locales.
+ *
+ *
This class implements {@link LoadableResource} to support loading/unloading and {@link
+ * BundledResource} to represent resources that can contain multiple localized bundles.
+ *
+ *
Files handled by this class must have the {@code .properties} extension, optionally with a
+ * locale suffix, e.g., {@code messages_en_US.properties}.
+ *
+ *
- *
*/
@FileExtension({"properties"})
public class LocalizationAsset extends BaseResource implements LoadableResource, BundledResource {
@@ -54,18 +49,14 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
super(file);
}
- /**
- * Loads the resource file into memory and prepares localized bundles.
- */
+ /** Loads the resource file into memory and prepares localized bundles. */
@Override
public void load() {
loadFile(getFile());
isLoaded = true;
}
- /**
- * Unloads all loaded resource bundles, freeing memory.
- */
+ /** Unloads all loaded resource bundles, freeing memory. */
@Override
public void unload() {
bundles.clear();
@@ -83,11 +74,10 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
}
/**
- * Retrieves a localized string for the given key and locale.
- * If an exact match for the locale is not found, a fallback
- * matching the language or the default locale will be used.
+ * Retrieves a localized string for the given key and locale. If an exact match for the locale
+ * is not found, a fallback matching the language or the default locale will be used.
*
- * @param key the key of the string
+ * @param key the key of the string
* @param locale the desired locale
* @return the localized string
* @throws MissingResourceException if no resource bundle is available for the locale
@@ -95,14 +85,15 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
public String getString(String key, Locale locale) {
Locale target = findBestLocale(locale);
ResourceBundle bundle = bundles.get(target);
- if (bundle == null) throw new MissingResourceException(
- "No bundle for locale: " + target, getClass().getName(), key);
+ if (bundle == null)
+ throw new MissingResourceException(
+ "No bundle for locale: " + target, getClass().getName(), key);
return bundle.getString(key);
}
/**
- * Finds the best matching locale among loaded bundles.
- * Prefers an exact match, then language-only match, then fallback.
+ * Finds the best matching locale among loaded bundles. Prefers an exact match, then
+ * language-only match, then fallback.
*
* @param locale the desired locale
* @return the best matching locale
@@ -125,8 +116,8 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
}
/**
- * Loads a specific property file as a resource bundle.
- * The locale is extracted from the file name if present.
+ * Loads a specific property file as a resource bundle. The locale is extracted from the file
+ * name if present.
*
* @param file the property file to load
* @throws RuntimeException if the file cannot be read
@@ -134,7 +125,7 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
@Override
public void loadFile(File file) {
try (InputStreamReader reader =
- new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
+ new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
Locale locale = extractLocale(file.getName(), baseName);
bundles.put(locale, new PropertyResourceBundle(reader));
} catch (IOException e) {
@@ -153,22 +144,23 @@ public class LocalizationAsset extends BaseResource implements LoadableResource,
return this.baseName;
}
-// /**
-// * Extracts the base name from a file name.
-// *
-// * @param fileName the file name
-// * @return base name without locale or extension
-// */
-// private String getBaseName(String fileName) {
-// int dotIndex = fileName.lastIndexOf('.');
-// String nameWithoutExtension = (dotIndex > 0) ? fileName.substring(0, dotIndex) : fileName;
-//
-// int underscoreIndex = nameWithoutExtension.indexOf('_');
-// if (underscoreIndex > 0) {
-// return nameWithoutExtension.substring(0, underscoreIndex);
-// }
-// return nameWithoutExtension;
-// }
+ // /**
+ // * Extracts the base name from a file name.
+ // *
+ // * @param fileName the file name
+ // * @return base name without locale or extension
+ // */
+ // private String getBaseName(String fileName) {
+ // int dotIndex = fileName.lastIndexOf('.');
+ // String nameWithoutExtension = (dotIndex > 0) ? fileName.substring(0, dotIndex) :
+ // fileName;
+ //
+ // int underscoreIndex = nameWithoutExtension.indexOf('_');
+ // if (underscoreIndex > 0) {
+ // return nameWithoutExtension.substring(0, underscoreIndex);
+ // }
+ // return nameWithoutExtension;
+ // }
/**
* Extracts a locale from a file name based on the pattern "base_LOCALE.properties".
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/MusicAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/MusicAsset.java
index fc6eec7..1d79c88 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/MusicAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/MusicAsset.java
@@ -1,11 +1,10 @@
package org.toop.framework.asset.resources;
+import java.io.*;
import javafx.scene.media.Media;
import org.toop.framework.asset.types.FileExtension;
import org.toop.framework.asset.types.LoadableResource;
-import java.io.*;
-
@FileExtension({"mp3"})
public class MusicAsset extends BaseResource implements LoadableResource {
private Media media;
@@ -37,4 +36,4 @@ public class MusicAsset extends BaseResource implements LoadableResource {
public boolean isLoaded() {
return isLoaded;
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/SettingsAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/SettingsAsset.java
index c496213..d329d98 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/SettingsAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/SettingsAsset.java
@@ -1,10 +1,8 @@
package org.toop.framework.asset.resources;
-
-import org.toop.framework.settings.Settings;
-
import java.io.File;
import java.util.Locale;
+import org.toop.framework.settings.Settings;
public class SettingsAsset extends JsonAsset {
@@ -32,13 +30,13 @@ public class SettingsAsset extends JsonAsset {
return getContent().fullScreen;
}
- public String getTheme() {
- return getContent().theme;
- }
+ public String getTheme() {
+ return getContent().theme;
+ }
- public String getLayoutSize() {
- return getContent().layoutSize;
- }
+ public String getLayoutSize() {
+ return getContent().layoutSize;
+ }
public void setVolume(int volume) {
getContent().volume = volume;
@@ -65,13 +63,13 @@ public class SettingsAsset extends JsonAsset {
save();
}
- public void setTheme(String theme) {
- getContent().theme = theme;
- save();
- }
+ public void setTheme(String theme) {
+ getContent().theme = theme;
+ save();
+ }
- public void setLayoutSize(String layoutSize) {
- getContent().layoutSize = layoutSize;
- save();
- }
-}
\ No newline at end of file
+ public void setLayoutSize(String layoutSize) {
+ getContent().layoutSize = layoutSize;
+ save();
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/SoundEffectAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/SoundEffectAsset.java
index d207077..b85951b 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/SoundEffectAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/SoundEffectAsset.java
@@ -1,11 +1,10 @@
package org.toop.framework.asset.resources;
-import org.toop.framework.asset.types.FileExtension;
-import org.toop.framework.asset.types.LoadableResource;
-
-import javax.sound.sampled.*;
import java.io.*;
import java.nio.file.Files;
+import javax.sound.sampled.*;
+import org.toop.framework.asset.types.FileExtension;
+import org.toop.framework.asset.types.LoadableResource;
@FileExtension({"wav"})
public class SoundEffectAsset extends BaseResource implements LoadableResource {
@@ -16,22 +15,25 @@ public class SoundEffectAsset extends BaseResource implements LoadableResource {
}
// Gets a new clip to play
- public Clip getNewClip() throws LineUnavailableException, UnsupportedAudioFileException, IOException {
+ public Clip getNewClip()
+ throws LineUnavailableException, UnsupportedAudioFileException, IOException {
// Get a new clip from audio system
Clip clip = AudioSystem.getClip();
// Insert a new audio stream into the clip
AudioInputStream inputStream = this.getAudioStream();
AudioFormat baseFormat = inputStream.getFormat();
- if (baseFormat.getSampleSizeInBits() > 16) inputStream = downSampleAudio(inputStream, baseFormat);
- clip.open(inputStream); // ^ Clip can only run 16 bit and lower, thus downsampling necessary.
+ if (baseFormat.getSampleSizeInBits() > 16)
+ inputStream = downSampleAudio(inputStream, baseFormat);
+ clip.open(
+ inputStream); // ^ Clip can only run 16 bit and lower, thus downsampling necessary.
return clip;
}
// Generates a new audio stream from byte array
private AudioInputStream getAudioStream() throws UnsupportedAudioFileException, IOException {
// Check if raw data is loaded into memory
- if(!this.isLoaded()){
+ if (!this.isLoaded()) {
this.load();
}
@@ -39,16 +41,18 @@ public class SoundEffectAsset extends BaseResource implements LoadableResource {
return AudioSystem.getAudioInputStream(new ByteArrayInputStream(this.rawData));
}
- private AudioInputStream downSampleAudio(AudioInputStream audioInputStream, AudioFormat baseFormat) {
- AudioFormat decodedFormat = new AudioFormat(
- AudioFormat.Encoding.PCM_SIGNED,
- baseFormat.getSampleRate(),
- 16, // force 16-bit
- baseFormat.getChannels(),
- baseFormat.getChannels() * 2,
- baseFormat.getSampleRate(),
- false // little-endian
- );
+ private AudioInputStream downSampleAudio(
+ AudioInputStream audioInputStream, AudioFormat baseFormat) {
+ AudioFormat decodedFormat =
+ new AudioFormat(
+ AudioFormat.Encoding.PCM_SIGNED,
+ baseFormat.getSampleRate(),
+ 16, // force 16-bit
+ baseFormat.getChannels(),
+ baseFormat.getChannels() * 2,
+ baseFormat.getSampleRate(),
+ false // little-endian
+ );
return AudioSystem.getAudioInputStream(decodedFormat, audioInputStream);
}
diff --git a/framework/src/main/java/org/toop/framework/asset/resources/TextAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/TextAsset.java
index e6acc3c..88c9c33 100644
--- a/framework/src/main/java/org/toop/framework/asset/resources/TextAsset.java
+++ b/framework/src/main/java/org/toop/framework/asset/resources/TextAsset.java
@@ -1,12 +1,11 @@
package org.toop.framework.asset.resources;
-import org.toop.framework.asset.types.FileExtension;
-import org.toop.framework.asset.types.LoadableResource;
-
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
+import org.toop.framework.asset.types.FileExtension;
+import org.toop.framework.asset.types.LoadableResource;
@FileExtension({"txt", "json", "xml"})
public class TextAsset extends BaseResource implements LoadableResource {
@@ -41,4 +40,4 @@ public class TextAsset extends BaseResource implements LoadableResource {
public String getContent() {
return this.content;
}
-}
\ No newline at end of file
+}
diff --git a/framework/src/main/java/org/toop/framework/asset/types/BundledResource.java b/framework/src/main/java/org/toop/framework/asset/types/BundledResource.java
index ceb0f5f..a243188 100644
--- a/framework/src/main/java/org/toop/framework/asset/types/BundledResource.java
+++ b/framework/src/main/java/org/toop/framework/asset/types/BundledResource.java
@@ -1,30 +1,33 @@
package org.toop.framework.asset.types;
+import java.io.File;
import org.toop.framework.asset.ResourceLoader;
-import java.io.File;
-
/**
- * Represents a resource that can be composed of multiple files, or "bundled" together
- * under a common base name.
+ * Represents a resource that can be composed of multiple files, or "bundled" together under a
+ * common base name.
*
- *
Implementing classes allow an {@link ResourceLoader}
- * to automatically merge multiple related files into a single resource instance.
+ *
Implementing classes allow an {@link ResourceLoader} to automatically merge multiple related
+ * files into a single resource instance.
+ *
+ *
Typical use cases include:
*
- *
Typical use cases include:
*
- *
Localization assets, where multiple `.properties` files (e.g., `messages_en.properties`,
- * `messages_nl.properties`) are grouped under the same logical resource.
- *
Sprite sheets, tile sets, or other multi-file resources that logically belong together.
+ *
Localization assets, where multiple `.properties` files (e.g., `messages_en.properties`,
+ * `messages_nl.properties`) are grouped under the same logical resource.
+ *
Sprite sheets, tile sets, or other multi-file resources that logically belong together.
*
*
- *
Implementing classes must provide:
+ *
Implementing classes must provide:
+ *
*
- *
{@link #loadFile(File)}: Logic to load or merge an individual file into the resource.
- *
{@link #getBaseName()}: A consistent base name used to group multiple files into this resource.
+ *
{@link #loadFile(File)}: Logic to load or merge an individual file into the resource.
+ *
{@link #getBaseName()}: A consistent base name used to group multiple files into this
+ * resource.
*
*
- *
Example usage:
+ *
Example usage:
+ *
*
{@code
* public class LocalizationAsset extends BaseResource implements BundledResource {
* private final String baseName;
@@ -47,8 +50,8 @@ import java.io.File;
* }
* }
*
- *
When used with an asset loader, all files sharing the same base name are
- * automatically merged into a single resource instance.
+ *
When used with an asset loader, all files sharing the same base name are automatically merged
+ * into a single resource instance.
*/
public interface BundledResource {
@@ -60,15 +63,15 @@ public interface BundledResource {
void loadFile(File file);
/**
- * Return a base name for grouping multiple files into this single resource.
- * Files with the same base name are automatically merged by the loader.
+ * Return a base name for grouping multiple files into this single resource. Files with the same
+ * base name are automatically merged by the loader.
*
* @return the base name used to identify this bundled resource
*/
String getBaseName();
-// /**
-// Returns the name
-// */
-// String getDefaultName();
-}
\ No newline at end of file
+ // /**
+ // Returns the name
+ // */
+ // String getDefaultName();
+}
diff --git a/framework/src/main/java/org/toop/framework/asset/types/FileExtension.java b/framework/src/main/java/org/toop/framework/asset/types/FileExtension.java
index b3c42d5..ab70275 100644
--- a/framework/src/main/java/org/toop/framework/asset/types/FileExtension.java
+++ b/framework/src/main/java/org/toop/framework/asset/types/FileExtension.java
@@ -1,23 +1,21 @@
package org.toop.framework.asset.types;
-import org.toop.framework.asset.ResourceLoader;
-import org.toop.framework.asset.resources.BaseResource;
-
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
+import org.toop.framework.asset.ResourceLoader;
+import org.toop.framework.asset.resources.BaseResource;
/**
- * Annotation to declare which file extensions a {@link BaseResource} subclass
- * can handle.
+ * Annotation to declare which file extensions a {@link BaseResource} subclass can handle.
*
- *
This annotation is processed by the {@link ResourceLoader}
- * to automatically register resource types for specific file extensions.
- * Each extension listed will be mapped to the annotated resource class,
- * allowing the loader to instantiate the correct type when scanning files.
+ *
This annotation is processed by the {@link ResourceLoader} to automatically register resource
+ * types for specific file extensions. Each extension listed will be mapped to the annotated
+ * resource class, allowing the loader to instantiate the correct type when scanning files.
+ *
+ *
The annotation is retained at runtime for reflection-based registration.
- *
Can only be applied to types (classes) that extend {@link BaseResource}.
- *
Multiple extensions can be specified in the {@code value()} array.
+ *
The annotation is retained at runtime for reflection-based registration.
+ *
Can only be applied to types (classes) that extend {@link BaseResource}.
+ *
Multiple extensions can be specified in the {@code value()} array.
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FileExtension {
/**
- * The list of file extensions (without leading dot) that the annotated resource class can handle.
+ * The list of file extensions (without leading dot) that the annotated resource class can
+ * handle.
*
* @return array of file extensions
*/
diff --git a/framework/src/main/java/org/toop/framework/asset/types/LoadableResource.java b/framework/src/main/java/org/toop/framework/asset/types/LoadableResource.java
index d25ba9e..d43f9c0 100644
--- a/framework/src/main/java/org/toop/framework/asset/types/LoadableResource.java
+++ b/framework/src/main/java/org/toop/framework/asset/types/LoadableResource.java
@@ -4,20 +4,23 @@ import org.toop.framework.asset.ResourceLoader;
/**
* Represents a resource that can be explicitly loaded and unloaded.
- *
- * Any class implementing {@code LoadableResource} is responsible for managing its own
- * loading and unloading logic, such as reading files, initializing data structures,
- * or allocating external resources.
- *
*
- *
Implementing classes must define the following behaviors:
+ *
Any class implementing {@code LoadableResource} is responsible for managing its own loading
+ * and unloading logic, such as reading files, initializing data structures, or allocating external
+ * resources.
+ *
+ *
Implementing classes must define the following behaviors:
+ *
*
- *
{@link #load()}: Load the resource into memory or perform necessary initialization.
- *
{@link #unload()}: Release any held resources or memory when the resource is no longer needed.
- *
{@link #isLoaded()}: Return {@code true} if the resource has been successfully loaded and is ready for use, {@code false} otherwise.
+ *
{@link #load()}: Load the resource into memory or perform necessary initialization.
+ *
{@link #unload()}: Release any held resources or memory when the resource is no longer
+ * needed.
+ *
{@link #isLoaded()}: Return {@code true} if the resource has been successfully loaded and
+ * is ready for use, {@code false} otherwise.
*
This interface is commonly used with {@link PreloadResource} to allow automatic
- * loading by an {@link ResourceLoader} if desired.
+ *
This interface is commonly used with {@link PreloadResource} to allow automatic loading by an
+ * {@link ResourceLoader} if desired.
*/
public interface LoadableResource {
/**
- * Load the resource into memory or initialize it.
- * This method may throw runtime exceptions if loading fails.
+ * Load the resource into memory or initialize it. This method may throw runtime exceptions if
+ * loading fails.
*/
void load();
/**
- * Unload the resource and free any associated resources.
- * After this call, {@link #isLoaded()} should return false.
+ * Unload the resource and free any associated resources. After this call, {@link #isLoaded()}
+ * should return false.
*/
void unload();
diff --git a/framework/src/main/java/org/toop/framework/asset/types/PreloadResource.java b/framework/src/main/java/org/toop/framework/asset/types/PreloadResource.java
index 07d213d..bf4fafd 100644
--- a/framework/src/main/java/org/toop/framework/asset/types/PreloadResource.java
+++ b/framework/src/main/java/org/toop/framework/asset/types/PreloadResource.java
@@ -3,17 +3,19 @@ package org.toop.framework.asset.types;
import org.toop.framework.asset.ResourceLoader;
/**
- * Marker interface for resources that should be **automatically loaded** by the {@link ResourceLoader}.
+ * Marker interface for resources that should be **automatically loaded** by the {@link
+ * ResourceLoader}.
*
- *
Extends {@link LoadableResource}, so any implementing class must provide the standard
- * {@link LoadableResource#load()} and {@link LoadableResource#unload()} methods, as well as the
- * {@link LoadableResource#isLoaded()} check.
+ *
Extends {@link LoadableResource}, so any implementing class must provide the standard {@link
+ * LoadableResource#load()} and {@link LoadableResource#unload()} methods, as well as the {@link
+ * LoadableResource#isLoaded()} check.
*
*
When a resource implements {@code PreloadResource}, the {@code ResourceLoader} will invoke
* {@link LoadableResource#load()} automatically after the resource is discovered and instantiated,
- * without requiring manual loading by the user.
+ * without requiring manual loading by the user.
+ *
+ *
Typical usage:
*
- *
Typical usage:
*
{@code
* public class MyFontAsset extends BaseResource implements PreloadResource {
* @Override
@@ -34,6 +36,6 @@ import org.toop.framework.asset.ResourceLoader;
* }
*
*
Note: Only use this interface for resources that are safe to load at startup, as it may
- * increase memory usage or startup time.
+ * increase memory usage or startup time.
*/
public interface PreloadResource extends LoadableResource {}
diff --git a/framework/src/main/java/org/toop/framework/audio/AudioVolumeManager.java b/framework/src/main/java/org/toop/framework/audio/AudioVolumeManager.java
index 7d256cc..add826b 100644
--- a/framework/src/main/java/org/toop/framework/audio/AudioVolumeManager.java
+++ b/framework/src/main/java/org/toop/framework/audio/AudioVolumeManager.java
@@ -1,12 +1,10 @@
package org.toop.framework.audio;
-import com.sun.scenario.Settings;
import javafx.scene.media.MediaPlayer;
-import org.toop.framework.audio.events.AudioEvents;
-import org.toop.framework.eventbus.EventFlow;
-
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
+import org.toop.framework.audio.events.AudioEvents;
+import org.toop.framework.eventbus.EventFlow;
public class AudioVolumeManager {
private final SoundManager sM;
@@ -15,7 +13,7 @@ public class AudioVolumeManager {
private double fxVolume = 1.0;
private double musicVolume = 1.0;
- public AudioVolumeManager(SoundManager soundManager){
+ public AudioVolumeManager(SoundManager soundManager) {
this.sM = soundManager;
new EventFlow()
@@ -25,19 +23,22 @@ public class AudioVolumeManager {
.listen(this::handleGetCurrentVolume)
.listen(this::handleGetCurrentFxVolume)
.listen(this::handleGetCurrentMusicVolume);
-
}
- public void updateMusicVolume(MediaPlayer mediaPlayer){
+ public void updateMusicVolume(MediaPlayer mediaPlayer) {
mediaPlayer.setVolume(this.musicVolume * this.volume);
}
- public void updateSoundEffectVolume(Clip clip){
- if (clip.isControlSupported(FloatControl.Type.MASTER_GAIN)){
- FloatControl volumeControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
+ public void updateSoundEffectVolume(Clip clip) {
+ if (clip.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
+ FloatControl volumeControl =
+ (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
float min = volumeControl.getMinimum();
float max = volumeControl.getMaximum();
- float dB = (float) (Math.log10(Math.max(this.fxVolume * this.volume, 0.0001)) * 20.0); // convert linear to dB
+ float dB =
+ (float)
+ (Math.log10(Math.max(this.fxVolume * this.volume, 0.0001))
+ * 20.0); // convert linear to dB
dB = Math.max(min, Math.min(max, dB));
volumeControl.setValue(dB);
}
@@ -50,7 +51,7 @@ public class AudioVolumeManager {
private void handleFxVolumeChange(AudioEvents.ChangeFxVolume event) {
this.fxVolume = limitVolume(event.newVolume() / 100);
- for (Clip clip : sM.getActiveSoundEffects().values()){
+ for (Clip clip : sM.getActiveSoundEffects().values()) {
updateSoundEffectVolume(clip);
}
}
@@ -60,32 +61,40 @@ public class AudioVolumeManager {
for (MediaPlayer mediaPlayer : sM.getActiveMusic()) {
this.updateMusicVolume(mediaPlayer);
}
- for (Clip clip : sM.getActiveSoundEffects().values()){
+ for (Clip clip : sM.getActiveSoundEffects().values()) {
updateSoundEffectVolume(clip);
}
}
- private void handleMusicVolumeChange(AudioEvents.ChangeMusicVolume event){
+ private void handleMusicVolumeChange(AudioEvents.ChangeMusicVolume event) {
this.musicVolume = limitVolume(event.newVolume() / 100);
System.out.println(this.musicVolume);
System.out.println(this.volume);
- for (MediaPlayer mediaPlayer : sM.getActiveMusic()){
+ for (MediaPlayer mediaPlayer : sM.getActiveMusic()) {
this.updateMusicVolume(mediaPlayer);
}
}
private void handleGetCurrentVolume(AudioEvents.GetCurrentVolume event) {
- new EventFlow().addPostEvent(new AudioEvents.GetCurrentVolumeResponse(volume * 100, event.snowflakeId()))
+ new EventFlow()
+ .addPostEvent(
+ new AudioEvents.GetCurrentVolumeResponse(volume * 100, event.snowflakeId()))
.asyncPostEvent();
}
private void handleGetCurrentFxVolume(AudioEvents.GetCurrentFxVolume event) {
- new EventFlow().addPostEvent(new AudioEvents.GetCurrentFxVolumeResponse(fxVolume * 100, event.snowflakeId()))
+ new EventFlow()
+ .addPostEvent(
+ new AudioEvents.GetCurrentFxVolumeResponse(
+ fxVolume * 100, event.snowflakeId()))
.asyncPostEvent();
}
- private void handleGetCurrentMusicVolume(AudioEvents.GetCurrentMusicVolume event){
- new EventFlow().addPostEvent(new AudioEvents.GetCurrentMusicVolumeResponse(musicVolume * 100, event.snowflakeId()))
+ private void handleGetCurrentMusicVolume(AudioEvents.GetCurrentMusicVolume event) {
+ new EventFlow()
+ .addPostEvent(
+ new AudioEvents.GetCurrentMusicVolumeResponse(
+ musicVolume * 100, event.snowflakeId()))
.asyncPostEvent();
}
}
diff --git a/framework/src/main/java/org/toop/framework/audio/SoundManager.java b/framework/src/main/java/org/toop/framework/audio/SoundManager.java
index 51c31ad..f6608ba 100644
--- a/framework/src/main/java/org/toop/framework/audio/SoundManager.java
+++ b/framework/src/main/java/org/toop/framework/audio/SoundManager.java
@@ -1,5 +1,9 @@
package org.toop.framework.audio;
+import java.io.*;
+import java.util.*;
+import javafx.scene.media.MediaPlayer;
+import javax.sound.sampled.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.SnowflakeGenerator;
@@ -10,25 +14,20 @@ import org.toop.framework.asset.resources.SoundEffectAsset;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
-import javafx.scene.media.MediaPlayer;
-
-import java.io.*;
-import java.util.*;
-import javax.sound.sampled.*;
-
public class SoundManager {
private static final Logger logger = LogManager.getLogger(SoundManager.class);
private final List activeMusic = new ArrayList<>();
private final Queue backgroundMusicQueue = new LinkedList<>();
private final Map activeSoundEffects = new HashMap<>();
private final HashMap audioResources = new HashMap<>();
- private final SnowflakeGenerator idGenerator = new SnowflakeGenerator(); // TODO: Don't create a new generator
+ private final SnowflakeGenerator idGenerator =
+ new SnowflakeGenerator(); // TODO: Don't create a new generator
private final AudioVolumeManager audioVolumeManager = new AudioVolumeManager(this);
-
public SoundManager() {
// Get all Audio Resources and add them to a list.
- for (ResourceMeta asset : ResourceManager.getAllOfType(SoundEffectAsset.class)) {
+ for (ResourceMeta asset :
+ ResourceManager.getAllOfType(SoundEffectAsset.class)) {
try {
this.addAudioResource(asset);
} catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) {
@@ -39,13 +38,17 @@ public class SoundManager {
.listen(this::handlePlaySound)
.listen(this::handleStopSound)
.listen(this::handleMusicStart)
- .listen(AudioEvents.ClickButton.class, _ -> {
- try {
- playSound("medium-button-click.wav", false);
- } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
- logger.error(e);
- }
- });
+ .listen(
+ AudioEvents.ClickButton.class,
+ _ -> {
+ try {
+ playSound("medium-button-click.wav", false);
+ } catch (UnsupportedAudioFileException
+ | LineUnavailableException
+ | IOException e) {
+ logger.error(e);
+ }
+ });
}
private void handlePlaySound(AudioEvents.PlayEffect event) {
@@ -68,14 +71,13 @@ public class SoundManager {
private void handleMusicStart(AudioEvents.StartBackgroundMusic e) {
backgroundMusicQueue.clear();
- List shuffledArray = new ArrayList<>(ResourceManager.getAllOfType(MusicAsset.class)
- .stream()
- .map(ResourceMeta::getResource)
- .toList());
+ List shuffledArray =
+ new ArrayList<>(
+ ResourceManager.getAllOfType(MusicAsset.class).stream()
+ .map(ResourceMeta::getResource)
+ .toList());
Collections.shuffle(shuffledArray);
- backgroundMusicQueue.addAll(
- shuffledArray
- );
+ backgroundMusicQueue.addAll(shuffledArray);
backgroundMusicPlayer();
}
@@ -89,34 +91,40 @@ public class SoundManager {
MediaPlayer mediaPlayer = new MediaPlayer(ma.getMedia());
- mediaPlayer.setOnEndOfMedia(() -> {
- addBackgroundMusic(ma);
- activeMusic.remove(mediaPlayer);
- mediaPlayer.dispose();
- ma.unload();
- backgroundMusicPlayer(); // play next
- });
+ mediaPlayer.setOnEndOfMedia(
+ () -> {
+ addBackgroundMusic(ma);
+ activeMusic.remove(mediaPlayer);
+ mediaPlayer.dispose();
+ ma.unload();
+ backgroundMusicPlayer(); // play next
+ });
- mediaPlayer.setOnStopped(() -> {
- addBackgroundMusic(ma);
- activeMusic.remove(mediaPlayer);
- ma.unload();
- });
+ mediaPlayer.setOnStopped(
+ () -> {
+ addBackgroundMusic(ma);
+ activeMusic.remove(mediaPlayer);
+ ma.unload();
+ });
- mediaPlayer.setOnError(() -> {
- addBackgroundMusic(ma);
- activeMusic.remove(mediaPlayer);
- ma.unload();
- });
+ mediaPlayer.setOnError(
+ () -> {
+ addBackgroundMusic(ma);
+ activeMusic.remove(mediaPlayer);
+ ma.unload();
+ });
audioVolumeManager.updateMusicVolume(mediaPlayer);
mediaPlayer.play();
activeMusic.add(mediaPlayer);
logger.info("Playing background music: {}", ma.getFile().getName());
- logger.info("Background music next in line: {}", backgroundMusicQueue.peek().getFile().getName());
+ logger.info(
+ "Background music next in line: {}",
+ backgroundMusicQueue.peek().getFile().getName());
}
- private long playSound(String audioFileName, boolean loop) throws UnsupportedAudioFileException, LineUnavailableException, IOException {
+ private long playSound(String audioFileName, boolean loop)
+ throws UnsupportedAudioFileException, LineUnavailableException, IOException {
SoundEffectAsset asset = audioResources.get(audioFileName);
// Return -1 which indicates resource wasn't available
@@ -134,8 +142,7 @@ public class SoundManager {
// If supposed to loop make it loop, else just start it once
if (loop) {
clip.loop(Clip.LOOP_CONTINUOUSLY);
- }
- else {
+ } else {
clip.start();
}
@@ -148,12 +155,13 @@ public class SoundManager {
activeSoundEffects.put(clipId, clip); // TODO: Do on snowflake for specific sound to stop
// remove when finished (only for non-looping sounds)
- clip.addLineListener(event -> {
- if (event.getType() == LineEvent.Type.STOP && !clip.isRunning()) {
- activeSoundEffects.remove(clipId);
- clip.close();
- }
- });
+ clip.addLineListener(
+ event -> {
+ if (event.getType() == LineEvent.Type.STOP && !clip.isRunning()) {
+ activeSoundEffects.remove(clipId);
+ clip.close();
+ }
+ });
// Return id so it can be stopped
return clipId;
@@ -179,7 +187,11 @@ public class SoundManager {
activeSoundEffects.clear();
}
- public Map getActiveSoundEffects(){ return this.activeSoundEffects; }
+ public Map getActiveSoundEffects() {
+ return this.activeSoundEffects;
+ }
- public List getActiveMusic() { return activeMusic; }
+ public List getActiveMusic() {
+ return activeMusic;
+ }
}
diff --git a/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java b/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java
index 5cb596d..aed23ee 100644
--- a/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java
+++ b/framework/src/main/java/org/toop/framework/audio/events/AudioEvents.java
@@ -1,21 +1,22 @@
package org.toop.framework.audio.events;
+import java.util.Map;
import org.toop.framework.eventbus.events.EventWithSnowflake;
import org.toop.framework.eventbus.events.EventWithoutSnowflake;
import org.toop.framework.eventbus.events.EventsBase;
-import java.util.Map;
-
public class AudioEvents extends EventsBase {
/** Starts playing a sound. */
- public record PlayEffect(String fileName, boolean loop)
- implements EventWithoutSnowflake {}
+ public record PlayEffect(String fileName, boolean loop) implements EventWithoutSnowflake {}
public record StopEffect(long clipId) implements EventWithoutSnowflake {}
public record StartBackgroundMusic() implements EventWithoutSnowflake {}
+
public record ChangeVolume(double newVolume) implements EventWithoutSnowflake {}
+
public record ChangeFxVolume(double newVolume) implements EventWithoutSnowflake {}
+
public record ChangeMusicVolume(double newVolume) implements EventWithoutSnowflake {}
public record GetCurrentVolume(long snowflakeId) implements EventWithSnowflake {
@@ -29,7 +30,9 @@ public class AudioEvents extends EventsBase {
return snowflakeId;
}
}
- public record GetCurrentVolumeResponse(double currentVolume, long snowflakeId) implements EventWithSnowflake {
+
+ public record GetCurrentVolumeResponse(double currentVolume, long snowflakeId)
+ implements EventWithSnowflake {
@Override
public Map result() {
return Map.of();
@@ -65,7 +68,8 @@ public class AudioEvents extends EventsBase {
}
}
- public record GetCurrentFxVolumeResponse(double currentVolume, long snowflakeId) implements EventWithSnowflake {
+ public record GetCurrentFxVolumeResponse(double currentVolume, long snowflakeId)
+ implements EventWithSnowflake {
@Override
public Map result() {
return Map.of();
@@ -77,7 +81,8 @@ public class AudioEvents extends EventsBase {
}
}
- public record GetCurrentMusicVolumeResponse(double currentVolume, long snowflakeId) implements EventWithSnowflake {
+ public record GetCurrentMusicVolumeResponse(double currentVolume, long snowflakeId)
+ implements EventWithSnowflake {
@Override
public Map result() {
return Map.of();
@@ -90,5 +95,4 @@ public class AudioEvents extends EventsBase {
}
public record ClickButton() implements EventWithoutSnowflake {}
-
- }
+}
diff --git a/framework/src/main/java/org/toop/framework/settings/Settings.java b/framework/src/main/java/org/toop/framework/settings/Settings.java
index b1ed334..052107c 100644
--- a/framework/src/main/java/org/toop/framework/settings/Settings.java
+++ b/framework/src/main/java/org/toop/framework/settings/Settings.java
@@ -3,8 +3,8 @@ package org.toop.framework.settings;
public class Settings {
public boolean fullScreen = false;
public String locale = "en";
- public String theme = "dark";
- public String layoutSize = "medium";
+ public String theme = "dark";
+ public String layoutSize = "medium";
public int volume = 100;
public int fxVolume = 20;
public int musicVolume = 15;
diff --git a/game/src/main/java/org/toop/game/Game.java b/game/src/main/java/org/toop/game/Game.java
index 71b2214..9b4259c 100644
--- a/game/src/main/java/org/toop/game/Game.java
+++ b/game/src/main/java/org/toop/game/Game.java
@@ -3,34 +3,37 @@ package org.toop.game;
import java.util.Arrays;
public abstract class Game {
- public enum State {
- NORMAL, DRAW, WIN,
- }
+ public enum State {
+ NORMAL,
+ DRAW,
+ WIN,
+ }
- public record Move(int position, char value) {}
+ public record Move(int position, char value) {}
- public static final char EMPTY = (char)0;
+ public static final char EMPTY = (char) 0;
- public final int rowSize;
- public final int columnSize;
- public final char[] board;
+ public final int rowSize;
+ public final int columnSize;
+ public final char[] board;
- protected Game(int rowSize, int columnSize) {
- assert rowSize > 0 && columnSize > 0;
+ protected Game(int rowSize, int columnSize) {
+ assert rowSize > 0 && columnSize > 0;
- this.rowSize = rowSize;
- this.columnSize = columnSize;
+ this.rowSize = rowSize;
+ this.columnSize = columnSize;
- board = new char[rowSize * columnSize];
- Arrays.fill(board, EMPTY);
- }
+ board = new char[rowSize * columnSize];
+ Arrays.fill(board, EMPTY);
+ }
- protected Game(Game other) {
- rowSize = other.rowSize;
- columnSize = other.columnSize;
- board = Arrays.copyOf(other.board, other.board.length);
- }
+ protected Game(Game other) {
+ rowSize = other.rowSize;
+ columnSize = other.columnSize;
+ board = Arrays.copyOf(other.board, other.board.length);
+ }
- public abstract Move[] getLegalMoves();
- public abstract State play(Move move);
-}
\ No newline at end of file
+ public abstract Move[] getLegalMoves();
+
+ public abstract State play(Move move);
+}
diff --git a/game/src/main/java/org/toop/game/TurnBasedGame.java b/game/src/main/java/org/toop/game/TurnBasedGame.java
index 2da6337..b4eb1d3 100644
--- a/game/src/main/java/org/toop/game/TurnBasedGame.java
+++ b/game/src/main/java/org/toop/game/TurnBasedGame.java
@@ -1,25 +1,27 @@
package org.toop.game;
public abstract class TurnBasedGame extends Game {
- public final int turns;
+ public final int turns;
- protected int currentTurn;
+ protected int currentTurn;
- protected TurnBasedGame(int rowSize, int columnSize, int turns) {
- super(rowSize, columnSize);
+ protected TurnBasedGame(int rowSize, int columnSize, int turns) {
+ super(rowSize, columnSize);
assert turns >= 2;
this.turns = turns;
- }
+ }
- protected TurnBasedGame(TurnBasedGame other) {
- super(other);
- turns = other.turns;
- currentTurn = other.currentTurn;
- }
+ protected TurnBasedGame(TurnBasedGame other) {
+ super(other);
+ turns = other.turns;
+ currentTurn = other.currentTurn;
+ }
- protected void nextTurn() {
- currentTurn = (currentTurn + 1) % turns;
- }
+ protected void nextTurn() {
+ currentTurn = (currentTurn + 1) % turns;
+ }
- public int getCurrentTurn() { return currentTurn; }
-}
\ No newline at end of file
+ public int getCurrentTurn() {
+ return currentTurn;
+ }
+}
diff --git a/game/src/main/java/org/toop/game/othello/Othello.java b/game/src/main/java/org/toop/game/othello/Othello.java
index 3012eac..435527a 100644
--- a/game/src/main/java/org/toop/game/othello/Othello.java
+++ b/game/src/main/java/org/toop/game/othello/Othello.java
@@ -3,17 +3,17 @@ package org.toop.game.othello;
import org.toop.game.TurnBasedGame;
public final class Othello extends TurnBasedGame {
- Othello() {
- super(8, 8, 2);
- }
+ Othello() {
+ super(8, 8, 2);
+ }
- @Override
- public Move[] getLegalMoves() {
- return new Move[0];
- }
+ @Override
+ public Move[] getLegalMoves() {
+ return new Move[0];
+ }
- @Override
- public State play(Move move) {
- return null;
- }
-}
\ No newline at end of file
+ @Override
+ public State play(Move move) {
+ return null;
+ }
+}
diff --git a/game/src/main/java/org/toop/game/othello/OthelloAI.java b/game/src/main/java/org/toop/game/othello/OthelloAI.java
index 8957387..40f147c 100644
--- a/game/src/main/java/org/toop/game/othello/OthelloAI.java
+++ b/game/src/main/java/org/toop/game/othello/OthelloAI.java
@@ -4,8 +4,8 @@ import org.toop.game.AI;
import org.toop.game.Game;
public final class OthelloAI extends AI {
- @Override
- public Game.Move findBestMove(Othello game, int depth) {
- return null;
- }
+ @Override
+ public Game.Move findBestMove(Othello game, int depth) {
+ return null;
+ }
}
diff --git a/game/src/main/java/org/toop/game/tictactoe/TicTacToe.java b/game/src/main/java/org/toop/game/tictactoe/TicTacToe.java
index ee2a5b9..0fa6ca8 100644
--- a/game/src/main/java/org/toop/game/tictactoe/TicTacToe.java
+++ b/game/src/main/java/org/toop/game/tictactoe/TicTacToe.java
@@ -1,8 +1,7 @@
package org.toop.game.tictactoe;
-import org.toop.game.TurnBasedGame;
-
import java.util.ArrayList;
+import org.toop.game.TurnBasedGame;
public final class TicTacToe extends TurnBasedGame {
private int movesLeft;
@@ -19,8 +18,8 @@ public final class TicTacToe extends TurnBasedGame {
@Override
public Move[] getLegalMoves() {
- final ArrayList legalMoves = new ArrayList<>();
- final char currentValue = getCurrentValue();
+ final ArrayList legalMoves = new ArrayList<>();
+ final char currentValue = getCurrentValue();
for (int i = 0; i < board.length; i++) {
if (board[i] == EMPTY) {
@@ -44,12 +43,12 @@ public final class TicTacToe extends TurnBasedGame {
return State.WIN;
}
- nextTurn();
+ nextTurn();
if (movesLeft <= 2) {
- if (movesLeft <= 0 || checkForEarlyDraw(this)) {
- return State.DRAW;
- }
+ if (movesLeft <= 0 || checkForEarlyDraw(this)) {
+ return State.DRAW;
+ }
}
return State.NORMAL;
@@ -60,7 +59,9 @@ public final class TicTacToe extends TurnBasedGame {
for (int i = 0; i < 3; i++) {
final int index = i * 3;
- if (board[index] != EMPTY && board[index] == board[index + 1] && board[index] == board[index + 2]) {
+ if (board[index] != EMPTY
+ && board[index] == board[index + 1]
+ && board[index] == board[index + 2]) {
return true;
}
}
@@ -83,7 +84,7 @@ public final class TicTacToe extends TurnBasedGame {
private boolean checkForEarlyDraw(TicTacToe game) {
for (final Move move : game.getLegalMoves()) {
- final TicTacToe copy = new TicTacToe(game);
+ final TicTacToe copy = new TicTacToe(game);
if (copy.play(move) == State.WIN || !checkForEarlyDraw(copy)) {
return false;
@@ -93,7 +94,7 @@ public final class TicTacToe extends TurnBasedGame {
return true;
}
- private char getCurrentValue() {
- return currentTurn == 0? 'X' : 'O';
- }
-}
\ No newline at end of file
+ private char getCurrentValue() {
+ return currentTurn == 0 ? 'X' : 'O';
+ }
+}
diff --git a/game/src/test/java/org/toop/game/tictactoe/TicTacToeAITest.java b/game/src/test/java/org/toop/game/tictactoe/TicTacToeAITest.java
index 6be92f5..325b8ee 100644
--- a/game/src/test/java/org/toop/game/tictactoe/TicTacToeAITest.java
+++ b/game/src/test/java/org/toop/game/tictactoe/TicTacToeAITest.java
@@ -1,83 +1,81 @@
package org.toop.game.tictactoe;
-import org.toop.game.Game;
-
-import java.util.Set;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
import static org.junit.jupiter.api.Assertions.*;
+import java.util.Set;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.toop.game.Game;
+
class TicTacToeAITest {
- private TicTacToe game;
- private TicTacToeAI ai;
+ private TicTacToe game;
+ private TicTacToeAI ai;
- @BeforeEach
- void setup() {
- game = new TicTacToe();
- ai = new TicTacToeAI();
- }
+ @BeforeEach
+ void setup() {
+ game = new TicTacToe();
+ ai = new TicTacToeAI();
+ }
- @Test
- void testBestMove_returnWinningMoveWithDepth1() {
- // X X -
- // O O -
- // - - -
- game.play(new Game.Move(0, 'X'));
- game.play(new Game.Move(3, 'O'));
- game.play(new Game.Move(1, 'X'));
- game.play(new Game.Move(4, 'O'));
+ @Test
+ void testBestMove_returnWinningMoveWithDepth1() {
+ // X X -
+ // O O -
+ // - - -
+ game.play(new Game.Move(0, 'X'));
+ game.play(new Game.Move(3, 'O'));
+ game.play(new Game.Move(1, 'X'));
+ game.play(new Game.Move(4, 'O'));
- final Game.Move move = ai.findBestMove(game, 1);
+ final Game.Move move = ai.findBestMove(game, 1);
- assertNotNull(move);
- assertEquals('X', move.value());
- assertEquals(2, move.position());
- }
+ assertNotNull(move);
+ assertEquals('X', move.value());
+ assertEquals(2, move.position());
+ }
- @Test
- void testBestMove_blockOpponentWinDepth1() {
- // - - -
- // O - -
- // X X -
- game.play(new Game.Move(6, 'X'));
- game.play(new Game.Move(3, 'O'));
- game.play(new Game.Move(7, 'X'));
+ @Test
+ void testBestMove_blockOpponentWinDepth1() {
+ // - - -
+ // O - -
+ // X X -
+ game.play(new Game.Move(6, 'X'));
+ game.play(new Game.Move(3, 'O'));
+ game.play(new Game.Move(7, 'X'));
- final Game.Move move = ai.findBestMove(game, 1);
+ final Game.Move move = ai.findBestMove(game, 1);
- assertNotNull(move);
- assertEquals('O', move.value());
- assertEquals(8, move.position());
- }
+ assertNotNull(move);
+ assertEquals('O', move.value());
+ assertEquals(8, move.position());
+ }
- @Test
- void testBestMove_preferCornerOnEmpty() {
- final Game.Move move = ai.findBestMove(game, 0);
+ @Test
+ void testBestMove_preferCornerOnEmpty() {
+ final Game.Move move = ai.findBestMove(game, 0);
- assertNotNull(move);
- assertEquals('X', move.value());
- assertTrue(Set.of(0, 2, 6, 8).contains(move.position()));
- }
+ assertNotNull(move);
+ assertEquals('X', move.value());
+ assertTrue(Set.of(0, 2, 6, 8).contains(move.position()));
+ }
- @Test
- void testBestMove_findBestMoveDraw() {
- // O X -
- // - O X
- // X O X
- game.play(new Game.Move(1, 'X'));
- game.play(new Game.Move(0, 'O'));
- game.play(new Game.Move(5, 'X'));
- game.play(new Game.Move(4, 'O'));
- game.play(new Game.Move(6, 'X'));
- game.play(new Game.Move(7, 'O'));
- game.play(new Game.Move(8, 'X'));
+ @Test
+ void testBestMove_findBestMoveDraw() {
+ // O X -
+ // - O X
+ // X O X
+ game.play(new Game.Move(1, 'X'));
+ game.play(new Game.Move(0, 'O'));
+ game.play(new Game.Move(5, 'X'));
+ game.play(new Game.Move(4, 'O'));
+ game.play(new Game.Move(6, 'X'));
+ game.play(new Game.Move(7, 'O'));
+ game.play(new Game.Move(8, 'X'));
- final Game.Move move = ai.findBestMove(game, game.getLegalMoves().length);
+ final Game.Move move = ai.findBestMove(game, game.getLegalMoves().length);
- assertNotNull(move);
- assertEquals('O', move.value());
- assertEquals(2, move.position());
- }
-}
\ No newline at end of file
+ assertNotNull(move);
+ assertEquals('O', move.value());
+ assertEquals(2, move.position());
+ }
+}