Major refactoring - now using far more logical class names.

- Renamed "OsuFile" to "Beatmap".  All related variables and methods with "osu" have also been renamed to "beatmap" (or variants of each).
- Renamed "OsuGroupNode" to "BeatmapSetNode".  Avoids confusion since groups are identified by a "set ID", not a "group ID".
- Renamed "OsuGroupList" to "BeatmapSetList", for the same reason as above.
- Renamed "OsuDB" to "BeatmapDB", for the same reason as above.
- Moved classes directly related to parsed beatmaps (Beatmap, BeatmapSetList, BeatmapSetNode, OsuHitObject, and TimingPoint) into a new "beatmap" package.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-05-16 21:25:19 -04:00
parent 0a80590505
commit 53c79c5d85
36 changed files with 786 additions and 761 deletions

View File

@ -19,6 +19,8 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.downloads.DownloadList; import itdelatrisu.opsu.downloads.DownloadList;
import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.downloads.Updater;
@ -118,14 +120,14 @@ public class Container extends AppGameContainer {
// reset image references // reset image references
GameImage.clearReferences(); GameImage.clearReferences();
GameData.Grade.clearReferences(); GameData.Grade.clearReferences();
OsuFile.resetImageCache(); Beatmap.resetImageCache();
// prevent loading tracks from re-initializing OpenAL // prevent loading tracks from re-initializing OpenAL
MusicController.reset(); MusicController.reset();
// reset OsuGroupList data // reset BeatmapSetList data
if (OsuGroupList.get() != null) if (BeatmapSetList.get() != null)
OsuGroupList.get().reset(); BeatmapSetList.get().reset();
} }
@Override @Override

View File

