diff --git a/.gitignore b/.gitignore index ab252d5..88e6855 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ /bin/ /target/ +/~local/ /.rogue-save/ -/build/.rogue-save/ -/build/out/.rogue-save/ +/build/ /build/out/*.jar /build/in/*.jar *.log diff --git a/src/mightypork/gamecore/core/events/MainLoopRequest.java b/src/mightypork/gamecore/core/events/MainLoopRequest.java index 64c3338..277bbe4 100644 --- a/src/mightypork/gamecore/core/events/MainLoopRequest.java +++ b/src/mightypork/gamecore/core/events/MainLoopRequest.java @@ -15,20 +15,23 @@ import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent; public class MainLoopRequest extends BusEvent { private final Runnable task; + private final boolean priority; /** * @param task task to run on main thread in rendering context + * @param priority if true, skip other tasks in queue */ - public MainLoopRequest(Runnable task) + public MainLoopRequest(Runnable task, boolean priority) { this.task = task; + this.priority = priority; } @Override public void handleBy(MainLoop handler) { - handler.queueTask(task); + handler.queueTask(task, priority); } } diff --git a/src/mightypork/gamecore/core/events/ShudownRequest.java b/src/mightypork/gamecore/core/events/ShudownRequest.java index e7e19ff..73fbb8c 100644 --- a/src/mightypork/gamecore/core/events/ShudownRequest.java +++ b/src/mightypork/gamecore/core/events/ShudownRequest.java @@ -5,6 +5,7 @@ import mightypork.gamecore.core.modules.MainLoop; import mightypork.gamecore.eventbus.BusEvent; import mightypork.gamecore.eventbus.event_flags.NonConsumableEvent; import mightypork.gamecore.eventbus.event_flags.SingleReceiverEvent; +import mightypork.gamecore.resources.audio.SoundSystem; /** @@ -27,6 +28,6 @@ public class ShudownRequest extends BusEvent { { handler.shutdown(); } - }); + }, true); } } diff --git a/src/mightypork/gamecore/core/modules/MainLoop.java b/src/mightypork/gamecore/core/modules/MainLoop.java index fee41d4..03e29dd 100644 --- a/src/mightypork/gamecore/core/modules/MainLoop.java +++ b/src/mightypork/gamecore/core/modules/MainLoop.java @@ -1,14 +1,18 @@ package mightypork.gamecore.core.modules; +import java.util.Deque; import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedQueue; import mightypork.gamecore.eventbus.events.UpdateEvent; import mightypork.gamecore.gui.screens.ScreenRegistry; +import mightypork.gamecore.logging.Log; import mightypork.gamecore.render.Renderable; import mightypork.gamecore.render.TaskTakeScreenshot; import mightypork.gamecore.render.events.ScreenshotRequestListener; +import mightypork.gamecore.resources.Profiler; import mightypork.gamecore.util.Utils; import mightypork.gamecore.util.annot.DefaultImpl; import mightypork.gamecore.util.math.timing.TimerDelta; @@ -21,7 +25,10 @@ import mightypork.gamecore.util.math.timing.TimerDelta; */ public class MainLoop extends AppModule implements ScreenshotRequestListener { - private final Queue taskQueue = new ConcurrentLinkedQueue<>(); + private static final double MAX_TIME_TASKS = 1 / 30D; // (avoid queue from hogging timing) + private static final double MAX_DELTA = 1 / 20D; // (skip huge gaps caused by loading resources etc) + + private final Deque tasks = new ConcurrentLinkedDeque<>(); private TimerDelta timer; private Renderable rootRenderable; private volatile boolean running = true; @@ -58,11 +65,23 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener { while (running) { getDisplay().beginFrame(); - getEventBus().sendDirect(new UpdateEvent(timer.getDelta())); + double delta = timer.getDelta(); + if (delta > MAX_DELTA) { + Log.f3("(timing) Cropping delta: was " + delta + " , limit " + MAX_DELTA); + delta = MAX_DELTA; + } + + getEventBus().sendDirect(new UpdateEvent(delta)); Runnable r; - while ((r = taskQueue.poll()) != null) { + long t = Profiler.begin(); + while ((r = tasks.poll()) != null) { + Log.f3(" * Main loop task."); r.run(); + if (Profiler.end(t) > MAX_TIME_TASKS) { + Log.f3("! Postponing main loop tasks to next cycle."); + break; + } } beforeRender(); @@ -109,10 +128,15 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener { * Add a task to queue to be executed in the main loop (OpenGL thread) * * @param request task + * @param priority if true, skip other tasks */ - public synchronized void queueTask(Runnable request) + public synchronized void queueTask(Runnable request, boolean priority) { - taskQueue.add(request); + if (priority) { + tasks.addFirst(request); + } else { + tasks.addLast(request); + } } @@ -127,7 +151,7 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener { { Utils.runAsThread(new TaskTakeScreenshot()); } - }); + }, false); } } diff --git a/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java b/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java index 0f881e5..b13b18d 100644 --- a/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java +++ b/src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java @@ -67,6 +67,11 @@ public class CrossfadeOverlay extends Overlay { { requestedScreenName = screen; + if(screen == null) { + // going for halt + getSoundSystem().fadeOutAllLoops(); + } + if (fromDark) { alpha.setTo(1); revealTask.run(); diff --git a/src/mightypork/gamecore/gui/screens/impl/FadingLayer.java b/src/mightypork/gamecore/gui/screens/impl/FadingLayer.java index a169436..699bd4d 100644 --- a/src/mightypork/gamecore/gui/screens/impl/FadingLayer.java +++ b/src/mightypork/gamecore/gui/screens/impl/FadingLayer.java @@ -3,6 +3,7 @@ package mightypork.gamecore.gui.screens.impl; import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.ScreenLayer; +import mightypork.gamecore.util.annot.DefaultImpl; import mightypork.gamecore.util.math.Easing; import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated; import mightypork.gamecore.util.math.timing.TimedTask; @@ -73,6 +74,7 @@ public abstract class FadingLayer extends ScreenLayer { /** * Called after the fade-out was completed */ + @DefaultImpl protected void onHideFinished() { } @@ -81,6 +83,7 @@ public abstract class FadingLayer extends ScreenLayer { /** * Called after the fade-in was completed */ + @DefaultImpl protected void onShowFinished() { } @@ -98,6 +101,7 @@ public abstract class FadingLayer extends ScreenLayer { super.show(); numa.fadeIn(); hideTimer.stop(); + showTimer.start(numa.getDefaultDuration()); fadingOut = false; fadingIn = true; diff --git a/src/mightypork/gamecore/resources/AsyncResourceLoader.java b/src/mightypork/gamecore/resources/AsyncResourceLoader.java index c76c00d..e84a491 100644 --- a/src/mightypork/gamecore/resources/AsyncResourceLoader.java +++ b/src/mightypork/gamecore/resources/AsyncResourceLoader.java @@ -18,7 +18,7 @@ import mightypork.gamecore.logging.Log; */ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destroyable { - private final ExecutorService exs = Executors.newCachedThreadPool(); + private final ExecutorService exs = Executors.newFixedThreadPool(2); private final LinkedBlockingQueue toLoad = new LinkedBlockingQueue<>(); private volatile boolean stopped; @@ -57,9 +57,9 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr if (resource.getClass().isAnnotationPresent(TextureBasedResource.class)) { if (!mainLoopQueuing) { - Log.f3(" Cannot load async: " + Log.str(resource)); + // just let it be } else { - Log.f3(" Delegating to main thread:\n " + Log.str(resource)); + Log.f3("(loader) Delegating to main thread: " + Log.str(resource)); app.getEventBus().send(new MainLoopRequest(new Runnable() { @@ -68,7 +68,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr { resource.load(); } - })); + }, false)); } return; @@ -91,14 +91,16 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr if (!def.isLoaded()) { - Log.f3(" Loading: " + Log.str(def)); + Log.f3("(loader) Scheduling... " + Log.str(def)); exs.submit(new Runnable() { @Override public void run() { - def.load(); + if(!def.isLoaded()) { + def.load(); + } } }); } diff --git a/src/mightypork/gamecore/resources/BaseLazyResource.java b/src/mightypork/gamecore/resources/BaseLazyResource.java index c7f855d..0cef349 100644 --- a/src/mightypork/gamecore/resources/BaseLazyResource.java +++ b/src/mightypork/gamecore/resources/BaseLazyResource.java @@ -6,6 +6,8 @@ import java.io.IOException; import mightypork.gamecore.eventbus.events.Destroyable; import mightypork.gamecore.logging.Log; import mightypork.gamecore.logging.LogAlias; +import mightypork.gamecore.util.math.Calc; +import mightypork.gamecore.util.strings.StringUtils; /** @@ -45,12 +47,14 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable { throw new NullPointerException("Resource string cannot be null for non-null resource."); } - Log.f3(" Loading: " + this); + long time = Profiler.begin(); + Log.f3("(res) + Load: " + this); loadResource(resource); - Log.f3(" Loaded: " + this); + Log.f3("(res) - Done: " + this + " in " + Profiler.endStr(time)); + } catch (final Throwable t) { loadFailed = true; - Log.e(" Failed to load: " + this, t); + Log.e("(res) Failed to load: " + this, t); } } @@ -74,7 +78,7 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable { } else { if (loadFailed) return false; - Log.f3(" (!) Loading on access: " + this); + Log.f3("(res) !! Loading on access: " + this); load(); } @@ -99,7 +103,7 @@ public abstract class BaseLazyResource implements LazyResource, Destroyable { @Override public String toString() { - return Log.str(getClass()) + "(\"" + resource + "\")"; + return StringUtils.fromLastChar(resource, '/'); } diff --git a/src/mightypork/gamecore/resources/Profiler.java b/src/mightypork/gamecore/resources/Profiler.java new file mode 100644 index 0000000..83429e1 --- /dev/null +++ b/src/mightypork/gamecore/resources/Profiler.java @@ -0,0 +1,32 @@ +package mightypork.gamecore.resources; + + +import mightypork.gamecore.util.math.Calc; + + +public class Profiler { + + public static long begin() + { + return System.currentTimeMillis(); + } + + + public static double end(long begun) + { + return endLong(begun) / 1000D; + } + + + public static long endLong(long begun) + { + return System.currentTimeMillis() - begun; + } + + + public static String endStr(long begun) + { + return Calc.toString(end(begun)) + " s"; + } + +} diff --git a/src/mightypork/gamecore/resources/Res.java b/src/mightypork/gamecore/resources/Res.java index f9593b6..94f9534 100644 --- a/src/mightypork/gamecore/resources/Res.java +++ b/src/mightypork/gamecore/resources/Res.java @@ -94,8 +94,8 @@ public final class Res { public static void load(ResourceSetup binder) { binder.addFonts(fonts); - binder.addSounds(sounds); binder.addTextures(textures); + binder.addSounds(sounds); } } diff --git a/src/mightypork/gamecore/resources/audio/SoundSystem.java b/src/mightypork/gamecore/resources/audio/SoundSystem.java index f49715f..d1fef9c 100644 --- a/src/mightypork/gamecore/resources/audio/SoundSystem.java +++ b/src/mightypork/gamecore/resources/audio/SoundSystem.java @@ -2,7 +2,9 @@ package mightypork.gamecore.resources.audio; import java.nio.FloatBuffer; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import mightypork.gamecore.core.modules.AppAccess; @@ -71,8 +73,8 @@ public class SoundSystem extends RootBusNode implements Updateable { private final Volume effectsVolume = new JointVolume(masterVolume); private final Volume loopsVolume = new JointVolume(masterVolume); - private final Set loopPlayers = new HashSet<>(); - private final Set resources = new HashSet<>(); + private final List loopPlayers = new ArrayList<>(); + private final List resources = new ArrayList<>(); /** @@ -130,7 +132,7 @@ public class SoundSystem extends RootBusNode implements Updateable { */ public EffectPlayer createEffect(String resource, double pitch, double gain) { - return new EffectPlayer(getResource(resource), pitch, gain, effectsVolume); + return new EffectPlayer(createResource(resource), pitch, gain, effectsVolume); } @@ -146,7 +148,7 @@ public class SoundSystem extends RootBusNode implements Updateable { */ public LoopPlayer createLoop(String resource, double pitch, double gain, double fadeIn, double fadeOut) { - final LoopPlayer p = new LoopPlayer(getResource(resource), pitch, gain, loopsVolume); + final LoopPlayer p = new LoopPlayer(createResource(resource), pitch, gain, loopsVolume); p.setFadeTimes(fadeIn, fadeOut); loopPlayers.add(p); return p; @@ -160,12 +162,10 @@ public class SoundSystem extends RootBusNode implements Updateable { * @return the resource * @throws IllegalArgumentException if resource is already registered */ - private LazyAudio getResource(String res) + private LazyAudio createResource(String res) { - final LazyAudio a = new LazyAudio(res); + final LazyAudio a = new LazyAudio(res); getEventBus().send(new ResourceLoadRequest(a)); - - if (resources.contains(a)) throw new IllegalArgumentException("Sound resource " + res + " is already registered."); resources.add(a); return a; } diff --git a/src/mightypork/gamecore/resources/audio/players/LoopPlayer.java b/src/mightypork/gamecore/resources/audio/players/LoopPlayer.java index 182f722..9da7e11 100644 --- a/src/mightypork/gamecore/resources/audio/players/LoopPlayer.java +++ b/src/mightypork/gamecore/resources/audio/players/LoopPlayer.java @@ -98,6 +98,8 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable sourceID = getAudio().resumeLoop(); paused = false; + + adjustGain(getGain(fadeAnim.value())); } @@ -112,7 +114,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable final double gain = getGain(fadeAnim.value()); if (!paused && gain != lastUpdateGain) { - AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain); + adjustGain(gain); lastUpdateGain = gain; } @@ -120,6 +122,12 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable } + private void adjustGain(double gain) + { + AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain); + } + + /** * Resume if paused, and fade in (pick up from current volume). * @@ -129,6 +137,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable { if (!hasAudio()) return; + if (isPaused()) fadeAnim.setTo(0); resume(); fadeAnim.fadeIn(secs); } @@ -142,7 +151,7 @@ public class LoopPlayer extends BaseAudioPlayer implements Updateable, Pauseable public void fadeOut(double secs) { if (!hasAudio()) return; - + if (isPaused()) return; fadeAnim.fadeOut(secs); }