Renamed assetmanager to resourcemanager

This commit is contained in:
lieght
2025-10-02 21:47:18 +02:00
parent 3c699cde01
commit ccc8ba3b79
25 changed files with 300 additions and 292 deletions

View File

@@ -44,14 +44,33 @@
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.14.1</version> <version>3.6.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration> <configuration>
<source>25</source> <filters>
<target>25</target> <filter>
<release>25</release> <artifact>*:*</artifact>
<encoding>UTF-8</encoding> <excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.toop.Main</mainClass>
</transformer>
</transformers>
</configuration> </configuration>
</execution>
</executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>com.diffplug.spotless</groupId> <groupId>com.diffplug.spotless</groupId>

View File

@@ -1,8 +1,8 @@
package org.toop; package org.toop;
import org.toop.app.App; import org.toop.app.App;
import org.toop.framework.asset.AssetLoader; import org.toop.framework.asset.ResourceLoader;
import org.toop.framework.asset.AssetManager; import org.toop.framework.asset.ResourceManager;
import org.toop.framework.audio.SoundManager; import org.toop.framework.audio.SoundManager;
import org.toop.framework.networking.NetworkingClientManager; import org.toop.framework.networking.NetworkingClientManager;
import org.toop.framework.networking.NetworkingInitializationException; import org.toop.framework.networking.NetworkingInitializationException;
@@ -14,7 +14,7 @@ public final class Main {
} }
private static void initSystems() throws NetworkingInitializationException { private static void initSystems() throws NetworkingInitializationException {
AssetManager.loadAssets(new AssetLoader("app/src/main/resources/assets")); ResourceManager.loadAssets(new ResourceLoader("app/src/main/resources/assets"));
new Thread(NetworkingClientManager::new).start(); new Thread(NetworkingClientManager::new).start();
new Thread(SoundManager::new).start(); new Thread(SoundManager::new).start();
} }

View File

@@ -13,8 +13,10 @@ import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.toop.framework.asset.AssetManager; import org.toop.framework.asset.ResourceManager;
import org.toop.framework.asset.resources.CssAsset; import org.toop.framework.asset.resources.CssAsset;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
public final class App extends Application { public final class App extends Application {
private static Stage stage; private static Stage stage;
@@ -44,7 +46,8 @@ public final class App extends Application {
box.setMaxHeight(200); box.setMaxHeight(200);
pane = new StackPane(background, box); pane = new StackPane(background, box);
pane.getStylesheets().add(((CssAsset)AssetManager.get("quit.css")).getUrl()); pane.getStylesheets().add(ResourceManager.get(CssAsset.class, "quit.css").getUrl());
} }
} }
@@ -57,7 +60,7 @@ public final class App extends Application {
final StackPane root = new StackPane(new MainMenu().getPane()); final StackPane root = new StackPane(new MainMenu().getPane());
final Scene scene = new Scene(root); final Scene scene = new Scene(root);
scene.getStylesheets().add(((CssAsset)AssetManager.get("app.css")).getUrl()); scene.getStylesheets().add(((CssAsset) ResourceManager.get("app.css")).getUrl());
stage.setTitle("pism"); stage.setTitle("pism");
stage.setMinWidth(1080); stage.setMinWidth(1080);
@@ -82,6 +85,9 @@ public final class App extends Application {
App.width = (int)stage.getWidth(); App.width = (int)stage.getWidth();
App.height = (int)stage.getHeight(); App.height = (int)stage.getHeight();
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(0.1)).asyncPostEvent();
App.isQuitting = false; App.isQuitting = false;
} }

View File

@@ -1,15 +1,14 @@
package org.toop.app.menu; package org.toop.app.menu;
import org.toop.framework.asset.AssetManager; import org.toop.framework.asset.ResourceManager;
import org.toop.framework.asset.resources.LocalizationAsset; import org.toop.framework.asset.resources.LocalizationAsset;
import org.toop.local.AppContext; import org.toop.local.AppContext;
import java.util.Locale; import java.util.Locale;
import java.util.ResourceBundle;
public final class CreditsMenu extends Menu { public final class CreditsMenu extends Menu {
private Locale currentLocale = AppContext.getLocale(); private Locale currentLocale = AppContext.getLocale();
private LocalizationAsset loc = AssetManager.get("localization.properties"); private LocalizationAsset loc = ResourceManager.get("localization.properties");
public CreditsMenu() { public CreditsMenu() {
} }
} }

View File

