Added a listener for the end of music tracks.

Fixes a bug during gameplay where if the music track ends before the last hit object is processed (esp. spinners), the game would hang.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-01-29 21:24:21 -05:00
parent e93fe25834
commit 84e463e8fb
3 changed files with 29 additions and 9 deletions

View File

@ -33,6 +33,7 @@ import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL; import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10; import org.lwjgl.openal.AL10;
import org.newdawn.slick.Music; import org.newdawn.slick.Music;
import org.newdawn.slick.MusicListener;
import org.newdawn.slick.SlickException; import org.newdawn.slick.SlickException;
import org.newdawn.slick.openal.Audio; import org.newdawn.slick.openal.Audio;
import org.newdawn.slick.openal.SoundStore; import org.newdawn.slick.openal.SoundStore;
@ -53,6 +54,9 @@ public class MusicController {
/** Thread for loading tracks. */ /** Thread for loading tracks. */
private static Thread trackLoader; private static Thread trackLoader;
/** Whether or not the current track has ended. */
private static boolean trackEnded;
/** Whether the theme song is currently playing. */ /** Whether the theme song is currently playing. */
private static boolean themePlaying = false; private static boolean themePlaying = false;
@ -107,6 +111,13 @@ public class MusicController {
private static void loadTrack(File file, int previewTime, boolean loop) { private static void loadTrack(File file, int previewTime, boolean loop) {
try { // create a new player try { // create a new player
player = new Music(file.getPath()); player = new Music(file.getPath());
player.addListener(new MusicListener() {
@Override
public void musicEnded(Music music) { trackEnded = true; }
@Override
public void musicSwapped(Music music, Music newMusic) {}
});
playAt((previewTime > 0) ? previewTime : 0, loop); playAt((previewTime > 0) ? previewTime : 0, loop);
} catch (Exception e) { } catch (Exception e) {
ErrorHandler.error(String.format("Could not play track '%s'.", file.getName()), e, false); ErrorHandler.error(String.format("Could not play track '%s'.", file.getName()), e, false);
@ -120,6 +131,7 @@ public class MusicController {
if (trackExists()) { if (trackExists()) {
setVolume(Options.getMusicVolume() * Options.getMasterVolume()); setVolume(Options.getMusicVolume() * Options.getMasterVolume());
player.setPosition(position / 1000f); player.setPosition(position / 1000f);
trackEnded = false;
pauseTime = 0f; pauseTime = 0f;
if (loop) if (loop)
player.loop(); player.loop();
@ -263,6 +275,11 @@ public class MusicController {
SoundStore.get().setMusicVolume(volume); SoundStore.get().setMusicVolume(volume);
} }
/**
* Returns whether or not the current track has ended.
*/
public static boolean trackEnded() { return trackEnded; }
/** /**
* Plays the theme song. * Plays the theme song.
*/ */
@ -320,6 +337,7 @@ public class MusicController {
// reset state // reset state
lastOsu = null; lastOsu = null;
trackEnded = false;
themePlaying = false; themePlaying = false;
pauseTime = 0f; pauseTime = 0f;
trackDimmed = false; trackDimmed = false;

View File

@ -152,11 +152,9 @@ public class Spinner implements HitObject {
@Override @Override
public boolean update(boolean overlap, int delta, int mouseX, int mouseY) { public boolean update(boolean overlap, int delta, int mouseX, int mouseY) {
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
if (overlap)
return true;
// end of spinner // end of spinner
if (trackPosition > hitObject.getEndTime()) { if (overlap || trackPosition > hitObject.getEndTime()) {
hitResult(); hitResult();
return true; return true;
} }

View File

@ -332,7 +332,7 @@ public class Game extends BasicGameState {
// draw hit objects in reverse order, or else overlapping objects are unreadable // draw hit objects in reverse order, or else overlapping objects are unreadable
Stack<Integer> stack = new Stack<Integer>(); Stack<Integer> stack = new Stack<Integer>();
for (int i = objectIndex; i < osu.objects.length && osu.objects[i].getTime() < trackPosition + approachTime; i++) for (int i = objectIndex; i < hitObjects.length && osu.objects[i].getTime() < trackPosition + approachTime; i++)
stack.add(i); stack.add(i);
while (!stack.isEmpty()) while (!stack.isEmpty())
@ -417,7 +417,11 @@ public class Game extends BasicGameState {
data.updateDisplays(delta); data.updateDisplays(delta);
// map complete! // map complete!
if (objectIndex >= osu.objects.length) { if (objectIndex >= hitObjects.length || (MusicController.trackEnded() && objectIndex > 0)) {
// track ended before last object was processed: force a hit result
if (MusicController.trackEnded() && objectIndex < hitObjects.length)
hitObjects[objectIndex].update(true, delta, mouseX, mouseY);
if (checkpointLoaded) // if checkpoint used, skip ranking screen if (checkpointLoaded) // if checkpoint used, skip ranking screen
game.closeRequested(); game.closeRequested();
else { // go to ranking screen else { // go to ranking screen
@ -501,9 +505,9 @@ public class Game extends BasicGameState {
} }
// update objects (loop in unlikely event of any skipped indexes) // update objects (loop in unlikely event of any skipped indexes)
while (objectIndex < osu.objects.length && trackPosition > osu.objects[objectIndex].getTime()) { while (objectIndex < hitObjects.length && trackPosition > osu.objects[objectIndex].getTime()) {
// check if we've already passed the next object's start time // check if we've already passed the next object's start time
boolean overlap = (objectIndex + 1 < osu.objects.length && boolean overlap = (objectIndex + 1 < hitObjects.length &&
trackPosition > osu.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_300]); trackPosition > osu.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_300]);
// update hit object and check completion status // update hit object and check completion status
@ -594,7 +598,7 @@ public class Game extends BasicGameState {
// skip to checkpoint // skip to checkpoint
MusicController.setPosition(checkpoint); MusicController.setPosition(checkpoint);
while (objectIndex < osu.objects.length && while (objectIndex < hitObjects.length &&
osu.objects[objectIndex++].getTime() <= checkpoint) osu.objects[objectIndex++].getTime() <= checkpoint)
; ;
objectIndex--; objectIndex--;
@ -635,7 +639,7 @@ public class Game extends BasicGameState {
return; return;
} }
if (objectIndex >= osu.objects.length) // nothing left to do here if (objectIndex >= hitObjects.length) // nothing left to do here
return; return;
OsuHitObject hitObject = osu.objects[objectIndex]; OsuHitObject hitObject = osu.objects[objectIndex];