Enabled application restarts.

- Pressing Ctrl+Shift+F5 in the options menu restarts the game.  Beatmaps and sounds are not reloaded.
- Use GameContainer.setForceExit(false) to trigger a restart after exiting.

Other changes:
- Fixed general issues with track pausing/pause states.
- Store all background images loaded in OsuFiles in a static hash table, instead of in individual objects.  This allows easier access to the allocated memory.
- Only delete OSZ files if they were unzipped. (They were previously deleted in all cases.)
- Moved more images (mods, playfield, lighting) into GameImage.
- Moved OsuHitObject initialization inside Utils.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-01-20 19:01:18 -05:00
parent 3b13cc794b
commit f98edf8fc8
15 changed files with 229 additions and 118 deletions

View File

@ -24,6 +24,7 @@ import itdelatrisu.opsu.states.Options;
import org.newdawn.slick.AppGameContainer; import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.Game; import org.newdawn.slick.Game;
import org.newdawn.slick.SlickException; import org.newdawn.slick.SlickException;
import org.newdawn.slick.opengl.InternalTextureLoader;
/** /**
* AppGameContainer extension that sends critical errors to ErrorHandler. * AppGameContainer extension that sends critical errors to ErrorHandler.
@ -65,8 +66,11 @@ public class Container extends AppGameContainer {
while (running()) while (running())
gameLoop(); gameLoop();
} finally { } finally {
MusicController.reset(); // prevent loading tracks from re-initializing OpenAL // destroy the game container
close_sub();
destroy(); destroy();
// report any critical errors
if (e != null) { if (e != null) {
ErrorHandler.error(null, e, true); ErrorHandler.error(null, e, true);
e = null; e = null;
@ -77,20 +81,34 @@ public class Container extends AppGameContainer {
System.exit(0); System.exit(0);
} }
/**
* Actions to perform before destroying the game container.
*/
private void close_sub() {
// save user options
Options.saveOptions();
// close server socket
Opsu.closeSocket();
// prevent loading tracks from re-initializing OpenAL
MusicController.reset();
// destroy images
InternalTextureLoader.get().clear();
// reset image references
GameImage.clearReferences();
OsuFile.resetImageCache();
}
@Override @Override
protected void updateAndRender(int delta) throws SlickException { protected void updateAndRender(int delta) throws SlickException {
try { try {
super.updateAndRender(delta); super.updateAndRender(delta);
} catch (SlickException e) { } catch (SlickException e) {
this.e = e; this.e = e; // store exception to display later
throw e; throw e; // re-throw exception
} }
} }
@Override
public void exit() {
Options.saveOptions();
Opsu.closeSocket();
running = false;
}
} }

View File

