From c1d3f61b00419ef78f7d23181adbcc3ff300151d Mon Sep 17 00:00:00 2001 From: asterisk727 <59166650+asterisk727@users.noreply.github.com> Date: Fri, 25 Sep 2026 12:49:14 -0500 Subject: [PATCH] feat: no longer stub maimai magical --- .../samnyan/aqua/sega/maimai2/Maimai2Apis.kt | 90 ++++++++++++++++++- .../maimai2/handler/UpsertUserAllHandler.kt | 13 ++- .../sega/maimai2/model/GameDataEntities.kt | 16 ++++ .../samnyan/aqua/sega/maimai2/model/Repos.kt | 12 +++ .../model/request/Mai2UpsertUserAll.kt | 8 +- .../maimai2/model/userdata/Mai2UserDetail.kt | 1 + .../maimai2/model/userdata/UserEntities.kt | 19 ++++ .../samnyan/aqua/sega/util/GameDataService.kt | 6 ++ .../data/game/maimai2/game_pass_charge.json | 4 + .../game/maimai2/game_selling_pass_pack.json | 5 ++ .../db/120/V1000_89__maimai_magical.sql | 31 +++++++ 11 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/data/game/maimai2/game_pass_charge.json create mode 100644 src/main/resources/data/game/maimai2/game_selling_pass_pack.json create mode 100644 src/main/resources/db/120/V1000_89__maimai_magical.sql diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt index 33ec5287..10097143 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt @@ -7,6 +7,11 @@ import icu.samnyan.aqua.sega.general.model.CardStatus import icu.samnyan.aqua.sega.maimai2.model.UserRivalMusic import icu.samnyan.aqua.sega.maimai2.model.UserRivalMusicDetail import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserKaleidx +import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2ItemKind +import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserItem +import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserPass +import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserTicketLimitDate +import icu.samnyan.aqua.sega.maimai2.model.userdata.MAIMAI_DATETIME import icu.samnyan.aqua.sega.maimai2.model.userdata.UserRegions import java.time.LocalDate import kotlin.random.Random @@ -55,7 +60,81 @@ fun Maimai2ServletController.initApis() { // Maimai only request for event type 1 "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 db.gamePassCharge.findAll() + ) + } + } + + "GetGameSellingPassPack" static { + mapOf("gameSellingPassPackList" to db.gameSellingPassPack.findAll()) + } + + "GetUserPass" { + db.userData.findByCardExtId(uid) ?: (404 - "User not found") + mapOf("userId" to uid, "userPassList" to db.userPass.findByUser_Card_ExtId(uid)) + } + + "GetUserTicketLimitDate" { + db.userData.findByCardExtId(uid) ?: (404 - "User not found") + mapOf("userTicketLimitDateList" to db.userTicketLimitDate.findByUser_Card_ExtId(uid)) + } + + "UserPassModeEnter" static { mapOf("returnCode" to 1) } + "UserPassModeExit" static { mapOf("returnCode" to 1) } + + "UpsertUserPassMode" { + val user = db.userData.findByCardExtId(uid) ?: (404 - "User not found") + val pass = (data["userPassList"] as List<*>).first() as Map<*, *> + val passTypeId = (pass["passTypeId"] as Number).toInt() + val passPackId = (pass["passPackId"] as Number).toInt() + val passCharaId = (pass["passCharaId"] as Number).toInt() + val now = jstNow() + val startDate = now.format(MAIMAI_DATETIME) + val endDate = now.plusDays(14).format(MAIMAI_DATETIME) + + // store the new pass + val storedPass = (db.userPass.findByUserAndPassTypeId(user, passTypeId) ?: Mai2UserPass()).apply { + this.user = user + this.passTypeId = passTypeId + this.passPackId = passPackId + this.passCharaId = passCharaId + this.startDate = startDate + this.endDate = endDate + } + db.userPass.save(storedPass) + + // attempt to give user ticket 40001 (+1 track ticket) up to a max of 10 + val ticketId = 40001 + val ticket = (db.userItem.findByUserAndItemKindAndItemId(user, Mai2ItemKind.ticket.id, ticketId) + ?: Mai2UserItem().apply { + this.user = user + itemKind = Mai2ItemKind.ticket.id + itemId = ticketId + }).apply { + stock = (stock + 1).coerceAtMost(10) + isValid = true + } + db.userItem.save(ticket) + + // set expiry date for newly granted ticket + val limit = (db.userTicketLimitDate.findByUserAndItemId(user, ticketId) + ?: Mai2UserTicketLimitDate().apply { this.user = user; itemId = ticketId }).apply { + limitDate = endDate + } + db.userTicketLimitDate.save(limit) + + mapOf( + "returnCode" to 1, + "userPassList" to db.userPass.findByUser_Card_ExtId(uid), + "userItemList" to listOf(ticket), + "userTicketLimitDateList" to db.userTicketLimitDate.findByUser_Card_ExtId(uid) + ) + } "GetUserOption" { mapOf( "userId" to uid, @@ -383,14 +462,19 @@ fun Maimai2ServletController.initApis() { "aggrDate" to "" ) } - "GetUserCircleData" static { mapOf( + "GetUserCircleData" { + mapOf( + "userId" to uid, "circleId" to 0, "circleName" to "一緒に歌おう!", "isPlace" to false, "circleClass" to 0, "lastLoginDate" to "", + "mapBonusId" to 0, + "lastMapBonusDate" to (db.userData.findByCardExtId(uid)?.lastMapBonusDate ?: ""), "circlePointRankingList" to empty - ) } + ) + } "GetUserCircleChallenge" { mapOf( "userId" to uid, diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/UpsertUserAllHandler.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/UpsertUserAllHandler.kt index 9e742ea4..d0eca22a 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/UpsertUserAllHandler.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/UpsertUserAllHandler.kt @@ -75,7 +75,7 @@ class UpsertUserAllHandler( listOfNotNull( userExtend, userOption, userCharacterList, userMapList, userLoginBonusList, userItemList, userMusicDetailList, userCourseList, userFriendSeasonRankingList, userFavoriteList, - userKaleidxScopeList, userIntimateList, upsertUserAll.userPlaylogList + userKaleidxScopeList, userIntimateList, userTicketLimitDateList, upsertUserAll.userPlaylogList ) }.flatten().forEach { it.user = u } @@ -142,6 +142,17 @@ class UpsertUserAllHandler( repos.userIntimate.saveAll(lst.mapApply { id = repos.userIntimate.findByUserAndPartnerId(u, partnerId)?.id ?: 0 }) } + req.userTicketLimitDateList?.unique { it.itemId }?.let { lst -> + repos.userTicketLimitDate.saveAll(lst.mapApply { + id = repos.userTicketLimitDate.findByUserAndItemId(u, itemId)?.id ?: 0 + }) + } + + req.userCircleData?.lastMapBonusDate?.let { + u.lastMapBonusDate = it + repos.userData.save(u) + } + // Added on SDGA 1.65 / SDGB 1.53 upsertUserAll.userPlaylogList?.let(repos.userPlaylog::saveAll) diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt index 87188316..b3191056 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/GameDataEntities.kt @@ -20,6 +20,22 @@ class Mai2GameCharge { var endDate: String? = "2029-01-01 00:00:00.000000" } +class Mai2GamePassCharge { + var orderId: Long = 0 + var passTypeId = 0 + var price = 0 + var startDate: String? = "2019-01-01 00:00:00.000000" + var endDate: String? = "2099-01-01 00:00:00.000000" +} + +class Mai2GameSellingPassPack { + var passPackId = 0 + var startDate: String? = "2019-01-01 00:00:00.000000" + var endDate: String? = "2099-01-01 00:00:00.000000" + var noticeStartDate: String? = "2019-01-01 00:00:00.000000" + var noticeEndDate: String? = "2099-01-01 00:00:00.000000" +} + class Mai2GameSellingCard { var cardId = 0L var startDate: String? = "2019-01-01 00:00:00.000000" diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt index 326067a8..6afe315c 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt @@ -42,6 +42,14 @@ interface Mai2UserCharacterRepo : Mai2UserLinked { interface Mai2UserChargeRepo : Mai2UserLinked +interface Mai2UserPassRepo : Mai2UserLinked { + fun findByUserAndPassTypeId(user: Mai2UserDetail, passTypeId: Int): Mai2UserPass? +} + +interface Mai2UserTicketLimitDateRepo : Mai2UserLinked { + fun findByUserAndItemId(user: Mai2UserDetail, itemId: Int): Mai2UserTicketLimitDate? +} + interface Mai2UserCourseRepo : Mai2UserLinked { fun findByUserAndCourseId(user: Mai2UserDetail, courseId: Int): Mai2UserCourse? } @@ -130,6 +138,8 @@ class Mai2Repos( val userCard: Mai2UserCardRepo, val userCharacter: Mai2UserCharacterRepo, val userCharge: Mai2UserChargeRepo, + val userPass: Mai2UserPassRepo, + val userTicketLimitDate: Mai2UserTicketLimitDateRepo, val userCourse: Mai2UserCourseRepo, val userData: Mai2UserDataRepo, val userExtend: Mai2UserExtendRepo, @@ -150,6 +160,8 @@ class Mai2Repos( val gameData: GameDataService ) { val gameCharge = StaticRepo(gameData.mai2Charges) { it.orderId } + val gamePassCharge = StaticRepo(gameData.mai2PassCharges) { it.passTypeId.toLong() } + val gameSellingPassPack = StaticRepo(gameData.mai2SellingPassPacks) { it.passPackId.toLong() } val gameEvent = StaticRepo(gameData.mai2Events) { it.id } val gameSellingCard = StaticRepo(gameData.mai2SellingCards) { it.cardId } } diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt index 4e8916fe..f3408735 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/Mai2UpsertUserAll.kt @@ -30,6 +30,8 @@ class Mai2UserAll { var userFavoritemusicList: List? = null var userKaleidxScopeList: List? = null var userIntimateList: List? = null + var userTicketLimitDateList: List? = null + var userCircleData: Mai2UserCircleData? = null var isNewCharacterList: String? = null var isNewMapList: String? = null var isNewLoginBonusList: String? = null @@ -42,6 +44,11 @@ class Mai2UserAll { var isNewKaleidxScopeList: String? = null } +class Mai2UserCircleData { + var lastLoginDate: String = "" + var lastMapBonusDate: String = "" +} + class Mai2UserFavoriteItem { var orderId = 0 var id = 0 @@ -52,4 +59,3 @@ class Mai2UserActivity { var musicList: List = emptyList() } - diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt index 7cac8598..a354cfc5 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/Mai2UserDetail.kt @@ -87,6 +87,7 @@ class Mai2UserDetail( var dailyCourseBonusDate: String = "", var lastPairLoginDate: String = "", var lastTrialPlayDate: String = "", + var lastMapBonusDate: String = "", var playVsCount: Int = 0, var playSyncCount: Int = 0, var winCount: Int = 0, diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt index 83bfe3bb..a4674aa5 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt @@ -111,6 +111,25 @@ class Mai2UserCharge : Mai2UserEntity() { var validDate: String = "" } +@Table(name = "maimai2_user_pass", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "pass_type_id"])]) +@Entity +class Mai2UserPass : Mai2UserEntity() { + var passTypeId = 0 + var passPackId = 0 + var passCharaId = 0 + var mapId = 0 + var startDate: String = "" + var endDate: String = "" +} + +@Table(name = "maimai2_user_ticket_limit_date", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "item_id"])]) +@Entity +class Mai2UserTicketLimitDate : Mai2UserEntity() { + var itemId = 0 + var limitDate: String = "" + var lastUsedDate: String = "" +} + @Table(name = "maimai2_user_course") @Entity class Mai2UserCourse : Mai2UserEntity() { diff --git a/src/main/java/icu/samnyan/aqua/sega/util/GameDataService.kt b/src/main/java/icu/samnyan/aqua/sega/util/GameDataService.kt index ce830e97..a86b5e28 100644 --- a/src/main/java/icu/samnyan/aqua/sega/util/GameDataService.kt +++ b/src/main/java/icu/samnyan/aqua/sega/util/GameDataService.kt @@ -13,6 +13,8 @@ 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.Mai2GamePassCharge +import icu.samnyan.aqua.sega.maimai2.model.Mai2GameSellingPassPack 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 @@ -55,6 +57,8 @@ class GameDataService() { // maimai2 lateinit var mai2Events: List lateinit var mai2Charges: List + lateinit var mai2PassCharges: List + lateinit var mai2SellingPassPacks: List lateinit var mai2SellingCards: List lateinit var mai2GameEncryption: List @@ -88,6 +92,8 @@ class GameDataService() { fun load() { mai2Events = load("maimai2", "game_event.json") mai2Charges = load("maimai2", "game_charge.json") + mai2PassCharges = load("maimai2", "game_pass_charge.json") + mai2SellingPassPacks = load("maimai2", "game_selling_pass_pack.json") mai2SellingCards = load("maimai2", "game_selling_card.json") mai2GameEncryption = load(game = "maimai2", file = "game_encryption.json") diff --git a/src/main/resources/data/game/maimai2/game_pass_charge.json b/src/main/resources/data/game/maimai2/game_pass_charge.json new file mode 100644 index 00000000..ec94405c --- /dev/null +++ b/src/main/resources/data/game/maimai2/game_pass_charge.json @@ -0,0 +1,4 @@ +[ + {"orderId": 0, "passTypeId": 2, "price": 2, "startDate": "2026-09-17 00:00:00.000000", "endDate": "2099-01-01 00:00:00.000000"}, + {"orderId": 0, "passTypeId": 3, "price": 3, "startDate": "2026-09-17 00:00:00.000000", "endDate": "2099-01-01 00:00:00.000000"} +] diff --git a/src/main/resources/data/game/maimai2/game_selling_pass_pack.json b/src/main/resources/data/game/maimai2/game_selling_pass_pack.json new file mode 100644 index 00000000..e56bd9f7 --- /dev/null +++ b/src/main/resources/data/game/maimai2/game_selling_pass_pack.json @@ -0,0 +1,5 @@ +[ + {"passPackId": 7001, "startDate": "2026-09-17 00:00:00.000000", "endDate": "2026-11-06 00:00:00.000000", "noticeStartDate": "2026-09-03 00:00:00.000000", "noticeEndDate": "2026-11-06 00:00:00.000000"}, + {"passPackId": 7002, "startDate": "2026-11-06 00:00:00.000000", "endDate": "2027-01-08 00:00:00.000000", "noticeStartDate": "2026-10-23 00:00:00.000000", "noticeEndDate": "2027-01-08 00:00:00.000000"}, + {"passPackId": 7003, "startDate": "2027-01-08 00:00:00.000000", "endDate": "2099-01-01 00:00:00.000000", "noticeStartDate": "2026-12-25 00:00:00.000000", "noticeEndDate": "2099-01-01 00:00:00.000000"} +] diff --git a/src/main/resources/db/120/V1000_89__maimai_magical.sql b/src/main/resources/db/120/V1000_89__maimai_magical.sql new file mode 100644 index 00000000..2bccf34a --- /dev/null +++ b/src/main/resources/db/120/V1000_89__maimai_magical.sql @@ -0,0 +1,31 @@ +ALTER TABLE maimai2_user_detail + ADD COLUMN last_map_bonus_date VARCHAR(64) NOT NULL DEFAULT ''; + +CREATE TABLE maimai2_user_pass +( + id BIGINT AUTO_INCREMENT NOT NULL, + user_id BIGINT NOT NULL, + pass_type_id INT NOT NULL, + pass_pack_id INT NOT NULL, + pass_chara_id INT NOT NULL, + map_id INT NOT NULL DEFAULT 0, + start_date VARCHAR(64) NOT NULL DEFAULT '', + end_date VARCHAR(64) NOT NULL DEFAULT '', + CONSTRAINT pk_maimai2_user_pass PRIMARY KEY (id), + CONSTRAINT uc_maimai2_user_pass_type UNIQUE (user_id, pass_type_id), + CONSTRAINT fk_maimai2_user_pass_user FOREIGN KEY (user_id) + REFERENCES maimai2_user_detail (id) ON DELETE CASCADE +); + +CREATE TABLE maimai2_user_ticket_limit_date +( + id BIGINT AUTO_INCREMENT NOT NULL, + user_id BIGINT NOT NULL, + item_id INT NOT NULL, + limit_date VARCHAR(64) NOT NULL DEFAULT '', + last_used_date VARCHAR(64) NOT NULL DEFAULT '', + CONSTRAINT pk_maimai2_user_ticket_limit_date PRIMARY KEY (id), + CONSTRAINT uc_maimai2_user_ticket_limit_date_item UNIQUE (user_id, item_id), + CONSTRAINT fk_maimai2_user_ticket_limit_date_user FOREIGN KEY (user_id) + REFERENCES maimai2_user_detail (id) ON DELETE CASCADE +);