diff --git a/core/data/schema/versions/SDEZ_8_rollback.sql b/core/data/schema/versions/SDEZ_8_rollback.sql new file mode 100644 index 0000000..cfc5d4c --- /dev/null +++ b/core/data/schema/versions/SDEZ_8_rollback.sql @@ -0,0 +1,8 @@ +ALTER TABLE mai2_profile_detail + DROP COLUMN currentPlayCount, + DROP COLUMN renameCredit; + +ALTER TABLE mai2_playlog + DROP COLUMN extBool1; + +DROP TABLE IF EXISTS `mai2_playlog_2p`; diff --git a/core/data/schema/versions/SDEZ_9_upgrade.sql b/core/data/schema/versions/SDEZ_9_upgrade.sql new file mode 100644 index 0000000..4481075 --- /dev/null +++ b/core/data/schema/versions/SDEZ_9_upgrade.sql @@ -0,0 +1,20 @@ +ALTER TABLE mai2_profile_detail + ADD currentPlayCount INT NULL AFTER playCount, + ADD renameCredit INT NULL AFTER banState; + +ALTER TABLE mai2_playlog + ADD extBool1 BOOLEAN NULL AFTER extNum4; + +CREATE TABLE `mai2_playlog_2p` ( + `id` INT NOT NULL AUTO_INCREMENT, + `user` INT NOT NULL, + `userId1` BIGINT, + `userId2` BIGINT, + `userName1` VARCHAR(255), + `userName2` VARCHAR(255), + `regionId` INT, + `placeId` INT, + `user2pPlaylogDetailList` JSON, + PRIMARY KEY (`id`), + FOREIGN KEY (`user`) REFERENCES `aime_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/docs/game_specific_info.md b/docs/game_specific_info.md index ab2daab..8b04697 100644 --- a/docs/game_specific_info.md +++ b/docs/game_specific_info.md @@ -192,6 +192,7 @@ Config file is located in `config/cxb.yaml`. | SDEZ | 18 | maimai DX UNiVERSE PLUS | | SDEZ | 19 | maimai DX FESTiVAL | | SDEZ | 20 | maimai DX FESTiVAL PLUS | +| SDEZ | 21 | maimai DX BUDDiES | ### Importer @@ -406,6 +407,7 @@ After that, on next login the present should be received (or whenever it suppose * UNiVERSE PLUS: Yes * FESTiVAL: Yes (added in A031) * FESTiVAL PLUS: Yes (added in A035) + * BUDDiES: Yes (added in A039) * O.N.G.E.K.I. bright MEMORY: Yes diff --git a/readme.md b/readme.md index 1226784..114fef5 100644 --- a/readme.md +++ b/readme.md @@ -47,6 +47,7 @@ Games listed below have been tested and confirmed working. Only game versions ol + UNiVERSE PLUS + FESTiVAL + FESTiVAL PLUS + + BUDDiES + O.N.G.E.K.I. + SUMMER diff --git a/titles/chuni/index.py b/titles/chuni/index.py index b102d5e..68266e6 100644 --- a/titles/chuni/index.py +++ b/titles/chuni/index.py @@ -195,7 +195,7 @@ class ChuniServlet(BaseServlet): internal_ver = ChuniConstants.VER_CHUNITHM_NEW_PLUS elif version >= 210 and version < 215: # SUN internal_ver = ChuniConstants.VER_CHUNITHM_SUN - elif version >= 215: # SUN + elif version >= 215: # SUN PLUS internal_ver = ChuniConstants.VER_CHUNITHM_SUN_PLUS elif game_code == "SDGS": # Int if version < 110: # SUPERSTAR diff --git a/titles/cm/base.py b/titles/cm/base.py index e4fd1cb..4a49832 100644 --- a/titles/cm/base.py +++ b/titles/cm/base.py @@ -51,7 +51,7 @@ class CardMakerBase: { "modelKind": 1, "type": 1, - "titleUri": f"{uri}/{self._parse_int_ver(games_ver['maimai'])}/Maimai2Servlet/", + "titleUri": f"{uri}/SDEZ/{self._parse_int_ver(games_ver['maimai'])}/Maimai2Servlet/", }, # ONGEKI { diff --git a/titles/cm/read.py b/titles/cm/read.py index 0e2c841..6cc11fd 100644 --- a/titles/cm/read.py +++ b/titles/cm/read.py @@ -206,6 +206,7 @@ class CardMakerReader(BaseReader): "1.25": Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS, "1.30": Mai2Constants.VER_MAIMAI_DX_FESTIVAL, "1.35": Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS, + "1.40": Mai2Constants.VER_MAIMAI_DX_BUDDIES, } for root, dirs, files in os.walk(base_dir): diff --git a/titles/mai2/__init__.py b/titles/mai2/__init__.py index 962423b..ac4b6e0 100644 --- a/titles/mai2/__init__.py +++ b/titles/mai2/__init__.py @@ -7,6 +7,7 @@ index = Mai2Servlet database = Mai2Data reader = Mai2Reader game_codes = [ + Mai2Constants.GAME_CODE_INT, Mai2Constants.GAME_CODE_DX, Mai2Constants.GAME_CODE_FINALE, Mai2Constants.GAME_CODE_MILK, diff --git a/titles/mai2/buddies.py b/titles/mai2/buddies.py new file mode 100644 index 0000000..38049a1 --- /dev/null +++ b/titles/mai2/buddies.py @@ -0,0 +1,19 @@ +from typing import Dict + +from core.config import CoreConfig +from titles.mai2.festivalplus import Mai2FestivalPlus +from titles.mai2.const import Mai2Constants +from titles.mai2.config import Mai2Config + + +class Mai2Buddies(Mai2FestivalPlus): + def __init__(self, cfg: CoreConfig, game_cfg: Mai2Config) -> None: + super().__init__(cfg, game_cfg) + self.version = Mai2Constants.VER_MAIMAI_DX_BUDDIES + + 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.40.00" + return user_data diff --git a/titles/mai2/const.py b/titles/mai2/const.py index a4c29db..c9b4255 100644 --- a/titles/mai2/const.py +++ b/titles/mai2/const.py @@ -28,6 +28,7 @@ class Mai2Constants: GAME_CODE_MILK = "SDDZ" GAME_CODE_FINALE = "SDEY" GAME_CODE_DX = "SDEZ" + GAME_CODE_INT = "SDGA" CONFIG_NAME = "mai2.yaml" @@ -53,6 +54,7 @@ class Mai2Constants: VER_MAIMAI_DX_UNIVERSE_PLUS = 18 VER_MAIMAI_DX_FESTIVAL = 19 VER_MAIMAI_DX_FESTIVAL_PLUS = 20 + VER_MAIMAI_DX_BUDDIES = 21 VERSION_STRING = ( "maimai", @@ -76,6 +78,7 @@ class Mai2Constants: "maimai DX UNiVERSE PLUS", "maimai DX FESTiVAL", "maimai DX FESTiVAL PLUS", + "maimai DX BUDDiES", ) @classmethod diff --git a/titles/mai2/dx.py b/titles/mai2/dx.py index fff39f2..bfc14f2 100644 --- a/titles/mai2/dx.py +++ b/titles/mai2/dx.py @@ -213,6 +213,9 @@ class Mai2DX(Mai2Base): ) await self.data.item.put_friend_season_ranking(user_id, fsr) + if "user2pPlaylog" in upsert: + await self.data.score.put_2p_playlog(user_id, upsert["user2pPlaylog"]) + return {"returnCode": 1, "apiName": "UpsertUserAllApi"} async def handle_get_user_data_api_request(self, data: Dict) -> Dict: diff --git a/titles/mai2/index.py b/titles/mai2/index.py index 2ee4cae..16cf198 100644 --- a/titles/mai2/index.py +++ b/titles/mai2/index.py @@ -25,6 +25,7 @@ from .universe import Mai2Universe from .universeplus import Mai2UniversePlus from .festival import Mai2Festival from .festivalplus import Mai2FestivalPlus +from .buddies import Mai2Buddies class Mai2Servlet(BaseServlet): @@ -58,6 +59,7 @@ class Mai2Servlet(BaseServlet): Mai2UniversePlus, Mai2Festival, Mai2FestivalPlus, + Mai2Buddies, ] self.logger = logging.getLogger("mai2") @@ -111,18 +113,18 @@ class Mai2Servlet(BaseServlet): Route("/{version:int}/MaimaiServlet/usbdl/{endpoint:str}", self.handle_usbdl), Route("/{version:int}/MaimaiServlet/deliver/{endpoint:str}", self.handle_deliver), Route("/{version:int}/MaimaiServlet/{endpoint:str}", self.handle_mai, methods=['POST']), - Route("/{version:int}/Maimai2Servlet/{endpoint:str}", self.handle_mai2, methods=['POST']), + Route("/{game:str}/{version:int}/Maimai2Servlet/{endpoint:str}", self.handle_mai2, methods=['POST']), ] def get_allnet_info(self, game_code: str, game_ver: int, keychip: str) -> Tuple[str, str]: if not self.core_cfg.server.is_using_proxy and Utils.get_title_port(self.core_cfg) != 80: return ( - f"http://{self.core_cfg.server.hostname}:{Utils.get_title_port(self.core_cfg)}/{game_ver}/", + f"http://{self.core_cfg.server.hostname}:{Utils.get_title_port(self.core_cfg)}/{game_code}/{game_ver}/", f"{self.core_cfg.server.hostname}", ) return ( - f"http://{self.core_cfg.server.hostname}/{game_ver}/", + f"http://{self.core_cfg.server.hostname}/{game_code}/{game_ver}/", f"{self.core_cfg.server.hostname}", ) @@ -237,6 +239,7 @@ class Mai2Servlet(BaseServlet): async def handle_mai2(self, request: Request) -> bytes: endpoint: str = request.path_params.get('endpoint') version: int = request.path_params.get('version') + game_code: str = request.path_params.get('game') if endpoint.lower() == "ping": return Response(zlib.compress(b'{"returnCode": "1"}')) @@ -257,8 +260,10 @@ class Mai2Servlet(BaseServlet): internal_ver = Mai2Constants.VER_MAIMAI_DX_UNIVERSE_PLUS elif version >= 130 and version < 135: # FESTiVAL internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL - elif version >= 135: # FESTiVAL PLUS + elif version >= 135 and version < 140: # FESTiVAL PLUS internal_ver = Mai2Constants.VER_MAIMAI_DX_FESTIVAL_PLUS + elif version >= 140: # BUDDiES + internal_ver = Mai2Constants.VER_MAIMAI_DX_BUDDIES if ( request.headers.get("Mai-Encoding") is not None @@ -288,6 +293,7 @@ class Mai2Servlet(BaseServlet): self.logger.info(f"v{version} {endpoint} request from {client_ip}") self.logger.debug(req_data) + endpoint = endpoint.replace("MaimaiExp", "") if game_code == "SDGA" else endpoint func_to_find = "handle_" + inflection.underscore(endpoint) + "_request" handler_cls = self.versions[internal_ver](self.core_cfg, self.game_cfg) diff --git a/titles/mai2/schema/profile.py b/titles/mai2/schema/profile.py index b4cdbd8..ded7844 100644 --- a/titles/mai2/schema/profile.py +++ b/titles/mai2/schema/profile.py @@ -40,6 +40,8 @@ detail = Table( Column("charaLockSlot", JSON), Column("contentBit", BigInteger), Column("playCount", Integer), + Column("currentPlayCount", Integer), # new with bud + Column("renameCredit", Integer), # new with bud Column("mapStock", Integer), # new with fes+ Column("eventWatchedDate", String(25)), Column("lastGameId", String(25)), diff --git a/titles/mai2/schema/score.py b/titles/mai2/schema/score.py index 51dcc18..c4efdd0 100644 --- a/titles/mai2/schema/score.py +++ b/titles/mai2/schema/score.py @@ -146,10 +146,30 @@ playlog = Table( Column("extNum1", Integer), Column("extNum2", Integer), Column("extNum4", Integer, server_default="0"), + Column("extBool1", Boolean), # new with bud Column("trialPlayAchievement", Integer), mysql_charset="utf8mb4", ) +playlog_2p = Table( # new with buddies, the in-game name is 2pPlaylog + "mai2_playlog_2p", + metadata, + Column("id", Integer, primary_key=True, nullable=False), + Column( + "user", + ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"), + nullable=False, + ), + Column("userId1", BigInteger), + Column("userId2", BigInteger), + Column("userName1", String(255)), + Column("userName2", String(255)), + Column("regionId", Integer), + Column("placeId", Integer), + Column("user2pPlaylogDetailList", JSON), + mysql_charset="utf8mb4", +) + course = Table( "mai2_score_course", metadata, @@ -343,6 +363,18 @@ class Mai2ScoreData(BaseData): self.logger.error(f"put_playlog: Failed to insert! user_id {user_id} is_dx {is_dx}") return None return result.lastrowid + + async def put_2p_playlog(self, user_id: int, playlog_2p_data: Dict) -> Optional[int]: + playlog_2p_data["user"] = user_id + sql = insert(playlog_2p).values(**playlog_2p_data) + + conflict = sql.on_duplicate_key_update(**playlog_2p_data) + + result = await self.execute(conflict) + if result is None: + self.logger.error(f"put_2p_playlog: Failed to insert! user_id {user_id}") + return None + return result.lastrowid async def put_course(self, user_id: int, course_data: Dict) -> Optional[int]: course_data["user"] = user_id