Replay importing

This commit is contained in:
fd 2015-04-01 22:10:36 -04:00
parent 66bd97242f
commit a49b5bc945
12 changed files with 156 additions and 10 deletions

View File

@ -1235,6 +1235,7 @@ public class GameData {
scoreData.perfect = (comboMax == fullObjectCount); scoreData.perfect = (comboMax == fullObjectCount);
scoreData.mods = GameMod.getModState(); scoreData.mods = GameMod.getModState();
scoreData.replayString = (replay == null) ? null : replay.getReplayFilename(); scoreData.replayString = (replay == null) ? null : replay.getReplayFilename();
scoreData.playerName = "OpsuPlayer"; //TODO?
return scoreData; return scoreData;
} }

View File

@ -95,6 +95,9 @@ public class Options {
/** The replay directory (created when needed). */ /** The replay directory (created when needed). */
private static File replayDir; private static File replayDir;
/** The replay import directory. */
private static File replayImportDir;
/** The current skin directory (for user skins). */ /** The current skin directory (for user skins). */
private static File skinDir; private static File skinDir;
@ -824,7 +827,20 @@ public class Options {
oszDir.mkdir(); oszDir.mkdir();
return oszDir; return oszDir;
} }
/**
* Returns the replay import directory.
* If invalid, this will create and return a "SongPacks" directory.
* @return the OSZ archive directory
*/
public static File getReplayImportDir() {
if (replayImportDir != null && replayImportDir.isDirectory())
return replayImportDir;
replayImportDir = new File(DATA_DIR, "ReplayImport/");
replayImportDir.mkdir();
return replayImportDir;
}
/** /**
* Returns the screenshot directory. * Returns the screenshot directory.
* If invalid, this will return a "Screenshot" directory. * If invalid, this will return a "Screenshot" directory.

View File

@ -179,6 +179,8 @@ public class OsuFile implements Comparable<OsuFile> {
/** Combo colors (max 8). */ /** Combo colors (max 8). */
public Color[] combo; public Color[] combo;
public String md5Hash;
/** /**
* [HitObjects] * [HitObjects]

View File

@ -26,6 +26,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
@ -55,6 +56,10 @@ public class OsuGroupList {
/** 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;
/** Set of all beatmap set IDs for the parsed beatmaps. */
public HashMap<String, OsuFile> beatmapHashesToFile;
/** Index of current expanded node (-1 if no node is expanded). */ /** Index of current expanded node (-1 if no node is expanded). */
private int expandedIndex; private int expandedIndex;
@ -81,6 +86,7 @@ public class OsuGroupList {
private OsuGroupList() { private OsuGroupList() {
parsedNodes = new ArrayList<OsuGroupNode>(); parsedNodes = new ArrayList<OsuGroupNode>();
MSIDdb = new HashSet<Integer>(); MSIDdb = new HashSet<Integer>();
beatmapHashesToFile = new HashMap<String, OsuFile>();
reset(); reset();
} }
@ -114,6 +120,9 @@ public class OsuGroupList {
int msid = osuFiles.get(0).beatmapSetID; int msid = osuFiles.get(0).beatmapSetID;
if (msid > 0) if (msid > 0)
MSIDdb.add(msid); MSIDdb.add(msid);
for(OsuFile f : osuFiles) {
beatmapHashesToFile.put(f.md5Hash, f);
}
return node; return node;
} }
@ -498,4 +507,8 @@ public class OsuGroupList {
* @return true if id is in the list * @return true if id is in the list
*/ */
public boolean containsBeatmapSetID(int id) { return MSIDdb.contains(id); } public boolean containsBeatmapSetID(int id) { return MSIDdb.contains(id); }
public OsuFile getFileFromBeatmapHash(String beatmapHash) {
return beatmapHashesToFile.get(beatmapHash);
}
} }

View File

@ -586,6 +586,8 @@ public class OsuParser {
// parse hit objects now? // parse hit objects now?
if (parseObjects) if (parseObjects)
parseHitObjects(osu); parseHitObjects(osu);
osu.md5Hash = Utils.getMD5(file);
return osu; return osu;
} }

View File

