Skip to content

Commit 09b70df

Browse files
committed
Store freq & override judge value in separate table
# Conflicts: # core/src/bms/player/beatoraja/select/bar/ContextMenuBar.java
1 parent dc37dca commit 09b70df

File tree

12 files changed

+536
-12
lines changed

12 files changed

+536
-12
lines changed

core/src/bms/player/beatoraja/PlayDataAccessor.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.nio.file.Paths;
66
import java.security.MessageDigest;
77
import java.util.*;
8+
9+
import bms.player.beatoraja.select.QueryScoreContext;
810
import org.slf4j.Logger;
911
import org.slf4j.LoggerFactory;
1012
import java.util.stream.Stream;
@@ -21,6 +23,7 @@
2123
import bms.player.beatoraja.ScoreDatabaseAccessor.ScoreDataCollector;
2224
import bms.player.beatoraja.ScoreLogDatabaseAccessor.ScoreLog;
2325
import bms.player.beatoraja.ir.LR2IRConnection;
26+
import bms.player.beatoraja.modmenu.SongManagerMenu;
2427
import bms.player.beatoraja.song.SongData;
2528

2629
import com.badlogic.gdx.utils.Json;
@@ -171,6 +174,13 @@ public ScoreData readScoreData(String hash, boolean ln, int lnmode) {
171174
return scoredb.getScoreData(hash, ln ? lnmode : 0);
172175
}
173176

177+
public ScoreData readScoreData(String hash, boolean ln, QueryScoreContext ctx) {
178+
if (!ctx.isQueryModdedScore()) {
179+
return readScoreData(hash, ln, ctx.lnMode());
180+
}
181+
return scoredatalogdb.getBestScoreDataLog(hash, ctx);
182+
}
183+
174184
/**
175185
* スコアデータをまとめて読み込み、collectorに渡す
176186
* @param collector スコアデータのcollector
@@ -181,6 +191,14 @@ public void readScoreDatas(ScoreDataCollector collector, SongData[] songs, int l
181191
scoredb.getScoreDatas(collector, songs, lnmode);
182192
}
183193

194+
public void readScoreDatas(ScoreDataCollector collector, SongData[] songs, QueryScoreContext ctx) {
195+
if (!ctx.isQueryModdedScore()) {
196+
readScoreDatas(collector, songs, ctx.lnMode());
197+
}
198+
scoredatalogdb.getBestScoreDataLogs(collector, songs, ctx);
199+
}
200+
201+
184202
public List<ScoreData> readScoreDatas(String sql) {
185203
return scoredb.getScoreDatas(sql);
186204
}
@@ -285,6 +303,7 @@ public void writeScoreData(ScoreData newscore, BMSModel model, int lnmode, boole
285303
newscore.setClearcount(score.getClearcount());
286304
newscore.setScorehash(getScoreHash(newscore));
287305

306+
SongManagerMenu.invalidCache(newscore.getSha256());
288307
scoredatalogdb.setScoreDataLog(newscore);
289308
}
290309

@@ -359,6 +378,16 @@ public ScoreData readScoreData(String[] hashes, boolean ln, int lnmode, int opti
359378
return readScoreData(hash, ln, lnmode, option, constraint);
360379
}
361380

381+
/**
382+
* Load one specific chart's play history
383+
*
384+
* @param hash chart's hash
385+
* @return play records
386+
*/
387+
public List<ScoreData> readScoreDataLog(String hash) {
388+
return scoredatalogdb.getScoreDataLog(hash);
389+
}
390+
362391
/**
363392
* コーススコアデータを書き込む
364393
*/
@@ -432,6 +461,19 @@ public void writeScoreData(ScoreData newscore, BMSModel[] models, int lnmode, in
432461
log.setDate(score.getDate());
433462
scorelogdb.setScoreLog(log);
434463
}
464+
if (log.getSha256() != null && scoredatalogdb != null) {
465+
// TODO: I don't know why newscore doesn't have course's sha256 here, pls kill me
466+
newscore.setSha256(log.getSha256());
467+
newscore.setTrophy("");
468+
newscore.setMode(score.getMode());
469+
newscore.setDate(score.getDate());
470+
newscore.setPlaycount(score.getPlaycount());
471+
newscore.setClearcount(score.getClearcount());
472+
newscore.setScorehash(getScoreHash(newscore));
473+
474+
SongManagerMenu.invalidCache(newscore.getSha256());
475+
scoredatalogdb.setScoreDataLog(newscore);
476+
}
435477

