Moved loads to own class for better memory management. Added ability to add text- and localizationassets.

This commit is contained in:
lieght
2025-10-01 04:19:28 +02:00
parent f11ff0421b
commit 5e4db91750
11 changed files with 177 additions and 93 deletions

View File

@@ -6,6 +6,7 @@
<w>dcompile</w> <w>dcompile</w>
<w>errorprone</w> <w>errorprone</w>
<w>flushnl</w> <w>flushnl</w>
<w>gaaf</w>
<w>gamelist</w> <w>gamelist</w>
<w>playerlist</w> <w>playerlist</w>
<w>tictactoe</w> <w>tictactoe</w>

View File

@@ -3,6 +3,7 @@ package org.toop;
import org.toop.app.gui.LocalServerSelector; import org.toop.app.gui.LocalServerSelector;
import org.toop.framework.asset.AssetLoader; import org.toop.framework.asset.AssetLoader;
import org.toop.framework.asset.AssetManager; import org.toop.framework.asset.AssetManager;
import org.toop.framework.asset.resources.TextAsset;
import org.toop.framework.audio.SoundManager; import org.toop.framework.audio.SoundManager;
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;
@@ -14,22 +15,26 @@ import java.io.IOException;
import java.nio.file.NotDirectoryException; import java.nio.file.NotDirectoryException;
public class Main { 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(new AssetLoader("app/src/main/resources/assets"));
AssetManager.loadAssets(AssetLoader.getInstance()); var text = AssetManager.getAllOfType(TextAsset.class).getFirst().getResource();
text.load();
IO.println(text.getContent());
var b = new NetworkingClientManager(); var b = new NetworkingClientManager();
var c = new SoundManager(); var c = new SoundManager();
new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", true)).asyncPostEvent(); 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); // Thread.sleep(200);
new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", true)).asyncPostEvent(); // new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", false)).asyncPostEvent();
new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", true)).asyncPostEvent(); // new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", false)).asyncPostEvent();
Thread.sleep(200); // Thread.sleep(200);
new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", true)).asyncPostEvent(); // new EventFlow().addPostEvent(new AudioEvents.PlayAudio("mainmenu.wav", false)).asyncPostEvent();
new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", true)).asyncPostEvent(); // new EventFlow().addPostEvent(new AudioEvents.PlayAudio("sadtrombone.wav", false)).asyncPostEvent();
javax.swing.SwingUtilities.invokeLater(LocalServerSelector::new); javax.swing.SwingUtilities.invokeLater(LocalServerSelector::new);
} }

View File

@@ -0,0 +1 @@
Super gaaf!

View File

@@ -13,29 +13,16 @@ import org.toop.framework.asset.resources.FileExtension;
public class AssetLoader { public class AssetLoader {
private static AssetLoader INSTANCE;
private final File rootFolder;
private final List<Asset<? extends BaseResource>> assets = new CopyOnWriteArrayList<>(); private final List<Asset<? 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 AssetLoader(File rootFolder) { public AssetLoader(File rootFolder) {
this.rootFolder = rootFolder;
autoRegisterResources(); autoRegisterResources();
fileSearcher(rootFolder); fileSearcher(rootFolder);
} }
public static synchronized void initialize(String rootFolderPath) { public AssetLoader(String rootFolder) {
if (INSTANCE == null) { this(new File(rootFolder));
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 List<Asset<? extends BaseResource>> getAssets() { public List<Asset<? extends BaseResource>> getAssets() {

View File

@@ -26,6 +26,26 @@ public class AudioAsset extends BaseResource implements LoadableResource {
// Generates a new audio stream from byte array // Generates a new audio stream from byte array
private AudioInputStream getAudioStream() throws UnsupportedAudioFileException, IOException { 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;
} }
} }

View File

@@ -1,53 +1,18 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import java.io.*; import java.io.*;
import java.nio.file.Files;
public abstract class BaseResource { public abstract class BaseResource {
private byte[] rawData;
final File file; final File file;
private boolean isLoaded = false; boolean isLoaded = false;
BaseResource(final File file) { protected BaseResource(final File file) {
this.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() { public File getFile() {
return this.file; 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));
}
} }

View File

@@ -1,28 +1,25 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
public class FontAsset extends BaseResource implements LoadableResource { public class FontAsset extends BaseResource implements LoadableResource {
private boolean isLoaded = false;
public FontAsset(final File fontFile) { public FontAsset(final File fontFile) {
super(fontFile); super(fontFile);
} }
@Override @Override
public void load() throws FileNotFoundException { public void load() {
this.isLoaded = true;
} }
@Override @Override
public void unload() { public void unload() {
this.isLoaded = false;
} }
@Override @Override
public boolean isLoaded() { public boolean isLoaded() {
return false; return this.isLoaded;
} }
} }

View File

@@ -2,9 +2,9 @@ package org.toop.framework.asset.resources;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import java.io.File; 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 { public class ImageAsset extends BaseResource implements LoadableResource {
private Image image; private Image image;
@@ -13,25 +13,33 @@ public class ImageAsset extends BaseResource implements LoadableResource {
} }
@Override @Override
public void load() throws FileNotFoundException { public void load() {
if (!this.isLoaded()) { if (!this.isLoaded) {
super.load(); // Make sure that base class (byte[]) is loaded try (FileInputStream fis = new FileInputStream(this.file)) {
this.image = new Image(this.getInputStream()); this.image = new Image(fis);
this.isLoaded = true;
} catch (Exception e) {
throw new RuntimeException("Failed to load image: " + this.file, e);
}
} }
} }
@Override @Override
public void unload() { public void unload() {
this.image = null; this.image = null;
super.unload(); this.isLoaded = false;
}
@Override
public boolean isLoaded() {
return this.isLoaded;
} }
public Image getImage() { public Image getImage() {
if (!this.isLoaded()) try { if (!this.isLoaded) {
load(); this.load();
} catch (FileNotFoundException e) { return image;
throw new RuntimeException(e);
} }
return image; return null;
} }
} }

View File

@@ -3,7 +3,7 @@ package org.toop.framework.asset.resources;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
public interface LoadableResource { public interface LoadableResource {
void load() throws FileNotFoundException; void load();
void unload(); void unload();
boolean isLoaded(); boolean isLoaded();
} }

View File

@@ -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<Locale, ResourceBundle> 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<Locale> 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
}
}

View File

@@ -1,26 +1,41 @@
package org.toop.framework.asset.resources; package org.toop.framework.asset.resources;
import java.io.File; 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 { public class TextAsset extends BaseResource implements LoadableResource {
private String content;
TextAsset(final File file) { public TextAsset(File file) {
super(file); super(file);
} }
@Override @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 @Override
public void unload() { public void unload() {
this.content = null;
this.isLoaded = false;
} }
@Override @Override
public boolean isLoaded() { public boolean isLoaded() {
return false; return this.isLoaded;
}
public String getContent() {
return this.content;
} }
} }