From 1d545b2bd26601d54b831289d4c03deaa4a3c51e Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 02:32:34 +0800 Subject: [PATCH 01/14] add const.py of prism --- titles/mai2/const.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/titles/mai2/const.py b/titles/mai2/const.py index 0d13a0d..1d6a4dd 100644 --- a/titles/mai2/const.py +++ b/titles/mai2/const.py @@ -56,6 +56,7 @@ class Mai2Constants: VER_MAIMAI_DX_FESTIVAL_PLUS = 20 VER_MAIMAI_DX_BUDDIES = 21 VER_MAIMAI_DX_BUDDIES_PLUS = 22 + VER_MAIMAI_DX_PRISM = 23 VERSION_STRING = ( "maimai", @@ -80,7 +81,8 @@ class Mai2Constants: "maimai DX FESTiVAL", "maimai DX FESTiVAL PLUS", "maimai DX BUDDiES", - "maimai DX BUDDiES PLUS" + "maimai DX BUDDiES PLUS", + "maimai DX PRiSM" ) @classmethod From fa94c029ca936ae12f4a1e5b5c3e9ccaf4f3803e Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 03:07:35 +0800 Subject: [PATCH 02/14] add GetUserNewItemListApi handler --- titles/mai2/index.py | 17 ++++++++++++++--- titles/mai2/prism.py | 25 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 titles/mai2/prism.py diff --git a/titles/mai2/index.py b/titles/mai2/index.py index e8b88ec..86923e7 100644 --- a/titles/mai2/index.py +++ b/titles/mai2/index.py @@ -31,6 +31,7 @@ from .festival import Mai2Festival from .festivalplus import Mai2FestivalPlus from .buddies import Mai2Buddies from .buddiesplus import Mai2BuddiesPlus +from .prism import Mai2Prism class Mai2Servlet(BaseServlet): @@ -66,7 +67,8 @@ class Mai2Servlet(BaseServlet): Mai2Festival, Mai2FestivalPlus, Mai2Buddies, - Mai2BuddiesPlus + Mai2BuddiesPlus, + Mai2Prism ] self.logger = logging.getLogger("mai2") @@ -306,8 +308,11 @@ class Mai2Servlet(BaseServlet): internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS elif version >= 140 and version < 145: # BUDDiES internal_ver = Mai2Constants.VER_MAIMAI_DX_BUDDIES - elif version >= 145: # BUDDiES PLUS - internal_ver = Mai2Constants.VER_MAIMAI_DX_BUDDIES_PLUS + elif version >= 145 and version <150: # BUDDiES PLUS + internal_ver = Mai2Constants.VER_MAIMAI_DX_BUDDIES_PLUS, + elif version >=150: + internal_ver = Mai2Constants.VER_MAIMAI_DX_PRISM + elif game_code == "SDGA": # Int if version < 105: # 1.0 internal_ver = Mai2Constants.VER_MAIMAI_DX @@ -325,6 +330,12 @@ class Mai2Servlet(BaseServlet): internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL elif version >= 135 and version < 140: # FESTiVAL PLUS internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS + elif version >= 140 and version < 145: # BUDDiES + internal_ver = Mai2Constants.VER_MAIMAI_DX_BUDDIES + elif version >= 145 and version <150: # BUDDiES PLUS + internal_ver = Mai2Constants.VER_MAIMAI_DX_BUDDIES_PLUS, + elif version >=150: + internal_ver = Mai2Constants.VER_MAIMAI_DX_PRISM if all(c in string.hexdigits for c in endpoint) and len(endpoint) == 32: # If we get a 32 character long hex string, it's a hash and we're diff --git a/titles/mai2/prism.py b/titles/mai2/prism.py new file mode 100644 index 0000000..c208a85 --- /dev/null +++ b/titles/mai2/prism.py @@ -0,0 +1,25 @@ +from typing import Dict + +from core.config import CoreConfig +from titles.mai2.buddiesplus import Mai2BuddiesPlus +from titles.mai2.const import Mai2Constants +from titles.mai2.config import Mai2Config + +class Mai2Prism(Mai2BuddiesPlus): + def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None: + super().__init__(cfg, game_cfg) + self.version = Mai2Constants.VER_MAIMAI_DX_PRISM + + async def handle_cm_get_user_preview_api_request(self, data: Dict) -> Dict: + user_data = await super().handle_cm_get_user_preview_api_request(data) + + # hardcode lastDataVersion for CardMaker + user_data["lastDataVersion"] = "1.50.00" + return user_data + + + async def handle_get_user_new_item_list_api_request(self, data: Dict) -> Dict: + return { + "user_id": data["userId"], + "userItemList": [] + } \ No newline at end of file From f4b9f48ed62e54f4ca038d4945f873783b33323e Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 03:07:59 +0800 Subject: [PATCH 03/14] add cardmaker support for Prism --- titles/cm/read.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/titles/cm/read.py b/titles/cm/read.py index b4b3b5e..cf697c6 100644 --- a/titles/cm/read.py +++ b/titles/cm/read.py @@ -207,7 +207,8 @@ class CardMakerReader(BaseReader): "1.30": Mai2Constants.VER_MAIMAI_DX_FESTIVAL, "1.35": Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS, "1.40": Mai2Constants.VER_MAIMAI_DX_BUDDIES, - "1.45": Mai2Constants.VER_MAIMAI_DX_BUDDIES_PLUS + "1.45": Mai2Constants.VER_MAIMAI_DX_BUDDIES_PLUS, + "1.50": Mai2Constants.VER_MAIMAI_DX_PRISM } for root, dirs, files in os.walk(base_dir): From 6b1b607db068c39b1001c1d295128eb1302bc1ed Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 04:35:14 +0800 Subject: [PATCH 04/14] add GetGameMusicScoreApi handler --- titles/mai2/prism.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/titles/mai2/prism.py b/titles/mai2/prism.py index c208a85..30044df 100644 --- a/titles/mai2/prism.py +++ b/titles/mai2/prism.py @@ -22,4 +22,15 @@ class Mai2Prism(Mai2BuddiesPlus): return { "user_id": data["userId"], "userItemList": [] - } \ No newline at end of file + } + + #seems to be used for downloading music scores online + async def handle_get_game_music_score_api_request(self, data: Dict) -> Dict: + return { + "gameMusicScore": { + "musicId": data["musicId"], + "level": data["level"], + "type": data["type"], + "scoreData": "" + } + } From 6821ab6f4668b89974998fbd494eb995097a6e40 Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 04:35:39 +0800 Subject: [PATCH 05/14] add UploadUserPlaylogListApi handler for Exp version --- titles/mai2/dx.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/titles/mai2/dx.py b/titles/mai2/dx.py index b37a3f4..01e440f 100644 --- a/titles/mai2/dx.py +++ b/titles/mai2/dx.py @@ -112,6 +112,17 @@ class Mai2DX(Mai2Base): return {"returnCode": 1, "apiName": "UploadUserPlaylogApi"} + # Exp version use this instead of UploadUserPlaylogApi in 1.50 + async def handle_upload_user_playlog_list_api_request(self, data: Dict) -> Dict: + user_id = data["userId"] + playlog_list = data["userPlaylogList"] + + for playlog in playlog_list: + await self.data.score.put_playlog(user_id, playlog) + + return {"returnCode": 1, "apiName": "UploadUserPlaylogApi"} + + async def handle_upsert_user_chargelog_api_request(self, data: Dict) -> Dict: user_id = data["userId"] charge = data["userCharge"] From 814c4fd28407ff6c2e6c82f0bfce2d9a21777a83 Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 04:54:01 +0800 Subject: [PATCH 06/14] add GetGameKaleidxScopeApi handler --- titles/mai2/prism.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/titles/mai2/prism.py b/titles/mai2/prism.py index 30044df..addb646 100644 --- a/titles/mai2/prism.py +++ b/titles/mai2/prism.py @@ -34,3 +34,15 @@ class Mai2Prism(Mai2BuddiesPlus): "scoreData": "" } } + + async def handle_get_game_kaleidx_scope_api_request(self, data: Dict) -> Dict: + return { + "gameKaleidxScopeList": [ + {"gateId": 1, "phaseId": 6}, + {"gateId": 2, "phaseId": 6}, + {"gateId": 3, "phaseId": 6}, + {"gateId": 4, "phaseId": 6}, + {"gateId": 5, "phaseId": 6}, + {"gateId": 6, "phaseId": 6} + ] + } \ No newline at end of file From 36354ae109d5a4c11ef66cb496ab972f33edff68 Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 05:46:44 +0800 Subject: [PATCH 07/14] add GetUserKaleidxScopeApi handler --- titles/mai2/prism.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/titles/mai2/prism.py b/titles/mai2/prism.py index addb646..c826330 100644 --- a/titles/mai2/prism.py +++ b/titles/mai2/prism.py @@ -45,4 +45,13 @@ class Mai2Prism(Mai2BuddiesPlus): {"gateId": 5, "phaseId": 6}, {"gateId": 6, "phaseId": 6} ] + } + + async def handle_get_user_kaleidx_scope_api_request(self, data: Dict) -> Dict: + user_id = data["userId"] + + + return { + "userId": user_id, + "userKaleidxScopeList": [] } \ No newline at end of file From d77d02c2dde132025773abae468e2cb4eab5091d Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 06:42:28 +0800 Subject: [PATCH 08/14] database add Mai2Prism support --- .../d0f1c7fa9505_mai2_add_prism_support.py | 28 +++++++++++++++++++ titles/mai2/schema/score.py | 1 + 2 files changed, 29 insertions(+) create mode 100644 core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py diff --git a/core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py b/core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py new file mode 100644 index 0000000..c879706 --- /dev/null +++ b/core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py @@ -0,0 +1,28 @@ +"""Mai2 add PRiSM support + +Revision ID: d0f1c7fa9505 +Revises: 1d0014d35220 +Create Date: 2025-04-02 06:37:10.657372 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'd0f1c7fa9505' +down_revision = '1d0014d35220' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('mai2_playlog', sa.Column('extBool2', sa.Boolean(), nullable=True,server_default=sa.text("NULL"))) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('mai2_playlog', 'extBool2') + # ### end Alembic commands ### diff --git a/titles/mai2/schema/score.py b/titles/mai2/schema/score.py index cbe7448..56957b3 100644 --- a/titles/mai2/schema/score.py +++ b/titles/mai2/schema/score.py @@ -147,6 +147,7 @@ playlog = Table( Column("extNum2", Integer), Column("extNum4", Integer), Column("extBool1", Boolean), # new with buddies + Column("extBool2", Boolean), # new with prism Column("trialPlayAchievement", Integer), mysql_charset="utf8mb4", ) From 3d84e328928e8fef9e7964a1ad58e4e3b2e497d5 Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 09:42:08 +0800 Subject: [PATCH 09/14] add Kaleidx Scope Support --- titles/mai2/dx.py | 6 +++++ titles/mai2/prism.py | 16 ++++++++++--- titles/mai2/schema/score.py | 48 +++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/titles/mai2/dx.py b/titles/mai2/dx.py index 01e440f..82e99f9 100644 --- a/titles/mai2/dx.py +++ b/titles/mai2/dx.py @@ -282,6 +282,12 @@ class Mai2DX(Mai2Base): for intimate in upsert["userIntimateList"]: await self.data.profile.put_intimacy(user_id, intimate["partnerId"], intimate["intimateLevel"], intimate["intimateCountRewarded"]) + # added in PRiSM + if "userKaleidxScopeList" in upsert and len(upsert["userKaleidxScopeList"]) > 0: + for kaleidx_scope in upsert["userKaleidxScopeList"]: + await self.data.score.put_user_kaleidx_scope(user_id, kaleidx_scope) + + return {"returnCode": 1, "apiName": "UpsertUserAllApi"} async def handle_get_user_data_api_request(self, data: Dict) -> Dict: diff --git a/titles/mai2/prism.py b/titles/mai2/prism.py index c826330..5d0da41 100644 --- a/titles/mai2/prism.py +++ b/titles/mai2/prism.py @@ -4,6 +4,8 @@ from core.config import CoreConfig from titles.mai2.buddiesplus import Mai2BuddiesPlus from titles.mai2.const import Mai2Constants from titles.mai2.config import Mai2Config +from titles.mai2.schema.score import kaleidx_scope + class Mai2Prism(Mai2BuddiesPlus): def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None: @@ -48,10 +50,18 @@ class Mai2Prism(Mai2BuddiesPlus): } async def handle_get_user_kaleidx_scope_api_request(self, data: Dict) -> Dict: - user_id = data["userId"] + kaleidx_scope = await self.data.score.get_user_kaleidx_scope_list(data["userId"]) + if kaleidx_scope is None: + return {"userId": data["userId"], "userKaleidxScopeList":[]} + kaleidx_scope_list = [] + for kaleidx_scope_data in kaleidx_scope: + tmp = kaleidx_scope_data._asdict() + tmp.pop("user") + tmp.pop("id") + kaleidx_scope_list.append(tmp) return { - "userId": user_id, - "userKaleidxScopeList": [] + "userId": data["userId"], + "userKaleidxScopeList": kaleidx_scope_list } \ No newline at end of file diff --git a/titles/mai2/schema/score.py b/titles/mai2/schema/score.py index 56957b3..f3e7002 100644 --- a/titles/mai2/schema/score.py +++ b/titles/mai2/schema/score.py @@ -1,3 +1,4 @@ +from configparser import Interpolation from typing import Dict, List, Optional from sqlalchemy import Column, Table, UniqueConstraint, and_ @@ -174,6 +175,34 @@ playlog_2p = Table( mysql_charset="utf8mb4", ) +kaleidx_scope = Table( + "mai2_score_kaleidx_scope", + metadata, + Column("id", Integer, primary_key=True, nullable=False), + Column( + "user", + ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), + nullable=False, + ), + Column("gateId", Integer), + Column("isGateFound", Boolean), + Column("isKeyFound", Boolean), + Column("isClear", Boolean), + Column("totalRestLife", Integer), + Column("totalAchievement", Integer), + Column("totalDeluxscore", Integer), + Column("bestAchievement", Integer), + Column("bestDeluxscore", Integer), + Column("bestAchievementDate", String(25)), + Column("bestDeluxscoreDate", String(25)), + Column("playCount", Integer), + Column("clearDate", String(25)), + Column("lastPlayDate", String(25)), + Column("isInfoWatched", Boolean), + UniqueConstraint("user", "gateId", name="mai2_score_best_uk"), + mysql_charset="utf8mb4" +) + course = Table( "mai2_score_course", metadata, @@ -451,3 +480,22 @@ class Mai2ScoreData(BaseData): self.logger.warning(f"aime_id {aime_id} has no playlog ") return None return result.scalar() + + async def get_user_kaleidx_scope_list(self, user_id: int) -> Optional[List[Row]]: + sql = kaleidx_scope.select(kaleidx_scope.c.user == user_id) + result = await self.execute(sql) + if result is None: + return None + return result.fetchall() + + async def put_user_kaleidx_scope(self, user_id: int, user_kaleidx_scope_data: Dict) -> Optional[int]: + user_kaleidx_scope_data["user"] = user_id + sql = insert(kaleidx_scope).values(**user_kaleidx_scope_data) + + conflict = sql.on_duplicate_key_update(**user_kaleidx_scope_data) + + result = await self.execute(conflict) + if result is None: + self.logger.error(f"put_user_kaleidx_scope: Failed to insert! user_id {user_id}") + return None + return result.lastrowid \ No newline at end of file From 94b3c47c3c35dfcc5bbeffdbcc2f5898aa24d4d5 Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 09:42:40 +0800 Subject: [PATCH 10/14] update readme.md and game_specific_info.md --- docs/game_specific_info.md | 4 +++- readme.md | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/game_specific_info.md b/docs/game_specific_info.md index 7337191..6bb3f67 100644 --- a/docs/game_specific_info.md +++ b/docs/game_specific_info.md @@ -203,7 +203,7 @@ Presents are items given to the user when they login, with a little animation (f ### Versions | Game Code | Version ID | Version Name | -| --------- | ---------- | ----------------------- | +|-----------|------------|-------------------------| | SBXL | 0 | maimai | | SBXL | 1 | maimai PLUS | | SBZF | 2 | maimai GreeN | @@ -227,6 +227,8 @@ Presents are items given to the user when they login, with a little animation (f | SDEZ | 20 | maimai DX FESTiVAL PLUS | | SDEZ | 21 | maimai DX BUDDiES | | SDEZ | 22 | maimai DX BUDDiES PLUS | +| SDEZ | 23 | maimai DX PRiSM | + ### Importer diff --git a/readme.md b/readme.md index 57f81a4..e29784d 100644 --- a/readme.md +++ b/readme.md @@ -52,6 +52,7 @@ Games listed below have been tested and confirmed working. Only game versions ol + FESTiVAL PLUS + BUDDiES + BUDDiES PLUS + + PRiSM + O.N.G.E.K.I. + SUMMER From cc7afa6b67dbd8f763ce31568625433ec494f97e Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Wed, 2 Apr 2025 11:57:08 +0800 Subject: [PATCH 11/14] database add kaleidx scope support --- ...16f34bf7b968_mai2_kaleidx_scope_support.py | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 core/data/alembic/versions/16f34bf7b968_mai2_kaleidx_scope_support.py diff --git a/core/data/alembic/versions/16f34bf7b968_mai2_kaleidx_scope_support.py b/core/data/alembic/versions/16f34bf7b968_mai2_kaleidx_scope_support.py new file mode 100644 index 0000000..b8baa1a --- /dev/null +++ b/core/data/alembic/versions/16f34bf7b968_mai2_kaleidx_scope_support.py @@ -0,0 +1,50 @@ +"""Mai2 Kaleidx Scope Support + +Revision ID: 16f34bf7b968 +Revises: d0f1c7fa9505 +Create Date: 2025-04-02 07:06:15.829591 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '16f34bf7b968' +down_revision = 'd0f1c7fa9505' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('mai2_score_kaleidx_scope', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user', sa.Integer(), nullable=False), + sa.Column('gateId', sa.Integer(), nullable=True), + sa.Column('isGateFound', sa.Boolean(), nullable=True), + sa.Column('isKeyFound', sa.Boolean(), nullable=True), + sa.Column('isClear', sa.Boolean(), nullable=True), + sa.Column('totalRestLife', sa.Integer(), nullable=True), + sa.Column('totalAchievement', sa.Integer(), nullable=True), + sa.Column('totalDeluxscore', sa.Integer(), nullable=True), + sa.Column('bestAchievement', sa.Integer(), nullable=True), + sa.Column('bestDeluxscore', sa.Integer(), nullable=True), + sa.Column('bestAchievementDate', sa.String(length=25), nullable=True), + sa.Column('bestDeluxscoreDate', sa.String(length=25), nullable=True), + sa.Column('playCount', sa.Integer(), nullable=True), + sa.Column('clearDate', sa.String(length=25), nullable=True), + sa.Column('lastPlayDate', sa.String(length=25), nullable=True), + sa.Column('isInfoWatched', sa.Boolean(), nullable=True), + sa.ForeignKeyConstraint(['user'], ['aime_user.id'], onupdate='cascade', ondelete='cascade'), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('user', 'gateId', name='mai2_score_best_uk'), + mysql_charset='utf8mb4' + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('mai2_score_kaleidx_scope') + # ### end Alembic commands ### From 9a7fc007bc9cf8046bed792ef110d82e67874177 Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Fri, 4 Apr 2025 05:42:53 +0800 Subject: [PATCH 12/14] standardization KaleidxScope variable names --- titles/mai2/dx.py | 4 ++-- titles/mai2/prism.py | 15 +++++++-------- titles/mai2/schema/score.py | 18 +++++++++--------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/titles/mai2/dx.py b/titles/mai2/dx.py index 82e99f9..9b8b547 100644 --- a/titles/mai2/dx.py +++ b/titles/mai2/dx.py @@ -284,8 +284,8 @@ class Mai2DX(Mai2Base): # added in PRiSM if "userKaleidxScopeList" in upsert and len(upsert["userKaleidxScopeList"]) > 0: - for kaleidx_scope in upsert["userKaleidxScopeList"]: - await self.data.score.put_user_kaleidx_scope(user_id, kaleidx_scope) + for kaleidxscope in upsert["userKaleidxScopeList"]: + await self.data.score.put_user_kaleidxscope(user_id, kaleidxscope) return {"returnCode": 1, "apiName": "UpsertUserAllApi"} diff --git a/titles/mai2/prism.py b/titles/mai2/prism.py index 5d0da41..5db7c8a 100644 --- a/titles/mai2/prism.py +++ b/titles/mai2/prism.py @@ -4,7 +4,6 @@ from core.config import CoreConfig from titles.mai2.buddiesplus import Mai2BuddiesPlus from titles.mai2.const import Mai2Constants from titles.mai2.config import Mai2Config -from titles.mai2.schema.score import kaleidx_scope class Mai2Prism(Mai2BuddiesPlus): @@ -50,18 +49,18 @@ class Mai2Prism(Mai2BuddiesPlus): } async def handle_get_user_kaleidx_scope_api_request(self, data: Dict) -> Dict: - kaleidx_scope = await self.data.score.get_user_kaleidx_scope_list(data["userId"]) + kaleidxscope = await self.data.score.get_user_kaleidxscope_list(data["userId"]) - if kaleidx_scope is None: + if kaleidxscope is None: return {"userId": data["userId"], "userKaleidxScopeList":[]} - kaleidx_scope_list = [] - for kaleidx_scope_data in kaleidx_scope: - tmp = kaleidx_scope_data._asdict() + kaleidxscope_list = [] + for kaleidxscope_data in kaleidxscope: + tmp = kaleidxscope_data._asdict() tmp.pop("user") tmp.pop("id") - kaleidx_scope_list.append(tmp) + kaleidxscope_list.append(tmp) return { "userId": data["userId"], - "userKaleidxScopeList": kaleidx_scope_list + "userKaleidxScopeList": kaleidxscope_list } \ No newline at end of file diff --git a/titles/mai2/schema/score.py b/titles/mai2/schema/score.py index f3e7002..d03dba4 100644 --- a/titles/mai2/schema/score.py +++ b/titles/mai2/schema/score.py @@ -175,8 +175,8 @@ playlog_2p = Table( mysql_charset="utf8mb4", ) -kaleidx_scope = Table( - "mai2_score_kaleidx_scope", +kaleidxscope = Table( + "mai2_score_kaleidxscope", metadata, Column("id", Integer, primary_key=True, nullable=False), Column( @@ -481,21 +481,21 @@ class Mai2ScoreData(BaseData): return None return result.scalar() - async def get_user_kaleidx_scope_list(self, user_id: int) -> Optional[List[Row]]: - sql = kaleidx_scope.select(kaleidx_scope.c.user == user_id) + async def get_user_kaleidxscope_list(self, user_id: int) -> Optional[List[Row]]: + sql = kaleidxscope.select(kaleidxscope.c.user == user_id) result = await self.execute(sql) if result is None: return None return result.fetchall() - async def put_user_kaleidx_scope(self, user_id: int, user_kaleidx_scope_data: Dict) -> Optional[int]: - user_kaleidx_scope_data["user"] = user_id - sql = insert(kaleidx_scope).values(**user_kaleidx_scope_data) + async def put_user_kaleidxscope(self, user_id: int, user_kaleidxscope_data: Dict) -> Optional[int]: + user_kaleidxscope_data["user"] = user_id + sql = insert(kaleidxscope).values(**user_kaleidxscope_data) - conflict = sql.on_duplicate_key_update(**user_kaleidx_scope_data) + conflict = sql.on_duplicate_key_update(**user_kaleidxscope_data) result = await self.execute(conflict) if result is None: - self.logger.error(f"put_user_kaleidx_scope: Failed to insert! user_id {user_id}") + self.logger.error(f"put_user_kaleidxscope: Failed to insert! user_id {user_id}") return None return result.lastrowid \ No newline at end of file From 703068e9659d15ab2c40d17c26042a9cd378eea8 Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Tue, 8 Apr 2025 08:11:01 +0800 Subject: [PATCH 13/14] delete unused alembic file create new alembic file --- ....py => 5cf98cfe52ad_mai2_prism_support.py} | 18 ++++++------ .../d0f1c7fa9505_mai2_add_prism_support.py | 28 ------------------- docs/game_specific_info.md | 8 +++--- 3 files changed, 14 insertions(+), 40 deletions(-) rename core/data/alembic/versions/{16f34bf7b968_mai2_kaleidx_scope_support.py => 5cf98cfe52ad_mai2_prism_support.py} (79%) delete mode 100644 core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py diff --git a/core/data/alembic/versions/16f34bf7b968_mai2_kaleidx_scope_support.py b/core/data/alembic/versions/5cf98cfe52ad_mai2_prism_support.py similarity index 79% rename from core/data/alembic/versions/16f34bf7b968_mai2_kaleidx_scope_support.py rename to core/data/alembic/versions/5cf98cfe52ad_mai2_prism_support.py index b8baa1a..77ca08a 100644 --- a/core/data/alembic/versions/16f34bf7b968_mai2_kaleidx_scope_support.py +++ b/core/data/alembic/versions/5cf98cfe52ad_mai2_prism_support.py @@ -1,8 +1,8 @@ -"""Mai2 Kaleidx Scope Support +"""Mai2 PRiSM support -Revision ID: 16f34bf7b968 -Revises: d0f1c7fa9505 -Create Date: 2025-04-02 07:06:15.829591 +Revision ID: 5cf98cfe52ad +Revises: 263884e774cc +Create Date: 2025-04-08 08:00:51.243089 """ from alembic import op @@ -10,15 +10,15 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '16f34bf7b968' -down_revision = 'd0f1c7fa9505' +revision = '5cf98cfe52ad' +down_revision = '263884e774cc' branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.create_table('mai2_score_kaleidx_scope', + op.create_table('mai2_score_kaleidxscope', sa.Column('id', sa.Integer(), nullable=False), sa.Column('user', sa.Integer(), nullable=False), sa.Column('gateId', sa.Integer(), nullable=True), @@ -41,10 +41,12 @@ def upgrade(): sa.UniqueConstraint('user', 'gateId', name='mai2_score_best_uk'), mysql_charset='utf8mb4' ) + op.add_column('mai2_playlog', sa.Column('extBool2', sa.Boolean(), nullable=True, server_default=sa.text("NULL"))) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('mai2_score_kaleidx_scope') + op.drop_column('mai2_playlog', 'extBool2') + op.drop_table('mai2_score_kaleidxscope') # ### end Alembic commands ### diff --git a/core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py b/core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py deleted file mode 100644 index c879706..0000000 --- a/core/data/alembic/versions/d0f1c7fa9505_mai2_add_prism_support.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Mai2 add PRiSM support - -Revision ID: d0f1c7fa9505 -Revises: 1d0014d35220 -Create Date: 2025-04-02 06:37:10.657372 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'd0f1c7fa9505' -down_revision = '1d0014d35220' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('mai2_playlog', sa.Column('extBool2', sa.Boolean(), nullable=True,server_default=sa.text("NULL"))) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('mai2_playlog', 'extBool2') - # ### end Alembic commands ### diff --git a/docs/game_specific_info.md b/docs/game_specific_info.md index 6bb3f67..7121478 100644 --- a/docs/game_specific_info.md +++ b/docs/game_specific_info.md @@ -195,10 +195,10 @@ Config file is located in `config/cxb.yaml`. ### Presents Presents are items given to the user when they login, with a little animation (for example, the KOP song was given to the finalists as a present). To add a present, you must insert it into the `mai2_item_present` table. In that table, a NULL version means any version, a NULL user means any user, a NULL start date means always open, and a NULL end date means it never expires. Below is a list of presents one might wish to add: -| Game Version | Item ID | Item Kind | Item Description | Present Description | -|--------------|---------|-----------|-------------------------------------------------|------------------------------------------------| -| BUDDiES (21) | 409505 | Icon (3) | 旅行スタンプ(月面基地) (Travel Stamp - Moon Base) | Officially obtained on the webui with a serial | -| | | | | number, for project raputa | +| Game Version | Item ID | Item Kind | Item Description | Present Description | +|--------------|---------|----------------------|--------------------------------------------|----------------------------------------------------------------------------| +| BUDDiES (21) | 409505 | Icon (3) | 旅行スタンプ(月面基地) (Travel Stamp - Moon Base) | Officially obtained on the webui with a serial number, for project raputa | +| PRiSM (23) | 3 | KaleidxScopeKey (15) | 紫の鍵 (Purple Key) | Officially obtained on the webui with a serial number, for KaleidxScope | ### Versions From ecd4cc205e7553e73dc20ea4b57bc14b020629dc Mon Sep 17 00:00:00 2001 From: SoulGateKey Date: Tue, 8 Apr 2025 08:34:21 +0800 Subject: [PATCH 14/14] Add new KaleidxScope Condition handle method --- titles/mai2/const.py | 11 ++++++++++- titles/mai2/prism.py | 45 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/titles/mai2/const.py b/titles/mai2/const.py index df35da3..6a53324 100644 --- a/titles/mai2/const.py +++ b/titles/mai2/const.py @@ -87,7 +87,16 @@ class Mai2Constants: "maimai DX BUDDiES PLUS", "maimai DX PRiSM" ) - + KALEIDXSCOPE_KEY_CONDITION={ + 1: [11009, 11008, 11100, 11097, 11098, 11099, 11163, 11162, 11161, 11228, 11229, 11231, 11463, 11464, 11465, 11538, 11539, 11541, 11620, 11622, 11623, 11737, 11738, 11164, 11230, 11466, 11540, 11621, 11739], + #青の扉: Played 29 songs + 2: [11102, 11234, 11300, 11529, 11542, 11612], + #白の扉: set Frame as "Latent Kingdom" (459504), play 3 or 4 songs by the composer 大国奏音 in 1 pc + 3: [], + #紫の扉: need to enter redeem code 51090942171709440000 + 4: [11023, 11106, 11221, 11222, 11300, 11374, 11458, 11523, 11619, 11663, 11746], + #青の扉: Played 11 songs + } MAI_VERSION_LUT = { "100": VER_MAIMAI, "110": VER_MAIMAI_PLUS, diff --git a/titles/mai2/prism.py b/titles/mai2/prism.py index 5db7c8a..95ebb74 100644 --- a/titles/mai2/prism.py +++ b/titles/mai2/prism.py @@ -43,12 +43,53 @@ class Mai2Prism(Mai2BuddiesPlus): {"gateId": 2, "phaseId": 6}, {"gateId": 3, "phaseId": 6}, {"gateId": 4, "phaseId": 6}, - {"gateId": 5, "phaseId": 6}, - {"gateId": 6, "phaseId": 6} ] } async def handle_get_user_kaleidx_scope_api_request(self, data: Dict) -> Dict: + # kaleidxscope keyget condition judgement + # player may get key before GateFound + for gate in range(1,5): + if gate == 1 or gate == 4: + condition_satisfy = 0 + for condition in Mai2Constants.KALEIDXSCOPE_KEY_CONDITION[gate]: + score_list = await self.data.score.get_best_scores(user_id=data["userId"], song_id=condition) + if score_list: + condition_satisfy = condition_satisfy + 1 + if len(Mai2Constants.KALEIDXSCOPE_KEY_CONDITION[gate]) == condition_satisfy: + new_kaleidxscope = {'gateId': gate, "isKeyFound": True} + await self.data.score.put_user_kaleidxscope(data["userId"], new_kaleidxscope) + + elif gate == 2: + user_profile = await self.data.profile.get_profile_detail(user_id=data["userId"], version=self.version) + user_frame = user_profile["frameId"] + if user_frame == 459504: + playlogs = await self.data.score.get_playlogs(user_id=data["userId"], idx=0, limit=0) + + playlog_dict = {} + for playlog in playlogs: + playlog_id = playlog["playlogId"] + if playlog_id not in playlog_dict: + playlog_dict[playlog_id] = [] + playlog_dict[playlog_id].append(playlog["musicId"]) + valid_playlogs = [] + allowed_music = set(Mai2Constants.KALEIDXSCOPE_KEY_CONDITION[2]) + for playlog_id, music_ids in playlog_dict.items(): + + if len(music_ids) != len(set(music_ids)): + continue + all_valid = True + for mid in music_ids: + if mid not in allowed_music: + all_valid = False + break + if all_valid: + valid_playlogs.append(playlog_id) + + if valid_playlogs: + new_kaleidxscope = {'gateId': 2, "isKeyFound": True} + await self.data.score.put_user_kaleidxscope(data["userId"], new_kaleidxscope) + kaleidxscope = await self.data.score.get_user_kaleidxscope_list(data["userId"]) if kaleidxscope is None: