Save game scores to an SQLite database. [Incomplete!]
Implemented basic features (mostly stable). The remaining features are mostly graphical. - Added package org.xerial.sqlite-jdbc. All scores are saved to .opsu_scores.db on table `scores` after a game completes. - Added "Scores" class to handle all game score data (including database connections). The "Score" subclass encapsulates all database fields. - Added "score viewing" constructor to GameData, for use only in the ranking screen. - Draw the grade of the highest score next to expanded song buttons in the song menu. - Added "bit" and "abbrev" fields to GameMod, used in storing/displaying scores. - Hide the retry/exit buttons in the ranking screen when viewing a score. Other changes: - Removed "objectCount" field in GameData (no longer necessary). - Removed "getID()" method in GameMod (no longer used). - Moved most drawing in GameRanking state to GameData. - Removed File parameter of "GameData.loadImages()" (leftover, no longer used). Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import itdelatrisu.opsu.Options;
|
||||
import itdelatrisu.opsu.OsuFile;
|
||||
import itdelatrisu.opsu.OsuHitObject;
|
||||
import itdelatrisu.opsu.OsuTimingPoint;
|
||||
import itdelatrisu.opsu.Scores;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.audio.HitSound;
|
||||
import itdelatrisu.opsu.audio.MusicController;
|
||||
@@ -160,7 +161,6 @@ public class Game extends BasicGameState {
|
||||
|
||||
// create the associated GameData object
|
||||
data = new GameData(width, height);
|
||||
((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -419,8 +419,12 @@ public class Game extends BasicGameState {
|
||||
if (objectIndex >= osu.objects.length) {
|
||||
if (checkpointLoaded) // if checkpoint used, skip ranking screen
|
||||
game.closeRequested();
|
||||
else // go to ranking screen
|
||||
else { // go to ranking screen
|
||||
((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameData(data);
|
||||
if (!GameMod.AUTO.isActive())
|
||||
Scores.addScore(data.getScoreData(osu));
|
||||
game.enterState(Opsu.STATE_GAMERANKING, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -800,7 +804,7 @@ public class Game extends BasicGameState {
|
||||
|
||||
// load other images...
|
||||
((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages();
|
||||
data.loadImages(osu.getFile().getParentFile());
|
||||
data.loadImages();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,9 +18,8 @@
|
||||
|
||||
package itdelatrisu.opsu.states;
|
||||
|
||||
import itdelatrisu.opsu.GameImage;
|
||||
import itdelatrisu.opsu.GameMod;
|
||||
import itdelatrisu.opsu.GameData;
|
||||
import itdelatrisu.opsu.GameImage;
|
||||
import itdelatrisu.opsu.MenuButton;
|
||||
import itdelatrisu.opsu.Opsu;
|
||||
import itdelatrisu.opsu.OsuFile;
|
||||
@@ -100,29 +99,13 @@ public class GameRanking extends BasicGameState {
|
||||
g.setBackground(Utils.COLOR_BLACK_ALPHA);
|
||||
|
||||
// ranking screen elements
|
||||
data.drawRankingElements(g, width, height);
|
||||
|
||||
// game mods
|
||||
for (GameMod mod : GameMod.VALUES_REVERSED) {
|
||||
if (mod.isActive()) {
|
||||
Image modImage = mod.getImage();
|
||||
modImage.draw(
|
||||
(width * 0.75f) + ((mod.getID() - (GameMod.SIZE / 2)) * modImage.getWidth() / 3f),
|
||||
height / 2f
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// header text
|
||||
float marginX = width * 0.01f, marginY = height * 0.01f;
|
||||
Utils.FONT_LARGE.drawString(marginX, marginY,
|
||||
String.format("%s - %s [%s]", osu.getArtist(), osu.getTitle(), osu.version), Color.white);
|
||||
Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() - 6,
|
||||
String.format("Beatmap by %s", osu.creator), Color.white);
|
||||
data.drawRankingElements(g, osu);
|
||||
|
||||
// buttons
|
||||
retryButton.draw();
|
||||
exitButton.draw();
|
||||
if (data.isGameplay()) {
|
||||
retryButton.draw();
|
||||
exitButton.draw();
|
||||
}
|
||||
Utils.getBackButton().draw();
|
||||
|
||||
Utils.drawVolume(g);
|
||||
@@ -146,12 +129,7 @@ public class GameRanking extends BasicGameState {
|
||||
public void keyPressed(int key, char c) {
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
SongMenu songMenu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
|
||||
songMenu.resetGameDataOnLoad();
|
||||
songMenu.resetTrackOnLoad();
|
||||
Utils.resetCursor();
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
returnToSongMenu();
|
||||
break;
|
||||
case Input.KEY_F12:
|
||||
Utils.takeScreenShot();
|
||||
@@ -165,25 +143,26 @@ public class GameRanking extends BasicGameState {
|
||||
if (button != Input.MOUSE_LEFT_BUTTON)
|
||||
return;
|
||||
|
||||
if (retryButton.contains(x, y)) {
|
||||
OsuFile osu = MusicController.getOsuFile();
|
||||
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
|
||||
((Game) game.getState(Opsu.STATE_GAME)).setRestart(Game.Restart.MANUAL);
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
} else if (exitButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
|
||||
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad();
|
||||
Utils.resetCursor();
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
} else if (Utils.getBackButton().contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
SongMenu songMenu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
|
||||
songMenu.resetGameDataOnLoad();
|
||||
songMenu.resetTrackOnLoad();
|
||||
Utils.resetCursor();
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
if (data.isGameplay()) {
|
||||
if (retryButton.contains(x, y)) {
|
||||
OsuFile osu = MusicController.getOsuFile();
|
||||
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString()));
|
||||
((Game) game.getState(Opsu.STATE_GAME)).setRestart(Game.Restart.MANUAL);
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
return;
|
||||
} else if (exitButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
|
||||
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad();
|
||||
Utils.resetCursor();
|
||||
game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Utils.getBackButton().contains(x, y)) {
|
||||
returnToSongMenu();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +174,26 @@ public class GameRanking extends BasicGameState {
|
||||
SoundController.playSound(SoundEffect.APPLAUSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leave(GameContainer container, StateBasedGame game)
|
||||
throws SlickException {
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns to the song menu.
|
||||
*/
|
||||
private void returnToSongMenu() {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
if (data.isGameplay()) {
|
||||
SongMenu songMenu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
|
||||
songMenu.resetGameDataOnLoad();
|
||||
songMenu.resetTrackOnLoad();
|
||||
}
|
||||
Utils.resetCursor();
|
||||
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the associated GameData object.
|
||||
* @param data the GameData
|
||||
|
||||
@@ -28,6 +28,9 @@ import itdelatrisu.opsu.OsuGroupList;
|
||||
import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.OsuParser;
|
||||
import itdelatrisu.opsu.OszUnpacker;
|
||||
import itdelatrisu.opsu.Scores;
|
||||
import itdelatrisu.opsu.GameData.Grade;
|
||||
import itdelatrisu.opsu.Scores.ScoreData;
|
||||
import itdelatrisu.opsu.SongSort;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.audio.HitSound;
|
||||
@@ -36,6 +39,7 @@ import itdelatrisu.opsu.audio.SoundController;
|
||||
import itdelatrisu.opsu.audio.SoundEffect;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
@@ -153,6 +157,9 @@ public class SongMenu extends BasicGameState {
|
||||
/** Beatmap reloading thread. */
|
||||
private Thread reloadThread;
|
||||
|
||||
/** Current map of scores (Version, ScoreData[]). */
|
||||
private Map<String, ScoreData[]> scoreMap;
|
||||
|
||||
// game-related variables
|
||||
private GameContainer container;
|
||||
private StateBasedGame game;
|
||||
@@ -261,8 +268,16 @@ public class SongMenu extends BasicGameState {
|
||||
// song buttons
|
||||
OsuGroupNode node = startNode;
|
||||
for (int i = 0; i < MAX_BUTTONS && node != null; i++, node = node.next) {
|
||||
// draw the node
|
||||
float offset = (i == hoverIndex) ? hoverOffset : 0f;
|
||||
node.draw(buttonX - offset, buttonY + (i*buttonOffset), (node == focusNode));
|
||||
ScoreData[] scores = getScoreDataForNode(node);
|
||||
node.draw(
|
||||
buttonX - offset, buttonY + (i*buttonOffset),
|
||||
(scores == null) ? Grade.NULL : scores[0].getGrade(),
|
||||
(node == focusNode)
|
||||
);
|
||||
|
||||
// load glyphs
|
||||
Utils.loadGlyphs(node.osuFiles.get(0));
|
||||
}
|
||||
|
||||
@@ -703,11 +718,17 @@ public class SongMenu extends BasicGameState {
|
||||
// reset game data
|
||||
if (resetGame) {
|
||||
((Game) game.getState(Opsu.STATE_GAME)).resetGameData();
|
||||
|
||||
// destroy skin images, if any
|
||||
for (GameImage img : GameImage.values()) {
|
||||
if (img.isSkinnable())
|
||||
img.destroySkinImage();
|
||||
}
|
||||
|
||||
// reload scores
|
||||
if (focusNode != null)
|
||||
scoreMap = Scores.getMapSetScores(focusNode.osuFiles.get(focusNode.osuFileIndex));
|
||||
|
||||
resetGame = false;
|
||||
}
|
||||
}
|
||||
@@ -798,6 +819,9 @@ public class SongMenu extends BasicGameState {
|
||||
MusicController.play(osu, true);
|
||||
Utils.loadGlyphs(osu);
|
||||
|
||||
// load scores
|
||||
scoreMap = Scores.getMapSetScores(osu);
|
||||
|
||||
// check startNode bounds
|
||||
while (startNode.index >= OsuGroupList.get().size() + length - MAX_BUTTONS && startNode.prev != null)
|
||||
startNode = startNode.prev;
|
||||
@@ -835,6 +859,30 @@ public class SongMenu extends BasicGameState {
|
||||
*/
|
||||
public void resetTrackOnLoad() { resetTrack = true; }
|
||||
|
||||
/**
|
||||
* Returns all the score data for an OsuGroupNode from scoreMap.
|
||||
* If no score data is available for the node, return null.
|
||||
* @param node the OsuGroupNode
|
||||
* @return the ScoreData array
|
||||
*/
|
||||
private ScoreData[] getScoreDataForNode(OsuGroupNode node) {
|
||||
if (scoreMap == null || node.osuFileIndex == -1) // node not expanded
|
||||
return null;
|
||||
|
||||
OsuFile osu = node.osuFiles.get(node.osuFileIndex);
|
||||
ScoreData[] scores = scoreMap.get(osu.version);
|
||||
if (scores == null || scores.length < 1) // no scores
|
||||
return null;
|
||||
|
||||
ScoreData s = scores[0];
|
||||
if (osu.beatmapID == s.MID && osu.beatmapSetID == s.MSID &&
|
||||
osu.title.equals(s.title) && osu.artist.equals(s.artist) &&
|
||||
osu.creator.equals(s.creator))
|
||||
return scores;
|
||||
else
|
||||
return null; // incorrect map
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the game.
|
||||
* @param osu the OsuFile to send to the game
|
||||
|
||||
Reference in New Issue
Block a user