3 Commits
Author SHA1 Message Date
asterisk727 4a0254ec19 chore: update readme for ongeki 2026-09-25 12:58:18 -05:00
crxmsxnandRaymond c3661d3c94 feat: ongeki 1.60 support (#240)
Co-authored-by: Raymond <101374892+raymonable@users.noreply.github.com>
2026-09-24 23:17:01 -04:00
topty bcbc770ca7 feat(mai2): stub MAGiCAL API responses (#246) 2026-09-22 16:54:23 -04:00
18 changed files with 3756 additions and 1463 deletions
+9 -9
View File
@@ -32,15 +32,15 @@ Multipurpose game server for ALL.Net games.
> [!WARNING] > [!WARNING]
> CHUNITHM pre-NEW!! and maimai pre-DX are no longer supported after February 6th, 2026 and all associated data will be removed. > 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 | Web UI | Import | AES | | Game | Latest Ver. | Initial Ver. | Notes | Web UI | Import | AES |
|------------------------|--------------------|---------------------|-------------------------------------------------------------|--------|-------------|---------| |------------------------|-----------------------|---------------------|-------------------------------------------------------------|--------|-------------|-----|
| SDHD: CHUNITHM | 2.50 (MATE) | 2.00 (NEW) | | ✅ | ✅ | ✅ | | SDHD: CHUNITHM | 2.50 (Mate) | 2.00 (NEW) | | ✅ | ✅ | ✅ |
| SDEZ: maimai DX | 1.65 (CiRCLE PLUS) | 1.00 (DX) | Thanks [@Menci](https://github.com/Menci) | ✅ | ✅ | ✅ | | SDEZ: maimai DX | 1.65 (CiRCLE PLUS) | 1.00 (DX) | Thanks [@Menci](https://github.com/Menci) | ✅ | ✅ | ✅ |
| SDGA: maimai DX (Intl) | 1.60 (CiRCLE) | 1.00 (DX) | Thanks [@Clansty](https://github.com/clansty) | ✅ | ✅ | ✅ | | 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) | ❌ | ❌ | ❌ | | 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) | ✅ | ✅ | ✅ | | SDDT: O.N.G.E.K.I. | 1.60 (Re:Fresh Act 2) | N/A | Thanks [@PenguinCaptain](https://github.com/PenguinCaptain) | ✅ | ✅ | ❌ |
| SBZV: Project DIVA | 7.10 | N/A | Minimal support | ❌ | ❌ | 🔓 | | SBZV: Project DIVA | 7.10 | N/A | Minimal support | ❌ | ❌ | 🔓 |
| SDFE: Wacca | 3.07 (REVERSE) | N/A | Later versions are EOS patches | ✅ | ❌ | 🔓 | | SDFE: Wacca | 3.07 (REVERSE) | N/A | Later versions are EOS patches | ✅ | ❌ | 🔓 |
<!-- A majority of them have been left as N/A for initial version as they do not appear to have restrictions --> <!-- A majority of them have been left as N/A for initial version as they do not appear to have restrictions -->
+6 -1
View File
@@ -32,6 +32,7 @@ import java.time.ZoneOffset.UTC
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.util.* import java.util.*
import java.util.concurrent.locks.Lock import java.util.concurrent.locks.Lock
import kotlin.math.floor
import kotlin.reflect.KCallable import kotlin.reflect.KCallable
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
@@ -199,6 +200,10 @@ val Any?.truthy get() = when (this) {
} }
val Any?.str get() = toString() val Any?.str get() = toString()
fun truncateVersion(version: Number): Number {
return (floor(version.toFloat() / 5.0) * 5).toInt();
}
// Collections // Collections
fun <T> ls(vararg args: T) = args.toList() fun <T> ls(vararg args: T) = args.toList()
inline fun <reified T> arr(vararg args: T) = arrayOf(*args) inline fun <reified T> arr(vararg args: T) = arrayOf(*args)
@@ -277,4 +282,4 @@ fun List<List<Any?>>.numCsv(vararg head: Str) = head.joinToString(",") + "\n" +
joinToString("\n") { it.joinToString(",") } joinToString("\n") { it.joinToString(",") }
// DI // DI
inline fun <reified T : Any> ApplicationContext.lazy() = kotlin.lazy { getBean(T::class.java) } inline fun <reified T : Any> ApplicationContext.lazy() = kotlin.lazy { getBean(T::class.java) }
@@ -3,6 +3,7 @@ package icu.samnyan.aqua.sega.general.filter
import ext.details import ext.details
import ext.logger import ext.logger
import ext.toJson import ext.toJson
import ext.truncateVersion
import icu.samnyan.aqua.net.components.GeoIP import icu.samnyan.aqua.net.components.GeoIP
import icu.samnyan.aqua.sega.allnet.TokenChecker import icu.samnyan.aqua.sega.allnet.TokenChecker
import icu.samnyan.aqua.sega.general.model.GameEncryptionKey import icu.samnyan.aqua.sega.general.model.GameEncryptionKey
@@ -36,9 +37,6 @@ class CompressionFilter(
} }
fun truncateVersion(version: Number): Number {
return (floor(version.toFloat() / 5.0) * 5).toInt();
}
fun getVersion(req: HttpServletRequest, game: String): Int { fun getVersion(req: HttpServletRequest, game: String): Int {
// NOTE: this should help with some issues regarding mismatched data // NOTE: this should help with some issues regarding mismatched data
val expectedVersion = (req.getHeader("Mai-Encoding") ?: val expectedVersion = (req.getHeader("Mai-Encoding") ?:
@@ -55,7 +55,12 @@ fun Maimai2ServletController.initApis() {
// Maimai only request for event type 1 // Maimai only request for event type 1
"GetGameEvent" static { mapOf("type" to 1, "gameEventList" to db.gameEvent.findAll()) } "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) } }
"GetGameCharge" static {
db.gameCharge.findAll().let {
mapOf("length" to it.size, "gameChargeList" to it, "gamePassChargeList" to empty)
}
}
"GetUserOption" { mapOf( "GetUserOption" { mapOf(
"userId" to uid, "userId" to uid,
@@ -438,6 +443,12 @@ fun Maimai2ServletController.initApis() {
) )
) } ) }
"GetGameSellingPassPack" static { mapOf("gameSellingPassPackList" to empty) }
"GetUserPass" { mapOf("userId" to uid, "userPassList" to empty) }
"GetUserTicketLimitDate" static { mapOf("userTicketLimitDateList" to empty) }
// NOTE: no-op APIs moved to respect encryption // NOTE: no-op APIs moved to respect encryption
"UpsertUserPlaceCircleRegist" static { mapOf( "returnCode" to 0, "apiName" to "com.sega.maimai2servlet.api.UpsertUserPlaceCircleRegistApi") } "UpsertUserPlaceCircleRegist" static { mapOf( "returnCode" to 0, "apiName" to "com.sega.maimai2servlet.api.UpsertUserPlaceCircleRegistApi") }
"GetUserScoreRanking" static { """{"returnCode":1, "apiName":"com.sega.maimai2servlet.api.GetUserScoreRankingApi"}""" } "GetUserScoreRanking" static { """{"returnCode":1, "apiName":"com.sega.maimai2servlet.api.GetUserScoreRankingApi"}""" }
@@ -4,6 +4,8 @@ import ext.empty
import ext.int import ext.int
import ext.parsing import ext.parsing
import ext.plus import ext.plus
import ext.str
import ext.truncateVersion
fun OngekiController.ongekiInit() { fun OngekiController.ongekiInit() {
fun <T> List<T>.staticLst(key: String) = mapOf("length" to size, key to this) fun <T> List<T>.staticLst(key: String) = mapOf("length" to size, key to this)
@@ -13,18 +15,21 @@ fun OngekiController.ongekiInit() {
initUpsertAll() initUpsertAll()
// Has type, but type is always 1 // Has type, but type is always 1
"GetGameEvent".static { "GetGameEvent" {
gdb.event.findAll().map { // val trunkVer = truncateVersion((data["version"] ?: "1.50.00").str.split(".").take(2).joinToString("").int)
mapOf("id" to it.id, "type" to 1, "startDate" to "2005-01-01 00:00:00.0", "endDate" to "2099-01-01 05:00:00.0") val events = gdb.event.findAll()
}.staticLst("gameEventList") + mapOf("type" to 1) // .filter{ it.id.str.startsWith(trunkVer.str) }
.map {
mapOf("id" to it.id, "type" to 1, "startDate" to "2005-01-01 00:00:00.0", "endDate" to "2099-01-01 05:00:00.0")
}
mapOf("gameEventList" to events, "length" to events.size, "type" to 1)
} }
"GetGamePoint".static { gdb.point.findAll().staticLst("gamePointList") } "GetGamePoint".static { gdb.point.findAll().staticLst("gamePointList") }
"GetGamePresent".static { gdb.present.findAll().staticLst("gamePresentList") } "GetGamePresent".static { gdb.present.findAll().staticLst("gamePresentList") }
"GetGameReward".static { gdb.reward.findAll().staticLst("gameRewardList") } "GetGameReward".static { gdb.reward.findAll().staticLst("gameRewardList") }
// Dummy endpoints "GetGameTechMusic".static { gdb.gameData.ogkGameTechMusics.staticLst("gameTechMusicList") }
"GetGameTechMusic".static { empty.staticLst("gameTechMusicList") }
"GetGameMessage" { mapOf("type" to data["type"], "length" to 0, "gameMessageList" to empty) } "GetGameMessage" { mapOf("type" to data["type"], "length" to 0, "gameMessageList" to empty) }
"GetGameMusicReleaseState".static { mapOf("techScore" to 0, "cardNum" to 0) } "GetGameMusicReleaseState".static { mapOf("techScore" to 0, "cardNum" to 0) }
@@ -82,4 +87,4 @@ fun OngekiController.ongekiInit() {
"UpsertClientTestmode" static { """{"returnCode":1, "apiName":"UpsertClientTestmodeApi"}""" } "UpsertClientTestmode" static { """{"returnCode":1, "apiName":"UpsertClientTestmodeApi"}""" }
"UpsertUserGplog" static { """{"returnCode":1, "apiName":"UpsertUserGplogApi"}""" } "UpsertUserGplog" static { """{"returnCode":1, "apiName":"UpsertUserGplogApi"}""" }
"Ping" static { """{"returnCode":1, "apiName":"Ping"}""" } "Ping" static { """{"returnCode":1, "apiName":"Ping"}""" }
} }
@@ -54,11 +54,12 @@ interface OgkUserDeckRepo : OngekiUserLinked<UserDeck> {
} }
interface OgkUserEventMusicRepo : OngekiUserLinked<UserEventMusic> { interface OgkUserEventMusicRepo : OngekiUserLinked<UserEventMusic> {
fun findByUserAndEventIdAndTypeAndMusicId( fun findByUserAndEventIdAndTypeAndMusicIdAndLevel(
userData: UserData, userData: UserData,
eventId: Int, eventId: Int,
type: Int, type: Int,
musicId: Int musicId: Int,
level: Int
): UserEventMusic? ): UserEventMusic?
} }
@@ -162,7 +163,10 @@ interface OgkUserGachaRepo : OngekiUserLinked<UserGacha> {
} }
// Re:Fresh // Re:Fresh
interface OgkUserEventMapRepo : OngekiUserLinked<UserEventMap> interface OgkUserEventMapRepo : OngekiUserLinked<UserEventMap> {
fun findByUserAndEventIdAndMapId(user: UserData, eventId: Int, mapId: Int): UserEventMap?
fun findByUser_Card_ExtIdAndEventIdAndMapId(extId: Long, eventId: Int, mapId: Int): UserEventMap?
}
interface OgkUserSkinRepo : OngekiUserLinked<UserSkin> interface OgkUserSkinRepo : OngekiUserLinked<UserSkin>
@@ -74,7 +74,9 @@ fun OngekiController.initUpsertAll() {
// UserEventMap // UserEventMap
userEventMap?.let { userEventMap?.let {
db.eventMap.save(it.apply { db.eventMap.save(it.apply {
id = db.eventMap.findSingleByUser(u)?.id ?: 0 }) } id = db.eventMap.findByUserAndEventIdAndMapId(u, it.eventId, it.mapId)?.id ?: 0
})
}
// UserPlaylogList // UserPlaylogList
userPlaylogList?.let { db.playlog.saveAll(it) } userPlaylogList?.let { db.playlog.saveAll(it) }
@@ -195,8 +197,9 @@ fun OngekiController.initUpsertAll() {
// UserEventMusicList // UserEventMusicList
userEventMusicList?.let { list -> userEventMusicList?.let { list ->
db.eventMusic.saveAll(list.distinctBy { it.eventId to it.type to it.musicId }.mapApply { db.eventMusic.saveAll(list.distinctBy { it.eventId to it.type to it.musicId to it.level }.mapApply {
id = db.eventMusic.findByUserAndEventIdAndTypeAndMusicId(u, eventId, type, musicId)?.id ?: 0 }) } id = db.eventMusic.findByUserAndEventIdAndTypeAndMusicIdAndLevel(u, eventId, type, musicId, level)?.id ?: 0
}) }
// UserTechEventList // UserTechEventList
userTechEventList?.let { list -> userTechEventList?.let { list ->
@@ -7,6 +7,7 @@ import icu.samnyan.aqua.sega.general.model.CardStatus
import icu.samnyan.aqua.sega.general.model.UserRecentRating import icu.samnyan.aqua.sega.general.model.UserRecentRating
import icu.samnyan.aqua.sega.ongeki.model.OgkItemType import icu.samnyan.aqua.sega.ongeki.model.OgkItemType
import icu.samnyan.aqua.sega.ongeki.model.UserItem import icu.samnyan.aqua.sega.ongeki.model.UserItem
import icu.samnyan.aqua.sega.ongeki.model.UserEventMap
import org.springframework.data.domain.PageRequest import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort import org.springframework.data.domain.Sort
import java.time.LocalDateTime import java.time.LocalDateTime
@@ -14,10 +15,25 @@ import java.time.format.DateTimeFormatter
fun OngekiController.initUser() { fun OngekiController.initUser() {
val emptyEventMapData = """{"unlockPoints":0,"_unlockedTileIDs":[1],"_rewardScenarioIDs":[],"_rewardRewardKeyIDs":[],"endless":false,"loopCount":0}"""
"GetUserData" { mapOf("userId" to uid, "userData" to db.data.findByCard_ExtId(uid)) } "GetUserData" { mapOf("userId" to uid, "userData" to db.data.findByCard_ExtId(uid)) }
"GetUserOption" { mapOf("userId" to uid, "userOption" to db.option.findSingleByUser_Card_ExtId(uid)) } "GetUserOption" { mapOf("userId" to uid, "userOption" to db.option.findSingleByUser_Card_ExtId(uid)) }
"GetUserEventMap" { mapOf("userId" to uid, "userEventMap" to db.eventMap.findSingleByUser_Card_ExtId(uid)) } "GetUserEventMap" {
val eventId = data["eventId"]?.int ?: 0
val mapId = data["mapId"]?.int ?: 0
val userEventMap = db.eventMap.findByUser_Card_ExtIdAndEventIdAndMapId(uid, eventId, mapId)
?: UserEventMap().apply {
this.eventId = eventId
this.mapId = mapId
this.mapData = emptyEventMapData
}
mapOf(
"userId" to uid,
"userEventMap" to userEventMap
)
}
"GetUserTechEvent".unpaged { db.techEvent.findByUser_Card_ExtId(uid) } "GetUserTechEvent".unpaged { db.techEvent.findByUser_Card_ExtId(uid) }
"GetUserBoss".unpaged { db.boss.findByUser_Card_ExtId(uid) } "GetUserBoss".unpaged { db.boss.findByUser_Card_ExtId(uid) }
@@ -29,6 +29,12 @@ class GameEvent {
var id: Long = 0 var id: Long = 0
} }
class GameTechMusic {
var eventId = 0
var musicId = 0
var level = 0
}
class GameMusic { class GameMusic {
var id: Long = 0 var id: Long = 0
var name: String = "" var name: String = ""
@@ -105,4 +111,4 @@ class GameGacha {
@JsonProperty("isCeiling") @JsonProperty("isCeiling")
var isCeiling: Boolean = false var isCeiling: Boolean = false
} }
@@ -166,6 +166,7 @@ class UserChapter : OngekiUserEntity() {
var jewelCount = 0 var jewelCount = 0
var lastPlayMusicCategory = 0 var lastPlayMusicCategory = 0
var lastPlayMusicId = 0 var lastPlayMusicId = 0
var lastPlayMusicMinorCategory: String = ""
var lastPlayMusicLevel = 0 var lastPlayMusicLevel = 0
var isStoryWatched = false var isStoryWatched = false
var isClear = false var isClear = false
@@ -197,7 +198,10 @@ class UserDeck : OngekiUserEntity() {
} }
@Entity(name = "OngekiUserEventMusic") @Entity(name = "OngekiUserEventMusic")
@Table(name = "ongeki_user_event_music") @Table(
name = "ongeki_user_event_music",
uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "event_id", "type", "music_id", "level"])]
)
class UserEventMusic : OngekiUserEntity() { class UserEventMusic : OngekiUserEntity() {
var eventId = 0 var eventId = 0
var type = 0 var type = 0
@@ -318,6 +322,7 @@ class UserMusicItem : OngekiUserEntity() {
class UserOption : OngekiUserEntity() { class UserOption : OngekiUserEntity() {
var optionSet = 0 var optionSet = 0
var speed = 0 var speed = 0
var fieldWall = 0
var mirror = 0 var mirror = 0
var judgeTiming = 0 var judgeTiming = 0
var judgeAdjustment = 0 var judgeAdjustment = 0
@@ -342,20 +347,19 @@ class UserOption : OngekiUserEntity() {
var colorSide = 0 var colorSide = 0
var effectDamage = 0 var effectDamage = 0
var effectPos = 0 var effectPos = 0
var effectAttack = 0
var judgeDisp = 0 var judgeDisp = 0
var judgePos = 0 var judgePos = 0
var judgeBreak = 0 var judgeBreak = 0
var judgeHit = 0 var judgeHit = 0
var platinumBreakDisp = 0
var judgeCriticalBreak = 0 var judgeCriticalBreak = 0
var platinumBreakDisp = 0
var matching = 0 var matching = 0
var dispPlayerLv = 0 var dispPlayerLv = 0
var dispRating = 0 var dispRating = 0
var dispBP = 0 var dispBP = 0
var headphone = 0 var headphone = 0
// Re:Fresh
var effectAttack = 0
} }
@@ -457,6 +461,7 @@ class UserStory : OngekiUserEntity() {
var jewelCount = 0 var jewelCount = 0
var lastPlayMusicId = 0 var lastPlayMusicId = 0
var lastPlayMusicCategory = 0 var lastPlayMusicCategory = 0
var lastPlayMusicMinorCategory: String = ""
var lastPlayMusicLevel = 0 var lastPlayMusicLevel = 0
} }
@@ -498,7 +503,10 @@ class UserTrainingRoom : OngekiUserEntity() {
// Re:Fresh // Re:Fresh
@Entity(name = "OngekiUserEventMap") @Entity(name = "OngekiUserEventMap")
@Table(name = "ongeki_user_event_map") @Table(
name = "ongeki_user_event_map",
uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "event_id", "map_id"])]
)
class UserEventMap : OngekiUserEntity() { class UserEventMap : OngekiUserEntity() {
var eventId = 0 var eventId = 0
var mapId = 0 var mapId = 0
@@ -19,6 +19,7 @@ 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.GameEvent as OgkGameEvent
import icu.samnyan.aqua.sega.ongeki.model.GameGacha as OgkGameGacha 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.GameGachaCard as OgkGameGachaCard
import icu.samnyan.aqua.sega.ongeki.model.GameTechMusic as OgkGameTechMusic
import icu.samnyan.aqua.sega.ongeki.model.GameMusic as OgkGameMusic 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.GamePoint as OgkGamePoint
import icu.samnyan.aqua.sega.ongeki.model.GamePresent as OgkGamePresent import icu.samnyan.aqua.sega.ongeki.model.GamePresent as OgkGamePresent
@@ -50,6 +51,7 @@ class GameDataService() {
log.warn("Game data file $f or resource $resPath not found, using empty list") log.warn("Game data file $f or resource $resPath not found, using empty list")
return emptyList() return emptyList()
} }
} }
// maimai2 // maimai2
@@ -72,6 +74,7 @@ class GameDataService() {
lateinit var ogkGameCards: List<OgkGameCard> lateinit var ogkGameCards: List<OgkGameCard>
lateinit var ogkGameCharas: List<OgkGameChara> lateinit var ogkGameCharas: List<OgkGameChara>
lateinit var ogkGameEvents: List<OgkGameEvent> lateinit var ogkGameEvents: List<OgkGameEvent>
lateinit var ogkGameTechMusics: List<OgkGameTechMusic>
lateinit var ogkGameMusics: List<OgkGameMusic> lateinit var ogkGameMusics: List<OgkGameMusic>
lateinit var ogkGamePoints: List<OgkGamePoint> lateinit var ogkGamePoints: List<OgkGamePoint>
lateinit var ogkGamePresents: List<OgkGamePresent> lateinit var ogkGamePresents: List<OgkGamePresent>
@@ -103,6 +106,7 @@ class GameDataService() {
ogkGameCards = load("ongeki", "game_card.json") ogkGameCards = load("ongeki", "game_card.json")
ogkGameCharas = load("ongeki", "game_chara.json") ogkGameCharas = load("ongeki", "game_chara.json")
ogkGameEvents = load("ongeki", "game_event.json") ogkGameEvents = load("ongeki", "game_event.json")
ogkGameTechMusics = load("ongeki", "game_tech_music.json")
ogkGameMusics = load("ongeki", "game_music.json") ogkGameMusics = load("ongeki", "game_music.json")
ogkGamePoints = load("ongeki", "game_point.json") ogkGamePoints = load("ongeki", "game_point.json")
ogkGamePresents = load("ongeki", "game_present.json") ogkGamePresents = load("ongeki", "game_present.json")
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,20 @@
-- should have been not nullable in the first place smh
DELETE FROM ongeki_user_event_map
WHERE user_id IS NULL;
ALTER TABLE ongeki_user_event_map
MODIFY user_id BIGINT NOT NULL;
-- dedupe before adding new constraint just in case
DELETE FROM ongeki_user_event_map
WHERE id NOT IN (
SELECT id
FROM (
SELECT MAX(id) AS id
FROM ongeki_user_event_map
GROUP BY user_id, event_id, map_id
) AS rows_to_keep
);
ALTER TABLE ongeki_user_event_map
ADD UNIQUE KEY uniq_ongeki_user_event_map (user_id, event_id, map_id);
@@ -0,0 +1,23 @@
-- allow separate Technical Challenge records for each chart difficulty
-- drop the old constraint and dedupe with the new constraint just in case again
ALTER TABLE ongeki_user_event_music
DROP INDEX IF EXISTS UKo5PU3BgZeTKB8SNykq9U7xjfshp;
DELETE FROM ongeki_user_event_music
WHERE user_id IS NULL;
ALTER TABLE ongeki_user_event_music
MODIFY user_id BIGINT NOT NULL;
DELETE FROM ongeki_user_event_music
WHERE id NOT IN (
SELECT id
FROM (
SELECT MAX(id) AS id
FROM ongeki_user_event_music
GROUP BY user_id, event_id, type, music_id, level
) AS rows_to_keep
);
ALTER TABLE ongeki_user_event_music
ADD UNIQUE KEY uniq_ongeki_user_event_music (user_id, event_id, type, music_id, level);
@@ -0,0 +1,5 @@
ALTER TABLE ongeki_user_chapter
ADD COLUMN last_play_music_minor_category VARCHAR(255) NOT NULL DEFAULT '';
ALTER TABLE ongeki_user_story
ADD COLUMN last_play_music_minor_category VARCHAR(255) NOT NULL DEFAULT '';
@@ -0,0 +1,7 @@
-- new field wall option field
ALTER TABLE ongeki_user_option
ADD COLUMN field_wall INT NOT NULL DEFAULT 0;
-- varchar(255) not enough for event map storage
ALTER TABLE ongeki_user_event_map
MODIFY COLUMN map_data TEXT NULL;
+1 -1
View File
@@ -59,7 +59,7 @@ class Mai2Test : StringSpec({
liveTest("GetGameChargeApi") { liveTest("GetGameChargeApi") {
post("GetGameChargeApi", """{"isAll":false}""").let { (_, result) -> post("GetGameChargeApi", """{"isAll":false}""").let { (_, result) ->
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() 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"}],"gamePassChargeList":[]}""".jsonMap()
} }
} }