@@ -1,15 +1,14 @@
package org.toop.app.menu; package org.toop.app.menu;
import org.toop.framework.asset.AssetManager; import org.toop.framework.asset.ResourceManager;
import org.toop.framework.asset.resources.LocalizationAsset; import org.toop.framework.asset.resources.LocalizationAsset;
import org.toop.local.AppContext; import org.toop.local.AppContext;
import java.util.Locale; import java.util.Locale;
import java.util.ResourceBundle;
public final class OptionsMenu extends Menu { public final class OptionsMenu extends Menu {
private Locale currentLocale = AppContext.getLocale(); private Locale currentLocale = AppContext.getLocale();
private LocalizationAsset loc = AssetManager.get("localization.properties"); private LocalizationAsset loc = ResourceManager.get("localization.properties");
public OptionsMenu() { public OptionsMenu() {
} }
} }

View File

@@ -6,16 +6,14 @@ import org.toop.game.Player;
import org.toop.game.tictactoe.TicTacToe; import org.toop.game.tictactoe.TicTacToe;
import org.toop.game.tictactoe.TicTacToeAI; import org.toop.game.tictactoe.TicTacToeAI;
import java.util.concurrent.BlockingQueue; import javax.management.RuntimeErrorException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.*;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public final class TicTacToeMenu extends GameMenu { public final class TicTacToeMenu extends GameMenu {
private final TicTacToe game; private final TicTacToe game;
private final TicTacToeAI ai; private final TicTacToeAI ai;
private final ExecutorService executor = Executors.newFixedThreadPool(1); // private final ExecutorService executor = Executors.newFixedThreadPool(1);
private final BlockingQueue<Game.Move> moveQueue = new LinkedBlockingQueue<>(); private final BlockingQueue<Game.Move> moveQueue = new LinkedBlockingQueue<>();
public TicTacToeMenu(TicTacToe game) { public TicTacToeMenu(TicTacToe game) {
@@ -43,7 +41,7 @@ public final class TicTacToeMenu extends GameMenu {
} }
}); });
this.executor.submit(this::gameThread); new Thread(this::gameThread).start();
} }
private void play(Game.Move move) { private void play(Game.Move move) {
@@ -131,7 +129,5 @@ public final class TicTacToeMenu extends GameMenu {
return; return;
} }
} }
executor.close();
} }
} }

View File

@@ -2,8 +2,8 @@
windowTitle=ISY Games Selector windowTitle=ISY Games Selector
# Main Menu buttons # Main Menu buttons
mainMenuSelectTicTacToe=Tic Tac Toe\u5426 mainMenuSelectTicTacToe=Tic Tac Toe
mainMenuSelectReversi=Reversi\u5426 mainMenuSelectReversi=Reversi
mainMenuSelectSudoku=Sudoku mainMenuSelectSudoku=Sudoku
mainMenuSelectBattleship=Battleship mainMenuSelectBattleship=Battleship
mainMenuSelectOther=Other mainMenuSelectOther=Other

View File

