def format_profile(self, profile: ValidatedDict, playstats: ValidatedDict) -> Dict[str, Any]: formatted_profile = super().format_profile(profile, playstats) if profile.get_int('version') in (VersionConstants.DDR_ACE, VersionConstants.DDR_A20): formatted_profile.update({ 'sp': playstats.get_int('single_plays'), 'dp': playstats.get_int('double_plays'), 'early_late': profile.get_int('early_late') != 0, 'background_combo': profile.get_int('combo') != 0, 'workout_mode': profile.get_bool('workout_mode'), 'weight': profile.get_int('weight'), 'settings': { 'arrowskin': profile.get_int('arrowskin'), 'guidelines': profile.get_int('guidelines'), 'filter': profile.get_int('filter'), 'character': profile.get_int('character'), }, }) else: formatted_profile.update({ 'sp': playstats.get_int('single_plays'), 'dp': playstats.get_int('double_plays'), 'early_late': profile.get_int('early_late') != 0, 'background_combo': profile.get_int('combo') != 0, 'workout_mode': 'weight' in profile, 'weight': profile.get_int('weight'), }) return formatted_profile
def format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: root = Node.void('gametop') data = Node.void('data') root.add_child(data) player = Node.void('player') data.add_child(player) # Player info and statistics info = Node.void('info') player.add_child(info) info.add_child(Node.s16('jubility', profile.get_int('jubility'))) info.add_child(Node.s16('jubility_yday', profile.get_int('jubility_yday'))) info.add_child(Node.s32('tune_cnt', profile.get_int('tune_cnt'))) info.add_child(Node.s32('save_cnt', profile.get_int('save_cnt'))) info.add_child(Node.s32('saved_cnt', profile.get_int('saved_cnt'))) info.add_child(Node.s32('fc_cnt', profile.get_int('fc_cnt'))) info.add_child(Node.s32('ex_cnt', profile.get_int('ex_cnt'))) info.add_child(Node.s32('pf_cnt', profile.get_int('pf_cnt'))) info.add_child(Node.s32('clear_cnt', profile.get_int('clear_cnt'))) info.add_child(Node.s32('match_cnt', profile.get_int('match_cnt'))) info.add_child(Node.s32('beat_cnt', profile.get_int('beat_cnt'))) info.add_child(Node.s32('mynews_cnt', profile.get_int('mynews_cnt'))) if 'total_best_score' in profile: info.add_child(Node.s32('total_best_score', profile.get_int('total_best_score'))) # Looks to be set to true when there's an old profile, stops tutorial from # happening on first load. info.add_child(Node.bool('inherit', profile.get_bool('has_old_version'))) # Not saved, but loaded info.add_child(Node.s32('mtg_entry_cnt', 123)) info.add_child(Node.s32('mtg_hold_cnt', 456)) info.add_child(Node.u8('mtg_result', 10)) # Secret unlocks item = Node.void('item') player.add_child(item) item.add_child(Node.s32_array( 'secret_list', profile.get_int_array( 'secret_list', 32, [-1] * 32, ), )) item.add_child(Node.s32_array( 'title_list', profile.get_int_array( 'title_list', 96, [-1] * 96, ), )) item.add_child(Node.s16('theme_list', profile.get_int('theme_list', -1))) item.add_child(Node.s32_array('marker_list', profile.get_int_array('marker_list', 2, [-1] * 2))) item.add_child(Node.s32_array('parts_list', profile.get_int_array('parts_list', 96, [-1] * 96))) new = Node.void('new') item.add_child(new) new.add_child(Node.s32_array( 'secret_list', profile.get_int_array( 'secret_list_new', 32, [-1] * 32, ), )) new.add_child(Node.s32_array( 'title_list', profile.get_int_array( 'title_list_new', 96, [-1] * 96, ), )) new.add_child(Node.s16('theme_list', profile.get_int('theme_list_new', -1))) new.add_child(Node.s32_array('marker_list', profile.get_int_array('marker_list_new', 2, [-1] * 2))) # Last played data, for showing cursor and such lastdict = profile.get_dict('last') last = Node.void('last') player.add_child(last) last.add_child(Node.s32('music_id', lastdict.get_int('music_id'))) last.add_child(Node.s8('marker', lastdict.get_int('marker'))) last.add_child(Node.s16('title', lastdict.get_int('title'))) last.add_child(Node.s8('theme', lastdict.get_int('theme'))) last.add_child(Node.s8('sort', lastdict.get_int('sort'))) last.add_child(Node.s8('rank_sort', lastdict.get_int('rank_sort'))) last.add_child(Node.s8('combo_disp', lastdict.get_int('combo_disp'))) last.add_child(Node.s8('seq_id', lastdict.get_int('seq_id'))) last.add_child(Node.s16('parts', lastdict.get_int('parts'))) last.add_child(Node.s8('category', lastdict.get_int('category'))) last.add_child(Node.s64('play_time', lastdict.get_int('play_time'))) last.add_child(Node.string('shopname', lastdict.get_str('shopname'))) last.add_child(Node.string('areaname', lastdict.get_str('areaname'))) # Miscelaneous crap player.add_child(Node.s32('session_id', 1)) # Maybe hook this up? Unsure what it does, is it like IIDX dailies? today_music = Node.void('today_music') player.add_child(today_music) today_music.add_child(Node.s32('music_id', 0)) # No news, ever. news = Node.void('news') player.add_child(news) news.add_child(Node.s16('checked', 0)) # No rival support, yet. rivallist = Node.void('rivallist') player.add_child(rivallist) rivallist.set_attribute('count', '0') mylist = Node.void('mylist') player.add_child(mylist) mylist.set_attribute('count', '0') # No collaboration support yet. collabo = Node.void('collabo') player.add_child(collabo) collabo.add_child(Node.bool('success', False)) collabo.add_child(Node.bool('completed', False)) # Daily FC challenge. entry = self.data.local.game.get_time_sensitive_settings(self.game, self.version, 'fc_challenge') if entry is None: entry = ValidatedDict() # Figure out if we've played these songs start_time, end_time = self.data.local.network.get_schedule_duration('daily') today_attempts = self.data.local.music.get_all_attempts(self.game, self.version, userid, entry.get_int('today', -1), timelimit=start_time) challenge = Node.void('challenge') player.add_child(challenge) today = Node.void('today') challenge.add_child(today) today.add_child(Node.s32('music_id', entry.get_int('today', -1))) today.add_child(Node.u8('state', 0x40 if len(today_attempts) > 0 else 0x0)) onlynow = Node.void('onlynow') challenge.add_child(onlynow) onlynow.add_child(Node.s32('magic_no', 0)) onlynow.add_child(Node.s16('cycle', 0)) # Bistro event bistro = Node.void('bistro') player.add_child(bistro) # Presumably these can affect the speed of the event info_1 = Node.void('info') bistro.add_child(info_1) info_1.add_child(Node.float('delicious_rate', 1.0)) info_1.add_child(Node.float('favorite_rate', 1.0)) bistro.add_child(Node.s32('carry_over', profile.get_int('bistro_carry_over'))) # Your chef dude, I guess? chefdict = profile.get_dict('chef') chef = Node.void('chef') bistro.add_child(chef) chef.add_child(Node.s32('id', chefdict.get_int('id', 1))) chef.add_child(Node.u8('ability', chefdict.get_int('ability', 2))) chef.add_child(Node.u8('remain', chefdict.get_int('remain', 30))) chef.add_child(Node.u8('rate', chefdict.get_int('rate', 1))) # Routes, similar to story mode in Pop'n I guess? routes = [ { 'id': 50000284, 'price': 20, 'satisfaction': 10, 'favorite': True, }, { 'id': 50000283, 'price': 20, 'satisfaction': 20, 'favorite': False, }, { 'id': 50000282, 'price': 30, 'satisfaction': 10, 'favorite': False, }, { 'id': 50000275, 'price': 10, 'satisfaction': 55, 'favorite': False, }, { 'id': 50000274, 'price': 40, 'satisfaction': 40, 'favorite': False, }, { 'id': 50000273, 'price': 80, 'satisfaction': 60, 'favorite': False, }, { 'id': 50000272, 'price': 70, 'satisfaction': 60, 'favorite': False, }, { 'id': 50000271, 'price': 90, 'satisfaction': 80, 'favorite': False, }, { 'id': 50000270, 'price': 90, 'satisfaction': 20, 'favorite': False, }, ] for route_no in range(len(routes)): routedata = routes[route_no] route = Node.void('route') bistro.add_child(route) route.set_attribute('no', str(route_no)) music = Node.void('music') route.add_child(music) music.add_child(Node.s32('id', routedata['id'])) music.add_child(Node.u16('price', routedata['price'])) music.add_child(Node.s32('price_s32', routedata['price'])) # Look up any updated satisfaction stored by the game routesaved = self.data.local.user.get_achievement(self.game, self.version, userid, route_no + 1, 'route') if routesaved is None: routesaved = ValidatedDict() satisfaction = routesaved.get_int('satisfaction', routedata['satisfaction']) gourmates = Node.void('gourmates') route.add_child(gourmates) gourmates.add_child(Node.s32('id', route_no + 1)) gourmates.add_child(Node.u8('favorite', 1 if routedata['favorite'] else 0)) gourmates.add_child(Node.u16('satisfaction', satisfaction)) gourmates.add_child(Node.s32('satisfaction_s32', satisfaction)) # Sane defaults for unknown nodes only_now_music = Node.void('only_now_music') player.add_child(only_now_music) only_now_music.set_attribute('count', '0') requested_music = Node.void('requested_music') player.add_child(requested_music) requested_music.set_attribute('count', '0') kac_music = Node.void('kac_music') player.add_child(kac_music) kac_music.set_attribute('count', '0') history = Node.void('history') player.add_child(history) history.set_attribute('count', '0') # Basic profile info player.add_child(Node.string('name', profile.get_str('name', 'なし'))) player.add_child(Node.s32('jid', profile.get_int('extid'))) player.add_child(Node.string('refid', profile.get_str('refid'))) # Miscelaneous history stuff data.add_child(Node.u8('termver', 16)) data.add_child(Node.u32('season_etime', 0)) data.add_child(Node.s32('bistro_last_music_id', 0)) data.add_child(Node.s32_array( 'white_music_list', [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], )) data.add_child(Node.s32_array( 'old_music_list', [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], )) data.add_child(Node.s32_array( 'open_music_list', [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], )) # Unsupported collaboration events with other games collabo_info = Node.void('collabo_info') data.add_child(collabo_info) # Unsupported marathon stuff run_run_marathon = Node.void('run_run_marathon') collabo_info.add_child(run_run_marathon) run_run_marathon.set_attribute('type', '1') run_run_marathon.add_child(Node.u8('state', 1)) run_run_marathon.add_child(Node.bool('is_report_end', True)) # Unsupported policy break stuff policy_break = Node.void('policy_break') collabo_info.add_child(policy_break) policy_break.set_attribute('type', '1') policy_break.add_child(Node.u8('state', 1)) policy_break.add_child(Node.bool('is_report_end', False)) # Unsupported vocaloid stuff vocaloid_event = Node.void('vocaloid_event') collabo_info.add_child(vocaloid_event) vocaloid_event.set_attribute('type', '1') vocaloid_event.add_child(Node.u8('state', 0)) vocaloid_event.add_child(Node.s32('music_id', 0)) # No obnoxious 30 second wait to play. matching_off = Node.void('matching_off') data.add_child(matching_off) matching_off.add_child(Node.bool('is_open', True)) 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.music_version, userid, 5) ] most_played = [ x[0] for x in self.data.local.music.get_most_played( self.game, self.music_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)) # Number of rivals that are active for this version. links = self.data.local.user.get_links(self.game, self.version, userid) rivalcount = 0 for link in links: if link.type != 'rival': continue if not self.has_profile(link.other_userid): continue # This profile is valid. rivalcount += 1 account.add_child(Node.u8('active_fr_num', rivalcount)) # 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 format_profile(self, userid: UserID, profile: ValidatedDict) -> Node: root = Node.void('gametop') data = Node.void('data') root.add_child(data) player = Node.void('player') data.add_child(player) # Player info and statistics info = Node.void('info') player.add_child(info) info.add_child(Node.s16('jubility', profile.get_int('jubility'))) info.add_child(Node.s16('jubility_yday', profile.get_int('jubility_yday'))) info.add_child(Node.s32('tune_cnt', profile.get_int('tune_cnt'))) info.add_child(Node.s32('save_cnt', profile.get_int('save_cnt'))) info.add_child(Node.s32('saved_cnt', profile.get_int('saved_cnt'))) info.add_child(Node.s32('fc_cnt', profile.get_int('fc_cnt'))) info.add_child(Node.s32('ex_cnt', profile.get_int('ex_cnt'))) info.add_child(Node.s32('pf_cnt', profile.get_int('pf_cnt'))) info.add_child(Node.s32('clear_cnt', profile.get_int('clear_cnt'))) info.add_child(Node.s32('match_cnt', profile.get_int('match_cnt'))) info.add_child(Node.s32('beat_cnt', profile.get_int('beat_cnt'))) info.add_child(Node.s32('mynews_cnt', profile.get_int('mynews_cnt'))) info.add_child(Node.s32('extra_point', profile.get_int('extra_point'))) info.add_child(Node.bool('is_extra_played', profile.get_bool('is_extra_played'))) if 'total_best_score' in profile: info.add_child(Node.s32('total_best_score', profile.get_int('total_best_score'))) # Looks to be set to true when there's an old profile, stops tutorial from # happening on first load. info.add_child(Node.bool('inherit', profile.get_bool('has_old_version'))) # Not saved, but loaded info.add_child(Node.s32('mtg_entry_cnt', 123)) info.add_child(Node.s32('mtg_hold_cnt', 456)) info.add_child(Node.u8('mtg_result', 10)) # First play stuff we don't support free_first_play = Node.void('free_first_play') player.add_child(free_first_play) free_first_play.add_child(Node.bool('is_available', False)) free_first_play.add_child(Node.s32('point', 0)) free_first_play.add_child(Node.s32('point_used', 0)) # Secret unlocks item = Node.void('item') player.add_child(item) item.add_child(Node.s32_array( 'secret_list', profile.get_int_array( 'secret_list', 32, [-1] * 32, ), )) item.add_child(Node.s32_array( 'title_list', profile.get_int_array( 'title_list', 96, [-1] * 96, ), )) item.add_child(Node.s16('theme_list', profile.get_int('theme_list', -1))) item.add_child(Node.s32_array('marker_list', profile.get_int_array('marker_list', 2, [-1] * 2))) item.add_child(Node.s32_array('parts_list', profile.get_int_array('parts_list', 96, [-1] * 96))) new = Node.void('new') item.add_child(new) new.add_child(Node.s32_array( 'secret_list', profile.get_int_array( 'secret_list_new', 32, [-1] * 32, ), )) new.add_child(Node.s32_array( 'title_list', profile.get_int_array( 'title_list_new', 96, [-1] * 96, ), )) new.add_child(Node.s16('theme_list', profile.get_int('theme_list_new', -1))) new.add_child(Node.s32_array('marker_list', profile.get_int_array('marker_list_new', 2, [-1] * 2))) # Last played data, for showing cursor and such lastdict = profile.get_dict('last') last = Node.void('last') player.add_child(last) last.add_child(Node.s32('music_id', lastdict.get_int('music_id'))) last.add_child(Node.s8('marker', lastdict.get_int('marker'))) last.add_child(Node.s16('title', lastdict.get_int('title'))) last.add_child(Node.s8('theme', lastdict.get_int('theme'))) last.add_child(Node.s8('sort', lastdict.get_int('sort'))) last.add_child(Node.s8('rank_sort', lastdict.get_int('rank_sort'))) last.add_child(Node.s8('combo_disp', lastdict.get_int('combo_disp'))) last.add_child(Node.s8('seq_id', lastdict.get_int('seq_id'))) last.add_child(Node.s16('parts', lastdict.get_int('parts'))) last.add_child(Node.s8('category', lastdict.get_int('category'))) last.add_child(Node.s64('play_time', lastdict.get_int('play_time'))) last.add_child(Node.string('shopname', lastdict.get_str('shopname'))) last.add_child(Node.string('areaname', lastdict.get_str('areaname'))) last.add_child(Node.s8('expert_option', lastdict.get_int('expert_option'))) last.add_child(Node.s8('matching', lastdict.get_int('matching'))) last.add_child(Node.s8('hazard', lastdict.get_int('hazard'))) last.add_child(Node.s8('hard', lastdict.get_int('hard'))) # Miscelaneous crap player.add_child(Node.s32('session_id', 1)) player.add_child(Node.u64('event_flag', 0)) # Macchiato event macchiatodict = profile.get_dict('macchiato') macchiato = Node.void('macchiato') player.add_child(macchiato) macchiato.add_child(Node.s32('pack_id', macchiatodict.get_int('pack_id'))) macchiato.add_child(Node.u16('bean_num', macchiatodict.get_int('bean_num'))) macchiato.add_child(Node.s32('daily_milk_num', macchiatodict.get_int('daily_milk_num'))) macchiato.add_child(Node.bool('is_received_daily_milk', macchiatodict.get_bool('is_received_daily_milk'))) macchiato.add_child(Node.s32('today_tune_cnt', macchiatodict.get_int('today_tune_cnt'))) macchiato.add_child(Node.s32_array( 'daily_milk_bonus', macchiatodict.get_int_array('daily_milk_bonus', 9, [-1, -1, -1, -1, -1, -1, -1, -1, -1]), )) macchiato.add_child(Node.s32('daily_play_burst', macchiatodict.get_int('daily_play_burst'))) macchiato.add_child(Node.bool('sub_menu_is_completed', macchiatodict.get_bool('sub_menu_is_completed'))) macchiato.add_child(Node.s32('compensation_milk', macchiatodict.get_int('compensation_milk'))) macchiato.add_child(Node.s32('match_cnt', macchiatodict.get_int('match_cnt'))) # Probably never will support this macchiato_music_list = Node.void('macchiato_music_list') macchiato.add_child(macchiato_music_list) macchiato_music_list.set_attribute('count', '0') # Same with this comment macchiato.add_child(Node.s32('sub_pack_id', 0)) sub_macchiato_music_list = Node.void('sub_macchiato_music_list') macchiato.add_child(sub_macchiato_music_list) sub_macchiato_music_list.set_attribute('count', '0') # And this season_music_list = Node.void('season_music_list') macchiato.add_child(season_music_list) season_music_list.set_attribute('count', '0') # Weird, this is sent as a void with a bunch of subnodes, but returned as an int array. achievement_list = Node.void('achievement_list') macchiato.add_child(achievement_list) achievement_list.set_attribute('count', '0') # Also probably never supporting this either cow_list = Node.void('cow_list') macchiato.add_child(cow_list) cow_list.set_attribute('count', '0') # No news, ever. news = Node.void('news') player.add_child(news) news.add_child(Node.s16('checked', 0)) # No rival support, yet. rivallist = Node.void('rivallist') player.add_child(rivallist) rivallist.set_attribute('count', '0') # Full combo daily challenge. entry = self.data.local.game.get_time_sensitive_settings(self.game, self.version, 'fc_challenge') if entry is None: entry = ValidatedDict() # Figure out if we've played these songs start_time, end_time = self.data.local.network.get_schedule_duration('daily') today_attempts = self.data.local.music.get_all_attempts(self.game, self.version, userid, entry.get_int('today', -1), timelimit=start_time) whim_attempts = self.data.local.music.get_all_attempts(self.game, self.version, userid, entry.get_int('whim', -1), timelimit=start_time) challenge = Node.void('challenge') player.add_child(challenge) today = Node.void('today') challenge.add_child(today) today.add_child(Node.s32('music_id', entry.get_int('today', -1))) today.add_child(Node.u8('state', 0x40 if len(today_attempts) > 0 else 0x0)) whim = Node.void('whim') challenge.add_child(whim) whim.add_child(Node.s32('music_id', entry.get_int('whim', -1))) whim.add_child(Node.u8('state', 0x40 if len(whim_attempts) > 0 else 0x0)) # Sane defaults for unknown nodes only_now_music = Node.void('only_now_music') player.add_child(only_now_music) only_now_music.set_attribute('count', '0') lab_edit_seq = Node.void('lab_edit_seq') player.add_child(lab_edit_seq) lab_edit_seq.set_attribute('count', '0') kac_music = Node.void('kac_music') player.add_child(kac_music) kac_music.set_attribute('count', '0') history = Node.void('history') player.add_child(history) history.set_attribute('count', '0') share_music = Node.void('share_music') player.add_child(share_music) share_music.set_attribute('count', '0') bonus_music = Node.void('bonus_music') player.add_child(bonus_music) bonus_music.set_attribute('count', '0') bingo = Node.void('bingo') player.add_child(bingo) reward = Node.void('reward') bingo.add_child(reward) reward.add_child(Node.s32('total', 0)) reward.add_child(Node.s32('point', 0)) group = Node.void('group') player.add_child(group) group.add_child(Node.s32('group_id', 0)) # Basic profile info player.add_child(Node.string('name', profile.get_str('name', 'なし'))) player.add_child(Node.s32('jid', profile.get_int('extid'))) player.add_child(Node.string('refid', profile.get_str('refid'))) # Miscelaneous history stuff data.add_child(Node.u8('termver', 16)) data.add_child(Node.u32('season_etime', 0)) data.add_child(Node.s32_array( 'white_music_list', [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], )) data.add_child(Node.s32_array( 'open_music_list', [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], )) # Unsupported collaboration events with other games collabo_info = Node.void('collabo_info') data.add_child(collabo_info) # Unsupported policy break stuff policy_break = Node.void('policy_break') collabo_info.add_child(policy_break) policy_break.set_attribute('type', '1') policy_break.add_child(Node.u8('state', 1)) policy_break.add_child(Node.bool('is_report_end', False)) # Unsupported vocaloid stuff vocaloid_event = Node.void('vocaloid_event') collabo_info.add_child(vocaloid_event) vocaloid_event.set_attribute('type', '1') vocaloid_event.add_child(Node.u8('state', 0)) vocaloid_event.add_child(Node.s32('music_id', 0)) # Unsupported vocaloid stuff vocaloid_event2 = Node.void('vocaloid_event2') collabo_info.add_child(vocaloid_event2) vocaloid_event2.set_attribute('type', '1') vocaloid_event2.add_child(Node.u8('state', 0)) vocaloid_event2.add_child(Node.s32('music_id', 0)) # Maybe it is possible to turn off internet matching here? lab = Node.void('lab') data.add_child(lab) lab.add_child(Node.bool('is_open', False)) matching_off = Node.void('matching_off') data.add_child(matching_off) matching_off.add_child(Node.bool('is_open', True)) return root