diff --git a/AquaNet/src/components/RatingComposition.svelte b/AquaNet/src/components/RatingComposition.svelte
index dd285f21..a32041da 100644
--- a/AquaNet/src/components/RatingComposition.svelte
+++ b/AquaNet/src/components/RatingComposition.svelte
@@ -16,19 +16,25 @@
if (top) split = split?.toSorted((a, b) => b.score - a.score).slice(0, top)
if (split) console.log("Split", split)
+
+ let mustResize = split && split.length > 12
-{#if split && comp}
-
-
{title}
-
- {#each split as p}
-
-
-
- {/each}
+{#if split && split.length > 0 && comp}
+
+ {#if mustResize}
+
+ {/if}
+
+
{title}
+
+ {#each split as p}
+
+
+
+ {/each}
+
-
{/if}
diff --git a/AquaNet/src/libs/generalTypes.ts b/AquaNet/src/libs/generalTypes.ts
index 069b8e91..da82d445 100644
--- a/AquaNet/src/libs/generalTypes.ts
+++ b/AquaNet/src/libs/generalTypes.ts
@@ -79,7 +79,8 @@ export interface GenericRanking {
rating: number
fullCombo: number
allPerfect: number
- lastSeen: string
+ lastSeen: string,
+ modernRating: number
}
export interface RankCount {
diff --git a/AquaNet/src/libs/i18n/en_ref.ts b/AquaNet/src/libs/i18n/en_ref.ts
index e68513b0..8a119cc0 100644
--- a/AquaNet/src/libs/i18n/en_ref.ts
+++ b/AquaNet/src/libs/i18n/en_ref.ts
@@ -2,6 +2,8 @@ export const EN_REF_USER = {
'UserHome.ServerRank': 'Server Rank',
'UserHome.DXRating': 'DX Rating',
'UserHome.Rating': 'Rating',
+ 'UserHome.LegacyRating': 'Legacy Rating',
+ 'UserHome.ModernRating': 'Modern Rating',
'UserHome.Statistics': 'Statistics',
'UserHome.Accuracy': 'Accuracy',
'UserHome.MaxCombo': 'Max Combo',
@@ -24,6 +26,16 @@ export const EN_REF_USER = {
'UserHome.RankDetail.Title': 'Achievement Details',
'UserHome.RankDetail.Level': 'Level',
'UserHome.B50': 'B50',
+ 'UserHome.RatingComposition.Best50': 'Best 50',
+ 'UserHome.RatingComposition.Best35': 'Best 35',
+ 'UserHome.RatingComposition.Best30': 'Best 30',
+ 'UserHome.RatingComposition.Best15': 'Best 15',
+ 'UserHome.RatingComposition.New15': 'New 15',
+ 'UserHome.RatingComposition.New10': 'New 10',
+ 'UserHome.RatingComposition.Best25Candidates': 'Best 25 (Candidates)',
+ 'UserHome.RatingComposition.Platinum': 'Platinum',
+ 'UserHome.RatingComposition.New20': 'New 20',
+ 'UserHome.RatingComposition.Recent10': 'Recent 10',
'UserHome.AddRival': "Add to Rival",
'UserHome.RemoveRival': "Remove from Rival",
'UserHome.InvalidGame': "Game ${game} is not supported on the web UI yet. We only support maimai, chunithm, wacca, and ongeki for now.",
@@ -67,6 +79,8 @@ export const EN_REF_LEADERBOARD = {
'Leaderboard.Title': 'Server Leaderboard',
'Leaderboard.Rank': 'Rank',
'Leaderboard.Rating': 'Rating',
+ 'Leaderboard.LegacyRating': 'Legacy Rating',
+ 'Leaderboard.ModernRating': 'Modern Rating',
'Leaderboard.Accuracy': 'Accuracy',
'Leaderboard.FC': 'FC',
'Leaderboard.AP': 'AP',
diff --git a/AquaNet/src/libs/i18n/zh.ts b/AquaNet/src/libs/i18n/zh.ts
index dee56fb8..bdb58cad 100644
--- a/AquaNet/src/libs/i18n/zh.ts
+++ b/AquaNet/src/libs/i18n/zh.ts
@@ -15,6 +15,8 @@ const zhUser: typeof EN_REF_USER = {
'UserHome.ServerRank': '服务器排名',
'UserHome.DXRating': 'DX B50',
'UserHome.Rating': '评分',
+ 'UserHome.LegacyRating': '旧评分',
+ 'UserHome.ModernRating': '新评分',
'UserHome.Statistics': '统计数据',
'UserHome.Accuracy': '准确率',
'UserHome.MaxCombo': '最大连击',
@@ -37,6 +39,16 @@ const zhUser: typeof EN_REF_USER = {
'UserHome.RankDetail.Title': '评分详细',
'UserHome.RankDetail.Level': "等级",
'UserHome.B50': "B50",
+ 'UserHome.RatingComposition.Best50': '最佳 50',
+ 'UserHome.RatingComposition.Best35': '最佳 35',
+ 'UserHome.RatingComposition.Best30': '最佳 30',
+ 'UserHome.RatingComposition.Best15': '最佳 15',
+ 'UserHome.RatingComposition.New15': '新曲 15',
+ 'UserHome.RatingComposition.New10': '新曲 10',
+ 'UserHome.RatingComposition.Best25Candidates': '最佳 25(候选)',
+ 'UserHome.RatingComposition.Platinum': '白金分',
+ 'UserHome.RatingComposition.New20': '新曲 20',
+ 'UserHome.RatingComposition.Recent10': '最近 10',
'UserHome.AddRival': "添加劲敌",
'UserHome.RemoveRival': "移除劲敌",
'UserHome.InvalidGame': "游戏 ${game} 还不支持网页端查看。我们目前只支持舞萌、中二、华卡和音击。",
@@ -73,12 +85,15 @@ const zhWelcome: typeof EN_REF_Welcome = {
'welcome.verified': '您的邮箱已经验证成功!您现在可以登录了',
'welcome.verification-failed': '验证失败:${message}。请重试',
'welcome.password-reset-done': '您的密码已更新!请重新登录',
+ 'welcome.login_link': '登录或注册以绑定卡片。',
}
const zhLeaderboard: typeof EN_REF_LEADERBOARD = {
'Leaderboard.Title': '排行榜',
'Leaderboard.Rank': '排名',
'Leaderboard.Rating': '评分',
+ 'Leaderboard.LegacyRating': '旧评分',
+ 'Leaderboard.ModernRating': '新评分',
'Leaderboard.Accuracy': '准确率',
'Leaderboard.FC': 'FC',
'Leaderboard.AP': 'AP',
diff --git a/AquaNet/src/libs/ongekiTypes.ts b/AquaNet/src/libs/ongekiTypes.ts
index 5f107fe2..a5981dbd 100644
--- a/AquaNet/src/libs/ongekiTypes.ts
+++ b/AquaNet/src/libs/ongekiTypes.ts
@@ -22,3 +22,8 @@ export interface OngekiUserSummaryEntry {
recent10: string
recent: GenericGamePlaylog[]
}
+
+export interface OngekiRefreshData {
+ playerRating: number,
+ highestRating: number
+}
\ No newline at end of file
diff --git a/AquaNet/src/libs/sdk.ts b/AquaNet/src/libs/sdk.ts
index 1c04775c..2ad3ac98 100644
--- a/AquaNet/src/libs/sdk.ts
+++ b/AquaNet/src/libs/sdk.ts
@@ -12,6 +12,7 @@ import type {
Dict,
GameUserOption
} from './generalTypes'
+import type { OngekiRefreshData } from './ongekiTypes'
import type { GameName } from './scoring'
interface ExtReqInit extends RequestInit {
@@ -244,6 +245,8 @@ export const GAME = {
post(`/api/v2/game/${game}/import-music-detail`, {}, { json: data }),
setRival: (game: GameName, rivalUserName: string, isAdd: boolean) =>
post(`/api/v2/game/${game}/set-rival`, { rivalUserName, isAdd }),
+ refreshData: (username: string): Promise
=>
+ post(`/api/v2/game/ongeki/refresh-data`, { username })
}
export const DATA = {
diff --git a/AquaNet/src/pages/Ranking.svelte b/AquaNet/src/pages/Ranking.svelte
index 52269922..543da201 100644
--- a/AquaNet/src/pages/Ranking.svelte
+++ b/AquaNet/src/pages/Ranking.svelte
@@ -52,7 +52,12 @@
hoveringUser = ""} role="heading" aria-level="2">
{t("Leaderboard.Rank")}
-
{t("Leaderboard.Rating")}
+ {#if game == "ongeki"}
+
{t("Leaderboard.ModernRating")}
+
{t("Leaderboard.LegacyRating")}
+ {:else}
+
{t("Leaderboard.Rating")}
+ {/if}
{t("Leaderboard.Accuracy")}
{t("Leaderboard.FC")}
{t("Leaderboard.AP")}
@@ -70,11 +75,23 @@
{user.name}
{/if}
-
{
- game === 'chu3' || game === 'ongeki' ?
- (user.rating / 100).toFixed(2) :
- user.rating.toLocaleString()
- }
+ {#if game == 'ongeki'}
+ {#if user.modernRating > 0}
+
{
+ user.modernRating.toLocaleString()
+ }
+ {/if}
+
{
+ (user.rating / 100).toFixed(2)
+ }
+ {:else}
+
{
+ game === 'chu3' ?
+ (user.rating / 100).toFixed(2) :
+ user.rating.toLocaleString()
+ }
+ {/if}
+
{(+user.accuracy).toFixed(2)}%
{user.fullCombo}
{user.allPerfect}
@@ -141,6 +158,14 @@
.accuracy
display: none
+ .modern-rating
+ display: none
+ .legacy-rating
+ /* this is officially the worst css i've ever written dear god */
+ white-space: nowrap
+ overflow: hidden
+ text-overflow: clip
+ min-width: 3.5em !important
&.alternate
background-color: vars.$ov-light
diff --git a/AquaNet/src/pages/UserHome.svelte b/AquaNet/src/pages/UserHome.svelte
index d9f25442..f48232d3 100644
--- a/AquaNet/src/pages/UserHome.svelte
+++ b/AquaNet/src/pages/UserHome.svelte
@@ -24,6 +24,7 @@
import useLocalStorage from "../libs/hooks/useLocalStorage.svelte";
import Line from "../components/chart/Line.svelte";
import ChuniUserboxDisplay from "../components/settings/userbox/ChuniUserboxDisplay.svelte";
+ import type { OngekiRefreshData } from "../libs/ongekiTypes";
const TREND_DAYS = 60
@@ -51,6 +52,8 @@
let isLoading = false
let showMoreRecent = false
+ let ongekiData: OngekiRefreshData
+
function init() {
USER.isLoggedIn() && USER.me().then(u => me = u)
@@ -77,7 +80,7 @@
GAME.userSummary(username, game),
GAME.trend(username, game),
DATA.allMusic(game),
- ]).then(([user, trend, music]) => {
+ ]).then(async ([user, trend, music]) => {
console.log(user)
console.log(trend)
console.log(games)
@@ -92,6 +95,11 @@
})
}
+ if (game == 'ongeki') {
+ let ogkData = await GAME.refreshData(username).catch(err => {});
+ if(ogkData) ongekiData = ogkData
+ }
+
// Set beforeRating in recent to the last play's afterRating
user.recent.forEach((it, i) => {
if (i < user.recent.length - 1) {
@@ -187,14 +195,28 @@
-
- {game === 'mai2' ? t("UserHome.DXRating"): t("UserHome.Rating")}
- {
- game === 'chu3' || game === 'ongeki' ?
- (d.user.rating / 100).toFixed(2) :
- d.user.rating.toLocaleString()
- }
-
+
+
+ {#if game == "ongeki" && ongekiData}
+
+
+ {t("UserHome.ModernRating")}
+ {ongekiData.playerRating.toLocaleString()}
+
+
+ {t("UserHome.LegacyRating")}
+ {(d.user.rating / 100).toFixed(2)}
+
+ {:else}
+
+ {game === 'mai2' ? t("UserHome.DXRating"): t("UserHome.Rating")}
+ {
+ game === 'chu3' ?
+ (d.user.rating / 100).toFixed(2) :
+ d.user.rating.toLocaleString()
+ }
+
+ {/if}
{t('UserHome.ServerRank')}
@@ -306,18 +328,20 @@
-
+
+
+
+
+
+
+
+
-
-
-
-
-
{#if d.user.ratingComposition.new}
-
+
{:else}
-
+
{/if}
diff --git a/src/main/java/icu/samnyan/aqua/net/games/GameApiController.kt b/src/main/java/icu/samnyan/aqua/net/games/GameApiController.kt
index 496757c6..1a28cb37 100644
--- a/src/main/java/icu/samnyan/aqua/net/games/GameApiController.kt
+++ b/src/main/java/icu/samnyan/aqua/net/games/GameApiController.kt
@@ -57,7 +57,7 @@ abstract class GameApiController(val name: String, userDataClass:
val time = millis()
// Check cache validity
- if (rankingCache.isEmpty()) (500 - "Rank is empty or is currently computing. Please come back later.")
+ if (rankingCache.isEmpty()) (500 - "Rank is empty or is currently computing.")
val reqUser = token?.let { us.jwt.auth(it) }?.let { u ->
// Optimization: If the user is not banned, we don't need to process user information
@@ -98,7 +98,7 @@ abstract class GameApiController(val name: String, userDataClass:
SUM(p.is_full_combo) AS fc,
SUM(p.is_all_perfect) AS ap,
c.ranking_banned or a.opt_out_of_leaderboard or c.status = 12 AS hide,
- a.username
+ a.username ${if (name == "ongeki") ", u.new_player_rating" else ""}
FROM ${tableName}_user_playlog_view p
JOIN ${tableName}_user_data_view u ON p.user_id = u.id
JOIN sega_card c ON u.aime_card_id = c.id
@@ -115,7 +115,8 @@ abstract class GameApiController(val name: String, userDataClass:
accuracy = it[4]!!.double,
fullCombo = it[5]!!.int,
allPerfect = it[6]!!.int,
- username = it[8]?.toString() ?: "user${it[0]}"
+ username = it[8]?.toString() ?: "user${it[0]}",
+ modernRating = if (name == "ongeki") it[9]?.int() ?: 0 else 0
)
}
rankingSortedIndex = rankingCache.filter { !it.l }.map { it.r.rating }.reversed()
diff --git a/src/main/java/icu/samnyan/aqua/net/games/Models.kt b/src/main/java/icu/samnyan/aqua/net/games/Models.kt
index 5fefbb11..a4bcc14e 100644
--- a/src/main/java/icu/samnyan/aqua/net/games/Models.kt
+++ b/src/main/java/icu/samnyan/aqua/net/games/Models.kt
@@ -59,7 +59,8 @@ data class GenericRankingPlayer(
val rating: Int,
val allPerfect: Int,
val fullCombo: Int,
- val lastSeen: String
+ val lastSeen: String,
+ val modernRating: Int = 0
)
@Serializable
diff --git a/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt b/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt
index 8c95ef54..92b45676 100644
--- a/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt
+++ b/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt
@@ -60,7 +60,7 @@ class Maimai2(
val ratingComposition = mapOf(
"best35" to (extra["recent_rating"] ?: ""),
- "best15" to (extra["recent_rating_new"] ?: "")
+ "new15" to (extra["recent_rating_new"] ?: "")
)
// if isLogin than boolean or null
diff --git a/src/main/java/icu/samnyan/aqua/net/games/ongeki/Ongeki.kt b/src/main/java/icu/samnyan/aqua/net/games/ongeki/Ongeki.kt
index 57e3fe37..f03d2fc1 100644
--- a/src/main/java/icu/samnyan/aqua/net/games/ongeki/Ongeki.kt
+++ b/src/main/java/icu/samnyan/aqua/net/games/ongeki/Ongeki.kt
@@ -42,16 +42,35 @@ class Ongeki(
) }
override suspend fun userSummary(username: String, token: String?) = us.cardByName(username) { card ->
+ val user = userDataRepo.findByCard_ExtId(card.extId) ?: (404 - "User not found")
val extra = userGeneralDataRepository.findByUser_Card_ExtId(card.extId)
.associate { it.propertyKey to it.propertyValue }
- val ratingComposition = mapOf(
- "best30" to (extra["rating_base_best"] ?: ""),
- "best15" to (extra["rating_base_new_best"] ?: ""),
- "recent10" to (extra["rating_base_hot_best"] ?: "")
- )
+ val isRefresh = user.newHighestRating > 0
+ if (isRefresh)
+ genericUserSummary(card, mapOf(
+ "best50" to (extra["new_rating_base_best"] ?: ""),
+ "new10" to (extra["new_rating_base_new_best"] ?: ""),
+ "best25_candidates" to (extra["new_rating_base_next_best"] ?: ""),
+ "pscore" to (extra["new_rating_base_pscore"] ?: "")
+ ))
+ else
+ genericUserSummary(card, mapOf(
+ "best30" to (extra["rating_base_best"] ?: ""),
+ "new15" to (extra["rating_base_new_best"] ?: ""),
+ "recent10" to (extra["rating_base_hot_best"] ?: "")
+ ))
+ }
- genericUserSummary(card, ratingComposition)
+ @API("refresh-data")
+ suspend fun refreshData(@RP username: String) = us.cardByName(username) { card ->
+ val user = userDataRepo.findByCard_ExtId(card.extId) ?: (404 - "User not found")
+ if (user.newHighestRating > 0)
+ mapOf(
+ "playerRating" to user.newPlayerRating,
+ "highestRating" to user.newHighestRating
+ )
+ else (400 - "User has not played Refresh")
}
@API("user-option")
diff --git a/src/main/resources/db/80/V1000_79__ongeki_fk_2.sql b/src/main/resources/db/80/V1000_79__ongeki_fk_2.sql
new file mode 100644
index 00000000..11cef5dc
--- /dev/null
+++ b/src/main/resources/db/80/V1000_79__ongeki_fk_2.sql
@@ -0,0 +1,14 @@
+ALTER TABLE ongeki_user_regions
+DROP FOREIGN KEY IF EXISTS fk_ongekiregions_on_ongeki_user_data;
+
+ALTER TABLE ongeki_user_regions
+DROP FOREIGN KEY IF EXISTS fk_ongekiregions_on_aqua_net_user;
+
+ALTER TABLE ongeki_user_regions
+ ADD CONSTRAINT fk_ongekiregions_on_ongeki_user_data
+ FOREIGN KEY (user_id) REFERENCES ongeki_user_data (id)
+ ON DELETE CASCADE ON UPDATE CASCADE;
+
+DROP VIEW IF EXISTS ongeki_user_data_view;
+ CREATE VIEW ongeki_user_data_view AS
+ SELECT * FROM ongeki_user_data;
\ No newline at end of file