diff --git a/src/junk/AppInitOptions.java b/src/junk/AppInitOptions.java index 22ac9ee..7d60a5e 100644 --- a/src/junk/AppInitOptions.java +++ b/src/junk/AppInitOptions.java @@ -7,7 +7,7 @@ import java.util.List; import java.util.logging.Level; import mightypork.gamecore.core.AppBackend; -import mightypork.gamecore.resources.ResourceSetup; +import mightypork.gamecore.resources.ResourceInitializer; import mightypork.gamecore.resources.loading.AsyncResourceLoader; import mightypork.gamecore.resources.loading.ResourceLoader; @@ -27,7 +27,7 @@ public class AppInitOptions { String configFile = "settings.cfg"; String configComment = "Main config file"; - final List resourceLists = new ArrayList<>(); + final List resourceLists = new ArrayList<>(); final List keyLists = new ArrayList<>(); final List configLists = new ArrayList<>(); @@ -56,7 +56,7 @@ public class AppInitOptions { } - public void addResources(ResourceSetup res) + public void addResources(ResourceInitializer res) { resourceLists.add(res); } diff --git a/src/junk/BaseApp.java b/src/junk/BaseApp.java index 50a9728..cf5416c 100644 --- a/src/junk/BaseApp.java +++ b/src/junk/BaseApp.java @@ -10,7 +10,7 @@ import mightypork.gamecore.core.config.Config; import mightypork.gamecore.gui.screens.ScreenRegistry; import mightypork.gamecore.gui.screens.impl.CrossfadeOverlay; import mightypork.gamecore.resources.Res; -import mightypork.gamecore.resources.ResourceSetup; +import mightypork.gamecore.resources.ResourceInitializer; import mightypork.utils.files.WorkDir; import mightypork.utils.logging.Log; @@ -140,7 +140,7 @@ public abstract class BaseApp extends App implements UncaughtExceptionHandler { Res.setBaseDir(this); - for (final ResourceSetup rl : opt.resourceLists) { + for (final ResourceInitializer rl : opt.resourceLists) { Res.load(rl); } diff --git a/src/mightypork/gamecore/audio/DeferredAudio.java b/src/mightypork/gamecore/audio/DeferredAudio.java index c24c9bf..4a18528 100644 --- a/src/mightypork/gamecore/audio/DeferredAudio.java +++ b/src/mightypork/gamecore/audio/DeferredAudio.java @@ -29,14 +29,14 @@ public abstract class DeferredAudio extends BaseDeferredResource implements IAud @Override public void play(double gain, double pitch, boolean loop) { - play(gain, pitch, loop, App.audio().getListenerPos()); + play(gain, pitch, loop, App.sound().getListenerPos()); } @Override public void play(double gain, double pitch, boolean loop, double x, double y) { - play(gain, pitch, loop, x, y, App.audio().getListenerPos().z()); + play(gain, pitch, loop, x, y, App.sound().getListenerPos().z()); } diff --git a/src/mightypork/gamecore/audio/IAudio.java b/src/mightypork/gamecore/audio/IAudio.java index bf5e862..9105e3f 100644 --- a/src/mightypork/gamecore/audio/IAudio.java +++ b/src/mightypork/gamecore/audio/IAudio.java @@ -19,7 +19,7 @@ public interface IAudio extends Destroyable { /** - * Resume loop (if was paused) + * Resume loop (if was looping and paused) */ void resumeLoop(); @@ -34,7 +34,8 @@ public interface IAudio extends Destroyable { /** - * Stop audio playback, free source. + * Stop audio playback, free source. Meaningful for loops, may not work + * properly for effects. */ void stop(); diff --git a/src/mightypork/gamecore/audio/SoundRegistry.java b/src/mightypork/gamecore/audio/SoundRegistry.java index 898f5d3..00581b4 100644 --- a/src/mightypork/gamecore/audio/SoundRegistry.java +++ b/src/mightypork/gamecore/audio/SoundRegistry.java @@ -6,6 +6,8 @@ import java.util.Map; import mightypork.gamecore.audio.players.EffectPlayer; import mightypork.gamecore.audio.players.LoopPlayer; +import mightypork.gamecore.core.App; +import mightypork.utils.exceptions.KeyAlreadyExistsException; /** @@ -19,6 +21,28 @@ public class SoundRegistry { private final Map loops = new HashMap<>(); + /** + * Register effect resource + * + * @param key sound key + * @param resourcePath path to the effect resource + * @param gain gain adjustment + * @param pitch pitch adjustment + * @return the just created effect player + */ + public EffectPlayer addEffect(String key, String resourcePath, double gain, double pitch) + { + final EffectPlayer effect = App.sound().createEffect(resourcePath); + + effect.setPitch(pitch); + effect.setGain(gain); + + addEffect(key, effect); + + return effect; + } + + /** * Register effect resource * @@ -27,10 +51,37 @@ public class SoundRegistry { */ public void addEffect(String key, EffectPlayer effect) { + if (effects.containsKey(key)) throw new KeyAlreadyExistsException(); + effects.put(key, effect); } + /** + * Register loop resource (music / effect loop) + * + * @param key sound key + * @param resourcePath path to the effect resource + * @param gain gain adjustment + * @param pitch pitch adjustment + * @param fadeIn fadeIn time (s) + * @param fadeOut fadeOut time (s) + * @return the just created loop player + */ + public LoopPlayer addLoop(String key, String resourcePath, double gain, double pitch, double fadeIn, double fadeOut) + { + final LoopPlayer loop = App.sound().createLoop(resourcePath); + + loop.setPitch(pitch); + loop.setGain(gain); + loop.setFadeTimes(fadeIn, fadeOut); + + addLoop(key, loop); + + return loop; + } + + /** * Register loop resource (music / effect loop) * @@ -39,6 +90,8 @@ public class SoundRegistry { */ public void addLoop(String key, LoopPlayer loop) { + if (loops.containsKey(key)) throw new KeyAlreadyExistsException(); + loops.put(key, loop); } diff --git a/src/mightypork/gamecore/audio/players/AudioPlayer.java b/src/mightypork/gamecore/audio/players/AudioPlayer.java index 198b33b..51d0de1 100644 --- a/src/mightypork/gamecore/audio/players/AudioPlayer.java +++ b/src/mightypork/gamecore/audio/players/AudioPlayer.java @@ -12,20 +12,20 @@ import mightypork.utils.interfaces.Destroyable; * @author Ondřej Hruška (MightyPork) */ public abstract class AudioPlayer implements Destroyable { - + /** the track */ private final IAudio audio; - + /** base gain for sfx */ private double baseGain; - + /** base pitch for sfx */ private double basePitch; - + /** dedicated volume control */ private final Volume gainMultiplier; - - + + /** * @param track audio resource * @param volume colume control @@ -33,20 +33,20 @@ public abstract class AudioPlayer implements Destroyable { public AudioPlayer(IAudio track, Volume volume) { this.audio = track; - + if (volume == null) volume = new Volume(1D); - + this.gainMultiplier = volume; } - - + + @Override public void destroy() { audio.destroy(); } - - + + /** * @return audio resource */ @@ -54,8 +54,8 @@ public abstract class AudioPlayer implements Destroyable { { return audio; } - - + + /** * Get play gain, computed based on volume and given multiplier * @@ -66,8 +66,8 @@ public abstract class AudioPlayer implements Destroyable { { return baseGain * gainMultiplier.get() * multiplier; } - - + + /** * Get pitch * @@ -78,8 +78,8 @@ public abstract class AudioPlayer implements Destroyable { { return basePitch * multiplier; } - - + + /** * Get if audio is valid * @@ -89,27 +89,27 @@ public abstract class AudioPlayer implements Destroyable { { return (audio != null); } - - + + /** * Set base gain. 1 is original volume, 0 is silence. * - * @param baseGain base gain + * @param gain base gain */ - public void setGain(double baseGain) + public void setGain(double gain) { - this.baseGain = baseGain; + this.baseGain = gain; } - - + + /** * Set base pitch. 1 is original pitch, less is deeper, more is higher. * - * @param basePitch base pitch + * @param pitch base pitch */ - public void setPitch(double basePitch) + public void setPitch(double pitch) { - this.basePitch = basePitch; + this.basePitch = pitch; } - + } diff --git a/src/mightypork/gamecore/audio/players/LoopPlayer.java b/src/mightypork/gamecore/audio/players/LoopPlayer.java index eb733e9..3cc64c6 100644 --- a/src/mightypork/gamecore/audio/players/LoopPlayer.java +++ b/src/mightypork/gamecore/audio/players/LoopPlayer.java @@ -9,27 +9,27 @@ import mightypork.utils.math.animation.NumAnimated; /** - * Audio loop player (with fading, good for music) + * Audio loop player (with fading, for music) * * @author Ondřej Hruška (MightyPork) */ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { - + /** animator for fade in and fade out */ private final NumAnimated fadeAnim = new NumAnimated(0); - + private double lastUpdateGain = 0; - + /** flag that track is paused */ private boolean paused = true; - + /** Default fadeIn time */ private double inTime = 1; - + /** Default fadeOut time */ private double outTime = 1; - - + + /** * @param track audio resource * @param volume volume control @@ -37,11 +37,11 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { public LoopPlayer(DeferredAudio track, Volume volume) { super(track, volume); - + paused = true; } - - + + /** * Set fading duration (seconds) * @@ -53,8 +53,8 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { inTime = in; outTime = out; } - - + + private void initLoop() { if (hasAudio() && !getAudio().isActive()) { @@ -62,27 +62,27 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { getAudio().pauseLoop(); } } - - + + @Override public void pause() { if (!hasAudio() || paused) return; - + initLoop(); - + getAudio().pauseLoop(); paused = true; } - - + + @Override public boolean isPaused() { return paused; } - - + + /** * Alias to resume (more meaningful name) */ @@ -90,40 +90,40 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { { resume(); } - - + + @Override public void resume() { if (!hasAudio() || !paused) return; - + initLoop(); - + paused = false; - + getAudio().adjustGain(computeGain(fadeAnim.value())); } - - + + @Override public void update(double delta) { if (!hasAudio() || paused) return; - + initLoop(); - + fadeAnim.update(delta); - + final double gain = computeGain(fadeAnim.value()); if (!paused && gain != lastUpdateGain) { getAudio().adjustGain(gain); lastUpdateGain = gain; } - + if (gain == 0 && !paused) pause(); // pause on zero volume } - - + + /** * Resume if paused, and fade in (pick up from current volume). * @@ -132,13 +132,13 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { public void fadeIn(double fadeTime) { if (!hasAudio()) return; - + if (isPaused()) fadeAnim.setTo(0); resume(); fadeAnim.fadeIn(fadeTime); } - - + + /** * Fade out and pause when reached zero volume * @@ -150,8 +150,8 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { if (isPaused()) return; fadeAnim.fadeOut(fadeTime); } - - + + /** * Fade in with default duration */ @@ -159,8 +159,8 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { { fadeIn(inTime); } - - + + /** * Fade out with default duration */ @@ -168,5 +168,5 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable { { fadeOut(outTime); } - + } diff --git a/src/mightypork/gamecore/core/App.java b/src/mightypork/gamecore/core/App.java index 7cf9054..f8032ed 100644 --- a/src/mightypork/gamecore/core/App.java +++ b/src/mightypork/gamecore/core/App.java @@ -7,6 +7,8 @@ import java.util.List; import mightypork.gamecore.audio.AudioModule; import mightypork.gamecore.core.config.Config; import mightypork.gamecore.core.events.ShutdownEvent; +import mightypork.gamecore.core.init.InitTask; +import mightypork.gamecore.core.plugins.AppPlugin; import mightypork.gamecore.graphics.GraphicsModule; import mightypork.gamecore.input.InputModule; import mightypork.utils.annotations.Stub; @@ -23,19 +25,19 @@ import mightypork.utils.logging.Log; * @author MightyPork */ public class App extends BusNode { - + private static App instance; - + private final AppBackend backend; private final EventBus eventBus = new EventBus(); private boolean started = false; - + /** List of installed App plugins */ protected final DelegatingList plugins = new DelegatingList(); /** List of initializers */ protected final List initializers = new ArrayList<>(); - - + + /** * Create an app with given backend. * @@ -46,24 +48,24 @@ public class App extends BusNode { if (App.instance != null) { throw new IllegalStateException("App already initialized"); } - + // store current instance in static field App.instance = this; - + // join the bus this.eventBus.subscribe(this); - + // create plugin registry attached to bus this.eventBus.subscribe(this.plugins); - + // initialize and use backend this.backend = backend; this.backend.bind(this); this.eventBus.subscribe(backend); this.backend.initialize(); } - - + + /** * Add a plugin to the app. Plugins can eg. listen to bus events and react * to them. @@ -75,14 +77,14 @@ public class App extends BusNode { if (started) { throw new IllegalStateException("App already started, cannot add plugins."); } - + // attach to event bus plugins.add(plugin); plugin.bind(this); plugin.initialize(); } - - + + /** * Add an initializer to the app. * @@ -93,11 +95,11 @@ public class App extends BusNode { if (started) { throw new IllegalStateException("App already started, cannot add initializers."); } - + initializers.add(initializer); } - - + + /** * Get current backend * @@ -107,8 +109,8 @@ public class App extends BusNode { { return backend; } - - + + /** * Initialize the App and start operating.
* This method should be called after adding all required initializers and @@ -120,41 +122,41 @@ public class App extends BusNode { throw new IllegalStateException("Already started."); } started = true; - + // pre-init hook, just in case anyone wanted to have one. Log.f2("Calling pre-init hook..."); preInit(); - + Log.i("=== Starting initialization sequence ==="); - + // sort initializers by order. final List orderedInitializers = InitTask.inOrder(initializers); - + for (final InitTask initTask : orderedInitializers) { Log.f1("Running init task \"" + initTask.getName() + "\"..."); - + initTask.bind(this); - + // set the task options initTask.init(); - + initTask.before(); - + // main task action initTask.run(); - + // after hook for extra actions immeditaely after the task completes initTask.after(); } - + Log.i("=== Initialization sequence completed ==="); - + // user can now start the main loop etc. Log.f2("Calling post-init hook..."); postInit(); } - - + + /** * Hook called before the initialization sequence starts. */ @@ -162,8 +164,8 @@ public class App extends BusNode { protected void preInit() { } - - + + /** * Hook called after the initialization sequence is finished. */ @@ -171,8 +173,8 @@ public class App extends BusNode { protected void postInit() { } - - + + /** * Shut down the running instance.
* Deinitialize backend modules and terminate the JVM. @@ -181,9 +183,9 @@ public class App extends BusNode { { if (instance != null) { Log.i("Dispatching Shutdown event..."); - + bus().send(new ShutdownEvent(new Runnable() { - + @Override public void run() { @@ -196,19 +198,19 @@ public class App extends BusNode { } catch (final Throwable e) { Log.e(e); } - + Log.i("Shutdown completed."); System.exit(0); } })); - + } else { Log.w("App is not running."); System.exit(0); } } - - + + /** * Get the currently running App instance. * @@ -218,8 +220,8 @@ public class App extends BusNode { { return instance; } - - + + /** * Get graphics module from the running app's backend * @@ -229,19 +231,19 @@ public class App extends BusNode { { return instance.backend.getGraphics(); } - - + + /** * Get audio module from the running app's backend * * @return audio module */ - public static AudioModule audio() + public static AudioModule sound() { return instance.backend.getAudio(); } - - + + /** * Get input module from the running app's backend * @@ -251,8 +253,8 @@ public class App extends BusNode { { return instance.backend.getInput(); } - - + + /** * Get event bus instance. * @@ -262,8 +264,8 @@ public class App extends BusNode { { return instance.eventBus; } - - + + /** * Get the main config, if initialized. * @@ -274,8 +276,8 @@ public class App extends BusNode { { return cfg("main"); } - - + + /** * Get a config by alias. * diff --git a/src/mightypork/gamecore/core/config/InitTaskConfig.java b/src/mightypork/gamecore/core/config/InitTaskConfig.java index 0f65c89..cbc1d05 100644 --- a/src/mightypork/gamecore/core/config/InitTaskConfig.java +++ b/src/mightypork/gamecore/core/config/InitTaskConfig.java @@ -1,7 +1,7 @@ package mightypork.gamecore.core.config; -import mightypork.gamecore.core.InitTask; +import mightypork.gamecore.core.init.InitTask; import mightypork.utils.annotations.Stub; diff --git a/src/mightypork/gamecore/core/InitTask.java b/src/mightypork/gamecore/core/init/InitTask.java similarity index 94% rename from src/mightypork/gamecore/core/InitTask.java rename to src/mightypork/gamecore/core/init/InitTask.java index cd3923a..0bee46b 100644 --- a/src/mightypork/gamecore/core/InitTask.java +++ b/src/mightypork/gamecore/core/init/InitTask.java @@ -1,4 +1,4 @@ -package mightypork.gamecore.core; +package mightypork.gamecore.core.init; import java.util.ArrayList; @@ -7,6 +7,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import mightypork.gamecore.core.App; import mightypork.utils.Reflect; import mightypork.utils.annotations.Stub; import mightypork.utils.logging.Log; @@ -20,22 +21,22 @@ import mightypork.utils.logging.Log; * @author Ondřej Hruška (MightyPork) */ public abstract class InitTask { - + /** App instance assigned using bind() */ protected App app; - - + + /** * Assign the initialized app instance to an "app" field. * * @param app app */ - final void bind(App app) + public final void bind(App app) { this.app = app; } - - + + /** * An init method that is called before the run() method.
* This method should be left unimplemented in the task, and can be used to @@ -46,8 +47,8 @@ public abstract class InitTask { { // } - - + + /** * Hook for extra action before the main task action.
* Can be overridden during app configuration to "bake-in" extra actions. @@ -57,14 +58,14 @@ public abstract class InitTask { { // } - - + + /** * Run the initializer on app. */ public abstract void run(); - - + + /** * Hook executed after the "run()" method.
* Can be overridden during app configuration to "bake-in" extra actions. @@ -74,8 +75,8 @@ public abstract class InitTask { { // } - - + + /** * Get name of this initializer (for dependency resolver).
* The name should be short, snake_case and precise. @@ -83,8 +84,8 @@ public abstract class InitTask { * @return name */ public abstract String getName(); - - + + /** * Get what other initializers must be already loaded before this can load.
* Depending on itself or creating a circular dependency will cause error.
@@ -98,8 +99,8 @@ public abstract class InitTask { { return new String[] {}; } - - + + /** * Order init tasks so that all dependencies are loaded before thye are * needed by the tasks. @@ -110,25 +111,25 @@ public abstract class InitTask { public static List inOrder(List tasks) { final List remaining = new ArrayList<>(tasks); - + final List ordered = new ArrayList<>(); final Set loaded = new HashSet<>(); - + // resolve task order int addedThisIteration = 0; do { for (final Iterator i = remaining.iterator(); i.hasNext();) { final InitTask task = i.next(); - + String[] deps = task.getDependencies(); if (deps == null) deps = new String[] {}; - + int unmetDepsCount = deps.length; - + for (final String d : deps) { if (loaded.contains(d)) unmetDepsCount--; } - + if (unmetDepsCount == 0) { ordered.add(task); loaded.add(task.getName()); @@ -137,38 +138,38 @@ public abstract class InitTask { } } } while (addedThisIteration > 0); - + // check if any tasks are left out if (remaining.size() > 0) { - + // build error message for each bad task int badInitializers = 0; for (final InitTask task : remaining) { if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) { continue; } - + badInitializers++; - + String notSatisfied = ""; - + for (final String d : task.getDependencies()) { if (!loaded.contains(d)) { - + if (!notSatisfied.isEmpty()) { notSatisfied += ", "; } - + notSatisfied += d; } } - + Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied); } - + if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied."); } - + return ordered; } } diff --git a/src/mightypork/gamecore/core/init/InitTaskCrashHandler.java b/src/mightypork/gamecore/core/init/InitTaskCrashHandler.java index 0abea2c..a7cef0e 100644 --- a/src/mightypork/gamecore/core/init/InitTaskCrashHandler.java +++ b/src/mightypork/gamecore/core/init/InitTaskCrashHandler.java @@ -4,7 +4,6 @@ package mightypork.gamecore.core.init; import java.lang.Thread.UncaughtExceptionHandler; import mightypork.gamecore.core.App; -import mightypork.gamecore.core.InitTask; import mightypork.utils.annotations.Stub; import mightypork.utils.logging.Log; diff --git a/src/mightypork/gamecore/core/init/InitTaskDisplay.java b/src/mightypork/gamecore/core/init/InitTaskDisplay.java index 2b38350..ebb7f03 100644 --- a/src/mightypork/gamecore/core/init/InitTaskDisplay.java +++ b/src/mightypork/gamecore/core/init/InitTaskDisplay.java @@ -1,7 +1,6 @@ package mightypork.gamecore.core.init; -import mightypork.gamecore.core.InitTask; import mightypork.gamecore.graphics.GraphicsModule; diff --git a/src/mightypork/gamecore/core/init/InitTaskIonizables.java b/src/mightypork/gamecore/core/init/InitTaskIonizables.java index b9abd49..c8092c1 100644 --- a/src/mightypork/gamecore/core/init/InitTaskIonizables.java +++ b/src/mightypork/gamecore/core/init/InitTaskIonizables.java @@ -3,7 +3,6 @@ package mightypork.gamecore.core.init; import java.io.IOException; -import mightypork.gamecore.core.InitTask; import mightypork.utils.ion.Ion; import mightypork.utils.ion.IonInput; import mightypork.utils.ion.IonOutput; diff --git a/src/mightypork/gamecore/core/init/InitTaskLog.java b/src/mightypork/gamecore/core/init/InitTaskLog.java index 7783117..215683f 100644 --- a/src/mightypork/gamecore/core/init/InitTaskLog.java +++ b/src/mightypork/gamecore/core/init/InitTaskLog.java @@ -4,7 +4,6 @@ package mightypork.gamecore.core.init; import java.io.File; import java.util.logging.Level; -import mightypork.gamecore.core.InitTask; import mightypork.utils.files.WorkDir; import mightypork.utils.logging.Log; import mightypork.utils.logging.writers.LogWriter; diff --git a/src/mightypork/gamecore/core/init/InitTaskLogHeader.java b/src/mightypork/gamecore/core/init/InitTaskLogHeader.java index 2c62257..d83e648 100644 --- a/src/mightypork/gamecore/core/init/InitTaskLogHeader.java +++ b/src/mightypork/gamecore/core/init/InitTaskLogHeader.java @@ -3,8 +3,6 @@ package mightypork.gamecore.core.init; import java.io.IOException; -import mightypork.gamecore.core.InitTask; -import mightypork.gamecore.core.OptionalInitTask; import mightypork.utils.files.WorkDir; import mightypork.utils.logging.Log; diff --git a/src/mightypork/gamecore/core/init/InitTaskResourceLoader.java b/src/mightypork/gamecore/core/init/InitTaskResourceLoader.java new file mode 100644 index 0000000..9605ebe --- /dev/null +++ b/src/mightypork/gamecore/core/init/InitTaskResourceLoader.java @@ -0,0 +1,40 @@ +package mightypork.gamecore.core.init; + + +import mightypork.gamecore.resources.loading.ResourceLoader; + + +/** + * Task to add a resource loader.
+ * By default the async resource loader is used + * + * @author Ondřej Hruška (MightyPork) + */ +public abstract class InitTaskResourceLoader extends InitTask { + + /** The loader. */ + protected ResourceLoader loader; + + + @Override + public void run() + { + loader = getLoaderImpl(); + if (loader != null) loader.init(); + } + + + /** + * Create a loader impl + * + * @return loader + */ + protected abstract ResourceLoader getLoaderImpl(); + + + @Override + public String getName() + { + return "resource_loader"; + } +} diff --git a/src/mightypork/gamecore/core/init/InitTaskResourceLoaderAsync.java b/src/mightypork/gamecore/core/init/InitTaskResourceLoaderAsync.java new file mode 100644 index 0000000..1ba8c66 --- /dev/null +++ b/src/mightypork/gamecore/core/init/InitTaskResourceLoaderAsync.java @@ -0,0 +1,30 @@ +package mightypork.gamecore.core.init; + + +import mightypork.gamecore.resources.loading.AsyncResourceLoader; +import mightypork.gamecore.resources.loading.ResourceLoader; + + +/** + * Task to add a resource loader.
+ * By default the async resource loader is used + * + * @author Ondřej Hruška (MightyPork) + */ +public class InitTaskResourceLoaderAsync extends InitTaskResourceLoader { + + /** + * Create a loader impl + * + * @return loader + */ + @Override + protected ResourceLoader getLoaderImpl() + { + final AsyncResourceLoader loader = new AsyncResourceLoader(); + + // could now configure the loader + + return loader; + } +} diff --git a/src/mightypork/gamecore/core/init/InitTaskResourceLoaderNone.java b/src/mightypork/gamecore/core/init/InitTaskResourceLoaderNone.java new file mode 100644 index 0000000..8801747 --- /dev/null +++ b/src/mightypork/gamecore/core/init/InitTaskResourceLoaderNone.java @@ -0,0 +1,21 @@ +package mightypork.gamecore.core.init; + + +import mightypork.gamecore.resources.loading.ResourceLoader; + + +/** + * Task to add a resource loader.
+ * By default the async resource loader is used + * + * @author Ondřej Hruška (MightyPork) + */ +public class InitTaskResourceLoaderNone extends InitTaskResourceLoader { + + + @Override + protected ResourceLoader getLoaderImpl() + { + return null; + } +} diff --git a/src/mightypork/gamecore/core/init/InitTaskResources.java b/src/mightypork/gamecore/core/init/InitTaskResources.java new file mode 100644 index 0000000..da57a49 --- /dev/null +++ b/src/mightypork/gamecore/core/init/InitTaskResources.java @@ -0,0 +1,34 @@ +package mightypork.gamecore.core.init; + + +import mightypork.gamecore.resources.Res; +import mightypork.gamecore.resources.ResourceInitializer; + + +/** + * Task to initialize resources + * + * @author Ondřej Hruška (MightyPork) + */ +public abstract class InitTaskResources extends InitTask implements ResourceInitializer { + + @Override + public void run() + { + Res.load(this); + } + + + @Override + public String getName() + { + return "resources"; + } + + + @Override + public String[] getDependencies() + { + return new String[] { "resource_loader" }; + } +} diff --git a/src/mightypork/gamecore/core/init/InitTaskWorkdir.java b/src/mightypork/gamecore/core/init/InitTaskWorkdir.java index 4a6c9ab..5315cb0 100644 --- a/src/mightypork/gamecore/core/init/InitTaskWorkdir.java +++ b/src/mightypork/gamecore/core/init/InitTaskWorkdir.java @@ -9,7 +9,6 @@ import java.util.Map.Entry; import javax.swing.JOptionPane; import mightypork.gamecore.core.App; -import mightypork.gamecore.core.InitTask; import mightypork.utils.annotations.Stub; import mightypork.utils.files.InstanceLock; import mightypork.utils.files.WorkDir; diff --git a/src/mightypork/gamecore/core/OptionalInitTask.java b/src/mightypork/gamecore/core/init/OptionalInitTask.java similarity index 92% rename from src/mightypork/gamecore/core/OptionalInitTask.java rename to src/mightypork/gamecore/core/init/OptionalInitTask.java index b6dbab2..5b8f3fd 100644 --- a/src/mightypork/gamecore/core/OptionalInitTask.java +++ b/src/mightypork/gamecore/core/init/OptionalInitTask.java @@ -1,4 +1,4 @@ -package mightypork.gamecore.core; +package mightypork.gamecore.core.init; import java.lang.annotation.Documented; @@ -20,5 +20,5 @@ import java.lang.annotation.Target; @Documented @Inherited public @interface OptionalInitTask { - + // } diff --git a/src/mightypork/gamecore/core/AppPlugin.java b/src/mightypork/gamecore/core/plugins/AppPlugin.java similarity index 85% rename from src/mightypork/gamecore/core/AppPlugin.java rename to src/mightypork/gamecore/core/plugins/AppPlugin.java index 043e1d3..0074f67 100644 --- a/src/mightypork/gamecore/core/AppPlugin.java +++ b/src/mightypork/gamecore/core/plugins/AppPlugin.java @@ -1,6 +1,7 @@ -package mightypork.gamecore.core; +package mightypork.gamecore.core.plugins; +import mightypork.gamecore.core.App; import mightypork.utils.annotations.Stub; import mightypork.utils.eventbus.clients.BusNode; @@ -13,22 +14,22 @@ import mightypork.utils.eventbus.clients.BusNode; * @author Ondřej Hruška (MightyPork) */ public class AppPlugin extends BusNode { - + /** App instance assigned using bind() */ protected App app; - - + + /** * Assign the initialized app instance to an "app" field. * * @param app app */ - void bind(App app) + public void bind(App app) { this.app = app; } - - + + /** * Initialize the plugin for the given App.
* The plugin is already attached to the event bus. diff --git a/src/mightypork/gamecore/core/plugins/screenshot/InitTaskPluginScreenshot.java b/src/mightypork/gamecore/core/plugins/screenshot/InitTaskPluginScreenshot.java index e4cfa2e..4197cb9 100644 --- a/src/mightypork/gamecore/core/plugins/screenshot/InitTaskPluginScreenshot.java +++ b/src/mightypork/gamecore/core/plugins/screenshot/InitTaskPluginScreenshot.java @@ -1,7 +1,7 @@ package mightypork.gamecore.core.plugins.screenshot; -import mightypork.gamecore.core.InitTask; +import mightypork.gamecore.core.init.InitTask; import mightypork.utils.files.WorkDir; diff --git a/src/mightypork/gamecore/core/plugins/screenshot/ScreenshotPlugin.java b/src/mightypork/gamecore/core/plugins/screenshot/ScreenshotPlugin.java index 1de6c4f..59aa359 100644 --- a/src/mightypork/gamecore/core/plugins/screenshot/ScreenshotPlugin.java +++ b/src/mightypork/gamecore/core/plugins/screenshot/ScreenshotPlugin.java @@ -2,8 +2,8 @@ package mightypork.gamecore.core.plugins.screenshot; import mightypork.gamecore.core.App; -import mightypork.gamecore.core.AppPlugin; import mightypork.gamecore.core.events.MainLoopRequest; +import mightypork.gamecore.core.plugins.AppPlugin; import mightypork.utils.Support; @@ -15,14 +15,14 @@ import mightypork.utils.Support; * @author Ondřej Hruška (MightyPork) */ public class ScreenshotPlugin extends AppPlugin { - + /** * Take screenshot. Called by the trigger event. */ void takeScreenshot() { App.bus().send(new MainLoopRequest(new Runnable() { - + @Override public void run() { diff --git a/src/mightypork/gamecore/graphics/fonts/DeferredFont.java b/src/mightypork/gamecore/graphics/fonts/DeferredFont.java index 4791138..c5aadfc 100644 --- a/src/mightypork/gamecore/graphics/fonts/DeferredFont.java +++ b/src/mightypork/gamecore/graphics/fonts/DeferredFont.java @@ -12,36 +12,6 @@ import mightypork.gamecore.resources.BaseDeferredResource; */ public abstract class DeferredFont extends BaseDeferredResource implements IFont { - /** - * Font style enum - */ - public static enum FontStyle - { - /** Plan style */ - PLAIN(0), - /** Bold style */ - BOLD(1), - /** Italic style */ - ITALIC(2), - /** Bond and italic together */ - BOLD_ITALIC(1 + 2); - - /** Number associated with the style */ - public int numval; - - - /** - * Font style - * - * @param style style index as in awt Font. Not using constants to be - * independent on awt. - */ - private FontStyle(int style) - { - this.numval = style; - } - } - /** * Requested font size. For bitmap fonts, this should match the actual font * size (in pixels). The font can be scaled after loaded, but it may be diff --git a/src/mightypork/gamecore/graphics/fonts/FontRegistry.java b/src/mightypork/gamecore/graphics/fonts/FontRegistry.java index d47f395..7b81f55 100644 --- a/src/mightypork/gamecore/graphics/fonts/FontRegistry.java +++ b/src/mightypork/gamecore/graphics/fonts/FontRegistry.java @@ -14,11 +14,11 @@ import mightypork.utils.eventbus.clients.BusNode; * @author Ondřej Hruška (MightyPork) */ public class FontRegistry extends BusNode { - + private final HashMap fonts = new HashMap<>(); private final HashMap aliases = new HashMap<>(); - - + + /** * Load a {@link DeferredFont} * @@ -28,11 +28,11 @@ public class FontRegistry extends BusNode { public void addFont(String key, DeferredFont font) { App.bus().send(new ResourceLoadRequest(font)); - + fonts.put(key, font); } - - + + /** * Add a {@link IFont} to the bank. * @@ -43,10 +43,13 @@ public class FontRegistry extends BusNode { { fonts.put(key, font); } - - + + /** - * Add a font alias. + * Add a font alias. Useful to specify fonts to use for various parts of the + * app, without having to change the aliases throughout the app whenever the + * font alias is changed.
+ * It is, however, NOT possible to make alias to alias. * * @param alias_key alias key * @param font_key font key @@ -55,8 +58,8 @@ public class FontRegistry extends BusNode { { aliases.put(alias_key, font_key); } - - + + /** * Get a loaded {@link IFont} * @@ -66,14 +69,14 @@ public class FontRegistry extends BusNode { public IFont getFont(String key) { IFont f = fonts.get(key); - + if (f == null) f = fonts.get(aliases.get(key)); - + if (f == null) { throw new RuntimeException("There's no font called " + key + "!"); } - + return f; } - + } diff --git a/src/mightypork/gamecore/graphics/fonts/FontStyle.java b/src/mightypork/gamecore/graphics/fonts/FontStyle.java new file mode 100644 index 0000000..ef01a7d --- /dev/null +++ b/src/mightypork/gamecore/graphics/fonts/FontStyle.java @@ -0,0 +1,31 @@ +package mightypork.gamecore.graphics.fonts; + +/** + * Font style enum + */ +public enum FontStyle +{ + /** Plan style */ + PLAIN(0), + /** Bold style */ + BOLD(1), + /** Italic style */ + ITALIC(2), + /** Bond and italic together */ + BOLD_ITALIC(1 + 2); + + /** Number associated with the style */ + public int numval; + + + /** + * Font style + * + * @param style style index as in awt Font. Not using constants to be + * independent on awt. + */ + private FontStyle(int style) + { + this.numval = style; + } +} \ No newline at end of file diff --git a/src/mightypork/gamecore/graphics/textures/TextureRegistry.java b/src/mightypork/gamecore/graphics/textures/TextureRegistry.java index 4c2b4a7..46f8d95 100644 --- a/src/mightypork/gamecore/graphics/textures/TextureRegistry.java +++ b/src/mightypork/gamecore/graphics/textures/TextureRegistry.java @@ -20,20 +20,25 @@ public class TextureRegistry { private final Map textures = new HashMap<>(); private final Map sheets = new HashMap<>(); - - + + /** - * Load a texture from resource, without a key. This texture will not be - * added to the bank. + * Load a texture from resource. * * @param resourcePath resource path of the texture * @param filter filtering mode * @param wrap wrapping mode * @return texture reference */ - public ITexture addTexture(String resourcePath, FilterMode filter, WrapMode wrap) + public ITexture loadTexture(String resourcePath, FilterMode filter, WrapMode wrap) { - return addTexture(resourcePath, resourcePath, filter, wrap); + final DeferredTexture texture = App.gfx().createTextureResource(resourcePath); + texture.setFilter(filter); + texture.setWrap(wrap); + + App.bus().send(new ResourceLoadRequest(texture)); + + return texture; } @@ -51,11 +56,7 @@ public class TextureRegistry { { if (key != null) if (textures.containsKey(key)) throw new KeyAlreadyExistsException(); - final DeferredTexture texture = App.gfx().createTextureResource(resourcePath); - texture.setFilter(filter); - texture.setWrap(wrap); - - App.bus().send(new ResourceLoadRequest(texture)); + final ITexture texture = loadTexture(resourcePath, filter, wrap); if (key != null) { textures.put(key, texture); diff --git a/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java b/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java index 02126f3..e981ae6 100644 --- a/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java +++ b/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java @@ -76,7 +76,7 @@ public class CrossfadeOverlay extends Overlay { if (screen == null) { // going for halt - App.audio().fadeOutAllLoops(); + App.sound().fadeOutAllLoops(); } if (fromDark) { diff --git a/src/mightypork/gamecore/resources/Res.java b/src/mightypork/gamecore/resources/Res.java index 6d168d3..a131f92 100644 --- a/src/mightypork/gamecore/resources/Res.java +++ b/src/mightypork/gamecore/resources/Res.java @@ -18,83 +18,127 @@ import mightypork.gamecore.graphics.textures.TxSheet; * @author Ondřej Hruška (MightyPork) */ public final class Res { - - private static TextureRegistry textures; - private static SoundRegistry sounds; - private static FontRegistry fonts; - - private static boolean initialized = false; - - + + private static TextureRegistry textures = new TextureRegistry(); + private static SoundRegistry sounds = new SoundRegistry(); + private static FontRegistry fonts = new FontRegistry(); + + /** - * Load on behalf of given base app + * Get a texture by key * - * @param app app access + * @param key the key + * @return texture */ - public static void init() - { - if (initialized) return; - initialized = true; - - textures = new TextureRegistry(); - sounds = new SoundRegistry(); - fonts = new FontRegistry(); - } - - - public static ITexture getTexture(String key) + public static ITexture texture(String key) { return textures.getTexture(key); } - - + + /** * Get a texture sheet by key * - * @param key + * @param key the key * @return sheet */ - public static TxSheet getTxSheet(String key) + public static TxSheet txSheet(String key) { return textures.getSheet(key); } - - + + /** * Get a texture quad by key * - * @param key + * @param key the key * @return quad */ - public static TxQuad getTxQuad(String key) + public static TxQuad txQuad(String key) { return textures.getQuad(key); } - - - public static LoopPlayer getSoundLoop(String key) + + + /** + * Get a sound loop player by key + * + * @param key the key + * @return loop player + */ + public static LoopPlayer loop(String key) { return sounds.getLoop(key); } - - - public static EffectPlayer getSoundEffect(String key) + + + /** + * Get a sound effect player by key + * + * @param key the key + * @return effect player + */ + public static EffectPlayer sound(String key) { return sounds.getEffect(key); } - public static IFont getFont(String key) + /** + * Get a font by key + * + * @param key the key + * @return font + */ + public static IFont font(String key) { return fonts.getFont(key); } + + + /** + * Get internal texture registry + * + * @return registry + */ + public static TextureRegistry getTextureRegistry() + { + return textures; + } - public static void load(ResourceSetup binder) + /** + * Get internal font registry + * + * @return registry + */ + public static FontRegistry getFontRegistry() { - binder.addFonts(fonts); - binder.addTextures(textures); - binder.addSounds(sounds); + return fonts; } + + + /** + * Get internal sound registry + * + * @return registry + */ + public static SoundRegistry getSoundRegistry() + { + return sounds; + } + + /** + * Load resources by a resource initializer. + * + * @param initializer the resource initializer + */ + public static void load(ResourceInitializer initializer) + { + initializer.addFonts(fonts); + initializer.addTextures(textures); + initializer.addSounds(sounds); + } + } diff --git a/src/mightypork/gamecore/resources/ResourceSetup.java b/src/mightypork/gamecore/resources/ResourceInitializer.java similarity index 94% rename from src/mightypork/gamecore/resources/ResourceSetup.java rename to src/mightypork/gamecore/resources/ResourceInitializer.java index 4aa8ab8..b1cee0a 100644 --- a/src/mightypork/gamecore/resources/ResourceSetup.java +++ b/src/mightypork/gamecore/resources/ResourceInitializer.java @@ -11,7 +11,7 @@ import mightypork.gamecore.graphics.textures.TextureRegistry; * * @author Ondřej Hruška (MightyPork) */ -public interface ResourceSetup { +public interface ResourceInitializer { /** * Add fonts to load. diff --git a/src/mightypork/gamecore/resources/loading/AsyncResourceLoader.java b/src/mightypork/gamecore/resources/loading/AsyncResourceLoader.java index 1bee35f..2976c51 100644 --- a/src/mightypork/gamecore/resources/loading/AsyncResourceLoader.java +++ b/src/mightypork/gamecore/resources/loading/AsyncResourceLoader.java @@ -20,50 +20,60 @@ import mightypork.utils.logging.Log; * @author Ondřej Hruška (MightyPork) */ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destroyable { - + private final ExecutorService exs = Executors.newFixedThreadPool(2); - + private final LinkedBlockingQueue toLoad = new LinkedBlockingQueue<>(); private volatile boolean stopped; private volatile boolean mainLoopQueuing = true; - - + + + /** + * Create a resource loader. + */ + public AsyncResourceLoader() + { + super("Deferred loader"); + } + + @Override public synchronized void init() { - App.bus().subscribe(this); // FIXME bad + App.bus().subscribe(this); setDaemon(true); super.start(); } - - + + + /** + * True to queue resources that must load in rendering context to main loop. + * May cause lag at the beginning, but results in smoother performance later + * (better than load-on-demand) + * + * @param yes true to allow queuing + */ public void enableMainLoopQueuing(boolean yes) { mainLoopQueuing = yes; } - - - public AsyncResourceLoader() - { - super("Deferred loader"); - } - - + + @Override public void loadResource(final DeferredResource resource) { if (resource.isLoaded()) return; - + // textures & fonts needs to be loaded in main thread if (Reflect.hasAnnotation(resource, MustLoadInRenderingContext.class)) { - + if (!mainLoopQueuing) { // just let it be } else { Log.f3("(loader) Delegating to main thread: " + Support.str(resource)); - + App.bus().send(new MainLoopRequest(new Runnable() { - + @Override public void run() { @@ -71,31 +81,31 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr } }, false)); } - + return; } - + toLoad.add(resource); } - - + + @Override public void run() { Log.f3("Asynchronous resource loader started."); - + while (!stopped) { - + try { final DeferredResource def = toLoad.take(); if (def == null) continue; - + if (!def.isLoaded()) { - + Log.f3("(loader) Scheduling... " + Support.str(def)); - + exs.submit(new Runnable() { - + @Override public void run() { @@ -105,15 +115,15 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr } }); } - + } catch (final InterruptedException ignored) { // } - + } } - - + + // apparently, destroy method exists on thread :/ @SuppressWarnings("deprecation") @Override @@ -123,5 +133,5 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr stopped = true; exs.shutdownNow(); } - + } diff --git a/src/mightypork/gamecore/resources/loading/ResourceLoader.java b/src/mightypork/gamecore/resources/loading/ResourceLoader.java index 192c434..5586d71 100644 --- a/src/mightypork/gamecore/resources/loading/ResourceLoader.java +++ b/src/mightypork/gamecore/resources/loading/ResourceLoader.java @@ -10,17 +10,17 @@ import mightypork.gamecore.resources.DeferredResource; * @author Ondřej Hruška (MightyPork) */ public interface ResourceLoader { - + /** * Load a resource * * @param resource */ void loadResource(DeferredResource resource); - - + + /** - * Initialize the loader (Join the bus, start a stread etc) + * Initialize the loader (Join the bus, start a thread etc) * * @param app app the loader works for. The event bus must already be * initialized.