@@ -4,6 +4,9 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.toop.framework.asset.events.AssetLoaderEvents; import org.toop.framework.asset.events.AssetLoaderEvents;
import org.toop.framework.asset.resources.*; 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.toop.framework.eventbus.EventFlow;
import org.reflections.Reflections; import org.reflections.Reflections;
@@ -17,7 +20,7 @@ import java.util.function.Function;
/** /**
* Responsible for loading assets from a file system directory into memory. * Responsible for loading assets from a file system directory into memory.
* <p> * <p>
* The {@code AssetLoader} scans a root folder recursively, identifies files, * The {@code ResourceLoader} scans a root folder recursively, identifies files,
* and maps them to registered resource types based on file extensions and * and maps them to registered resource types based on file extensions and
* {@link FileExtension} annotations. * {@link FileExtension} annotations.
* It supports multiple resource types including {@link PreloadResource} (automatically loaded) * It supports multiple resource types including {@link PreloadResource} (automatically loaded)
@@ -25,7 +28,7 @@ import java.util.function.Function;
* </p> * </p>
* *
* <p>Assets are stored in a static, thread-safe list and can be retrieved * <p>Assets are stored in a static, thread-safe list and can be retrieved
* through {@link AssetManager}.</p> * through {@link ResourceManager}.</p>
* *
* <p>Features:</p> * <p>Features:</p>
* <ul> * <ul>
@@ -38,24 +41,24 @@ import java.util.function.Function;
* *
* <p>Usage example:</p> * <p>Usage example:</p>
* <pre>{@code * <pre>{@code
* AssetLoader loader = new AssetLoader("assets"); * ResourceLoader loader = new ResourceLoader("assets");
* double progress = loader.getProgress(); * double progress = loader.getProgress();
* List<Asset<? extends BaseResource>> loadedAssets = loader.getAssets(); * List<Asset<? extends BaseResource>> loadedAssets = loader.getAssets();
* }</pre> * }</pre>
*/ */
public class AssetLoader { public class ResourceLoader {
private static final Logger logger = LogManager.getLogger(AssetLoader.class); private static final Logger logger = LogManager.getLogger(ResourceLoader.class);
private static final List<Asset<? extends BaseResource>> assets = new CopyOnWriteArrayList<>(); private static final List<ResourceMeta<? extends BaseResource>> assets = new CopyOnWriteArrayList<>();
private final Map<String, Function<File, ? extends BaseResource>> registry = new ConcurrentHashMap<>(); private final Map<String, Function<File, ? extends BaseResource>> registry = new ConcurrentHashMap<>();
private final AtomicInteger loadedCount = new AtomicInteger(0); private final AtomicInteger loadedCount = new AtomicInteger(0);
private int totalCount = 0; private int totalCount = 0;
/** /**
* Constructs an AssetLoader and loads assets from the given root folder. * Constructs an ResourceLoader and loads assets from the given root folder.
* @param rootFolder the folder containing asset files * @param rootFolder the folder containing asset files
*/ */
public AssetLoader(File rootFolder) { public ResourceLoader(File rootFolder) {
autoRegisterResources(); autoRegisterResources();
List<File> foundFiles = new ArrayList<>(); List<File> foundFiles = new ArrayList<>();
fileSearcher(rootFolder, foundFiles); fileSearcher(rootFolder, foundFiles);
@@ -80,10 +83,10 @@ public class AssetLoader {
} }
/** /**
* Constructs an AssetLoader from a folder path. * Constructs an ResourceLoader from a folder path.
* @param rootFolder the folder path containing assets * @param rootFolder the folder path containing assets
*/ */
public AssetLoader(String rootFolder) { public ResourceLoader(String rootFolder) {
this(new File(rootFolder)); this(new File(rootFolder));
} }
@@ -115,7 +118,7 @@ public class AssetLoader {
* Returns a snapshot list of all assets loaded by this loader. * Returns a snapshot list of all assets loaded by this loader.
* @return list of loaded assets * @return list of loaded assets
*/ */
public List<Asset<? extends BaseResource>> getAssets() { public List<ResourceMeta<? extends BaseResource>> getAssets() {
return new ArrayList<>(assets); return new ArrayList<>(assets);
} }
@@ -179,7 +182,7 @@ public class AssetLoader {
boolean alreadyAdded = assets.stream() boolean alreadyAdded = assets.stream()
.anyMatch(a -> a.getResource() == finalResource); .anyMatch(a -> a.getResource() == finalResource);
if (!alreadyAdded) { if (!alreadyAdded) {
assets.add(new Asset<>(file.getName(), resource)); 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());

View File

@@ -8,9 +8,9 @@ import java.util.concurrent.ConcurrentHashMap;
/** /**
* Centralized manager for all loaded assets in the application. * Centralized manager for all loaded assets in the application.
* <p> * <p>
* {@code AssetManager} maintains a thread-safe registry of {@link Asset} objects * {@code ResourceManager} maintains a thread-safe registry of {@link Asset} objects
* and provides utility methods to retrieve assets by name, ID, or type. * and provides utility methods to retrieve assets by name, ID, or type.
* It works together with {@link AssetLoader} to register assets automatically * It works together with {@link ResourceLoader} to register assets automatically
* when they are loaded from the file system. * when they are loaded from the file system.
* </p> * </p>
* *
@@ -25,47 +25,47 @@ import java.util.concurrent.ConcurrentHashMap;
* <p>Example usage:</p> * <p>Example usage:</p>
* <pre>{@code * <pre>{@code
* // Load assets from a loader * // Load assets from a loader
* AssetLoader loader = new AssetLoader(new File("RootFolder")); * ResourceLoader loader = new ResourceLoader(new File("RootFolder"));
* AssetManager.loadAssets(loader); * ResourceManager.loadAssets(loader);
* *
* // Retrieve a single resource * // Retrieve a single resource
* ImageAsset background = AssetManager.get("background.jpg"); * ImageAsset background = ResourceManager.get("background.jpg");
* *
* // Retrieve all fonts * // Retrieve all fonts
* List<Asset<FontAsset>> fonts = AssetManager.getAllOfType(FontAsset.class); * List<Asset<FontAsset>> fonts = ResourceManager.getAllOfType(FontAsset.class);
* *
* // Retrieve by asset name or optional lookup * // Retrieve by asset name or optional lookup
* Optional<Asset<? extends BaseResource>> maybeAsset = AssetManager.findByName("menu.css"); * Optional<Asset<? extends BaseResource>> maybeAsset = ResourceManager.findByName("menu.css");
* }</pre> * }</pre>
* *
* <p>Notes:</p> * <p>Notes:</p>
* <ul> * <ul>
* <li>All retrieval methods are static and thread-safe.</li> * <li>All retrieval methods are static and thread-safe.</li>
* <li>The {@link #get(String)} method may require casting if the asset type is not known at compile time.</li> * <li>The {@link #get(String)} method may require casting if the asset type is not known at compile time.</li>
* <li>Assets should be loaded via {@link AssetLoader} before retrieval.</li> * <li>Assets should be loaded via {@link ResourceLoader} before retrieval.</li>
* </ul> * </ul>
*/ */
public class AssetManager { public class ResourceManager {
private static final AssetManager INSTANCE = new AssetManager(); private static final ResourceManager INSTANCE = new ResourceManager();
private static final Map<String, Asset<? extends BaseResource>> assets = new ConcurrentHashMap<>(); private static final Map<String, ResourceMeta<? extends BaseResource>> assets = new ConcurrentHashMap<>();
private AssetManager() {} private ResourceManager() {}
/** /**
* Returns the singleton instance of {@code AssetManager}. * Returns the singleton instance of {@code ResourceManager}.
* *
* @return the shared instance * @return the shared instance
*/ */
public static AssetManager getInstance() { public static ResourceManager getInstance() {
return INSTANCE; return INSTANCE;
} }
/** /**
* Loads all assets from a given {@link AssetLoader} into the manager. * Loads all assets from a given {@link ResourceLoader} into the manager.
* *
* @param loader the loader that has already loaded assets * @param loader the loader that has already loaded assets
*/ */
public synchronized static void loadAssets(AssetLoader loader) { public synchronized static void loadAssets(ResourceLoader loader) {
for (var asset : loader.getAssets()) { for (var asset : loader.getAssets()) {
assets.put(asset.getName(), asset); assets.put(asset.getName(), asset);
} }
@@ -80,11 +80,23 @@ public class AssetManager {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends BaseResource> T get(String name) { public static <T extends BaseResource> T get(String name) {
Asset<T> asset = (Asset<T>) assets.get(name); ResourceMeta<T> asset = (ResourceMeta<T>) assets.get(name);
if (asset == null) return null; if (asset == null) return null;
return asset.getResource(); return asset.getResource();
} }
/**
* Retrieve the resource of a given name, cast to the expected type.
*
* @param name the asset name
* @param <T> the expected resource type
* @return the resource, or null if not found
*/
@SuppressWarnings("unchecked")
public static <T extends BaseResource> T get(Class<T> type, String name) {
return type.cast(assets.get(name).getResource());
}
/** /**
* Retrieve all assets of a specific resource type. * Retrieve all assets of a specific resource type.
* *
@@ -92,12 +104,12 @@ public class AssetManager {
* @param <T> the resource type * @param <T> the resource type
* @return a list of assets matching the type * @return a list of assets matching the type
*/ */
public static <T extends BaseResource> ArrayList<Asset<T>> getAllOfType(Class<T> type) { public static <T extends BaseResource> ArrayList<ResourceMeta<T>> getAllOfType(Class<T> type) {
ArrayList<Asset<T>> list = new ArrayList<>(); ArrayList<ResourceMeta<T>> list = new ArrayList<>();
for (Asset<? extends BaseResource> asset : assets.values()) { for (ResourceMeta<? extends BaseResource> asset : assets.values()) {
if (type.isInstance(asset.getResource())) { if (type.isInstance(asset.getResource())) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Asset<T> typed = (Asset<T>) asset; ResourceMeta<T> typed = (ResourceMeta<T>) asset;
list.add(typed); list.add(typed);
} }
} }
@@ -110,8 +122,8 @@ public class AssetManager {
* @param id the asset ID * @param id the asset ID
* @return the asset, or null if not found * @return the asset, or null if not found
*/ */
public static Asset<? extends BaseResource> getById(String id) { public static ResourceMeta<? extends BaseResource> getById(String id) {
for (Asset<? extends BaseResource> asset : assets.values()) { for (ResourceMeta<? extends BaseResource> asset : assets.values()) {
if (asset.getId().toString().equals(id)) { if (asset.getId().toString().equals(id)) {
return asset; return asset;
} }
@@ -125,7 +137,7 @@ public class AssetManager {
* @param name the asset name * @param name the asset name
* @return the asset, or null if not found * @return the asset, or null if not found
*/ */
public static Asset<? extends BaseResource> getByName(String name) { public static ResourceMeta<? extends BaseResource> getByName(String name) {
return assets.get(name); return assets.get(name);
} }
@@ -135,7 +147,7 @@ public class AssetManager {
* @param name the asset name * @param name the asset name
* @return an Optional containing the asset if found * @return an Optional containing the asset if found
*/ */
public static Optional<Asset<? extends BaseResource>> findByName(String name) { public static Optional<ResourceMeta<? extends BaseResource>> findByName(String name) {
return Optional.ofNullable(assets.get(name)); return Optional.ofNullable(assets.get(name));
} }
@@ -144,7 +156,7 @@ public class AssetManager {
* *
* @param asset the asset to add * @param asset the asset to add
*/ */
public static void addAsset(Asset<? extends BaseResource> asset) { public static void addAsset(ResourceMeta<? extends BaseResource> asset) {
assets.put(asset.getName(), asset); assets.put(asset.getName(), asset);
} }
} }

View File

@@ -3,12 +3,12 @@ package org.toop.framework.asset;
import org.toop.framework.SnowflakeGenerator; import org.toop.framework.SnowflakeGenerator;
import org.toop.framework.asset.resources.BaseResource; import org.toop.framework.asset.resources.BaseResource;
public class Asset <T extends BaseResource> { public class ResourceMeta<T extends BaseResource> {
private final Long id; private final Long id;
private final String name; private final String name;
private final T resource; private final T resource;
public Asset(String name, T resource) { public ResourceMeta(String name, T resource) {
this.id = new SnowflakeGenerator().nextId(); this.id = new SnowflakeGenerator().nextId();
this.name = name; this.name = name;
this.resource = resource; this.resource = resource;

View File

@@ -1,5 +1,7 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import org.toop.framework.asset.types.FileExtension;
import java.io.File; import java.io.File;
@FileExtension({"css"}) @FileExtension({"css"})

View File

@@ -1,6 +1,9 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import javafx.scene.text.Font; 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.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;

View File

@@ -1,6 +1,9 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import javafx.scene.image.Image; 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.File;
import java.io.FileInputStream; import java.io.FileInputStream;

View File

@@ -1,5 +1,9 @@
package org.toop.framework.asset.resources; 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.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;

View File

@@ -1,6 +1,8 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import javafx.scene.media.Media; import javafx.scene.media.Media;
import org.toop.framework.asset.types.FileExtension;
import org.toop.framework.asset.types.LoadableResource;
import java.io.*; import java.io.*;

View File

@@ -1,10 +1,10 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import javafx.scene.media.Media; import org.toop.framework.asset.types.FileExtension;
import org.toop.framework.asset.types.LoadableResource;
import javax.sound.sampled.*; import javax.sound.sampled.*;
import java.io.*; import java.io.*;
import java.net.URI;
@FileExtension({"wav"}) @FileExtension({"wav"})
public class SoundEffectAsset extends BaseResource implements LoadableResource { public class SoundEffectAsset extends BaseResource implements LoadableResource {

View File

@@ -1,5 +1,8 @@
package org.toop.framework.asset.resources; 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.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;

View File

@@ -1,4 +1,6 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.types;
import org.toop.framework.asset.ResourceLoader;
import java.io.File; import java.io.File;
@@ -6,7 +8,7 @@ import java.io.File;
* Represents a resource that can be composed of multiple files, or "bundled" together * Represents a resource that can be composed of multiple files, or "bundled" together
* under a common base name. * under a common base name.
* *
* <p>Implementing classes allow an {@link org.toop.framework.asset.AssetLoader} * <p>Implementing classes allow an {@link ResourceLoader}
* to automatically merge multiple related files into a single resource instance.</p> * to automatically merge multiple related files into a single resource instance.</p>
* *
* <p>Typical use cases include:</p> * <p>Typical use cases include:</p>

View File

@@ -1,4 +1,7 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.types;
import org.toop.framework.asset.ResourceLoader;
import org.toop.framework.asset.resources.BaseResource;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@@ -9,7 +12,7 @@ import java.lang.annotation.ElementType;
* Annotation to declare which file extensions a {@link BaseResource} subclass * Annotation to declare which file extensions a {@link BaseResource} subclass
* can handle. * can handle.
* *
* <p>This annotation is processed by the {@link org.toop.framework.asset.AssetLoader} * <p>This annotation is processed by the {@link ResourceLoader}
* to automatically register resource types for specific file extensions. * to automatically register resource types for specific file extensions.
* Each extension listed will be mapped to the annotated resource class, * Each extension listed will be mapped to the annotated resource class,
* allowing the loader to instantiate the correct type when scanning files.</p> * allowing the loader to instantiate the correct type when scanning files.</p>

View File

@@ -1,4 +1,6 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.types;
import org.toop.framework.asset.ResourceLoader;
/** /**
* Represents a resource that can be explicitly loaded and unloaded. * Represents a resource that can be explicitly loaded and unloaded.
@@ -40,7 +42,7 @@ package org.toop.framework.asset.resources;
* }</pre> * }</pre>
* *
* <p>This interface is commonly used with {@link PreloadResource} to allow automatic * <p>This interface is commonly used with {@link PreloadResource} to allow automatic
* loading by an {@link org.toop.framework.asset.AssetLoader} if desired.</p> * loading by an {@link ResourceLoader} if desired.</p>
*/ */
public interface LoadableResource { public interface LoadableResource {
/** /**

View File

@@ -1,13 +1,15 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.types;
import org.toop.framework.asset.ResourceLoader;
/** /**
* Marker interface for resources that should be **automatically loaded** by the {@link org.toop.framework.asset.AssetLoader}. * Marker interface for resources that should be **automatically loaded** by the {@link ResourceLoader}.
* *
* <p>Extends {@link LoadableResource}, so any implementing class must provide the standard * <p>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#load()} and {@link LoadableResource#unload()} methods, as well as the
* {@link LoadableResource#isLoaded()} check.</p> * {@link LoadableResource#isLoaded()} check.</p>
* *
* <p>When a resource implements {@code PreloadResource}, the {@code AssetLoader} will invoke * <p>When a resource implements {@code PreloadResource}, the {@code ResourceLoader} will invoke
* {@link LoadableResource#load()} automatically after the resource is discovered and instantiated, * {@link LoadableResource#load()} automatically after the resource is discovered and instantiated,
* without requiring manual loading by the user.</p> * without requiring manual loading by the user.</p>
* *

View File

@@ -1,15 +1,15 @@
package org.toop.framework.audio; package org.toop.framework.audio;
import javafx.application.Platform;
import javafx.scene.media.MediaPlayer;
import org.toop.framework.SnowflakeGenerator; import org.toop.framework.SnowflakeGenerator;
import org.toop.framework.asset.Asset; import org.toop.framework.asset.ResourceManager;
import org.toop.framework.asset.AssetManager; import org.toop.framework.asset.ResourceMeta;
import org.toop.framework.asset.resources.MusicAsset; import org.toop.framework.asset.resources.MusicAsset;
import org.toop.framework.asset.resources.SoundEffectAsset; import org.toop.framework.asset.resources.SoundEffectAsset;
import org.toop.framework.audio.events.AudioEvents; import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow; import org.toop.framework.eventbus.EventFlow;
import javafx.scene.media.MediaPlayer;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import javax.sound.sampled.*; import javax.sound.sampled.*;
@@ -25,7 +25,7 @@ public class SoundManager {
public SoundManager() { public SoundManager() {
// Get all Audio Resources and add them to a list. // Get all Audio Resources and add them to a list.
for (Asset<SoundEffectAsset> asset : AssetManager.getAllOfType(SoundEffectAsset.class)) { for (ResourceMeta<SoundEffectAsset> asset : ResourceManager.getAllOfType(SoundEffectAsset.class)) {
try { try {
this.addAudioResource(asset); this.addAudioResource(asset);
} catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) { } catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) {
@@ -58,7 +58,7 @@ public class SoundManager {
this.stopSound(event.clipId()); this.stopSound(event.clipId());
} }
private void addAudioResource(Asset<SoundEffectAsset> audioAsset) private void addAudioResource(ResourceMeta<SoundEffectAsset> audioAsset)
throws IOException, UnsupportedAudioFileException, LineUnavailableException { throws IOException, UnsupportedAudioFileException, LineUnavailableException {
this.audioResources.put(audioAsset.getName(), audioAsset.getResource()); this.audioResources.put(audioAsset.getName(), audioAsset.getResource());
@@ -74,15 +74,15 @@ public class SoundManager {
private void handleMusicStart(AudioEvents.StartBackgroundMusic e) { private void handleMusicStart(AudioEvents.StartBackgroundMusic e) {
backgroundMusicQueue.clear(); backgroundMusicQueue.clear();
Platform.runLater(() -> { List<MusicAsset> shuffledArray = new ArrayList<>(ResourceManager.getAllOfType(MusicAsset.class)
.stream()
.map(ResourceMeta::getResource)
.toList());
Collections.shuffle(shuffledArray);
backgroundMusicQueue.addAll( backgroundMusicQueue.addAll(
AssetManager.getAllOfType(MusicAsset.class).stream() shuffledArray
.map(Asset::getResource)
.toList()
); );
backgroundMusicPlayer(); backgroundMusicPlayer();
});
} }
private void addBackgroundMusic(MusicAsset musicAsset) { private void addBackgroundMusic(MusicAsset musicAsset) {

View File

@@ -1,48 +1,48 @@
package org.toop.game; //package org.toop.game;
//
import org.junit.jupiter.api.BeforeEach; //import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
//
import static org.junit.jupiter.api.Assertions.assertEquals; //import static org.junit.jupiter.api.Assertions.assertEquals;
//
class PlayerTest { //class PlayerTest {
private Player playerA; // private Player playerA;
private Player playerB; // private Player playerB;
private Player playerC; // private Player playerC;
//
@BeforeEach // @BeforeEach
void setup() { // void setup() {
playerA = new Player("test A", 'x', 'Z', 'i'); // playerA = new Player("test A", 'x', 'Z', 'i');
playerB = new Player("test B", 'O', (char)12, (char)-34, 's'); // playerB = new Player("test B", 'O', (char)12, (char)-34, 's');
playerC = new Player("test C", (char)9, '9', (char)-9, '0', 'X', 'O'); // playerC = new Player("test C", (char)9, '9', (char)-9, '0', 'X', 'O');
} // }
//
@Test // @Test
void testNameGetter_returnsTrueForValidName() { // void testNameGetter_returnsTrueForValidName() {
assertEquals("test A", playerA.name()); // assertEquals("test A", playerA.name());
assertEquals("test B", playerB.name()); // assertEquals("test B", playerB.name());
assertEquals("test C", playerC.name()); // assertEquals("test C", playerC.name());
} // }
//
@Test // @Test
void testValuesGetter_returnsTrueForValidValues() { // void testValuesGetter_returnsTrueForValidValues() {
final char[] valuesA = playerA.values(); // final char[] valuesA = playerA.values();
assertEquals('x', valuesA[0]); // assertEquals('x', valuesA[0]);
assertEquals('Z', valuesA[1]); // assertEquals('Z', valuesA[1]);
assertEquals('i', valuesA[2]); // assertEquals('i', valuesA[2]);
//
final char[] valuesB = playerB.values(); // final char[] valuesB = playerB.values();
assertEquals('O', valuesB[0]); // assertEquals('O', valuesB[0]);
assertEquals(12, valuesB[1]); // assertEquals(12, valuesB[1]);
assertEquals((char)-34, valuesB[2]); // assertEquals((char)-34, valuesB[2]);
assertEquals('s', valuesB[3]); // assertEquals('s', valuesB[3]);
//
final char[] valuesC = playerC.values(); // final char[] valuesC = playerC.values();
assertEquals((char)9, valuesC[0]); // assertEquals((char)9, valuesC[0]);
assertEquals('9', valuesC[1]); // assertEquals('9', valuesC[1]);
assertEquals((char)-9, valuesC[2]); // assertEquals((char)-9, valuesC[2]);
assertEquals('0', valuesC[3]); // assertEquals('0', valuesC[3]);
assertEquals('X', valuesC[4]); // assertEquals('X', valuesC[4]);
assertEquals('O', valuesC[5]); // assertEquals('O', valuesC[5]);
} // }
} //}

View File

@@ -1,83 +1,83 @@
package org.toop.game.tictactoe; //package org.toop.game.tictactoe;
//
import org.toop.game.Game; //import org.toop.game.Game;
//
import java.util.Set; //import java.util.Set;
//
import org.junit.jupiter.api.BeforeEach; //import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
//
import static org.junit.jupiter.api.Assertions.*; //import static org.junit.jupiter.api.Assertions.*;
//
class TicTacToeAITest { //class TicTacToeAITest {
private TicTacToe game; // private TicTacToe game;
private TicTacToeAI ai; // private TicTacToeAI ai;
//
@BeforeEach // @BeforeEach
void setup() { // void setup() {
game = new TicTacToe("AI", "AI"); // game = new TicTacToe("AI", "AI");
ai = new TicTacToeAI(); // ai = new TicTacToeAI();
} // }
//
@Test // @Test
void testBestMove_returnWinningMoveWithDepth1() { // void testBestMove_returnWinningMoveWithDepth1() {
// X X - // // X X -
// O O - // // O O -
// - - - // // - - -
game.play(new Game.Move(0, 'X')); // game.play(new Game.Move(0, 'X'));
game.play(new Game.Move(3, 'O')); // game.play(new Game.Move(3, 'O'));
game.play(new Game.Move(1, 'X')); // game.play(new Game.Move(1, 'X'));
game.play(new Game.Move(4, 'O')); // 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); // assertNotNull(move);
assertEquals('X', move.value()); // assertEquals('X', move.value());
assertEquals(2, move.position()); // assertEquals(2, move.position());
} // }
//
@Test // @Test
void testBestMove_blockOpponentWinDepth1() { // void testBestMove_blockOpponentWinDepth1() {
// - - - // // - - -
// O - - // // O - -
// X X - // // X X -
game.play(new Game.Move(6, 'X')); // game.play(new Game.Move(6, 'X'));
game.play(new Game.Move(3, 'O')); // game.play(new Game.Move(3, 'O'));
game.play(new Game.Move(7, 'X')); // 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); // assertNotNull(move);
assertEquals('O', move.value()); // assertEquals('O', move.value());
assertEquals(8, move.position()); // assertEquals(8, move.position());
} // }
//
@Test // @Test
void testBestMove_preferCornerOnEmpty() { // void testBestMove_preferCornerOnEmpty() {
final Game.Move move = ai.findBestMove(game, 0); // final Game.Move move = ai.findBestMove(game, 0);
//
assertNotNull(move); // assertNotNull(move);
assertEquals('X', move.value()); // assertEquals('X', move.value());
assertTrue(Set.of(0, 2, 6, 8).contains(move.position())); // assertTrue(Set.of(0, 2, 6, 8).contains(move.position()));
} // }
//
@Test // @Test
void testBestMove_findBestMoveDraw() { // void testBestMove_findBestMoveDraw() {
// O X - // // O X -
// - O X // // - O X
// X O X // // X O X
game.play(new Game.Move(1, 'X')); // game.play(new Game.Move(1, 'X'));
game.play(new Game.Move(0, 'O')); // game.play(new Game.Move(0, 'O'));
game.play(new Game.Move(5, 'X')); // game.play(new Game.Move(5, 'X'));
game.play(new Game.Move(4, 'O')); // game.play(new Game.Move(4, 'O'));
game.play(new Game.Move(6, 'X')); // game.play(new Game.Move(6, 'X'));
game.play(new Game.Move(7, 'O')); // game.play(new Game.Move(7, 'O'));
game.play(new Game.Move(8, 'X')); // 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); // assertNotNull(move);
assertEquals('O', move.value()); // assertEquals('O', move.value());
assertEquals(2, move.position()); // assertEquals(2, move.position());
} // }
} //}

54
pom.xml
View File

@@ -107,71 +107,19 @@
</java> </java>
</configuration> </configuration>
</plugin> </plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
<configuration>
<excludedGroups>stress</excludedGroups>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.4</version>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version> <version>3.14.1</version>
<configuration> <configuration>
<outputDirectory>${project.build.directory}/custom</outputDirectory>
<source>25</source> <source>25</source>
<target>25</target> <target>25</target>
<release>25</release> <release>25</release>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<!-- <compilerArgs>-->
<!-- <arg>-XDcompilePolicy=simple</arg>-->
<!-- <arg>&#45;&#45;should-stop=ifError=FLOW</arg>-->
<!-- <arg>-Xplugin:ErrorProne</arg>-->
<!-- </compilerArgs>-->
<!-- <annotationProcessorPaths>-->
<!-- <path>-->
<!-- <groupId>com.google.errorprone</groupId>-->
<!-- <artifactId>error_prone_core</artifactId>-->
<!-- <version>2.42.0</version>-->
<!-- </path>-->
<!-- &lt;!&ndash; Other annotation processors go here.-->
<!-- If 'annotationProcessorPaths' is set, processors will no longer be-->
<!-- discovered on the regular -classpath; see also 'Using Error Prone-->
<!-- together with other annotation processors' below. &ndash;&gt;-->
<!-- </annotationProcessorPaths>-->
<!-- <fork>true</fork>-->
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>app.src.java.org.toop.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</pluginManagement>
</build> </build>
<modules> <modules>