From 9dd2b4d524cdbc382276ae69d8651ea6c711d595 Mon Sep 17 00:00:00 2001 From: Midorica Date: Wed, 28 Jun 2023 00:18:02 -0400 Subject: [PATCH] Adding dummy hero QR code scanning for SAO --- docs/game_specific_info.md | 4 +- titles/sao/base.py | 10 ++ titles/sao/handlers/base.py | 249 ++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+), 1 deletion(-) diff --git a/docs/game_specific_info.md b/docs/game_specific_info.md index d2ae6d8..9bc75a6 100644 --- a/docs/game_specific_info.md +++ b/docs/game_specific_info.md @@ -437,9 +437,11 @@ python dbutils.py --game SDEW upgrade ``` ### Notes -- Co-Op (matching) is not supported +- Defrag Match will crash at loading +- Co-Op Online is not supported - Shop is not functionnal - Player title is currently static and cannot be changed in-game +- QR Card Scanning currently only load a static hero ### Credits for SAO support: diff --git a/titles/sao/base.py b/titles/sao/base.py index c2ec49d..8886a49 100644 --- a/titles/sao/base.py +++ b/titles/sao/base.py @@ -1188,4 +1188,14 @@ class SaoBase: def handle_cd06(self, request: Any) -> bytes: #defrag_match/get_defrag_match_league_score_ranking_list resp = SaoGetDefragMatchLeagueScoreRankingListResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1) + return resp.make() + + def handle_d404(self, request: Any) -> bytes: + #other/bnid_serial_code_check + resp = SaoBnidSerialCodeCheckResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1) + return resp.make() + + def handle_c306(self, request: Any) -> bytes: + #card/scan_qr_quest_profile_card + resp = SaoScanQrQuestProfileCardResponse(int.from_bytes(bytes.fromhex(request[:4]), "big")+1) return resp.make() \ No newline at end of file diff --git a/titles/sao/handlers/base.py b/titles/sao/handlers/base.py index fcae572..c634caf 100644 --- a/titles/sao/handlers/base.py +++ b/titles/sao/handlers/base.py @@ -2460,5 +2460,254 @@ class SaoGetDefragMatchLeagueScoreRankingListResponse(SaoBaseResponse): have_league_score=self.have_league_score, )) + self.length = len(resp_data) + return super().make() + resp_data + +class SaoBnidSerialCodeCheckRequest(SaoBaseRequest): + def __init__(self, data: bytes) -> None: + super().__init__(data) + +class SaoBnidSerialCodeCheckResponse(SaoBaseResponse): + def __init__(self, cmd) -> None: + super().__init__(cmd) + + self.result = 1 + self.bnid_item_id = "130050" + self.use_status = 0 + + def make(self) -> bytes: + # create a resp struct + resp_struct = Struct( + "result" / Int8ul, # result is either 0 or 1 + "bnid_item_id_size" / Int32ub, # big endian + "bnid_item_id" / Int16ul[len(self.bnid_item_id)], + "use_status" / Int8ul, # result is either 0 or 1 + ) + + resp_data = resp_struct.build(dict( + result=self.result, + bnid_item_id_size=len(self.bnid_item_id) * 2, + bnid_item_id=[ord(x) for x in self.bnid_item_id], + use_status=self.use_status, + )) + + self.length = len(resp_data) + return super().make() + resp_data + +class SaoScanQrQuestProfileCardRequest(SaoBaseRequest): + def __init__(self, data: bytes) -> None: + super().__init__(data) + +class SaoScanQrQuestProfileCardResponse(SaoBaseResponse): + def __init__(self, cmd) -> None: + super().__init__(cmd) + self.result = 1 + + # read_profile_card_data + self.profile_card_code = "1234123412341234123" # ID of the QR code + self.nick_name = "PLAYER" + self.rank_num = 1 #short + self.setting_title_id = 20005 #int + self.skill_id = 0 #short + self.hero_log_hero_log_id = 118000230 #int + self.hero_log_log_level = 1 #short + self.hero_log_awakening_stage = 1 #short + + self.hero_log_property1_property_id = 0 #int + self.hero_log_property1_value1 = 0 #int + self.hero_log_property1_value2 = 0 #int + self.hero_log_property2_property_id = 0 #int + self.hero_log_property2_value1 = 0 #int + self.hero_log_property2_value2 = 0 #int + self.hero_log_property3_property_id = 0 #int + self.hero_log_property3_value1 = 0 #int + self.hero_log_property3_value2 = 0 #int + self.hero_log_property4_property_id = 0 #int + self.hero_log_property4_value1 = 0 #int + self.hero_log_property4_value2 = 0 #int + + self.main_weapon_equipment_id = 0 #int + self.main_weapon_enhancement_value = 0 #short + self.main_weapon_awakening_stage = 0 #short + + self.main_weapon_property1_property_id = 0 #int + self.main_weapon_property1_value1 = 0 #int + self.main_weapon_property1_value2 = 0 #int + self.main_weapon_property2_property_id = 0 #int + self.main_weapon_property2_value1 = 0 #int + self.main_weapon_property2_value2 = 0 #int + self.main_weapon_property3_property_id = 0 #int + self.main_weapon_property3_value1 = 0 #int + self.main_weapon_property3_value2 = 0 #int + self.main_weapon_property4_property_id = 0 #int + self.main_weapon_property4_value1 = 0 #int + self.main_weapon_property4_value2 = 0 #int + + self.sub_equipment_equipment_id = 0 #int + self.sub_equipment_enhancement_value = 0 #short + self.sub_equipment_awakening_stage = 0 #short + + self.sub_equipment_property1_property_id = 0 #int + self.sub_equipment_property1_value1 = 0 #int + self.sub_equipment_property1_value2 = 0 #int + self.sub_equipment_property2_property_id = 0 #int + self.sub_equipment_property2_value1 = 0 #int + self.sub_equipment_property2_value2 = 0 #int + self.sub_equipment_property3_property_id = 0 #int + self.sub_equipment_property3_value1 = 0 #int + self.sub_equipment_property3_value2 = 0 #int + self.sub_equipment_property4_property_id = 0 #int + self.sub_equipment_property4_value1 = 0 #int + self.sub_equipment_property4_value2 = 0 #int + + self.holographic_flag = 1 #byte + + def make(self) -> bytes: + #new stuff + + read_profile_card_data_struct = Struct( + "profile_card_code_size" / Int32ub, # big endian + "profile_card_code" / Int16ul[len(self.profile_card_code)], + "nick_name_size" / Int32ub, # big endian + "nick_name" / Int16ul[len(self.nick_name)], + "rank_num" / Int16ub, #short + "setting_title_id" / Int32ub, #int + "skill_id" / Int16ub, #short + "hero_log_hero_log_id" / Int32ub, #int + "hero_log_log_level" / Int16ub, #short + "hero_log_awakening_stage" / Int16ub, #short + + "hero_log_property1_property_id" / Int32ub, #int + "hero_log_property1_value1" / Int32ub, #int + "hero_log_property1_value2" / Int32ub, #int + "hero_log_property2_property_id" / Int32ub, #int + "hero_log_property2_value1" / Int32ub, #int + "hero_log_property2_value2" / Int32ub, #int + "hero_log_property3_property_id" / Int32ub, #int + "hero_log_property3_value1" / Int32ub, #int + "hero_log_property3_value2" / Int32ub, #int + "hero_log_property4_property_id" / Int32ub, #int + "hero_log_property4_value1" / Int32ub, #int + "hero_log_property4_value2" / Int32ub, #int + + "main_weapon_equipment_id" / Int32ub, #int + "main_weapon_enhancement_value" / Int16ub, #short + "main_weapon_awakening_stage" / Int16ub, #short + + "main_weapon_property1_property_id" / Int32ub, #int + "main_weapon_property1_value1" / Int32ub, #int + "main_weapon_property1_value2" / Int32ub, #int + "main_weapon_property2_property_id" / Int32ub, #int + "main_weapon_property2_value1" / Int32ub, #int + "main_weapon_property2_value2" / Int32ub, #int + "main_weapon_property3_property_id" / Int32ub, #int + "main_weapon_property3_value1" / Int32ub, #int + "main_weapon_property3_value2" / Int32ub, #int + "main_weapon_property4_property_id" / Int32ub, #int + "main_weapon_property4_value1" / Int32ub, #int + "main_weapon_property4_value2" / Int32ub, #int + + "sub_equipment_equipment_id" / Int32ub, #int + "sub_equipment_enhancement_value" / Int16ub, #short + "sub_equipment_awakening_stage" / Int16ub, #short + + "sub_equipment_property1_property_id" / Int32ub, #int + "sub_equipment_property1_value1" / Int32ub, #int + "sub_equipment_property1_value2" / Int32ub, #int + "sub_equipment_property2_property_id" / Int32ub, #int + "sub_equipment_property2_value1" / Int32ub, #int + "sub_equipment_property2_value2" / Int32ub, #int + "sub_equipment_property3_property_id" / Int32ub, #int + "sub_equipment_property3_value1" / Int32ub, #int + "sub_equipment_property3_value2" / Int32ub, #int + "sub_equipment_property4_property_id" / Int32ub, #int + "sub_equipment_property4_value1" / Int32ub, #int + "sub_equipment_property4_value2" / Int32ub, #int + + "holographic_flag" / Int8ul, # result is either 0 or 1 + + ) + + # create a resp struct + resp_struct = Struct( + "result" / Int8ul, # result is either 0 or 1 + "read_profile_card_data_size" / Rebuild(Int32ub, len_(this.read_profile_card_data)), # big endian + "read_profile_card_data" / Array(this.read_profile_card_data_size, read_profile_card_data_struct), + ) + + resp_data = resp_struct.parse(resp_struct.build(dict( + result=self.result, + read_profile_card_data_size=0, + read_profile_card_data=[], + ))) + + hero_data = dict( + profile_card_code_size=len(self.profile_card_code) * 2, + profile_card_code=[ord(x) for x in self.profile_card_code], + nick_name_size=len(self.nick_name) * 2, + nick_name=[ord(x) for x in self.nick_name], + + rank_num=self.rank_num, + setting_title_id=self.setting_title_id, + skill_id=self.skill_id, + hero_log_hero_log_id=self.hero_log_hero_log_id, + hero_log_log_level=self.hero_log_log_level, + hero_log_awakening_stage=self.hero_log_awakening_stage, + + hero_log_property1_property_id=self.hero_log_property1_property_id, + hero_log_property1_value1=self.hero_log_property1_value1, + hero_log_property1_value2=self.hero_log_property1_value2, + hero_log_property2_property_id=self.hero_log_property2_property_id, + hero_log_property2_value1=self.hero_log_property2_value1, + hero_log_property2_value2=self.hero_log_property2_value2, + hero_log_property3_property_id=self.hero_log_property3_property_id, + hero_log_property3_value1=self.hero_log_property3_value1, + hero_log_property3_value2=self.hero_log_property3_value2, + hero_log_property4_property_id=self.hero_log_property4_property_id, + hero_log_property4_value1=self.hero_log_property4_value1, + hero_log_property4_value2=self.hero_log_property4_value2, + + main_weapon_equipment_id=self.main_weapon_equipment_id, + main_weapon_enhancement_value=self.main_weapon_enhancement_value, + main_weapon_awakening_stage=self.main_weapon_awakening_stage, + + main_weapon_property1_property_id=self.main_weapon_property1_property_id, + main_weapon_property1_value1=self.main_weapon_property1_value1, + main_weapon_property1_value2=self.main_weapon_property1_value2, + main_weapon_property2_property_id=self.main_weapon_property2_property_id, + main_weapon_property2_value1=self.main_weapon_property2_value1, + main_weapon_property2_value2=self.main_weapon_property2_value2, + main_weapon_property3_property_id=self.main_weapon_property3_property_id, + main_weapon_property3_value1=self.main_weapon_property3_value1, + main_weapon_property3_value2=self.main_weapon_property3_value2, + main_weapon_property4_property_id=self.main_weapon_property4_property_id, + main_weapon_property4_value1=self.main_weapon_property4_value1, + main_weapon_property4_value2=self.main_weapon_property4_value2, + + sub_equipment_equipment_id=self.sub_equipment_equipment_id, + sub_equipment_enhancement_value=self.sub_equipment_enhancement_value, + sub_equipment_awakening_stage=self.sub_equipment_awakening_stage, + + sub_equipment_property1_property_id=self.sub_equipment_property1_property_id, + sub_equipment_property1_value1=self.sub_equipment_property1_value1, + sub_equipment_property1_value2=self.sub_equipment_property1_value2, + sub_equipment_property2_property_id=self.sub_equipment_property2_property_id, + sub_equipment_property2_value1=self.sub_equipment_property2_value1, + sub_equipment_property2_value2=self.sub_equipment_property2_value2, + sub_equipment_property3_property_id=self.sub_equipment_property3_property_id, + sub_equipment_property3_value1=self.sub_equipment_property3_value1, + sub_equipment_property3_value2=self.sub_equipment_property3_value2, + sub_equipment_property4_property_id=self.sub_equipment_property4_property_id, + sub_equipment_property4_value1=self.sub_equipment_property4_value1, + sub_equipment_property4_value2=self.sub_equipment_property4_value2, + + holographic_flag=self.holographic_flag, + ) + + resp_data.read_profile_card_data.append(hero_data) + + # finally, rebuild the resp_data + resp_data = resp_struct.build(resp_data) + self.length = len(resp_data) return super().make() + resp_data \ No newline at end of file