Prevent downloading songs that are already loaded. (base: fluddokt/opsu/76778f8)

- All beatmap set IDs are now stored in a set in OsuGroupList.
- OsuParser now checks the directory name for beatmap set IDs if the OsuFile doesn't contain one (for older beatmap formats).

Tweaks:
- Clear completed downloads when hitting "Import All".
- Call Download.updateReadSoFar() upon starting downloads instead of waiting for user to hover over the button (causing an unnecessary delay).

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-02-09 23:22:58 -05:00
parent f56c02864b
commit be3b94f5db
7 changed files with 72 additions and 8 deletions

View File

@ -392,8 +392,8 @@ public class Options {
RES_1366_768 (1366, 768),
RES_1440_900 (1440, 900),
RES_1600_900 (1600, 900),
RES_1680_1050 (1680, 1050),
RES_1600_1200 (1600, 1200),
RES_1680_1050 (1680, 1050),
RES_1920_1080 (1920, 1080),
RES_1920_1200 (1920, 1200),
RES_2560_1440 (2560, 1440),

View File

@ -21,6 +21,7 @@ package itdelatrisu.opsu;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.regex.Matcher;
@ -47,6 +48,9 @@ public class OsuGroupList {
/** Current list of nodes (subset of parsedNodes, used for searches). */
private ArrayList<OsuGroupNode> nodes;
/** Set of all beatmap set IDs for the parsed beatmaps. */
private HashSet<Integer> MSIDdb;
/** Index of current expanded node (-1 if no node is expanded). */
private int expandedIndex;
@ -68,6 +72,7 @@ public class OsuGroupList {
*/
private OsuGroupList() {
parsedNodes = new ArrayList<OsuGroupNode>();
MSIDdb = new HashSet<Integer>();
reset();
}
@ -95,6 +100,12 @@ public class OsuGroupList {
OsuGroupNode node = new OsuGroupNode(osuFiles);
parsedNodes.add(node);
mapCount += osuFiles.size();
// add beatmap set ID to set
int msid = osuFiles.get(0).beatmapSetID;
if (msid > 0)
MSIDdb.add(msid);
return node;
}
@ -335,4 +346,14 @@ public class OsuGroupList {
return true;
}
/**
* Returns whether or not the list contains the given beatmap set ID.
* <p>
* Note that IDs for older maps might have been improperly parsed, so
* there is no guarantee that this method will return an accurate value.
* @param id the beatmap set ID to check
* @return true if id is in the list
*/
public boolean containsBeatmapSetID(int id) { return MSIDdb.contains(id); }
}

View File

@ -37,6 +37,12 @@ import org.newdawn.slick.util.Log;
* Parser for OSU files.
*/
public class OsuParser {
/** The string lookup database. */
private static HashMap<String, String> stringdb = new HashMap<String, String>();
/** The expected pattern for beatmap directories, used to find beatmap set IDs. */
private static final String DIR_MSID_PATTERN = "^\\d+ .*";
/** The current file being parsed. */
private static File currentFile;
@ -46,9 +52,6 @@ public class OsuParser {
/** The total number of directories to parse. */
private static int totalDirectories = -1;
/** The string lookup database. */
private static HashMap<String, String> stringdb = new HashMap<String, String>();
// This class should not be instantiated.
private OsuParser() {}
@ -100,7 +103,7 @@ public class OsuParser {
// Parse hit objects only when needed to save time/memory.
// Change boolean to 'true' to parse them immediately.
parseFile(file, osuFiles, false);
parseFile(file, dir, osuFiles, false);
}
if (!osuFiles.isEmpty()) { // add entry if non-empty
osuFiles.trimToSize();
@ -125,11 +128,12 @@ public class OsuParser {
/**
* Parses an OSU file.
* @param file the file to parse
* @param dir the directory containing the beatmap
* @param osuFiles the song group
* @param parseObjects if true, hit objects will be fully parsed now
* @return the new OsuFile object
*/
public static OsuFile parseFile(File file, ArrayList<OsuFile> osuFiles, boolean parseObjects) {
private static OsuFile parseFile(File file, File dir, ArrayList<OsuFile> osuFiles, boolean parseObjects) {
OsuFile osu = new OsuFile(file);
try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
@ -295,6 +299,13 @@ public class OsuParser {
Log.warn(String.format("Failed to read metadata '%s' for file '%s'.",
line, file.getAbsolutePath()), e);
}
if (osu.beatmapSetID <= 0) { // try to determine MSID from directory name
if (dir != null && dir.isDirectory()) {
String dirName = dir.getName();
if (!dirName.isEmpty() && dirName.matches(DIR_MSID_PATTERN))
osu.beatmapSetID = Integer.parseInt(dirName.substring(0, dirName.indexOf(' ')));
}
}
}
break;
case "[Difficulty]":

View File

@ -165,6 +165,7 @@ public class Download {
rbc = new ReadableByteChannelWrapper(readableByteChannel);
fos = fileOutputStream;
status = Status.DOWNLOADING;
updateReadSoFar();
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
if (status == Status.DOWNLOADING) { // not interrupted
status = Status.COMPLETE;

View File

@ -19,6 +19,7 @@
package itdelatrisu.opsu.downloads;
import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.downloads.Download.Status;
import java.util.ArrayList;
import java.util.HashMap;
@ -143,6 +144,23 @@ public class DownloadList {
}
}
/**
* Removes all downloads with the given status from the list.
* @param status the download status
*/
public void clearDownloads(Status status) {
Iterator<DownloadNode> iter = nodes.iterator();
while (iter.hasNext()) {
DownloadNode node = iter.next();
Download dl = node.getDownload();
if (dl != null && dl.getStatus() == status) {
node.clearDownload();
iter.remove();
map.remove(node.getID());
}
}
}
/**
* Shows a confirmation dialog (used before exiting the game).
* @return true if user selects "yes", false otherwise

View File

@ -21,6 +21,7 @@ package itdelatrisu.opsu.downloads;
import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.Download.Status;
@ -296,6 +297,12 @@ public class DownloadNode {
g.setColor((focus) ? BG_FOCUS : (hover) ? BG_HOVER : BG_NORMAL);
g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight);
// map is already loaded
if (OsuGroupList.get().containsBeatmapSetID(beatmapSetID)) {
g.setColor(Utils.COLOR_BLUE_BUTTON);
g.fillRect(buttonBaseX, y, buttonWidth, buttonHeight);
}
// download progress
if (dl != null) {
float progress = dl.getProgress();
@ -349,7 +356,7 @@ public class DownloadNode {
else if (status == Download.Status.WAITING)
info = String.format("%s...", status.getName());
else {
if (hover)
if (hover && status == Download.Status.DOWNLOADING)
info = String.format("%s: %s left (%s)", status.getName(), download.getTimeRemaining(), download.getDownloadSpeed());
else
info = String.format("%s: %.1f%% (%s/%s)", status.getName(), progress,

View File

@ -438,6 +438,12 @@ public class DownloadsMenu extends BasicGameState {
if (index >= nodes.length)
break;
if (DownloadNode.resultContains(x, y, i)) {
DownloadNode node = nodes[index];
// check if map is already loaded
if (OsuGroupList.get().containsBeatmapSetID(node.getID()))
return;
SoundController.playSound(SoundEffect.MENUCLICK);
if (index == focusResult) {
if (focusTimer >= FOCUS_DELAY) {
@ -445,7 +451,6 @@ public class DownloadsMenu extends BasicGameState {
focusTimer = 0;
} else {
// start download
DownloadNode node = nodes[index];
if (!DownloadList.get().contains(node.getID())) {
DownloadList.get().addNode(node);
node.createDownload(server);
@ -515,6 +520,7 @@ public class DownloadsMenu extends BasicGameState {
}
}
DownloadList.get().clearDownloads(Download.Status.COMPLETE);
importThread = null;
}
};