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:
Jeffrey Han
2015-01-28 03:47:24 -05:00
parent f71b2c25f2
commit 0bd72e731a
13 changed files with 693 additions and 133 deletions

View File

@@ -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();
}
/**

View File

@@ -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

View File

@@ -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