feat: ongeki 1.60 support (#240)

Co-authored-by: Raymond <101374892+raymonable@users.noreply.github.com>
This commit is contained in:
crxmsxn
2026-09-24 23:17:01 -04:00
committed by GitHub
co-authored by Raymond
parent bcbc770ca7
commit c3661d3c94
15 changed files with 3734 additions and 1452 deletions
+6 -1
View File
@@ -32,6 +32,7 @@ import java.time.ZoneOffset.UTC
import java.time.format.DateTimeFormatter
import java.util.*
import java.util.concurrent.locks.Lock
import kotlin.math.floor
import kotlin.reflect.KCallable
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty1
@@ -199,6 +200,10 @@ val Any?.truthy get() = when (this) {
}
val Any?.str get() = toString()
fun truncateVersion(version: Number): Number {
return (floor(version.toFloat() / 5.0) * 5).toInt();
}
// Collections
fun <T> ls(vararg args: T) = args.toList()
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(",") }
// 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.logger
import ext.toJson
import ext.truncateVersion
import icu.samnyan.aqua.net.components.GeoIP
import icu.samnyan.aqua.sega.allnet.TokenChecker
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 {
// NOTE: this should help with some issues regarding mismatched data
val expectedVersion = (req.getHeader("Mai-Encoding") ?:
@@ -4,6 +4,8 @@ import ext.empty
import ext.int
import ext.parsing
import ext.plus
import ext.str
import ext.truncateVersion
fun OngekiController.ongekiInit() {
fun <T> List<T>.staticLst(key: String) = mapOf("length" to size, key to this)
@@ -13,18 +15,21 @@ fun OngekiController.ongekiInit() {
initUpsertAll()
// Has type, but type is always 1
"GetGameEvent".static {
gdb.event.findAll().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")
}.staticLst("gameEventList") + mapOf("type" to 1)
"GetGameEvent" {
// val trunkVer = truncateVersion((data["version"] ?: "1.50.00").str.split(".").take(2).joinToString("").int)
val events = gdb.event.findAll()
// .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") }
"GetGamePresent".static { gdb.present.findAll().staticLst("gamePresentList") }
"GetGameReward".static { gdb.reward.findAll().staticLst("gameRewardList") }
// Dummy endpoints
"GetGameTechMusic".static { empty.staticLst("gameTechMusicList") }
"GetGameTechMusic".static { gdb.gameData.ogkGameTechMusics.staticLst("gameTechMusicList") }
"GetGameMessage" { mapOf("type" to data["type"], "length" to 0, "gameMessageList" to empty) }
"GetGameMusicReleaseState".static { mapOf("techScore" to 0, "cardNum" to 0) }
@@ -82,4 +87,4 @@ fun OngekiController.ongekiInit() {
"UpsertClientTestmode" static { """{"returnCode":1, "apiName":"UpsertClientTestmodeApi"}""" }
"UpsertUserGplog" static { """{"returnCode":1, "apiName":"UpsertUserGplogApi"}""" }
"Ping" static { """{"returnCode":1, "apiName":"Ping"}""" }
}
}
@@ -54,11 +54,12 @@ interface OgkUserDeckRepo : OngekiUserLinked<UserDeck> {
}
interface OgkUserEventMusicRepo : OngekiUserLinked<UserEventMusic> {
fun findByUserAndEventIdAndTypeAndMusicId(
fun findByUserAndEventIdAndTypeAndMusicIdAndLevel(
userData: UserData,
eventId: Int,
type: Int,
musicId: Int
musicId: Int,
level: Int
): UserEventMusic?
}
@@ -162,7 +163,10 @@ interface OgkUserGachaRepo : OngekiUserLinked<UserGacha> {
}
// 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>
@@ -74,7 +74,9 @@ fun OngekiController.initUpsertAll() {
// UserEventMap
userEventMap?.let {
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?.let { db.playlog.saveAll(it) }
@@ -195,8 +197,9 @@ fun OngekiController.initUpsertAll() {
// UserEventMusicList
userEventMusicList?.let { list ->
db.eventMusic.saveAll(list.distinctBy { it.eventId to it.type to it.musicId }.mapApply {
id = db.eventMusic.findByUserAndEventIdAndTypeAndMusicId(u, eventId, type, musicId)?.id ?: 0 }) }
db.eventMusic.saveAll(list.distinctBy { it.eventId to it.type to it.musicId to it.level }.mapApply {
id = db.eventMusic.findByUserAndEventIdAndTypeAndMusicIdAndLevel(u, eventId, type, musicId, level)?.id ?: 0
}) }
// UserTechEventList
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.ongeki.model.OgkItemType
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.Sort
import java.time.LocalDateTime
@@ -14,10 +15,25 @@ import java.time.format.DateTimeFormatter
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)) }
"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) }
"GetUserBoss".unpaged { db.boss.findByUser_Card_ExtId(uid) }
@@ -29,6 +29,12 @@ class GameEvent {
var id: Long = 0
}
class GameTechMusic {
var eventId = 0
var musicId = 0
var level = 0
}
class GameMusic {
var id: Long = 0
var name: String = ""
@@ -105,4 +111,4 @@ class GameGacha {
@JsonProperty("isCeiling")
var isCeiling: Boolean = false
}
}
@@ -166,6 +166,7 @@ class UserChapter : OngekiUserEntity() {
var jewelCount = 0
var lastPlayMusicCategory = 0
var lastPlayMusicId = 0
var lastPlayMusicMinorCategory: String = ""
var lastPlayMusicLevel = 0
var isStoryWatched = false
var isClear = false
@@ -197,7 +198,10 @@ class UserDeck : OngekiUserEntity() {
}
@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() {
var eventId = 0
var type = 0
@@ -318,6 +322,7 @@ class UserMusicItem : OngekiUserEntity() {
class UserOption : OngekiUserEntity() {
var optionSet = 0
var speed = 0
var fieldWall = 0
var mirror = 0
var judgeTiming = 0
var judgeAdjustment = 0
@@ -342,20 +347,19 @@ class UserOption : OngekiUserEntity() {
var colorSide = 0
var effectDamage = 0
var effectPos = 0
var effectAttack = 0
var judgeDisp = 0
var judgePos = 0
var judgeBreak = 0
var judgeHit = 0
var platinumBreakDisp = 0
var judgeCriticalBreak = 0
var platinumBreakDisp = 0
var matching = 0
var dispPlayerLv = 0
var dispRating = 0
var dispBP = 0
var headphone = 0
// Re:Fresh
var effectAttack = 0
}
@@ -457,6 +461,7 @@ class UserStory : OngekiUserEntity() {
var jewelCount = 0
var lastPlayMusicId = 0
var lastPlayMusicCategory = 0
var lastPlayMusicMinorCategory: String = ""
var lastPlayMusicLevel = 0
}
@@ -498,7 +503,10 @@ class UserTrainingRoom : OngekiUserEntity() {
// Re:Fresh
@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() {
var eventId = 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.GameGacha as OgkGameGacha
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.GamePoint as OgkGamePoint
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")
return emptyList()
}
}
// maimai2
@@ -72,6 +74,7 @@ class GameDataService() {
lateinit var ogkGameCards: List<OgkGameCard>
lateinit var ogkGameCharas: List<OgkGameChara>
lateinit var ogkGameEvents: List<OgkGameEvent>
lateinit var ogkGameTechMusics: List<OgkGameTechMusic>
lateinit var ogkGameMusics: List<OgkGameMusic>
lateinit var ogkGamePoints: List<OgkGamePoint>
lateinit var ogkGamePresents: List<OgkGamePresent>
@@ -103,6 +106,7 @@ class GameDataService() {
ogkGameCards = load("ongeki", "game_card.json")
ogkGameCharas = load("ongeki", "game_chara.json")
ogkGameEvents = load("ongeki", "game_event.json")
ogkGameTechMusics = load("ongeki", "game_tech_music.json")
ogkGameMusics = load("ongeki", "game_music.json")
ogkGamePoints = load("ongeki", "game_point.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;