Implemented in-game beatmap reloading.
- Press F5 to reload beatmaps in the song menu (resets OsuGroupList, then invokes OSZ unpacker and OsuFile parser). - Many components reused from Splash screen (progress display, 'Esc' interrupt). Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
19476993f9
commit
a48f8bd54d
|
@ -63,7 +63,7 @@ public class Opsu extends StateBasedGame {
|
||||||
STATE_GAME = 4,
|
STATE_GAME = 4,
|
||||||
STATE_GAMEPAUSEMENU = 5,
|
STATE_GAMEPAUSEMENU = 5,
|
||||||
STATE_GAMERANKING = 6,
|
STATE_GAMERANKING = 6,
|
||||||
STATE_OPTIONS = 7;
|
STATE_OPTIONSMENU = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to restrict the program to a single instance.
|
* Used to restrict the program to a single instance.
|
||||||
|
@ -83,7 +83,7 @@ public class Opsu extends StateBasedGame {
|
||||||
addState(new Game(STATE_GAME));
|
addState(new Game(STATE_GAME));
|
||||||
addState(new GamePauseMenu(STATE_GAMEPAUSEMENU));
|
addState(new GamePauseMenu(STATE_GAMEPAUSEMENU));
|
||||||
addState(new GameRanking(STATE_GAMERANKING));
|
addState(new GameRanking(STATE_GAMERANKING));
|
||||||
addState(new OptionsMenu(STATE_OPTIONS));
|
addState(new OptionsMenu(STATE_OPTIONSMENU));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -587,6 +587,47 @@ public class Utils {
|
||||||
volumeDisplay = VOLUME_DISPLAY_TIME / 10;
|
volumeDisplay = VOLUME_DISPLAY_TIME / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws loading progress (OSZ unpacking, OsuFile parsing, sound loading)
|
||||||
|
* at the bottom of the screen.
|
||||||
|
*/
|
||||||
|
public static void drawLoadingProgress(Graphics g) {
|
||||||
|
String text, file;
|
||||||
|
int progress;
|
||||||
|
|
||||||
|
// determine current action
|
||||||
|
if ((file = OszUnpacker.getCurrentFileName()) != null) {
|
||||||
|
text = "Unpacking new beatmaps...";
|
||||||
|
progress = OszUnpacker.getUnpackerProgress();
|
||||||
|
} else if ((file = OsuParser.getCurrentFileName()) != null) {
|
||||||
|
text = "Loading beatmaps...";
|
||||||
|
progress = OsuParser.getParserProgress();
|
||||||
|
} else if ((file = SoundController.getCurrentFileName()) != null) {
|
||||||
|
text = "Loading sounds...";
|
||||||
|
progress = SoundController.getLoadingProgress();
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
|
||||||
|
// draw loading info
|
||||||
|
float marginX = container.getWidth() * 0.02f, marginY = container.getHeight() * 0.02f;
|
||||||
|
float lineY = container.getHeight() - marginY;
|
||||||
|
int lineOffsetY = Utils.FONT_MEDIUM.getLineHeight();
|
||||||
|
if (Options.isLoadVerbose()) {
|
||||||
|
// verbose: display percentages and file names
|
||||||
|
Utils.FONT_MEDIUM.drawString(
|
||||||
|
marginX, lineY - (lineOffsetY * 2),
|
||||||
|
String.format("%s (%d%%)", text, progress), Color.white);
|
||||||
|
Utils.FONT_MEDIUM.drawString(marginX, lineY - lineOffsetY, file, Color.white);
|
||||||
|
} else {
|
||||||
|
// draw loading bar
|
||||||
|
Utils.FONT_MEDIUM.drawString(marginX, lineY - (lineOffsetY * 2), text, Color.white);
|
||||||
|
g.setColor(Color.white);
|
||||||
|
g.fillRoundRect(marginX, lineY - (lineOffsetY / 2f),
|
||||||
|
(container.getWidth() - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a screenshot.
|
* Takes a screenshot.
|
||||||
* @author http://wiki.lwjgl.org/index.php?title=Taking_Screen_Shots
|
* @author http://wiki.lwjgl.org/index.php?title=Taking_Screen_Shots
|
||||||
|
|
|
@ -43,7 +43,7 @@ import org.newdawn.slick.state.transition.EmptyTransition;
|
||||||
import org.newdawn.slick.state.transition.FadeInTransition;
|
import org.newdawn.slick.state.transition.FadeInTransition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Game OptionsMenu" state.
|
* "Game Options" state.
|
||||||
*/
|
*/
|
||||||
public class OptionsMenu extends BasicGameState {
|
public class OptionsMenu extends BasicGameState {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,10 +22,12 @@ import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameMod;
|
import itdelatrisu.opsu.GameMod;
|
||||||
import itdelatrisu.opsu.MenuButton;
|
import itdelatrisu.opsu.MenuButton;
|
||||||
import itdelatrisu.opsu.Opsu;
|
import itdelatrisu.opsu.Opsu;
|
||||||
|
import itdelatrisu.opsu.Options;
|
||||||
import itdelatrisu.opsu.OsuFile;
|
import itdelatrisu.opsu.OsuFile;
|
||||||
import itdelatrisu.opsu.OsuGroupList;
|
import itdelatrisu.opsu.OsuGroupList;
|
||||||
import itdelatrisu.opsu.OsuGroupNode;
|
import itdelatrisu.opsu.OsuGroupNode;
|
||||||
import itdelatrisu.opsu.OsuParser;
|
import itdelatrisu.opsu.OsuParser;
|
||||||
|
import itdelatrisu.opsu.OszUnpacker;
|
||||||
import itdelatrisu.opsu.SongSort;
|
import itdelatrisu.opsu.SongSort;
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.HitSound;
|
import itdelatrisu.opsu.audio.HitSound;
|
||||||
|
@ -33,6 +35,7 @@ import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import org.lwjgl.opengl.Display;
|
import org.lwjgl.opengl.Display;
|
||||||
|
@ -187,6 +190,11 @@ public class SongMenu extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
private boolean resetTrack = false;
|
private boolean resetTrack = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Beatmap reloading thread.
|
||||||
|
*/
|
||||||
|
private Thread reloadThread;
|
||||||
|
|
||||||
// game-related variables
|
// game-related variables
|
||||||
private GameContainer container;
|
private GameContainer container;
|
||||||
private StateBasedGame game;
|
private StateBasedGame game;
|
||||||
|
@ -339,8 +347,18 @@ public class SongMenu extends BasicGameState {
|
||||||
g.fillRoundRect(width - 10, scrollStartY + (scrollEndY * startNode.index / OsuGroupList.get().size()), 5, 20, 4);
|
g.fillRoundRect(width - 10, scrollStartY + (scrollEndY * startNode.index / OsuGroupList.get().size()), 5, 20, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reloading beatmaps
|
||||||
|
if (reloadThread != null) {
|
||||||
|
// darken the screen
|
||||||
|
g.setColor(Utils.COLOR_BLACK_ALPHA);
|
||||||
|
g.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
Utils.drawLoadingProgress(g);
|
||||||
|
}
|
||||||
|
|
||||||
// back button
|
// back button
|
||||||
Utils.getBackButton().draw();
|
else
|
||||||
|
Utils.getBackButton().draw();
|
||||||
|
|
||||||
Utils.drawVolume(g);
|
Utils.drawVolume(g);
|
||||||
Utils.drawFPS();
|
Utils.drawFPS();
|
||||||
|
@ -445,6 +463,10 @@ public class SongMenu extends BasicGameState {
|
||||||
if (button != Input.MOUSE_LEFT_BUTTON)
|
if (button != Input.MOUSE_LEFT_BUTTON)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// block input during beatmap reloading
|
||||||
|
if (reloadThread != null)
|
||||||
|
return;
|
||||||
|
|
||||||
// back
|
// back
|
||||||
if (Utils.getBackButton().contains(x, y)) {
|
if (Utils.getBackButton().contains(x, y)) {
|
||||||
SoundController.playSound(SoundEffect.MENUBACK);
|
SoundController.playSound(SoundEffect.MENUBACK);
|
||||||
|
@ -456,7 +478,7 @@ public class SongMenu extends BasicGameState {
|
||||||
// options
|
// options
|
||||||
if (optionsButton.contains(x, y)) {
|
if (optionsButton.contains(x, y)) {
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
game.enterState(Opsu.STATE_OPTIONS, new EmptyTransition(), new FadeInTransition(Color.black));
|
game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,19 +542,30 @@ public class SongMenu extends BasicGameState {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyPressed(int key, char c) {
|
public void keyPressed(int key, char c) {
|
||||||
|
// block input during beatmap reloading
|
||||||
|
if (reloadThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12))
|
||||||
|
return;
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case Input.KEY_ESCAPE:
|
case Input.KEY_ESCAPE:
|
||||||
if (!search.getText().isEmpty()) {
|
if (reloadThread != null) {
|
||||||
|
// beatmap reloading: stop parsing OsuFiles by sending interrupt to OsuParser
|
||||||
|
if (reloadThread != null)
|
||||||
|
reloadThread.interrupt();
|
||||||
|
} else if (!search.getText().isEmpty()) {
|
||||||
|
// clear search text
|
||||||
search.setText("");
|
search.setText("");
|
||||||
searchTimer = SEARCH_DELAY;
|
searchTimer = SEARCH_DELAY;
|
||||||
} else {
|
} else {
|
||||||
|
// return to main menu
|
||||||
SoundController.playSound(SoundEffect.MENUBACK);
|
SoundController.playSound(SoundEffect.MENUBACK);
|
||||||
((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
|
((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
|
||||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Input.KEY_F1:
|
case Input.KEY_F1:
|
||||||
game.enterState(Opsu.STATE_OPTIONS, new EmptyTransition(), new FadeInTransition(Color.black));
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
|
game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition(Color.black));
|
||||||
break;
|
break;
|
||||||
case Input.KEY_F2:
|
case Input.KEY_F2:
|
||||||
if (focusNode == null)
|
if (focusNode == null)
|
||||||
|
@ -549,6 +582,42 @@ public class SongMenu extends BasicGameState {
|
||||||
setFocus(OsuGroupList.get().getRandomNode(), -1, true);
|
setFocus(OsuGroupList.get().getRandomNode(), -1, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Input.KEY_F5:
|
||||||
|
// TODO: osu! has a confirmation menu
|
||||||
|
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||||
|
|
||||||
|
// reset state and node references
|
||||||
|
MusicController.reset();
|
||||||
|
startNode = focusNode = null;
|
||||||
|
oldFocusNode = null;
|
||||||
|
randomStack = new Stack<SongNode>();
|
||||||
|
songInfo = null;
|
||||||
|
hoverOffset = 0f;
|
||||||
|
hoverIndex = -1;
|
||||||
|
search.setText("");
|
||||||
|
searchTimer = SEARCH_DELAY;
|
||||||
|
|
||||||
|
// reload songs in new thread
|
||||||
|
reloadThread = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// invoke unpacker and parser
|
||||||
|
File beatmapDir = Options.getBeatmapDir();
|
||||||
|
OszUnpacker.unpackAllFiles(Options.getOSZDir(), beatmapDir);
|
||||||
|
OsuParser.parseAllFiles(beatmapDir, container.getWidth(), container.getHeight());
|
||||||
|
|
||||||
|
// initialize song list
|
||||||
|
if (OsuGroupList.get().size() > 0) {
|
||||||
|
OsuGroupList.get().init();
|
||||||
|
setFocus(OsuGroupList.get().getRandomNode(), -1, true);
|
||||||
|
} else if (Options.isThemSongEnabled())
|
||||||
|
MusicController.playThemeSong();
|
||||||
|
|
||||||
|
reloadThread = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reloadThread.start();
|
||||||
|
break;
|
||||||
case Input.KEY_F12:
|
case Input.KEY_F12:
|
||||||
Utils.takeScreenShot();
|
Utils.takeScreenShot();
|
||||||
break;
|
break;
|
||||||
|
@ -616,6 +685,10 @@ public class SongMenu extends BasicGameState {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseDragged(int oldx, int oldy, int newx, int newy) {
|
public void mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||||
|
// block input during beatmap reloading
|
||||||
|
if (reloadThread != null)
|
||||||
|
return;
|
||||||
|
|
||||||
// check mouse button (right click scrolls faster)
|
// check mouse button (right click scrolls faster)
|
||||||
int multiplier;
|
int multiplier;
|
||||||
if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON))
|
if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON))
|
||||||
|
@ -634,6 +707,10 @@ public class SongMenu extends BasicGameState {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseWheelMoved(int newValue) {
|
public void mouseWheelMoved(int newValue) {
|
||||||
|
// block input during beatmap reloading
|
||||||
|
if (reloadThread != null)
|
||||||
|
return;
|
||||||
|
|
||||||
changeIndex((newValue < 0) ? 1 : -1);
|
changeIndex((newValue < 0) ? 1 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,27 +85,7 @@ public class Splash extends BasicGameState {
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
g.setBackground(Color.black);
|
g.setBackground(Color.black);
|
||||||
GameImage.MENU_LOGO.getImage().drawCentered(container.getWidth() / 2, container.getHeight() / 2);
|
GameImage.MENU_LOGO.getImage().drawCentered(container.getWidth() / 2, container.getHeight() / 2);
|
||||||
|
Utils.drawLoadingProgress(g);
|
||||||
// display progress
|
|
||||||
String unpackedFile = OszUnpacker.getCurrentFileName();
|
|
||||||
String parsedFile = OsuParser.getCurrentFileName();
|
|
||||||
String soundFile = SoundController.getCurrentFileName();
|
|
||||||
if (unpackedFile != null) {
|
|
||||||
drawLoadProgress(
|
|
||||||
g, OszUnpacker.getUnpackerProgress(),
|
|
||||||
"Unpacking new beatmaps...", unpackedFile
|
|
||||||
);
|
|
||||||
} else if (parsedFile != null) {
|
|
||||||
drawLoadProgress(
|
|
||||||
g, OsuParser.getParserProgress(),
|
|
||||||
"Loading beatmaps...", parsedFile
|
|
||||||
);
|
|
||||||
} else if (soundFile != null) {
|
|
||||||
drawLoadProgress(
|
|
||||||
g, SoundController.getLoadingProgress(),
|
|
||||||
"Loading sounds...", soundFile
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -136,6 +116,7 @@ public class Splash extends BasicGameState {
|
||||||
SoundController.init();
|
SoundController.init();
|
||||||
|
|
||||||
finished = true;
|
finished = true;
|
||||||
|
thread = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
thread.start();
|
thread.start();
|
||||||
|
@ -151,8 +132,10 @@ public class Splash extends BasicGameState {
|
||||||
// change states when loading complete
|
// change states when loading complete
|
||||||
if (finished && alpha >= 1f) {
|
if (finished && alpha >= 1f) {
|
||||||
// initialize song list
|
// initialize song list
|
||||||
OsuGroupList.get().init();
|
if (OsuGroupList.get().size() > 0) {
|
||||||
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(OsuGroupList.get().getRandomNode(), -1, true);
|
OsuGroupList.get().init();
|
||||||
|
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(OsuGroupList.get().getRandomNode(), -1, true);
|
||||||
|
}
|
||||||
|
|
||||||
// play the theme song
|
// play the theme song
|
||||||
if (Options.isThemSongEnabled())
|
if (Options.isThemSongEnabled())
|
||||||
|
@ -175,29 +158,4 @@ public class Splash extends BasicGameState {
|
||||||
else if (key == Input.KEY_ESCAPE && thread != null)
|
else if (key == Input.KEY_ESCAPE && thread != null)
|
||||||
thread.interrupt();
|
thread.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws loading progress.
|
|
||||||
* @param g the graphics context
|
|
||||||
* @param progress the completion percentage
|
|
||||||
* @param text the progress text
|
|
||||||
* @param file the file being loaded
|
|
||||||
*/
|
|
||||||
private void drawLoadProgress(Graphics g, int progress, String text, String file) {
|
|
||||||
float marginX = container.getWidth() * 0.02f, marginY = container.getHeight() * 0.02f;
|
|
||||||
float lineY = container.getHeight() - marginY;
|
|
||||||
int lineOffsetY = Utils.FONT_MEDIUM.getLineHeight();
|
|
||||||
if (Options.isLoadVerbose()) {
|
|
||||||
Utils.FONT_MEDIUM.drawString(
|
|
||||||
marginX, lineY - (lineOffsetY * 2),
|
|
||||||
String.format("%s (%d%%)", text, progress), Color.white);
|
|
||||||
Utils.FONT_MEDIUM.drawString(marginX, lineY - lineOffsetY, file, Color.white);
|
|
||||||
} else {
|
|
||||||
Utils.FONT_MEDIUM.drawString(marginX, lineY - (lineOffsetY * 2), text, Color.white);
|
|
||||||
g.setColor(Color.white);
|
|
||||||
g.fillRoundRect(marginX, lineY - (lineOffsetY / 2f),
|
|
||||||
(container.getWidth() - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user