diff --git a/src/itdelatrisu/opsu/Container.java b/src/itdelatrisu/opsu/Container.java new file mode 100644 index 00000000..4080a313 --- /dev/null +++ b/src/itdelatrisu/opsu/Container.java @@ -0,0 +1,88 @@ +/* + * opsu! - an open-source osu! client + * Copyright (C) 2014, 2015 Jeffrey Han + * + * opsu! is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu! is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!. If not, see . + */ + +package itdelatrisu.opsu; + +import itdelatrisu.opsu.audio.MusicController; + +import org.newdawn.slick.AppGameContainer; +import org.newdawn.slick.Game; +import org.newdawn.slick.SlickException; + +/** + * AppGameContainer extension that sends critical errors to ErrorHandler. + */ +public class Container extends AppGameContainer { + /** + * SlickException causing game failure. + */ + protected SlickException e = null; + + /** + * Create a new container wrapping a game + * + * @param game The game to be wrapped + * @throws SlickException Indicates a failure to initialise the display + */ + public Container(Game game) throws SlickException { + super(game); + } + + /** + * Create a new container wrapping a game + * + * @param game The game to be wrapped + * @param width The width of the display required + * @param height The height of the display required + * @param fullscreen True if we want fullscreen mode + * @throws SlickException Indicates a failure to initialise the display + */ + public Container(Game game, int width, int height, boolean fullscreen) throws SlickException { + super(game); + } + + @Override + public void start() throws SlickException { + try { + setup(); + getDelta(); + while (running()) + gameLoop(); + } finally { + MusicController.reset(); // prevent loading tracks from re-initializing OpenAL + destroy(); + if (e != null) { + ErrorHandler.error(null, e, true); + e = null; + } + } + + if (forceExit) + System.exit(0); + } + + @Override + protected void updateAndRender(int delta) throws SlickException { + try { + super.updateAndRender(delta); + } catch (SlickException e) { + this.e = e; + throw e; + } + } +} diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 6f20fd8d..8b796340 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -34,7 +34,6 @@ import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; -import org.newdawn.slick.AppGameContainer; import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; import org.newdawn.slick.SlickException; @@ -140,7 +139,7 @@ public class Opsu extends StateBasedGame { // start the game Opsu opsu = new Opsu("opsu!"); try { - AppGameContainer app = new AppGameContainer(opsu); + Container app = new Container(opsu); // basic game settings Options.setDisplayMode(app); @@ -173,7 +172,7 @@ public class Opsu extends StateBasedGame { } Options.saveOptions(); - ((AppGameContainer) this.getContainer()).destroy(); + ((Container) this.getContainer()).destroy(); closeSocket(); return true; } diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java index 13ab7367..2fdca837 100644 --- a/src/itdelatrisu/opsu/audio/MusicController.java +++ b/src/itdelatrisu/opsu/audio/MusicController.java @@ -82,24 +82,11 @@ public class MusicController { /** * Plays an audio file at the preview position. */ - @SuppressWarnings("deprecation") public static void play(final OsuFile osu, final boolean loop) { boolean play = (lastOsu == null || !osu.audioFilename.equals(lastOsu.audioFilename)); lastOsu = osu; if (play) { - themePlaying = false; - - // TODO: properly interrupt instead of using deprecated Thread.stop(); - // interrupt the conversion/track loading - if (isTrackLoading()) -// trackLoader.interrupt(); - trackLoader.stop(); - - if (wavFile != null) - wavFile.delete(); - - // releases all sources from previous tracks - destroyOpenAL(); + reset(); System.gc(); switch (OsuParser.getExtension(osu.audioFilename.getName())) { @@ -152,8 +139,6 @@ public class MusicController { player.loop(); else player.play(); - pauseTime = 0f; - trackDimmed = false; } } @@ -322,6 +307,38 @@ public class MusicController { trackDimmed = !trackDimmed; } + /** + * Completely resets MusicController state. + *

+ * Stops the current track, cancels track conversions, erases + * temporary files, releases OpenAL sources, and resets state. + */ + @SuppressWarnings("deprecation") + public static void reset() { + stop(); + + // TODO: properly interrupt instead of using deprecated Thread.stop(); + // interrupt the conversion/track loading + if (isTrackLoading()) +// trackLoader.interrupt(); + trackLoader.stop(); + trackLoader = null; + + // delete temporary WAV file + if (wavFile != null) { + wavFile.delete(); + wavFile = null; + } + + // reset state + themePlaying = false; + pauseTime = 0f; + trackDimmed = false; + + // releases all sources from previous tracks + destroyOpenAL(); + } + /** * Stops and releases all sources, clears each of the specified Audio * buffers, destroys the OpenAL context, and resets SoundStore for future use. diff --git a/src/itdelatrisu/opsu/states/Options.java b/src/itdelatrisu/opsu/states/Options.java index de2f0377..7fc96109 100644 --- a/src/itdelatrisu/opsu/states/Options.java +++ b/src/itdelatrisu/opsu/states/Options.java @@ -18,6 +18,7 @@ package itdelatrisu.opsu.states; +import itdelatrisu.opsu.Container; import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameMod; @@ -43,7 +44,6 @@ import java.util.Locale; import java.util.concurrent.TimeUnit; import org.lwjgl.input.Keyboard; -import org.newdawn.slick.AppGameContainer; import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; @@ -1083,10 +1083,10 @@ public class Options extends BasicGameState { * @param app the game container * @throws SlickException failure to set display mode */ - public static void setDisplayMode(AppGameContainer app) throws SlickException { + public static void setDisplayMode(Container app) throws SlickException { int screenWidth = app.getScreenWidth(); int screenHeight = app.getScreenHeight(); - + // check for larger-than-screen dimensions if (screenWidth < resolution.getWidth() || screenHeight < resolution.getHeight()) resolution = Resolution.RES_800_600;