@ -22,6 +22,8 @@ import itdelatrisu.opsu.audio.HitSound;
import itdelatrisu.opsu.audio.MusicController; 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 itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.objects.curves.Curve; import itdelatrisu.opsu.objects.curves.Curve;
import itdelatrisu.opsu.replay.Replay; import itdelatrisu.opsu.replay.Replay;
@ -334,7 +336,7 @@ public class GameData {
/** /**
* Constructor for score viewing. * Constructor for score viewing.
* This will initialize all parameters and images needed for the * This will initialize all parameters and images needed for the
* {@link #drawRankingElements(Graphics, OsuFile)} method. * {@link #drawRankingElements(Graphics, Beatmap)} method.
* @param s the ScoreData object * @param s the ScoreData object
* @param width container width * @param width container width
* @param height container height * @param height container height
@ -582,8 +584,8 @@ public class GameData {
width - margin, symbolHeight, 0.60f, 1f, true); width - margin, symbolHeight, 0.60f, 1f, true);
// map progress circle // map progress circle
OsuFile osu = MusicController.getOsuFile(); Beatmap beatmap = MusicController.getBeatmap();
int firstObjectTime = osu.objects[0].getTime(); int firstObjectTime = beatmap.objects[0].getTime();
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
float circleDiameter = symbolHeight * 0.60f; float circleDiameter = symbolHeight * 0.60f;
int circleX = (int) (width - margin - ( // max width: "100.00%" int circleX = (int) (width - margin - ( // max width: "100.00%"
@ -600,7 +602,7 @@ public class GameData {
if (trackPosition > firstObjectTime) { if (trackPosition > firstObjectTime) {
// map progress (white) // map progress (white)
g.fillArc(circleX, symbolHeight, circleDiameter, circleDiameter, g.fillArc(circleX, symbolHeight, circleDiameter, circleDiameter,
-90, -90 + (int) (360f * (trackPosition - firstObjectTime) / (osu.endTime - firstObjectTime)) -90, -90 + (int) (360f * (trackPosition - firstObjectTime) / (beatmap.endTime - firstObjectTime))
); );
} else { } else {
// lead-in time (yellow) // lead-in time (yellow)
@ -742,9 +744,9 @@ public class GameData {
/** /**
* Draws ranking elements: score, results, ranking, game mods. * Draws ranking elements: score, results, ranking, game mods.
* @param g the graphics context * @param g the graphics context
* @param osu the OsuFile * @param beatmap the beatmap
*/ */
public void drawRankingElements(Graphics g, OsuFile osu) { public void drawRankingElements(Graphics g, Beatmap beatmap) {
// TODO Version 2 skins // TODO Version 2 skins
float rankingHeight = 75; float rankingHeight = 75;
float scoreTextScale = 1.0f; float scoreTextScale = 1.0f;
@ -825,9 +827,9 @@ public class GameData {
rankingTitle.draw((width * 0.97f) - rankingTitle.getWidth(), 0); rankingTitle.draw((width * 0.97f) - rankingTitle.getWidth(), 0);
float marginX = width * 0.01f, marginY = height * 0.002f; float marginX = width * 0.01f, marginY = height * 0.002f;
Utils.FONT_LARGE.drawString(marginX, marginY, Utils.FONT_LARGE.drawString(marginX, marginY,
String.format("%s - %s [%s]", osu.getArtist(), osu.getTitle(), osu.version), Color.white); String.format("%s - %s [%s]", beatmap.getArtist(), beatmap.getTitle(), beatmap.version), Color.white);
Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() - 6, Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() - 6,
String.format("Beatmap by %s", osu.creator), Color.white); String.format("Beatmap by %s", beatmap.creator), Color.white);
Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() + Utils.FONT_MEDIUM.getLineHeight() - 10, Utils.FONT_MEDIUM.drawString(marginX, marginY + Utils.FONT_LARGE.getLineHeight() + Utils.FONT_MEDIUM.getLineHeight() - 10,
String.format("Played on %s.", scoreData.getTimeString()), Color.white); String.format("Played on %s.", scoreData.getTimeString()), Color.white);
@ -1309,21 +1311,21 @@ public class GameData {
* Returns a ScoreData object encapsulating all game data. * Returns a ScoreData object encapsulating all game data.
* If score data already exists, the existing object will be returned * If score data already exists, the existing object will be returned
* (i.e. this will not overwrite existing data). * (i.e. this will not overwrite existing data).
* @param osu the OsuFile * @param beatmap the beatmap
* @return the ScoreData object * @return the ScoreData object
*/ */
public ScoreData getScoreData(OsuFile osu) { public ScoreData getScoreData(Beatmap beatmap) {
if (scoreData != null) if (scoreData != null)
return scoreData; return scoreData;
scoreData = new ScoreData(); scoreData = new ScoreData();
scoreData.timestamp = System.currentTimeMillis() / 1000L; scoreData.timestamp = System.currentTimeMillis() / 1000L;
scoreData.MID = osu.beatmapID; scoreData.MID = beatmap.beatmapID;
scoreData.MSID = osu.beatmapSetID; scoreData.MSID = beatmap.beatmapSetID;
scoreData.title = osu.title; scoreData.title = beatmap.title;
scoreData.artist = osu.artist; scoreData.artist = beatmap.artist;
scoreData.creator = osu.creator; scoreData.creator = beatmap.creator;
scoreData.version = osu.version; scoreData.version = beatmap.version;
scoreData.hit300 = hitResultCount[HIT_300]; scoreData.hit300 = hitResultCount[HIT_300];
scoreData.hit100 = hitResultCount[HIT_100]; scoreData.hit100 = hitResultCount[HIT_100];
scoreData.hit50 = hitResultCount[HIT_50]; scoreData.hit50 = hitResultCount[HIT_50];
@ -1342,10 +1344,10 @@ public class GameData {
* Returns a Replay object encapsulating all game data. * Returns a Replay object encapsulating all game data.
* If a replay already exists and frames is null, the existing object will be returned. * If a replay already exists and frames is null, the existing object will be returned.
* @param frames the replay frames * @param frames the replay frames
* @param osu the associated OsuFile * @param beatmap the associated beatmap
* @return the Replay object, or null if none exists and frames is null * @return the Replay object, or null if none exists and frames is null
*/ */
public Replay getReplay(ReplayFrame[] frames, OsuFile osu) { public Replay getReplay(ReplayFrame[] frames, Beatmap beatmap) {
if (replay != null && frames == null) if (replay != null && frames == null)
return replay; return replay;
@ -1353,9 +1355,9 @@ public class GameData {
return null; return null;
replay = new Replay(); replay = new Replay();
replay.mode = OsuFile.MODE_OSU; replay.mode = Beatmap.MODE_OSU;
replay.version = Updater.get().getBuildDate(); replay.version = Updater.get().getBuildDate();
replay.beatmapHash = (osu == null) ? "" : Utils.getMD5(osu.getFile()); replay.beatmapHash = (beatmap == null) ? "" : Utils.getMD5(beatmap.getFile());
replay.playerName = ""; // TODO replay.playerName = ""; // TODO
replay.replayHash = Long.toString(System.currentTimeMillis()); // TODO replay.replayHash = Long.toString(System.currentTimeMillis()); // TODO
replay.hit300 = (short) hitResultCount[HIT_300]; replay.hit300 = (short) hitResultCount[HIT_300];

View File

@ -19,6 +19,7 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.beatmap.Beatmap;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@ -63,7 +64,7 @@ public class Options {
}; };
/** Cached beatmap database name. */ /** Cached beatmap database name. */
public static final File OSU_DB = new File(DATA_DIR, ".opsu.db"); public static final File BEATMAP_DB = new File(DATA_DIR, ".opsu.db");
/** Score database name. */ /** Score database name. */
public static final File SCORE_DB = new File(DATA_DIR, ".opsu_scores.db"); public static final File SCORE_DB = new File(DATA_DIR, ".opsu_scores.db");
@ -866,28 +867,28 @@ public class Options {
} }
/** /**
* Returns a dummy OsuFile containing the theme song. * Returns a dummy Beatmap containing the theme song.
* @return the theme song OsuFile * @return the theme song beatmap
*/ */
public static OsuFile getOsuTheme() { public static Beatmap getThemeBeatmap() {
String[] tokens = themeString.split(","); String[] tokens = themeString.split(",");
if (tokens.length != 4) { if (tokens.length != 4) {
ErrorHandler.error("Theme song string is malformed.", null, false); ErrorHandler.error("Theme song string is malformed.", null, false);
return null; return null;
} }
OsuFile osu = new OsuFile(null); Beatmap beatmap = new Beatmap(null);
osu.audioFilename = new File(tokens[0]); beatmap.audioFilename = new File(tokens[0]);
osu.title = tokens[1]; beatmap.title = tokens[1];
osu.artist = tokens[2]; beatmap.artist = tokens[2];
try { try {
osu.endTime = Integer.parseInt(tokens[3]); beatmap.endTime = Integer.parseInt(tokens[3]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
ErrorHandler.error("Theme song length is not a valid integer", e, false); ErrorHandler.error("Theme song length is not a valid integer", e, false);
return null; return null;
} }
return osu; return beatmap;
} }
/** /**

View File

@ -18,7 +18,12 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.db.OsuDB; import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.db.BeatmapDB;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@ -67,12 +72,12 @@ public class OsuParser {
/** /**
* Invokes parser for each OSU file in a root directory and * Invokes parser for each OSU file in a root directory and
* adds the OsuFiles to a new OsuGroupList. * adds the beatmaps to a new BeatmapSetList.
* @param root the root directory (search has depth 1) * @param root the root directory (search has depth 1)
*/ */
public static void parseAllFiles(File root) { public static void parseAllFiles(File root) {
// create a new OsuGroupList // create a new BeatmapSetList
OsuGroupList.create(); BeatmapSetList.create();
// parse all directories // parse all directories
parseDirectories(root.listFiles()); parseDirectories(root.listFiles());
@ -80,11 +85,11 @@ public class OsuParser {
/** /**
* Invokes parser for each directory in the given array and * Invokes parser for each directory in the given array and
* adds the OsuFiles to the existing OsuGroupList. * adds the beatmaps to the existing BeatmapSetList.
* @param dirs the array of directories to parse * @param dirs the array of directories to parse
* @return the last OsuGroupNode parsed, or null if none * @return the last BeatmapSetNode parsed, or null if none
*/ */
public static OsuGroupNode parseDirectories(File[] dirs) { public static BeatmapSetNode parseDirectories(File[] dirs) {
if (dirs == null) if (dirs == null)
return null; return null;
@ -94,15 +99,15 @@ public class OsuParser {
totalDirectories = dirs.length; totalDirectories = dirs.length;
// get last modified map from database // get last modified map from database
Map<String, Long> map = OsuDB.getLastModifiedMap(); Map<String, Long> map = BeatmapDB.getLastModifiedMap();
// OsuFile lists // beatmap lists
List<ArrayList<OsuFile>> allOsuFiles = new LinkedList<ArrayList<OsuFile>>(); List<ArrayList<Beatmap>> allBeatmaps = new LinkedList<ArrayList<Beatmap>>();
List<OsuFile> cachedOsuFiles = new LinkedList<OsuFile>(); // loaded from database List<Beatmap> cachedBeatmaps = new LinkedList<Beatmap>(); // loaded from database
List<OsuFile> parsedOsuFiles = new LinkedList<OsuFile>(); // loaded from parser List<Beatmap> parsedBeatmaps = new LinkedList<Beatmap>(); // loaded from parser
// parse directories // parse directories
OsuGroupNode lastNode = null; BeatmapSetNode lastNode = null;
for (File dir : dirs) { for (File dir : dirs) {
currentDirectoryIndex++; currentDirectoryIndex++;
if (!dir.isDirectory()) if (!dir.isDirectory())
@ -119,7 +124,7 @@ public class OsuParser {
continue; continue;
// create a new group entry // create a new group entry
ArrayList<OsuFile> osuFiles = new ArrayList<OsuFile>(); ArrayList<Beatmap> beatmaps = new ArrayList<Beatmap>();
for (File file : files) { for (File file : files) {
currentFile = file; currentFile = file;
@ -130,29 +135,29 @@ public class OsuParser {
long lastModified = map.get(path); long lastModified = map.get(path);
if (lastModified == file.lastModified()) { if (lastModified == file.lastModified()) {
// add to cached beatmap list // add to cached beatmap list
OsuFile osu = new OsuFile(file); Beatmap beatmap = new Beatmap(file);
osuFiles.add(osu); beatmaps.add(beatmap);
cachedOsuFiles.add(osu); cachedBeatmaps.add(beatmap);
continue; continue;
} else } else
OsuDB.delete(dir.getName(), file.getName()); BeatmapDB.delete(dir.getName(), file.getName());
} }
// Parse hit objects only when needed to save time/memory. // Parse hit objects only when needed to save time/memory.
// Change boolean to 'true' to parse them immediately. // Change boolean to 'true' to parse them immediately.
OsuFile osu = parseFile(file, dir, osuFiles, false); Beatmap beatmap = parseFile(file, dir, beatmaps, false);
// add to parsed beatmap list // add to parsed beatmap list
if (osu != null) { if (beatmap != null) {
osuFiles.add(osu); beatmaps.add(beatmap);
parsedOsuFiles.add(osu); parsedBeatmaps.add(beatmap);
} }
} }
// add group entry if non-empty // add group entry if non-empty
if (!osuFiles.isEmpty()) { if (!beatmaps.isEmpty()) {
osuFiles.trimToSize(); beatmaps.trimToSize();
allOsuFiles.add(osuFiles); allBeatmaps.add(beatmaps);
} }
// stop parsing files (interrupted) // stop parsing files (interrupted)
@ -161,27 +166,27 @@ public class OsuParser {
} }
// load cached entries from database // load cached entries from database
if (!cachedOsuFiles.isEmpty()) { if (!cachedBeatmaps.isEmpty()) {
status = Status.CACHE; status = Status.CACHE;
// Load array fields only when needed to save time/memory. // Load array fields only when needed to save time/memory.
// Change flag to 'LOAD_ALL' to load them immediately. // Change flag to 'LOAD_ALL' to load them immediately.
OsuDB.load(cachedOsuFiles, OsuDB.LOAD_NONARRAY); BeatmapDB.load(cachedBeatmaps, BeatmapDB.LOAD_NONARRAY);
} }
// add group entries to OsuGroupList // add group entries to BeatmapSetList
for (ArrayList<OsuFile> osuFiles : allOsuFiles) { for (ArrayList<Beatmap> beatmaps : allBeatmaps) {
Collections.sort(osuFiles); Collections.sort(beatmaps);
lastNode = OsuGroupList.get().addSongGroup(osuFiles); lastNode = BeatmapSetList.get().addSongGroup(beatmaps);
} }
// clear string DB // clear string DB
stringdb = new HashMap<String, String>(); stringdb = new HashMap<String, String>();
// add beatmap entries to database // add beatmap entries to database
if (!parsedOsuFiles.isEmpty()) { if (!parsedBeatmaps.isEmpty()) {
status = Status.INSERTING; status = Status.INSERTING;
OsuDB.insert(parsedOsuFiles); BeatmapDB.insert(parsedBeatmaps);
} }
status = Status.NONE; status = Status.NONE;
@ -192,16 +197,16 @@ public class OsuParser {
} }
/** /**
* Parses an OSU file. * Parses a beatmap.
* @param file the file to parse * @param file the file to parse
* @param dir the directory containing the beatmap * @param dir the directory containing the beatmap
* @param osuFiles the song group * @param beatmaps the song group
* @param parseObjects if true, hit objects will be fully parsed now * @param parseObjects if true, hit objects will be fully parsed now
* @return the new OsuFile object * @return the new beatmap
*/ */
private static OsuFile parseFile(File file, File dir, ArrayList<OsuFile> osuFiles, boolean parseObjects) { private static Beatmap parseFile(File file, File dir, ArrayList<Beatmap> beatmaps, boolean parseObjects) {
OsuFile osu = new OsuFile(file); Beatmap beatmap = new Beatmap(file);
osu.timingPoints = new ArrayList<TimingPoint>(); beatmap.timingPoints = new ArrayList<TimingPoint>();
try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) { try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
String line = in.readLine(); String line = in.readLine();
@ -226,9 +231,9 @@ public class OsuParser {
switch (tokens[0]) { switch (tokens[0]) {
case "AudioFilename": case "AudioFilename":
File audioFileName = new File(dir, tokens[1]); File audioFileName = new File(dir, tokens[1]);
if (!osuFiles.isEmpty()) { if (!beatmaps.isEmpty()) {
// if possible, reuse the same File object from another OsuFile in the group // if possible, reuse the same File object from another Beatmap in the group
File groupAudioFileName = osuFiles.get(0).audioFilename; File groupAudioFileName = beatmaps.get(0).audioFilename;
if (groupAudioFileName != null && if (groupAudioFileName != null &&
tokens[1].equalsIgnoreCase(groupAudioFileName.getName())) tokens[1].equalsIgnoreCase(groupAudioFileName.getName()))
audioFileName = groupAudioFileName; audioFileName = groupAudioFileName;
@ -248,42 +253,42 @@ public class OsuParser {
return null; return null;
} }
} }
osu.audioFilename = audioFileName; beatmap.audioFilename = audioFileName;
break; break;
case "AudioLeadIn": case "AudioLeadIn":
osu.audioLeadIn = Integer.parseInt(tokens[1]); beatmap.audioLeadIn = Integer.parseInt(tokens[1]);
break; break;
// case "AudioHash": // deprecated // case "AudioHash": // deprecated
// osu.audioHash = tokens[1]; // beatmap.audioHash = tokens[1];
// break; // break;
case "PreviewTime": case "PreviewTime":
osu.previewTime = Integer.parseInt(tokens[1]); beatmap.previewTime = Integer.parseInt(tokens[1]);
break; break;
case "Countdown": case "Countdown":
osu.countdown = Byte.parseByte(tokens[1]); beatmap.countdown = Byte.parseByte(tokens[1]);
break; break;
case "SampleSet": case "SampleSet":
osu.sampleSet = getDBString(tokens[1]); beatmap.sampleSet = getDBString(tokens[1]);
break; break;
case "StackLeniency": case "StackLeniency":
osu.stackLeniency = Float.parseFloat(tokens[1]); beatmap.stackLeniency = Float.parseFloat(tokens[1]);
break; break;
case "Mode": case "Mode":
osu.mode = Byte.parseByte(tokens[1]); beatmap.mode = Byte.parseByte(tokens[1]);
/* Non-Opsu! standard files not implemented (obviously). */ /* Non-Opsu! standard files not implemented (obviously). */
if (osu.mode != OsuFile.MODE_OSU) if (beatmap.mode != Beatmap.MODE_OSU)
return null; return null;
break; break;
case "LetterboxInBreaks": case "LetterboxInBreaks":
osu.letterboxInBreaks = (Integer.parseInt(tokens[1]) == 1); beatmap.letterboxInBreaks = (Integer.parseInt(tokens[1]) == 1);
break; break;
case "WidescreenStoryboard": case "WidescreenStoryboard":
osu.widescreenStoryboard = (Integer.parseInt(tokens[1]) == 1); beatmap.widescreenStoryboard = (Integer.parseInt(tokens[1]) == 1);
break; break;
case "EpilepsyWarning": case "EpilepsyWarning":
osu.epilepsyWarning = (Integer.parseInt(tokens[1]) == 1); beatmap.epilepsyWarning = (Integer.parseInt(tokens[1]) == 1);
default: default:
break; break;
} }
@ -307,21 +312,21 @@ public class OsuParser {
// switch (tokens[0]) { // switch (tokens[0]) {
// case "Bookmarks": // case "Bookmarks":
// String[] bookmarks = tokens[1].split(","); // String[] bookmarks = tokens[1].split(",");
// osu.bookmarks = new int[bookmarks.length]; // beatmap.bookmarks = new int[bookmarks.length];
// for (int i = 0; i < bookmarks.length; i++) // for (int i = 0; i < bookmarks.length; i++)
// osu.bookmarks[i] = Integer.parseInt(bookmarks[i]); // osu.bookmarks[i] = Integer.parseInt(bookmarks[i]);
// break; // break;
// case "DistanceSpacing": // case "DistanceSpacing":
// osu.distanceSpacing = Float.parseFloat(tokens[1]); // beatmap.distanceSpacing = Float.parseFloat(tokens[1]);
// break; // break;
// case "BeatDivisor": // case "BeatDivisor":
// osu.beatDivisor = Byte.parseByte(tokens[1]); // beatmap.beatDivisor = Byte.parseByte(tokens[1]);
// break; // break;
// case "GridSize": // case "GridSize":
// osu.gridSize = Integer.parseInt(tokens[1]); // beatmap.gridSize = Integer.parseInt(tokens[1]);
// break; // break;
// case "TimelineZoom": // case "TimelineZoom":
// osu.timelineZoom = Integer.parseInt(tokens[1]); // beatmap.timelineZoom = Integer.parseInt(tokens[1]);
// break; // break;
// default: // default:
// break; // break;
@ -344,45 +349,45 @@ public class OsuParser {
try { try {
switch (tokens[0]) { switch (tokens[0]) {
case "Title": case "Title":
osu.title = getDBString(tokens[1]); beatmap.title = getDBString(tokens[1]);
break; break;
case "TitleUnicode": case "TitleUnicode":
osu.titleUnicode = getDBString(tokens[1]); beatmap.titleUnicode = getDBString(tokens[1]);
break; break;
case "Artist": case "Artist":
osu.artist = getDBString(tokens[1]); beatmap.artist = getDBString(tokens[1]);
break; break;
case "ArtistUnicode": case "ArtistUnicode":
osu.artistUnicode = getDBString(tokens[1]); beatmap.artistUnicode = getDBString(tokens[1]);
break; break;
case "Creator": case "Creator":
osu.creator = getDBString(tokens[1]); beatmap.creator = getDBString(tokens[1]);
break; break;
case "Version": case "Version":
osu.version = getDBString(tokens[1]); beatmap.version = getDBString(tokens[1]);
break; break;
case "Source": case "Source":
osu.source = getDBString(tokens[1]); beatmap.source = getDBString(tokens[1]);
break; break;
case "Tags": case "Tags":
osu.tags = getDBString(tokens[1].toLowerCase()); beatmap.tags = getDBString(tokens[1].toLowerCase());
break; break;
case "BeatmapID": case "BeatmapID":
osu.beatmapID = Integer.parseInt(tokens[1]); beatmap.beatmapID = Integer.parseInt(tokens[1]);
break; break;
case "BeatmapSetID": case "BeatmapSetID":
osu.beatmapSetID = Integer.parseInt(tokens[1]); beatmap.beatmapSetID = Integer.parseInt(tokens[1]);
break; break;
} }
} catch (Exception e) { } catch (Exception e) {
Log.warn(String.format("Failed to read metadata '%s' for file '%s'.", Log.warn(String.format("Failed to read metadata '%s' for file '%s'.",
line, file.getAbsolutePath()), e); line, file.getAbsolutePath()), e);
} }
if (osu.beatmapSetID <= 0) { // try to determine MSID from directory name if (beatmap.beatmapSetID <= 0) { // try to determine MSID from directory name
if (dir != null && dir.isDirectory()) { if (dir != null && dir.isDirectory()) {
String dirName = dir.getName(); String dirName = dir.getName();
if (!dirName.isEmpty() && dirName.matches(DIR_MSID_PATTERN)) if (!dirName.isEmpty() && dirName.matches(DIR_MSID_PATTERN))
osu.beatmapSetID = Integer.parseInt(dirName.substring(0, dirName.indexOf(' '))); beatmap.beatmapSetID = Integer.parseInt(dirName.substring(0, dirName.indexOf(' ')));
} }
} }
} }
@ -399,22 +404,22 @@ public class OsuParser {
try { try {
switch (tokens[0]) { switch (tokens[0]) {
case "HPDrainRate": case "HPDrainRate":
osu.HPDrainRate = Float.parseFloat(tokens[1]); beatmap.HPDrainRate = Float.parseFloat(tokens[1]);
break; break;
case "CircleSize": case "CircleSize":
osu.circleSize = Float.parseFloat(tokens[1]); beatmap.circleSize = Float.parseFloat(tokens[1]);
break; break;
case "OverallDifficulty": case "OverallDifficulty":
osu.overallDifficulty = Float.parseFloat(tokens[1]); beatmap.overallDifficulty = Float.parseFloat(tokens[1]);
break; break;
case "ApproachRate": case "ApproachRate":
osu.approachRate = Float.parseFloat(tokens[1]); beatmap.approachRate = Float.parseFloat(tokens[1]);
break; break;
case "SliderMultiplier": case "SliderMultiplier":
osu.sliderMultiplier = Float.parseFloat(tokens[1]); beatmap.sliderMultiplier = Float.parseFloat(tokens[1]);
break; break;
case "SliderTickRate": case "SliderTickRate":
osu.sliderTickRate = Float.parseFloat(tokens[1]); beatmap.sliderTickRate = Float.parseFloat(tokens[1]);
break; break;
} }
} catch (Exception e) { } catch (Exception e) {
@ -422,8 +427,8 @@ public class OsuParser {
line, file.getAbsolutePath()), e); line, file.getAbsolutePath()), e);
} }
} }
if (osu.approachRate == -1f) // not in old format if (beatmap.approachRate == -1f) // not in old format
osu.approachRate = osu.overallDifficulty; beatmap.approachRate = beatmap.overallDifficulty;
break; break;
case "[Events]": case "[Events]":
while ((line = in.readLine()) != null) { while ((line = in.readLine()) != null) {
@ -438,14 +443,14 @@ public class OsuParser {
tokens[2] = tokens[2].replaceAll("^\"|\"$", ""); tokens[2] = tokens[2].replaceAll("^\"|\"$", "");
String ext = OsuParser.getExtension(tokens[2]); String ext = OsuParser.getExtension(tokens[2]);
if (ext.equals("jpg") || ext.equals("png")) if (ext.equals("jpg") || ext.equals("png"))
osu.bg = getDBString(tokens[2]); beatmap.bg = getDBString(tokens[2]);
break; break;
case "2": // break periods case "2": // break periods
try { try {
if (osu.breaks == null) // optional, create if needed if (beatmap.breaks == null) // optional, create if needed
osu.breaks = new ArrayList<Integer>(); beatmap.breaks = new ArrayList<Integer>();
osu.breaks.add(Integer.parseInt(tokens[1])); beatmap.breaks.add(Integer.parseInt(tokens[1]));
osu.breaks.add(Integer.parseInt(tokens[2])); beatmap.breaks.add(Integer.parseInt(tokens[2]));
} catch (Exception e) { } catch (Exception e) {
Log.warn(String.format("Failed to read break period '%s' for file '%s'.", Log.warn(String.format("Failed to read break period '%s' for file '%s'.",
line, file.getAbsolutePath()), e); line, file.getAbsolutePath()), e);
@ -456,8 +461,8 @@ public class OsuParser {
break; break;
} }
} }
if (osu.breaks != null) if (beatmap.breaks != null)
osu.breaks.trimToSize(); beatmap.breaks.trimToSize();
break; break;
case "[TimingPoints]": case "[TimingPoints]":
while ((line = in.readLine()) != null) { while ((line = in.readLine()) != null) {
@ -474,21 +479,21 @@ public class OsuParser {
// calculate BPM // calculate BPM
if (!timingPoint.isInherited()) { if (!timingPoint.isInherited()) {
int bpm = Math.round(60000 / timingPoint.getBeatLength()); int bpm = Math.round(60000 / timingPoint.getBeatLength());
if (osu.bpmMin == 0) if (beatmap.bpmMin == 0)
osu.bpmMin = osu.bpmMax = bpm; beatmap.bpmMin = beatmap.bpmMax = bpm;
else if (bpm < osu.bpmMin) else if (bpm < beatmap.bpmMin)
osu.bpmMin = bpm; beatmap.bpmMin = bpm;
else if (bpm > osu.bpmMax) else if (bpm > beatmap.bpmMax)
osu.bpmMax = bpm; beatmap.bpmMax = bpm;
} }
osu.timingPoints.add(timingPoint); beatmap.timingPoints.add(timingPoint);
} catch (Exception e) { } catch (Exception e) {
Log.warn(String.format("Failed to read timing point '%s' for file '%s'.", Log.warn(String.format("Failed to read timing point '%s' for file '%s'.",
line, file.getAbsolutePath()), e); line, file.getAbsolutePath()), e);
} }
} }
osu.timingPoints.trimToSize(); beatmap.timingPoints.trimToSize();
break; break;
case "[Colours]": case "[Colours]":
LinkedList<Color> colors = new LinkedList<Color>(); LinkedList<Color> colors = new LinkedList<Color>();
@ -525,7 +530,7 @@ public class OsuParser {
} }
} }
if (!colors.isEmpty()) if (!colors.isEmpty())
osu.combo = colors.toArray(new Color[colors.size()]); beatmap.combo = colors.toArray(new Color[colors.size()]);
break; break;
case "[HitObjects]": case "[HitObjects]":
int type = 0; int type = 0;
@ -540,11 +545,11 @@ public class OsuParser {
try { try {
type = Integer.parseInt(tokens[3]); type = Integer.parseInt(tokens[3]);
if ((type & OsuHitObject.TYPE_CIRCLE) > 0) if ((type & OsuHitObject.TYPE_CIRCLE) > 0)
osu.hitObjectCircle++; beatmap.hitObjectCircle++;
else if ((type & OsuHitObject.TYPE_SLIDER) > 0) else if ((type & OsuHitObject.TYPE_SLIDER) > 0)
osu.hitObjectSlider++; beatmap.hitObjectSlider++;
else //if ((type & OsuHitObject.TYPE_SPINNER) > 0) else //if ((type & OsuHitObject.TYPE_SPINNER) > 0)
osu.hitObjectSpinner++; beatmap.hitObjectSpinner++;
} catch (Exception e) { } catch (Exception e) {
Log.warn(String.format("Failed to read hit object '%s' for file '%s'.", Log.warn(String.format("Failed to read hit object '%s' for file '%s'.",
line, file.getAbsolutePath()), e); line, file.getAbsolutePath()), e);
@ -558,9 +563,9 @@ public class OsuParser {
int index = tokens[5].indexOf(':'); int index = tokens[5].indexOf(':');
if (index != -1) if (index != -1)
tokens[5] = tokens[5].substring(0, index); tokens[5] = tokens[5].substring(0, index);
osu.endTime = Integer.parseInt(tokens[5]); beatmap.endTime = Integer.parseInt(tokens[5]);
} else if (type != 0) } else if (type != 0)
osu.endTime = Integer.parseInt(tokens[2]); beatmap.endTime = Integer.parseInt(tokens[2]);
} catch (Exception e) { } catch (Exception e) {
Log.warn(String.format("Failed to read hit object end time '%s' for file '%s'.", Log.warn(String.format("Failed to read hit object end time '%s' for file '%s'.",
line, file.getAbsolutePath()), e); line, file.getAbsolutePath()), e);
@ -576,32 +581,31 @@ public class OsuParser {
} }
// no associated audio file? // no associated audio file?
if (osu.audioFilename == null) if (beatmap.audioFilename == null)
return null; return null;
// if no custom colors, use the default color scheme // if no custom colors, use the default color scheme
if (osu.combo == null) if (beatmap.combo == null)
osu.combo = Utils.DEFAULT_COMBO; beatmap.combo = Utils.DEFAULT_COMBO;
// parse hit objects now? // parse hit objects now?
if (parseObjects) if (parseObjects)
parseHitObjects(osu); parseHitObjects(beatmap);
return osu; return beatmap;
} }
/** /**
* Parses all hit objects in an OSU file. * Parses all hit objects in a beatmap.
* @param osu the OsuFile to parse * @param beatmap the beatmap to parse
*/ */
public static void parseHitObjects(OsuFile osu) { public static void parseHitObjects(Beatmap beatmap) {
if (osu.objects != null) // already parsed if (beatmap.objects != null) // already parsed
return; return;
osu.objects = new OsuHitObject[(osu.hitObjectCircle beatmap.objects = new OsuHitObject[(beatmap.hitObjectCircle + beatmap.hitObjectSlider + beatmap.hitObjectSpinner)];
+ osu.hitObjectSlider + osu.hitObjectSpinner)];
try (BufferedReader in = new BufferedReader(new FileReader(osu.getFile()))) { try (BufferedReader in = new BufferedReader(new FileReader(beatmap.getFile()))) {
String line = in.readLine(); String line = in.readLine();
while (line != null) { while (line != null) {
line = line.trim(); line = line.trim();
@ -611,7 +615,7 @@ public class OsuParser {
break; break;
} }
if (line == null) { if (line == null) {
Log.warn(String.format("No hit objects found in OsuFile '%s'.", osu.toString())); Log.warn(String.format("No hit objects found in Beatmap '%s'.", beatmap.toString()));
return; return;
} }
@ -621,7 +625,7 @@ public class OsuParser {
int objectIndex = 0; int objectIndex = 0;
boolean first = true; boolean first = true;
while ((line = in.readLine()) != null && objectIndex < osu.objects.length) { while ((line = in.readLine()) != null && objectIndex < beatmap.objects.length) {
line = line.trim(); line = line.trim();
if (!isValidLine(line)) if (!isValidLine(line))
continue; continue;
@ -643,7 +647,7 @@ public class OsuParser {
if (hitObject.isNewCombo() || first) { if (hitObject.isNewCombo() || first) {
int skip = (hitObject.isSpinner() ? 0 : 1) + hitObject.getComboSkip(); int skip = (hitObject.isSpinner() ? 0 : 1) + hitObject.getComboSkip();
for (int i = 0; i < skip; i++) { for (int i = 0; i < skip; i++) {
comboIndex = (comboIndex + 1) % osu.combo.length; comboIndex = (comboIndex + 1) % beatmap.combo.length;
comboNumber = 1; comboNumber = 1;
} }
first = false; first = false;
@ -652,14 +656,14 @@ public class OsuParser {
hitObject.setComboIndex(comboIndex); hitObject.setComboIndex(comboIndex);
hitObject.setComboNumber(comboNumber++); hitObject.setComboNumber(comboNumber++);
osu.objects[objectIndex++] = hitObject; beatmap.objects[objectIndex++] = hitObject;
} catch (Exception e) { } catch (Exception e) {
Log.warn(String.format("Failed to read hit object '%s' for OsuFile '%s'.", Log.warn(String.format("Failed to read hit object '%s' for Beatmap '%s'.",
line, osu.toString()), e); line, beatmap.toString()), e);
} }
} }
} catch (IOException e) { } catch (IOException e) {
ErrorHandler.error(String.format("Failed to read file '%s'.", osu.getFile().getAbsolutePath()), e, false); ErrorHandler.error(String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath()), e, false);
} }
} }

View File

@ -18,6 +18,9 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -25,7 +28,7 @@ import java.util.Comparator;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;
/** /**
* OsuGroupNode sorts. * BeatmapSetNode sorts.
*/ */
public enum SongSort { public enum SongSort {
TITLE (0, "Title", new TitleOrder()), TITLE (0, "Title", new TitleOrder()),
@ -41,7 +44,7 @@ public enum SongSort {
private String name; private String name;
/** The comparator for the sort. */ /** The comparator for the sort. */
private Comparator<OsuGroupNode> comparator; private Comparator<BeatmapSetNode> comparator;
/** The tab associated with the sort (displayed in Song Menu screen). */ /** The tab associated with the sort (displayed in Song Menu screen). */
private MenuButton tab; private MenuButton tab;
@ -72,60 +75,60 @@ public enum SongSort {
public static void setSort(SongSort sort) { SongSort.currentSort = sort; } public static void setSort(SongSort sort) { SongSort.currentSort = sort; }
/** /**
* Compares two OsuGroupNode objects by title. * Compares two BeatmapSetNode objects by title.
*/ */
private static class TitleOrder implements Comparator<OsuGroupNode> { private static class TitleOrder implements Comparator<BeatmapSetNode> {
@Override @Override
public int compare(OsuGroupNode v, OsuGroupNode w) { public int compare(BeatmapSetNode v, BeatmapSetNode w) {
return v.osuFiles.get(0).title.compareToIgnoreCase(w.osuFiles.get(0).title); return v.beatmaps.get(0).title.compareToIgnoreCase(w.beatmaps.get(0).title);
} }
} }
/** /**
* Compares two OsuGroupNode objects by artist. * Compares two BeatmapSetNode objects by artist.
*/ */
private static class ArtistOrder implements Comparator<OsuGroupNode> { private static class ArtistOrder implements Comparator<BeatmapSetNode> {
@Override @Override
public int compare(OsuGroupNode v, OsuGroupNode w) { public int compare(BeatmapSetNode v, BeatmapSetNode w) {
return v.osuFiles.get(0).artist.compareToIgnoreCase(w.osuFiles.get(0).artist); return v.beatmaps.get(0).artist.compareToIgnoreCase(w.beatmaps.get(0).artist);
} }
} }
/** /**
* Compares two OsuGroupNode objects by creator. * Compares two BeatmapSetNode objects by creator.
*/ */
private static class CreatorOrder implements Comparator<OsuGroupNode> { private static class CreatorOrder implements Comparator<BeatmapSetNode> {
@Override @Override
public int compare(OsuGroupNode v, OsuGroupNode w) { public int compare(BeatmapSetNode v, BeatmapSetNode w) {
return v.osuFiles.get(0).creator.compareToIgnoreCase(w.osuFiles.get(0).creator); return v.beatmaps.get(0).creator.compareToIgnoreCase(w.beatmaps.get(0).creator);
} }
} }
/** /**
* Compares two OsuGroupNode objects by BPM. * Compares two BeatmapSetNode objects by BPM.
*/ */
private static class BPMOrder implements Comparator<OsuGroupNode> { private static class BPMOrder implements Comparator<BeatmapSetNode> {
@Override @Override
public int compare(OsuGroupNode v, OsuGroupNode w) { public int compare(BeatmapSetNode v, BeatmapSetNode w) {
return Integer.compare(v.osuFiles.get(0).bpmMax, w.osuFiles.get(0).bpmMax); return Integer.compare(v.beatmaps.get(0).bpmMax, w.beatmaps.get(0).bpmMax);
} }
} }
/** /**
* Compares two OsuGroupNode objects by length. * Compares two BeatmapSetNode objects by length.
* Uses the longest beatmap in each set for comparison. * Uses the longest beatmap in each set for comparison.
*/ */
private static class LengthOrder implements Comparator<OsuGroupNode> { private static class LengthOrder implements Comparator<BeatmapSetNode> {
@Override @Override
public int compare(OsuGroupNode v, OsuGroupNode w) { public int compare(BeatmapSetNode v, BeatmapSetNode w) {
int vMax = 0, wMax = 0; int vMax = 0, wMax = 0;
for (OsuFile osu : v.osuFiles) { for (Beatmap beatmap : v.beatmaps) {
if (osu.endTime > vMax) if (beatmap.endTime > vMax)
vMax = osu.endTime; vMax = beatmap.endTime;
} }
for (OsuFile osu : w.osuFiles) { for (Beatmap beatmap : w.beatmaps) {
if (osu.endTime > wMax) if (beatmap.endTime > wMax)
wMax = osu.endTime; wMax = beatmap.endTime;
} }
return Integer.compare(vMax, wMax); return Integer.compare(vMax, wMax);
} }
@ -137,7 +140,7 @@ public enum SongSort {
* @param name the sort name * @param name the sort name
* @param comparator the comparator for the sort * @param comparator the comparator for the sort
*/ */
SongSort(int id, String name, Comparator<OsuGroupNode> comparator) { SongSort(int id, String name, Comparator<BeatmapSetNode> comparator) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.comparator = comparator; this.comparator = comparator;
@ -167,7 +170,7 @@ public enum SongSort {
* Returns the comparator for the sort. * Returns the comparator for the sort.
* @return the comparator * @return the comparator
*/ */
public Comparator<OsuGroupNode> getComparator() { return comparator; } public Comparator<BeatmapSetNode> getComparator() { return comparator; }
/** /**
* Checks if the coordinates are within the image bounds. * Checks if the coordinates are within the image bounds.

View File

@ -483,7 +483,7 @@ public class UI {
} }
/** /**
* Draws loading progress (OSZ unpacking, OsuFile parsing, sound loading) * Draws loading progress (OSZ unpacking, beatmap parsing, sound loading)
* at the bottom of the screen. * at the bottom of the screen.
*/ */
public static void drawLoadingProgress(Graphics g) { public static void drawLoadingProgress(Graphics g) {

View File

@ -20,6 +20,7 @@ package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import itdelatrisu.opsu.downloads.Download; import itdelatrisu.opsu.downloads.Download;
import itdelatrisu.opsu.downloads.DownloadNode; import itdelatrisu.opsu.downloads.DownloadNode;
import itdelatrisu.opsu.replay.PlaybackSpeed; import itdelatrisu.opsu.replay.PlaybackSpeed;

View File

@ -20,8 +20,8 @@ package itdelatrisu.opsu.audio;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.beatmap.Beatmap;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -50,8 +50,8 @@ public class MusicController {
/** The current music track. */ /** The current music track. */
private static Music player; private static Music player;
/** The last OsuFile passed to play(). */ /** The last beatmap passed to play(). */
private static OsuFile lastOsu; private static Beatmap lastBeatmap;
/** The track duration. */ /** The track duration. */
private static int duration = 0; private static int duration = 0;
@ -80,23 +80,23 @@ public class MusicController {
/** /**
* Plays an audio file at the preview position. * Plays an audio file at the preview position.
* If the audio file is already playing, then nothing will happen. * If the audio file is already playing, then nothing will happen.
* @param osu the OsuFile to play * @param beatmap the beatmap to play
* @param loop whether or not to loop the track * @param loop whether or not to loop the track
* @param preview whether to start at the preview time (true) or beginning (false) * @param preview whether to start at the preview time (true) or beginning (false)
*/ */
public static void play(final OsuFile osu, final boolean loop, final boolean preview) { public static void play(final Beatmap beatmap, final boolean loop, final boolean preview) {
// new track: load and play // new track: load and play
if (lastOsu == null || !osu.audioFilename.equals(lastOsu.audioFilename)) { if (lastBeatmap == null || !beatmap.audioFilename.equals(lastBeatmap.audioFilename)) {
reset(); reset();
System.gc(); System.gc();
switch (OsuParser.getExtension(osu.audioFilename.getName())) { switch (OsuParser.getExtension(beatmap.audioFilename.getName())) {
case "ogg": case "ogg":
case "mp3": case "mp3":
trackLoader = new Thread() { trackLoader = new Thread() {
@Override @Override
public void run() { public void run() {
loadTrack(osu.audioFilename, (preview) ? osu.previewTime : 0, loop); loadTrack(beatmap.audioFilename, (preview) ? beatmap.previewTime : 0, loop);
} }
}; };
trackLoader.start(); trackLoader.start();
@ -107,10 +107,10 @@ public class MusicController {
} }
// new track position: play at position // new track position: play at position
else if (osu.previewTime != lastOsu.previewTime) else if (beatmap.previewTime != lastBeatmap.previewTime)
playAt(osu.previewTime, loop); playAt(beatmap.previewTime, loop);
lastOsu = osu; lastBeatmap = beatmap;
} }
/** /**
@ -170,9 +170,9 @@ public class MusicController {
public static boolean trackExists() { return (player != null); } public static boolean trackExists() { return (player != null); }
/** /**
* Returns the OsuFile associated with the current track. * Returns the beatmap associated with the current track.
*/ */
public static OsuFile getOsuFile() { return lastOsu; } public static Beatmap getBeatmap() { return lastBeatmap; }
/** /**
* Returns true if the current track is playing. * Returns true if the current track is playing.
@ -251,17 +251,17 @@ public class MusicController {
* Returns the duration of the current track, in milliseconds. * Returns the duration of the current track, in milliseconds.
* Currently only works for MP3s. * Currently only works for MP3s.
* @return the duration, or -1 if no track exists, else the {@code endTime} * @return the duration, or -1 if no track exists, else the {@code endTime}
* field of the OsuFile loaded * field of the beatmap loaded
* @author Tom Brito (http://stackoverflow.com/a/3056161) * @author Tom Brito (http://stackoverflow.com/a/3056161)
*/ */
public static int getDuration() { public static int getDuration() {
if (!trackExists() || lastOsu == null) if (!trackExists() || lastBeatmap == null)
return -1; return -1;
if (duration == 0) { if (duration == 0) {
if (lastOsu.audioFilename.getName().endsWith(".mp3")) { if (lastBeatmap.audioFilename.getName().endsWith(".mp3")) {
try { try {
AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(lastOsu.audioFilename); AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(lastBeatmap.audioFilename);
if (fileFormat instanceof TAudioFileFormat) { if (fileFormat instanceof TAudioFileFormat) {
Map<?, ?> properties = ((TAudioFileFormat) fileFormat).properties(); Map<?, ?> properties = ((TAudioFileFormat) fileFormat).properties();
Long microseconds = (Long) properties.get("duration"); Long microseconds = (Long) properties.get("duration");
@ -270,7 +270,7 @@ public class MusicController {
} }
} catch (UnsupportedAudioFileException | IOException e) {} } catch (UnsupportedAudioFileException | IOException e) {}
} }
duration = lastOsu.endTime; duration = lastBeatmap.endTime;
} }
return duration; return duration;
} }
@ -316,16 +316,16 @@ public class MusicController {
*/ */
public static void loopTrackIfEnded(boolean preview) { public static void loopTrackIfEnded(boolean preview) {
if (trackEnded && trackExists()) if (trackEnded && trackExists())
playAt((preview) ? lastOsu.previewTime : 0, false); playAt((preview) ? lastBeatmap.previewTime : 0, false);
} }
/** /**
* Plays the theme song. * Plays the theme song.
*/ */
public static void playThemeSong() { public static void playThemeSong() {
OsuFile osu = Options.getOsuTheme(); Beatmap beatmap = Options.getThemeBeatmap();
if (osu != null) { if (beatmap != null) {
play(osu, true, false); play(beatmap, true, false);
themePlaying = true; themePlaying = true;
} }
} }
@ -376,7 +376,7 @@ public class MusicController {
trackLoader = null; trackLoader = null;
// reset state // reset state
lastOsu = null; lastBeatmap = null;
duration = 0; duration = 0;
trackEnded = false; trackEnded = false;
themePlaying = false; themePlaying = false;

View File

@ -20,8 +20,8 @@ package itdelatrisu.opsu.audio;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.audio.HitSound.SampleSet; import itdelatrisu.opsu.audio.HitSound.SampleSet;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View File

@ -16,7 +16,10 @@
* along with opsu!. If not, see <http://www.gnu.org/licenses/>. * along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/ */
package itdelatrisu.opsu; package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -29,19 +32,19 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
/** /**
* Data type storing parsed data from OSU files. * Beatmap structure storing data parsed from OSU files.
*/ */
public class OsuFile implements Comparable<OsuFile> { public class Beatmap implements Comparable<Beatmap> {
/** Game modes. */ /** Game modes. */
public static final byte MODE_OSU = 0, MODE_TAIKO = 1, MODE_CTB = 2, MODE_MANIA = 3; public static final byte MODE_OSU = 0, MODE_TAIKO = 1, MODE_CTB = 2, MODE_MANIA = 3;
/** Map of all loaded background images. */ /** Map of all loaded background images. */
private static HashMap<OsuFile, Image> bgImageMap = new HashMap<OsuFile, Image>(); private static HashMap<Beatmap, Image> bgImageMap = new HashMap<Beatmap, Image>();
/** Maximum number of cached images before all get erased. */ /** Maximum number of cached images before all get erased. */
private static final int MAX_CACHE_SIZE = 10; private static final int MAX_CACHE_SIZE = 10;
/** The OSU File object associated with this OsuFile. */ /** The OSU File object associated with this beatmap. */
private File file; private File file;
/** /**
@ -217,14 +220,14 @@ public class OsuFile implements Comparable<OsuFile> {
* This does NOT destroy images, so be careful of memory leaks! * This does NOT destroy images, so be careful of memory leaks!
*/ */
public static void resetImageCache() { public static void resetImageCache() {
bgImageMap = new HashMap<OsuFile, Image>(); bgImageMap = new HashMap<Beatmap, Image>();
} }
/** /**
* Constructor. * Constructor.
* @param file the file associated with this OsuFile * @param file the file associated with this beatmap
*/ */
public OsuFile(File file) { public Beatmap(File file) {
this.file = file; this.file = file;
} }
@ -253,7 +256,7 @@ public class OsuFile implements Comparable<OsuFile> {
} }
/** /**
* Draws the background associated with the OsuFile. * Draws the beatmap background.
* @param width the container width * @param width the container width
* @param height the container height * @param height the container height
* @param alpha the alpha value * @param alpha the alpha value
@ -300,10 +303,10 @@ public class OsuFile implements Comparable<OsuFile> {
} }
/** /**
* Compares two OsuFile objects first by overall difficulty, then by total objects. * Compares two Beatmap objects first by overall difficulty, then by total objects.
*/ */
@Override @Override
public int compareTo(OsuFile that) { public int compareTo(Beatmap that) {
int cmp = Float.compare(this.overallDifficulty, that.overallDifficulty); int cmp = Float.compare(this.overallDifficulty, that.overallDifficulty);
if (cmp == 0) if (cmp == 0)
cmp = Integer.compare( cmp = Integer.compare(

View File

@ -16,10 +16,13 @@
* along with opsu!. If not, see <http://www.gnu.org/licenses/>. * along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/ */
package itdelatrisu.opsu; package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.SongSort;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.db.OsuDB; import itdelatrisu.opsu.db.BeatmapDB;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -35,9 +38,9 @@ import java.util.regex.Pattern;
/** /**
* Indexed, expanding, doubly-linked list data type for song groups. * Indexed, expanding, doubly-linked list data type for song groups.
*/ */
public class OsuGroupList { public class BeatmapSetList {
/** Song group structure (each group contains of an ArrayList of OsuFiles). */ /** Song group structure (each group contains a list of beatmaps). */
private static OsuGroupList list; private static BeatmapSetList list;
/** Search pattern for conditional expressions. */ /** Search pattern for conditional expressions. */
private static final Pattern SEARCH_CONDITION_PATTERN = Pattern.compile( private static final Pattern SEARCH_CONDITION_PATTERN = Pattern.compile(
@ -45,13 +48,13 @@ public class OsuGroupList {
); );
/** List containing all parsed nodes. */ /** List containing all parsed nodes. */
private ArrayList<OsuGroupNode> parsedNodes; private ArrayList<BeatmapSetNode> parsedNodes;
/** Total number of beatmaps (i.e. OsuFile objects). */ /** Total number of beatmaps (i.e. Beatmap objects). */
private int mapCount = 0; private int mapCount = 0;
/** Current list of nodes (subset of parsedNodes, used for searches). */ /** Current list of nodes (subset of parsedNodes, used for searches). */
private ArrayList<OsuGroupNode> nodes; private ArrayList<BeatmapSetNode> nodes;
/** Set of all beatmap set IDs for the parsed beatmaps. */ /** Set of all beatmap set IDs for the parsed beatmaps. */
private HashSet<Integer> MSIDdb; private HashSet<Integer> MSIDdb;
@ -60,7 +63,7 @@ public class OsuGroupList {
private int expandedIndex; private int expandedIndex;
/** Start and end nodes of expanded group. */ /** Start and end nodes of expanded group. */
private OsuGroupNode expandedStartNode, expandedEndNode; private BeatmapSetNode expandedStartNode, expandedEndNode;
/** The last search query. */ /** The last search query. */
private String lastQuery; private String lastQuery;
@ -68,18 +71,18 @@ public class OsuGroupList {
/** /**
* Creates a new instance of this class (overwriting any previous instance). * Creates a new instance of this class (overwriting any previous instance).
*/ */
public static void create() { list = new OsuGroupList(); } public static void create() { list = new BeatmapSetList(); }
/** /**
* Returns the single instance of this class. * Returns the single instance of this class.
*/ */
public static OsuGroupList get() { return list; } public static BeatmapSetList get() { return list; }
/** /**
* Constructor. * Constructor.
*/ */
private OsuGroupList() { private BeatmapSetList() {
parsedNodes = new ArrayList<OsuGroupNode>(); parsedNodes = new ArrayList<BeatmapSetNode>();
MSIDdb = new HashSet<Integer>(); MSIDdb = new HashSet<Integer>();
reset(); reset();
} }
@ -102,16 +105,16 @@ public class OsuGroupList {
/** /**
* Adds a song group. * Adds a song group.
* @param osuFiles the list of OsuFile objects in the group * @param beatmaps the list of beatmaps in the group
* @return the new OsuGroupNode * @return the new BeatmapSetNode
*/ */
public OsuGroupNode addSongGroup(ArrayList<OsuFile> osuFiles) { public BeatmapSetNode addSongGroup(ArrayList<Beatmap> beatmaps) {
OsuGroupNode node = new OsuGroupNode(osuFiles); BeatmapSetNode node = new BeatmapSetNode(beatmaps);
parsedNodes.add(node); parsedNodes.add(node);
mapCount += osuFiles.size(); mapCount += beatmaps.size();
// add beatmap set ID to set // add beatmap set ID to set
int msid = osuFiles.get(0).beatmapSetID; int msid = beatmaps.get(0).beatmapSetID;
if (msid > 0) if (msid > 0)
MSIDdb.add(msid); MSIDdb.add(msid);
@ -124,13 +127,13 @@ public class OsuGroupList {
* @param node the node containing the song group to delete * @param node the node containing the song group to delete
* @return true if the song group was deleted, false otherwise * @return true if the song group was deleted, false otherwise
*/ */
public boolean deleteSongGroup(OsuGroupNode node) { public boolean deleteSongGroup(BeatmapSetNode node) {
if (node == null) if (node == null)
return false; return false;
// re-link base nodes // re-link base nodes
int index = node.index; int index = node.index;
OsuGroupNode ePrev = getBaseNode(index - 1), eCur = getBaseNode(index), eNext = getBaseNode(index + 1); BeatmapSetNode ePrev = getBaseNode(index - 1), eCur = getBaseNode(index), eNext = getBaseNode(index + 1);
if (ePrev != null) { if (ePrev != null) {
if (ePrev.index == expandedIndex) if (ePrev.index == expandedIndex)
expandedEndNode.next = eNext; expandedEndNode.next = eNext;
@ -149,12 +152,12 @@ public class OsuGroupList {
} }
// remove all node references // remove all node references
OsuFile osu = node.osuFiles.get(0); Beatmap beatmap = node.beatmaps.get(0);
nodes.remove(index); nodes.remove(index);
parsedNodes.remove(eCur); parsedNodes.remove(eCur);
mapCount -= node.osuFiles.size(); mapCount -= node.beatmaps.size();
if (osu.beatmapSetID > 0) if (beatmap.beatmapSetID > 0)
MSIDdb.remove(osu.beatmapSetID); MSIDdb.remove(beatmap.beatmapSetID);
// reset indices // reset indices
for (int i = index, size = size(); i < size; i++) for (int i = index, size = size(); i < size; i++)
@ -164,25 +167,25 @@ public class OsuGroupList {
expandedStartNode = expandedEndNode = null; expandedStartNode = expandedEndNode = null;
} else if (expandedIndex > index) { } else if (expandedIndex > index) {
expandedIndex--; expandedIndex--;
OsuGroupNode expandedNode = expandedStartNode; BeatmapSetNode expandedNode = expandedStartNode;
for (int i = 0, size = expandedNode.osuFiles.size(); for (int i = 0, size = expandedNode.beatmaps.size();
i < size && expandedNode != null; i < size && expandedNode != null;
i++, expandedNode = expandedNode.next) i++, expandedNode = expandedNode.next)
expandedNode.index = expandedIndex; expandedNode.index = expandedIndex;
} }
// stop playing the track // stop playing the track
File dir = osu.getFile().getParentFile(); File dir = beatmap.getFile().getParentFile();
if (MusicController.trackExists() || MusicController.isTrackLoading()) { if (MusicController.trackExists() || MusicController.isTrackLoading()) {
File audioFile = MusicController.getOsuFile().audioFilename; File audioFile = MusicController.getBeatmap().audioFilename;
if (audioFile != null && audioFile.equals(osu.audioFilename)) { if (audioFile != null && audioFile.equals(beatmap.audioFilename)) {
MusicController.reset(); MusicController.reset();
System.gc(); // TODO: why can't files be deleted without calling this? System.gc(); // TODO: why can't files be deleted without calling this?
} }
} }
// remove entry from cache // remove entry from cache
OsuDB.delete(dir.getName()); BeatmapDB.delete(dir.getName());
// delete the associated directory // delete the associated directory
try { try {
@ -200,26 +203,26 @@ public class OsuGroupList {
* beatmap directory will be deleted altogether. * beatmap directory will be deleted altogether.
* @param node the node containing the song group to delete (expanded only) * @param node the node containing the song group to delete (expanded only)
* @return true if the song or song group was deleted, false otherwise * @return true if the song or song group was deleted, false otherwise
* @see #deleteSongGroup(OsuGroupNode) * @see #deleteSongGroup(BeatmapSetNode)
*/ */
public boolean deleteSong(OsuGroupNode node) { public boolean deleteSong(BeatmapSetNode node) {
if (node == null || node.osuFileIndex == -1 || node.index != expandedIndex) if (node == null || node.beatmapIndex == -1 || node.index != expandedIndex)
return false; return false;
// last song in group? // last song in group?
int size = node.osuFiles.size(); int size = node.beatmaps.size();
if (node.osuFiles.size() == 1) if (node.beatmaps.size() == 1)
return deleteSongGroup(node); return deleteSongGroup(node);
// reset indices // reset indices
OsuGroupNode expandedNode = node.next; BeatmapSetNode expandedNode = node.next;
for (int i = node.osuFileIndex + 1; for (int i = node.beatmapIndex + 1;
i < size && expandedNode != null && expandedNode.index == node.index; i < size && expandedNode != null && expandedNode.index == node.index;
i++, expandedNode = expandedNode.next) i++, expandedNode = expandedNode.next)
expandedNode.osuFileIndex--; expandedNode.beatmapIndex--;
// remove song reference // remove song reference
OsuFile osu = node.osuFiles.remove(node.osuFileIndex); Beatmap beatmap = node.beatmaps.remove(node.beatmapIndex);
mapCount--; mapCount--;
// re-link nodes // re-link nodes
@ -229,8 +232,8 @@ public class OsuGroupList {
node.next.prev = node.prev; node.next.prev = node.prev;
// remove entry from cache // remove entry from cache
File file = osu.getFile(); File file = beatmap.getFile();
OsuDB.delete(file.getParentFile().getName(), file.getName()); BeatmapDB.delete(file.getParentFile().getName(), file.getName());
// delete the associated file // delete the associated file
try { try {
@ -243,7 +246,7 @@ public class OsuGroupList {
} }
/** /**
* Returns the total number of parsed maps (i.e. OsuFile objects). * Returns the total number of parsed maps (i.e. Beatmap objects).
*/ */
public int getMapCount() { return mapCount; } public int getMapCount() { return mapCount; }
@ -253,10 +256,10 @@ public class OsuGroupList {
public int getMapSetCount() { return parsedNodes.size(); } public int getMapSetCount() { return parsedNodes.size(); }
/** /**
* Returns the OsuGroupNode at an index, disregarding expansions. * Returns the BeatmapSetNode at an index, disregarding expansions.
* @param index the node index * @param index the node index
*/ */
public OsuGroupNode getBaseNode(int index) { public BeatmapSetNode getBaseNode(int index) {
if (index < 0 || index >= size()) if (index < 0 || index >= size())
return null; return null;
@ -266,20 +269,20 @@ public class OsuGroupList {
/** /**
* Returns a random base node. * Returns a random base node.
*/ */
public OsuGroupNode getRandomNode() { public BeatmapSetNode getRandomNode() {
OsuGroupNode node = getBaseNode((int) (Math.random() * size())); BeatmapSetNode node = getBaseNode((int) (Math.random() * size()));
if (node != null && node.index == expandedIndex) // don't choose an expanded group node if (node != null && node.index == expandedIndex) // don't choose an expanded group node
node = node.next; node = node.next;
return node; return node;
} }
/** /**
* Returns the OsuGroupNode a given number of positions forward or backwards. * Returns the BeatmapSetNode a given number of positions forward or backwards.
* @param node the starting node * @param node the starting node
* @param shift the number of nodes to shift forward (+) or backward (-). * @param shift the number of nodes to shift forward (+) or backward (-).
*/ */
public OsuGroupNode getNode(OsuGroupNode node, int shift) { public BeatmapSetNode getNode(BeatmapSetNode node, int shift) {
OsuGroupNode startNode = node; BeatmapSetNode startNode = node;
if (shift > 0) { if (shift > 0) {
for (int i = 0; i < shift && startNode != null; i++) for (int i = 0; i < shift && startNode != null; i++)
startNode = startNode.next; startNode = startNode.next;
@ -296,28 +299,28 @@ public class OsuGroupList {
public int getExpandedIndex() { return expandedIndex; } public int getExpandedIndex() { return expandedIndex; }
/** /**
* Expands the node at an index by inserting a new node for each OsuFile * Expands the node at an index by inserting a new node for each Beatmap
* in that node and hiding the group node. * in that node and hiding the group node.
* @return the first of the newly-inserted nodes * @return the first of the newly-inserted nodes
*/ */
public OsuGroupNode expand(int index) { public BeatmapSetNode expand(int index) {
// undo the previous expansion // undo the previous expansion
unexpand(); unexpand();
OsuGroupNode node = getBaseNode(index); BeatmapSetNode node = getBaseNode(index);
if (node == null) if (node == null)
return null; return null;
expandedStartNode = expandedEndNode = null; expandedStartNode = expandedEndNode = null;
// create new nodes // create new nodes
ArrayList<OsuFile> osuFiles = node.osuFiles; ArrayList<Beatmap> beatmaps = node.beatmaps;
OsuGroupNode prevNode = node.prev; BeatmapSetNode prevNode = node.prev;
OsuGroupNode nextNode = node.next; BeatmapSetNode nextNode = node.next;
for (int i = 0, size = node.osuFiles.size(); i < size; i++) { for (int i = 0, size = node.beatmaps.size(); i < size; i++) {
OsuGroupNode newNode = new OsuGroupNode(osuFiles); BeatmapSetNode newNode = new BeatmapSetNode(beatmaps);
newNode.index = index; newNode.index = index;
newNode.osuFileIndex = i; newNode.beatmapIndex = i;
newNode.prev = node; newNode.prev = node;
// unlink the group node // unlink the group node
@ -349,7 +352,7 @@ public class OsuGroupList {
return; return;
// recreate surrounding links // recreate surrounding links
OsuGroupNode BeatmapSetNode
ePrev = getBaseNode(expandedIndex - 1), ePrev = getBaseNode(expandedIndex - 1),
eCur = getBaseNode(expandedIndex), eCur = getBaseNode(expandedIndex),
eNext = getBaseNode(expandedIndex + 1); eNext = getBaseNode(expandedIndex + 1);
@ -379,11 +382,11 @@ public class OsuGroupList {
expandedStartNode = expandedEndNode = null; expandedStartNode = expandedEndNode = null;
// create links // create links
OsuGroupNode lastNode = nodes.get(0); BeatmapSetNode lastNode = nodes.get(0);
lastNode.index = 0; lastNode.index = 0;
lastNode.prev = null; lastNode.prev = null;
for (int i = 1, size = size(); i < size; i++) { for (int i = 1, size = size(); i < size; i++) {
OsuGroupNode node = nodes.get(i); BeatmapSetNode node = nodes.get(i);
lastNode.next = node; lastNode.next = node;
node.index = i; node.index = i;
node.prev = lastNode; node.prev = lastNode;
@ -433,20 +436,20 @@ public class OsuGroupList {
} }
// build an initial list from first search term // build an initial list from first search term
nodes = new ArrayList<OsuGroupNode>(); nodes = new ArrayList<BeatmapSetNode>();
if (terms.isEmpty()) { if (terms.isEmpty()) {
// conditional term // conditional term
String type = condType.remove(); String type = condType.remove();
String operator = condOperator.remove(); String operator = condOperator.remove();
float value = condValue.remove(); float value = condValue.remove();
for (OsuGroupNode node : parsedNodes) { for (BeatmapSetNode node : parsedNodes) {
if (node.matches(type, operator, value)) if (node.matches(type, operator, value))
nodes.add(node); nodes.add(node);
} }
} else { } else {
// normal term // normal term
String term = terms.remove(); String term = terms.remove();
for (OsuGroupNode node : parsedNodes) { for (BeatmapSetNode node : parsedNodes) {
if (node.matches(term)) if (node.matches(term))
nodes.add(node); nodes.add(node);
} }
@ -460,9 +463,9 @@ public class OsuGroupList {
String term = terms.remove(); String term = terms.remove();
// remove nodes from list if they don't match all terms // remove nodes from list if they don't match all terms
Iterator<OsuGroupNode> nodeIter = nodes.iterator(); Iterator<BeatmapSetNode> nodeIter = nodes.iterator();
while (nodeIter.hasNext()) { while (nodeIter.hasNext()) {
OsuGroupNode node = nodeIter.next(); BeatmapSetNode node = nodeIter.next();
if (!node.matches(term)) if (!node.matches(term))
nodeIter.remove(); nodeIter.remove();
} }
@ -478,9 +481,9 @@ public class OsuGroupList {
float value = condValue.remove(); float value = condValue.remove();
// remove nodes from list if they don't match all terms // remove nodes from list if they don't match all terms
Iterator<OsuGroupNode> nodeIter = nodes.iterator(); Iterator<BeatmapSetNode> nodeIter = nodes.iterator();
while (nodeIter.hasNext()) { while (nodeIter.hasNext()) {
OsuGroupNode node = nodeIter.next(); BeatmapSetNode node = nodeIter.next();
if (!node.matches(type, operator, value)) if (!node.matches(type, operator, value))
nodeIter.remove(); nodeIter.remove();
} }

View File

@ -16,9 +16,13 @@
* along with opsu!. If not, see <http://www.gnu.org/licenses/>. * along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/ */
package itdelatrisu.opsu; package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.GameData.Grade; import itdelatrisu.opsu.GameData.Grade;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -27,27 +31,27 @@ import org.newdawn.slick.Color;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;
/** /**
* Node in an OsuGroupList representing a group of OsuFile objects. * Node in an BeatmapSetList representing a group of beatmaps.
*/ */
public class OsuGroupNode { public class BeatmapSetNode {
/** List of associated OsuFile objects. */ /** List of associated beatmaps. */
public ArrayList<OsuFile> osuFiles; public ArrayList<Beatmap> beatmaps;
/** Index of this OsuGroupNode. */ /** Index of this node. */
public int index = 0; public int index = 0;
/** Index of selected osuFile (-1 if not focused). */ /** Index of the selected beatmap (-1 if not focused). */
public int osuFileIndex = -1; public int beatmapIndex = -1;
/** Links to other OsuGroupNode objects. */ /** Links to other nodes. */
public OsuGroupNode prev, next; public BeatmapSetNode prev, next;
/** /**
* Constructor. * Constructor.
* @param osuFiles the OsuFile objects in this group * @param beatmaps the beatmaps in this group
*/ */
public OsuGroupNode(ArrayList<OsuFile> osuFiles) { public BeatmapSetNode(ArrayList<Beatmap> beatmaps) {
this.osuFiles = osuFiles; this.beatmaps = beatmaps;
} }
/** /**
@ -59,8 +63,8 @@ public class OsuGroupNode {
*/ */
public void draw(float x, float y, Grade grade, boolean focus) { public void draw(float x, float y, Grade grade, boolean focus) {
Image bg = GameImage.MENU_BUTTON_BG.getImage(); Image bg = GameImage.MENU_BUTTON_BG.getImage();
boolean expanded = (osuFileIndex > -1); boolean expanded = (beatmapIndex > -1);
OsuFile osu; Beatmap beatmap;
bg.setAlpha(0.9f); bg.setAlpha(0.9f);
Color bgColor; Color bgColor;
Color textColor = Color.lightGray; Color textColor = Color.lightGray;
@ -73,10 +77,10 @@ public class OsuGroupNode {
textColor = Color.white; textColor = Color.white;
} else } else
bgColor = Utils.COLOR_BLUE_BUTTON; bgColor = Utils.COLOR_BLUE_BUTTON;
osu = osuFiles.get(osuFileIndex); beatmap = beatmaps.get(beatmapIndex);
} else { } else {
bgColor = Utils.COLOR_ORANGE_BUTTON; bgColor = Utils.COLOR_ORANGE_BUTTON;
osu = osuFiles.get(0); beatmap = beatmaps.get(0);
} }
bg.draw(x, y, bgColor); bg.draw(x, y, bgColor);
@ -92,15 +96,15 @@ public class OsuGroupNode {
// draw text // draw text
if (Options.useUnicodeMetadata()) { // load glyphs if (Options.useUnicodeMetadata()) { // load glyphs
Utils.loadGlyphs(Utils.FONT_MEDIUM, osu.titleUnicode, null); Utils.loadGlyphs(Utils.FONT_MEDIUM, beatmap.titleUnicode, null);
Utils.loadGlyphs(Utils.FONT_DEFAULT, null, osu.artistUnicode); Utils.loadGlyphs(Utils.FONT_DEFAULT, null, beatmap.artistUnicode);
} }
Utils.FONT_MEDIUM.drawString(cx, cy, osu.getTitle(), textColor); Utils.FONT_MEDIUM.drawString(cx, cy, beatmap.getTitle(), textColor);
Utils.FONT_DEFAULT.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() - 2, Utils.FONT_DEFAULT.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() - 2,
String.format("%s // %s", osu.getArtist(), osu.creator), textColor); String.format("%s // %s", beatmap.getArtist(), beatmap.creator), textColor);
if (expanded || osuFiles.size() == 1) if (expanded || beatmaps.size() == 1)
Utils.FONT_BOLD.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() + Utils.FONT_DEFAULT.getLineHeight() - 4, Utils.FONT_BOLD.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() + Utils.FONT_DEFAULT.getLineHeight() - 4,
osu.version, textColor); beatmap.version, textColor);
} }
/** /**
@ -114,45 +118,45 @@ public class OsuGroupNode {
* </ul> * </ul>
*/ */
public String[] getInfo() { public String[] getInfo() {
if (osuFileIndex < 0) if (beatmapIndex < 0)
return null; return null;
OsuFile osu = osuFiles.get(osuFileIndex); Beatmap beatmap = beatmaps.get(beatmapIndex);
float speedModifier = GameMod.getSpeedMultiplier(); float speedModifier = GameMod.getSpeedMultiplier();
long endTime = (long) (osu.endTime / speedModifier); long endTime = (long) (beatmap.endTime / speedModifier);
int bpmMin = (int) (osu.bpmMin * speedModifier); int bpmMin = (int) (beatmap.bpmMin * speedModifier);
int bpmMax = (int) (osu.bpmMax * speedModifier); int bpmMax = (int) (beatmap.bpmMax * speedModifier);
float multiplier = GameMod.getDifficultyMultiplier(); float multiplier = GameMod.getDifficultyMultiplier();
String[] info = new String[5]; String[] info = new String[5];
info[0] = osu.toString(); info[0] = beatmap.toString();
info[1] = String.format("Mapped by %s", osu.creator); info[1] = String.format("Mapped by %s", beatmap.creator);
info[2] = String.format("Length: %d:%02d BPM: %s Objects: %d", info[2] = String.format("Length: %d:%02d BPM: %s Objects: %d",
TimeUnit.MILLISECONDS.toMinutes(endTime), TimeUnit.MILLISECONDS.toMinutes(endTime),
TimeUnit.MILLISECONDS.toSeconds(endTime) - TimeUnit.MILLISECONDS.toSeconds(endTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(endTime)), TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(endTime)),
(bpmMax <= 0) ? "--" : ((bpmMin == bpmMax) ? bpmMin : String.format("%d-%d", bpmMin, bpmMax)), (bpmMax <= 0) ? "--" : ((bpmMin == bpmMax) ? bpmMin : String.format("%d-%d", bpmMin, bpmMax)),
(osu.hitObjectCircle + osu.hitObjectSlider + osu.hitObjectSpinner)); (beatmap.hitObjectCircle + beatmap.hitObjectSlider + beatmap.hitObjectSpinner));
info[3] = String.format("Circles: %d Sliders: %d Spinners: %d", info[3] = String.format("Circles: %d Sliders: %d Spinners: %d",
osu.hitObjectCircle, osu.hitObjectSlider, osu.hitObjectSpinner); beatmap.hitObjectCircle, beatmap.hitObjectSlider, beatmap.hitObjectSpinner);
info[4] = String.format("CS:%.1f HP:%.1f AR:%.1f OD:%.1f", info[4] = String.format("CS:%.1f HP:%.1f AR:%.1f OD:%.1f",
Math.min(osu.circleSize * multiplier, 10f), Math.min(beatmap.circleSize * multiplier, 10f),
Math.min(osu.HPDrainRate * multiplier, 10f), Math.min(beatmap.HPDrainRate * multiplier, 10f),
Math.min(osu.approachRate * multiplier, 10f), Math.min(beatmap.approachRate * multiplier, 10f),
Math.min(osu.overallDifficulty * multiplier, 10f)); Math.min(beatmap.overallDifficulty * multiplier, 10f));
return info; return info;
} }
/** /**
* Returns a formatted string for the OsuFile at osuFileIndex: * Returns a formatted string for the beatmap at {@code beatmapIndex}:
* "Artist - Title [Version]" (version omitted if osuFileIndex is invalid) * "Artist - Title [Version]" (version omitted if {@code beatmapIndex} is invalid)
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
@Override @Override
public String toString() { public String toString() {
if (osuFileIndex == -1) if (beatmapIndex == -1)
return String.format("%s - %s", osuFiles.get(0).getArtist(), osuFiles.get(0).getTitle()); return String.format("%s - %s", beatmaps.get(0).getArtist(), beatmaps.get(0).getTitle());
else else
return osuFiles.get(osuFileIndex).toString(); return beatmaps.get(beatmapIndex).toString();
} }
/** /**
@ -161,24 +165,24 @@ public class OsuGroupNode {
* @return true if title, artist, creator, source, version, or tag matches query * @return true if title, artist, creator, source, version, or tag matches query
*/ */
public boolean matches(String query) { public boolean matches(String query) {
OsuFile osu = osuFiles.get(0); Beatmap beatmap = beatmaps.get(0);
// search: title, artist, creator, source, version, tags (first OsuFile) // search: title, artist, creator, source, version, tags (first beatmap)
if (osu.title.toLowerCase().contains(query) || if (beatmap.title.toLowerCase().contains(query) ||
osu.titleUnicode.toLowerCase().contains(query) || beatmap.titleUnicode.toLowerCase().contains(query) ||
osu.artist.toLowerCase().contains(query) || beatmap.artist.toLowerCase().contains(query) ||
osu.artistUnicode.toLowerCase().contains(query) || beatmap.artistUnicode.toLowerCase().contains(query) ||
osu.creator.toLowerCase().contains(query) || beatmap.creator.toLowerCase().contains(query) ||
osu.source.toLowerCase().contains(query) || beatmap.source.toLowerCase().contains(query) ||
osu.version.toLowerCase().contains(query) || beatmap.version.toLowerCase().contains(query) ||
osu.tags.contains(query)) beatmap.tags.contains(query))
return true; return true;
// search: version, tags (remaining OsuFiles) // search: version, tags (remaining beatmaps)
for (int i = 1; i < osuFiles.size(); i++) { for (int i = 1; i < beatmaps.size(); i++) {
osu = osuFiles.get(i); beatmap = beatmaps.get(i);
if (osu.version.toLowerCase().contains(query) || if (beatmap.version.toLowerCase().contains(query) ||
osu.tags.contains(query)) beatmap.tags.contains(query))
return true; return true;
} }
@ -193,16 +197,16 @@ public class OsuGroupNode {
* @return true if the condition is met * @return true if the condition is met
*/ */
public boolean matches(String type, String operator, float value) { public boolean matches(String type, String operator, float value) {
for (OsuFile osu : osuFiles) { for (Beatmap beatmap : beatmaps) {
// get value // get value
float osuValue; float v;
switch (type) { switch (type) {
case "ar": osuValue = osu.approachRate; break; case "ar": v = beatmap.approachRate; break;
case "cs": osuValue = osu.circleSize; break; case "cs": v = beatmap.circleSize; break;
case "od": osuValue = osu.overallDifficulty; break; case "od": v = beatmap.overallDifficulty; break;
case "hp": osuValue = osu.HPDrainRate; break; case "hp": v = beatmap.HPDrainRate; break;
case "bpm": osuValue = osu.bpmMax; break; case "bpm": v = beatmap.bpmMax; break;
case "length": osuValue = osu.endTime / 1000; break; case "length": v = beatmap.endTime / 1000; break;
default: return false; default: return false;
} }
@ -210,11 +214,11 @@ public class OsuGroupNode {
boolean met; boolean met;
switch (operator) { switch (operator) {
case "=": case "=":
case "==": met = (osuValue == value); break; case "==": met = (v == value); break;
case ">": met = (osuValue > value); break; case ">": met = (v > value); break;
case ">=": met = (osuValue >= value); break; case ">=": met = (v >= value); break;
case "<": met = (osuValue < value); break; case "<": met = (v < value); break;
case "<=": met = (osuValue <= value); break; case "<=": met = (v <= value); break;
default: return false; default: return false;
} }

View File

@ -16,13 +16,15 @@
* along with opsu!. If not, see <http://www.gnu.org/licenses/>. * along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/ */
package itdelatrisu.opsu; package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.GameMod;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
/** /**
* Data type representing a hit object. * Data type representing a parsed hit object.
*/ */
public class OsuHitObject { public class OsuHitObject {
/** Hit object types (bits). */ /** Hit object types (bits). */

View File

@ -16,7 +16,7 @@
* along with opsu!. If not, see <http://www.gnu.org/licenses/>. * along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/ */
package itdelatrisu.opsu; package itdelatrisu.opsu.beatmap;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;

View File

@ -20,8 +20,8 @@ package itdelatrisu.opsu.db;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.beatmap.Beatmap;
import java.io.File; import java.io.File;
import java.sql.Connection; import java.sql.Connection;
@ -38,7 +38,7 @@ import org.newdawn.slick.util.Log;
/** /**
* Handles connections and queries with the cached beatmap database. * Handles connections and queries with the cached beatmap database.
*/ */
public class OsuDB { public class BeatmapDB {
/** /**
* Current database version. * Current database version.
* This value should be changed whenever the database format changes. * This value should be changed whenever the database format changes.
@ -51,7 +51,7 @@ public class OsuDB {
/** Minimum batch size to invoke batch insertion. */ /** Minimum batch size to invoke batch insertion. */
private static final int INSERT_BATCH_MIN = 100; private static final int INSERT_BATCH_MIN = 100;
/** OsuFile loading flags. */ /** Beatmap loading flags. */
public static final int LOAD_NONARRAY = 1, LOAD_ARRAY = 2, LOAD_ALL = 3; public static final int LOAD_NONARRAY = 1, LOAD_ARRAY = 2, LOAD_ALL = 3;
/** Database connection. */ /** Database connection. */
@ -64,14 +64,14 @@ public class OsuDB {
private static int cacheSize = -1; private static int cacheSize = -1;
// This class should not be instantiated. // This class should not be instantiated.
private OsuDB() {} private BeatmapDB() {}
/** /**
* Initializes the database connection. * Initializes the database connection.
*/ */
public static void init() { public static void init() {
// create a database connection // create a database connection
connection = DBController.createConnection(Options.OSU_DB.getPath()); connection = DBController.createConnection(Options.BEATMAP_DB.getPath());
if (connection == null) if (connection == null)
return; return;
@ -216,15 +216,15 @@ public class OsuDB {
} }
/** /**
* Adds the OsuFile to the database. * Adds the beatmap to the database.
* @param osu the OsuFile object * @param beatmap the beatmap
*/ */
public static void insert(OsuFile osu) { public static void insert(Beatmap beatmap) {
if (connection == null) if (connection == null)
return; return;
try { try {
setStatementFields(insertStmt, osu); setStatementFields(insertStmt, beatmap);
cacheSize += insertStmt.executeUpdate(); cacheSize += insertStmt.executeUpdate();
updateCacheSize(); updateCacheSize();
} catch (SQLException e) { } catch (SQLException e) {
@ -233,10 +233,10 @@ public class OsuDB {
} }
/** /**
* Adds the OsuFiles to the database in a batch. * Adds the beatmaps to the database in a batch.
* @param batch a list of OsuFile objects * @param batch a list of beatmaps
*/ */
public static void insert(List<OsuFile> batch) { public static void insert(List<Beatmap> batch) {
if (connection == null) if (connection == null)
return; return;
@ -253,11 +253,11 @@ public class OsuDB {
} }
// batch insert // batch insert
for (OsuFile osu : batch) { for (Beatmap beatmap : batch) {
try { try {
setStatementFields(insertStmt, osu); setStatementFields(insertStmt, beatmap);
} catch (SQLException e) { } catch (SQLException e) {
Log.error(String.format("Failed to insert map '%s' into database.", osu.getFile().getPath()), e); Log.error(String.format("Failed to insert map '%s' into database.", beatmap.getFile().getPath()), e);
continue; continue;
} }
insertStmt.addBatch(); insertStmt.addBatch();
@ -286,53 +286,53 @@ public class OsuDB {
} }
/** /**
* Sets all statement fields using a given OsuFile object. * Sets all statement fields using a given beatmap.
* @param stmt the statement to set fields for * @param stmt the statement to set fields for
* @param osu the OsuFile * @param beatmap the beatmap
* @throws SQLException * @throws SQLException
*/ */
private static void setStatementFields(PreparedStatement stmt, OsuFile osu) private static void setStatementFields(PreparedStatement stmt, Beatmap beatmap)
throws SQLException { throws SQLException {
try { try {
stmt.setString(1, osu.getFile().getParentFile().getName()); stmt.setString(1, beatmap.getFile().getParentFile().getName());
stmt.setString(2, osu.getFile().getName()); stmt.setString(2, beatmap.getFile().getName());
stmt.setLong(3, osu.getFile().lastModified()); stmt.setLong(3, beatmap.getFile().lastModified());
stmt.setInt(4, osu.beatmapID); stmt.setInt(4, beatmap.beatmapID);
stmt.setInt(5, osu.beatmapSetID); stmt.setInt(5, beatmap.beatmapSetID);
stmt.setString(6, osu.title); stmt.setString(6, beatmap.title);
stmt.setString(7, osu.titleUnicode); stmt.setString(7, beatmap.titleUnicode);
stmt.setString(8, osu.artist); stmt.setString(8, beatmap.artist);
stmt.setString(9, osu.artistUnicode); stmt.setString(9, beatmap.artistUnicode);
stmt.setString(10, osu.creator); stmt.setString(10, beatmap.creator);
stmt.setString(11, osu.version); stmt.setString(11, beatmap.version);
stmt.setString(12, osu.source); stmt.setString(12, beatmap.source);
stmt.setString(13, osu.tags); stmt.setString(13, beatmap.tags);
stmt.setInt(14, osu.hitObjectCircle); stmt.setInt(14, beatmap.hitObjectCircle);
stmt.setInt(15, osu.hitObjectSlider); stmt.setInt(15, beatmap.hitObjectSlider);
stmt.setInt(16, osu.hitObjectSpinner); stmt.setInt(16, beatmap.hitObjectSpinner);
stmt.setFloat(17, osu.HPDrainRate); stmt.setFloat(17, beatmap.HPDrainRate);
stmt.setFloat(18, osu.circleSize); stmt.setFloat(18, beatmap.circleSize);
stmt.setFloat(19, osu.overallDifficulty); stmt.setFloat(19, beatmap.overallDifficulty);
stmt.setFloat(20, osu.approachRate); stmt.setFloat(20, beatmap.approachRate);
stmt.setFloat(21, osu.sliderMultiplier); stmt.setFloat(21, beatmap.sliderMultiplier);
stmt.setFloat(22, osu.sliderTickRate); stmt.setFloat(22, beatmap.sliderTickRate);
stmt.setInt(23, osu.bpmMin); stmt.setInt(23, beatmap.bpmMin);
stmt.setInt(24, osu.bpmMax); stmt.setInt(24, beatmap.bpmMax);
stmt.setInt(25, osu.endTime); stmt.setInt(25, beatmap.endTime);
stmt.setString(26, osu.audioFilename.getName()); stmt.setString(26, beatmap.audioFilename.getName());
stmt.setInt(27, osu.audioLeadIn); stmt.setInt(27, beatmap.audioLeadIn);
stmt.setInt(28, osu.previewTime); stmt.setInt(28, beatmap.previewTime);
stmt.setByte(29, osu.countdown); stmt.setByte(29, beatmap.countdown);
stmt.setString(30, osu.sampleSet); stmt.setString(30, beatmap.sampleSet);
stmt.setFloat(31, osu.stackLeniency); stmt.setFloat(31, beatmap.stackLeniency);
stmt.setByte(32, osu.mode); stmt.setByte(32, beatmap.mode);
stmt.setBoolean(33, osu.letterboxInBreaks); stmt.setBoolean(33, beatmap.letterboxInBreaks);
stmt.setBoolean(34, osu.widescreenStoryboard); stmt.setBoolean(34, beatmap.widescreenStoryboard);
stmt.setBoolean(35, osu.epilepsyWarning); stmt.setBoolean(35, beatmap.epilepsyWarning);
stmt.setString(36, osu.bg); stmt.setString(36, beatmap.bg);
stmt.setString(37, osu.timingPointsToString()); stmt.setString(37, beatmap.timingPointsToString());
stmt.setString(38, osu.breaksToString()); stmt.setString(38, beatmap.breaksToString());
stmt.setString(39, osu.comboToString()); stmt.setString(39, beatmap.comboToString());
} catch (SQLException e) { } catch (SQLException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -341,80 +341,80 @@ public class OsuDB {
} }
/** /**
* Loads OsuFile fields from the database. * Loads beatmap fields from the database.
* @param osu the OsuFile object * @param beatmap the beatmap
* @param flag whether to load all fields (LOAD_ALL), non-array * @param flag whether to load all fields (LOAD_ALL), non-array
* fields (LOAD_NONARRAY), or array fields (LOAD_ARRAY) * fields (LOAD_NONARRAY), or array fields (LOAD_ARRAY)
*/ */
public static void load(OsuFile osu, int flag) { public static void load(Beatmap beatmap, int flag) {
if (connection == null) if (connection == null)
return; return;
try { try {
selectStmt.setString(1, osu.getFile().getParentFile().getName()); selectStmt.setString(1, beatmap.getFile().getParentFile().getName());
selectStmt.setString(2, osu.getFile().getName()); selectStmt.setString(2, beatmap.getFile().getName());
ResultSet rs = selectStmt.executeQuery(); ResultSet rs = selectStmt.executeQuery();
if (rs.next()) { if (rs.next()) {
if ((flag & LOAD_NONARRAY) > 0) if ((flag & LOAD_NONARRAY) > 0)
setOsuFileFields(rs, osu); setBeatmapFields(rs, beatmap);
if ((flag & LOAD_ARRAY) > 0) if ((flag & LOAD_ARRAY) > 0)
setOsuFileArrayFields(rs, osu); setBeatmapArrayFields(rs, beatmap);
} }
rs.close(); rs.close();
} catch (SQLException e) { } catch (SQLException e) {
ErrorHandler.error("Failed to load OsuFile from database.", e, true); ErrorHandler.error("Failed to load Beatmap from database.", e, true);
} }
} }
/** /**
* Loads OsuFile fields from the database in a batch. * Loads Beatmap fields from the database in a batch.
* @param batch a list of OsuFile objects * @param batch a list of beatmaps
* @param flag whether to load all fields (LOAD_ALL), non-array * @param flag whether to load all fields (LOAD_ALL), non-array
* fields (LOAD_NONARRAY), or array fields (LOAD_ARRAY) * fields (LOAD_NONARRAY), or array fields (LOAD_ARRAY)
*/ */
public static void load(List<OsuFile> batch, int flag) { public static void load(List<Beatmap> batch, int flag) {
if (connection == null) if (connection == null)
return; return;
// batch size too small // batch size too small
int size = batch.size(); int size = batch.size();
if (size < cacheSize * LOAD_BATCH_MIN_RATIO) { if (size < cacheSize * LOAD_BATCH_MIN_RATIO) {
for (OsuFile osu : batch) for (Beatmap beatmap : batch)
load(osu, flag); load(beatmap, flag);
return; return;
} }
try (Statement stmt = connection.createStatement()) { try (Statement stmt = connection.createStatement()) {
// create map // create map
HashMap<String, HashMap<String, OsuFile>> map = new HashMap<String, HashMap<String, OsuFile>>(); HashMap<String, HashMap<String, Beatmap>> map = new HashMap<String, HashMap<String, Beatmap>>();
for (OsuFile osu : batch) { for (Beatmap beatmap : batch) {
String parent = osu.getFile().getParentFile().getName(); String parent = beatmap.getFile().getParentFile().getName();
String name = osu.getFile().getName(); String name = beatmap.getFile().getName();
HashMap<String, OsuFile> m = map.get(parent); HashMap<String, Beatmap> m = map.get(parent);
if (m == null) { if (m == null) {
m = new HashMap<String, OsuFile>(); m = new HashMap<String, Beatmap>();
map.put(parent, m); map.put(parent, m);
} }
m.put(name, osu); m.put(name, beatmap);
} }
// iterate through database to load OsuFiles // iterate through database to load beatmaps
int count = 0; int count = 0;
stmt.setFetchSize(100); stmt.setFetchSize(100);
String sql = "SELECT * FROM beatmaps"; String sql = "SELECT * FROM beatmaps";
ResultSet rs = stmt.executeQuery(sql); ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) { while (rs.next()) {
String parent = rs.getString(1); String parent = rs.getString(1);
HashMap<String, OsuFile> m = map.get(parent); HashMap<String, Beatmap> m = map.get(parent);
if (m != null) { if (m != null) {
String name = rs.getString(2); String name = rs.getString(2);
OsuFile osu = m.get(name); Beatmap beatmap = m.get(name);
if (osu != null) { if (beatmap != null) {
try { try {
if ((flag & LOAD_NONARRAY) > 0) if ((flag & LOAD_NONARRAY) > 0)
setOsuFileFields(rs, osu); setBeatmapFields(rs, beatmap);
if ((flag & LOAD_ARRAY) > 0) if ((flag & LOAD_ARRAY) > 0)
setOsuFileArrayFields(rs, osu); setBeatmapArrayFields(rs, beatmap);
} catch (SQLException e) { } catch (SQLException e) {
Log.error(String.format("Failed to load map '%s/%s' from database.", parent, name), e); Log.error(String.format("Failed to load map '%s/%s' from database.", parent, name), e);
} }
@ -425,51 +425,51 @@ public class OsuDB {
} }
rs.close(); rs.close();
} catch (SQLException e) { } catch (SQLException e) {
ErrorHandler.error("Failed to load OsuFiles from database.", e, true); ErrorHandler.error("Failed to load beatmaps from database.", e, true);
} }
} }
/** /**
* Sets all OsuFile non-array fields using a given result set. * Sets all beatmap non-array fields using a given result set.
* @param rs the result set containing the fields * @param rs the result set containing the fields
* @param osu the OsuFile * @param beatmap the beatmap
* @throws SQLException * @throws SQLException
*/ */
private static void setOsuFileFields(ResultSet rs, OsuFile osu) throws SQLException { private static void setBeatmapFields(ResultSet rs, Beatmap beatmap) throws SQLException {
try { try {
osu.beatmapID = rs.getInt(4); beatmap.beatmapID = rs.getInt(4);
osu.beatmapSetID = rs.getInt(5); beatmap.beatmapSetID = rs.getInt(5);
osu.title = OsuParser.getDBString(rs.getString(6)); beatmap.title = OsuParser.getDBString(rs.getString(6));
osu.titleUnicode = OsuParser.getDBString(rs.getString(7)); beatmap.titleUnicode = OsuParser.getDBString(rs.getString(7));
osu.artist = OsuParser.getDBString(rs.getString(8)); beatmap.artist = OsuParser.getDBString(rs.getString(8));
osu.artistUnicode = OsuParser.getDBString(rs.getString(9)); beatmap.artistUnicode = OsuParser.getDBString(rs.getString(9));
osu.creator = OsuParser.getDBString(rs.getString(10)); beatmap.creator = OsuParser.getDBString(rs.getString(10));
osu.version = OsuParser.getDBString(rs.getString(11)); beatmap.version = OsuParser.getDBString(rs.getString(11));
osu.source = OsuParser.getDBString(rs.getString(12)); beatmap.source = OsuParser.getDBString(rs.getString(12));
osu.tags = OsuParser.getDBString(rs.getString(13)); beatmap.tags = OsuParser.getDBString(rs.getString(13));
osu.hitObjectCircle = rs.getInt(14); beatmap.hitObjectCircle = rs.getInt(14);
osu.hitObjectSlider = rs.getInt(15); beatmap.hitObjectSlider = rs.getInt(15);
osu.hitObjectSpinner = rs.getInt(16); beatmap.hitObjectSpinner = rs.getInt(16);
osu.HPDrainRate = rs.getFloat(17); beatmap.HPDrainRate = rs.getFloat(17);
osu.circleSize = rs.getFloat(18); beatmap.circleSize = rs.getFloat(18);
osu.overallDifficulty = rs.getFloat(19); beatmap.overallDifficulty = rs.getFloat(19);
osu.approachRate = rs.getFloat(20); beatmap.approachRate = rs.getFloat(20);
osu.sliderMultiplier = rs.getFloat(21); beatmap.sliderMultiplier = rs.getFloat(21);
osu.sliderTickRate = rs.getFloat(22); beatmap.sliderTickRate = rs.getFloat(22);
osu.bpmMin = rs.getInt(23); beatmap.bpmMin = rs.getInt(23);
osu.bpmMax = rs.getInt(24); beatmap.bpmMax = rs.getInt(24);
osu.endTime = rs.getInt(25); beatmap.endTime = rs.getInt(25);
osu.audioFilename = new File(osu.getFile().getParentFile(), OsuParser.getDBString(rs.getString(26))); beatmap.audioFilename = new File(beatmap.getFile().getParentFile(), OsuParser.getDBString(rs.getString(26)));
osu.audioLeadIn = rs.getInt(27); beatmap.audioLeadIn = rs.getInt(27);
osu.previewTime = rs.getInt(28); beatmap.previewTime = rs.getInt(28);
osu.countdown = rs.getByte(29); beatmap.countdown = rs.getByte(29);
osu.sampleSet = OsuParser.getDBString(rs.getString(30)); beatmap.sampleSet = OsuParser.getDBString(rs.getString(30));
osu.stackLeniency = rs.getFloat(31); beatmap.stackLeniency = rs.getFloat(31);
osu.mode = rs.getByte(32); beatmap.mode = rs.getByte(32);
osu.letterboxInBreaks = rs.getBoolean(33); beatmap.letterboxInBreaks = rs.getBoolean(33);
osu.widescreenStoryboard = rs.getBoolean(34); beatmap.widescreenStoryboard = rs.getBoolean(34);
osu.epilepsyWarning = rs.getBoolean(35); beatmap.epilepsyWarning = rs.getBoolean(35);
osu.bg = OsuParser.getDBString(rs.getString(36)); beatmap.bg = OsuParser.getDBString(rs.getString(36));
} catch (SQLException e) { } catch (SQLException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -478,16 +478,16 @@ public class OsuDB {
} }
/** /**
* Sets all OsuFile array fields using a given result set. * Sets all Beatmap array fields using a given result set.
* @param rs the result set containing the fields * @param rs the result set containing the fields
* @param osu the OsuFile * @param beatmap the beatmap
* @throws SQLException * @throws SQLException
*/ */
private static void setOsuFileArrayFields(ResultSet rs, OsuFile osu) throws SQLException { private static void setBeatmapArrayFields(ResultSet rs, Beatmap beatmap) throws SQLException {
try { try {
osu.timingPointsFromString(rs.getString(37)); beatmap.timingPointsFromString(rs.getString(37));
osu.breaksFromString(rs.getString(38)); beatmap.breaksFromString(rs.getString(38));
osu.comboFromString(rs.getString(39)); beatmap.comboFromString(rs.getString(39));
} catch (SQLException e) { } catch (SQLException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {

View File

@ -43,7 +43,7 @@ public class DBController {
} }
// initialize the databases // initialize the databases
OsuDB.init(); BeatmapDB.init();
ScoreDB.init(); ScoreDB.init();
} }
@ -51,7 +51,7 @@ public class DBController {
* Closes all database connections. * Closes all database connections.
*/ */
public static void closeConnections() { public static void closeConnections() {
OsuDB.closeConnection(); BeatmapDB.closeConnection();
ScoreDB.closeConnection(); ScoreDB.closeConnection();
} }

View File

@ -20,8 +20,8 @@ package itdelatrisu.opsu.db;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.beatmap.Beatmap;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -240,18 +240,18 @@ public class ScoreDB {
/** /**
* Deletes all the scores for the given beatmap from the database. * Deletes all the scores for the given beatmap from the database.
* @param osu the OsuFile object * @param beatmap the beatmap
*/ */
public static void deleteScore(OsuFile osu) { public static void deleteScore(Beatmap beatmap) {
if (connection == null) if (connection == null)
return; return;
try { try {
deleteSongStmt.setInt(1, osu.beatmapID); deleteSongStmt.setInt(1, beatmap.beatmapID);
deleteSongStmt.setString(2, osu.title); deleteSongStmt.setString(2, beatmap.title);
deleteSongStmt.setString(3, osu.artist); deleteSongStmt.setString(3, beatmap.artist);
deleteSongStmt.setString(4, osu.creator); deleteSongStmt.setString(4, beatmap.creator);
deleteSongStmt.setString(5, osu.version); deleteSongStmt.setString(5, beatmap.version);
deleteSongStmt.executeUpdate(); deleteSongStmt.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
ErrorHandler.error("Failed to delete scores from database.", e, true); ErrorHandler.error("Failed to delete scores from database.", e, true);
@ -286,21 +286,21 @@ public class ScoreDB {
} }
/** /**
* Retrieves the game scores for an OsuFile map. * Retrieves the game scores for a beatmap.
* @param osu the OsuFile * @param beatmap the beatmap
* @return all scores for the beatmap, or null if any error occurred * @return all scores for the beatmap, or null if any error occurred
*/ */
public static ScoreData[] getMapScores(OsuFile osu) { public static ScoreData[] getMapScores(Beatmap beatmap) {
if (connection == null) if (connection == null)
return null; return null;
List<ScoreData> list = new ArrayList<ScoreData>(); List<ScoreData> list = new ArrayList<ScoreData>();
try { try {
selectMapStmt.setInt(1, osu.beatmapID); selectMapStmt.setInt(1, beatmap.beatmapID);
selectMapStmt.setString(2, osu.title); selectMapStmt.setString(2, beatmap.title);
selectMapStmt.setString(3, osu.artist); selectMapStmt.setString(3, beatmap.artist);
selectMapStmt.setString(4, osu.creator); selectMapStmt.setString(4, beatmap.creator);
selectMapStmt.setString(5, osu.version); selectMapStmt.setString(5, beatmap.version);
ResultSet rs = selectMapStmt.executeQuery(); ResultSet rs = selectMapStmt.executeQuery();
while (rs.next()) { while (rs.next()) {
ScoreData s = new ScoreData(rs); ScoreData s = new ScoreData(rs);
@ -315,21 +315,21 @@ public class ScoreDB {
} }
/** /**
* Retrieves the game scores for an OsuFile map set. * Retrieves the game scores for a beatmap set.
* @param osu the OsuFile * @param beatmap the beatmap
* @return all scores for the beatmap set (Version, ScoreData[]), * @return all scores for the beatmap set (Version, ScoreData[]),
* or null if any error occurred * or null if any error occurred
*/ */
public static Map<String, ScoreData[]> getMapSetScores(OsuFile osu) { public static Map<String, ScoreData[]> getMapSetScores(Beatmap beatmap) {
if (connection == null) if (connection == null)
return null; return null;
Map<String, ScoreData[]> map = new HashMap<String, ScoreData[]>(); Map<String, ScoreData[]> map = new HashMap<String, ScoreData[]>();
try { try {
selectMapSetStmt.setInt(1, osu.beatmapSetID); selectMapSetStmt.setInt(1, beatmap.beatmapSetID);
selectMapSetStmt.setString(2, osu.title); selectMapSetStmt.setString(2, beatmap.title);
selectMapSetStmt.setString(3, osu.artist); selectMapSetStmt.setString(3, beatmap.artist);
selectMapSetStmt.setString(4, osu.creator); selectMapSetStmt.setString(4, beatmap.creator);
ResultSet rs = selectMapSetStmt.executeQuery(); ResultSet rs = selectMapSetStmt.executeQuery();
List<ScoreData> list = null; List<ScoreData> list = null;

View File

@ -21,9 +21,9 @@ package itdelatrisu.opsu.downloads;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.UI; import itdelatrisu.opsu.UI;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.downloads.Download.DownloadListener; import itdelatrisu.opsu.downloads.Download.DownloadListener;
import itdelatrisu.opsu.downloads.Download.Status; import itdelatrisu.opsu.downloads.Download.Status;
import itdelatrisu.opsu.downloads.servers.DownloadServer; import itdelatrisu.opsu.downloads.servers.DownloadServer;
@ -325,7 +325,7 @@ public class DownloadNode {
g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight); g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight);
// map is already loaded // map is already loaded
if (OsuGroupList.get().containsBeatmapSetID(beatmapSetID)) { if (BeatmapSetList.get().containsBeatmapSetID(beatmapSetID)) {
g.setColor(Utils.COLOR_BLUE_BUTTON); g.setColor(Utils.COLOR_BLUE_BUTTON);
g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight); g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight);
} }

View File

@ -22,8 +22,8 @@ import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.HitObjectType; import itdelatrisu.opsu.GameData.HitObjectType;
import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod; import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Game;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;

View File

@ -18,7 +18,7 @@
package itdelatrisu.opsu.objects; package itdelatrisu.opsu.objects;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.beatmap.OsuHitObject;
import org.newdawn.slick.Graphics; import org.newdawn.slick.Graphics;

View File

@ -22,9 +22,9 @@ import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.HitObjectType; import itdelatrisu.opsu.GameData.HitObjectType;
import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod; import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import itdelatrisu.opsu.objects.curves.CatmullCurve; import itdelatrisu.opsu.objects.curves.CatmullCurve;
import itdelatrisu.opsu.objects.curves.CircumscribedCircle; import itdelatrisu.opsu.objects.curves.CircumscribedCircle;
import itdelatrisu.opsu.objects.curves.Curve; import itdelatrisu.opsu.objects.curves.Curve;
@ -104,9 +104,9 @@ public class Slider implements HitObject {
* Initializes the Slider data type with images and dimensions. * Initializes the Slider data type with images and dimensions.
* @param container the game container * @param container the game container
* @param circleSize the map's circleSize value * @param circleSize the map's circleSize value
* @param osu the associated OsuFile object * @param beatmap the associated beatmap
*/ */
public static void init(GameContainer container, float circleSize, OsuFile osu) { public static void init(GameContainer container, float circleSize, Beatmap beatmap) {
containerWidth = container.getWidth(); containerWidth = container.getWidth();
containerHeight = container.getHeight(); containerHeight = container.getHeight();
@ -126,8 +126,8 @@ public class Slider implements HitObject {
GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter)); GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter));
GameImage.SLIDER_TICK.setImage(GameImage.SLIDER_TICK.getImage().getScaledCopy(diameter / 4, diameter / 4)); GameImage.SLIDER_TICK.setImage(GameImage.SLIDER_TICK.getImage().getScaledCopy(diameter / 4, diameter / 4));
sliderMultiplier = osu.sliderMultiplier; sliderMultiplier = beatmap.sliderMultiplier;
sliderTickRate = osu.sliderTickRate; sliderTickRate = beatmap.sliderTickRate;
} }
/** /**

View File

@ -22,10 +22,10 @@ import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.HitObjectType; import itdelatrisu.opsu.GameData.HitObjectType;
import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod; import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Game;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;

View File

@ -19,7 +19,7 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.beatmap.OsuHitObject;
import java.util.LinkedList; import java.util.LinkedList;

View File

@ -19,7 +19,7 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.beatmap.OsuHitObject;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;

View File

@ -19,8 +19,8 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;

View File

@ -18,7 +18,7 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.beatmap.OsuHitObject;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;

View File

@ -18,7 +18,7 @@
package itdelatrisu.opsu.objects.curves; package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.beatmap.OsuHitObject;
import java.util.LinkedList; import java.util.LinkedList;

View File

@ -18,7 +18,7 @@
package itdelatrisu.opsu.replay; package itdelatrisu.opsu.replay;
import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.beatmap.OsuHitObject;
/** /**
* Captures a single replay frame. * Captures a single replay frame.

View File

@ -23,14 +23,14 @@ 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.Options;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.OsuGroupNode;
import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.UI; import itdelatrisu.opsu.UI;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController; 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 itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -66,9 +66,9 @@ public class ButtonMenu extends BasicGameState {
BEATMAP (new Button[] { Button.CLEAR_SCORES, Button.DELETE, Button.CANCEL }) { BEATMAP (new Button[] { Button.CLEAR_SCORES, Button.DELETE, Button.CANCEL }) {
@Override @Override
public String[] getTitle(GameContainer container, StateBasedGame game) { public String[] getTitle(GameContainer container, StateBasedGame game) {
OsuGroupNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
String osuString = (node != null) ? OsuGroupList.get().getBaseNode(node.index).toString() : ""; String beatmapString = (node != null) ? BeatmapSetList.get().getBaseNode(node.index).toString() : "";
return new String[] { osuString, "What do you want to do with this beatmap?" }; return new String[] { beatmapString, "What do you want to do with this beatmap?" };
} }
@Override @Override
@ -86,9 +86,9 @@ public class ButtonMenu extends BasicGameState {
BEATMAP_DELETE_SELECT (new Button[] { Button.DELETE_GROUP, Button.DELETE_SONG, Button.CANCEL_DELETE }) { BEATMAP_DELETE_SELECT (new Button[] { Button.DELETE_GROUP, Button.DELETE_SONG, Button.CANCEL_DELETE }) {
@Override @Override
public String[] getTitle(GameContainer container, StateBasedGame game) { public String[] getTitle(GameContainer container, StateBasedGame game) {
OsuGroupNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
String osuString = (node != null) ? node.toString() : ""; String beatmapString = (node != null) ? node.toString() : "";
return new String[] { String.format("Are you sure you wish to delete '%s' from disk?", osuString) }; return new String[] { String.format("Are you sure you wish to delete '%s' from disk?", beatmapString) };
} }
@Override @Override
@ -451,7 +451,7 @@ public class ButtonMenu extends BasicGameState {
@Override @Override
public void click(GameContainer container, StateBasedGame game) { public void click(GameContainer container, StateBasedGame game) {
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
OsuGroupNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP, node); ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP, node);
game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black));
} }
@ -460,8 +460,8 @@ public class ButtonMenu extends BasicGameState {
@Override @Override
public void click(GameContainer container, StateBasedGame game) { public void click(GameContainer container, StateBasedGame game) {
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
OsuGroupNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
MenuState ms = (node.osuFileIndex == -1 || node.osuFiles.size() == 1) ? MenuState ms = (node.beatmapIndex == -1 || node.beatmaps.size() == 1) ?
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT; MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, node); ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, node);
game.enterState(Opsu.STATE_BUTTONMENU); game.enterState(Opsu.STATE_BUTTONMENU);
@ -478,7 +478,7 @@ public class ButtonMenu extends BasicGameState {
@Override @Override
public void click(GameContainer container, StateBasedGame game) { public void click(GameContainer container, StateBasedGame game) {
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
OsuGroupNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node); ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node);
game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black));
} }
@ -493,7 +493,7 @@ public class ButtonMenu extends BasicGameState {
@Override @Override
public void click(GameContainer container, StateBasedGame game) { public void click(GameContainer container, StateBasedGame game) {
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
OsuGroupNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node); ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node);
game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black));
} }
@ -582,7 +582,7 @@ public class ButtonMenu extends BasicGameState {
private MenuState menuState; private MenuState menuState;
/** The song node to process in the state. */ /** The song node to process in the state. */
private OsuGroupNode node; private BeatmapSetNode node;
/** The score data to process in the state. */ /** The score data to process in the state. */
private ScoreData scoreData; private ScoreData scoreData;
@ -691,7 +691,7 @@ public class ButtonMenu extends BasicGameState {
* @param menuState the new menu state * @param menuState the new menu state
* @param node the song node to process in the state * @param node the song node to process in the state
*/ */
public void setMenuState(MenuState menuState, OsuGroupNode node) { setMenuState(menuState, node, null); } public void setMenuState(MenuState menuState, BeatmapSetNode node) { setMenuState(menuState, node, null); }
/** /**
* Changes the menu state. * Changes the menu state.
@ -706,7 +706,7 @@ public class ButtonMenu extends BasicGameState {
* @param node the song node to process in the state * @param node the song node to process in the state
* @param scoreData the score scoreData * @param scoreData the score scoreData
*/ */
private void setMenuState(MenuState menuState, OsuGroupNode node, ScoreData scoreData) { private void setMenuState(MenuState menuState, BeatmapSetNode node, ScoreData scoreData) {
this.menuState = menuState; this.menuState = menuState;
this.node = node; this.node = node;
this.scoreData = scoreData; this.scoreData = scoreData;
@ -715,7 +715,7 @@ public class ButtonMenu extends BasicGameState {
/** /**
* Returns the song node being processed, or null if none. * Returns the song node being processed, or null if none.
*/ */
private OsuGroupNode getNode() { return node; } private BeatmapSetNode getNode() { return node; }
/** /**
* Returns the score data being processed, or null if none. * Returns the score data being processed, or null if none.

View File

@ -22,8 +22,6 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.MenuButton; import itdelatrisu.opsu.MenuButton;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.OsuGroupNode;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.OszUnpacker; import itdelatrisu.opsu.OszUnpacker;
import itdelatrisu.opsu.UI; import itdelatrisu.opsu.UI;
@ -31,6 +29,8 @@ import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController; 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 itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
import itdelatrisu.opsu.downloads.Download; import itdelatrisu.opsu.downloads.Download;
import itdelatrisu.opsu.downloads.DownloadList; import itdelatrisu.opsu.downloads.DownloadList;
import itdelatrisu.opsu.downloads.DownloadNode; import itdelatrisu.opsu.downloads.DownloadNode;
@ -482,7 +482,7 @@ public class DownloadsMenu extends BasicGameState {
final DownloadNode node = nodes[index]; final DownloadNode node = nodes[index];
// check if map is already loaded // check if map is already loaded
boolean isLoaded = OsuGroupList.get().containsBeatmapSetID(node.getID()); boolean isLoaded = BeatmapSetList.get().containsBeatmapSetID(node.getID());
// track preview // track preview
if (DownloadNode.resultIconContains(x, y, i)) { if (DownloadNode.resultIconContains(x, y, i)) {
@ -607,15 +607,15 @@ public class DownloadsMenu extends BasicGameState {
// invoke unpacker and parser // invoke unpacker and parser
File[] dirs = OszUnpacker.unpackAllFiles(Options.getOSZDir(), Options.getBeatmapDir()); File[] dirs = OszUnpacker.unpackAllFiles(Options.getOSZDir(), Options.getBeatmapDir());
if (dirs != null && dirs.length > 0) { if (dirs != null && dirs.length > 0) {
OsuGroupNode node = OsuParser.parseDirectories(dirs); BeatmapSetNode node = OsuParser.parseDirectories(dirs);
if (node != null) { if (node != null) {
// stop preview // stop preview
previewID = -1; previewID = -1;
SoundController.stopTrack(); SoundController.stopTrack();
// initialize song list // initialize song list
OsuGroupList.get().reset(); BeatmapSetList.get().reset();
OsuGroupList.get().init(); BeatmapSetList.get().init();
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(node, -1, true, true); ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(node, -1, true, true);
// send notification // send notification
@ -739,7 +739,7 @@ public class DownloadsMenu extends BasicGameState {
switch (key) { switch (key) {
case Input.KEY_ESCAPE: case Input.KEY_ESCAPE:
if (importThread != null) { if (importThread != null) {
// beatmap importing: stop parsing OsuFiles by sending interrupt to OsuParser // beatmap importing: stop parsing beatmaps by sending interrupt to OsuParser
importThread.interrupt(); importThread.interrupt();
} else if (!search.getText().isEmpty()) { } else if (!search.getText().isEmpty()) {
// clear search text // clear search text

View File

@ -25,18 +25,18 @@ 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.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuHitObject;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.TimingPoint;
import itdelatrisu.opsu.UI; import itdelatrisu.opsu.UI;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.HitSound; import itdelatrisu.opsu.audio.HitSound;
import itdelatrisu.opsu.audio.MusicController; 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 itdelatrisu.opsu.db.OsuDB; import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.OsuHitObject;
import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.db.BeatmapDB;
import itdelatrisu.opsu.db.ScoreDB; import itdelatrisu.opsu.db.ScoreDB;
import itdelatrisu.opsu.objects.Circle; import itdelatrisu.opsu.objects.Circle;
import itdelatrisu.opsu.objects.DummyObject; import itdelatrisu.opsu.objects.DummyObject;
@ -96,8 +96,8 @@ public class Game extends BasicGameState {
/** Stack position offset modifier. */ /** Stack position offset modifier. */
private static final float STACK_OFFSET_MODIFIER = 0.05f; private static final float STACK_OFFSET_MODIFIER = 0.05f;
/** The associated OsuFile object. */ /** The associated beatmap. */
private OsuFile osu; private Beatmap beatmap;
/** The associated GameData object. */ /** The associated GameData object. */
private GameData data; private GameData data;
@ -254,7 +254,7 @@ public class Game extends BasicGameState {
trackPosition = pauseTime; trackPosition = pauseTime;
else if (deathTime > -1) // "Easy" mod: health bar increasing else if (deathTime > -1) // "Easy" mod: health bar increasing
trackPosition = deathTime; trackPosition = deathTime;
int firstObjectTime = osu.objects[0].getTime(); int firstObjectTime = beatmap.objects[0].getTime();
int timeDiff = firstObjectTime - trackPosition; int timeDiff = firstObjectTime - trackPosition;
g.setBackground(Color.black); g.setBackground(Color.black);
@ -273,7 +273,7 @@ public class Game extends BasicGameState {
else else
dimLevel = 1f; dimLevel = 1f;
} }
if (Options.isDefaultPlayfieldForced() || !osu.drawBG(width, height, dimLevel, false)) { if (Options.isDefaultPlayfieldForced() || !beatmap.drawBG(width, height, dimLevel, false)) {
Image playfield = GameImage.PLAYFIELD.getImage(); Image playfield = GameImage.PLAYFIELD.getImage();
playfield.setAlpha(dimLevel); playfield.setAlpha(dimLevel);
playfield.draw(); playfield.draw();
@ -292,7 +292,7 @@ public class Game extends BasicGameState {
float[] autoXY = null; float[] autoXY = null;
if (isLeadIn()) { if (isLeadIn()) {
// lead-in // lead-in
float progress = Math.max((float) (leadInTime - osu.audioLeadIn) / approachTime, 0f); float progress = Math.max((float) (leadInTime - beatmap.audioLeadIn) / approachTime, 0f);
autoMouseY = (int) (height / (2f - progress)); autoMouseY = (int) (height / (2f - progress));
} else if (objectIndex == 0 && trackPosition < firstObjectTime) { } else if (objectIndex == 0 && trackPosition < firstObjectTime) {
// before first object // before first object
@ -301,20 +301,20 @@ public class Game extends BasicGameState {
float[] xy = hitObjects[0].getPointAt(trackPosition); float[] xy = hitObjects[0].getPointAt(trackPosition);
autoXY = getPointAt(autoMouseX, autoMouseY, xy[0], xy[1], 1f - ((float) timeDiff / Math.min(approachTime, firstObjectTime))); autoXY = getPointAt(autoMouseX, autoMouseY, xy[0], xy[1], 1f - ((float) timeDiff / Math.min(approachTime, firstObjectTime)));
} }
} else if (objectIndex < osu.objects.length) { } else if (objectIndex < beatmap.objects.length) {
// normal object // normal object
int objectTime = osu.objects[objectIndex].getTime(); int objectTime = beatmap.objects[objectIndex].getTime();
if (trackPosition < objectTime) { if (trackPosition < objectTime) {
float[] xyStart = hitObjects[objectIndex - 1].getPointAt(trackPosition); float[] xyStart = hitObjects[objectIndex - 1].getPointAt(trackPosition);
int startTime = hitObjects[objectIndex - 1].getEndTime(); int startTime = hitObjects[objectIndex - 1].getEndTime();
if (osu.breaks != null && breakIndex < osu.breaks.size()) { if (beatmap.breaks != null && breakIndex < beatmap.breaks.size()) {
// starting a break: keep cursor at previous hit object position // starting a break: keep cursor at previous hit object position
if (breakTime > 0 || objectTime > osu.breaks.get(breakIndex)) if (breakTime > 0 || objectTime > beatmap.breaks.get(breakIndex))
autoXY = xyStart; autoXY = xyStart;
// after a break ends: move startTime to break end time // after a break ends: move startTime to break end time
else if (breakIndex > 1) { else if (breakIndex > 1) {
int lastBreakEndTime = osu.breaks.get(breakIndex - 1); int lastBreakEndTime = beatmap.breaks.get(breakIndex - 1);
if (objectTime > lastBreakEndTime && startTime < lastBreakEndTime) if (objectTime > lastBreakEndTime && startTime < lastBreakEndTime)
startTime = lastBreakEndTime; startTime = lastBreakEndTime;
} }
@ -326,8 +326,8 @@ public class Game extends BasicGameState {
// hit circles: show a mouse press // hit circles: show a mouse press
int offset300 = hitResultOffset[GameData.HIT_300]; int offset300 = hitResultOffset[GameData.HIT_300];
if ((osu.objects[objectIndex].isCircle() && objectTime - trackPosition < offset300) || if ((beatmap.objects[objectIndex].isCircle() && objectTime - trackPosition < offset300) ||
(osu.objects[objectIndex - 1].isCircle() && trackPosition - osu.objects[objectIndex - 1].getTime() < offset300)) (beatmap.objects[objectIndex - 1].isCircle() && trackPosition - beatmap.objects[objectIndex - 1].getTime() < offset300))
autoMousePressed = true; autoMousePressed = true;
} }
} else { } else {
@ -388,12 +388,12 @@ public class Game extends BasicGameState {
} }
// break periods // break periods
if (osu.breaks != null && breakIndex < osu.breaks.size() && breakTime > 0) { if (beatmap.breaks != null && breakIndex < beatmap.breaks.size() && breakTime > 0) {
int endTime = osu.breaks.get(breakIndex); int endTime = beatmap.breaks.get(breakIndex);
int breakLength = endTime - breakTime; int breakLength = endTime - breakTime;
// letterbox effect (black bars on top/bottom) // letterbox effect (black bars on top/bottom)
if (osu.letterboxInBreaks && breakLength >= 4000) { if (beatmap.letterboxInBreaks && breakLength >= 4000) {
g.setColor(Color.black); g.setColor(Color.black);
g.fillRect(0, 0, width, height * 0.125f); g.fillRect(0, 0, width, height * 0.125f);
g.fillRect(0, height * 0.875f, width, height * 0.125f); g.fillRect(0, height * 0.875f, width, height * 0.125f);
@ -441,7 +441,7 @@ public class Game extends BasicGameState {
// skip beginning // skip beginning
if (objectIndex == 0 && if (objectIndex == 0 &&
trackPosition < osu.objects[0].getTime() - SKIP_OFFSET) trackPosition < beatmap.objects[0].getTime() - SKIP_OFFSET)
skipButton.draw(); skipButton.draw();
// show retries // show retries
@ -465,7 +465,7 @@ public class Game extends BasicGameState {
trackPosition = (leadInTime - Options.getMusicOffset()) * -1; // render approach circles during song lead-in trackPosition = (leadInTime - Options.getMusicOffset()) * -1; // render approach circles during song lead-in
// countdown // countdown
if (osu.countdown > 0) { if (beatmap.countdown > 0) {
float speedModifier = GameMod.getSpeedMultiplier() * playbackSpeed.getModifier(); float speedModifier = GameMod.getSpeedMultiplier() * playbackSpeed.getModifier();
timeDiff = firstObjectTime - trackPosition; timeDiff = firstObjectTime - trackPosition;
if (timeDiff >= 500 * speedModifier && timeDiff < 3000 * speedModifier) { if (timeDiff >= 500 * speedModifier && timeDiff < 3000 * speedModifier) {
@ -667,11 +667,11 @@ public class Game extends BasicGameState {
replayFrames.getFirst().setTimeDiff(replaySkipTime * -1); replayFrames.getFirst().setTimeDiff(replaySkipTime * -1);
replayFrames.addFirst(ReplayFrame.getStartFrame(replaySkipTime)); replayFrames.addFirst(ReplayFrame.getStartFrame(replaySkipTime));
replayFrames.addFirst(ReplayFrame.getStartFrame(0)); replayFrames.addFirst(ReplayFrame.getStartFrame(0));
Replay r = data.getReplay(replayFrames.toArray(new ReplayFrame[replayFrames.size()]), osu); Replay r = data.getReplay(replayFrames.toArray(new ReplayFrame[replayFrames.size()]), beatmap);
if (r != null && !unranked) if (r != null && !unranked)
r.save(); r.save();
} }
ScoreData score = data.getScoreData(osu); ScoreData score = data.getScoreData(beatmap);
// add score to database // add score to database
if (!unranked && !isReplay) if (!unranked && !isReplay)
@ -683,8 +683,8 @@ public class Game extends BasicGameState {
} }
// timing points // timing points
if (timingPointIndex < osu.timingPoints.size()) { if (timingPointIndex < beatmap.timingPoints.size()) {
TimingPoint timingPoint = osu.timingPoints.get(timingPointIndex); TimingPoint timingPoint = beatmap.timingPoints.get(timingPointIndex);
if (trackPosition >= timingPoint.getTime()) { if (trackPosition >= timingPoint.getTime()) {
setBeatLength(timingPoint, true); setBeatLength(timingPoint, true);
timingPointIndex++; timingPointIndex++;
@ -692,12 +692,12 @@ public class Game extends BasicGameState {
} }
// song beginning // song beginning
if (objectIndex == 0 && trackPosition < osu.objects[0].getTime()) if (objectIndex == 0 && trackPosition < beatmap.objects[0].getTime())
return; // nothing to do here return; // nothing to do here
// break periods // break periods
if (osu.breaks != null && breakIndex < osu.breaks.size()) { if (beatmap.breaks != null && breakIndex < beatmap.breaks.size()) {
int breakValue = osu.breaks.get(breakIndex); int breakValue = beatmap.breaks.get(breakIndex);
if (breakTime > 0) { // in a break period if (breakTime > 0) { // in a break period
if (trackPosition < breakValue) if (trackPosition < breakValue)
return; return;
@ -749,10 +749,10 @@ 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)
boolean keyPressed = keys != ReplayFrame.KEY_NONE; boolean keyPressed = keys != ReplayFrame.KEY_NONE;
while (objectIndex < hitObjects.length && trackPosition > osu.objects[objectIndex].getTime()) { while (objectIndex < hitObjects.length && trackPosition > beatmap.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 < hitObjects.length && boolean overlap = (objectIndex + 1 < hitObjects.length &&
trackPosition > osu.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_300]); trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_300]);
// update hit object and check completion status // update hit object and check completion status
if (hitObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition)) if (hitObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition))
@ -791,7 +791,7 @@ public class Game extends BasicGameState {
} }
// pause game // pause game
if (pauseTime < 0 && breakTime <= 0 && trackPosition >= osu.objects[0].getTime()) { if (pauseTime < 0 && breakTime <= 0 && trackPosition >= beatmap.objects[0].getTime()) {
pausedMouseX = mouseX; pausedMouseX = mouseX;
pausedMouseY = mouseY; pausedMouseY = mouseY;
pausePulse = 0f; pausePulse = 0f;
@ -808,7 +808,7 @@ public class Game extends BasicGameState {
// restart // restart
if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) { if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
try { try {
if (trackPosition < osu.objects[0].getTime()) if (trackPosition < beatmap.objects[0].getTime())
retries--; // don't count this retry (cancel out later increment) retries--; // don't count this retry (cancel out later increment)
restart = Restart.MANUAL; restart = Restart.MANUAL;
enter(container, game); enter(container, game);
@ -835,7 +835,7 @@ public class Game extends BasicGameState {
// load checkpoint // load checkpoint
if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) { if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
int checkpoint = Options.getCheckpoint(); int checkpoint = Options.getCheckpoint();
if (checkpoint == 0 || checkpoint > osu.endTime) if (checkpoint == 0 || checkpoint > beatmap.endTime)
break; // invalid checkpoint break; // invalid checkpoint
try { try {
restart = Restart.MANUAL; restart = Restart.MANUAL;
@ -852,10 +852,10 @@ public class Game extends BasicGameState {
MusicController.setPosition(checkpoint); MusicController.setPosition(checkpoint);
MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier()); MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier());
while (objectIndex < hitObjects.length && while (objectIndex < hitObjects.length &&
osu.objects[objectIndex++].getTime() <= checkpoint) beatmap.objects[objectIndex++].getTime() <= checkpoint)
; ;
objectIndex--; objectIndex--;
lastReplayTime = osu.objects[objectIndex].getTime(); lastReplayTime = beatmap.objects[objectIndex].getTime();
} catch (SlickException e) { } catch (SlickException e) {
ErrorHandler.error("Failed to load checkpoint.", e, false); ErrorHandler.error("Failed to load checkpoint.", e, false);
} }
@ -905,7 +905,7 @@ public class Game extends BasicGameState {
// mouse wheel: pause the game // mouse wheel: pause the game
if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) { if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) {
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
if (pauseTime < 0 && breakTime <= 0 && trackPosition >= osu.objects[0].getTime()) { if (pauseTime < 0 && breakTime <= 0 && trackPosition >= beatmap.objects[0].getTime()) {
pausedMouseX = x; pausedMouseX = x;
pausedMouseY = y; pausedMouseY = y;
pausePulse = 0f; pausePulse = 0f;
@ -1021,8 +1021,8 @@ public class Game extends BasicGameState {
throws SlickException { throws SlickException {
UI.enter(); UI.enter();
if (osu == null || osu.objects == null) if (beatmap == null || beatmap.objects == null)
throw new RuntimeException("Running game with no OsuFile loaded."); throw new RuntimeException("Running game with no beatmap loaded.");
// grab the mouse (not working for touchscreen) // grab the mouse (not working for touchscreen)
// container.setMouseGrabbed(true); // container.setMouseGrabbed(true);
@ -1044,8 +1044,8 @@ public class Game extends BasicGameState {
resetGameData(); resetGameData();
// load the first timingPoint for stacking // load the first timingPoint for stacking
if (!osu.timingPoints.isEmpty()) { if (!beatmap.timingPoints.isEmpty()) {
TimingPoint timingPoint = osu.timingPoints.get(0); TimingPoint timingPoint = beatmap.timingPoints.get(0);
if (!timingPoint.isInherited()) { if (!timingPoint.isInherited()) {
setBeatLength(timingPoint, true); setBeatLength(timingPoint, true);
timingPointIndex++; timingPointIndex++;
@ -1053,20 +1053,20 @@ public class Game extends BasicGameState {
} }
// initialize object maps // initialize object maps
for (int i = 0; i < osu.objects.length; i++) { for (int i = 0; i < beatmap.objects.length; i++) {
OsuHitObject hitObject = osu.objects[i]; OsuHitObject hitObject = beatmap.objects[i];
// is this the last note in the combo? // is this the last note in the combo?
boolean comboEnd = false; boolean comboEnd = false;
if (i + 1 < osu.objects.length && osu.objects[i + 1].isNewCombo()) if (i + 1 < beatmap.objects.length && beatmap.objects[i + 1].isNewCombo())
comboEnd = true; comboEnd = true;
Color color = osu.combo[hitObject.getComboIndex()]; Color color = beatmap.combo[hitObject.getComboIndex()];
// pass beatLength to hit objects // pass beatLength to hit objects
int hitObjectTime = hitObject.getTime(); int hitObjectTime = hitObject.getTime();
while (timingPointIndex < osu.timingPoints.size()) { while (timingPointIndex < beatmap.timingPoints.size()) {
TimingPoint timingPoint = osu.timingPoints.get(timingPointIndex); TimingPoint timingPoint = beatmap.timingPoints.get(timingPointIndex);
if (timingPoint.getTime() > hitObjectTime) if (timingPoint.getTime() > hitObjectTime)
break; break;
setBeatLength(timingPoint, false); setBeatLength(timingPoint, false);
@ -1095,8 +1095,8 @@ public class Game extends BasicGameState {
// load the first timingPoint // load the first timingPoint
timingPointIndex = 0; timingPointIndex = 0;
beatLengthBase = beatLength = 1; beatLengthBase = beatLength = 1;
if (!osu.timingPoints.isEmpty()) { if (!beatmap.timingPoints.isEmpty()) {
TimingPoint timingPoint = osu.timingPoints.get(0); TimingPoint timingPoint = beatmap.timingPoints.get(0);
if (!timingPoint.isInherited()) { if (!timingPoint.isInherited()) {
setBeatLength(timingPoint, true); setBeatLength(timingPoint, true);
timingPointIndex++; timingPointIndex++;
@ -1140,7 +1140,7 @@ public class Game extends BasicGameState {
replayFrames.add(new ReplayFrame(0, 0, input.getMouseX(), input.getMouseY(), 0)); replayFrames.add(new ReplayFrame(0, 0, input.getMouseX(), input.getMouseY(), 0));
} }
leadInTime = osu.audioLeadIn + approachTime; leadInTime = beatmap.audioLeadIn + approachTime;
restart = Restart.FALSE; restart = Restart.FALSE;
// needs to play before setting position to resume without lag later // needs to play before setting position to resume without lag later
@ -1181,27 +1181,27 @@ public class Game extends BasicGameState {
private void drawHitObjects(Graphics g, int trackPosition) { private void drawHitObjects(Graphics g, int trackPosition) {
// include previous object in follow points // include previous object in follow points
int lastObjectIndex = -1; int lastObjectIndex = -1;
if (objectIndex > 0 && objectIndex < osu.objects.length && if (objectIndex > 0 && objectIndex < beatmap.objects.length &&
trackPosition < osu.objects[objectIndex].getTime() && !osu.objects[objectIndex - 1].isSpinner()) trackPosition < beatmap.objects[objectIndex].getTime() && !beatmap.objects[objectIndex - 1].isSpinner())
lastObjectIndex = objectIndex - 1; lastObjectIndex = objectIndex - 1;
// 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 index = objectIndex; index < hitObjects.length && osu.objects[index].getTime() < trackPosition + approachTime; index++) { for (int index = objectIndex; index < hitObjects.length && beatmap.objects[index].getTime() < trackPosition + approachTime; index++) {
stack.add(index); stack.add(index);
// draw follow points // draw follow points
if (!Options.isFollowPointEnabled()) if (!Options.isFollowPointEnabled())
continue; continue;
if (osu.objects[index].isSpinner()) { if (beatmap.objects[index].isSpinner()) {
lastObjectIndex = -1; lastObjectIndex = -1;
continue; continue;
} }
if (lastObjectIndex != -1 && !osu.objects[index].isNewCombo()) { if (lastObjectIndex != -1 && !beatmap.objects[index].isNewCombo()) {
// calculate points // calculate points
final int followPointInterval = container.getHeight() / 14; final int followPointInterval = container.getHeight() / 14;
int lastObjectEndTime = hitObjects[lastObjectIndex].getEndTime() + 1; int lastObjectEndTime = hitObjects[lastObjectIndex].getEndTime() + 1;
int objectStartTime = osu.objects[index].getTime(); int objectStartTime = beatmap.objects[index].getTime();
float[] startXY = hitObjects[lastObjectIndex].getPointAt(lastObjectEndTime); float[] startXY = hitObjects[lastObjectIndex].getPointAt(lastObjectEndTime);
float[] endXY = hitObjects[index].getPointAt(objectStartTime); float[] endXY = hitObjects[index].getPointAt(objectStartTime);
float xDiff = endXY[0] - startXY[0]; float xDiff = endXY[0] - startXY[0];
@ -1257,23 +1257,23 @@ public class Game extends BasicGameState {
} }
/** /**
* Loads all required data from an OsuFile. * Loads all required data from a beatmap.
* @param osu the OsuFile to load * @param beatmap the beatmap to load
*/ */
public void loadOsuFile(OsuFile osu) { public void loadBeatmap(Beatmap beatmap) {
this.osu = osu; this.beatmap = beatmap;
Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString())); Display.setTitle(String.format("%s - %s", game.getTitle(), beatmap.toString()));
if (osu.timingPoints == null || osu.combo == null) if (beatmap.timingPoints == null || beatmap.combo == null)
OsuDB.load(osu, OsuDB.LOAD_ARRAY); BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY);
OsuParser.parseHitObjects(osu); OsuParser.parseHitObjects(beatmap);
HitSound.setDefaultSampleSet(osu.sampleSet); HitSound.setDefaultSampleSet(beatmap.sampleSet);
} }
/** /**
* Resets all game data and structures. * Resets all game data and structures.
*/ */
public void resetGameData() { public void resetGameData() {
hitObjects = new HitObject[osu.objects.length]; hitObjects = new HitObject[beatmap.objects.length];
data.clear(); data.clear();
objectIndex = 0; objectIndex = 0;
breakIndex = 0; breakIndex = 0;
@ -1308,7 +1308,7 @@ public class Game extends BasicGameState {
* @return true if skipped, false otherwise * @return true if skipped, false otherwise
*/ */
private synchronized boolean skipIntro() { private synchronized boolean skipIntro() {
int firstObjectTime = osu.objects[0].getTime(); int firstObjectTime = beatmap.objects[0].getTime();
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
if (objectIndex == 0 && trackPosition < firstObjectTime - SKIP_OFFSET) { if (objectIndex == 0 && trackPosition < firstObjectTime - SKIP_OFFSET) {
if (isLeadIn()) { if (isLeadIn()) {
@ -1336,7 +1336,7 @@ public class Game extends BasicGameState {
int height = container.getHeight(); int height = container.getHeight();
// set images // set images
File parent = osu.getFile().getParentFile(); File parent = beatmap.getFile().getParentFile();
for (GameImage img : GameImage.values()) { for (GameImage img : GameImage.values()) {
if (img.isSkinnable()) { if (img.isSkinnable()) {
img.setDefaultImage(); img.setDefaultImage();
@ -1365,10 +1365,10 @@ public class Game extends BasicGameState {
private void setMapModifiers() { private void setMapModifiers() {
// map-based properties, re-initialized each game // map-based properties, re-initialized each game
float multiplier = GameMod.getDifficultyMultiplier(); float multiplier = GameMod.getDifficultyMultiplier();
float circleSize = Math.min(osu.circleSize * multiplier, 10f); float circleSize = Math.min(beatmap.circleSize * multiplier, 10f);
float approachRate = Math.min(osu.approachRate * multiplier, 10f); float approachRate = Math.min(beatmap.approachRate * multiplier, 10f);
float overallDifficulty = Math.min(osu.overallDifficulty * multiplier, 10f); float overallDifficulty = Math.min(beatmap.overallDifficulty * multiplier, 10f);
float HPDrainRate = Math.min(osu.HPDrainRate * multiplier, 10f); float HPDrainRate = Math.min(beatmap.HPDrainRate * multiplier, 10f);
// fixed difficulty overrides // fixed difficulty overrides
if (Options.getFixedCS() > 0f) if (Options.getFixedCS() > 0f)
@ -1387,7 +1387,7 @@ public class Game extends BasicGameState {
// initialize objects // initialize objects
Circle.init(container, circleSize); Circle.init(container, circleSize);
Slider.init(container, circleSize, osu); Slider.init(container, circleSize, beatmap);
Spinner.init(container); Spinner.init(container);
// approachRate (hit object approach time) // approachRate (hit object approach time)
@ -1522,7 +1522,7 @@ public class Game extends BasicGameState {
if (objectIndex >= hitObjects.length) // nothing to do here if (objectIndex >= hitObjects.length) // nothing to do here
return; return;
OsuHitObject hitObject = osu.objects[objectIndex]; OsuHitObject hitObject = beatmap.objects[objectIndex];
// circles // circles
if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(x, y, trackPosition)) if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(x, y, trackPosition))
@ -1582,14 +1582,14 @@ public class Game extends BasicGameState {
return; return;
int width = container.getWidth(), height = container.getHeight(); int width = container.getWidth(), height = container.getHeight();
boolean firstObject = (objectIndex == 0 && trackPosition < osu.objects[0].getTime()); boolean firstObject = (objectIndex == 0 && trackPosition < beatmap.objects[0].getTime());
if (isLeadIn()) { if (isLeadIn()) {
// lead-in: expand area // lead-in: expand area
float progress = Math.max((float) (leadInTime - osu.audioLeadIn) / approachTime, 0f); float progress = Math.max((float) (leadInTime - beatmap.audioLeadIn) / approachTime, 0f);
flashlightRadius = width - (int) ((width - (height * 2 / 3)) * progress); flashlightRadius = width - (int) ((width - (height * 2 / 3)) * progress);
} else if (firstObject) { } else if (firstObject) {
// before first object: shrink area // before first object: shrink area
int timeDiff = osu.objects[0].getTime() - trackPosition; int timeDiff = beatmap.objects[0].getTime() - trackPosition;
flashlightRadius = width; flashlightRadius = width;
if (timeDiff < approachTime) { if (timeDiff < approachTime) {
float progress = (float) timeDiff / approachTime; float progress = (float) timeDiff / approachTime;
@ -1605,10 +1605,10 @@ public class Game extends BasicGameState {
targetRadius = height / 2; targetRadius = height / 2;
else else
targetRadius = height / 3; targetRadius = height / 3;
if (osu.breaks != null && breakIndex < osu.breaks.size() && breakTime > 0) { if (beatmap.breaks != null && breakIndex < beatmap.breaks.size() && breakTime > 0) {
// breaks: expand at beginning, shrink at end // breaks: expand at beginning, shrink at end
flashlightRadius = targetRadius; flashlightRadius = targetRadius;
int endTime = osu.breaks.get(breakIndex); int endTime = beatmap.breaks.get(breakIndex);
int breakLength = endTime - breakTime; int breakLength = endTime - breakTime;
if (breakLength > approachTime * 3) { if (breakLength > approachTime * 3) {
float progress = 1f; float progress = 1f;
@ -1642,7 +1642,7 @@ public class Game extends BasicGameState {
private void calculateStacks() { private void calculateStacks() {
// reverse pass for stack calculation // reverse pass for stack calculation
for (int i = hitObjects.length - 1; i > 0; i--) { for (int i = hitObjects.length - 1; i > 0; i--) {
OsuHitObject hitObjectI = osu.objects[i]; OsuHitObject hitObjectI = beatmap.objects[i];
// already calculated // already calculated
if (hitObjectI.getStack() != 0 || hitObjectI.isSpinner()) if (hitObjectI.getStack() != 0 || hitObjectI.isSpinner())
@ -1650,12 +1650,12 @@ public class Game extends BasicGameState {
// search for hit objects in stack // search for hit objects in stack
for (int n = i - 1; n >= 0; n--) { for (int n = i - 1; n >= 0; n--) {
OsuHitObject hitObjectN = osu.objects[n]; OsuHitObject hitObjectN = beatmap.objects[n];
if (hitObjectN.isSpinner()) if (hitObjectN.isSpinner())
continue; continue;
// check if in range stack calculation // check if in range stack calculation
float timeI = hitObjectI.getTime() - (STACK_TIMEOUT * osu.stackLeniency); float timeI = hitObjectI.getTime() - (STACK_TIMEOUT * beatmap.stackLeniency);
float timeN = hitObjectN.isSlider() ? hitObjects[n].getEndTime() : hitObjectN.getTime(); float timeN = hitObjectN.isSlider() ? hitObjects[n].getEndTime() : hitObjectN.getTime();
if (timeI > timeN) if (timeI > timeN)
break; break;
@ -1671,7 +1671,7 @@ public class Game extends BasicGameState {
if (distance < STACK_LENIENCE * OsuHitObject.getXMultiplier()) { if (distance < STACK_LENIENCE * OsuHitObject.getXMultiplier()) {
int offset = hitObjectI.getStack() - hitObjectN.getStack() + 1; int offset = hitObjectI.getStack() - hitObjectN.getStack() + 1;
for (int j = n + 1; j <= i; j++) { for (int j = n + 1; j <= i; j++) {
OsuHitObject hitObjectJ = osu.objects[j]; OsuHitObject hitObjectJ = beatmap.objects[j];
p1 = hitObjects[j].getPointAt(hitObjectJ.getTime()); p1 = hitObjects[j].getPointAt(hitObjectJ.getTime());
distance = Utils.distance(p1[0], p1[1], p2[0], p2[1]); distance = Utils.distance(p1[0], p1[1], p2[0], p2[1]);
@ -1697,7 +1697,7 @@ public class Game extends BasicGameState {
// update hit object positions // update hit object positions
for (int i = 0; i < hitObjects.length; i++) { for (int i = 0; i < hitObjects.length; i++) {
if (osu.objects[i].getStack() != 0) if (beatmap.objects[i].getStack() != 0)
hitObjects[i].updatePosition(); hitObjects[i].updatePosition();
} }
} }

View File

@ -132,7 +132,7 @@ public class GamePauseMenu extends BasicGameState {
if (gameState.getRestart() == Game.Restart.LOSE) { if (gameState.getRestart() == Game.Restart.LOSE) {
SoundController.playSound(SoundEffect.MENUBACK); SoundController.playSound(SoundEffect.MENUBACK);
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad(); ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad();
MusicController.playAt(MusicController.getOsuFile().previewTime, true); MusicController.playAt(MusicController.getBeatmap().previewTime, true);
UI.resetCursor(); UI.resetCursor();
game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
} else { } else {
@ -183,7 +183,7 @@ public class GamePauseMenu extends BasicGameState {
SoundController.playSound(SoundEffect.MENUBACK); SoundController.playSound(SoundEffect.MENUBACK);
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad(); ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad();
if (loseState) if (loseState)
MusicController.playAt(MusicController.getOsuFile().previewTime, true); MusicController.playAt(MusicController.getBeatmap().previewTime, true);
else else
MusicController.resume(); MusicController.resume();
UI.resetCursor(); UI.resetCursor();

View File

@ -23,12 +23,12 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.MenuButton; import itdelatrisu.opsu.MenuButton;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.UI; import itdelatrisu.opsu.UI;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController; 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 itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.replay.Replay; import itdelatrisu.opsu.replay.Replay;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -102,14 +102,14 @@ public class GameRanking extends BasicGameState {
int width = container.getWidth(); int width = container.getWidth();
int height = container.getHeight(); int height = container.getHeight();
OsuFile osu = MusicController.getOsuFile(); Beatmap beatmap = MusicController.getBeatmap();
// background // background
if (!osu.drawBG(width, height, 0.7f, true)) if (!beatmap.drawBG(width, height, 0.7f, true))
GameImage.PLAYFIELD.getImage().draw(0,0); GameImage.PLAYFIELD.getImage().draw(0,0);
// ranking screen elements // ranking screen elements
data.drawRankingElements(g, osu); data.drawRankingElements(g, beatmap);
// buttons // buttons
replayButton.draw(); replayButton.draw();
@ -201,8 +201,8 @@ public class GameRanking extends BasicGameState {
} }
if (returnToGame) { if (returnToGame) {
OsuFile osu = MusicController.getOsuFile(); Beatmap beatmap = MusicController.getBeatmap();
gameState.loadOsuFile(osu); gameState.loadBeatmap(beatmap);
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));
return; return;

View File

@ -24,14 +24,14 @@ import itdelatrisu.opsu.MenuButton;
import itdelatrisu.opsu.MenuButton.Expand; import itdelatrisu.opsu.MenuButton.Expand;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.OsuGroupNode;
import itdelatrisu.opsu.UI; import itdelatrisu.opsu.UI;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController; 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 itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.states.ButtonMenu.MenuState; import itdelatrisu.opsu.states.ButtonMenu.MenuState;
@ -91,7 +91,7 @@ public class MainMenu extends BasicGameState {
private MenuButton updateButton; private MenuButton updateButton;
/** Application start time, for drawing the total running time. */ /** Application start time, for drawing the total running time. */
private long osuStartTime; private long programStartTime;
/** Indexes of previous songs. */ /** Indexes of previous songs. */
private Stack<Integer> previous; private Stack<Integer> previous;
@ -127,7 +127,7 @@ public class MainMenu extends BasicGameState {
this.game = game; this.game = game;
this.input = container.getInput(); this.input = container.getInput();
osuStartTime = System.currentTimeMillis(); programStartTime = System.currentTimeMillis();
previous = new Stack<Integer>(); previous = new Stack<Integer>();
int width = container.getWidth(); int width = container.getWidth();
@ -199,9 +199,9 @@ public class MainMenu extends BasicGameState {
int height = container.getHeight(); int height = container.getHeight();
// draw background // draw background
OsuFile osu = MusicController.getOsuFile(); Beatmap beatmap = MusicController.getBeatmap();
if (Options.isDynamicBackgroundEnabled() && if (Options.isDynamicBackgroundEnabled() &&
osu != null && osu.drawBG(width, height, bgAlpha, true)) beatmap != null && beatmap.drawBG(width, height, bgAlpha, true))
; ;
else { else {
Image bg = GameImage.MENU_BG.getImage(); Image bg = GameImage.MENU_BG.getImage();
@ -240,7 +240,7 @@ public class MainMenu extends BasicGameState {
g.setColor((musicPositionBarContains(mouseX, mouseY)) ? BG_HOVER : BG_NORMAL); g.setColor((musicPositionBarContains(mouseX, mouseY)) ? BG_HOVER : BG_NORMAL);
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4); g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
g.setColor(Color.white); g.setColor(Color.white);
if (!MusicController.isTrackLoading() && osu != null) { if (!MusicController.isTrackLoading() && beatmap != null) {
float musicBarPosition = Math.min((float) MusicController.getPosition() / MusicController.getDuration(), 1f); float musicBarPosition = Math.min((float) MusicController.getPosition() / MusicController.getDuration(), 1f);
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth * musicBarPosition, musicBarHeight, 4); g.fillRoundRect(musicBarX, musicBarY, musicBarWidth * musicBarPosition, musicBarHeight, 4);
} }
@ -274,17 +274,17 @@ public class MainMenu extends BasicGameState {
g.setFont(Utils.FONT_MEDIUM); g.setFont(Utils.FONT_MEDIUM);
float lineHeight = Utils.FONT_MEDIUM.getLineHeight() * 0.925f; float lineHeight = Utils.FONT_MEDIUM.getLineHeight() * 0.925f;
g.drawString(String.format("Loaded %d songs and %d beatmaps.", g.drawString(String.format("Loaded %d songs and %d beatmaps.",
OsuGroupList.get().getMapSetCount(), OsuGroupList.get().getMapCount()), marginX, topMarginY); BeatmapSetList.get().getMapSetCount(), BeatmapSetList.get().getMapCount()), marginX, topMarginY);
if (MusicController.isTrackLoading()) if (MusicController.isTrackLoading())
g.drawString("Track loading...", marginX, topMarginY + lineHeight); g.drawString("Track loading...", marginX, topMarginY + lineHeight);
else if (MusicController.trackExists()) { else if (MusicController.trackExists()) {
if (Options.useUnicodeMetadata()) // load glyphs if (Options.useUnicodeMetadata()) // load glyphs
Utils.loadGlyphs(Utils.FONT_MEDIUM, osu.titleUnicode, osu.artistUnicode); Utils.loadGlyphs(Utils.FONT_MEDIUM, beatmap.titleUnicode, beatmap.artistUnicode);
g.drawString((MusicController.isPlaying()) ? "Now Playing:" : "Paused:", marginX, topMarginY + lineHeight); g.drawString((MusicController.isPlaying()) ? "Now Playing:" : "Paused:", marginX, topMarginY + lineHeight);
g.drawString(String.format("%s: %s", osu.getArtist(), osu.getTitle()), marginX + 25, topMarginY + (lineHeight * 2)); g.drawString(String.format("%s: %s", beatmap.getArtist(), beatmap.getTitle()), marginX + 25, topMarginY + (lineHeight * 2));
} }
g.drawString(String.format("opsu! has been running for %s.", g.drawString(String.format("opsu! has been running for %s.",
Utils.getTimeString((int) (System.currentTimeMillis() - osuStartTime) / 1000)), Utils.getTimeString((int) (System.currentTimeMillis() - programStartTime) / 1000)),
marginX, height - bottomMarginY - (lineHeight * 2)); marginX, height - bottomMarginY - (lineHeight * 2));
g.drawString(String.format("It is currently %s.", g.drawString(String.format("It is currently %s.",
new SimpleDateFormat("h:mm a").format(new Date())), new SimpleDateFormat("h:mm a").format(new Date())),
@ -455,7 +455,7 @@ public class MainMenu extends BasicGameState {
} else if (musicPrevious.contains(x, y)) { } else if (musicPrevious.contains(x, y)) {
if (!previous.isEmpty()) { if (!previous.isEmpty()) {
SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU); SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
menu.setFocus(OsuGroupList.get().getBaseNode(previous.pop()), -1, true, false); menu.setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
if (Options.isDynamicBackgroundEnabled()) if (Options.isDynamicBackgroundEnabled())
bgAlpha = 0f; bgAlpha = 0f;
} else } else
@ -603,10 +603,10 @@ public class MainMenu extends BasicGameState {
private void nextTrack() { private void nextTrack() {
boolean isTheme = MusicController.isThemePlaying(); boolean isTheme = MusicController.isThemePlaying();
SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU); SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
OsuGroupNode node = menu.setFocus(OsuGroupList.get().getRandomNode(), -1, true, false); BeatmapSetNode node = menu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false);
boolean sameAudio = false; boolean sameAudio = false;
if (node != null) { if (node != null) {
sameAudio = MusicController.getOsuFile().audioFilename.equals(node.osuFiles.get(0).audioFilename); sameAudio = MusicController.getBeatmap().audioFilename.equals(node.beatmaps.get(0).audioFilename);
if (!isTheme && !sameAudio) if (!isTheme && !sameAudio)
previous.add(node.index); previous.add(node.index);
} }
@ -619,7 +619,7 @@ public class MainMenu extends BasicGameState {
*/ */
private void enterSongMenu() { private void enterSongMenu() {
int state = Opsu.STATE_SONGMENU; int state = Opsu.STATE_SONGMENU;
if (OsuGroupList.get().getMapSetCount() == 0) { if (BeatmapSetList.get().getMapSetCount() == 0) {
((DownloadsMenu) game.getState(Opsu.STATE_DOWNLOADSMENU)).notifyOnLoad("Download some beatmaps to get started!"); ((DownloadsMenu) game.getState(Opsu.STATE_DOWNLOADSMENU)).notifyOnLoad("Download some beatmaps to get started!");
state = Opsu.STATE_DOWNLOADSMENU; state = Opsu.STATE_DOWNLOADSMENU;
} }

View File

@ -25,9 +25,6 @@ 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.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.OsuGroupNode;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.OszUnpacker; import itdelatrisu.opsu.OszUnpacker;
import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.ScoreData;
@ -38,7 +35,10 @@ import itdelatrisu.opsu.audio.MultiClip;
import itdelatrisu.opsu.audio.MusicController; 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 itdelatrisu.opsu.db.OsuDB; import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
import itdelatrisu.opsu.db.BeatmapDB;
import itdelatrisu.opsu.db.ScoreDB; import itdelatrisu.opsu.db.ScoreDB;
import itdelatrisu.opsu.states.ButtonMenu.MenuState; import itdelatrisu.opsu.states.ButtonMenu.MenuState;
@ -91,28 +91,28 @@ public class SongMenu extends BasicGameState {
/** Line width of the header/footer divider. */ /** Line width of the header/footer divider. */
private static final int DIVIDER_LINE_WIDTH = 4; private static final int DIVIDER_LINE_WIDTH = 4;
/** Song node class representing an OsuGroupNode and file index. */ /** Song node class representing an BeatmapSetNode and file index. */
private static class SongNode { private static class SongNode {
/** Song node. */ /** Song node. */
private OsuGroupNode node; private BeatmapSetNode node;
/** File index. */ /** File index. */
private int index; private int index;
/** /**
* Constructor. * Constructor.
* @param node the OsuGroupNode * @param node the BeatmapSetNode
* @param index the file index * @param index the file index
*/ */
public SongNode(OsuGroupNode node, int index) { public SongNode(BeatmapSetNode node, int index) {
this.node = node; this.node = node;
this.index = index; this.index = index;
} }
/** /**
* Returns the associated OsuGroupNode. * Returns the associated BeatmapSetNode.
*/ */
public OsuGroupNode getNode() { return node; } public BeatmapSetNode getNode() { return node; }
/** /**
* Returns the associated file index. * Returns the associated file index.
@ -121,10 +121,10 @@ public class SongMenu extends BasicGameState {
} }
/** Current start node (topmost menu entry). */ /** Current start node (topmost menu entry). */
private OsuGroupNode startNode; private BeatmapSetNode startNode;
/** Current focused (selected) node. */ /** Current focused (selected) node. */
private OsuGroupNode focusNode; private BeatmapSetNode focusNode;
/** The base node of the previous focus node. */ /** The base node of the previous focus node. */
private SongNode oldFocusNode = null; private SongNode oldFocusNode = null;
@ -172,7 +172,7 @@ public class SongMenu extends BasicGameState {
private MenuState stateAction; private MenuState stateAction;
/** If non-null, the node that stateAction acts upon. */ /** If non-null, the node that stateAction acts upon. */
private OsuGroupNode stateActionNode; private BeatmapSetNode stateActionNode;
/** If non-null, the score data that stateAction acts upon. */ /** If non-null, the score data that stateAction acts upon. */
private ScoreData stateActionScore; private ScoreData stateActionScore;
@ -292,13 +292,13 @@ public class SongMenu extends BasicGameState {
// background // background
if (focusNode != null) { if (focusNode != null) {
OsuFile focusNodeOsu = focusNode.osuFiles.get(focusNode.osuFileIndex); Beatmap focusNodeBeatmap = focusNode.beatmaps.get(focusNode.beatmapIndex);
if (!focusNodeOsu.drawBG(width, height, 1.0f, true)) if (!focusNodeBeatmap.drawBG(width, height, 1.0f, true))
GameImage.PLAYFIELD.getImage().draw(); GameImage.PLAYFIELD.getImage().draw();
} }
// song buttons // song buttons
OsuGroupNode node = startNode; BeatmapSetNode node = startNode;
int songButtonIndex = 0; int songButtonIndex = 0;
if (node != null && node.prev != null) { if (node != null && node.prev != null) {
node = node.prev; node = node.prev;
@ -339,8 +339,8 @@ public class SongMenu extends BasicGameState {
if (songInfo == null) { if (songInfo == null) {
songInfo = focusNode.getInfo(); songInfo = focusNode.getInfo();
if (Options.useUnicodeMetadata()) { // load glyphs if (Options.useUnicodeMetadata()) { // load glyphs
OsuFile osu = focusNode.osuFiles.get(0); Beatmap beatmap = focusNode.beatmaps.get(0);
Utils.loadGlyphs(Utils.FONT_LARGE, osu.titleUnicode, osu.artistUnicode); Utils.loadGlyphs(Utils.FONT_LARGE, beatmap.titleUnicode, beatmap.artistUnicode);
} }
} }
marginX += 5; marginX += 5;
@ -437,14 +437,14 @@ public class SongMenu extends BasicGameState {
// scroll bar // scroll bar
if (focusNode != null) { if (focusNode != null) {
int focusNodes = focusNode.osuFiles.size(); int focusNodes = focusNode.beatmaps.size();
int totalNodes = OsuGroupList.get().size() + focusNodes - 1; int totalNodes = BeatmapSetList.get().size() + focusNodes - 1;
if (totalNodes > MAX_SONG_BUTTONS) { if (totalNodes > MAX_SONG_BUTTONS) {
int startIndex = startNode.index; int startIndex = startNode.index;
if (startNode.index > focusNode.index) if (startNode.index > focusNode.index)
startIndex += focusNodes; startIndex += focusNodes;
else if (startNode.index == focusNode.index) else if (startNode.index == focusNode.index)
startIndex += startNode.osuFileIndex; startIndex += startNode.beatmapIndex;
UI.drawScrollbar(g, startIndex, totalNodes, MAX_SONG_BUTTONS, UI.drawScrollbar(g, startIndex, totalNodes, MAX_SONG_BUTTONS,
width, headerY + DIVIDER_LINE_WIDTH / 2, 0, buttonOffset - DIVIDER_LINE_WIDTH * 1.5f, buttonOffset, width, headerY + DIVIDER_LINE_WIDTH / 2, 0, buttonOffset - DIVIDER_LINE_WIDTH * 1.5f, buttonOffset,
Utils.COLOR_BLACK_ALPHA, Color.white, true); Utils.COLOR_BLACK_ALPHA, Color.white, true);
@ -501,9 +501,9 @@ public class SongMenu extends BasicGameState {
// store the start/focus nodes // store the start/focus nodes
if (focusNode != null) if (focusNode != null)
oldFocusNode = new SongNode(OsuGroupList.get().getBaseNode(focusNode.index), focusNode.osuFileIndex); oldFocusNode = new SongNode(BeatmapSetList.get().getBaseNode(focusNode.index), focusNode.beatmapIndex);
if (OsuGroupList.get().search(search.getText())) { if (BeatmapSetList.get().search(search.getText())) {
// reset song stack // reset song stack
randomStack = new Stack<SongNode>(); randomStack = new Stack<SongNode>();
@ -515,19 +515,19 @@ public class SongMenu extends BasicGameState {
startNode = focusNode = null; startNode = focusNode = null;
scoreMap = null; scoreMap = null;
focusScores = null; focusScores = null;
if (OsuGroupList.get().size() > 0) { if (BeatmapSetList.get().size() > 0) {
OsuGroupList.get().init(); BeatmapSetList.get().init();
if (search.getText().isEmpty()) { // cleared search if (search.getText().isEmpty()) { // cleared search
// use previous start/focus if possible // use previous start/focus if possible
if (oldFocusNode != null) if (oldFocusNode != null)
setFocus(oldFocusNode.getNode(), oldFocusNode.getIndex(), true, true); setFocus(oldFocusNode.getNode(), oldFocusNode.getIndex(), true, true);
else else
setFocus(OsuGroupList.get().getRandomNode(), -1, true, true); setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
} else { } else {
int size = OsuGroupList.get().size(); int size = BeatmapSetList.get().size();
searchResultString = String.format("%d match%s found!", searchResultString = String.format("%d match%s found!",
size, (size == 1) ? "" : "es"); size, (size == 1) ? "" : "es");
setFocus(OsuGroupList.get().getRandomNode(), -1, true, true); setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
} }
oldFocusNode = null; oldFocusNode = null;
} else if (!search.getText().isEmpty()) } else if (!search.getText().isEmpty())
@ -555,9 +555,9 @@ public class SongMenu extends BasicGameState {
// mouse hover // mouse hover
boolean isHover = false; boolean isHover = false;
if (mouseY > headerY && mouseY < footerY) { if (mouseY > headerY && mouseY < footerY) {
OsuGroupNode node = startNode; BeatmapSetNode node = startNode;
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) { for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
float cx = (node.index == OsuGroupList.get().getExpandedIndex()) ? buttonX * 0.9f : buttonX; float cx = (node.index == BeatmapSetList.get().getExpandedIndex()) ? buttonX * 0.9f : buttonX;
if ((mouseX > cx && mouseX < cx + buttonWidth) && if ((mouseX > cx && mouseX < cx + buttonWidth) &&
(mouseY > buttonY + (i * buttonOffset) && mouseY < buttonY + (i * buttonOffset) + buttonHeight)) { (mouseY > buttonY + (i * buttonOffset) && mouseY < buttonY + (i * buttonOffset) + buttonHeight)) {
if (i == hoverIndex) { if (i == hoverIndex) {
@ -641,10 +641,10 @@ public class SongMenu extends BasicGameState {
if (sort != SongSort.getSort()) { if (sort != SongSort.getSort()) {
SongSort.setSort(sort); SongSort.setSort(sort);
SoundController.playSound(SoundEffect.MENUCLICK); SoundController.playSound(SoundEffect.MENUCLICK);
OsuGroupNode oldFocusBase = OsuGroupList.get().getBaseNode(focusNode.index); BeatmapSetNode oldFocusBase = BeatmapSetList.get().getBaseNode(focusNode.index);
int oldFocusFileIndex = focusNode.osuFileIndex; int oldFocusFileIndex = focusNode.beatmapIndex;
focusNode = null; focusNode = null;
OsuGroupList.get().init(); BeatmapSetList.get().init();
setFocus(oldFocusBase, oldFocusFileIndex, true, true); setFocus(oldFocusBase, oldFocusFileIndex, true, true);
} }
return; return;
@ -653,8 +653,8 @@ public class SongMenu extends BasicGameState {
// song buttons // song buttons
if (y > headerY && y < footerY) { if (y > headerY && y < footerY) {
int expandedIndex = OsuGroupList.get().getExpandedIndex(); int expandedIndex = BeatmapSetList.get().getExpandedIndex();
OsuGroupNode node = startNode; BeatmapSetNode node = startNode;
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) { for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
// is button at this index clicked? // is button at this index clicked?
float cx = (node.index == expandedIndex) ? buttonX * 0.9f : buttonX; float cx = (node.index == expandedIndex) ? buttonX * 0.9f : buttonX;
@ -665,7 +665,7 @@ public class SongMenu extends BasicGameState {
// clicked node is already expanded // clicked node is already expanded
if (node.index == expandedIndex) { if (node.index == expandedIndex) {
if (node.osuFileIndex == focusNode.osuFileIndex) { if (node.beatmapIndex == focusNode.beatmapIndex) {
// if already focused, load the beatmap // if already focused, load the beatmap
if (button != Input.MOUSE_RIGHT_BUTTON) if (button != Input.MOUSE_RIGHT_BUTTON)
startGame(); startGame();
@ -730,7 +730,7 @@ public class SongMenu extends BasicGameState {
switch (key) { switch (key) {
case Input.KEY_ESCAPE: case Input.KEY_ESCAPE:
if (reloadThread != null) { if (reloadThread != null) {
// beatmap reloading: stop parsing OsuFiles by sending interrupt to OsuParser // beatmap reloading: stop parsing beatmaps by sending interrupt to OsuParser
reloadThread.interrupt(); reloadThread.interrupt();
} else if (!search.getText().isEmpty()) { } else if (!search.getText().isEmpty()) {
// clear search text // clear search text
@ -761,8 +761,8 @@ public class SongMenu extends BasicGameState {
setFocus(prev.getNode(), prev.getIndex(), true, true); setFocus(prev.getNode(), prev.getIndex(), true, true);
} else { } else {
// random track, add previous to stack // random track, add previous to stack
randomStack.push(new SongNode(OsuGroupList.get().getBaseNode(focusNode.index), focusNode.osuFileIndex)); randomStack.push(new SongNode(BeatmapSetList.get().getBaseNode(focusNode.index), focusNode.beatmapIndex));
setFocus(OsuGroupList.get().getRandomNode(), -1, true, true); setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
} }
break; break;
case Input.KEY_F3: case Input.KEY_F3:
@ -782,7 +782,7 @@ public class SongMenu extends BasicGameState {
break; break;
if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) { if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) {
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
MenuState ms = (focusNode.osuFileIndex == -1 || focusNode.osuFiles.size() == 1) ? MenuState ms = (focusNode.beatmapIndex == -1 || focusNode.beatmaps.size() == 1) ?
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT; MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, focusNode); ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, focusNode);
game.enterState(Opsu.STATE_BUTTONMENU); game.enterState(Opsu.STATE_BUTTONMENU);
@ -816,10 +816,10 @@ public class SongMenu extends BasicGameState {
case Input.KEY_RIGHT: case Input.KEY_RIGHT:
if (focusNode == null) if (focusNode == null)
break; break;
OsuGroupNode next = focusNode.next; BeatmapSetNode next = focusNode.next;
if (next != null) { if (next != null) {
SoundController.playSound(SoundEffect.MENUCLICK); SoundController.playSound(SoundEffect.MENUCLICK);
OsuGroupNode oldStartNode = startNode; BeatmapSetNode oldStartNode = startNode;
float oldHoverOffset = hoverOffset; float oldHoverOffset = hoverOffset;
int oldHoverIndex = hoverIndex; int oldHoverIndex = hoverIndex;
setFocus(next, 0, false, true); setFocus(next, 0, false, true);
@ -832,13 +832,13 @@ public class SongMenu extends BasicGameState {
case Input.KEY_LEFT: case Input.KEY_LEFT:
if (focusNode == null) if (focusNode == null)
break; break;
OsuGroupNode prev = focusNode.prev; BeatmapSetNode prev = focusNode.prev;
if (prev != null) { if (prev != null) {
SoundController.playSound(SoundEffect.MENUCLICK); SoundController.playSound(SoundEffect.MENUCLICK);
OsuGroupNode oldStartNode = startNode; BeatmapSetNode oldStartNode = startNode;
float oldHoverOffset = hoverOffset; float oldHoverOffset = hoverOffset;
int oldHoverIndex = hoverIndex; int oldHoverIndex = hoverIndex;
setFocus(prev, (prev.index == focusNode.index) ? 0 : prev.osuFiles.size() - 1, false, true); setFocus(prev, (prev.index == focusNode.index) ? 0 : prev.beatmaps.size() - 1, false, true);
if (startNode == oldStartNode) { if (startNode == oldStartNode) {
hoverOffset = oldHoverOffset; hoverOffset = oldHoverOffset;
hoverIndex = oldHoverIndex; hoverIndex = oldHoverIndex;
@ -949,13 +949,13 @@ public class SongMenu extends BasicGameState {
randomStack = new Stack<SongNode>(); randomStack = new Stack<SongNode>();
// set focus node if not set (e.g. theme song playing) // set focus node if not set (e.g. theme song playing)
if (focusNode == null && OsuGroupList.get().size() > 0) if (focusNode == null && BeatmapSetList.get().size() > 0)
setFocus(OsuGroupList.get().getRandomNode(), -1, true, true); setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
// reset music track // reset music track
else if (resetTrack) { else if (resetTrack) {
MusicController.pause(); MusicController.pause();
MusicController.playAt(MusicController.getOsuFile().previewTime, true); MusicController.playAt(MusicController.getBeatmap().previewTime, true);
resetTrack = false; resetTrack = false;
} }
@ -982,7 +982,7 @@ public class SongMenu extends BasicGameState {
// reload scores // reload scores
if (focusNode != null) { if (focusNode != null) {
scoreMap = ScoreDB.getMapSetScores(focusNode.osuFiles.get(focusNode.osuFileIndex)); scoreMap = ScoreDB.getMapSetScores(focusNode.beatmaps.get(focusNode.beatmapIndex));
focusScores = getScoreDataForNode(focusNode, true); focusScores = getScoreDataForNode(focusNode, true);
} }
@ -993,31 +993,31 @@ public class SongMenu extends BasicGameState {
if (stateAction != null) { if (stateAction != null) {
switch (stateAction) { switch (stateAction) {
case BEATMAP: // clear all scores case BEATMAP: // clear all scores
if (stateActionNode == null || stateActionNode.osuFileIndex == -1) if (stateActionNode == null || stateActionNode.beatmapIndex == -1)
break; break;
OsuFile osu = stateActionNode.osuFiles.get(stateActionNode.osuFileIndex); Beatmap beatmap = stateActionNode.beatmaps.get(stateActionNode.beatmapIndex);
ScoreDB.deleteScore(osu); ScoreDB.deleteScore(beatmap);
if (stateActionNode == focusNode) { if (stateActionNode == focusNode) {
focusScores = null; focusScores = null;
scoreMap.remove(osu.version); scoreMap.remove(beatmap.version);
} }
break; break;
case SCORE: // clear single score case SCORE: // clear single score
if (stateActionScore == null) if (stateActionScore == null)
break; break;
ScoreDB.deleteScore(stateActionScore); ScoreDB.deleteScore(stateActionScore);
scoreMap = ScoreDB.getMapSetScores(focusNode.osuFiles.get(focusNode.osuFileIndex)); scoreMap = ScoreDB.getMapSetScores(focusNode.beatmaps.get(focusNode.beatmapIndex));
focusScores = getScoreDataForNode(focusNode, true); focusScores = getScoreDataForNode(focusNode, true);
startScore = 0; startScore = 0;
break; break;
case BEATMAP_DELETE_CONFIRM: // delete song group case BEATMAP_DELETE_CONFIRM: // delete song group
if (stateActionNode == null) if (stateActionNode == null)
break; break;
OsuGroupNode BeatmapSetNode
prev = OsuGroupList.get().getBaseNode(stateActionNode.index - 1), prev = BeatmapSetList.get().getBaseNode(stateActionNode.index - 1),
next = OsuGroupList.get().getBaseNode(stateActionNode.index + 1); next = BeatmapSetList.get().getBaseNode(stateActionNode.index + 1);
int oldIndex = stateActionNode.index, focusNodeIndex = focusNode.index, startNodeIndex = startNode.index; int oldIndex = stateActionNode.index, focusNodeIndex = focusNode.index, startNodeIndex = startNode.index;
OsuGroupList.get().deleteSongGroup(stateActionNode); BeatmapSetList.get().deleteSongGroup(stateActionNode);
if (oldIndex == focusNodeIndex) { if (oldIndex == focusNodeIndex) {
if (prev != null) if (prev != null)
setFocus(prev, -1, true, true); setFocus(prev, -1, true, true);
@ -1046,7 +1046,7 @@ public class SongMenu extends BasicGameState {
if (stateActionNode == null) if (stateActionNode == null)
break; break;
int index = stateActionNode.index; int index = stateActionNode.index;
OsuGroupList.get().deleteSong(stateActionNode); BeatmapSetList.get().deleteSong(stateActionNode);
if (stateActionNode == focusNode) { if (stateActionNode == focusNode) {
if (stateActionNode.prev != null && if (stateActionNode.prev != null &&
!(stateActionNode.next != null && stateActionNode.next.index == index)) { !(stateActionNode.next != null && stateActionNode.next.index == index)) {
@ -1088,7 +1088,7 @@ public class SongMenu extends BasicGameState {
@Override @Override
public void run() { public void run() {
// clear the beatmap cache // clear the beatmap cache
OsuDB.clearDatabase(); BeatmapDB.clearDatabase();
// invoke unpacker and parser // invoke unpacker and parser
File beatmapDir = Options.getBeatmapDir(); File beatmapDir = Options.getBeatmapDir();
@ -1096,9 +1096,9 @@ public class SongMenu extends BasicGameState {
OsuParser.parseAllFiles(beatmapDir); OsuParser.parseAllFiles(beatmapDir);
// initialize song list // initialize song list
if (OsuGroupList.get().size() > 0) { if (BeatmapSetList.get().size() > 0) {
OsuGroupList.get().init(); BeatmapSetList.get().init();
setFocus(OsuGroupList.get().getRandomNode(), -1, true, true); setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
} else } else
MusicController.playThemeSong(); MusicController.playThemeSong();
@ -1146,7 +1146,7 @@ public class SongMenu extends BasicGameState {
n++; n++;
shifted = true; shifted = true;
} else if (n > 0 && startNode.next != null && } else if (n > 0 && startNode.next != null &&
OsuGroupList.get().getNode(startNode, MAX_SONG_BUTTONS) != null) { BeatmapSetList.get().getNode(startNode, MAX_SONG_BUTTONS) != null) {
startNode = startNode.next; startNode = startNode.next;
buttonY -= buttonOffset / 4; buttonY -= buttonOffset / 4;
if (buttonY < headerY - height * 0.02f) if (buttonY < headerY - height * 0.02f)
@ -1166,69 +1166,69 @@ public class SongMenu extends BasicGameState {
/** /**
* Sets a new focus node. * Sets a new focus node.
* @param node the base node; it will be expanded if it isn't already * @param node the base node; it will be expanded if it isn't already
* @param osuFileIndex the OsuFile element to focus; if out of bounds, it will be randomly chosen * @param beatmapIndex the beatmap element to focus; if out of bounds, it will be randomly chosen
* @param changeStartNode if true, startNode will be set to the first node in the group * @param changeStartNode if true, startNode will be set to the first node in the group
* @param preview whether to start at the preview time (true) or beginning (false) * @param preview whether to start at the preview time (true) or beginning (false)
* @return the old focus node * @return the old focus node
*/ */
public OsuGroupNode setFocus(OsuGroupNode node, int osuFileIndex, boolean changeStartNode, boolean preview) { public BeatmapSetNode setFocus(BeatmapSetNode node, int beatmapIndex, boolean changeStartNode, boolean preview) {
if (node == null) if (node == null)
return null; return null;
hoverOffset = 0f; hoverOffset = 0f;
hoverIndex = -1; hoverIndex = -1;
songInfo = null; songInfo = null;
OsuGroupNode oldFocus = focusNode; BeatmapSetNode oldFocus = focusNode;
// expand node before focusing it // expand node before focusing it
int expandedIndex = OsuGroupList.get().getExpandedIndex(); int expandedIndex = BeatmapSetList.get().getExpandedIndex();
if (node.index != expandedIndex) { if (node.index != expandedIndex) {
node = OsuGroupList.get().expand(node.index); node = BeatmapSetList.get().expand(node.index);
// if start node was previously expanded, move it // if start node was previously expanded, move it
if (startNode != null && startNode.index == expandedIndex) if (startNode != null && startNode.index == expandedIndex)
startNode = OsuGroupList.get().getBaseNode(startNode.index); startNode = BeatmapSetList.get().getBaseNode(startNode.index);
} }
// check osuFileIndex bounds // check beatmapIndex bounds
int length = node.osuFiles.size(); int length = node.beatmaps.size();
if (osuFileIndex < 0 || osuFileIndex > length - 1) // set a random index if (beatmapIndex < 0 || beatmapIndex > length - 1) // set a random index
osuFileIndex = (int) (Math.random() * length); beatmapIndex = (int) (Math.random() * length);
// change the focus node // change the focus node
if (changeStartNode || (startNode.index == 0 && startNode.osuFileIndex == -1 && startNode.prev == null)) if (changeStartNode || (startNode.index == 0 && startNode.beatmapIndex == -1 && startNode.prev == null))
startNode = node; startNode = node;
focusNode = OsuGroupList.get().getNode(node, osuFileIndex); focusNode = BeatmapSetList.get().getNode(node, beatmapIndex);
OsuFile osu = focusNode.osuFiles.get(focusNode.osuFileIndex); Beatmap beatmap = focusNode.beatmaps.get(focusNode.beatmapIndex);
MusicController.play(osu, false, preview); MusicController.play(beatmap, false, preview);
// load scores // load scores
scoreMap = ScoreDB.getMapSetScores(osu); scoreMap = ScoreDB.getMapSetScores(beatmap);
focusScores = getScoreDataForNode(focusNode, true); focusScores = getScoreDataForNode(focusNode, true);
startScore = 0; startScore = 0;
// check startNode bounds // check startNode bounds
while (startNode.index >= OsuGroupList.get().size() + length - MAX_SONG_BUTTONS && startNode.prev != null) while (startNode.index >= BeatmapSetList.get().size() + length - MAX_SONG_BUTTONS && startNode.prev != null)
startNode = startNode.prev; startNode = startNode.prev;
// make sure focusNode is on the screen (TODO: cleanup...) // make sure focusNode is on the screen (TODO: cleanup...)
int val = focusNode.index + focusNode.osuFileIndex - (startNode.index + MAX_SONG_BUTTONS) + 1; int val = focusNode.index + focusNode.beatmapIndex - (startNode.index + MAX_SONG_BUTTONS) + 1;
if (val > 0) // below screen if (val > 0) // below screen
changeIndex(val); changeIndex(val);
else { // above screen else { // above screen
if (focusNode.index == startNode.index) { if (focusNode.index == startNode.index) {
val = focusNode.index + focusNode.osuFileIndex - (startNode.index + startNode.osuFileIndex); val = focusNode.index + focusNode.beatmapIndex - (startNode.index + startNode.beatmapIndex);
if (val < 0) if (val < 0)
changeIndex(val); changeIndex(val);
} else if (startNode.index > focusNode.index) { } else if (startNode.index > focusNode.index) {
val = focusNode.index - focusNode.osuFiles.size() + focusNode.osuFileIndex - startNode.index + 1; val = focusNode.index - focusNode.beatmaps.size() + focusNode.beatmapIndex - startNode.index + 1;
if (val < 0) if (val < 0)
changeIndex(val); changeIndex(val);
} }
} }
// if start node is expanded and on group node, move it // if start node is expanded and on group node, move it
if (startNode.index == focusNode.index && startNode.osuFileIndex == -1) if (startNode.index == focusNode.index && startNode.beatmapIndex == -1)
changeIndex(1); changeIndex(1);
return oldFocus; return oldFocus;
@ -1255,7 +1255,7 @@ public class SongMenu extends BasicGameState {
* @param menuState the menu state determining the action * @param menuState the menu state determining the action
* @param node the song node to perform the action on * @param node the song node to perform the action on
*/ */
public void doStateActionOnLoad(MenuState menuState, OsuGroupNode node) { public void doStateActionOnLoad(MenuState menuState, BeatmapSetNode node) {
doStateActionOnLoad(menuState, node, null); doStateActionOnLoad(menuState, node, null);
} }
@ -1274,32 +1274,32 @@ public class SongMenu extends BasicGameState {
* @param node the song node to perform the action on * @param node the song node to perform the action on
* @param scoreData the score data to perform the action on * @param scoreData the score data to perform the action on
*/ */
private void doStateActionOnLoad(MenuState menuState, OsuGroupNode node, ScoreData scoreData) { private void doStateActionOnLoad(MenuState menuState, BeatmapSetNode node, ScoreData scoreData) {
stateAction = menuState; stateAction = menuState;
stateActionNode = node; stateActionNode = node;
stateActionScore = scoreData; stateActionScore = scoreData;
} }
/** /**
* Returns all the score data for an OsuGroupNode from scoreMap. * Returns all the score data for an BeatmapSetNode from scoreMap.
* If no score data is available for the node, return null. * If no score data is available for the node, return null.
* @param node the OsuGroupNode * @param node the BeatmapSetNode
* @param setTimeSince whether or not to set the "time since" field for the scores * @param setTimeSince whether or not to set the "time since" field for the scores
* @return the ScoreData array * @return the ScoreData array
*/ */
private ScoreData[] getScoreDataForNode(OsuGroupNode node, boolean setTimeSince) { private ScoreData[] getScoreDataForNode(BeatmapSetNode node, boolean setTimeSince) {
if (scoreMap == null || scoreMap.isEmpty() || node.osuFileIndex == -1) // node not expanded if (scoreMap == null || scoreMap.isEmpty() || node.beatmapIndex == -1) // node not expanded
return null; return null;
OsuFile osu = node.osuFiles.get(node.osuFileIndex); Beatmap beatmap = node.beatmaps.get(node.beatmapIndex);
ScoreData[] scores = scoreMap.get(osu.version); ScoreData[] scores = scoreMap.get(beatmap.version);
if (scores == null || scores.length < 1) // no scores if (scores == null || scores.length < 1) // no scores
return null; return null;
ScoreData s = scores[0]; ScoreData s = scores[0];
if (osu.beatmapID == s.MID && osu.beatmapSetID == s.MSID && if (beatmap.beatmapID == s.MID && beatmap.beatmapSetID == s.MSID &&
osu.title.equals(s.title) && osu.artist.equals(s.artist) && beatmap.title.equals(s.title) && beatmap.artist.equals(s.artist) &&
osu.creator.equals(s.creator)) { beatmap.creator.equals(s.creator)) {
if (setTimeSince) { if (setTimeSince) {
for (int i = 0; i < scores.length; i++) for (int i = 0; i < scores.length; i++)
scores[i].getTimeSince(); scores[i].getTimeSince();
@ -1318,9 +1318,9 @@ public class SongMenu extends BasicGameState {
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
MultiClip.destroyExtraClips(); MultiClip.destroyExtraClips();
OsuFile osu = MusicController.getOsuFile(); Beatmap beatmap = MusicController.getBeatmap();
Game gameState = (Game) game.getState(Opsu.STATE_GAME); Game gameState = (Game) game.getState(Opsu.STATE_GAME);
gameState.loadOsuFile(osu); gameState.loadBeatmap(beatmap);
gameState.setRestart(Game.Restart.NEW); gameState.setRestart(Game.Restart.NEW);
gameState.setReplay(null); gameState.setReplay(null);
game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black));

View File

@ -21,13 +21,13 @@ package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.OszUnpacker; import itdelatrisu.opsu.OszUnpacker;
import itdelatrisu.opsu.UI; import itdelatrisu.opsu.UI;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import java.io.File; import java.io.File;
@ -89,7 +89,7 @@ public class Splash extends BasicGameState {
if (!init) { if (!init) {
init = true; init = true;
if (OsuGroupList.get() != null) { if (BeatmapSetList.get() != null) {
// resources already loaded (from application restart) // resources already loaded (from application restart)
finished = true; finished = true;
} else { } else {
@ -125,12 +125,12 @@ 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
if (OsuGroupList.get().size() > 0) { if (BeatmapSetList.get().size() > 0) {
OsuGroupList.get().init(); BeatmapSetList.get().init();
if (Options.isThemeSongEnabled()) if (Options.isThemeSongEnabled())
MusicController.playThemeSong(); MusicController.playThemeSong();
else else
((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(OsuGroupList.get().getRandomNode(), -1, true, true); ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
} }
// play the theme song // play the theme song
@ -151,7 +151,7 @@ public class Splash extends BasicGameState {
if (++escapeCount >= 3) if (++escapeCount >= 3)
container.exit(); container.exit();
// stop parsing OsuFiles by sending interrupt to OsuParser // stop parsing beatmaps by sending interrupt to OsuParser
else if (thread != null) else if (thread != null)
thread.interrupt(); thread.interrupt();
} }