Added init tasks for resources.

master
Ondřej Hruška 10 years ago
parent 6d901ddfe5
commit af8535620b
  1. 6
      src/junk/AppInitOptions.java
  2. 4
      src/junk/BaseApp.java
  3. 4
      src/mightypork/gamecore/audio/DeferredAudio.java
  4. 5
      src/mightypork/gamecore/audio/IAudio.java
  5. 53
      src/mightypork/gamecore/audio/SoundRegistry.java
  6. 58
      src/mightypork/gamecore/audio/players/AudioPlayer.java
  7. 84
      src/mightypork/gamecore/audio/players/LoopPlayer.java
  8. 112
      src/mightypork/gamecore/core/App.java
  9. 2
      src/mightypork/gamecore/core/config/InitTaskConfig.java
  10. 71
      src/mightypork/gamecore/core/init/InitTask.java
  11. 1
      src/mightypork/gamecore/core/init/InitTaskCrashHandler.java
  12. 1
      src/mightypork/gamecore/core/init/InitTaskDisplay.java
  13. 1
      src/mightypork/gamecore/core/init/InitTaskIonizables.java
  14. 1
      src/mightypork/gamecore/core/init/InitTaskLog.java
  15. 2
      src/mightypork/gamecore/core/init/InitTaskLogHeader.java
  16. 40
      src/mightypork/gamecore/core/init/InitTaskResourceLoader.java
  17. 30
      src/mightypork/gamecore/core/init/InitTaskResourceLoaderAsync.java
  18. 21
      src/mightypork/gamecore/core/init/InitTaskResourceLoaderNone.java
  19. 34
      src/mightypork/gamecore/core/init/InitTaskResources.java
  20. 1
      src/mightypork/gamecore/core/init/InitTaskWorkdir.java
  21. 4
      src/mightypork/gamecore/core/init/OptionalInitTask.java
  22. 15
      src/mightypork/gamecore/core/plugins/AppPlugin.java
  23. 2
      src/mightypork/gamecore/core/plugins/screenshot/InitTaskPluginScreenshot.java
  24. 6
      src/mightypork/gamecore/core/plugins/screenshot/ScreenshotPlugin.java
  25. 30
      src/mightypork/gamecore/graphics/fonts/DeferredFont.java
  26. 33
      src/mightypork/gamecore/graphics/fonts/FontRegistry.java
  27. 31
      src/mightypork/gamecore/graphics/fonts/FontStyle.java
  28. 23
      src/mightypork/gamecore/graphics/textures/TextureRegistry.java
  29. 2
      src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java
  30. 126
      src/mightypork/gamecore/resources/Res.java
  31. 2
      src/mightypork/gamecore/resources/ResourceInitializer.java
  32. 78
      src/mightypork/gamecore/resources/loading/AsyncResourceLoader.java
  33. 8
      src/mightypork/gamecore/resources/loading/ResourceLoader.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<ResourceSetup> resourceLists = new ArrayList<>();
final List<ResourceInitializer> resourceLists = new ArrayList<>();
final List<KeySetup> keyLists = new ArrayList<>();
final List<ConfigSetup> configLists = new ArrayList<>();
@ -56,7 +56,7 @@ public class AppInitOptions {
}
public void addResources(ResourceSetup res)
public void addResources(ResourceInitializer res)
{
resourceLists.add(res);
}

@ -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);
}

@ -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());
}

@ -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();

@ -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<String, LoopPlayer> 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);
}

@ -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;
}
}

@ -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);
}
}

@ -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<InitTask> 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.<br>
* 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<InitTask> 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.<br>
* 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.
*

@ -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;

@ -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 <code>bind()</code> */
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 <code>run()</code> method.<br>
* 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.<br>
* 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.<br>
* 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).<br>
* 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.<br>
* Depending on itself or creating a circular dependency will cause error.<br>
@ -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<InitTask> inOrder(List<InitTask> tasks)
{
final List<InitTask> remaining = new ArrayList<>(tasks);
final List<InitTask> ordered = new ArrayList<>();
final Set<String> loaded = new HashSet<>();
// resolve task order
int addedThisIteration = 0;
do {
for (final Iterator<InitTask> 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;
}
}

@ -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;

@ -1,7 +1,6 @@
package mightypork.gamecore.core.init;
import mightypork.gamecore.core.InitTask;
import mightypork.gamecore.graphics.GraphicsModule;

@ -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;

@ -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;

@ -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;

@ -0,0 +1,40 @@
package mightypork.gamecore.core.init;
import mightypork.gamecore.resources.loading.ResourceLoader;
/**
* Task to add a resource loader.<br>
* 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";
}
}

@ -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.<br>
* 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;
}
}

@ -0,0 +1,21 @@
package mightypork.gamecore.core.init;
import mightypork.gamecore.resources.loading.ResourceLoader;
/**
* Task to add a resource loader.<br>
* 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;
}
}

@ -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" };
}
}

@ -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;

@ -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 {
//
}

@ -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 <code>bind()</code> */
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.<br>
* The plugin is already attached to the event bus.

@ -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;

@ -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()
{

@ -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

@ -14,11 +14,11 @@ import mightypork.utils.eventbus.clients.BusNode;
* @author Ondřej Hruška (MightyPork)
*/
public class FontRegistry extends BusNode {
private final HashMap<String, IFont> fonts = new HashMap<>();
private final HashMap<String, String> 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.<br>
* 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;
}
}

@ -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;
}
}

@ -20,20 +20,25 @@ public class TextureRegistry {
private final Map<String, ITexture> textures = new HashMap<>();
private final Map<String, TxSheet> 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);

@ -76,7 +76,7 @@ public class CrossfadeOverlay extends Overlay {
if (screen == null) {
// going for halt
App.audio().fadeOutAllLoops();
App.sound().fadeOutAllLoops();
}
if (fromDark) {

@ -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);
}
}

@ -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.

@ -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<DeferredResource> 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();
}
}

@ -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.

Loading…
Cancel
Save