@ -73,6 +73,13 @@ public enum GameImage {
}, },
HITCIRCLE_SELECT ("hitcircleselect", "png"), HITCIRCLE_SELECT ("hitcircleselect", "png"),
UNRANKED ("play-unranked", "png"), UNRANKED ("play-unranked", "png"),
PLAYFIELD ("playfield", "png|jpg", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
img.setAlpha(0.7f);
return img.getScaledCopy(w, h);
}
},
// Game Pause/Fail // Game Pause/Fail
PAUSE_CONTINUE ("pause-continue", "png"), PAUSE_CONTINUE ("pause-continue", "png"),
@ -206,6 +213,70 @@ public enum GameImage {
SCORE_DOT ("score-dot", "png"), SCORE_DOT ("score-dot", "png"),
SCORE_PERCENT ("score-percent", "png"), SCORE_PERCENT ("score-percent", "png"),
SCORE_X ("score-x", "png"), SCORE_X ("score-x", "png"),
LIGHTING ("lighting", "png"),
LIGHTING1 ("lighting1", "png"),
// Game Mods
MOD_EASY ("selection-mod-easy", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_NO_FAIL ("selection-mod-nofail", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_HARD_ROCK ("selection-mod-hardrock", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_SUDDEN_DEATH ("selection-mod-suddendeath", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_SPUN_OUT ("selection-mod-spunout", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_AUTO ("selection-mod-autoplay", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_HALF_TIME ("selection-mod-halftime", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_DOUBLE_TIME ("selection-mod-doubletime", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_HIDDEN ("selection-mod-hidden", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
MOD_FLASHLIGHT ("selection-mod-flashlight", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
return img.getScaledCopy((h * 0.12f) / img.getHeight());
}
},
// Non-Game Components // Non-Game Components
VOLUME ("volume-bg", "png", false, false) { VOLUME ("volume-bg", "png", false, false) {
@ -291,12 +362,10 @@ public enum GameImage {
}, },
MENU_BUTTON_LEFT ("button-left", "png", false, false), MENU_BUTTON_LEFT ("button-left", "png", false, false),
MENU_BUTTON_RIGHT ("button-right", "png", false, false), MENU_BUTTON_RIGHT ("button-right", "png", false, false),
MUSIC_PLAY ("music-play", "png", false, false), MUSIC_PLAY ("music-play", "png", false, false),
MUSIC_PAUSE ("music-pause", "png", false, false), MUSIC_PAUSE ("music-pause", "png", false, false),
MUSIC_NEXT ("music-next", "png", false, false), MUSIC_NEXT ("music-next", "png", false, false),
MUSIC_PREVIOUS ("music-previous", "png", false, false), MUSIC_PREVIOUS ("music-previous", "png", false, false),
RANKING_RETRY ("ranking-retry", "png", false, false) { RANKING_RETRY ("ranking-retry", "png", false, false) {
@Override @Override
protected Image process_sub(Image img, int w, int h) { protected Image process_sub(Image img, int w, int h) {
@ -309,7 +378,6 @@ public enum GameImage {
return img.getScaledCopy((h * 0.15f) / img.getHeight()); return img.getScaledCopy((h * 0.15f) / img.getHeight());
} }
}, },
REPOSITORY ("repo", "png", false, false) { REPOSITORY ("repo", "png", false, false) {
@Override @Override
protected Image process_sub(Image img, int w, int h) { protected Image process_sub(Image img, int w, int h) {
@ -375,6 +443,15 @@ public enum GameImage {
containerHeight = height; containerHeight = height;
} }
/**
* Clears all image references.
* This does NOT destroy images, so be careful of memory leaks!
*/
public static void clearReferences() {
for (GameImage img : GameImage.values())
img.defaultImage = img.skinImage = null;
}
/** /**
* Destroys all skin images, if any have been loaded. * Destroys all skin images, if any have been loaded.
*/ */

View File

@ -23,22 +23,21 @@ import java.util.Collections;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;
import org.newdawn.slick.Input; import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
/** /**
* Game mods. * Game mods.
*/ */
public enum GameMod { public enum GameMod {
EASY (0, "selection-mod-easy.png", Input.KEY_Q, 0.5f), EASY (0, GameImage.MOD_EASY, Input.KEY_Q, 0.5f),
NO_FAIL (1, "selection-mod-nofail.png", Input.KEY_W, 0.5f), NO_FAIL (1, GameImage.MOD_NO_FAIL, Input.KEY_W, 0.5f),
HARD_ROCK (2, "selection-mod-hardrock.png", Input.KEY_A, 1.06f), HARD_ROCK (2, GameImage.MOD_HARD_ROCK, Input.KEY_A, 1.06f),
SUDDEN_DEATH (3, "selection-mod-suddendeath.png", Input.KEY_S), SUDDEN_DEATH (3, GameImage.MOD_SUDDEN_DEATH, Input.KEY_S),
SPUN_OUT (4, "selection-mod-spunout.png", Input.KEY_V, 0.9f), SPUN_OUT (4, GameImage.MOD_SPUN_OUT, Input.KEY_V, 0.9f),
AUTO (5, "selection-mod-autoplay.png", Input.KEY_B); AUTO (5, GameImage.MOD_AUTO, Input.KEY_B);
// HALF_TIME (, "selection-mod-halftime.png", Input.KEY_E, 0.3f), // HALF_TIME (, GameImage.MOD_HALF_TIME, Input.KEY_E, 0.3f),
// DOUBLE_TIME (, "selection-mod-doubletime.png", Input.KEY_D, 1.12f), // DOUBLE_TIME (, GameImage.MOD_DOUBLE_TIME, Input.KEY_D, 1.12f),
// HIDDEN (, "selection-mod-hidden.png", Input.KEY_F, 1.06f), // HIDDEN (, GameImage.MOD_HIDDEN, Input.KEY_F, 1.06f),
// FLASHLIGHT (, "selection-mod-flashlight.png", Input.KEY_G, 1.12f); // FLASHLIGHT (, GameImage.MOD_FLASHLIGHT, Input.KEY_G, 1.12f);
/** /**
* The ID of the mod (used for positioning). * The ID of the mod (used for positioning).
@ -48,7 +47,7 @@ public enum GameMod {
/** /**
* The file name of the mod image. * The file name of the mod image.
*/ */
private String filename; private GameImage image;
/** /**
* The shortcut key associated with the mod. * The shortcut key associated with the mod.
@ -94,12 +93,12 @@ public enum GameMod {
/** /**
* Constructor. * Constructor.
* @param id the ID of the mod (for positioning). * @param id the ID of the mod (for positioning).
* @param filename the image file name * @param image the GameImage
* @param key the shortcut key * @param key the shortcut key
*/ */
GameMod(int id, String filename, int key) { GameMod(int id, GameImage image, int key) {
this.id = id; this.id = id;
this.filename = filename; this.image = image;
this.key = key; this.key = key;
this.multiplier = 1f; this.multiplier = 1f;
} }
@ -107,13 +106,13 @@ public enum GameMod {
/** /**
* Constructor. * Constructor.
* @param id the ID of the mod (for positioning). * @param id the ID of the mod (for positioning).
* @param filename the image file name * @param image the GameImage
* @param key the shortcut key * @param key the shortcut key
* @param multiplier the score multiplier * @param multiplier the score multiplier
*/ */
GameMod(int id, String filename, int key, float multiplier) { GameMod(int id, GameImage image, int key, float multiplier) {
this.id = id; this.id = id;
this.filename = filename; this.image = image;
this.key = key; this.key = key;
this.multiplier = multiplier; this.multiplier = multiplier;
} }
@ -124,24 +123,17 @@ public enum GameMod {
* @param height the container height * @param height the container height
*/ */
public void init(int width, int height) { public void init(int width, int height) {
try { Image img = image.getImage();
// create and scale image
Image img = new Image(filename);
float scale = (height * 0.12f) / img.getHeight();
img = img.getScaledCopy(scale);
// find coordinates // find coordinates
float offsetX = img.getWidth() * 1.5f; float offsetX = img.getWidth() * 1.5f;
float x = (width / 2f) - (offsetX * SIZE / 2.75f); float x = (width / 2f) - (offsetX * SIZE / 2.75f);
float y = (height * 0.8f) + (img.getHeight() / 2); float y = (height * 0.8f) + (img.getHeight() / 2);
// create button // create button
img.setAlpha(0.5f); img.setAlpha(0.5f);
this.button = new MenuButton(img, x + (offsetX * id), y); this.button = new MenuButton(img, x + (offsetX * id), y);
this.button.setHoverScale(1.15f); this.button.setHoverScale(1.15f);
} catch (SlickException e) {
ErrorHandler.error(String.format("Failed to initialize game mod '%s'.", this), e, false);
}
} }
/** /**
@ -202,7 +194,7 @@ public enum GameMod {
* Returns the image associated with the mod. * Returns the image associated with the mod.
* @return the associated image * @return the associated image
*/ */
public Image getImage() { return button.getImage(); } public Image getImage() { return image.getImage(); }
/** /**
* Returns the mod ID. * Returns the mod ID.

View File

@ -305,8 +305,8 @@ public class GameScore {
} }
} else { // load default image } else { // load default image
try { try {
lighting = new Image("lighting.png"); lighting = GameImage.LIGHTING.getImage();
lighting1 = new Image("lighting1.png"); lighting1 = GameImage.LIGHTING1.getImage();
} catch (Exception e) { } catch (Exception e) {
// optional // optional
} }

View File

@ -18,7 +18,6 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Game;
import itdelatrisu.opsu.states.GamePauseMenu; import itdelatrisu.opsu.states.GamePauseMenu;
import itdelatrisu.opsu.states.GameRanking; import itdelatrisu.opsu.states.GameRanking;
@ -138,16 +137,20 @@ public class Opsu extends StateBasedGame {
Options.TMP_DIR.deleteOnExit(); Options.TMP_DIR.deleteOnExit();
// start the game // start the game
Opsu opsu = new Opsu("opsu!");
try { try {
Container app = new Container(opsu); // loop until force exit
while (true) {
Opsu opsu = new Opsu("opsu!");
Container app = new Container(opsu);
// basic game settings // basic game settings
Options.setDisplayMode(app); Options.setDisplayMode(app);
String[] icons = { "icon16.png", "icon32.png" }; String[] icons = { "icon16.png", "icon32.png" };
app.setIcons(icons); app.setIcons(icons);
app.setForceExit(true);
app.start(); app.start();
}
} catch (SlickException e) { } catch (SlickException e) {
// JARs will not run properly inside directories containing '!' // JARs will not run properly inside directories containing '!'
// http://bugs.java.com/view_bug.do?bug_id=4523159 // http://bugs.java.com/view_bug.do?bug_id=4523159
@ -172,10 +175,6 @@ public class Opsu extends StateBasedGame {
return false; return false;
} }
MusicController.reset();
Options.saveOptions();
((Container) this.getContainer()).destroy();
closeSocket();
return true; return true;
} }

View File

@ -22,9 +22,11 @@ import itdelatrisu.opsu.states.Options;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
/** /**
@ -80,7 +82,7 @@ public class OsuFile implements Comparable<OsuFile> {
/* [Events] */ /* [Events] */
//Background and Video events (0) //Background and Video events (0)
public String bg; // background image path public String bg; // background image path
private Image bgImage; // background image (created when needed) // private Image bgImage; // background image (created when needed)
// public Video bgVideo; // background video (not implemented) // public Video bgVideo; // background video (not implemented)
//Break Periods (2) //Break Periods (2)
public ArrayList<Integer> breaks; // break periods (start time, end time, ...) public ArrayList<Integer> breaks; // break periods (start time, end time, ...)
@ -100,6 +102,35 @@ public class OsuFile implements Comparable<OsuFile> {
public int hitObjectSpinner = 0; // number of spinners public int hitObjectSpinner = 0; // number of spinners
public int endTime = -1; // last object end time (in ms) public int endTime = -1; // last object end time (in ms)
/**
* Map of all loaded background images.
*/
private static HashMap<OsuFile, Image> bgImageMap = new HashMap<OsuFile, Image>();
/**
* Destroys all cached background images and resets the cache.
*/
public static void clearImageCache() {
for (Image img : bgImageMap.values()) {
if (img != null && !img.isDestroyed()) {
try {
img.destroy();
} catch (SlickException e) {
Log.warn(String.format("Failed to destroy image '%s'.", img.getResourceReference()), e);
}
}
}
resetImageCache();
}
/**
* Resets the image cache.
* This does NOT destroy images, so be careful of memory leaks!
*/
public static void resetImageCache() {
bgImageMap = new HashMap<OsuFile, Image>();
}
/** /**
* Constructor. * Constructor.
* @param file the file associated with this OsuFile * @param file the file associated with this OsuFile
@ -143,8 +174,11 @@ public class OsuFile implements Comparable<OsuFile> {
if (bg == null) if (bg == null)
return false; return false;
try { try {
if (bgImage == null) Image bgImage = bgImageMap.get(this);
if (bgImage == null) {
bgImage = new Image(bg).getScaledCopy(width, height); bgImage = new Image(bg).getScaledCopy(width, height);
bgImageMap.put(this, bgImage);
}
bgImage.setAlpha(alpha); bgImage.setAlpha(alpha);
bgImage.draw(); bgImage.draw();
} catch (Exception e) { } catch (Exception e) {

View File

@ -28,10 +28,6 @@ import org.newdawn.slick.Image;
* Node in an OsuGroupList representing a group of OsuFile objects. * Node in an OsuGroupList representing a group of OsuFile objects.
*/ */
public class OsuGroupNode { public class OsuGroupNode {
/**
* Menu background image.
*/
private static Image bg;
/** /**
* List of associated OsuFile objects. * List of associated OsuFile objects.
@ -62,11 +58,6 @@ public class OsuGroupNode {
this.osuFiles = osuFiles; this.osuFiles = osuFiles;
} }
/**
* Sets a button background image.
*/
public static void setBackground(Image background) { bg = background; }
/** /**
* Draws the button. * Draws the button.
* @param x the x coordinate * @param x the x coordinate
@ -78,6 +69,7 @@ public class OsuGroupNode {
float xOffset = 0f; float xOffset = 0f;
OsuFile osu; OsuFile osu;
Color textColor = Color.lightGray; Color textColor = Color.lightGray;
Image bg = GameImage.MENU_BUTTON_BG.getImage();
if (expanded) { // expanded if (expanded) { // expanded
xOffset = bg.getWidth() / 10f; xOffset = bg.getWidth() / 10f;

View File

@ -67,9 +67,6 @@ public class OsuParser {
* @param height the container height * @param height the container height
*/ */
public static void parseAllFiles(File root, int width, int height) { public static void parseAllFiles(File root, int width, int height) {
// initialize hit objects
OsuHitObject.init(width, height);
// progress tracking // progress tracking
File[] folders = root.listFiles(); File[] folders = root.listFiles();
currentDirectoryIndex = 0; currentDirectoryIndex = 0;

View File

@ -65,8 +65,8 @@ public class OszUnpacker {
if (!songDir.isDirectory()) { if (!songDir.isDirectory()) {
songDir.mkdir(); songDir.mkdir();
unzip(file, songDir); unzip(file, songDir);
file.delete(); // delete the OSZ when finished
} }
file.delete(); // delete the OSZ when finished
} }
fileIndex = -1; fileIndex = -1;

View File

@ -217,6 +217,9 @@ public class Utils {
for (SongSort sort : SongSort.values()) for (SongSort sort : SongSort.values())
sort.init(width, height); sort.init(width, height);
// initialize hit objects
OsuHitObject.init(width, height);
// back button // back button
Image back = GameImage.MENU_BACK.getImage(); Image back = GameImage.MENU_BACK.getImage();
backButton = new MenuButton(back, backButton = new MenuButton(back,
@ -316,11 +319,11 @@ public class Utils {
*/ */
public static void loadCursor() throws SlickException { public static void loadCursor() throws SlickException {
// destroy old cursors, if they exist // destroy old cursors, if they exist
if (cursor != null) if (cursor != null && !cursor.isDestroyed())
cursor.destroy(); cursor.destroy();
if (cursorTrail != null) if (cursorTrail != null && !cursorTrail.isDestroyed())
cursorTrail.destroy(); cursorTrail.destroy();
if (cursorMiddle != null) if (cursorMiddle != null && !cursorMiddle.isDestroyed())
cursorMiddle.destroy(); cursorMiddle.destroy();
cursor = cursorTrail = cursorMiddle = null; cursor = cursorTrail = cursorMiddle = null;

View File

@ -135,6 +135,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);
pauseTime = 0f;
if (loop) if (loop)
player.loop(); player.loop();
else else
@ -237,6 +238,8 @@ public class MusicController {
public static void stop() { public static void stop() {
if (isPlaying()) if (isPlaying())
player.stop(); player.stop();
if (trackExists())
pauseTime = 0f;
} }
/** /**
@ -400,7 +403,7 @@ public class MusicController {
player = null; player = null;
} catch (Exception e) { } catch (Exception e) {
ErrorHandler.error("Failed to destroy OpenAL.", e, false); ErrorHandler.error("Failed to destroy OpenAL.", e, true);
} }
} }
} }

View File

@ -165,12 +165,6 @@ public class Game extends BasicGameState {
*/ */
private float pausePulse; private float pausePulse;
/**
* Default playfield background (optional).
* Overridden by song background unless "ForceDefaultPlayfield" option enabled.
*/
private Image playfield;
/** /**
* Whether a checkpoint has been loaded during this game. * Whether a checkpoint has been loaded during this game.
*/ */
@ -214,13 +208,6 @@ public class Game extends BasicGameState {
// create the associated GameScore object // create the associated GameScore object
score = new GameScore(width, height); score = new GameScore(width, height);
((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameScore(score); ((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameScore(score);
// playfield background
try {
playfield = new Image("playfield.png").getScaledCopy(width, height);
} catch (Exception e) {
// optional
}
} }
@Override @Override
@ -232,10 +219,8 @@ public class Game extends BasicGameState {
// background // background
g.setBackground(Color.black); g.setBackground(Color.black);
float dimLevel = Options.getBackgroundDim(); float dimLevel = Options.getBackgroundDim();
if (Options.isDefaultPlayfieldForced() && playfield != null) { if (Options.isDefaultPlayfieldForced() || !osu.drawBG(width, height, dimLevel)) {
playfield.setAlpha(dimLevel); Image playfield = GameImage.PLAYFIELD.getImage();
playfield.draw();
} else if (!osu.drawBG(width, height, dimLevel) && playfield != null) {
playfield.setAlpha(dimLevel); playfield.setAlpha(dimLevel);
playfield.draw(); playfield.draw();
} }

View File

@ -139,7 +139,7 @@ public class Options extends BasicGameState {
*/ */
private static enum GameOption { private static enum GameOption {
NULL (null, null), NULL (null, null),
SCREEN_RESOLUTION ("Screen Resolution", "Restart to apply resolution changes.") { SCREEN_RESOLUTION ("Screen Resolution", "Restart (Ctrl+Shift+F5) to apply resolution changes.") {
@Override @Override
public String getValueString() { return resolution.toString(); } public String getValueString() { return resolution.toString(); }
@ -325,7 +325,7 @@ public class Options extends BasicGameState {
@Override @Override
public void click(GameContainer container) { loadVerbose = !loadVerbose; } public void click(GameContainer container) { loadVerbose = !loadVerbose; }
}, },
CHECKPOINT ("Track Checkpoint", "Press CTRL+L while playing to load a checkpoint, and CTRL+S to set one.") { CHECKPOINT ("Track Checkpoint", "Press Ctrl+L while playing to load a checkpoint, and Ctrl+S to set one.") {
@Override @Override
public String getValueString() { public String getValueString() {
return (checkpoint == 0) ? "Disabled" : String.format("%02d:%02d", return (checkpoint == 0) ? "Disabled" : String.format("%02d:%02d",
@ -975,10 +975,19 @@ public class Options extends BasicGameState {
SoundController.playSound(SoundEffect.MENUBACK); SoundController.playSound(SoundEffect.MENUBACK);
game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black));
break; break;
case Input.KEY_F5:
// restart application
if ((input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) &&
(input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT))) {
container.setForceExit(false);
container.exit();
}
break;
case Input.KEY_F12: case Input.KEY_F12:
Utils.takeScreenShot(); Utils.takeScreenShot();
break; break;
case Input.KEY_TAB: case Input.KEY_TAB:
// change tabs
int i = 1; int i = 1;
if (input.isKeyDown(Input.KEY_LSHIFT) || input.isKeyDown(Input.KEY_RSHIFT)) if (input.isKeyDown(Input.KEY_LSHIFT) || input.isKeyDown(Input.KEY_RSHIFT))
i = TAB_MAX - 1; i = TAB_MAX - 1;
@ -1130,8 +1139,8 @@ public class Options extends BasicGameState {
app.setDisplayMode(resolution.getWidth(), resolution.getHeight(), false); app.setDisplayMode(resolution.getWidth(), resolution.getHeight(), false);
// set borderless window if dimensions match screen size // set borderless window if dimensions match screen size
if (screenWidth == resolution.getWidth() && screenHeight == resolution.getHeight()) boolean borderless = (screenWidth == resolution.getWidth() && screenHeight == resolution.getHeight());
System.setProperty("org.lwjgl.opengl.Window.undecorated", "true"); System.setProperty("org.lwjgl.opengl.Window.undecorated", Boolean.toString(borderless));
} }
// /** // /**

View File

@ -209,7 +209,6 @@ public class SongMenu extends BasicGameState {
// song button background & graphics context // song button background & graphics context
Image menuBackground = GameImage.MENU_BUTTON_BG.getImage(); Image menuBackground = GameImage.MENU_BUTTON_BG.getImage();
OsuGroupNode.setBackground(menuBackground);
// song button coordinates // song button coordinates
buttonX = width * 0.6f; buttonX = width * 0.6f;
@ -651,6 +650,13 @@ public class SongMenu extends BasicGameState {
if (MusicController.isThemePlaying() && focusNode != null) if (MusicController.isThemePlaying() && focusNode != null)
MusicController.play(focusNode.osuFiles.get(focusNode.osuFileIndex), true); MusicController.play(focusNode.osuFiles.get(focusNode.osuFileIndex), true);
// reset music track
else if (resetTrack) {
MusicController.pause();
MusicController.playAt(MusicController.getOsuFile().previewTime, true);
resetTrack = false;
}
// unpause track // unpause track
else if (MusicController.isPaused()) else if (MusicController.isPaused())
MusicController.resume(); MusicController.resume();
@ -664,13 +670,6 @@ public class SongMenu extends BasicGameState {
GameImage.destroySkinImages(); // destroy skin images, if any GameImage.destroySkinImages(); // destroy skin images, if any
resetGame = false; resetGame = false;
} }
// reset music track
if (resetTrack) {
MusicController.pause();
MusicController.playAt(MusicController.getOsuFile().previewTime, true);
resetTrack = false;
}
} }
@Override @Override

View File

@ -119,16 +119,19 @@ public class Splash extends BasicGameState {
thread = new Thread() { thread = new Thread() {
@Override @Override
public void run() { public void run() {
File beatmapDir = Options.getBeatmapDir(); // application restart: everything already loaded
if (OsuGroupList.get().size() < 1) {
File beatmapDir = Options.getBeatmapDir();
// unpack all OSZ archives // unpack all OSZ archives
OszUnpacker.unpackAllFiles(Options.getOSZDir(), beatmapDir); OszUnpacker.unpackAllFiles(Options.getOSZDir(), beatmapDir);
// parse song directory // parse song directory
OsuParser.parseAllFiles(beatmapDir, width, height); OsuParser.parseAllFiles(beatmapDir, width, height);
// load sounds // load sounds
SoundController.init(); SoundController.init();
}
finished = true; finished = true;
} }