diff --git a/src/main/java/cc/fascinated/backend/common/MathUtils.java b/src/main/java/cc/fascinated/backend/common/MathUtils.java index 3285700..9afff85 100644 --- a/src/main/java/cc/fascinated/backend/common/MathUtils.java +++ b/src/main/java/cc/fascinated/backend/common/MathUtils.java @@ -1,5 +1,8 @@ package cc.fascinated.backend.common; +import lombok.experimental.UtilityClass; + +@UtilityClass public class MathUtils { /** diff --git a/src/main/java/cc/fascinated/backend/common/Timer.java b/src/main/java/cc/fascinated/backend/common/Timer.java index 3f9ea18..3695f26 100644 --- a/src/main/java/cc/fascinated/backend/common/Timer.java +++ b/src/main/java/cc/fascinated/backend/common/Timer.java @@ -1,5 +1,8 @@ package cc.fascinated.backend.common; +import lombok.experimental.UtilityClass; + +@UtilityClass public class Timer { /** diff --git a/src/main/java/cc/fascinated/backend/leaderboard/Leaderboard.java b/src/main/java/cc/fascinated/backend/leaderboard/Leaderboard.java index bbb7fea..584c36c 100644 --- a/src/main/java/cc/fascinated/backend/leaderboard/Leaderboard.java +++ b/src/main/java/cc/fascinated/backend/leaderboard/Leaderboard.java @@ -10,6 +10,11 @@ public class Leaderboard { */ private final String name; + /** + * The version of the leaderboard. + */ + private int curveVersion; + /** * The curve of the leaderboard. */ diff --git a/src/main/java/cc/fascinated/backend/leaderboard/impl/ScoreSaberLeaderboard.java b/src/main/java/cc/fascinated/backend/leaderboard/impl/ScoreSaberLeaderboard.java index 18b6f84..5bb7dec 100644 --- a/src/main/java/cc/fascinated/backend/leaderboard/impl/ScoreSaberLeaderboard.java +++ b/src/main/java/cc/fascinated/backend/leaderboard/impl/ScoreSaberLeaderboard.java @@ -24,7 +24,7 @@ public class ScoreSaberLeaderboard extends Leaderboard { private final double weightCoefficient = 0.965; public ScoreSaberLeaderboard() { - super("ScoreSaber", new LeaderboardCurvePoint[] { + super("ScoreSaber", 1, new LeaderboardCurvePoint[] { new LeaderboardCurvePoint(1.0, 5.367394282890631), new LeaderboardCurvePoint(0.9995, 5.019543595874787), new LeaderboardCurvePoint(0.999, 4.715470646416203), diff --git a/src/main/java/cc/fascinated/backend/model/score/Score.java b/src/main/java/cc/fascinated/backend/model/score/Score.java index b793b12..e3f25a1 100644 --- a/src/main/java/cc/fascinated/backend/model/score/Score.java +++ b/src/main/java/cc/fascinated/backend/model/score/Score.java @@ -1,6 +1,7 @@ package cc.fascinated.backend.model.score; import cc.fascinated.backend.common.DateUtils; +import cc.fascinated.backend.leaderboard.impl.ScoreSaberLeaderboard; import cc.fascinated.backend.model.token.ScoreSaberLeaderboardToken; import cc.fascinated.backend.model.token.ScoreSaberPlayerScoreToken; import cc.fascinated.backend.model.token.ScoreSaberScoreToken; @@ -8,8 +9,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.index.CompoundIndex; -import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; import java.util.ArrayList; @@ -20,7 +19,7 @@ import java.util.List; * A score for an account. */ @Document -@AllArgsConstructor @Getter @Setter +@Getter @Setter public class Score { /** * The id for this score. @@ -128,11 +127,45 @@ public class Score { */ private String leaderboardId; + /** + * The curve version for this score. + */ + private Integer curveVersion; + /** * The difficulty this score was set on. */ private Difficulty difficulty; + public Score(String id, int rank, int baseScore, int modifiedScore, Double pp, int weight, List modifiers, + int multiplier, int badCuts, int missedNotes, int maxCombo, boolean fullCombo, int hmd, Date timeSet, + boolean hasReplay, String deviceHmd, String deviceControllerLeft, String deviceControllerRight, + List previousScores, String accountId, String leaderboardId, Integer curveVersion, Difficulty difficulty) { + this.id = id; + this.rank = rank; + this.baseScore = baseScore; + this.modifiedScore = modifiedScore; + this.pp = pp; + this.weight = weight; + this.modifiers = modifiers; + this.multiplier = multiplier; + this.badCuts = badCuts; + this.missedNotes = missedNotes; + this.maxCombo = maxCombo; + this.fullCombo = fullCombo; + this.hmd = hmd; + this.timeSet = timeSet; + this.hasReplay = hasReplay; + this.deviceHmd = deviceHmd; + this.deviceControllerLeft = deviceControllerLeft; + this.deviceControllerRight = deviceControllerRight; + this.previousScores = previousScores; + this.accountId = accountId; + this.leaderboardId = leaderboardId; + this.curveVersion = curveVersion == null ? ScoreSaberLeaderboard.INSTANCE.getCurveVersion() : curveVersion; + this.difficulty = difficulty; + } + /** * Gets a score from the given token. * @@ -171,6 +204,7 @@ public class Score { new ArrayList<>(), playerId, leaderboard.getId(), + ScoreSaberLeaderboard.INSTANCE.getCurveVersion(), // Get the curve version from the leaderboard. Difficulty.fromId(leaderboard.getDifficulty().getDifficulty()) ); } diff --git a/src/main/java/cc/fascinated/backend/service/AccountService.java b/src/main/java/cc/fascinated/backend/service/AccountService.java index fc1e067..a90d3e5 100644 --- a/src/main/java/cc/fascinated/backend/service/AccountService.java +++ b/src/main/java/cc/fascinated/backend/service/AccountService.java @@ -10,7 +10,6 @@ import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/cc/fascinated/backend/service/ScoreSaberService.java b/src/main/java/cc/fascinated/backend/service/ScoreSaberService.java index 165d018..dc2c4a9 100644 --- a/src/main/java/cc/fascinated/backend/service/ScoreSaberService.java +++ b/src/main/java/cc/fascinated/backend/service/ScoreSaberService.java @@ -120,33 +120,6 @@ public class ScoreSaberService extends TextWebSocketHandler { return scores; } - /** - * Fetch the scores until the specified score id. - * - * @param account The account. - * @param scoreUntil The score to fetch until. - * @return The scores. - */ - public List getScoreUntil(Account account, Score scoreUntil) { - List scores = new ArrayList<>(); - int page = 1; - do { - ScoreSaberScoresPageToken pageToken = getPageScores(account, page); - for (ScoreSaberPlayerScoreToken score : pageToken.getPlayerScores()) { - // If the score isn't the same as the scoreUntil, add it to the list. - if (!DateUtils.getDateFromString(score.getScore().getTimeSet()).equals(scoreUntil.getTimeSet())) { - scores.add(score); - } - - if (score.getScore().getId().equals(scoreUntil.getId())) { - // If the current score matches the specified scoreUntil, stop fetching. - return scores; - } - } - page++; - } while (true); - } - /** * Fetches the scores for the account. * @@ -165,9 +138,11 @@ public class ScoreSaberService extends TextWebSocketHandler { List leaderboardToSave = new ArrayList<>(); for (ScoreSaberScoresPageToken page : scoresPageTokens) { - for (ScoreSaberPlayerScoreToken score : page.getPlayerScores()) { - newScores.add(Score.fromToken(id, score)); - leaderboardToSave.add(Leaderboard.fromToken(score.getLeaderboard())); + for (ScoreSaberPlayerScoreToken scoreToken : page.getPlayerScores()) { + Score score = Score.fromToken(id, scoreToken); + newScores.add(score); + scores.add(score); + leaderboardToSave.add(Leaderboard.fromToken(scoreToken.getLeaderboard())); } } @@ -185,33 +160,39 @@ public class ScoreSaberService extends TextWebSocketHandler { long start = System.currentTimeMillis(); log.info("Fetching new scores for account '{}'.", id); - Score latestScore = scoreRepository.getScoresSortedByNewest(id).get(0); - List newScores = this.getScoreUntil(account, latestScore); - if (newScores.isEmpty()) { - log.info("No new scores found for account '{}'.", id); - return; - } - - int newScoreCount = 0; - for (ScoreSaberPlayerScoreToken newScore : newScores) { - if (saveScore(account, newScore)) { - newScoreCount++; + int page = 1; // The current page to search for scores. + boolean done = false; // Whether we are done fetching scores. + List newScores = new ArrayList<>(); + do { + // This will keep fetching score pages until it finds a score that already exists. + ScoreSaberScoresPageToken pageScores = getPageScores(account, page); + for (ScoreSaberPlayerScoreToken score : pageScores.getPlayerScores()) { + boolean exists = scores.stream().anyMatch(s -> s.getId().equals(score.getScore().getId())); + if (!exists) { + newScores.add(score); + continue; + } + done = true; } + page++; + } while (!done); + + // Save the new scores. + for (ScoreSaberPlayerScoreToken score : newScores) { + saveScore(account, score); } - log.info("Found {} new scores for account '{}'. (took: {}ms)", newScoreCount, id, System.currentTimeMillis() - start); + log.info("Found {} new scores for account '{}'. (took: {}ms)", newScores.size(), id, System.currentTimeMillis() - start); } /** * Saves the score for the account. * * @param account The account. - * @param score The score to save. - * @return Whether the score was saved. + * @param score The score to save. */ - private boolean saveScore(Account account, ScoreSaberPlayerScoreToken score) { - boolean didSave = false; + private void saveScore(Account account, ScoreSaberPlayerScoreToken score) { Leaderboard newScoreLeaderboard = Leaderboard.fromToken(score.getLeaderboard()); Score oldScore = scoreRepository.findById(score.getScore().getId()).orElse(null); @@ -227,19 +208,16 @@ public class ScoreSaberService extends TextWebSocketHandler { scoreRepository.delete(oldScore); // Delete the old score. scoreRepository.save(scoreSet); // Save the new score. - didSave = true; } } else { // The score is new scoreRepository.save(Score.fromToken(account.getId(), score)); // Save the new score. - didSave = true; } // Check if the leaderboard doesn't already exist. if (leaderboardRepository.findById(newScoreLeaderboard.getId()).isEmpty()) { leaderboardRepository.save(newScoreLeaderboard); // Save the leaderboard. } - return didSave; } /** @@ -276,9 +254,21 @@ public class ScoreSaberService extends TextWebSocketHandler { */ @SneakyThrows private void connectWebSocket() { + log.info("Connecting to the ScoreSaber WSS."); new StandardWebSocketClient().execute(this, "wss://scoresaber.com/ws").get(); } + @Override + public void afterConnectionEstablished(@NonNull WebSocketSession session) { + log.info("Connected to the ScoreSaber WSS."); + } + + @Override + public void afterConnectionClosed(@NonNull WebSocketSession session, @NonNull CloseStatus status) { + log.info("Disconnected from the ScoreSaber WSS."); + connectWebSocket(); // Reconnect to the WebSocket. + } + @Override @SneakyThrows protected void handleTextMessage(@NonNull WebSocketSession session, @NonNull TextMessage message) { // Ignore the connection message. @@ -310,10 +300,4 @@ public class ScoreSaberService extends TextWebSocketHandler { log.error("An error occurred while handling the message.", ex); } } - - @Override - public void afterConnectionClosed(@NonNull WebSocketSession session, @NonNull CloseStatus status) { - log.info("Disconnected from the ScoreSaber WSS."); - connectWebSocket(); // Reconnect to the WebSocket. - } }