436478
logger.info("スコアデータベース更新完了 ");
437479

core/src/bms/player/beatoraja/PlayerResource.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*/
3131
public final class PlayerResource {
3232
private static final Logger logger = LoggerFactory.getLogger(PlayerResource.class);
33-
33+
3434
/**
3535
* 選曲中のBMS
3636
*/
@@ -132,8 +132,10 @@ public final class PlayerResource {
132132
private String tablelevel = "";
133133
private String tablefull;
134134
private boolean freqOn;
135+
private int freqValue;
135136
private String freqString;
136137
private boolean forceNoIRSend;
138+
private int overrideJudgeRank;
137139
// Full list of difficult tables that contains current song
138140
private List<String> reverseLookup = new ArrayList<>();
139141

@@ -672,4 +674,20 @@ public void setForceNoIRSend(boolean forceNoIRSend) {
672674
public Future<BMSLoudnessAnalyzer.AnalysisResult> getAnalysisTask() {
673675
return analysisTask;
674676
}
675-
}
677+
678+
public int getFreqValue() {
679+
return freqValue;
680+
}
681+
682+
public void setFreqValue(int freqValue) {
683+
this.freqValue = freqValue;
684+
}
685+
686+
public int getOverrideJudgeRank() {
687+
return overrideJudgeRank;
688+
}
689+
690+
public void setOverrideJudgeRank(int overrideJudgeRank) {
691+
this.overrideJudgeRank = overrideJudgeRank;
692+
}
693+
}

core/src/bms/player/beatoraja/ScoreData.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ public class ScoreData implements Validatable {
119119
* プレイゲージ
120120
*/
121121
private int gauge;
122+
/**
123+
* Rate percentage, e.g. 120 == 1.2x
124+
*/
125+
private int rate;
126+
/**
127+
* Override judgement, -1 as didn't use
128+
*/
129+
private int overridejudge = -1;
122130
/**
123131
* 入力デバイス
124132
*/
@@ -236,6 +244,18 @@ public int getLms() {
236244
public void setLms(int lms) {
237245
this.lms = lms;
238246
}
247+
public int getRate() {
248+
return rate;
249+
}
250+
public void setRate(int rate) {
251+
this.rate = rate;
252+
}
253+
public int getOverridejudge() {
254+
return overridejudge;
255+
}
256+
public void setOverridejudge(int overridejudge) {
257+
this.overridejudge = overridejudge;
258+
}
239259

240260
public int getJudgeCount(int judge) {
241261
return getJudgeCount(judge, true) + getJudgeCount(judge, false);

core/src/bms/player/beatoraja/ScoreDataLogDatabaseAccessor.java

Lines changed: 165 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,23 @@
22

33
import java.sql.*;
44
import java.util.*;
5+
6+
import bms.player.beatoraja.select.QueryScoreContext;
7+
import bms.player.beatoraja.song.SongData;
58
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
710

811
import org.apache.commons.dbutils.QueryRunner;
912
import org.apache.commons.dbutils.ResultSetHandler;
1013
import org.apache.commons.dbutils.handlers.BeanListHandler;
1114
import org.sqlite.SQLiteConfig;
12-
import org.sqlite.SQLiteDataSource;
1315
import org.sqlite.SQLiteConfig.SynchronousMode;
16+
import org.sqlite.SQLiteDataSource;
17+
18+
import javax.management.Query;
19+
import java.sql.Connection;
20+
import java.sql.SQLException;
21+
import java.util.List;
1422

1523
/**
1624
* スコアデータログデータベースアクセサ
@@ -24,9 +32,10 @@ public class ScoreDataLogDatabaseAccessor extends SQLiteDatabaseAccessor {
2432
private final ResultSetHandler<List<ScoreData>> scoreHandler = new BeanListHandler<ScoreData>(ScoreData.class);
2533

2634
private final QueryRunner qr;
35+
private static final int LOAD_CHUNK_SIZE = 1000;
2736

2837
public ScoreDataLogDatabaseAccessor(String path) throws ClassNotFoundException {
29-
super( new Table("scoredatalog",
38+
super( new Table("scoredatalog",
3039
new Column("sha256", "TEXT", 1, 1),
3140
new Column("mode", "INTEGER",0,1),
3241
new Column("clear", "INTEGER"),
@@ -56,7 +65,40 @@ public ScoreDataLogDatabaseAccessor(String path) throws ClassNotFoundException {
5665
new Column("date", "INTEGER"),
5766
new Column("state", "INTEGER"),
5867
new Column("scorehash", "TEXT")
59-
));
68+
),
69+
new Table( "eddatalog",
70+
new Column("sha256", "TEXT", 1, 0),
71+
new Column("mode", "INTEGER"),
72+
new Column("clear", "INTEGER"),
73+
new Column("epg", "INTEGER"),
74+
new Column("lpg", "INTEGER"),
75+
new Column("egr", "INTEGER"),
76+
new Column("lgr", "INTEGER"),
77+
new Column("egd", "INTEGER"),
78+
new Column("lgd", "INTEGER"),
79+
new Column("ebd", "INTEGER"),
80+
new Column("lbd", "INTEGER"),
81+
new Column("epr", "INTEGER"),
82+
new Column("lpr", "INTEGER"),
83+
new Column("ems", "INTEGER"),
84+
new Column("lms", "INTEGER"),
85+
new Column("notes", "INTEGER"),
86+
new Column("combo", "INTEGER"),
87+
new Column("minbp", "INTEGER"),
88+
new Column("avgjudge", "INTEGER", 1, 0, String.valueOf(Integer.MAX_VALUE)),
89+
new Column("playcount", "INTEGER"),
90+
new Column("clearcount", "INTEGER"),
91+
new Column("trophy", "TEXT"),
92+
new Column("ghost", "TEXT"),
93+
new Column("option", "INTEGER"),
94+
new Column("seed", "INTEGER"),
95+
new Column("random", "INTEGER"),
96+
new Column("date", "INTEGER"),
97+
new Column("state", "INTEGER"),
98+
new Column("scorehash", "TEXT"),
99+
new Column("rate", "INTEGER"),
100+
new Column("overridejudge", "INTEGER")
101+
));
60102

61103
Class.forName("org.sqlite.JDBC");
62104
SQLiteConfig conf = new SQLiteConfig();
@@ -83,10 +125,129 @@ public void setScoreDataLog(ScoreData[] scores) {
83125
con.setAutoCommit(false);
84126
for (ScoreData score : scores) {
85127
this.insert(qr, con, "scoredatalog", score);
128+
this.insert(qr, con, "eddatalog", score);
86129
}
87130
con.commit();
88131
} catch (Exception e) {
89-
logger.error("スコア更新時の例外:" + e.getMessage());
132+
logger.error("スコア更新時の例外:{}", e.getMessage());
133+
}
134+
}
135+
136+
public List<ScoreData> getScoreDataLog(String sha256) {
137+
List<ScoreData> result = null;
138+
try {
139+
// TODO: One day we shall use prepared statement instead
140+
result = Validatable.removeInvalidElements(qr.query(String.format("SELECT * FROM eddatalog WHERE sha256 = '%s'", sha256), scoreHandler));
141+
} catch (Exception e) {
142+
logger.error("Failed to query table eddatalog: {}", e.getMessage());
143+
}
144+
return result;
145+
}
146+
147+
public List<ScoreData> getScoreDataLog(String sha256, QueryScoreContext ctx) {
148+
List<ScoreData> result = null;
149+
try (Connection con = qr.getDataSource().getConnection()) {
150+
PreparedStatement ps = con.prepareStatement("SELECT * FROM eddatalog WHERE sha256 = ? AND rate = ? AND overridejudge = ?");
151+
ps.setString(1, sha256);
152+
ps.setInt(2, ctx.freqValue() != null ? ctx.freqValue() : 0);
153+
ps.setInt(3, ctx.overrideJudge() != null ? ctx.overrideJudge() : -1);
154+
result = Validatable.removeInvalidElements(scoreHandler.handle(ps.executeQuery()));
155+
} catch (Exception e) {
156+
logger.error("Failed to query table eddatalog: {}", e.getMessage());
157+
}
158+
return result;
159+
}
160+
161+
/**
162+
* TODO: Maybe we should make the definition of "best" programmable?
163+
*/
164+
public ScoreData getBestScoreDataLog(String sha256, QueryScoreContext ctx) {
165+
List<ScoreData> rawLogs = getScoreDataLog(sha256, ctx);
166+
if (rawLogs.isEmpty()) {
167+
return null;
168+
}
169+
ScoreData result = rawLogs.get(0);
170+
for (ScoreData score : rawLogs) {
171+
if (score.getClear() > result.getClear()) {
172+
result = score;
173+
} else if (score.getClear() == result.getClear() && score.getExscore() > result.getExscore()) {
174+
result = score;
175+
}
176+
}
177+
return result;
178+
}
179+
180+
public void getBestScoreDataLogs(ScoreDatabaseAccessor.ScoreDataCollector collector, SongData[] songs, QueryScoreContext ctx) {
181+
StringBuilder str = new StringBuilder(songs.length * 68);
182+
getBestScoreDataLogs(collector, songs, ctx.lnMode(), str, true, ctx);
183+
str.setLength(0);
184+
getBestScoreDataLogs(collector, songs, 0, str, false, ctx);
185+
}
186+
187+
public void getBestScoreDataLogs(ScoreDatabaseAccessor.ScoreDataCollector collector, SongData[] songs, int mode, StringBuilder str, boolean hasLN, QueryScoreContext ctx) {
188+
try (Connection con = qr.getDataSource().getConnection()) {
189+
int songLength = songs.length;
190+
int chunkLength = (songLength + LOAD_CHUNK_SIZE - 1) / LOAD_CHUNK_SIZE;
191+
List<ScoreData> scores = new ArrayList<>();
192+
for (int i = 0; i < chunkLength;++i) {
193+
// [i * CHUNK_SIZE, min(length, (i + 1) * CHUNK_SIZE)
194+
final int chunkStart = i * LOAD_CHUNK_SIZE;
195+
final int chunkEnd = Math.min(songLength, (i + 1) * LOAD_CHUNK_SIZE);
196+
for (int j = chunkStart; j < chunkEnd; ++j) {
197+
SongData song = songs[j];
198+
if((hasLN && song.hasUndefinedLongNote()) || (!hasLN && !song.hasUndefinedLongNote())) {
199+
if (str.length() > 0) {
200+
str.append(',');
201+
}
202+
str.append('\'').append(song.getSha256()).append('\'');
203+
}
204+
}
205+
206+
PreparedStatement ps = con.prepareStatement("SELECT * FROM eddatalog WHERE sha256 in (?) AND mode = ? AND rate = ? AND overridejudge = ?");
207+
ps.setString(1, str.toString());
208+
ps.setInt(2, mode);
209+
ps.setInt(3, ctx.freqValue() != null ? ctx.freqValue() : 0);
210+
ps.setInt(4, ctx.overrideJudge() != null ? ctx.overrideJudge() : -1);
211+
212+
List<ScoreData> subScores = Validatable.removeInvalidElements(scoreHandler.handle(ps.executeQuery()));
213+
str.setLength(0);
214+
scores.addAll(subScores);
215+
}
216+
scores.sort(Comparator.comparing(ScoreData::getSha256));
217+
// For every chart, we calculate it's best score
218+
List<ScoreData> bestScores = new ArrayList<>();
219+
for (int i = 0; i <scores.size(); ++i) {
220+
int j = i;
221+
ScoreData bestScore = scores.get(i);
222+
while (j + 1 < scores.size() && scores.get(j + 1).getSha256().equals(bestScore.getSha256())) {
223+
ScoreData next = scores.get(j + 1);
224+
if (next.getClear() > bestScore.getClear()) {
225+
bestScore = next;
226+
} else if (next.getClear() == bestScore.getClear() && next.getExscore() > bestScore.getExscore()) {
227+
bestScore = next;
228+
}
229+
j++;
230+
}
231+
bestScores.add(bestScore);
232+
i = j;
233+
}
234+
for(SongData song : songs) {
235+
if((hasLN && song.hasUndefinedLongNote()) || (!hasLN && !song.hasUndefinedLongNote())) {
236+
boolean b = true;
237+
for (ScoreData score : bestScores) {
238+
if(song.getSha256().equals(score.getSha256())) {
239+
collector.collect(song, score);
240+
b = false;
241+
break;
242+
}
243+
}
244+
if(b) {
245+
collector.collect(song, null);
246+
}
247+
}
248+
}
249+
} catch (Exception e) {
250+
logger.error("Failed to query table eddatalog: {}", e.getMessage());
90251
}
91252
}
92253
}

0 commit comments

Comments
 (0)