def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: root = Node.void('player22') # Result root.add_child(Node.s8('result', 0)) # Set up account account = Node.void('account') root.add_child(account) account.add_child(Node.string('name', profile.get_str('name', 'なし'))) account.add_child( Node.string('g_pm_id', ID.format_extid(profile.get_int('extid')))) account.add_child(Node.s8('tutorial', profile.get_int('tutorial', -1))) account.add_child( Node.s16('read_news', profile.get_int('read_news', 0))) account.add_child(Node.s8('staff', 0)) account.add_child(Node.s8('is_conv', 0)) account.add_child(Node.s16('item_type', 0)) account.add_child(Node.s16('item_id', 0)) account.add_child( Node.s16_array('license_data', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1])) # Statistics section and scores section statistics = self.get_play_statistics(userid) last_play_date = statistics.get_int_array('last_play_date', 3) today_play_date = Time.todays_date() if (last_play_date[0] == today_play_date[0] and last_play_date[1] == today_play_date[1] and last_play_date[2] == today_play_date[2]): today_count = statistics.get_int('today_plays', 0) else: today_count = 0 account.add_child(Node.u8('active_fr_num', 0)) # TODO: Hook up rivals code? account.add_child( Node.s16('total_play_cnt', statistics.get_int('total_plays', 0))) account.add_child(Node.s16('today_play_cnt', today_count)) account.add_child( Node.s16('consecutive_days', statistics.get_int('consecutive_days', 0))) account.add_child( Node.s16('total_days', statistics.get_int('total_days', 0))) account.add_child(Node.s16('interval_day', 0)) # Add scores section last_played = [ x[0] for x in self.data.local.music.get_last_played( self.game, self.version, userid, 5) ] most_played = [ x[0] for x in self.data.local.music.get_most_played( self.game, self.version, userid, 10) ] while len(last_played) < 5: last_played.append(-1) while len(most_played) < 10: most_played.append(-1) account.add_child(Node.s16_array('my_best', most_played)) account.add_child(Node.s16_array('latest_music', last_played)) scores = self.data.remote.music.get_scores(self.game, self.version, userid) for score in scores: # Skip any scores for chart types we don't support if score.chart not in [ self.CHART_TYPE_EASY, self.CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER, self.CHART_TYPE_EX, ]: continue points = score.points medal = score.data.get_int('medal') music = Node.void('music') root.add_child(music) music.add_child(Node.s16('music_num', score.id)) music.add_child( Node.u8( 'sheet_num', { self.CHART_TYPE_EASY: self.GAME_CHART_TYPE_EASY, self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER, self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX, }[score.chart])) music.add_child(Node.s16('cnt', score.plays)) music.add_child(Node.s32('score', points)) music.add_child( Node.u8( 'clear_type', { self.PLAY_MEDAL_CIRCLE_FAILED: self.GAME_PLAY_MEDAL_CIRCLE_FAILED, self.PLAY_MEDAL_DIAMOND_FAILED: self.GAME_PLAY_MEDAL_DIAMOND_FAILED, self.PLAY_MEDAL_STAR_FAILED: self.GAME_PLAY_MEDAL_STAR_FAILED, self.PLAY_MEDAL_EASY_CLEAR: self.GAME_PLAY_MEDAL_EASY_CLEAR, self.PLAY_MEDAL_CIRCLE_CLEARED: self.GAME_PLAY_MEDAL_CIRCLE_CLEARED, self.PLAY_MEDAL_DIAMOND_CLEARED: self.GAME_PLAY_MEDAL_DIAMOND_CLEARED, self.PLAY_MEDAL_STAR_CLEARED: self.GAME_PLAY_MEDAL_STAR_CLEARED, self.PLAY_MEDAL_CIRCLE_FULL_COMBO: self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO, self.PLAY_MEDAL_DIAMOND_FULL_COMBO: self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO, self.PLAY_MEDAL_STAR_FULL_COMBO: self.GAME_PLAY_MEDAL_STAR_FULL_COMBO, self.PLAY_MEDAL_PERFECT: self.GAME_PLAY_MEDAL_PERFECT, }[medal])) music.add_child(Node.s32('old_score', 0)) music.add_child(Node.u8('old_clear_type', 0)) # Net VS section netvs = Node.void('netvs') root.add_child(netvs) netvs.add_child(Node.s32('rank_point', 0)) netvs.add_child(Node.s16_array('record', [0, 0, 0, 0, 0, 0])) netvs.add_child(Node.u8('rank', 0)) netvs.add_child(Node.s8('vs_rank_old', 0)) netvs.add_child(Node.s8_array('ojama_condition', [0] * 74)) netvs.add_child(Node.s8_array('set_ojama', [0, 0, 0])) netvs.add_child(Node.s8_array('set_recommend', [0, 0, 0])) netvs.add_child(Node.u32('netvs_play_cnt', 0)) for dialog in [0, 1, 2, 3, 4, 5]: # TODO: Configure this, maybe? netvs.add_child(Node.string('dialog', 'dialog#{}'.format(dialog))) # Set up config config = Node.void('config') root.add_child(config) config.add_child(Node.u8('mode', profile.get_int('mode', 0))) config.add_child(Node.s16('chara', profile.get_int('chara', -1))) config.add_child(Node.s16('music', profile.get_int('music', -1))) config.add_child(Node.u8('sheet', profile.get_int('sheet', 0))) config.add_child(Node.s8('category', profile.get_int('category', 1))) config.add_child( Node.s8('sub_category', profile.get_int('sub_category', -1))) config.add_child( Node.s8('chara_category', profile.get_int('chara_category', -1))) config.add_child(Node.s16('story_id', profile.get_int('story_id', -1))) config.add_child( Node.s16('course_id', profile.get_int('course_id', -1))) config.add_child( Node.s8('course_folder', profile.get_int('course_folder', -1))) config.add_child( Node.s8('story_folder', profile.get_int('story_folder', -1))) config.add_child( Node.s8('ms_banner_disp', profile.get_int('ms_banner_disp'))) config.add_child( Node.s8('ms_down_info', profile.get_int('ms_down_info'))) config.add_child( Node.s8('ms_side_info', profile.get_int('ms_side_info'))) config.add_child( Node.s8('ms_raise_type', profile.get_int('ms_raise_type'))) config.add_child(Node.s8('ms_rnd_type', profile.get_int('ms_rnd_type'))) # Set up option option_dict = profile.get_dict('option') option = Node.void('option') root.add_child(option) option.add_child( Node.s16('hispeed', option_dict.get_int('hispeed', 10))) option.add_child(Node.u8('popkun', option_dict.get_int('popkun', 0))) option.add_child( Node.bool('hidden', option_dict.get_bool('hidden', False))) option.add_child( Node.s16('hidden_rate', option_dict.get_int('hidden_rate', -1))) option.add_child( Node.bool('sudden', option_dict.get_bool('sudden', False))) option.add_child( Node.s16('sudden_rate', option_dict.get_int('sudden_rate', -1))) option.add_child(Node.s8('randmir', option_dict.get_int('randmir', 0))) option.add_child( Node.s8('gauge_type', option_dict.get_int('gauge_type', 0))) option.add_child(Node.u8('ojama_0', option_dict.get_int('ojama_0', 0))) option.add_child(Node.u8('ojama_1', option_dict.get_int('ojama_1', 0))) option.add_child( Node.bool('forever_0', option_dict.get_bool('forever_0', False))) option.add_child( Node.bool('forever_1', option_dict.get_bool('forever_1', False))) option.add_child( Node.bool('full_setting', option_dict.get_bool('full_setting', False))) # Set up info info = Node.void('info') root.add_child(info) info.add_child(Node.u16('ep', profile.get_int('ep', 0))) info.add_child(Node.u16('ap', profile.get_int('ap', 0))) # Set up custom_cate custom_cate = Node.void('custom_cate') root.add_child(custom_cate) custom_cate.add_child(Node.s8('valid', 0)) custom_cate.add_child(Node.s8('lv_min', -1)) custom_cate.add_child(Node.s8('lv_max', -1)) custom_cate.add_child(Node.s8('medal_min', -1)) custom_cate.add_child(Node.s8('medal_max', -1)) custom_cate.add_child(Node.s8('friend_no', -1)) custom_cate.add_child(Node.s8('score_flg', -1)) # Set up customize customize_dict = profile.get_dict('customize') customize = Node.void('customize') root.add_child(customize) customize.add_child( Node.u16('effect', customize_dict.get_int('effect'))) customize.add_child( Node.u16('hukidashi', customize_dict.get_int('hukidashi'))) customize.add_child(Node.u16('font', customize_dict.get_int('font'))) customize.add_child( Node.u16('comment_1', customize_dict.get_int('comment_1'))) customize.add_child( Node.u16('comment_2', customize_dict.get_int('comment_2'))) # Set up achievements achievements = self.data.local.user.get_achievements( self.game, self.version, userid) for achievement in achievements: if achievement.type == 'item': itemtype = achievement.data.get_int('type') param = achievement.data.get_int('param') item = Node.void('item') root.add_child(item) item.add_child(Node.u8('type', itemtype)) item.add_child(Node.u16('id', achievement.id)) item.add_child(Node.u16('param', param)) item.add_child(Node.bool('is_new', False)) elif achievement.type == 'achievement': count = achievement.data.get_int('count') ach_node = Node.void('achievement') root.add_child(ach_node) ach_node.add_child(Node.u8('type', achievement.id)) ach_node.add_child(Node.u32('count', count)) elif achievement.type == 'chara': friendship = achievement.data.get_int('friendship') chara = Node.void('chara_param') root.add_child(chara) chara.add_child(Node.u16('chara_id', achievement.id)) chara.add_child(Node.u16('friendship', friendship)) elif achievement.type == 'story': chapter = achievement.data.get_int('chapter') gauge = achievement.data.get_int('gauge') cleared = achievement.data.get_bool('cleared') clear_chapter = achievement.data.get_int('clear_chapter') story = Node.void('story') root.add_child(story) story.add_child(Node.u32('story_id', achievement.id)) story.add_child(Node.u32('chapter_id', chapter)) story.add_child(Node.u16('gauge_point', gauge)) story.add_child(Node.bool('is_cleared', cleared)) story.add_child(Node.u32('clear_chapter', clear_chapter)) return root
def handle_game_ranking_request(self, request: Node) -> Node: # Ranking request, unknown what its for return Node.void('game')
def handle_game_lock_request(self, request: Node) -> Node: game = Node.void('game') game.set_attribute('now_login', '0') return game
def handle_logger_report_request(self, request: Node) -> Node: # Handle this by returning nothing, game doesn't care root = Node.void('logger') return root
def handle_game_shop_request(self, request: Node) -> Node: self.update_machine_name(request.attribute('name')) game = Node.void('game') game.set_attribute('stop', '0') return game
def format_conversion(self, userid: UserID, profile: ValidatedDict) -> Node: root = Node.void('player23') root.add_child(Node.string('name', profile.get_str('name', 'なし'))) root.add_child(Node.s16('chara', profile.get_int('chara', -1))) root.add_child(Node.s8('result', 1)) scores = self.data.remote.music.get_scores(self.game, self.version, userid) for score in scores: # Skip any scores for chart types we don't support if score.chart not in [ self.CHART_TYPE_EASY, self.CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER, self.CHART_TYPE_EX, ]: continue points = score.points medal = score.data.get_int('medal') music = Node.void('music') root.add_child(music) music.add_child(Node.s16('music_num', score.id)) music.add_child( Node.u8( 'sheet_num', { self.CHART_TYPE_EASY: self.GAME_CHART_TYPE_EASY, self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER, self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX, }[score.chart])) music.add_child(Node.s32('score', points)) music.add_child( Node.u8( 'clear_type', { self.PLAY_MEDAL_CIRCLE_FAILED: self.GAME_PLAY_MEDAL_CIRCLE_FAILED, self.PLAY_MEDAL_DIAMOND_FAILED: self.GAME_PLAY_MEDAL_DIAMOND_FAILED, self.PLAY_MEDAL_STAR_FAILED: self.GAME_PLAY_MEDAL_STAR_FAILED, self.PLAY_MEDAL_EASY_CLEAR: self.GAME_PLAY_MEDAL_EASY_CLEAR, self.PLAY_MEDAL_CIRCLE_CLEARED: self.GAME_PLAY_MEDAL_CIRCLE_CLEARED, self.PLAY_MEDAL_DIAMOND_CLEARED: self.GAME_PLAY_MEDAL_DIAMOND_CLEARED, self.PLAY_MEDAL_STAR_CLEARED: self.GAME_PLAY_MEDAL_STAR_CLEARED, self.PLAY_MEDAL_CIRCLE_FULL_COMBO: self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO, self.PLAY_MEDAL_DIAMOND_FULL_COMBO: self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO, self.PLAY_MEDAL_STAR_FULL_COMBO: self.GAME_PLAY_MEDAL_STAR_FULL_COMBO, self.PLAY_MEDAL_PERFECT: self.GAME_PLAY_MEDAL_PERFECT, }[medal])) music.add_child(Node.s16('cnt', score.plays)) return root
def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: root = Node.void('player23') # Mark this as a current profile root.add_child(Node.s8('result', 0)) # Account stuff account = Node.void('account') root.add_child(account) account.add_child( Node.string('g_pm_id', self.format_extid( profile.get_int('extid')))) # Eclale formats on its own account.add_child(Node.string('name', profile.get_str('name', 'なし'))) account.add_child(Node.s8('tutorial', profile.get_int('tutorial'))) account.add_child(Node.s16('area_id', profile.get_int('area_id'))) account.add_child(Node.s16('lumina', profile.get_int('lumina', 300))) account.add_child(Node.s16('read_news', profile.get_int('read_news'))) account.add_child( Node.bool('welcom_pack', profile.get_bool('welcom_pack'))) account.add_child( Node.s16_array('medal_set', profile.get_int_array('medal_set', 4))) account.add_child( Node.s16_array('nice', profile.get_int_array('nice', 30, [-1] * 30))) account.add_child( Node.s16_array( 'favorite_chara', profile.get_int_array('favorite_chara', 20, [-1] * 20))) account.add_child( Node.s16_array('special_area', profile.get_int_array('special_area', 8))) account.add_child( Node.s16_array( 'chocolate_charalist', profile.get_int_array('chocolate_charalist', 5, [-1] * 5))) account.add_child( Node.s16_array('teacher_setting', profile.get_int_array('teacher_setting', 10))) # Stuff we never change account.add_child(Node.s8('staff', 0)) account.add_child(Node.s16('item_type', 0)) account.add_child(Node.s16('item_id', 0)) account.add_child(Node.s8('is_conv', 0)) account.add_child(Node.bool('meteor_flg', True)) account.add_child(Node.s16_array('license_data', [-1] * 20)) # Add statistics section last_played = [ x[0] for x in self.data.local.music.get_last_played( self.game, self.version, userid, 5) ] most_played = [ x[0] for x in self.data.local.music.get_most_played( self.game, self.version, userid, 10) ] while len(last_played) < 5: last_played.append(-1) while len(most_played) < 10: most_played.append(-1) account.add_child(Node.s16_array('my_best', most_played)) account.add_child(Node.s16_array('latest_music', last_played)) # TODO: Hook up rivals for Pop'n music? account.add_child(Node.u8('active_fr_num', 0)) # player statistics statistics = self.get_play_statistics(userid) last_play_date = statistics.get_int_array('last_play_date', 3) today_play_date = Time.todays_date() if (last_play_date[0] == today_play_date[0] and last_play_date[1] == today_play_date[1] and last_play_date[2] == today_play_date[2]): today_count = statistics.get_int('today_plays', 0) else: today_count = 0 account.add_child( Node.s16('total_play_cnt', statistics.get_int('total_plays', 0))) account.add_child(Node.s16('today_play_cnt', today_count)) account.add_child( Node.s16('consecutive_days', statistics.get_int('consecutive_days', 0))) account.add_child( Node.s16('total_days', statistics.get_int('total_days', 0))) account.add_child(Node.s16('interval_day', 0)) # Set up info node info = Node.void('info') root.add_child(info) info.add_child(Node.u16('ep', profile.get_int('ep'))) # Set up last information config = Node.void('config') root.add_child(config) config.add_child(Node.u8('mode', profile.get_int('mode'))) config.add_child(Node.s16('chara', profile.get_int('chara', -1))) config.add_child(Node.s16('music', profile.get_int('music', -1))) config.add_child(Node.u8('sheet', profile.get_int('sheet'))) config.add_child(Node.s8('category', profile.get_int('category', -1))) config.add_child( Node.s8('sub_category', profile.get_int('sub_category', -1))) config.add_child( Node.s8('chara_category', profile.get_int('chara_category', -1))) config.add_child( Node.s16('course_id', profile.get_int('course_id', -1))) config.add_child( Node.s8('course_folder', profile.get_int('course_folder', -1))) config.add_child( Node.s8('ms_banner_disp', profile.get_int('ms_banner_disp'))) config.add_child( Node.s8('ms_down_info', profile.get_int('ms_down_info'))) config.add_child( Node.s8('ms_side_info', profile.get_int('ms_side_info'))) config.add_child( Node.s8('ms_raise_type', profile.get_int('ms_raise_type'))) config.add_child(Node.s8('ms_rnd_type', profile.get_int('ms_rnd_type'))) # Player options option = Node.void('option') option_dict = profile.get_dict('option') root.add_child(option) option.add_child(Node.s16('hispeed', option_dict.get_int('hispeed'))) option.add_child(Node.u8('popkun', option_dict.get_int('popkun'))) option.add_child(Node.bool('hidden', option_dict.get_bool('hidden'))) option.add_child( Node.s16('hidden_rate', option_dict.get_int('hidden_rate'))) option.add_child(Node.bool('sudden', option_dict.get_bool('sudden'))) option.add_child( Node.s16('sudden_rate', option_dict.get_int('sudden_rate'))) option.add_child(Node.s8('randmir', option_dict.get_int('randmir'))) option.add_child( Node.s8('gauge_type', option_dict.get_int('gauge_type'))) option.add_child(Node.u8('ojama_0', option_dict.get_int('ojama_0'))) option.add_child(Node.u8('ojama_1', option_dict.get_int('ojama_1'))) option.add_child( Node.bool('forever_0', option_dict.get_bool('forever_0'))) option.add_child( Node.bool('forever_1', option_dict.get_bool('forever_1'))) option.add_child( Node.bool('full_setting', option_dict.get_bool('full_setting'))) option.add_child(Node.u8('judge', option_dict.get_int('judge'))) # Unknown custom category stuff? custom_cate = Node.void('custom_cate') root.add_child(custom_cate) custom_cate.add_child(Node.s8('valid', 0)) custom_cate.add_child(Node.s8('lv_min', -1)) custom_cate.add_child(Node.s8('lv_max', -1)) custom_cate.add_child(Node.s8('medal_min', -1)) custom_cate.add_child(Node.s8('medal_max', -1)) custom_cate.add_child(Node.s8('friend_no', -1)) custom_cate.add_child(Node.s8('score_flg', -1)) # Set up achievements achievements = self.data.local.user.get_achievements( self.game, self.version, userid) for achievement in achievements: if achievement.type[:5] == 'item_': itemtype = int(achievement.type[5:]) param = achievement.data.get_int('param') is_new = achievement.data.get_bool('is_new') item = Node.void('item') root.add_child(item) # Type is the type of unlock/item. Type 0 is song unlock in Eclale. # In this case, the id is the song ID according to the game. Unclear # what the param is supposed to be, but i've seen 8 and 0. Might be # what chart is available? item.add_child(Node.u8('type', itemtype)) item.add_child(Node.u16('id', achievement.id)) item.add_child(Node.u16('param', param)) item.add_child(Node.bool('is_new', is_new)) elif achievement.type == 'chara': friendship = achievement.data.get_int('friendship') chara = Node.void('chara_param') root.add_child(chara) chara.add_child(Node.u16('chara_id', achievement.id)) chara.add_child(Node.u16('friendship', friendship)) elif achievement.type == 'medal': level = achievement.data.get_int('level') exp = achievement.data.get_int('exp') set_count = achievement.data.get_int('set_count') get_count = achievement.data.get_int('get_count') medal = Node.void('medal') root.add_child(medal) medal.add_child(Node.s16('medal_id', achievement.id)) medal.add_child(Node.s16('level', level)) medal.add_child(Node.s32('exp', exp)) medal.add_child(Node.s32('set_count', set_count)) medal.add_child(Node.s32('get_count', get_count)) # Unknown customizations customize = Node.void('customize') root.add_child(customize) customize.add_child( Node.u16('effect_left', profile.get_int('effect_left'))) customize.add_child( Node.u16('effect_center', profile.get_int('effect_center'))) customize.add_child( Node.u16('effect_right', profile.get_int('effect_right'))) customize.add_child(Node.u16('hukidashi', profile.get_int('hukidashi'))) customize.add_child(Node.u16('comment_1', profile.get_int('comment_1'))) customize.add_child(Node.u16('comment_2', profile.get_int('comment_2'))) # NetVS section netvs = Node.void('netvs') root.add_child(netvs) netvs.add_child(Node.s16_array('record', [0] * 6)) netvs.add_child(Node.string('dialog', '')) netvs.add_child(Node.string('dialog', '')) netvs.add_child(Node.string('dialog', '')) netvs.add_child(Node.string('dialog', '')) netvs.add_child(Node.string('dialog', '')) netvs.add_child(Node.string('dialog', '')) netvs.add_child(Node.s8_array('ojama_condition', [0] * 74)) netvs.add_child(Node.s8_array('set_ojama', [0] * 3)) netvs.add_child(Node.s8_array('set_recommend', [0] * 3)) netvs.add_child(Node.u32('netvs_play_cnt', 0)) # Event stuff event = Node.void('event') root.add_child(event) event.add_child( Node.s16('enemy_medal', profile.get_int('event_enemy_medal'))) event.add_child(Node.s16('hp', profile.get_int('event_hp'))) # Stamp stuff stamp = Node.void('stamp') root.add_child(stamp) stamp.add_child(Node.s16('stamp_id', profile.get_int('stamp_id'))) stamp.add_child(Node.s16('cnt', profile.get_int('stamp_cnt'))) return root
def verify_iidx26music_arenacpu(self) -> None: call = self.call_node() IIDX26music = Node.void('IIDX26music') call.add_child(IIDX26music) IIDX26music.set_attribute('method', 'arenaCPU') music_list = Node.void('music_list') IIDX26music.add_child(music_list) music_list.add_child(Node.s32('index', 0)) music_list.add_child(Node.s32('music_id', 26072)) music_list.add_child(Node.s32('note_style', 0)) music_list.add_child(Node.s32('note_grade', 2)) music_list.add_child(Node.s32('total_notes', 1857)) music_list_1 = Node.void('music_list') IIDX26music.add_child(music_list_1) music_list_1.add_child(Node.s32('index', 1)) music_list_1.add_child(Node.s32('music_id', 25020)) music_list_1.add_child(Node.s32('note_style', 0)) music_list_1.add_child(Node.s32('note_grade', 0)) music_list_1.add_child(Node.s32('total_notes', 483)) music_list_2 = Node.void('music_list') IIDX26music.add_child(music_list_2) music_list_2.add_child(Node.s32('index', 2)) music_list_2.add_child(Node.s32('music_id', 2000)) music_list_2.add_child(Node.s32('note_style', 0)) music_list_2.add_child(Node.s32('note_grade', 0)) music_list_2.add_child(Node.s32('total_notes', 360)) music_list_3 = Node.void('music_list') IIDX26music.add_child(music_list_3) music_list_3.add_child(Node.s32('index', 3)) music_list_3.add_child(Node.s32('music_id', 19020)) music_list_3.add_child(Node.s32('note_style', 0)) music_list_3.add_child(Node.s32('note_grade', 0)) music_list_3.add_child(Node.s32('total_notes', 404)) cpu_list = Node.void('cpu_list') IIDX26music.add_child(cpu_list) cpu_list.add_child(Node.s32('index', 0)) cpu_list.add_child(Node.s32('play_style', 0)) cpu_list.add_child(Node.s32('arena_class', 0)) cpu_list.add_child(Node.s32('grade_id', -1)) cpu_list_1 = Node.void('cpu_list') IIDX26music.add_child(cpu_list_1) cpu_list_1.add_child(Node.s32('index', 1)) cpu_list_1.add_child(Node.s32('play_style', 0)) cpu_list_1.add_child(Node.s32('arena_class', 0)) cpu_list_1.add_child(Node.s32('grade_id', 6)) cpu_list_2 = Node.void('cpu_list') IIDX26music.add_child(cpu_list_2) cpu_list_2.add_child(Node.s32('index', 2)) cpu_list_2.add_child(Node.s32('play_style', 0)) cpu_list_2.add_child(Node.s32('arena_class', 0)) cpu_list_2.add_child(Node.s32('grade_id', 6)) cpu_list_3 = Node.void('cpu_list') IIDX26music.add_child(cpu_list_3) cpu_list_3.add_child(Node.s32('index', 3)) cpu_list_3.add_child(Node.s32('play_style', 0)) cpu_list_3.add_child(Node.s32('arena_class', 0)) cpu_list_3.add_child(Node.s32('grade_id', 6)) # Swap with server resp = self.exchange('', call) self.assert_path( resp, 'response/IIDX26music/cpu_score_list/score_list/score') self.assert_path( resp, 'response/IIDX26music/cpu_score_list/score_list/enable_score') self.assert_path( resp, 'response/IIDX26music/cpu_score_list/score_list/ghost') self.assert_path( resp, 'response/IIDX26music/cpu_score_list/score_list/enable_ghost')
def verify_usergamedata_send(self, ref_id: str, msg_type: str) -> None: call = self.call_node() # Set up profile write profiledata = [ b'ffffffff', b'IBBDAT00', b'1', b'0', b'0', b'0', b'0', b'0', b'e474c1b', b'0', b'0', b'ff', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'0.000000', b'0.000000', b'0.000000', b'0.000000', b'0.000000', b'0.000000', b'0.000000', b'0.000000', b'', b'', b'', b'\x96\xa2\x90\xdd\x92\xe8', b'\x8d\x81\x8d`', b'', b'', b'', ] if msg_type == 'new': # New profile gets blank name, because we save over it at the end of the round. profiledata[27] = b'' elif msg_type == 'existing': # Exiting profile gets our hardcoded name saved. profiledata[27] = self.NAME.encode('shift-jis') # Construct node playerdata = Node.void('playerdata') call.add_child(playerdata) playerdata.set_attribute('method', 'usergamedata_send') playerdata.add_child(Node.u32('retrycnt', 0)) data = Node.void('data') playerdata.add_child(data) data.add_child(Node.string('eaid', ref_id)) data.add_child(Node.string('gamekind', 'IBB')) data.add_child(Node.u32('datanum', 1)) record = Node.void('record') data.add_child(record) d = Node.string('d', base64.b64encode(b','.join(profiledata)).decode('ascii')) record.add_child(d) d.add_child(Node.string('bin1', '')) # Swap with server resp = self.exchange('', call) self.assert_path(resp, "response/playerdata/result")
def verify_iidx26music_getrank( self, extid: int) -> Dict[int, Dict[int, Dict[str, int]]]: scores: Dict[int, Dict[int, Dict[str, int]]] = {} for cltype in [0, 1]: # singles, doubles call = self.call_node() # Construct node IIDX26music = Node.void('IIDX26music') call.add_child(IIDX26music) IIDX26music.set_attribute('method', 'getrank') IIDX26music.set_attribute('iidxid', str(extid)) IIDX26music.set_attribute('cltype', str(cltype)) # Swap with server resp = self.exchange('', call) self.assert_path(resp, "response/IIDX26music/style") if int(resp.child('IIDX26music/style').attribute( 'type')) != cltype: raise Exception( 'Returned wrong clear type for IIDX26music.getrank!') for child in resp.child('IIDX26music').children: if child.name == 'm': if child.value[0] != -1: raise Exception( 'Got non-self score back when requesting only our scores!' ) music_id = child.value[1] normal_clear_status = child.value[2] hyper_clear_status = child.value[3] another_clear_status = child.value[4] normal_ex_score = child.value[5] hyper_ex_score = child.value[6] another_ex_score = child.value[7] normal_miss_count = child.value[8] hyper_miss_count = child.value[9] another_miss_count = child.value[10] if cltype == 0: normal = 0 hyper = 1 another = 2 else: normal = 3 hyper = 4 another = 5 if music_id not in scores: scores[music_id] = {} scores[music_id][normal] = { 'clear_status': normal_clear_status, 'ex_score': normal_ex_score, 'miss_count': normal_miss_count, } scores[music_id][hyper] = { 'clear_status': hyper_clear_status, 'ex_score': hyper_ex_score, 'miss_count': hyper_miss_count, } scores[music_id][another] = { 'clear_status': another_clear_status, 'ex_score': another_ex_score, 'miss_count': another_miss_count, } elif child.name == 'b': music_id = child.value[0] clear_status = child.value[1] scores[music_id][6] = { 'clear_status': clear_status, 'ex_score': -1, 'miss_count': -1, } return scores
def verify_iidx26pc_save( self, extid: int, card: str, lid: str, expert_point: Optional[Dict[str, int]] = None) -> None: call = self.call_node() # Construct node IIDX26pc = Node.void('IIDX26pc') call.add_child(IIDX26pc) IIDX26pc.set_attribute('s_disp_judge', '1') IIDX26pc.set_attribute('mode', '6') IIDX26pc.set_attribute('pmode', '0') IIDX26pc.set_attribute('method', 'save') IIDX26pc.set_attribute('s_sorttype', '0') IIDX26pc.set_attribute('s_exscore', '0') IIDX26pc.set_attribute('d_notes', '0.000000') IIDX26pc.set_attribute('gpos', '0') IIDX26pc.set_attribute('s_gno', '8') IIDX26pc.set_attribute('s_hispeed', '5.771802') IIDX26pc.set_attribute('s_judge', '0') IIDX26pc.set_attribute('d_timing', '0') IIDX26pc.set_attribute('rtype', '0') IIDX26pc.set_attribute('d_graph_score', '0') IIDX26pc.set_attribute('d_lift', '60') IIDX26pc.set_attribute('s_pace', '0') IIDX26pc.set_attribute('d_exscore', '0') IIDX26pc.set_attribute('d_sdtype', '0') IIDX26pc.set_attribute('s_opstyle', '1') IIDX26pc.set_attribute('s_achi', '449') IIDX26pc.set_attribute('s_graph_score', '0') IIDX26pc.set_attribute('d_gno', '0') IIDX26pc.set_attribute('s_lift', '60') IIDX26pc.set_attribute('s_notes', '31.484070') IIDX26pc.set_attribute('d_tune', '0') IIDX26pc.set_attribute('d_sdlen', '0') IIDX26pc.set_attribute('d_achi', '4') IIDX26pc.set_attribute('d_opstyle', '0') IIDX26pc.set_attribute('sp_opt', '8208') IIDX26pc.set_attribute('iidxid', str(extid)) IIDX26pc.set_attribute('lid', lid) IIDX26pc.set_attribute('s_judgeAdj', '0') IIDX26pc.set_attribute('s_tune', '3') IIDX26pc.set_attribute('s_sdtype', '1') IIDX26pc.set_attribute('s_gtype', '2') IIDX26pc.set_attribute('d_judge', '0') IIDX26pc.set_attribute('cid', card) IIDX26pc.set_attribute('cltype', '0') IIDX26pc.set_attribute('ctype', '1') IIDX26pc.set_attribute('bookkeep', '0') IIDX26pc.set_attribute('d_hispeed', '0.000000') IIDX26pc.set_attribute('d_pace', '0') IIDX26pc.set_attribute('d_judgeAdj', '0') IIDX26pc.set_attribute('s_timing', '1') IIDX26pc.set_attribute('d_disp_judge', '0') IIDX26pc.set_attribute('s_sdlen', '121') IIDX26pc.set_attribute('dp_opt2', '0') IIDX26pc.set_attribute('d_gtype', '0') IIDX26pc.set_attribute('d_sorttype', '0') IIDX26pc.set_attribute('dp_opt', '0') IIDX26pc.set_attribute('s_auto_scrach', '0') IIDX26pc.set_attribute('d_auto_scrach', '0') IIDX26pc.set_attribute('s_gauge_disp', '0') IIDX26pc.set_attribute('d_gauge_disp', '0') IIDX26pc.set_attribute('s_lane_brignt', '0') IIDX26pc.set_attribute('d_lane_brignt', '0') IIDX26pc.set_attribute('s_camera_layout', '0') IIDX26pc.set_attribute('d_camera_layout', '0') IIDX26pc.set_attribute('s_ghost_score', '0') IIDX26pc.set_attribute('d_ghost_score', '0') IIDX26pc.set_attribute('s_tsujigiri_disp', '0') IIDX26pc.set_attribute('d_tsujigiri_disp', '0') deller = Node.void('deller') IIDX26pc.add_child(deller) deller.set_attribute('deller', '150') if expert_point is not None: epnode = Node.void('expert_point') epnode.set_attribute('h_point', str(expert_point['h_point'])) epnode.set_attribute('course_id', str(expert_point['course_id'])) epnode.set_attribute('n_point', str(expert_point['n_point'])) epnode.set_attribute('a_point', str(expert_point['a_point'])) IIDX26pc.add_child(epnode) # Swap with server resp = self.exchange('', call) self.assert_path(resp, "response/IIDX26pc")
def verify_iidx26pc_get(self, ref_id: str, card_id: str, lid: str) -> Dict[str, Any]: call = self.call_node() # Construct node IIDX26pc = Node.void('IIDX26pc') call.add_child(IIDX26pc) IIDX26pc.set_attribute('rid', ref_id) IIDX26pc.set_attribute('did', ref_id) IIDX26pc.set_attribute('pid', '51') IIDX26pc.set_attribute('lid', lid) IIDX26pc.set_attribute('cid', card_id) IIDX26pc.set_attribute('method', 'get') IIDX26pc.set_attribute('ctype', '1') # Swap with server resp = self.exchange('', call) # Verify that the response is correct self.assert_path(resp, "response/IIDX26pc/pcdata/@name") self.assert_path(resp, "response/IIDX26pc/pcdata/@pid") self.assert_path(resp, "response/IIDX26pc/pcdata/@id") self.assert_path(resp, "response/IIDX26pc/pcdata/@idstr") self.assert_path(resp, "response/IIDX26pc/deller") self.assert_path(resp, "response/IIDX26pc/secret/flg1") self.assert_path(resp, "response/IIDX26pc/secret/flg2") self.assert_path(resp, "response/IIDX26pc/secret/flg3") self.assert_path(resp, "response/IIDX26pc/achievements/trophy") self.assert_path(resp, "response/IIDX26pc/skin") self.assert_path(resp, "response/IIDX26pc/qprodata") self.assert_path(resp, "response/IIDX26pc/grade") self.assert_path(resp, "response/IIDX26pc/rlist") self.assert_path(resp, "response/IIDX26pc/step") self.assert_path(resp, "response/IIDX26pc/favorite/sp_mlist") self.assert_path(resp, "response/IIDX26pc/favorite/sp_clist") self.assert_path(resp, "response/IIDX26pc/favorite/dp_mlist") self.assert_path(resp, "response/IIDX26pc/favorite/dp_clist") self.assert_path(resp, "response/IIDX26pc/extra_favorite/sp_mlist") self.assert_path(resp, "response/IIDX26pc/extra_favorite/sp_clist") self.assert_path(resp, "response/IIDX26pc/extra_favorite/dp_mlist") self.assert_path(resp, "response/IIDX26pc/extra_favorite/dp_clist") name = resp.child('IIDX26pc/pcdata').attribute('name') if name != self.NAME: raise Exception( f'Invalid name \'{name}\' returned for Ref ID \'{ref_id}\'') expert_point: Dict[int, Dict[str, int]] = {} for child in resp.child('IIDX26pc/expert_point').children: if child.name == 'detail': expert_point[int(child.attribute('course_id'))] = { 'n_point': int(child.attribute('n_point')), 'h_point': int(child.attribute('h_point')), 'a_point': int(child.attribute('a_point')), } return { 'extid': int(resp.child('IIDX26pc/pcdata').attribute('id')), 'sp_dan': int(resp.child('IIDX26pc/grade').attribute('sgid')), 'dp_dan': int(resp.child('IIDX26pc/grade').attribute('dgid')), 'deller': int(resp.child('IIDX26pc/deller').attribute('deller')), 'expert_point': expert_point, }
def verify_player22_read(self, ref_id: str, msg_type: str) -> Optional[Dict[str, Any]]: call = self.call_node() # Construct node player22 = Node.void('player22') call.add_child(player22) player22.set_attribute('method', 'read') player22.add_child(Node.string('ref_id', value=ref_id)) player22.add_child(Node.string('shop_name', '')) player22.add_child(Node.s8('pref', 51)) # Swap with server resp = self.exchange('', call) if msg_type == 'new': # Verify that response is correct self.assert_path(resp, "response/player22/@status") status = int(resp.child('player22').attribute('status')) if status != 109: raise Exception( f'Reference ID \'{ref_id}\' returned invalid status \'{status}\'' ) # No score data return None elif msg_type == 'query': # Verify that the response is correct self.assert_path(resp, "response/player22/account/name") self.assert_path(resp, "response/player22/account/g_pm_id") self.assert_path(resp, "response/player22/account/my_best") self.assert_path(resp, "response/player22/account/latest_music") self.assert_path(resp, "response/player22/netvs") self.assert_path(resp, "response/player22/config") self.assert_path(resp, "response/player22/option") self.assert_path(resp, "response/player22/info") self.assert_path(resp, "response/player22/custom_cate") self.assert_path(resp, "response/player22/customize") name = resp.child('player22').child('account').child('name').value if name != self.NAME: raise Exception( f'Invalid name \'{name}\' returned for Ref ID \'{ref_id}\'' ) # Extract and return score data medals: Dict[int, List[int]] = {} scores: Dict[int, List[int]] = {} for child in resp.child('player22').children: if child.name == 'music': songid = child.child_value('music_num') chart = child.child_value('sheet_num') medal = child.child_value('clear_type') points = child.child_value('score') if songid not in medals: medals[songid] = [0, 0, 0, 0] medals[songid][chart] = medal if songid not in scores: scores[songid] = [0, 0, 0, 0] scores[songid][chart] = points return {'medals': medals, 'scores': scores} else: raise Exception(f'Unrecognized message type \'{msg_type}\'')
def handle_info22_request(self, request: Node) -> Optional[Node]: method = request.attribute('method') if method == 'common': # TODO: Hook these up to config so we can change this phases = { # Unknown event 0: 0, # Unknown event 1: 0, # Pop'n Aura, max 10 (remov all aura requirements) 2: 10, # Story 3: 1, # BEMANI ruins Discovery! 4: 0, # Unknown event 5: 0, # Unknown event 6: 0, # Unknown event 7: 0, # Unknown event 8: 0, # Unknown event 9: 0, # Unknown event 10: 0, # Unknown event 11: 0, # Unknown event 12: 0, # Unknown event 13: 0, # Unknown event 14: 0, # Unknown event 15: 0, # Unknown event 16: 0, # Unknown event 17: 0, # Unknown event 18: 0, # Unknown event 19: 0, } stories = list(range(173)) root = Node.void('info22') for phaseid in phases: phase = Node.void('phase') root.add_child(phase) phase.add_child(Node.s16('event_id', phaseid)) phase.add_child(Node.s16('phase', phases[phaseid])) for storyid in stories: story = Node.void('story') root.add_child(story) story.add_child(Node.u32('story_id', storyid)) story.add_child(Node.bool('is_limited', False)) story.add_child(Node.u64('limit_date', 0)) return root # Invalid method return None
def handle_player23_logout_request(self, request: Node) -> Node: return Node.void('player23')
def verify_gameend_regist( self, ref_id: str, jid: int, scores: List[Dict[str, Any]], course: Dict[str, Any], league: Optional[Tuple[int, Tuple[int, int, int]]], ) -> None: call = self.call_node() # Construct node gameend = Node.void('gameend') call.add_child(gameend) gameend.set_attribute('method', 'regist') gameend.add_child(Node.s32('retry', 0)) data = Node.void('data') gameend.add_child(data) player = Node.void('player') data.add_child(player) player.add_child(Node.string('refid', ref_id)) player.add_child(Node.s32('jid', jid)) player.add_child(Node.string('name', self.NAME)) result = Node.void('result') data.add_child(result) result.set_attribute('count', str(len(scores))) # Send scores scoreid = 0 for score in scores: # Always played bits = 0x1 if score['clear']: bits |= 0x2 if score['fc']: bits |= 0x4 if score['ex']: bits |= 0x8 # Intentionally starting at 1 because that's what the game does scoreid = scoreid + 1 tune = Node.void('tune') result.add_child(tune) tune.set_attribute('id', str(scoreid)) tune.set_attribute('count', '0') tune.add_child(Node.s32('music', score['id'])) player_1 = Node.void('player') tune.add_child(player_1) player_1.set_attribute('rank', '1') scorenode = Node.s32('score', score['score']) player_1.add_child(scorenode) scorenode.set_attribute('seq', str(score['chart'])) scorenode.set_attribute('clear', str(bits)) scorenode.set_attribute('combo', '69') player_1.add_child( Node.u8_array('mbar', [ 239, 175, 170, 170, 190, 234, 187, 158, 153, 230, 170, 90, 102, 170, 85, 150, 150, 102, 85, 234, 171, 169, 157, 150, 170, 101, 230, 90, 214, 255 ])) if len(course) > 0: coursenode = Node.void('course') player.add_child(coursenode) coursenode.add_child(Node.s32('course_id', course['course_id'])) coursenode.add_child(Node.u8('rating', course['rating'])) index = 0 for coursescore in course['scores']: music = Node.void('music') coursenode.add_child(music) music.set_attribute('index', str(index)) music.add_child(Node.s32('score', coursescore)) index = index + 1 if league is not None: leaguenode = Node.void('league') player.add_child(leaguenode) leaguenode.add_child(Node.s32('league_id', league[0])) leaguenode.add_child(Node.bool('is_first_play', False)) leaguenode.add_child(Node.bool('is_checked', True)) index = 0 for leaguescore in league[1]: musicnode = Node.void('music') leaguenode.add_child(musicnode) musicnode.set_attribute('index', str(index)) index = index + 1 scorenode = Node.s32('score', leaguescore) musicnode.add_child(scorenode) scorenode.set_attribute('clear', '3') # Swap with server resp = self.exchange('', call) self.assert_path(resp, "response/gameend/data/player/session_id")
def handle_player23_read_score_request(self, request: Node) -> Node: refid = request.child_value('ref_id') root = Node.void('player23') userid = self.data.remote.user.from_refid(self.game, self.version, refid) if userid is not None: scores = self.data.remote.music.get_scores(self.game, self.version, userid) else: scores = [] for score in scores: # Skip any scores for chart types we don't support if score.chart not in [ self.CHART_TYPE_EASY, self.CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER, self.CHART_TYPE_EX, ]: continue points = score.points medal = score.data.get_int('medal') music = Node.void('music') root.add_child(music) music.add_child(Node.s16('music_num', score.id)) music.add_child( Node.u8( 'sheet_num', { self.CHART_TYPE_EASY: self.GAME_CHART_TYPE_EASY, self.CHART_TYPE_NORMAL: self.GAME_CHART_TYPE_NORMAL, self.CHART_TYPE_HYPER: self.GAME_CHART_TYPE_HYPER, self.CHART_TYPE_EX: self.GAME_CHART_TYPE_EX, }[score.chart])) music.add_child(Node.s32('score', points)) music.add_child( Node.u8( 'clear_type', { self.PLAY_MEDAL_CIRCLE_FAILED: self.GAME_PLAY_MEDAL_CIRCLE_FAILED, self.PLAY_MEDAL_DIAMOND_FAILED: self.GAME_PLAY_MEDAL_DIAMOND_FAILED, self.PLAY_MEDAL_STAR_FAILED: self.GAME_PLAY_MEDAL_STAR_FAILED, self.PLAY_MEDAL_EASY_CLEAR: self.GAME_PLAY_MEDAL_EASY_CLEAR, self.PLAY_MEDAL_CIRCLE_CLEARED: self.GAME_PLAY_MEDAL_CIRCLE_CLEARED, self.PLAY_MEDAL_DIAMOND_CLEARED: self.GAME_PLAY_MEDAL_DIAMOND_CLEARED, self.PLAY_MEDAL_STAR_CLEARED: self.GAME_PLAY_MEDAL_STAR_CLEARED, self.PLAY_MEDAL_CIRCLE_FULL_COMBO: self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO, self.PLAY_MEDAL_DIAMOND_FULL_COMBO: self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO, self.PLAY_MEDAL_STAR_FULL_COMBO: self.GAME_PLAY_MEDAL_STAR_FULL_COMBO, self.PLAY_MEDAL_PERFECT: self.GAME_PLAY_MEDAL_PERFECT, }[medal])) music.add_child(Node.s16('cnt', score.plays)) return root
def handle_pcb23_error_request(self, request: Node) -> Node: return Node.void('pcb23')
def __construct_common_info(self, root: Node) -> None: # Event phases phases = { # Unknown event (0-16) 0: 16, # Unknown event (0-3) 1: 3, # Unknown event (0-1) 2: 1, # Unknown event (0-2) 3: 2, # Unknown event (0-1) 4: 1, # Unknown event (0-2) 5: 2, # Unknown event (0-1) 6: 1, # Unknown event (0-4) 7: 4, # Unknown event (0-3) 8: 3, # Unknown event (0-4) 9: 4, # Unknown event (0-4) 10: 4, # Unknown event (0-1) 11: 1, # Possibly global event matching related? (0-1) 12: 1, # Unknown event (0-4) 13: 4, } for phaseid in phases: phase = Node.void('phase') root.add_child(phase) phase.add_child(Node.s16('event_id', phaseid)) phase.add_child(Node.s16('phase', phases[phaseid])) for areaid in range(1, 50): area = Node.void('area') root.add_child(area) area.add_child(Node.s16('area_id', areaid)) area.add_child(Node.u64('end_date', 0)) area.add_child(Node.s16('medal_id', areaid)) area.add_child(Node.bool('is_limit', False)) # Calculate most popular characters profiles = self.data.remote.user.get_all_profiles( self.game, self.version) charas: Dict[int, int] = {} for (userid, profile) in profiles: chara = profile.get_int('chara', -1) if chara <= 0: continue if chara not in charas: charas[chara] = 1 else: charas[chara] = charas[chara] + 1 # Order a typle by most popular character to least popular character charamap = sorted( [(c, charas[c]) for c in charas], key=lambda c: c[1], reverse=True, ) # Output the top 20 of them rank = 1 for (charaid, usecount) in charamap[:20]: popular = Node.void('popular') root.add_child(popular) popular.add_child(Node.s16('rank', rank)) popular.add_child(Node.s16('chara_num', charaid)) rank = rank + 1 # Output the hit chart for (songid, plays) in self.data.local.music.get_hit_chart( self.game, self.version, 500): popular_music = Node.void('popular_music') root.add_child(popular_music) popular_music.add_child(Node.s16('music_num', songid)) # Output goods prices for goodsid in range(1, 421): if goodsid >= 1 and goodsid <= 80: price = 60 elif goodsid >= 81 and goodsid <= 120: price = 250 elif goodsid >= 121 and goodsid <= 142: price = 500 elif goodsid >= 143 and goodsid <= 300: price = 100 elif goodsid >= 301 and goodsid <= 420: price = 150 else: raise Exception('Invalid goods ID!') goods = Node.void('goods') root.add_child(goods) goods.add_child(Node.s16('goods_id', goodsid)) goods.add_child(Node.s32('price', price)) goods.add_child(Node.s16('goods_type', 0))
def handle_pcb23_dlstatus_request(self, request: Node) -> Node: return Node.void('pcb23')
def handle_gameend_log_request(self, request: Node) -> Node: # Respond to request with nothing since we don't care about cardless players return Node.void('gameend')
def handle_pcb23_write_request(self, request: Node) -> Node: # Update the name of this cab for admin purposes self.update_machine_name(request.child_value('pcb_setting/name')) return Node.void('pcb23')
def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: """ Base handler for a profile. Given a userid and a profile dictionary, return a Node representing a profile. Should be overridden. """ return Node.void('game')
def handle_info23_common_request(self, request: Node) -> Node: info = Node.void('info23') self.__construct_common_info(info) return info
def handle_game_message_request(self, request: Node) -> Node: return Node.void('game')
def handle_lobby22_request(self, request: Node) -> Optional[Node]: # Stub out the entire lobby22 service (yes, its lobby22 in Pop'n 23) return Node.void('lobby22')
def handle_game_friend_request(self, request: Node) -> Node: extid = intish(request.attribute('code')) userid = None friend = None if extid is not None: # Rival score loading userid = self.data.remote.user.from_extid(self.game, self.version, extid) if userid is not None: friend = self.get_profile(userid) play_stats = self.get_play_statistics(userid) if friend is None: # Return an empty node to tell the game we don't have a player here game = Node.void('game') return game game = Node.void('game') game.set_attribute('data', '1') game.add_child(Node.u32('code', friend.get_int('extid'))) game.add_child(Node.string('name', friend.get_str('name'))) game.add_child(Node.u8('area', friend.get_int('area', 51))) game.add_child(Node.u32('exp', play_stats.get_int('exp'))) game.add_child(Node.u32('star', friend.get_int('star'))) # Drill rankings if 'title' in friend: title = Node.void('title') game.add_child(title) titledict = friend.get_dict('title') if 't' in titledict: title.set_attribute('t', str(titledict.get_int('t'))) if 's' in titledict: title.set_attribute('s', str(titledict.get_int('s'))) if 'd' in titledict: title.set_attribute('d', str(titledict.get_int('d'))) if 'title_gr' in friend: title_gr = Node.void('title_gr') game.add_child(title_gr) title_grdict = friend.get_dict('title_gr') if 't' in title_grdict: title_gr.set_attribute('t', str(title_grdict.get_int('t'))) if 's' in title_grdict: title_gr.set_attribute('s', str(title_grdict.get_int('s'))) if 'd' in title_grdict: title_gr.set_attribute('d', str(title_grdict.get_int('d'))) # Groove gauge level-ups gr_s = Node.void('gr_s') game.add_child(gr_s) index = 1 for entry in friend.get_int_array('gr_s', 5): gr_s.set_attribute('gr{}'.format(index), str(entry)) index = index + 1 gr_d = Node.void('gr_d') game.add_child(gr_d) index = 1 for entry in friend.get_int_array('gr_d', 5): gr_d.set_attribute('gr{}'.format(index), str(entry)) index = index + 1 return game
def handle_player23_start_request(self, request: Node) -> Node: root = Node.void('player23') root.add_child(Node.s32('play_id', 0)) self.__construct_common_info(root) return root
def handle_game_tax_info_request(self, request: Node) -> Node: game = Node.void('game') tax_info = Node.void('tax_info') game.add_child(tax_info) tax_info.set_attribute('tax_phase', '0') return game
def handle_player22_request(self, request: Node) -> Optional[Node]: method = request.attribute('method') if method == 'read': refid = request.child_value('ref_id') # Pop'n Music 22 doesn't send a modelstring to load old profiles, # it just expects us to know. So always look for old profiles in # Pop'n 22 land. root = self.get_profile_by_refid(refid, self.OLD_PROFILE_FALLTHROUGH) if root is None: root = Node.void('player22') root.set_attribute('status', str(Status.NO_PROFILE)) return root elif method == 'new': refid = request.child_value('ref_id') name = request.child_value('name') root = self.new_profile_by_refid(refid, name) if root is None: root = Node.void('player22') root.set_attribute('status', str(Status.NO_PROFILE)) return root elif method == 'start': return Node.void('player22') elif method == 'logout': return Node.void('player22') elif method == 'write': refid = request.child_value('ref_id') root = Node.void('player22') if refid is None: return root userid = self.data.remote.user.from_refid(self.game, self.version, refid) if userid is None: return root oldprofile = self.get_profile(userid) or ValidatedDict() newprofile = self.unformat_profile(userid, request, oldprofile) if newprofile is not None: self.put_profile(userid, newprofile) return root elif method == 'conversion': refid = request.child_value('ref_id') name = request.child_value('name') chara = request.child_value('chara') root = self.new_profile_by_refid(refid, name, chara) if root is None: root = Node.void('playerdata') root.set_attribute('status', str(Status.NO_PROFILE)) return root elif method == 'write_music': refid = request.child_value('ref_id') root = Node.void('player22') if refid is None: return root userid = self.data.remote.user.from_refid(self.game, self.version, refid) if userid is None: return root songid = request.child_value('music_num') chart = { self.GAME_CHART_TYPE_EASY: self.CHART_TYPE_EASY, self.GAME_CHART_TYPE_NORMAL: self.CHART_TYPE_NORMAL, self.GAME_CHART_TYPE_HYPER: self.CHART_TYPE_HYPER, self.GAME_CHART_TYPE_EX: self.CHART_TYPE_EX, }[request.child_value('sheet_num')] medal = request.child_value('clearmedal') points = request.child_value('score') combo = request.child_value('combo') stats = { 'cool': request.child_value('cool'), 'great': request.child_value('great'), 'good': request.child_value('good'), 'bad': request.child_value('bad') } medal = { self.GAME_PLAY_MEDAL_CIRCLE_FAILED: self.PLAY_MEDAL_CIRCLE_FAILED, self.GAME_PLAY_MEDAL_DIAMOND_FAILED: self.PLAY_MEDAL_DIAMOND_FAILED, self.GAME_PLAY_MEDAL_STAR_FAILED: self.PLAY_MEDAL_STAR_FAILED, self.GAME_PLAY_MEDAL_EASY_CLEAR: self.PLAY_MEDAL_EASY_CLEAR, self.GAME_PLAY_MEDAL_CIRCLE_CLEARED: self.PLAY_MEDAL_CIRCLE_CLEARED, self.GAME_PLAY_MEDAL_DIAMOND_CLEARED: self.PLAY_MEDAL_DIAMOND_CLEARED, self.GAME_PLAY_MEDAL_STAR_CLEARED: self.PLAY_MEDAL_STAR_CLEARED, self.GAME_PLAY_MEDAL_CIRCLE_FULL_COMBO: self.PLAY_MEDAL_CIRCLE_FULL_COMBO, self.GAME_PLAY_MEDAL_DIAMOND_FULL_COMBO: self.PLAY_MEDAL_DIAMOND_FULL_COMBO, self.GAME_PLAY_MEDAL_STAR_FULL_COMBO: self.PLAY_MEDAL_STAR_FULL_COMBO, self.GAME_PLAY_MEDAL_PERFECT: self.PLAY_MEDAL_PERFECT, }[medal] self.update_score(userid, songid, chart, points, medal, combo=combo, stats=stats) return root # Invalid method return None