diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml index 5f1391a..46f4d3b 100644 --- a/.idea/dictionaries/project.xml +++ b/.idea/dictionaries/project.xml @@ -6,6 +6,7 @@ dcompile errorprone flushnl + gaaf gamelist playerlist tictactoe diff --git a/app/src/main/java/org/toop/Main.java b/app/src/main/java/org/toop/Main.java index 8fb2f17..a3dbd73 100644 --- a/app/src/main/java/org/toop/Main.java +++ b/app/src/main/java/org/toop/Main.java @@ -3,6 +3,7 @@ package org.toop; import org.toop.app.gui.LocalServerSelector; import org.toop.framework.asset.AssetLoader; import org.toop.framework.asset.AssetManager; +import org.toop.framework.asset.resources.TextAsset; import org.toop.framework.audio.SoundManager; import org.toop.framework.audio.events.AudioEvents; import org.toop.framework.eventbus.EventFlow; @@ -14,22 +15,26 @@ import java.io.IOException; import java.nio.file.NotDirectoryException; public class Main { - static void main(String[] args) throws IOException, UnsupportedAudioFileException, LineUnavailableException, InterruptedException { + static void main(String[] args) { - AssetLoader.initialize("app/src/main/resources/assets"); - AssetManager.loadAssets(AssetLoader.getInstance()); + AssetManager.loadAssets(new AssetLoader("app/src/main/resources/assets")); + var text = AssetManager.getAllOfType(TextAsset.class).getFirst().getResource(); + + text.load(); + + IO.println(text.getContent()); var b = new NetworkingClientManager(); var c = new SoundManager(); new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", true)).asyncPostEvent(); - new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", true)).asyncPostEvent(); - Thread.sleep(200); - new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", true)).asyncPostEvent(); - new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", true)).asyncPostEvent(); - Thread.sleep(200); - new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", true)).asyncPostEvent(); - new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", true)).asyncPostEvent(); +// new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", false)).asyncPostEvent(); +// Thread.sleep(200); +// new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", false)).asyncPostEvent(); +// new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", false)).asyncPostEvent(); +// Thread.sleep(200); +// new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", false)).asyncPostEvent(); +// new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", false)).asyncPostEvent(); javax.swing.SwingUtilities.invokeLater(LocalServerSelector::new); } diff --git a/app/src/main/resources/assets/text/test.txt b/app/src/main/resources/assets/text/test.txt new file mode 100644 index 0000000..9e44f93 --- /dev/null +++ b/app/src/main/resources/assets/text/test.txt @@ -0,0 +1 @@ +Super gaaf! \ No newline at end of file diff --git a/framework/src/main/java/org/toop/framework/asset/AssetLoader.java b/framework/src/main/java/org/toop/framework/asset/AssetLoader.java index 1c77c72..397a81a 100644 --- a/framework/src/main/java/org/toop/framework/asset/AssetLoader.java +++ b/framework/src/main/java/org/toop/framework/asset/AssetLoader.java @@ -13,29 +13,16 @@ import org.toop.framework.asset.resources.FileExtension; public class AssetLoader { - private static AssetLoader INSTANCE; - - private final File rootFolder; private final List> assets = new CopyOnWriteArrayList<>(); private final Map> registry = new ConcurrentHashMap<>(); - private AssetLoader(File rootFolder) { - this.rootFolder = rootFolder; + public AssetLoader(File rootFolder) { autoRegisterResources(); fileSearcher(rootFolder); } - public static synchronized void initialize(String rootFolderPath) { - if (INSTANCE == null) { - INSTANCE = new AssetLoader(new File(rootFolderPath)); - } - } - - public static AssetLoader getInstance() { - if (INSTANCE == null) { - throw new IllegalStateException("AssetLoader not initialized. Call initialize() first."); - } - return INSTANCE; + public AssetLoader(String rootFolder) { + this(new File(rootFolder)); } public List> getAssets() { diff --git a/framework/src/main/java/org/toop/framework/asset/resources/AudioAsset.java b/framework/src/main/java/org/toop/framework/asset/resources/AudioAsset.java index 9a4a679..4b00212 100644 --- a/framework/src/main/java/org/toop/framework/asset/resources/AudioAsset.java +++ b/framework/src/main/java/org/toop/framework/asset/resources/AudioAsset.java @@ -26,6 +26,26 @@ public class AudioAsset extends BaseResource implements LoadableResource { // Generates a new audio stream from byte array private AudioInputStream getAudioStream() throws UnsupportedAudioFileException, IOException { - return AudioSystem.getAudioInputStream(this.getInputStream()); + return AudioSystem.getAudioInputStream(this.file); + } + + @Override + public void load() { + try { + this.getAudioStream(); + this.isLoaded = true; + } catch (UnsupportedAudioFileException | IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void unload() { + this.isLoaded = false; // TODO? + } + + @Override + public boolean isLoaded() { + return this.isLoaded; } } 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 95ce7aa..c1aa040 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 @@ -1,53 +1,18 @@ package org.toop.framework.asset.resources; import java.io.*; -import java.nio.file.Files; public abstract class BaseResource { - private byte[] rawData; + final File file; - private boolean isLoaded = false; + boolean isLoaded = false; - BaseResource(final File file) { + protected BaseResource(final File file) { this.file = file; } - public boolean isLoaded() { - return this.isLoaded; - } - - public void load() throws FileNotFoundException { - this.loadRawData(); - isLoaded = true; - } - - private void loadRawData() throws FileNotFoundException{ - try { - this.rawData = Files.readAllBytes(file.toPath()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public void unload(){ - this.unloadRawData(); - isLoaded = false; - } - - private void unloadRawData() { - this.rawData = null; - } - public File getFile() { return this.file; } - public InputStream getInputStream() throws FileNotFoundException { - if (!isLoaded){ - // Manually load the data, makes sure it doesn't call subclass load() - loadRawData(); - isLoaded = true; - } - return new BufferedInputStream(new ByteArrayInputStream(this.rawData)); - } } 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 b4f3d06..db4ad84 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,28 +1,25 @@ package org.toop.framework.asset.resources; import java.io.File; -import java.io.FileNotFoundException; public class FontAsset extends BaseResource implements LoadableResource { - private boolean isLoaded = false; - public FontAsset(final File fontFile) { super(fontFile); } - @Override - public void load() throws FileNotFoundException { + public void load() { + this.isLoaded = true; } @Override public void unload() { - + this.isLoaded = false; } @Override public boolean isLoaded() { - return false; + return this.isLoaded; } } 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 5f12d58..3cc0a3b 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 @@ -2,9 +2,9 @@ package org.toop.framework.asset.resources; import javafx.scene.image.Image; import java.io.File; -import java.io.FileNotFoundException; +import java.io.FileInputStream; -@FileExtension({"png"}) +@FileExtension({"png", "jpg", "jpeg"}) public class ImageAsset extends BaseResource implements LoadableResource { private Image image; @@ -13,25 +13,33 @@ public class ImageAsset extends BaseResource implements LoadableResource { } @Override - public void load() throws FileNotFoundException { - if (!this.isLoaded()) { - super.load(); // Make sure that base class (byte[]) is loaded - this.image = new Image(this.getInputStream()); + public void load() { + if (!this.isLoaded) { + try (FileInputStream fis = new FileInputStream(this.file)) { + this.image = new Image(fis); + this.isLoaded = true; + } catch (Exception e) { + throw new RuntimeException("Failed to load image: " + this.file, e); + } } } @Override public void unload() { this.image = null; - super.unload(); + this.isLoaded = false; + } + + @Override + public boolean isLoaded() { + return this.isLoaded; } public Image getImage() { - if (!this.isLoaded()) try { - load(); - } catch (FileNotFoundException e) { - throw new RuntimeException(e); + if (!this.isLoaded) { + this.load(); + return image; } - return image; + return null; } -} +} \ No newline at end of file diff --git a/framework/src/main/java/org/toop/framework/asset/resources/LoadableResource.java b/framework/src/main/java/org/toop/framework/asset/resources/LoadableResource.java index fe14ab6..4b94092 100644 --- a/framework/src/main/java/org/toop/framework/asset/resources/LoadableResource.java +++ b/framework/src/main/java/org/toop/framework/asset/resources/LoadableResource.java @@ -3,7 +3,7 @@ package org.toop.framework.asset.resources; import java.io.FileNotFoundException; public interface LoadableResource { - void load() throws FileNotFoundException; + void load(); void unload(); boolean isLoaded(); } 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 new file mode 100644 index 0000000..27d9b83 --- /dev/null +++ b/framework/src/main/java/org/toop/framework/asset/resources/LocalizationAsset.java @@ -0,0 +1,85 @@ +package org.toop.framework.asset.resources; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.*; + +@FileExtension({"properties"}) +public class LocalizationAsset extends BaseResource implements LoadableResource { + private final Map bundles = new HashMap<>(); + private boolean isLoaded = false; + + public LocalizationAsset(File file) { + super(file); + } + + @Override + public void load() { + // Convention: file names like messages_en.properties, ui_de.properties, etc. + String baseName = getBaseName(getFile().getName()); + + // Scan the parent folder for all matching *.properties with same basename + File folder = getFile().getParentFile(); + File[] files = folder.listFiles((dir, name) -> + name.startsWith(baseName) && name.endsWith(".properties")); + + if (files != null) { + for (File f : files) { + Locale locale = extractLocale(f.getName(), baseName); + try (InputStreamReader reader = + new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8)) { + this.bundles.put(locale, new PropertyResourceBundle(reader)); + } catch (IOException e) { + throw new RuntimeException("Failed to load localization file: " + f, e); + } + } + } + + this.isLoaded = true; + } + + @Override + public void unload() { + this.bundles.clear(); + this.isLoaded = false; + } + + @Override + public boolean isLoaded() { + return this.isLoaded; + } + + public String getString(String key, Locale locale) { + ResourceBundle bundle = this.bundles.get(locale); + if (bundle == null) throw new MissingResourceException( + "No bundle for locale: " + locale, getClass().getName(), key); + return bundle.getString(key); + } + + public boolean hasLocale(Locale locale) { + return this.bundles.containsKey(locale); + } + + public Set getAvailableLocales() { + return Collections.unmodifiableSet(this.bundles.keySet()); + } + + private String getBaseName(String fileName) { + int underscoreIndex = fileName.indexOf('_'); + int dotIndex = fileName.lastIndexOf('.'); + if (underscoreIndex > 0) { + return fileName.substring(0, underscoreIndex); + } + return fileName.substring(0, dotIndex); + } + + private Locale extractLocale(String fileName, String baseName) { + int underscoreIndex = fileName.indexOf('_'); + int dotIndex = fileName.lastIndexOf('.'); + if (underscoreIndex > 0 && dotIndex > underscoreIndex) { + String localePart = fileName.substring(underscoreIndex + 1, dotIndex); + return Locale.forLanguageTag(localePart.replace('_', '-')); + } + return Locale.getDefault(); // fallback + } +} \ No newline at end of file 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 5231513..8fc51bc 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,26 +1,41 @@ package org.toop.framework.asset.resources; import java.io.File; -import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +@FileExtension({"txt", "json", "xml"}) public class TextAsset extends BaseResource implements LoadableResource { + private String content; - TextAsset(final File file) { + public TextAsset(File file) { super(file); } @Override - public void load() throws FileNotFoundException { - + public void load() { + try { + byte[] bytes = Files.readAllBytes(getFile().toPath()); + this.content = new String(bytes, StandardCharsets.UTF_8); + this.isLoaded = true; + } catch (IOException e) { + throw new RuntimeException("Failed to load text asset: " + getFile(), e); + } } @Override public void unload() { - + this.content = null; + this.isLoaded = false; } @Override public boolean isLoaded() { - return false; + return this.isLoaded; } -} + + public String getContent() { + return this.content; + } +} \ No newline at end of file