Merge branch 'v1-dev' and resolve all conflicts

This commit is contained in:
Azalea
2026-03-29 21:17:58 +00:00
10 changed files with 170 additions and 125 deletions
+9 -9
View File
@@ -32,15 +32,15 @@ Multipurpose game server for ALL.Net games.
> [!WARNING]
> CHUNITHM pre-NEW!! and maimai pre-DX are no longer supported after February 6th, 2026 and all associated data will be removed.
| Game | Latest Ver. | Initial Ver. | Notes |
|------------------------|---------------------|---------------------|-------------------------------------------------------------|
| SDHD: CHUNITHM | 2.45 (X-VERSE-X) | 2.00 (NEW) | |
| SDEZ: maimai DX | 1.65 (CiRCLE PLUS) | 1.00 (DX) | Missing circle (teams) support |
| SDGA: maimai DX (Intl) | 1.60 (CiRCLE) | 1.00 (DX) | Thanks [@Clansty](https://github.com/clansty) |
| SDED: Card Maker | 1.39 | N/A | Thanks [@Becods](https://github.com/Becods) |
| SDDT: O.N.G.E.K.I. | 1.50 (Re:Fresh) | N/A | Thanks [@PenguinCaptain](https://github.com/PenguinCaptain) |
| SBZV: Project DIVA | 7.10 | N/A | No web interface provided |
| SDFE: Wacca | 3.07 (Reverse) | N/A | Later versions are EOS patches, network will not work |
| Game | Latest Ver. | Initial Ver. | Notes | Web UI | Data Import |
|------------------------|---------------------|---------------------|-------------------------------------------------------------|--------|-------------|
| SDHD: CHUNITHM | 2.45 (X-VERSE-X) | 2.00 (NEW) | | ✅ | ❗ |
| SDEZ: maimai DX | 1.65 (CiRCLE PLUS) | 1.00 (DX) | Missing circle (teams) support | ✅ | ✅ |
| SDGA: maimai DX (Intl) | 1.60 (CiRCLE) | 1.00 (DX) | Thanks [@Clansty](https://github.com/clansty) | ✅ | ✅ |
| SDED: Card Maker | 1.39 | N/A | Thanks [@Becods](https://github.com/Becods) | ❌ | ❌ |
| SDDT: O.N.G.E.K.I. | 1.50 (Re:Fresh) | N/A | Thanks [@PenguinCaptain](https://github.com/PenguinCaptain) | ✅ | ❌ |
| SBZV: Project DIVA | 7.10 | N/A | Minimal support | ❌ | ❌ |
| SDFE: Wacca | 3.07 (Reverse) | N/A | Later versions are EOS patches, network will not work | ✅ | ❌ |
<!-- A majority of them have been left as N/A for initial version as they do not appear to have restrictions -->
+5
View File
@@ -0,0 +1,5 @@
```
gradle test -PrunTests --tests Mai2Test
```
@@ -377,7 +377,7 @@ fun ChusanController.chusanInit() {
}
// Static
"GetGameEvent" static { db.gameEvent.findByEnable(true).let { mapOf("type" to 1, "length" to it.size, "gameEventList" to it) } }
"GetGameEvent" static { db.gameEvent.findAll().let { mapOf("type" to 1, "length" to it.size, "gameEventList" to it) } }
"GetGameCharge" static { db.gameCharge.findAll().let { mapOf("length" to it.size, "gameChargeList" to it) } }
"GetGameGacha" static { db.gameGacha.findAll().let { mapOf("length" to it.size, "gameGachaList" to it, "registIdList" to empty) } }
"GetGameMapAreaCondition" static { ChusanData.mapAreaCondition }
@@ -53,7 +53,7 @@ fun Maimai2ServletController.initApis() {
}
// Maimai only request for event type 1
"GetGameEvent" static { mapOf("type" to 1, "gameEventList" to db.gameEvent.findByEnable(true)) }
"GetGameEvent" static { mapOf("type" to 1, "gameEventList" to db.gameEvent.findAll()) }
"GetGameCharge" static { db.gameCharge.findAll().let { mapOf("length" to it.size, "gameChargeList" to it) } }
"GetUserOption" { mapOf(
@@ -45,6 +45,8 @@ import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.NoRepositoryBean
import org.springframework.stereotype.Component
import icu.samnyan.aqua.sega.util.GameDataService
import icu.samnyan.aqua.sega.util.StaticRepo
import java.util.*
+27 -21
View File
@@ -13,7 +13,7 @@ class Mai2Test : StringSpec({
var userId = 0L
suspend fun post(url: String, body: String): Pair<HttpResponse, Map<String, Any?>> {
val resp = HTTP.post("$HOST/gs/$CLIENT_ID/mai2/$url") {
val resp = HTTP.post("$HOST/g/mai2/$url") {
contentType(ContentType.Application.Json)
setBody(body)
}
@@ -31,20 +31,23 @@ class Mai2Test : StringSpec({
"GetGameSettingApi" {
println("UserID: $userId")
post("GetGameSettingApi", """{"placeId":291,"clientId":"$CLIENT_ID"}""").let { (_, result) ->
result shouldBe """{"gameSetting":{"requestInterval":10,"rebootStartTime":"2099-01-01 23:59:00.0","rebootEndTime":"2099-01-01 23:59:00.0","movieUploadLimit":10000,"movieStatus":0,"movieServerUri":"","deliverServerUri":"","oldServerUri":"","usbDlServerUri":"","rebootInterval":0,"isMaintenance":false},"isAouAccession":true}""".jsonMap()
val gs = result["gameSetting"] as Map<*, *>
gs["requestInterval"] shouldBe 10
result["isAouAccession"] shouldBe true
}
}
"GetGameRankingApi" {
post("GetGameRankingApi", """{"type":1}""").let { (_, result) ->
result shouldBe """{"type":"1","gameRankingList":[]}""".jsonMap()
result["type"] shouldBe 1
assert(result["gameRankingList"] is List<*>)
}
}
"GetGameEventApi" {
post("GetGameEventApi", """{"type":1,"isAllEvent":true}""").let { (_, result) ->
result.keys shouldBe setOf("type", "gameEventList")
((result["gameEventList"] as List<*>).first() as Map<*, *>).keys shouldBe setOf("id", "type", "startDate", "endDate")
((result["gameEventList"] as List<*>).first() as Map<*, *>).keys shouldBe setOf("id", "type", "startDate", "endDate", "enable", "disableArea")
}
}
@@ -56,13 +59,13 @@ class Mai2Test : StringSpec({
"GetGameChargeApi" {
post("GetGameChargeApi", """{"isAll":false}""").let { (_, result) ->
result shouldBe """{"length":5,"gameChargeList":[{"orderId":1,"chargeId":2,"price":1,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"orderId":2,"chargeId":3,"price":2,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"orderId":3,"chargeId":4,"price":3,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"orderId":4,"chargeId":5,"price":4,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"orderId":5,"chargeId":6,"price":5,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"}]}""".jsonMap()
result shouldBe """{"length":5,"gameChargeList":[{"chargeId":0,"orderId":0,"price":1,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"chargeId":0,"orderId":0,"price":2,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"chargeId":0,"orderId":0,"price":3,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"chargeId":0,"orderId":0,"price":4,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"},{"chargeId":0,"orderId":0,"price":5,"startDate":"2019-01-01 00:00:00.000000","endDate":"2099-01-01 00:00:00.000000"}]}""".jsonMap()
}
}
"GetGameNgMusicIdApi" {
post("GetGameNgMusicIdApi", """{}""").let { (_, result) ->
result shouldBe """{"length":0,"musicIdList":[]}""".jsonMap()
result shouldBe """{"length":0,"musicIdList":[],"ngMusicDataList":[]}""".jsonMap()
}
}
@@ -115,13 +118,16 @@ class Mai2Test : StringSpec({
"GetUserDataApi" {
post("GetUserDataApi", """{"userId":$userId}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"userData":{"userName":"AZA☆","friendCode":"","isNetMember":1,"nameplateId":0,"iconId":11,"trophyId":0,"plateId":1,"titleId":11,"partnerId":1,"frameId":1,"selectMapId":400001,"totalAwake":0,"gradeRating":0,"musicRating":271,"playerRating":271,"highestRating":271,"gradeRank":0,"classRank":0,"courseRank":0,"charaSlot":[101,400101,105,104,103],"charaLockSlot":[0,0,0,0,0],"contentBit":2169888,"playCount":1,"eventWatchedDate":"2024-03-27 05:45:15.0","lastGameId":"SDEZ","lastRomVersion":"1.41.00","lastDataVersion":"1.40.08","lastLoginDate":"2024-03-27 05:45:15.0","lastPlayDate":"2024-03-27 05:56:54.0","lastPlayCredit":1,"lastPlayMode":0,"lastPlaceId":291,"lastPlaceName":"","lastAllNetId":0,"lastRegionId":1,"lastRegionName":"W","lastClientId":"$CLIENT_ID","lastCountryCode":"JPN","lastSelectEMoney":0,"lastSelectTicket":0,"lastSelectCourse":0,"lastCountCourse":0,"firstGameId":"SDEZ","firstRomVersion":"1.41.00","firstDataVersion":"1.40.08","firstPlayDate":"2024-03-27 05:45:15.0","compatibleCmVersion":"1.40.00","dailyBonusDate":"1970-01-01 09:00:00.0","dailyCourseBonusDate":"1970-01-01 09:00:00.0","lastPairLoginDate":"1970-01-01 09:00:00.0","lastTrialPlayDate":"1970-01-01 09:00:00.0","playVsCount":0,"playSyncCount":0,"winCount":0,"helpCount":0,"comboCount":0,"totalDeluxscore":1725,"totalBasicDeluxscore":0,"totalAdvancedDeluxscore":0,"totalExpertDeluxscore":1725,"totalMasterDeluxscore":0,"totalReMasterDeluxscore":0,"totalHiscore":0,"totalBasicHighscore":0,"totalAdvancedHighscore":0,"totalExpertHighscore":0,"totalMasterHighscore":0,"totalReMasterHighscore":0,"totalSync":0,"totalBasicSync":0,"totalAdvancedSync":0,"totalExpertSync":0,"totalMasterSync":0,"totalReMasterSync":0,"totalAchievement":997456,"totalBasicAchievement":0,"totalAdvancedAchievement":0,"totalExpertAchievement":997456,"totalMasterAchievement":0,"totalReMasterAchievement":0,"playerOldRating":271,"playerNewRating":0,"banState":0,"dateTime":1711485182,"cmLastEmoneyBrand":2,"cmLastEmoneyCredit":69,"mapStock":0,"currentPlayCount":1,"renameCredit":0,"accessCode":"$ACCESS_CODE"},"banState":0}""".jsonMap()
val userData = result["userData"] as Map<*, *>
userData["userName"] shouldBe "AZA☆"
userData["playerRating"] shouldBe 271
result["banState"] shouldBe 0
}
}
"GetUserCardApi" {
post("GetUserCardApi", """{"userId":$userId,"nextIndex":0,"maxCount":20}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"nextIndex":0,"userCardList":[]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":0,"userCardList":[]}""".jsonMap()
}
}
@@ -191,63 +197,63 @@ class Mai2Test : StringSpec({
"GetUserCourseApi" {
post("GetUserCourseApi", """{"userId":$userId,"nextIndex":0}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"nextIndex":0,"userCourseList":[]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":0,"userCourseList":[]}""".jsonMap()
}
}
"GetUserChargeApi" {
post("GetUserChargeApi", """{"userId":$userId}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"length":0,"userChargeList":[]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":0,"userChargeList":[]}""".jsonMap()
}
}
"GetUserFavoriteApi" {
post("GetUserFavoriteApi", """{"userId":$userId,"itemKind":1}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"userFavoriteData":[]}""".jsonMap()
result shouldBe """{"userId":$userId}""".jsonMap()
}
post("GetUserFavoriteApi", """{"userId":$userId,"itemKind":2}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"userFavoriteData":[]}""".jsonMap()
result shouldBe """{"userId":$userId}""".jsonMap()
}
post("GetUserFavoriteApi", """{"userId":$userId,"itemKind":3}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"userFavoriteData":[]}""".jsonMap()
result shouldBe """{"userId":$userId}""".jsonMap()
}
post("GetUserFavoriteApi", """{"userId":$userId,"itemKind":4}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"userFavoriteData":[]}""".jsonMap()
result shouldBe """{"userId":$userId}""".jsonMap()
}
post("GetUserFavoriteApi", """{"userId":$userId,"itemKind":5}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"userFavoriteData":[]}""".jsonMap()
result shouldBe """{"userId":$userId}""".jsonMap()
}
}
"GetUserGhostApi" {
post("GetUserGhostApi", """{"userId":$userId}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"userGhostList":[]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":0,"userGhostList":[]}""".jsonMap()
}
}
"GetUserMapApi" {
post("GetUserMapApi", """{"userId":$userId,"nextIndex":0,"maxCount":20}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"nextIndex":0,"userMapList":[{"mapId":1,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":2,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":3,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":4,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":5,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":6,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150001,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150002,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150003,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150004,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150005,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350001,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350003,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350004,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350006,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350007,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400001,"distance":14000,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400002,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400003,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400004,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400005,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400006,"distance":0,"isLock":false,"isClear":false,"isComplete":false}]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":22,"userMapList":[{"mapId":1,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":2,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":3,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":4,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":5,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":6,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150001,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150002,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150003,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150004,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":150005,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350001,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350003,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350004,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350006,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":350007,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400001,"distance":14000,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400002,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400003,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400004,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400005,"distance":0,"isLock":false,"isClear":false,"isComplete":false},{"mapId":400006,"distance":0,"isLock":false,"isClear":false,"isComplete":false}]}""".jsonMap()
}
}
"GetUserLoginBonusApi" {
post("GetUserLoginBonusApi", """{"userId":$userId,"nextIndex":0,"maxCount":20}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"nextIndex":0,"userLoginBonusList":[{"bonusId":38,"point":1,"isCurrent":true,"isComplete":false}]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":1,"userLoginBonusList":[{"bonusId":38,"point":1,"isCurrent":false,"isComplete":false}]}""".jsonMap()
}
}
"GetUserRegionApi" {
post("GetUserRegionApi", """{"userId":$userId}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"length":0,"userRegionList":[]}""".jsonMap()
result shouldBe """{"userId":$userId,"length":1,"userRegionList":[{"regionId":1,"playCount":1}]}""".jsonMap()
}
}
@@ -283,7 +289,7 @@ class Mai2Test : StringSpec({
"GetUserMusicApi" {
post("GetUserMusicApi", """{"userId":$userId,"nextIndex":0,"maxCount":50}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"nextIndex":0,"userMusicList":[{"userMusicDetailList":[{"musicId":11479,"level":2,"playCount":1,"achievement":997456,"comboStatus":1,"syncStatus":0,"deluxscoreMax":1725,"scoreRank":11,"extNum1":0}]}]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":1,"userMusicList":[{"userMusicDetailList":[{"musicId":11479,"level":2,"playCount":1,"achievement":997456,"comboStatus":1,"syncStatus":0,"deluxscoreMax":1725,"scoreRank":11,"extNum1":0}]}]}""".jsonMap()
}
}
@@ -310,7 +316,7 @@ class Mai2Test : StringSpec({
"GetUserFriendSeasonRankingApi" {
post("GetUserFriendSeasonRankingApi", """{"userId":$userId,"nextIndex":0,"maxCount":20}""").let { (_, result) ->
result shouldBe """{"userId":$userId,"nextIndex":0,"userFriendSeasonRankingList":[]}""".jsonMap()
result shouldBe """{"userId":$userId,"nextIndex":0,"length":0,"userFriendSeasonRankingList":[]}""".jsonMap()
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ class WaccaTest : StringSpec({
data class PostResp(val resp: HttpResponse, val res: List<Any>)
suspend fun post(url: String, par: String): PostResp {
requestNo++
val resp = HTTP.post("$HOST/gs/$CLIENT_ID/wacca/api/$url") {
val resp = HTTP.post("$HOST/g/wacca/api/$url") {
contentType(ContentType.Application.Json)
setBody("""{"requestNo": ${requestNo++},"appVersion": "$version","boardId": "$BOARD_ID","chipId": "$FULL_CLIENT_ID","params": $par}""")
}
@@ -0,0 +1,114 @@
package icu.samnyan.aqua.sega.util
import com.fasterxml.jackson.core.type.TypeReference
import ext.logger
import ext.toJson
import icu.samnyan.aqua.sega.chusan.model.GameCharge as Chu3GameCharge
import icu.samnyan.aqua.sega.chusan.model.GameEvent as Chu3GameEvent
import icu.samnyan.aqua.sega.chusan.model.GameGacha as Chu3GameGacha
import icu.samnyan.aqua.sega.chusan.model.GameGachaCard as Chu3GameGachaCard
import icu.samnyan.aqua.sega.chusan.model.GameLinkedVerse as Chu3GameLinkedVerse
import icu.samnyan.aqua.sega.chusan.model.GameLoginBonus as Chu3GameLoginBonus
import icu.samnyan.aqua.sega.chusan.model.GameLoginBonusPreset as Chu3GameLoginBonusPreset
import icu.samnyan.aqua.sega.maimai2.model.Mai2GameCharge
import icu.samnyan.aqua.sega.maimai2.model.Mai2GameEvent
import icu.samnyan.aqua.sega.maimai2.model.Mai2GameSellingCard
import icu.samnyan.aqua.sega.ongeki.model.GameCard as OgkGameCard
import icu.samnyan.aqua.sega.ongeki.model.GameChara as OgkGameChara
import icu.samnyan.aqua.sega.ongeki.model.GameEvent as OgkGameEvent
import icu.samnyan.aqua.sega.ongeki.model.GameGacha as OgkGameGacha
import icu.samnyan.aqua.sega.ongeki.model.GameGachaCard as OgkGameGachaCard
import icu.samnyan.aqua.sega.ongeki.model.GameMusic as OgkGameMusic
import icu.samnyan.aqua.sega.ongeki.model.GamePoint as OgkGamePoint
import icu.samnyan.aqua.sega.ongeki.model.GamePresent as OgkGamePresent
import icu.samnyan.aqua.sega.ongeki.model.GameReward as OgkGameReward
import icu.samnyan.aqua.sega.ongeki.model.GameSkill as OgkGameSkill
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.io.File
@Service
class GameDataService() {
companion object {
val log = logger()
val mapper = BasicMapper()
inline fun <reified T> load(game: String, file: String): List<T> {
val f = File("data/game/$game/$file")
if (f.exists()) return mapper.read(f.readText(), object : TypeReference<List<T>>() {})
// Try load from resources
val resPath = "/data/game/$game/$file"
val resStream = GameDataService::class.java.getResourceAsStream(resPath)
if (resStream != null) {
log.info("Loading game data from internal resources: $resPath")
return mapper.read(resStream.bufferedReader().use { it.readText() }, object : TypeReference<List<T>>() {})
}
log.warn("Game data file $f or resource $resPath not found, using empty list")
return emptyList()
}
}
// maimai2
lateinit var mai2Events: List<Mai2GameEvent>
lateinit var mai2Charges: List<Mai2GameCharge>
lateinit var mai2SellingCards: List<Mai2GameSellingCard>
// chusan
lateinit var chu3GameLinkedVerses: List<Chu3GameLinkedVerse>
lateinit var chu3GameCharges: List<Chu3GameCharge>
lateinit var chu3GameEvents: List<Chu3GameEvent>
lateinit var chu3GameGachaCards: List<Chu3GameGachaCard>
lateinit var chu3GameGachas: List<Chu3GameGacha>
lateinit var chu3GameLoginBonusPresets: List<Chu3GameLoginBonusPreset>
lateinit var chu3GameLoginBonuses: List<Chu3GameLoginBonus>
// ongeki
lateinit var ogkGameCards: List<OgkGameCard>
lateinit var ogkGameCharas: List<OgkGameChara>
lateinit var ogkGameEvents: List<OgkGameEvent>
lateinit var ogkGameMusics: List<OgkGameMusic>
lateinit var ogkGamePoints: List<OgkGamePoint>
lateinit var ogkGamePresents: List<OgkGamePresent>
lateinit var ogkGameRewards: List<OgkGameReward>
lateinit var ogkGameSkills: List<OgkGameSkill>
lateinit var ogkGameGachaCards: List<OgkGameGachaCard>
lateinit var ogkGameGachas: List<OgkGameGacha>
init {
load()
}
fun load() {
mai2Events = load("maimai2", "game_event.json")
mai2Charges = load("maimai2", "game_charge.json")
mai2SellingCards = load("maimai2", "game_selling_card.json")
chu3GameLinkedVerses = load("chusan", "game_linked_verse.json")
chu3GameCharges = load("chusan", "game_charge.json")
chu3GameEvents = load("chusan", "game_event.json")
chu3GameGachaCards = load("chusan", "game_gacha_card.json")
chu3GameGachas = load("chusan", "game_gacha.json")
chu3GameLoginBonusPresets = load("chusan", "game_login_bonus_preset.json")
chu3GameLoginBonuses = load("chusan", "game_login_bonus.json")
ogkGameCards = load("ongeki", "game_card.json")
ogkGameCharas = load("ongeki", "game_chara.json")
ogkGameEvents = load("ongeki", "game_event.json")
ogkGameMusics = load("ongeki", "game_music.json")
ogkGamePoints = load("ongeki", "game_point.json")
ogkGamePresents = load("ongeki", "game_present.json")
ogkGameRewards = load("ongeki", "game_reward.json")
ogkGameSkills = load("ongeki", "game_skill.json")
ogkGameGachaCards = load("ongeki", "game_gacha_card.json")
ogkGameGachas = load("ongeki", "game_gacha.json")
}
}
fun main(args: Array<String>) {
GameDataService().let {
it.load()
println(it.mai2Events[0].toJson())
}
}
@@ -0,0 +1,10 @@
package icu.samnyan.aqua.sega.util
import java.lang.reflect.Field
import java.util.*
open class StaticRepo<T : Any, ID>(val data: List<T>, val idGetter: (T) -> ID) {
fun findAll(): List<T> = data
private val idMap by lazy { data.associateBy { idGetter(it) } }
fun findById(id: ID): Optional<T> = Optional.ofNullable(idMap[id])
}
@@ -1,92 +0,0 @@
package aquadx.sega.chusan
import ext.*
import aquadx.net.db.AquaUserServices
import aquadx.net.games.chu3.Chusan
import aquadx.net.utils.simpleDescribe
import aquadx.sega.allnet.TokenChecker
import aquadx.sega.chusan.handler.chusanInit
import aquadx.sega.chusan.model.Chu3Repos
import aquadx.sega.general.GameMusicPopularity
import aquadx.sega.general.MeowApi
import aquadx.sega.general.RequestContext
import aquadx.sega.general.service.CardService
import aquadx.sega.util.BasicMapper
import aquadx.sega.util.StringMapper
import aquadx.spring.Metrics
import jakarta.servlet.http.HttpServletRequest
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.RestController
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Suppress("unused")
@RestController
@API(value = ["/g/chu3/{version}/ChuniServlet", "/g/chu3/{version}"])
class ChusanController(
val mapper: StringMapper,
val cmMapper: BasicMapper,
val db: Chu3Repos,
val us: AquaUserServices,
val cardService: CardService,
val versionHelper: ChusanVersionHelper,
val props: ChusanProps,
val pop: GameMusicPopularity,
val chusan: Chusan
): MeowApi({ api, resp ->
if (resp is String) resp
else (if ("CM" in api || api == "GetUserItemApi" ) cmMapper else mapper).write(resp)
}) {
val log = LoggerFactory.getLogger(ChusanController::class.java)
val noopEndpoint = setOf("UpsertClientBookkeepingApi", "UpsertClientDevelopApi", "UpsertClientErrorApi",
"UpsertClientSettingApi", "UpsertClientTestmodeApi", "CreateTokenApi", "RemoveTokenApi", "UpsertClientUploadApi",
"PrinterLoginApi", "PrinterLogoutApi", "Ping", "GameLogoutApi", "RemoveMatchingMemberApi",
"UpsertClientPlayTimeApi", "UpsertClientGameStartApi", "UpsertClientGameEndApi")
init { chusanInit() }
val handlers = initH
@API("/{endpoint}", "/MatchingServer/{endpoint}")
fun handle(@PV endpoint: Str, @RB data: MutableMap<Str, Any>, @PV version: Str, req: HttpServletRequest): Any {
val ctx = RequestContext(req, data)
var api = endpoint
data["version"] = version
// Export version
if (api.endsWith("C3Exp")) {
api = api.removeSuffix("C3Exp")
data["c3exp"] = true
}
if (api.startsWith("CM") && api !in handlers) api = api.removePrefix("CM")
val token = TokenChecker.tokenShort()
log.info("$token : $api < ${data.toJson()}")
val noop = """{"returnCode":"1","apiName":"$api"}"""
if (api !in noopEndpoint && !handlers.containsKey(api)) {
log.warn("$token : $api > not found")
return noop
}
// Only record the counter metrics if the API is known.
Metrics.counter("aquadx_chusan_api_call", "api" to api).increment()
if (api in noopEndpoint) {
log.info("$token : $api > no-op")
return noop
}
return try {
Metrics.timer("aquadx_chusan_api_latency", "api" to api).recordCallable {
serialize(api, handlers[api]!!(ctx) ?: noop).also {
if (api !in setOf("GetUserItemApi", "GetGameEventApi"))
log.info("$token : $api > ${it.truncate(500)}")
}
}
} catch (e: Exception) {
Metrics.counter("aquadx_chusan_api_error", "api" to api, "error" to e.simpleDescribe()).increment()
throw e
}
}
}