@ -76,6 +76,8 @@ public class ScoreData implements Comparable<ScoreData> {
/** The tooltip string. */ /** The tooltip string. */
private String tooltip; private String tooltip;
public String playerName;
/** Drawing values. */ /** Drawing values. */
private static float baseX, baseY, buttonWidth, buttonHeight, buttonOffset; private static float baseX, baseY, buttonWidth, buttonHeight, buttonOffset;
@ -163,6 +165,7 @@ public class ScoreData implements Comparable<ScoreData> {
this.perfect = rs.getBoolean(16); this.perfect = rs.getBoolean(16);
this.mods = rs.getInt(17); this.mods = rs.getInt(17);
this.replayString = rs.getString(18); this.replayString = rs.getString(18);
this.playerName = rs.getString(19);
} }
/** /**
@ -259,7 +262,7 @@ public class ScoreData implements Comparable<ScoreData> {
// hit counts (custom: osu! shows user instead, above score) // hit counts (custom: osu! shows user instead, above score)
Utils.FONT_SMALL.drawString( Utils.FONT_SMALL.drawString(
textX, y + textOffset + Utils.FONT_MEDIUM.getLineHeight(), textX, y + textOffset + Utils.FONT_MEDIUM.getLineHeight(),
String.format("300:%d 100:%d 50:%d Miss:%d", hit300, hit100, hit50, miss), String.format("300:%d 100:%d 50:%d Miss:%d Name:%s", hit300, hit100, hit50, miss, getPlayerName()),
Color.white Color.white
); );
@ -330,6 +333,11 @@ public class ScoreData implements Comparable<ScoreData> {
); );
} }
public String getPlayerName() {
if(playerName == null)
return "Null Name";
return playerName;
}
@Override @Override
public int compareTo(ScoreData that) { public int compareTo(ScoreData that) {
if (this.score != that.score) if (this.score != that.score)

View File

@ -43,7 +43,7 @@ public class OsuDB {
* 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.
*/ */
private static final String DATABASE_VERSION = "2014-03-08"; private static final String DATABASE_VERSION = "2015-03-30";
/** Minimum batch size ratio ({@code batchSize/cacheSize}) to invoke batch loading. */ /** Minimum batch size ratio ({@code batchSize/cacheSize}) to invoke batch loading. */
private static final float LOAD_BATCH_MIN_RATIO = 0.2f; private static final float LOAD_BATCH_MIN_RATIO = 0.2f;
@ -83,7 +83,7 @@ public class OsuDB {
insertStmt = connection.prepareStatement( insertStmt = connection.prepareStatement(
"INSERT INTO beatmaps VALUES (" + "INSERT INTO beatmaps VALUES (" +
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " +
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
); );
selectStmt = connection.prepareStatement("SELECT * FROM beatmaps WHERE dir = ? AND file = ?"); selectStmt = connection.prepareStatement("SELECT * FROM beatmaps WHERE dir = ? AND file = ?");
deleteMapStmt = connection.prepareStatement("DELETE FROM beatmaps WHERE dir = ? AND file = ?"); deleteMapStmt = connection.prepareStatement("DELETE FROM beatmaps WHERE dir = ? AND file = ?");
@ -116,7 +116,8 @@ public class OsuDB {
"bpmMin INTEGER, bpmMax INTEGER, endTime INTEGER, " + "bpmMin INTEGER, bpmMax INTEGER, endTime INTEGER, " +
"audioFile TEXT, audioLeadIn INTEGER, previewTime INTEGER, countdown INTEGER, sampleSet TEXT, stackLeniency REAL, " + "audioFile TEXT, audioLeadIn INTEGER, previewTime INTEGER, countdown INTEGER, sampleSet TEXT, stackLeniency REAL, " +
"mode INTEGER, letterboxInBreaks BOOLEAN, widescreenStoryboard BOOLEAN, epilepsyWarning BOOLEAN, " + "mode INTEGER, letterboxInBreaks BOOLEAN, widescreenStoryboard BOOLEAN, epilepsyWarning BOOLEAN, " +
"bg TEXT, timingPoints TEXT, breaks TEXT, combo TEXT" + "bg TEXT, timingPoints TEXT, breaks TEXT, combo TEXT," +
"md5hash TEXT" +
"); " + "); " +
"CREATE TABLE IF NOT EXISTS info (" + "CREATE TABLE IF NOT EXISTS info (" +
"key TEXT NOT NULL UNIQUE, value TEXT" + "key TEXT NOT NULL UNIQUE, value TEXT" +
@ -333,7 +334,8 @@ public class OsuDB {
stmt.setString(37, osu.timingPointsToString()); stmt.setString(37, osu.timingPointsToString());
stmt.setString(38, osu.breaksToString()); stmt.setString(38, osu.breaksToString());
stmt.setString(39, osu.comboToString()); stmt.setString(39, osu.comboToString());
} catch (SQLException e) { stmt.setString(40, osu.md5Hash);
} catch (SQLException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
throw new SQLException(e); throw new SQLException(e);
@ -470,6 +472,7 @@ public class OsuDB {
osu.widescreenStoryboard = rs.getBoolean(34); osu.widescreenStoryboard = rs.getBoolean(34);
osu.epilepsyWarning = rs.getBoolean(35); osu.epilepsyWarning = rs.getBoolean(35);
osu.bg = OsuParser.getDBString(rs.getString(36)); osu.bg = OsuParser.getDBString(rs.getString(36));
osu.md5Hash = OsuParser.getDBString(rs.getString(40));
} catch (SQLException e) { } catch (SQLException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {

View File

@ -45,7 +45,7 @@ public class ScoreDB {
* This value should be changed whenever the database format changes. * This value should be changed whenever the database format changes.
* Add any update queries to the {@link #getUpdateQueries(int)} method. * Add any update queries to the {@link #getUpdateQueries(int)} method.
*/ */
private static final int DATABASE_VERSION = 20140311; private static final int DATABASE_VERSION = 20150401;
/** /**
* Returns a list of SQL queries to apply, in order, to update from * Returns a list of SQL queries to apply, in order, to update from
@ -57,6 +57,8 @@ public class ScoreDB {
List<String> list = new LinkedList<String>(); List<String> list = new LinkedList<String>();
if (version < 20140311) if (version < 20140311)
list.add("ALTER TABLE scores ADD COLUMN replay TEXT"); list.add("ALTER TABLE scores ADD COLUMN replay TEXT");
if (version < 20150401)
list.add("ALTER TABLE scores ADD COLUMN playerName TEXT");
/* add future updates here */ /* add future updates here */
@ -96,7 +98,7 @@ public class ScoreDB {
// prepare sql statements // prepare sql statements
try { try {
insertStmt = connection.prepareStatement( insertStmt = connection.prepareStatement(
"INSERT INTO scores VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" "INSERT OR IGNORE INTO scores VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
); );
selectMapStmt = connection.prepareStatement( selectMapStmt = connection.prepareStatement(
"SELECT * FROM scores WHERE " + "SELECT * FROM scores WHERE " +
@ -137,7 +139,8 @@ public class ScoreDB {
"combo INTEGER, " + "combo INTEGER, " +
"perfect BOOLEAN, " + "perfect BOOLEAN, " +
"mods INTEGER, " + "mods INTEGER, " +
"replay TEXT" + "replay TEXT," +
"playerName TEXT"+
");" + ");" +
"CREATE TABLE IF NOT EXISTS info (" + "CREATE TABLE IF NOT EXISTS info (" +
"key TEXT NOT NULL UNIQUE, value TEXT" + "key TEXT NOT NULL UNIQUE, value TEXT" +
@ -283,6 +286,8 @@ public class ScoreDB {
stmt.setInt(15, data.combo); stmt.setInt(15, data.combo);
stmt.setBoolean(16, data.perfect); stmt.setBoolean(16, data.perfect);
stmt.setInt(17, data.mods); stmt.setInt(17, data.mods);
stmt.setString(19, data.playerName);
} }
/** /**

View File

@ -18,6 +18,7 @@
package itdelatrisu.opsu.io; package itdelatrisu.opsu.io;
import java.io.BufferedInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -50,7 +51,7 @@ public class OsuReader {
* @param source the input stream to read from * @param source the input stream to read from
*/ */
public OsuReader(InputStream source) { public OsuReader(InputStream source) {
this.reader = new DataInputStream(source); this.reader = new DataInputStream(new BufferedInputStream(source));
} }
/** /**

View File

@ -19,15 +19,20 @@
package itdelatrisu.opsu.replay; package itdelatrisu.opsu.replay;
import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.io.OsuReader; import itdelatrisu.opsu.io.OsuReader;
import itdelatrisu.opsu.io.OsuWriter; import itdelatrisu.opsu.io.OsuWriter;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder; import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -100,6 +105,8 @@ public class Replay {
/** Seed. (?) */ /** Seed. (?) */
public int seed; public int seed;
private ScoreData scoreData;
/** Seed string. */ /** Seed string. */
private static final String SEED_STRING = "-12345"; private static final String SEED_STRING = "-12345";
@ -130,6 +137,41 @@ public class Replay {
reader.close(); reader.close();
loaded = true; loaded = true;
} }
/**
* Returns a ScoreData object encapsulating all game data.
* If score data already exists, the existing object will be returned
* (i.e. this will not overwrite existing data).
* @param osu the OsuFile
* @return the ScoreData object
*/
public ScoreData getScoreData(OsuFile osu) {
if (scoreData != null)
return scoreData;
scoreData = new ScoreData();
scoreData.timestamp = file.lastModified() / 1000L;
scoreData.MID = osu.beatmapID;
scoreData.MSID = osu.beatmapSetID;
scoreData.title = osu.title;
scoreData.artist = osu.artist;
scoreData.creator = osu.creator;
scoreData.version = osu.version;
scoreData.hit300 = hit300;
scoreData.hit100 = hit100;
scoreData.hit50 = hit50;
scoreData.geki = geki;
scoreData.katu = katu;
scoreData.miss = miss;
scoreData.score = score;
scoreData.combo = combo;
scoreData.perfect = perfect;
scoreData.mods = mods;
scoreData.replayString = file!=null ? file.getName() : getReplayFilename();
scoreData.playerName = playerName!=null ? playerName : "No Name";
return scoreData;
}
/** /**
* Loads the replay header data. * Loads the replay header data.
@ -139,6 +181,7 @@ public class Replay {
private void loadHeader(OsuReader reader) throws IOException { private void loadHeader(OsuReader reader) throws IOException {
this.mode = reader.readByte(); this.mode = reader.readByte();
this.version = reader.readInt(); this.version = reader.readInt();
System.out.println("Header:"+file.getName()+" "+mode+" "+version);
this.beatmapHash = reader.readString(); this.beatmapHash = reader.readString();
this.playerName = reader.readString(); this.playerName = reader.readString();
this.replayHash = reader.readString(); this.replayHash = reader.readString();
@ -232,7 +275,7 @@ public class Replay {
new Thread() { new Thread() {
@Override @Override
public void run() { public void run() {
try (FileOutputStream out = new FileOutputStream(file)) { try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
OsuWriter writer = new OsuWriter(out); OsuWriter writer = new OsuWriter(out);
// header // header

View File

@ -0,0 +1,44 @@
package itdelatrisu.opsu.replay;
import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.OsuFile;
import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.db.ScoreDB;
import java.io.File;
import java.io.IOException;
public class ReplayImporter {
public static void importAllReplaysFromDir(File dir) {
System.out.println(OsuGroupList.get().beatmapHashesToFile);
for (File replayToImport : dir.listFiles()) {
try {
Replay r = new Replay(replayToImport);
r.load();
OsuFile oFile = OsuGroupList.get().getFileFromBeatmapHash(r.beatmapHash);
if(oFile != null){
//ErrorHandler.error("Importing"+replayToImport+" forBeatmap:"+oFile, null, false);
ScoreData data = r.getScoreData(oFile);
File moveToFile = new File(Options.getReplayDir(),replayToImport.getName());
System.out.println("Moving "+replayToImport+" to "+moveToFile);
if(
!replayToImport.renameTo(moveToFile)
){
System.out.println("Rename Failed "+moveToFile);
}
data.replayString = replayToImport.getName().substring(0, replayToImport.getName().length()-4);
ScoreDB.addScore(data);;
} else {
//ErrorHandler.error("Could not find beatmap for replay "+replayToImport, null, false);
}
} catch (IOException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println(e);
}
}
}
}

View File

@ -18,9 +18,11 @@
package itdelatrisu.opsu.states; package itdelatrisu.opsu.states;
import itdelatrisu.opsu.ErrorHandler;
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.OsuFile;
import itdelatrisu.opsu.OsuGroupList; import itdelatrisu.opsu.OsuGroupList;
import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.OsuParser;
import itdelatrisu.opsu.OszUnpacker; import itdelatrisu.opsu.OszUnpacker;
@ -28,8 +30,11 @@ 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.replay.Replay;
import itdelatrisu.opsu.replay.ReplayImporter;
import java.io.File; import java.io.File;
import java.io.IOException;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer; import org.newdawn.slick.GameContainer;
@ -39,6 +44,7 @@ import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException; import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState; import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame; import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.util.Log;
/** /**
* "Splash Screen" state. * "Splash Screen" state.
@ -104,6 +110,8 @@ public class Splash extends BasicGameState {
// parse song directory // parse song directory
OsuParser.parseAllFiles(beatmapDir); OsuParser.parseAllFiles(beatmapDir);
ReplayImporter.importAllReplaysFromDir(Options.getReplayImportDir());
// load sounds // load sounds
SoundController.init(); SoundController.init();