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;