diff --git a/src/main/java/ext/Ext.kt b/src/main/java/ext/Ext.kt index dff3d0b5..a4b7ec22 100644 --- a/src/main/java/ext/Ext.kt +++ b/src/main/java/ext/Ext.kt @@ -102,7 +102,10 @@ inline fun resJson(name: Str, warn: Boolean = true) = resStr(name)?. fun millis() = System.currentTimeMillis() val DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd") fun LocalDate.isoDate() = format(DATE_FORMAT) +fun String.isoDate() = DATE_FORMAT.parse(this, LocalDate::from) +fun LocalDate.toDate() = Date(atStartOfDay().toInstant(java.time.ZoneOffset.UTC).toEpochMilli()) fun LocalDateTime.isoDateTime() = format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) +fun String.isoDateTime() = LocalDateTime.parse(this, DateTimeFormatter.ISO_LOCAL_DATE_TIME) val URL_SAFE_DT = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss") fun LocalDateTime.urlSafeStr() = format(URL_SAFE_DT) @@ -114,6 +117,7 @@ catch (e: Exception) { null } } val Calendar.year get() = get(Calendar.YEAR) val Calendar.month get() = get(Calendar.MONTH) + 1 val Calendar.day get() = get(Calendar.DAY_OF_MONTH) +val Date.sec get() = time / 1000 // Encodings fun Long.toHex(len: Int = 16): Str = "0x${this.toString(len).padStart(len, '0').uppercase()}" diff --git a/src/main/java/icu/samnyan/aqua/sega/wacca/WaccaServer.kt b/src/main/java/icu/samnyan/aqua/sega/wacca/WaccaServer.kt index 3705dbc6..7ed9ae55 100644 --- a/src/main/java/icu/samnyan/aqua/sega/wacca/WaccaServer.kt +++ b/src/main/java/icu/samnyan/aqua/sega/wacca/WaccaServer.kt @@ -8,6 +8,7 @@ import icu.samnyan.aqua.sega.wacca.WaccaOptionType.SET_TITLE_ID import icu.samnyan.aqua.sega.wacca.model.BaseRequest import icu.samnyan.aqua.sega.wacca.model.db.WaccaRepos import icu.samnyan.aqua.sega.wacca.model.db.WaccaUser +import icu.samnyan.aqua.sega.wacca.model.db.WcUserGate import io.ktor.client.utils.* import jakarta.servlet.http.HttpServletRequest import org.springframework.http.ResponseEntity @@ -24,6 +25,7 @@ class WaccaServer(val rp: WaccaRepos, val cardRepo: CardRepository) { val log = logger() val season = 3 + val enabledGates = 1..24 init { init() } @@ -145,13 +147,19 @@ fun WaccaServer.init() { val scores = rp.bestScore.findByUser(u) val gates = rp.gate.findByUser(u) val bingo = rp.bingo.findByUser(u).firstOrNull() + val go = u.card.aquaUser?.gameOptions + + // TODO: make this and vip configurable + u.wp = 999999 u.run { ls("status" - lStatus(), "options" - o.map { (k, v) -> ls(k, v) }, "seasonalPlayModeCounts" - (ls(playcountSingle, playcountMultiVs, playcountMultiCoop, playcountStageup, playcountTimeFree) - .mapIndexed { i, it -> ls(season, i + 1, it) } + ls(0, 1, 1)), - "items" - ls(MUSIC_UNLOCK, TITLE, ICON, TROPHY, SKILL, TICKET, NOTE_COLOR, NOTE_SOUND, NAVIGATOR, USER_PLATE, TOUCH_EFFECT) - .map { items[it()]?.map { it.ls() } }, + .mapIndexed { i, it -> ls(season, i + 1, it) } + ls(ls(0, 1, 1))), + "items" - ls(MUSIC_UNLOCK, TITLE, ICON, TROPHY, SKILL, TICKET, NOTE_COLOR, NOTE_SOUND, NAVIGATOR, USER_PLATE, TOUCH_EFFECT).map { + if (it == TICKET && go?.unlockTickets == true) (0..4).map { ls(it, 106002, 0) } + else items[it()]?.map { it.ls() } ?: empty + }, "scores" - scores.map { it.ls() }, "songPlayStatus" - ls(lastSongId, 1), "seasonInfo" - ls(xp, wpTotal, wpSpent, scores.sumOf { it.score }, @@ -163,9 +171,11 @@ fun WaccaServer.init() { "favorites" - rp.favoriteSong.findByUser(u).map { it.songId }, "stoppedSongIds" - empty, "events" - empty, - "gate" - gates.map { it.ls() }, + "gate" - gates.associateBy { it.gateId }.let { gateMap -> enabledGates.map { + gateMap[it]?.ls() ?: WcUserGate().apply { gateId = it }.ls() + } }, "lastSongInfo" - ls(lastSongId, lastSongDifficulty, lastFolderOrder, lastFolderId, lastSongOrder), - "gateTutorialFlags" - (gateTutorialFlags ?: "[]").jsonArray().map { it as Array<*> }.map { ls(it[0], it[1]?.long()) }, + "gateTutorialFlags" - gateTutorialFlags.jsonArray(), "gatchaInfo" - empty, "friendList" - empty, "bingoStatus" - ls( diff --git a/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt b/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt index ba2a5573..4b1288ea 100644 --- a/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt +++ b/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUser.kt @@ -1,6 +1,9 @@ package icu.samnyan.aqua.sega.wacca.model.db +import ext.isoDate import ext.ls +import ext.sec +import ext.toDate import icu.samnyan.aqua.net.games.BaseEntity import icu.samnyan.aqua.sega.general.model.Card import jakarta.persistence.* @@ -29,7 +32,7 @@ class WaccaUser : BaseEntity() { var title2 = 0 var rating = 0 @Temporal(TemporalType.TIMESTAMP) - var vipExpireTime: Date = Date(0) + var vipExpireTime: Date = "2077-01-01".isoDate().toDate() var alwaysVip = false var loginCount = 0 var loginCountConsec = 0 @@ -52,9 +55,9 @@ class WaccaUser : BaseEntity() { var lastFolderId = 0 var lastSongOrder = 0 @Temporal(TemporalType.TIMESTAMP) - var lastLoginDate: Date = Date(0) - var gateTutorialFlags: String? = null + var lastLoginDate: Date = Date() + var gateTutorialFlags: String = "[[1, 0], [2, 0], [3, 0], [4, 0], [5, 0]]" fun lStatus() = ls(card.extId, username, 1, xp, danLevel, danType, wp, ls(0, 0, 0), loginCount, loginCountDays, - loginCountConsec, loginCountDaysConsec, vipExpireTime, loginCountToday, rating) + loginCountConsec, loginCountDaysConsec, vipExpireTime.sec, loginCountToday, rating) } \ No newline at end of file diff --git a/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt b/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt index e4195e05..cfaa8c96 100644 --- a/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt +++ b/src/main/java/icu/samnyan/aqua/sega/wacca/model/db/WaccaUserModels.kt @@ -2,6 +2,7 @@ package icu.samnyan.aqua.sega.wacca.model.db import com.fasterxml.jackson.annotation.JsonIgnore import ext.ls +import ext.sec import icu.samnyan.aqua.net.games.BaseEntity import icu.samnyan.aqua.sega.wacca.WaccaItemType import icu.samnyan.aqua.sega.wacca.WaccaItemType.* @@ -55,7 +56,7 @@ class WcUserFavoriteSong : WaccaUserEntity() { @Entity @Table(name = "wacca_user_gate", uniqueConstraints = [UC("", ["user_id", "gate_id"])]) class WcUserGate : WaccaUserEntity() { var gateId = 0 - var page = 0 + var page = 1 var progress = 0 var loops = 0 @Temporal(TemporalType.TIMESTAMP) @@ -63,7 +64,7 @@ class WcUserGate : WaccaUserEntity() { var missionFlag = 0 var totalPoints = 0 - fun ls() = ls(gateId, page, progress, loops, lastUsed, missionFlag) + fun ls() = ls(gateId, 1, page, progress, loops, lastUsed, missionFlag) } @Entity @Table(name = "wacca_user_item", uniqueConstraints = [UC("", ["user_id", "item_id", "type"])]) @@ -80,15 +81,15 @@ class WcUserItem( var acquiredDate: Date = Date(), ) : WaccaUserEntity() { fun ls() = when (type) { - MUSIC_UNLOCK() -> ls(itemId, p1, acquiredDate, acquiredDate) // songId, diff, acquireDate, unlockDate - ICON() -> ls(itemId, type, p1, acquiredDate) // id, type, uses, acquiredDate + MUSIC_UNLOCK() -> ls(itemId, p1, acquiredDate.sec, acquiredDate.sec) // songId, diff, acquireDate, unlockDate + ICON() -> ls(itemId, 1, p1, acquiredDate.sec) // id, type, uses, acquiredDate TROPHY() -> ls(itemId, p1, p2, p3) // id, season, progress, badgeType SKILL() -> ls(itemId, p1, p2, p3) // skillType, level, flag, badge TICKET() -> ls(id, itemId, p1) // userTicketId, ticketId, expire - NAVIGATOR() -> ls(itemId, type, acquiredDate, p1, p2) // id, type, acquiredDate, uses, usesToday + NAVIGATOR() -> ls(itemId, 1, acquiredDate.sec, p1, p2) // id, type, acquiredDate, uses, usesToday // Generic: title, note colors, note sounds, plates, touch effects - else -> ls(itemId, type, acquiredDate) // id, type, acquireDate + else -> ls(itemId, 1, acquiredDate.sec) // id, type, acquireDate } infix fun isType(t: WaccaItemType) = type == t() diff --git a/src/test/kotlin/test/WaccaTest.kt b/src/test/kotlin/test/WaccaTest.kt index be453e8e..5986438c 100644 --- a/src/test/kotlin/test/WaccaTest.kt +++ b/src/test/kotlin/test/WaccaTest.kt @@ -29,19 +29,16 @@ class WaccaTest : StringSpec({ } infix fun List.exp(expected: List) { - expected.size shouldBe size - for (i in indices) { - val a = this[i] - when (val b = expected[i]) { - null -> {} // Use null to ignore the value - is List<*> -> a as List exp b as List - else -> a shouldBe b - } - } + // Replace all timestamps as null + val start = millis().toString().substring(0..3) + val lst = this.toJson().replace(Regex("""$start\d{6}(?=[], ])"""), "null").jsonArray() + lst shouldBe expected } infix fun List.exp(json: String) = exp(json.jsonArray()) + System.getProperty("kotest.assertions.collection.print.size", "1000") + beforeTest { if (uid == 0L) uid = registerUser() } @@ -62,12 +59,12 @@ class WaccaTest : StringSpec({ "user/status/get #1" { post("user/status/get", """["$uid"]""").res exp - """[[0, "", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 0, 0, 0], 104001, 102001, 1, [2, "1.0.0"], []]""" + """[[0, "", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 3376684800, 0, 0], 104001, 102001, 1, [2, "1.0.0"], []]""" } "user/status/create #1" { post("user/status/create", """["$uid", "AZA"]""").res exp - """[[$uid, "AZA", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 0, 0, 0]]""" + """[[$uid, "AZA", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 3376684800, 0, 0]]""" } "user/status/login Guest" { @@ -79,4 +76,9 @@ class WaccaTest : StringSpec({ post("user/status/login", "[$uid]").res exp "[[], [], [], 0, [2077, 1, 1, 1, [], []], null, []]" } + + "user/status/getDetail #1" { + post("user/status/getDetail", "[$uid]").res exp + """[[$uid, "AZA", 1, 0, 0, 0, 999999, [0, 0, 0], 1, 0, 0, 0, 3376684800, 1, 0], [], [[3, 1, 0], [3, 2, 0], [3, 3, 0], [3, 4, 0], [3, 5, 0], [0, 1, 1]], [[], [[104001, 1, null], [104002, 1, null], [104003, 1, null], [104005, 1, null]], [[102001, 1, 0, null], [102002, 1, 0, null]], [], [], [], [[103001, 1, null], [203001, 1, null]], [[105001, 1, null], [205005, 1, null]], [[210001, 1, null, 0, 0], [210002, 1, null, 0, 0], [210054, 1, null, 0, 0], [210055, 1, null, 0, 0], [210056, 1, null, 0, 0], [210057, 1, null, 0, 0], [210058, 1, null, 0, 0], [210059, 1, null, 0, 0], [210060, 1, null, 0, 0], [210061, 1, null, 0, 0], [310001, 1, null, 0, 0], [310002, 1, null, 0, 0]], [[211001, 1, null]], [[312000, 1, null], [312001, 1, null]]], [], [0, 1], [0, 0, 0, 0, 4, 2, 0, 2, 2, 1, 0], [[0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0]], null, [], [], [], [[1, 1, 1, 0, 0, 0, 0], [2, 1, 1, 0, 0, 0, 0], [3, 1, 1, 0, 0, 0, 0], [4, 1, 1, 0, 0, 0, 0], [5, 1, 1, 0, 0, 0, 0], [6, 1, 1, 0, 0, 0, 0], [7, 1, 1, 0, 0, 0, 0], [8, 1, 1, 0, 0, 0, 0], [9, 1, 1, 0, 0, 0, 0], [10, 1, 1, 0, 0, 0, 0], [11, 1, 1, 0, 0, 0, 0], [12, 1, 1, 0, 0, 0, 0], [13, 1, 1, 0, 0, 0, 0], [14, 1, 1, 0, 0, 0, 0], [15, 1, 1, 0, 0, 0, 0], [16, 1, 1, 0, 0, 0, 0], [17, 1, 1, 0, 0, 0, 0], [18, 1, 1, 0, 0, 0, 0], [19, 1, 1, 0, 0, 0, 0], [20, 1, 1, 0, 0, 0, 0], [21, 1, 1, 0, 0, 0, 0], [22, 1, 1, 0, 0, 0, 0], [23, 1, 1, 0, 0, 0, 0], [24, 1, 1, 0, 0, 0, 0]], [0, 0, 0, 0, 0], [[1, 0], [2, 0], [3, 0], [4, 0], [5, 0]], [], [], [0, []]]""" + } }) \ No newline at end of file